串口通讯项目

起因:
周一王老师给了我一个小项目,独立的小程序,用啥语言都行
可是当时我电脑硬盘坏了,啥东西都没有,就放了几天
今天想来就花些时间搞定它
一个从没玩过的方向独立做程序,内容涉及较多,总用时6个半小时。
涉及内容C++boost库配置 简单的mfc 简单的winform 串口通讯相关软件和资料 C#字符格式处理(这些我都不熟悉)
本篇博客是今天独立完成项目的完全过程,类似于日志,为的是以后遇到类似问题的时候可以节省时间。


0x00 boost配置

刚上手的时候看看需求,串口通讯相关的,就想起来以前做过的一个Box项目,里面用到过这些东西,就拿出来看看,不错,可以用,于是打算用MFC写一个,因为boost库被我弄没了,就打算再弄一个,想想再编译一个花太长时间了,就去网上找了一个编译好的1.55版本的,直接拿来用。
//boost 1.55已编译,已传到百度云http://pan.baidu.com/s/1gfxeXsZ
配置的话,点开项目,当前项目的属性,然后直接看图,改包含目录,和库目录,
包含目录就是整个的头文件所在的目录,比如#include “boost/format.hpp”,包含目录就是boost这个文件夹的上级目录,
库目录就是实现的cpp或者链接库所在的地方,总之这两个就是头文件在的地方和实现文件所在的地方。
结合下图理解
这里写图片描述


0x01 简单mfc小程序

搞定了,用MFC拖几个控件进去,弄个界面,然后发现自己不能改里面的内容,很是尴尬
想起来以前TCP老师好像做的时候加了变量什么的,于是去网上查一查。
才明白MFC是要加变量才能玩文本框控件。

这里写图片描述
如上图,添加一个 value型的 CString类型的变量,
我就可以对 结果右边那栏 的内容进行控制了。
于是我又添加了三个,顺便改了 他们的初始内容
例如这样:
这里写图片描述

tb1 tb2 tb3 tb4就是我给这些变量起的名字

会玩了变量,这个MFC就算入门了把,这个就算我一个MFC程序了。


0x02 串口通讯函数与软件

项目要求是打开串口并向串口发送数据
那么至少要实现这两个功能,可是我都不知道串口是个啥子,百度呗

通过百度我知道了这两个软件。
一个功能是 虚拟串口 另一个是 操作和查看串口传入传出的数据

这个东西可以让我知道 我的程序管不管用,因为第一个软件的功能是这样的
模拟两个虚拟串口,你可以打开他们,你可以并通过这个软件查看这两个串口的状态
最重要的是,这两个串口是连接的,意味着 其中一个串口发送消息,一定是另一个串口接受消息,
利用这一点,我们 测试的时候,用自己的软件打开第一个串口,发送消息,就可以通过第二个串口查看我们是否发送成功。程序是否成功了。

这里写图片描述
//这两个软件 百度云http://pan.baidu.com/s/1kU4Odkb

函数的话,用到了boost库
而且我调试的时候出了点问题还没有解决,所以我换成了C#来做

下面这俩可以不用看,因为C#实现更方便,毕竟语言只是工具,什么实用用什么。

实现文件

#include "stdafx.h"
//  COM.c//---------------------------------------------------------------------------
#pragma hdrstop
#include <stdio.h>

#include "MyNewCom_tt.h"

#include <string>

#include <boost/format.hpp>
using namespace std;
//---------------------------------------------------------------------------
#pragma package( smart_init)


//串口句柄
HANDLE m_COM_Handle = NULL;
//两个信号全局变量(串口操作用)
OVERLAPPED m_OverlappedRead, m_OverlappedWrite;


//*************************************************************************
//函 数 名:OpenCom
//输 入:long lngPort,串口号
// char *cfgMessage,配置信息,形如"9600,e,8,1" 
// long lngInSize,接收缓冲区大小
// long lngOutSize 发送缓冲区大小 
//输 出:long
//功能描述:打开串口
//全局变量:
//调用模块:
//作 者:叶帆
//日 期:2006年4月4日
//修 改 人:
//日 期:
//版本:
//*************************************************************************
long OpenCom(long nPort, char *cfgMessage, long lngInSize, long lngOutSize)
{
    try {
//      wchar_t szMsg[255];
        DCB dcb; //打开端口
        wstring sPort;

        if (nPort>9)
            sPort = (boost::wformat(L"\\\\.\\COM%d") % nPort).str();
        else
            sPort = (boost::wformat(L"COM%d") % nPort).str();

        m_COM_Handle = CreateFile((LPCSTR)sPort.c_str(),
            GENERIC_READ | GENERIC_WRITE,
            0, NULL, OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
            NULL);
        if (m_COM_Handle == NULL)
            return( 2 );
        //清空异步读写参数
        memset(&(m_OverlappedRead),
            0, sizeof
            (OVERLAPPED));
        memset(&(m_OverlappedWrite),
            0, sizeof
            (OVERLAPPED));
        //设置dcb块
        dcb.DCBlength   =   sizeof(DCB); //长度 
        GetCommState(m_COM_Handle, &dcb ); //波特率,奇偶校验,数据位,停止位如:9600, n, 8, 1 
        auto szMsg = (boost::wformat(L"COM%d:%s")%nPort%cfgMessage).str();
        BuildCommDCB((LPCSTR)szMsg.c_str(), &dcb);
            //------------------------------
            dcb.fBinary = TRUE;
            //二进制方式
            dcb.fOutxCtsFlow = FALSE;
            //不用CTS检测发送流控制
            dcb.fOutxDsrFlow = FALSE;
            //不用DSR检测发送流控制
            dcb.fDtrControl = DTR_CONTROL_DISABLE;
            //禁止DTR流量控制
            dcb.fDsrSensitivity = FALSE;
            //对DTR信号线不敏感
            dcb.fTXContinueOnXoff = TRUE;
            //检测接收缓冲区
            dcb.fOutX = FALSE;
            //不做发送字符控制
            dcb.fInX = FALSE;
            //不做接收控制
            dcb.fErrorChar = FALSE;
            //是否用指定字符替换校验错的字符
            dcb.fNull = FALSE;
            //保留NULL字符
            dcb.fRtsControl = RTS_CONTROL_ENABLE;
            //允许RTS流量控制
            dcb.fAbortOnError = FALSE;
            //发送错误后,继续进行下面的读写操作
            dcb.fDummy2 = 0;
            //保留 dcb.wReserved=0;
            //没有使用,必须为0
            dcb.XonLim = 0;
            //指定在XOFF字符发送之前接收到缓冲区中可允许的最小字节数
            dcb.XoffLim = 0;
            //指定在XOFF字符发送之前缓冲区中可允许的最小可用字节数
            dcb.XonChar = 0;
            //发送和接收的XON字符
            dcb.XoffChar = 0;
            //发送和接收的XOFF字符
            dcb.ErrorChar = 0;
            //代替接收到奇偶校验错误的字符
            dcb.EofChar = 0;
            //用来表示数据的结束
            dcb.EvtChar = 0;
            //事件字符,接收到此字符时,会产生一个事件
            dcb.wReserved1 = 0;
            //没有使用
            //
            dcb.BaudRate = 1200; //波特率
            //
            dcb.Parity=0;   //奇偶校验
            //
            dcb.ByteSize=8;
            //数据位 //dcb.StopBits=0;
            //停止位 //------------------------------
            if (dcb.Parity == 0 )
                //              0 - 4 = None, Odd, Even, Mark, Space
            {
                dcb.fParity = FALSE;
                //奇偶校验无效
            }
            else
            {
                dcb.fParity = TRUE; //奇偶校验有效
            }
            szMsg = (boost::wformat(L"COM%d:%d,%d,%d,%d(InSize:%ld, OutSize : %ld)")
                %nPort%dcb.BaudRate% dcb.Parity%dcb.ByteSize%dcb.StopBits%lngInSize%lngOutSize).str();
            //读写超时设置
            //西门子参数
            COMMTIMEOUTS CommTimeOuts; 
            CommTimeOuts.ReadIntervalTimeout = 20;
            SetCommTimeouts(m_COM_Handle, &CommTimeOuts);
            //获取信号句柄
            m_OverlappedRead.hEvent =CreateEvent(NULL,TRUE,FALSE,NULL); 
            m_OverlappedWrite.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
            if (!SetCommState(m_COM_Handle, &dcb)  //判断设置参数是否成功
                || !SetupComm(m_COM_Handle, lngInSize, lngOutSize) || //设置输入和输出缓冲区是否成功
                m_OverlappedRead.hEvent == NULL ||
                m_OverlappedWrite.hEvent == NULL)
            {
                DWORD dwError = GetLastError();
                //获取最后的错误信息
                if (m_OverlappedRead.hEvent != NULL) 
                    CloseHandle(m_OverlappedRead.hEvent); 
                if ( m_OverlappedWrite.hEvent != NULL) 
                    CloseHandle(m_OverlappedWrite.hEvent);
                CloseHandle(m_COM_Handle);
                m_COM_Handle = NULL; 
                return  dwError;
            } 
            return (0);
    }
    catch (...)
    {
        return -1;
    }
} //*************************************************************************
//函 数 名:CloseCom
//输 入:
//输出:long //功能描述:关闭串口
//全局变量:
//调用模块:
//作 者:叶帆
//日 期:2006年4月4日
//修 改 人:
//日 期:
//版本:
//*************************************************************************
long CloseCom()
{
    try {
        if (m_COM_Handle    ==NULL)
            return(1);
        SetCommMask(m_COM_Handle, NULL); SetEvent(m_OverlappedRead.hEvent);
        SetEvent(m_OverlappedWrite.hEvent); 
        if (m_OverlappedRead.hEvent != NULL) 
            CloseHandle(m_OverlappedRead.hEvent);
        if (m_OverlappedWrite.hEvent != NULL)
            CloseHandle(m_OverlappedWrite.hEvent);
        if (CloseHandle(m_COM_Handle) == FALSE)
            return (2);
        m_COM_Handle=NULL;
    }
    catch (...)
    {
        return(3);
    }
    return( 0);
}
//*************************************************************************
//函 数 名:SendData
//输 入:BYTE *bytBuffer,数据 
// long lngSize 个数
//输 出:long
//功能描述:发送数据
//全局变量:
//调用模块:
//作 者:叶帆
//日 期:2006年4月4日
//修 改 人:
//日 期:
//版本: //*************************************************************************
long SendData(uchar*bytBuffer, long lngSize)
{
    try {
        if (m_COM_Handle    ==  NULL)
            return( -1); 
        DWORD dwBytesWritten = lngSize;
        BOOL bWriteStat;
        COMSTAT ComStat; DWORD dwErrorFlags;
        ClearCommError(m_COM_Handle, &dwErrorFlags, &ComStat);
        bWriteStat = WriteFile(m_COM_Handle,bytBuffer, lngSize, &dwBytesWritten,
            &(m_OverlappedWrite));
        if (!bWriteStat) {
            if (GetLastError() == ERROR_IO_PENDING)
            {
                GetOverlappedResult(m_COM_Handle, &(m_OverlappedWrite), &dwBytesWritten, TRUE);
                //等待直到发送完毕
            }
            else
            {
                dwBytesWritten = 0;
            }
        }
        return  (long)dwBytesWritten;
    }
    catch (...)
    {
        return  -1;
    }
} //*************************************************************************
//函 数 名:AcceptData
//输 入:BYTE *bytBuffer,数据 
// long lngSize 个数
//输 出:long
//功能描述:读取数据
//全局变量:
//调用模块:
//作 者:叶帆
//日 期:2006年4月4日
//修 改 人:
//日 期:
//版本:
//*************************************************************************
long AcceptData(uchar *bytBuffer, long lngSize)
{
    try {
        if (m_COM_Handle == NULL)
            return( -1); 
        DWORD lngBytesRead = lngSize;
        BOOL fReadStat;
        DWORD dwRes = 0; 
        //读数据 
        fReadStat=ReadFile(m_COM_Handle,bytBuffer,lngSize,&lngBytesRead,&(m_OverlappedRead));
        //Sleep(1);
        if (!fReadStat) {
            if (GetLastError()==ERROR_IO_PENDING)
                //重叠 I/O 操作在进行中
            {
                dwRes = WaitForSingleObject(m_OverlappedRead.hEvent, 1000);
                //等待,直到超时
                switch (dwRes)
                {
                    case
                    WAIT_OBJECT_0:
                        //读完成 if(GetOverlappedResult(m_COM_Handle,&(m_OverlappedRead),&lngBytesRead,FALSE)==0)
                    { //错误
                        return -2; } break;
                    case
                    WAIT_TIMEOUT:
                        //超时 
                        return -1; break;
                    default:
                        //WaitForSingleObject错误
                        break;
                }
            }
        }
        return lngBytesRead;
    }
    catch (...)
    {
        return
            -1;
    }
} //*************************************************************************
//函 数名:ClearAcceptBuffer //输 入:
//输出:long //功能描述:清除接收缓冲区
//全局变量:
//调用模块:
//作 者:叶帆
//日 期:2006年4月4日
//修 改 人:
//日 期:
//版本: //*************************************************************************
long  ClearAcceptBuffer()
{
    try {
        if (m_COM_Handle == NULL)
            return( -1);
        PurgeComm(m_COM_Handle, PURGE_RXABORT | PURGE_RXCLEAR);
        //
    }
    catch (...)
    {
        return(1);
    }
    return(0);
} //*************************************************************************
//函 数 名:ClearSendBuffer //输 入:
//输出:long //功能描述:清除发送缓冲区
//全局变量:
//调用模块:
//作 者:叶帆
//日 期:2006年4月4日
//修 改 人:
//日 期:
//版本: 
//*************************************************************************
long  ClearSendBuffer()
{
    try {
        if (m_COM_Handle == NULL)
            return( -1);
        PurgeComm(m_COM_Handle, PURGE_TXABORT | PURGE_TXCLEAR);
        //
    }
    catch (...)
    {
        return (1);
    } 
    return (0);
}

头文件

//COM.h
#ifndef  COMH_WWQ
#define  COMH_WWQ
//#include "vcl.h"
#include <Windows.h>
#pragma package( smart_init)
#define uchar unsigned char
long  OpenCom(long, char *, long, long);
long CloseCom();
long SendData(uchar*, long);
long  AcceptData(uchar *bytBuffer, long);
long ClearAcceptBuffer();
long  ClearSendBuffer();



#endif

0x03 简单的winform程序

对于.net 我以前做数据结构课设的时候接触过,玩过两周的WPF,感觉真的简单,方便还漂亮。
winform还是一个程序都没写过。不过感觉差不多吧,就是丑了点 =v=。
同样的整个界面,拖控件。
这里写图片描述
比MFC方便的是这里不用添加变量。
每一个控件都是一个对象,它的所有属性和方法给用的都基本能用。
比如上图的控件,都有一个属性叫做Text,我们可以直接在后台代码修改Text来改界面里Text的值
比MFC方便不知道那里去了。
同样的是双击控件添加函数,对于Button控件就是点击触发,对于textbox就是改变值触发。

接下来就是串口相关的了。
首先整个全局变量 System.IO.Ports.SerialPort com1 = null;
然后这样

string Port = "com1";
com1 = new System.IO.Ports.SerialPort(Port);

就是弄了一个操作串口相关的对象了
接下来
就是打开
写串口数据
和关闭

com1.Open();
com1.Write("233");
com1.Close();

是不是超级简单。。封装好的东西就是这么用。。在VS2015下还有函数的中文提示,写不出来都难。


0x04

然后就是一个字符串处理相关的东西
用到了Convert这个类

直接上需求和我的解决代码
这里写图片描述

        int calccc(string[] send)
        {
            int cc = 0;
            foreach (string i in send) cc += Convert.ToInt32(i, 16);
            cc = (~cc) + 1;
            return cc;
        }
textBox2.Text = "000911";
string sendA = "A5 FF 08 1E";
string id = "";
foreach (int i in textBox2.Text)
    id += " " + Convert.ToString(i, 16);

string[] sendB = (sendA + id).Split(' ');
int cc = calccc(sendB);

string CC = Convert.ToString(cc, 16);
string send = sendA + id + " " + CC[CC.Length - 2] + CC[CC.Length - 1];
string[] sendC = send.Split(' ');

byte[] buff = new byte[11];
for (int i = 0; i < 11; ++i)
    buff[i] = (byte)Convert.ToInt32(sendC[i], 16);

com1.Write(buff, 0, 11);

总结:
感觉还可以,自己解决问题的思路还是没问题,每次都玩一个没玩过新领域,解决问题的能力还是比较强的,最近感受越来越深的是:知识总是有用的,只要学会了,早晚会用的到。
换句话说就是 多一份知识,多一条思路。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值