C++/MFC 串口通讯——光源控制器控制

C++/MFC 串口通讯——光源控制器控制

一.背景
1、平台
VS2010+MFC+64位编译平台+使用 Unicode 字符集
2、 字符、字word、字节byte、位bit
(1)字符是指计算机中使用的字母、数字、字和符号。
(2)1word=2bytes=8bits
(3)开发是在vs2010下做的,默认字符集编码是Unicode,但在之前的工程中,默认的字符集形式是多字节字符集。
CString属于所谓的宽字符集,一个字符占两个字节;char类型属于窄字符集,一个char字符占一个字节,所以它们之间的转换涉及到字节大小的转换。CString默认采用unicode编码,而char采用ansi编码,两种编码中单个字符占的存储大小也是不同的。
假设正常COM接收的数据为:23 33 31… 如果直接用Cstring,接收到的数据为23 00 33 00…
需要进行转化:UniCode 下 CString 转 char* 的方法

3、光源控制器的硬件规范&数据格式(帧格式)

波特率数据长度停止位奇偶校验
9600 bps8 bits1 bit
1字节1字节1字节3字节2字节
特征字命令字通道字数据异或和校验字

(1)特征字 = #
(2)命令字 = 1,2,3,4,分别定义为:打开对应通道亮度,关闭对应通道亮度,设置对应通道亮度参数,读出对应通道亮度参数。
当命令字为1,2,3时,如控制器接收命令成功,则返回特征字$;如控制器接收命令失败,则返回&。
当命令字为4时,如控制器接收命令成功,则返回对应通道的亮度设置参数(返回格式跟发送格式相同);如控制器接收命令失败,则返回&。
(3) 通道字 = 1,2,3,4。分别代表4个输出通道。
(4)数据 = 0XX(XX=00~FF内的任一数值),对应通道电源的设置参数,转化为十进制为0~255。
(5)异或和校验字 = 除校验字外的字节(包括:特征字,命令字,通道字和数据)的异或校验和
在这里插入图片描述
4、串口通信常用API

二.程序
1、定义全局变量

HANDLE hcom1;//光源所在串口
OVERLAPPED m_osRead;// 用于重叠读
OVERLAPPED m_osWrite;// 用于重叠写
bool Open_ComPort1,light1_OpenOrClose=false;//是否成功打开串口,是否打开光源

2、串口初始化

hcom1 = CreateFile(L"COM2",GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING ,FILE_ATTRIBUTE_NORMAL,NULL);
	if (hcom1 == INVALID_HANDLE_VALUE)
	{
		MessageBox(_T("打开串口失败!"));
		Open_ComPort1=false;
	}
	else
	{
		DCB dcb;
		GetCommState(hcom1,&dcb);
		dcb.BaudRate = 9600;//波特率
		dcb.ByteSize = 8;//数据长度
		dcb.Parity = 0;//无奇偶校验位
		dcb.StopBits = 0;//停止位,0代表1,1代表1.5,2代表2
		SetCommState(hcom1,&dcb);
		Open_ComPort1=true;
	}

3、串口通讯函数

//发送指令并读取返回值,SendData(createStr(3,1,50)),指令字为4时更新显示框
bool C光源控制Dlg::SendData(CString data)
{
	//初始化缓冲区中的信息
	PurgeComm(hcom1, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);//清空缓冲区
	//发送指令
	BYTE reciveBuf[20];
	DWORD readLen=0;
	USES_CONVERSION;
	char* cstr = T2A(data);
	if(WriteSerial(cstr,8)<=0)
	{
		MessageBox(_T("串口指令发送失败!"));
		return false;
	}
	//接收反馈
	Sleep(100);
	int c=0;
	for( c=0;c<10;c++)
	{    
		int getReciveLength,readBufferLength;
		getReciveLength=getBufferLength();
		if(getReciveLength>0)		
		{  
			readBufferLength=ReadSerial(reciveBuf,getBufferLength());
			if(readBufferLength==1)//只有1个,代表命令字为1、2、3
			{
				if(reciveBuf[0]=='#')
				{
					return true;	
				}
				else
				{
					MessageBox(_T("光源控制器指令接收失败!"));
					return false;
				}
			}
			else//多个代表命令4,读取亮度值
			{
				int l=0;
				if(reciveBuf[0]=='#')
				{
					CString strValue=_T("00"),strValueTemp;
					strValue.Format(_T("%c%c"),reciveBuf[4],reciveBuf[5]);
					//16进制化成10进制
					BYTE decValue=(BYTE)(conHexStrToByte((char)strValue[0])*16+conHexStrToByte((char)strValue[1]));
					CString byte2cstring_temp;
					byte2cstring_temp.Format(_T("%s"),decValue);
					SetDlgItemText(IDC_EDIT_LightNum1,byte2cstring_temp);
					UpdateData(false);
				}
				else
				{
					MessageBox(_T("光源控制器反馈的数据格式错误!"));
					return false;
				}
			}
			break;
		}
		Sleep(15);
	}
	if(c>=10)
	{
		MessageBox(_T("读取光源控制器反馈超时!"));
		return false;
	}
	return true;
}
//输入命令字、通道和亮度值(3,1,50修改通道1亮度->50),输出命令语句# 3 1 032 17
CString  C光源控制Dlg::createStr(BYTE command,BYTE channle,BYTE data)
{
	char *conHex =new char[3];
	CString returnStr=_T("#"),temp,temp2; //将第1通道亮度设为50,则以ASCII码向下写“#3103217”
	//+命令字
	temp.Format(_T("%d"),command);
	returnStr+=temp;
	//+通道
	temp.Format(_T("%d"),channle);
	returnStr+=temp;
	//+亮度值
	if(data>15)
	{
		sprintf(conHex, "0%X", data);//十进制转十六进制
	}
	else
	{
		sprintf(conHex, "00%X", data);
	}
	temp2=conHex;
	returnStr=returnStr+temp2;
	//把所有的字符异或运算,+异或和校验字
	int i;
	BYTE xorData=returnStr[0];
	for(i=1;i<returnStr.GetLength();i++)
	{
		xorData=xorData^returnStr[i];
	}
	sprintf(conHex, "%X", xorData);
	temp2=conHex;
	returnStr=returnStr+temp2;
	return returnStr;
}
//向串口写入命令
DWORD C光源控制Dlg::WriteSerial(char *chBuf, DWORD dwLength)
{
	/*I/O设备处理的WriteFile和ReadFile会阻塞线程
	解决方法一:使用另一个线程进行I/O。
	即 CreateThread(…………);创建一个子线程做其他事情。Readfile(^…………);阻塞方式读数据。
	解决方法二:使用overlapped I/O。
	overlapped I/O是WIN32的一项技术,你可以要求操作系统为你传送数据,并且在传送完毕时通知你。
	这项技术使你的程序在I/O进行过程中仍然能够继续处理事务。事实上,操作系统内部正是以线程来I/O完成overlapped I/O。*/
	memset(&m_osWrite,0,sizeof(OVERLAPPED));
	BOOL bState;
	COMSTAT comStat;
	DWORD dwErrorFlags;	
	ClearCommError(hcom1, &dwErrorFlags, &comStat);	
	bState = WriteFile(hcom1, chBuf, dwLength, &dwLength, &m_osWrite);
	//因为是overlapped操作,ReadFile会将读文件请求放入读队列之后立即返回(false),而不会等到文件读完才返回(true)
	//如果bState=true表示写入成功了,而false就不一定了
	if(!bState)
	{
		if(GetLastError() == ERROR_IO_PENDING)//正在写入过程
		{
			GetOverlappedResult(hcom1, &m_osWrite, &dwLength, TRUE);// 没写完,等待。。
		}
		else//出错了
		{
			dwLength = 0;
		}
	}
	return dwLength;
}
//查看串口返回字节数
DWORD C光源控制Dlg::getBufferLength()
{
	memset(&m_osRead,0,sizeof(OVERLAPPED));
	COMSTAT comStat;
	DWORD dwErrorFlags;
	ClearCommError(hcom1, &dwErrorFlags, &comStat);
	return comStat.cbInQue;
}
//读取串口返回信息
DWORD C光源控制Dlg::ReadSerial(BYTE *chBuf, DWORD dwLength)
{
	DWORD nLen;
	COMSTAT comStat;
	DWORD dwErrorFlags;
	ClearCommError(hcom1, &dwErrorFlags, &comStat);
	nLen = min(dwLength, comStat.cbInQue);
	ReadFile(hcom1, chBuf, nLen, &nLen, &m_osRead);
	return nLen;
}
//16进制转BYTE
BYTE C光源控制Dlg::conHexStrToByte(char str)
{
	if(str>='0' &&str<='9')
	{
		return str-48;
	}else if(str=='a'||str=='A')
	{
		return 10;
	}else if(str=='b'||str=='B')
	{
		return 11;
	}else if(str=='c'||str=='C')
	{
		return 12;
	}else if(str=='d'||str=='D')
	{
		return 13;
	}else if(str=='e'||str=='E')
	{
		return 14;
	}else if(str=='f'||str=='F')
	{
		return 15;
	}
	return 0;
}

4、控制指令

//开关光源
	if (light1_OpenOrClose)//开>>关
	{
		if (SendData(createStr(2,1,255)))//已经关了
		{
			light1_OpenOrClose=false;
			GetDlgItem(IDC_EDIT_LightNum1)->EnableWindow(FALSE);
			GetDlgItem(IDC_SPIN_LightNum1)->EnableWindow(FALSE);
		}
		else
		{
			GetDlgItem(IDC_EDIT_LightNum1)->EnableWindow(TRUE);
			GetDlgItem(IDC_SPIN_LightNum1)->EnableWindow(TRUE);
		}
	} 
	else//关>>开
	{
		if (SendData(createStr(1,1,255)))
		{
			light1_OpenOrClose=true;
			SendData(createStr(4,1,0));//打开光源,更新参数
			GetDlgItem(IDC_EDIT_LightNum1)->EnableWindow(TRUE);
			GetDlgItem(IDC_SPIN_LightNum1)->EnableWindow(TRUE);
		}
		else
		{
			GetDlgItem(IDC_EDIT_LightNum1)->EnableWindow(FALSE);
			GetDlgItem(IDC_SPIN_LightNum1)->EnableWindow(FALSE);
		}
	}
//文本框输入亮度+回车确认
BOOL C光源控制Dlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加专用代码和/或调用基类
	if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)
	{
		if (GetFocus()->GetDlgCtrlID() == IDC_EDIT_LightNum1)//按下回车,如果当前焦点是在自己期望的控件上
		{
			int b=_ttoi(m_LightNum1);
			SendData(createStr(3,1,b));
		}
		return TRUE;
	}
	if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE)
		return TRUE;
	return CDialogEx::PreTranslateMessage(pMsg);
}
  • 6
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
凌云Visionware是一个全球领先的创新技术公司,专注于计算机视觉领域的研发和应用。公司致力于为企业和个人提供先进的视觉解决方案,以帮助他们解决各种复杂的视觉问题和提升工作效率。 凌云Visionware的技术团队由一群具有丰富经验和专业知识的工程师组成。他们熟练运用计算机视觉、人工智能、深度学习等前沿技术,开发出了一系列强大的产品和解决方案。 公司的产品主要包括图像识别、人脸识别、运动检测等功能。通过这些技术,用户可以对大量的图像和视频进行自动化处理和分析,从中提取所需的信息和数据。这对于许多行业来说具有很大的价值,比如安防领域可以通过人脸识别技术来识别嫌疑人;零售行业可以利用图像识别技术对商品进行自动化检测和分类等。 凌云Visionware的解决方案也非常灵活,可以根据客户的需求进行定制。无论是大型企业还是个人开发者,都可以根据自己的实际情况选择适合自己的解决方案。 除了产品和解决方案,凌云Visionware还积极开展科研合作和知识共享,以推动计算机视觉领域的发展。公司定期参加国内外的学术会议和展览,与业界专家进行交流和合作。同时,他们还开设培训课程,培养更多的人才加入到计算机视觉领域。 总的来说,凌云Visionware是一家致力于计算机视觉技术研发和应用的领先公司。他们通过先进的技术和灵活的解决方案,为企业和个人提供高效的视觉解决方案,推动着整个行业的发展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值