串口学习之串口服务器

由于工作的需要最近写了一个串口服务器。记录一下方便自己以后学习。

开发环境:window10 企业版操作系统           

                 vs2013编译器            

                 MFC应用程序


首先说下开发流程。见下图


说明:

         第一步:中控机发送指令到设备

         第二步:设备收到指令解析后发送相应指令到单片机

         第三步:单片机收到指令做相应的动作

例如:中控机通过串口1发送指令READLEDON

          设备串口2收到指令后解析通过串口3发送指令READLENON到单片机

          单片机串口1收到READLEDON立即点亮红色LED灯

        中控机                                                        设备机                                                           单片机

         com1------------------------------------->com2

                                                                           com3---------------------------------------->com1

代码解释:

 此为设备端的服务器源码

BOOL CTESTListenCMDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	// 将“关于...”菜单项添加到系统菜单中。
	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);
	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}
	SetIcon(m_hIcon, FALSE);// 设置大图标
	SetIcon(m_hIcon, TRUE);// 设置小图标
        /*初始化串口句柄*/
	hDeviceCom = INVALID_HANDLE_VALUE;
       hConnectMasConCom = INVALID_HANDLE_VALUE;
DeviceComNumber = ::GetPrivateProfileIntA("DevicePortSetting", _T("DeviceComNumber"), 4,path);CString DeviceComName;DeviceComName.Format("COM%d",DeviceComNumber);m_device_com.SetWindowText(DeviceComName);
        /*从ini文件获取串口号*/
	ConnectMCComNumber=::GetPrivateProfileIntA("ConnectMCComPortSetting", _T("ConnectMCComNumber"), 4,path); 
	CString CMCComName;
	armComName.Format("COM%d",CMCComNumber);
	m_arm_com.SetWindowText(CMCComName);
	if (initConnectMC() != 0){
		AfxMessageBox(_T("初始化串口失败"));
	}
	if (!(m_ConnectMCCom_Thread = AfxBeginThread(RecvCMCComThread, this))){
		AfxMessageBox(_T("创建线程失败"));
	}
	return TRUE; 
}


串口初始化源码

int CListenMasConComMsgDlg::ComInit(void)
{
	DCB dcb;
	CString mesg;
	COMMTIMEOUTS commtimeout;    
	CString strCom;

	if(ComNumber < 1)
		return 1;

	if(ComNumber < 9)
		strCom.Format("COM%d", ComNumber);
	else
		strCom.Format("\\\\.\\COM%d" , ComNumber);

	hbox = ::CreateFile(strCom,
		GENERIC_READ | GENERIC_WRITE,//允许读写
		0,	//独享方式
		NULL,
		OPEN_EXISTING,//打开已经存在的串口而不创建串口
		0,	//同步方式OVERLAPPED
		NULL);

	if(hbox == INVALID_HANDLE_VALUE){
		AfxMessageBox(_T("打开音频设备串口失败"));
		return 1;
	}
	if (!(SetupComm(hbox, 4096, 4096))){
		CloseHandle(hbox);
	    hbox = INVALID_HANDLE_VALUE;
		AfxMessageBox(_T("音频设备串口缓存区设置失败"));
		return 1;
	}
	/*commtimeout结构体参数初始化*/
	commtimeout.ReadIntervalTimeout = 20;
	commtimeout.ReadTotalTimeoutMultiplier = 0;
	commtimeout.ReadTotalTimeoutConstant = 400;
	commtimeout.WriteTotalTimeoutMultiplier = 400;
	commtimeout.WriteTotalTimeoutConstant = 0;

	if (!SetCommTimeouts(hbox, &commtimeout)) {
		CloseHandle(hbox);
	    hbox = INVALID_HANDLE_VALUE;
		AfxMessageBox(_T("设置音频设备串口超时失败"));
	    return 1;
	}
        /*获取串口状态数据非常重要----这里有一段啰嗦而沉痛的记忆----对方的疏忽自己的大意*/
	if (!GetCommState(hbox, &dcb)) {
		CloseHandle(hbox);
	    hbox = INVALID_HANDLE_VALUE;
		AfxMessageBox(_T("获取音频设备串口设置错误"));
	    return 1;
	}

	/*dcb结构体初始化*/
	dcb.BaudRate = CBR_9600;
	dcb.ByteSize = 8;            
	dcb.Parity   = NOPARITY;      
	dcb.StopBits = ONESTOPBIT;    

	if (!SetCommState(hbox, &dcb)) {
		CloseHandle(hbox);
	    hbox = INVALID_HANDLE_VALUE;
		AfxMessageBox(_T("设置音频设备串口错误"));
		return 1;
	} 

	//清空收发缓冲区
	if (FALSE ==PurgeComm(hbox, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT)){
		CloseHandle(hbox);
	    hbox = INVALID_HANDLE_VALUE;
	}
	return 0;
}


线程接收数据处理数据


UINT CListenMasConComMsgDlg::RecvMasConComThread(LPVOID pParam)
{
	CListenMasConComMsgDlg *port = (CListenMasConComMsgDlg*)pParam;
	CString strRead = "";
	char    sn[20];
	int     state;
	CString num;

	while (1)
	{
        /*关闭exe线程自动退出资源自动释放*/
		strRead  =  port->read_iron_msg();
		if (!(strRead.CompareNoCase(_T("-1")) == 0)){			     
				   port->fun_write_log(_T("收到控制指令:")+strRead);			       
				   if (strRead.Find(_T("DEOPEN"))>=0){
						if (port->DEOpenBox() == 0) {
							port->fun_write_log(_T("打开设备抽屉成功"));
							port->send_iron_msg(_T("OPEN\r"));
						}
						else{
							port->fun_write_log(_T("打开设备抽屉失败"));
							port->send_iron_msg(_T("ERR\r"));
						}
					}
					else if (strRead.Find(_T("DECLOSE"))>=0){
						if(port->DECloseBox()==0){
							port->fun_write_log(_T("关闭设备抽屉成功"));
							port->send_iron_msg(_T("DECLOSED\r"));	
						}
						else{
							port->fun_write_log(_T("关闭设备抽屉失败"));
							port->send_iron_msg(_T("DEERR\r"));	
						}
					}
					else if (strRead.Find(_T("DEMODEL?"))>=0){
						    int len;
							if (port->iron_get_verion(sn, &len) == 0){
								sn[len] = '\0';
								num.Format(_T("%s"), sn);								
								port->fun_write_log(_T("测试设备编号 ")+num);
								port->send_iron_msg(num);
							}
					}
					else if (strRead.Find(_T("DEDOOR?"))>=0){
							state = port->iron_get_status();
							switch(state){
									case 0:
									port->fun_write_log(_T("获取设备抽屉状态成功:OPEN"));
									port->send_iron_msg(_T("OPEN\r"));									
									break;
									case 1:									
									port->fun_write_log(_T("获取设备抽屉状态成功:CLOSED"));
									port->send_iron_msg(_T("CLOSED\r"));
									break;
									case 2:
									port->fun_write_log(_T("获取设备抽屉状态成功:MID"));
									port->send_iron_msg(_T("MID\r"));									
									break;
									case -1:
									port->fun_write_log(_T("获取设备抽屉状态失败"));
									port->send_iron_msg(_T("ERR\r"));
									break;
							}
					}
					else {
							port->fun_write_log(_T("错误指令:")+strRead);
					}
				    strRead.Empty();
		}
		//Sleep(100);
	}
	return 0;
}

总结:我第一次给别人分析源码就是在初始化DCB结构体上出现了问题。希望今后我记住这个教训。

      那个朋友有这方面的需求联系我。我可以把源码给你 2499280350@qq.com



  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值