实现真空荧光屏VFD的显示
最近接到一个工作任务,就是在Windows平台,通过写串口的方式,实现真空荧光屏VFD 的显示。
VFD是通过淘宝购来的,随产品附来的只有一份显示屏规格说明及保修卡。
如果要写程序实现VFD显示,需要参照产品指令说明。
以下是部分指令的说明。
第一步:选定需要使用的指令类型。
在我的代码里,使用的是EPSON POS指令类型。
相应代码段:
BOOL fState;
BYTE SendBuffer[256];
DWORD WrittenLen;
SendBuffer[0] = 0x01; //Command Type: 01 - EPSON POS
fState = WriteFile(m_hCom, (void*)SendBuffer, 1, &WrittenLen, NULL); 第二步:发送清屏、定位及显示字串等命令。
清屏代码段:
SendBuffer[0] = 0x0C; //0x0C - Clear display screen
fState = WriteFile(m_hCom, (void*)SendBuffer, 1, &WrittenLen, NULL);
清屏代码段:
/*
[1F 24 x y] : Move cursor to specified position
1≦x(column) ≦; 1≦y(row) ≦
*/
BYTE posi[16]={0};
posi[0] = 0x1F;
posi[1] = 0x24;
posi[2] = 0x01;
posi[3] = 0x01;
fState = WriteFile(m_hCom, (void*)posi, 4, &WrittenLen, NULL);
显示字串的代码段
memset(SendBuffer, 0, sizeof(SendBuffer));
if(bCashBox){
sprintf((char*)SendBuffer, "Total:");
nNumberOfBytes = 6;
}
else{
if(bUpdateSubTotal){
if(giProductListNum == 0){
sprintf((char*)SendBuffer, "");
nNumberOfBytes = 0;
}
else {
sprintf((char*)SendBuffer, "SubTotal:");
nNumberOfBytes = 9;
}
}
else {
sprintf((char*)SendBuffer, "Total:");
nNumberOfBytes = 6;
}
}
if(nNumberOfBytes != 0)
{
fState= WriteFile(m_hCom, (void*)&SendBuffer, nNumberOfBytes, &WrittenLen, NULL);
if (!fState)
break;
}
以下是完整功能函数。
void CPosDemoDlgMain::UpdateSubDisp(BOOL bUpdateSubTotal, BOOL bCashBox)
{
BOOL Result = FALSE, fState;
volatile HANDLE m_hCom=NULL; // 串口句柄
COMMTIMEOUTS timeOuts;
COMSTAT comState;
DCB dcb;
BYTE SendBuffer[256], posi[16]={0};
DWORD WrittenLen, dwErrorFlags;
int len, x, nNumberOfBytes;
while(1)
{
// Open COM port.
m_hCom = CreateFile(gComPortID2,
GENERIC_READ|GENERIC_WRITE, // enable read and write
0, // 独占方式
NULL,
OPEN_EXISTING, // 打开而不是创建
0, //FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, // 重叠方式
NULL);
if (m_hCom == INV ALID_HANDLE_V ALUE)
break;
SetupComm(m_hCom, 2048, 2048);
// Set timeout.
timeOuts.ReadIntervalTimeout = 1000;
timeOuts.ReadTotalTimeoutMultiplier = 500;
timeOuts.ReadTotalTimeoutConstant = 5000;
timeOuts.WriteTotalTimeoutMultiplier = 500;
timeOuts.WriteTotalTimeoutConstant = 5000;
if (!SetCommTimeouts(m_hCom, &timeOuts))
break;
// 设置传输参数
if (!GetCommState(m_hCom, &dcb)) // get para
break;
dcb.BaudRate = _wtol(gComBaudRate2);
dcb.ByteSize = _wtoi(gComDataBit2);
if (_wcsicmp(gComParity2, L"none")==0)
dcb.Parity = NOPARITY;
else if (_wcsicmp(gComParity2, L"odd")==0)
dcb.Parity = ODDPARITY;
else if (_wcsicmp(gComParity2, L"odd")==0)
dcb.Parity = EVENPARITY;
if (_wcsicmp(gComStopBit2, L"1") ==0)
dcb.StopBits = ONESTOPBIT;
else if (_wcsicmp(gComStopBit2, L"2") ==0)
dcb.StopBits = TWOSTOPBITS;
if (!SetCommState(m_hCom, &dcb)) // set para
break;
PurgeComm(m_hCom, PURGE_TXCLEAR | PURGE_RXCLEAR); // 清除发送、接收缓冲区
ClearCommError(m_hCom, &dwErrorFlags, &comState); // 清除错误
SendBuffer[0] = 0x01; //Command Type: 01 - EPSON POS
fState = WriteFile(m_hCom, (void*)SendBuffer, 1, &WrittenLen, NULL);
if (!fState)
break;
SendBuffer[0] = 0x0C; //0x0C - Clear display screen
fState = WriteFile(m_hCom, (void*)SendBuffer, 1, &WrittenLen, NULL);
if (!fState)
break;
/*
[1F 24 x y] : Move cursor to specified position
1≦x(column) ≦20 ; 1≦y(row) ≦2
*/
posi[0] = 0x1F;
posi[1] = 0x24;
posi[2] = 0x01;
posi[3] = 0x01;
fState = WriteFile(m_hCom, (void*)posi, 4, &WrittenLen, NULL);
if (!fState)
break;
memset(SendBuffer, 0, sizeof(SendBuffer));
if(bCashBox){
sprintf((char*)SendBuffer, "Total:");
nNumberOfBytes = 6;
}
else{
if(bUpdateSubTotal){
if(giProductListNum == 0){
sprintf((char*)SendBuffer, "");
nNumberOfBytes = 0;
}
else {
sprintf((char*)SendBuffer, "SubTotal:");
nNumberOfBytes = 9;
}
}
else {
sprintf((char*)SendBuffer, "Total:");
nNumberOfBytes = 6;
}
}
if(nNumberOfBytes != 0)
{
fState = WriteFile(m_hCom, (void*)&SendBuffer, nNumberOfBytes, &WrittenLen, NULL);
if (!fState)
break;
}
memset(SendBuffer, 0, sizeof(SendBuffer));
if(bCashBox){
sprintf((char*)SendBuffer, "%d.%02d", gTotalPrice/100, gTotalPrice%100);
}
else {
if(bUpdateSubTotal){
if(giProductListNum == 0){
strcpy((char*)SendBuffer, "");
}
else{
strcpy((char*)SendBuffer, m_sSubTotalBuf);
}
}
else {
sprintf((char*)SendBuffer, "%d.%02d", gTotalPrice/100, gTotalPrice%100);
}
}
len = strlen((char*)SendBuffer);
x = 20 - len;
//set display position
posi[0] = 0x1F;
posi[1] = 0x24;
posi[2] = toHex(x);
posi[3] = 0x01;
fState = WriteFile(m_hCom, (void*)posi, 4, &WrittenLen, NULL);
if (!fState)
break;
//display cash
fState = WriteFile(m_hCom, (void*)&SendBuffer, len, &WrittenLen, NULL);
if (!fState)
break;
//=== row 2 =====================
//set display position (row 2)
posi[0] = 0x1F;
posi[1] = 0x24;
posi[2] = 0x01;
posi[3] = 0x02;
fState = WriteFile(m_hCom, (void*)posi, 4, &WrittenLen, NULL);
if (!fState)
break;
memset(SendBuffer, 0, sizeof(SendBuffer));
if(bCashBox){
sprintf((char*)SendBuffer, "Cash Change:");
fState = WriteFile(m_hCom, (void*)&SendBuffer, 12, &WrittenLen, NULL);
}
else {
if(bUpdateSubTotal){
sprintf((char*)SendBuffer, "Total:");
fState = WriteFile(m_hCom, (void*)&SendBuffer, 6, &WrittenLen, NULL);
}
else {
sprintf((char*)SendBuffer, "Payment:");
fState = WriteFile(m_hCom, (void*)&SendBuffer, 8, &WrittenLen, NULL);
}
}
if (!fState)
break;
memset(SendBuffer, 0, sizeof(SendBuffer));
if(bCashBox){
if (m_Payment < gTotalPrice)
sprintf((char*)SendBuffer, "-%d.%02d", (gTotalPrice - m_Payment)/100, (gTotalPrice - m_Payment)%100);
else
sprintf((char*)SendBuffer, "%d.%02d", (m_Payment - gTotalPrice)/100, (m_Payment - gTotalPrice)%100);
}
else{
if(bUpdateSubTotal){
sprintf((char*)SendBuffer, "%d.%02d", gTotalPrice/100, gTotalPrice%100);
}
else {
sprintf((char*)SendBuffer, "%d.%02d", m_Payment/100, m_Payment%100);
}
}
len = strlen((char*)SendBuffer);
x = 20 - len;
//set display position
posi[0] = 0x1F;
posi[1] = 0x24;
posi[2] = toHex(x);
posi[3] = 0x02;
fState = WriteFile(m_hCom, (void*)posi, 4, &WrittenLen, NULL);
if (!fState)
break;
//display payment or cash change
fState = WriteFile(m_hCom, (void*)&SendBuffer, len, &WrittenLen, NULL);
if (!fState)
break;
Result = TRUE;
// always exit
break;
}
if (m_hCom != NULL)
CloseHandle(m_hCom);
}
在写代码之前,可以利用串口工具,直接向串口写命令,来测试VFD的显示命令。
我在写代码前,先用AccessPort工具向串口发十六进制数据,可以清屏及定位,如果直接发Ascii字串,可以在屏幕上显示。