介绍
在嵌入式设计中,需要与 PC 进行通信的通道是很常见的。最简单的方法是串行通信,因为每个微控制器都有 UART 端口来与外界进行串行通信。但在计算机上,这并不总是那么容易。
在这里,我提出了一个非常简单的串行通信库,具有非阻塞读取和不依赖事件的功能,这可能是一个优势,具体取决于我们需要的软件类型。
除此之外,我还提供了一个非常有用的串行端口枚举器,以及一个简单的Timer 类,它允许我们测量间隔并自动执行一些操作。此类timer 不是事件驱动的,因此您必须轮询间隔的状态以了解是否该执行某些操作。
在以后的文章中,我将解释如何使用事件驱动的计时器来真正实现功能的自动化。但就目前而言,这个简单的功能timer 对于我们的应用程序来说已经足够了。
使用代码
在代码中,我使用三个独立的库。一种用于串行通信,一种用于计时,一种用于 PC 中可用端口的摘要。我分别上传每个库以及使用它们的示例项目。
RS232库
该库为 PC 的 COM 端口带来了简单易用的界面。标题提供了这些功能:
#ifndef rs232_INCLUDED#define rs232_INCLUDED#ifdef __cplusplusextern "C" {#endif#include <stdio.h>#include <string.h>#ifdef __linux__#include <termios.h>#include <sys/ioctl.h>#include <unistd.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>#include <limits.h>#else#include <windows.h>#endifint RS232_OpenComport(int, int);int RS232_PollComport(int, unsigned char *, int);int RS232_SendByte(int, unsigned char);int RS232_SendBuf(int, unsigned char *, int);void RS232_CloseComport(int);void RS232_cputs(int, const char *);int RS232_IsDCDEnabled(int);int RS232_IsCTSEnabled(int);int RS232_IsDSREnabled(int);void RS232_enableDTR(int);void RS232_disableDTR(int);void RS232_enableRTS(int);void RS232_disableRTS(int);#ifdef __cplusplus} /* extern "C" */#endif#endif该库由 Teunis van Beelen 编写,更多信息请参见此处。
Com 端口枚举器
该库提供了一种枚举 PC 中可用串行端口的简单方法。它并不完美,但效果很好。
#ifndef LISTPORTS_H#define LISTPORTS_H#define VERSION_LISTPORTS 0x00020000#ifdef __cplusplusextern "C"{#endif#include <windows.h>typedef struct{
LPCTSTR lpPortName; /* "COM1", etc. */
LPCTSTR lpFriendlyName; /* Suitable to describe the port, as for */
/* instance "Infrared serial port (COM4)" */
LPCTSTR lpTechnology; /* "BIOS","INFRARED","USB", etc. */}LISTPORTS_PORTINFO;typedef BOOL (CALLBACK* LISTPORTS_CALLBACK)(LPVOID lpCallbackValue,
LISTPORTS_PORTINFO* lpPortInfo);/* User provided callback funtion that receives the information on each
* serial port available.
* The strings provided on the LISTPORTS_INFO are not to be referenced after
* the callback returns; instead make copies of them for later use.
* If the callback returns FALSE, port enumeration is aborted.
*/BOOL ListPorts(LISTPORTS_CALLBACK lpCallback,LPVOID lpCallbackValue);/* Lists serial ports available on the system, passing the information on
* each port on succesive calls to lpCallback.
* lpCallbackValue, treated opaquely by ListPorts(), is intended to carry
* information internal to the callback routine.
* Returns TRUE if succesful, otherwise error code can be retrieved via
* GetLastError().
*/#ifdef __cplusplus}#endif#elif VERSION_LISTPORTS!=0x00020000#error You have included two LISTPORTS.H with different version numbers#endiftypedef BOOL (CALLBACK* LISTPORTS_CALLBACK)(LPVOID lpCallbackValue, LISTPORTS_PORTINFO* lpPortInfo);
定义。在示例中,我提供:
string comPorts[4]; // Vector containing available portsint port_cnt=0;/* Callback function that list the available ports */static BOOL CALLBACK callback(LPVOID lpCallbackValue,LISTPORTS_PORTINFO* lpPortInfo)
{
_tprintf(
TEXT("\"%s\" \"%s\" \"%s\"\n"),
lpPortInfo->lpPortName,lpPortInfo->lpTechnology,lpPortInfo->lpFriendlyName);
comPorts[port_cnt] = lpPortInfo->lpPortName;
port_cnt++; return TRUE;
}该库由 Joaquín Mª López Muñoz 编写。
这个例子
该示例只是一个控制台应用程序,模拟一个非常简单的终端,该终端发送一个字符或string 到端口广告以显示连接到它的设备的响应。它是使用Code::Blocks Windows 7 编写的。
#include <iostream>#include "rs232.h"#include "timerclass.h"#include "listports.h"#include <tchar.h>using namespace std;
string comPorts[4]; // Vector containing available portsint port_cnt=0;/* Definition of the Callback function that list the available ports */static BOOL CALLBACK callback(LPVOID lpCallbackValue,LISTPORTS_PORTINFO* lpPortInfo)
{
_tprintf(
TEXT("\"%s\" \"%s\" \"%s\"\n"),
lpPortInfo->lpPortName,lpPortInfo->lpTechnology,lpPortInfo->lpFriendlyName);
comPorts[port_cnt] = lpPortInfo->lpPortName;
port_cnt++; return TRUE;
}int main(int argc, char* argv[])
{ int n; unsigned char buf[4096]; int cport_nr = 4; int bdrate = 9600; //unsigned char outBuffer[128]; string outBuffer;
ListPorts(callback,NULL); //Calling to the list ports function
cout << "Available ports: " << endl; for(int i=0; i<port_cnt; i++)
{
cout << (i+1) << ": " << comPorts[i] << endl;
}
cout << endl << "Choose a port ";
cin >> cport_nr;
cport_nr--; // according to rs232.h, the port numbers start on 0 for COM1
if(RS232_OpenComport(cport_nr, bdrate)) //Open the port {
cout << "Can not open com port " << comPorts[cport_nr]; return(0);
} while(1)
{ //n = RS232_PollComport(cport_nr, buf, 4095); cout << "Type message to send" << endl << "Type 'quit' to exit" << endl;
cin >> outBuffer; if(outBuffer == "quit")
{
RS232_CloseComport(cport_nr); return 0;
}
RS232_SendBuf(cport_nr, (unsigned char*) outBuffer.c_str(), outBuffer.size());
Sleep(100);
n = RS232_PollComport(cport_nr, buf, 4096); if(n>0)
{
buf[n]=0;
cout << "Received: " << buf << endl << endl;
}
buf[0]=0;
}
}包含库之后是端口列表器的回调函数的定义。它显示可用的端口并将其名称存储在string.
然后在main 函数中,首先调用该ListPort 函数并再次显示可用端口。询问所需的端口并尝试打开它。如果端口打开,程序将进入无限循环,直到用户键入“退出”。
在循环中,程序要求发送消息并将其放在 COM 端口上。
RS232_SendBuf(cport_nr, (unsigned char*) outBuffer.c_str(), outBuffer.size());
等待 100 毫秒并轮询端口以获取响应:
n = RS232_PollComport(cport_nr, buf, 4096);
如果有任何消息,则会显示在屏幕上:
if(n>0)
{
buf[n]=0;
cout << "Received: " << buf << endl << endl;
}在捕获过程中,与充当回声器的 Arduino 板进行通信。
发表评论