利用师姐QT2440开发板控制机械臂, 串口通信出现问题, 找到usb转串口后,任然找不到相应的驱动。初步打算用单片机实现。
1.基于Active控件的方式(MSComm)
优点是:直接利用控件,在串口有数据到达时,会促发相应的事件响应函数,然后你可以在实践响应函数里,进行数据的读取。
缺点是:数据在发送和接受的过程中VARIANT、 COleSafeArray 类型的转换,显得繁琐。
步骤:
①插入控件
选择Project菜单下Add To Project子菜单中的 Components and Controls…选项,在弹出的对话框中双击Registered ActiveX Controls项,则所有注册过的ActiveX控件出现在列表框中。 选择Microsoft Communications Control, version 6.0,单击Insert按钮将它插入到我们的Project中来,接受缺省的选项。这时在ClassView视窗中就可以看到CMSComm类了,并且在控件工具栏Controls中出现了电话图标,现在要做的是用鼠标将此图标拖到对话框中,程序运行后,这个图标是看不到的。
②为拖入对话框的 CMSComm控件添加对应的控制变量 m_ctrlComm。
③添加对应的消息响应函数OnComm()
打开ClassWizard->Message Maps,选择类CSCommTestDlg,选择IDC_MSCOMM1,双击消息OnComm,将弹出的对话框中将函数名改为OnComm,这个函数是用来处理串口消息事件的,如每当串口接收到数据,就会产生一个串口接收数据缓冲区中有字符的消息事件,我们刚才添加的函数就会执行,我们在OnComm()函数加入相应的处理代码就能实现自已想要的功能了。请你在函数中加入如下代码:
- void CSCommTestDlg::OnComm()
- {
- // TODO: Add your control notification handler code here
- VARIANT variant_inp;
- COleSafeArray safearray_inp;
- LONG len,k;
- BYTE rxdata[2048]; //设置BYTE数组 An 8-bit integerthat is not signed.
- CString strtemp;
- if(m_ctrlComm.GetCommEvent()==2) //事件值为2表示接收缓冲区内有字符
- { 以下你可以根据自己的通信协议加入处理代码
- variant_inp=m_ctrlComm.GetInput(); //读缓冲区
- safearray_inp=variant_inp; //VARIANT型变量转换为ColeSafeArray型变量
- len=safearray_inp.GetOneDimSize(); //得到有效数据长度
- for(k=0;k<len;k++)
- safearray_inp.GetElement(&k,rxdata+k);//转换为BYTE型数组
- for(k=0;k<len;k++) //将数组转换为Cstring型变量
- {
- BYTE bt=*(char*)(rxdata+k); //字符型
- strtemp.Format("%c",bt); //将字符送入临时变量strtemp存放
- m_strRXData+=strtemp; //加入接收编辑框对应字符串
- }
- }
- UpdateData(FALSE); //更新编辑框内容
- }
④.打开串口和设置串口参数
现在我们在主对话框的CSCommTestDlg::OnInitDialog()打开串口,加入如下代码:
- // TODO: Add extra initialization here
- if(m_ctrlComm.GetPortOpen())
- m_ctrlComm.SetPortOpen(FALSE);
- m_ctrlComm.SetCommPort(1); //选择com1
- if( !m_ctrlComm.GetPortOpen())
- m_ctrlComm.SetPortOpen(TRUE);//打开串口
- else
- AfxMessageBox("cannot open serial port");
- m_ctrlComm.SetSettings("9600,n,8,1"); //波特率9600,无校验,8个数据位,1个停止位
- m_ctrlComm.SetInputModel(1); //1:表示以二进制方式检取数据
- m_ctrlComm.SetRThreshold(1);
- //参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件
- m_ctrlComm.SetInputLen(0); //设置当前接收区数据长度为0
- m_ctrlComm.GetInput();//先预读缓冲区以清除残留数据
⑤.发送数据
- CString m_send = _T("你想要发送的数据")
- m_ctrlComm.SetOutput(COleVariant(m_send ));
2.基于win32 API的串口读写
①初始化打开串口
优点:设置、使用更加灵活,因为是基于win32的api函数。所以显得更加通用,适用任何windows程序上引用,不仅仅限于MFC.
缺点:需要主动的去读取串口上的数据,没有事件通知。
这里有一点需要注意的是,当COM号大于10的时候,会出现打开错误,一般解决的办法是修改com的名称让它的com号是一位数。除此之外也有其他解决办法,见网上。
- HANDLE InitCom(char* comName)
- {
- HANDLE hCom;
- hCom = CreateFile(comName,//COM7口
- GENERIC_READ|GENERIC_WRITE, //允许读和写
- 0, //独占方式
- NULL,
- OPEN_EXISTING, //打开而不是创建
- 0, //同步方式
- NULL);
- if(hCom == (HANDLE)-1)
- {
- return NULL;
- }
- SetupComm(hCom,100,100); //输入缓冲区和输出缓冲区的大小都是100
- COMMTIMEOUTS TimeOuts;
- //设定读超时
- TimeOuts.ReadIntervalTimeout=MAXDWORD;
- TimeOuts.ReadTotalTimeoutMultiplier=0;
- TimeOuts.ReadTotalTimeoutConstant=0;
- //在读一次输入缓冲区的内容后读操作就立即返回,
- //而不管是否读入了要求的字符。
- //设定写超时
- TimeOuts.WriteTotalTimeoutMultiplier=100;
- TimeOuts.WriteTotalTimeoutConstant=500;
- SetCommTimeouts(hCom,&TimeOuts); //设置超时
- DCB dcb;
- GetCommState(hCom, &dcb);
- dcb.BaudRate=115200; //波特率为9600
- dcb.ByteSize=8; //每个字节有8位
- dcb.Parity=NOPARITY; //无奇偶校验位
- dcb.StopBits=1; //两个停止位
- SetCommState(hCom, &dcb);
- PurgeComm(hCom, PURGE_TXCLEAR|PURGE_RXCLEAR);
- return hCom;
- }
- int ReadData(HANDLE handler, char* buffer)
- {
- char readBuffer[512];
- memset(readBuffer, 0, 512);
- DWORD wCount= 512;//读取的字节数
- BOOL bReadStat;
- bReadStat = ReadFile(handler, readBuffer, wCount, &wCount, NULL);
- if(!bReadStat)
- {
- AfxMessageBox("读串口失败!");
- return -1;
- }
- strcpy(buffer, readBuffer);
- PurgeComm(handler, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
- return 0;
- }
③写串口信息
- int WriteData(HANDLE handler, char* buffer)
- {
- unsigned long dwBytesWrite;
- COMSTAT ComStat;
- DWORD dwErrorFlags;
- BOOL bWriteStat;
- ClearCommError(handler, &dwErrorFlags, &ComStat);
- dwBytesWrite = strlen(buffer);
- bWriteStat=WriteFile(handler, buffer, dwBytesWrite, &dwBytesWrite, NULL);
- if(!bWriteStat)
- {
- AfxMessageBox("写串口失败!");
- return -1;
- }
- return 0;
- }
switch(arm_type){
case ARM_DEVICE_COM:
for(i=0; i<MAX_COM_NUM; i++){
DCB com_config_back;
COMSTAT comstat;
DWORD errorcode;
sprintf_s(comstr, "COM%d", i);
// 1. 尝试打开串口
hcom = CreateFileA(comstr, GENERIC_READ | GENERIC_WRITE ,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_OVERLAPPED, NULL);
if(hcom==INVALID_HANDLE_VALUE){
errorcode = GetLastError();
continue;
}
// 2. 创建缓冲区
SetupComm(hcom, 1024*8, 1024*8);
// 3. 串口配置
GetCommState(hcom, &com_config_back);
SetCommState(hcom, &__arm_com_config__);
// 4. 身份验证
ClearCommError(hcom,&errorcode,&comstat);
if(arm_com_is_alive(hcom, 5000)>=0){
break;
}
SetCommState(hcom, &com_config_back);
CloseHandle(hcom);
}
if(i==MAX_COM_NUM){
return NULL;
}
armctr = (arm_controller*)malloc(sizeof(*armctr));
armctr->arm_com = hcom;
break;
case ARM_DEVICE_VIRTUAL_STD:
armctr = (arm_controller*)malloc(sizeof(*armctr));
armctr->arm_com=NULL;
//armctr->arm_com=-1;
break;
default:
return NULL;
}
armctr->arm_type = arm_type;
printf("连接到串口设备:%s\n",comstr);
return armctr;
}