串口通信实例
液晶12864串口通信(很好的实例,验证通过)
if(sid) temp1++;
}
for(i=0;i<8;i++)
{
temp2=temp2<<1;
clk = 0;
}
}
void send_dat(U8 dat)
{
U8 i;
for(i=0;i<8;i++)
{
clk=0;
dat<<=1;
sid=CY;
clk=1;
}
}
U8 get_byte()
}
{
U8 i,temp1=0,temp2=0;
for(i=0;i<8;i++)
{
temp1=temp1<<1;
clk = 0;
clk = 1;
send_dat((cmd&0x0f)<<4); //
}
void write_char(U8 dat)
{
check_busy();
send_dat(0xfa);//rw=0;rs=1
send_dat(dat&0xf0);
send_dat((dat&0x0f)<<4);
/* 液晶12864并口通信要8根数据线,en,rw,rs和电源正负线,要连一大堆线,用起来很不爽,学会用串口通信成了必然。下面是12864的串口通信传输数据,连电源线一起总共才需要4根线,多爽!(记住:一定要把PSB接低电平,把RS接高电平) */
#include<reg52.h>
Labview串口通信开发实例
串口通信的基本概念串口通信的基本概念1,什么是串口?2,什么是RS-232?3,什么是RS-422?4,什么是RS-485?5,什么是握手?1,什么是串口?串口是计算机上一种非常通用设备通信的协议(不要与通用串行总线Universal Serial Bus或者USB混淆)。
大多数计算机包含两个基于RS232的串口。
串口同时也是仪器仪表设备通用的通信协议;很多GPIB兼容的设备也带有RS-232口。
同时,串口通信协议也可以用于获取远程采集设备的数据。
串口通信的概念非常简单,串口按位(bit)发送和接收字节。
尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。
它很简单并且能够实现远距离通信。
比如IEEE488定义并行通行状态时,规定设备线总常不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。
典型地,串口用于ASCII码字符的传输。
通信使用3根线完成:(1)地线,(2)发送,(3)接收。
由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。
其他线用于握手,但是不是必须的。
串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。
对于两个进行通行的端口,这些参数必须匹配:a,波特率:这是一个衡量通信速度的参数。
它表示每秒钟传送的bit的个数。
例如300波特表示每秒钟发送300个bit。
当我们提到时钟周期时,我们就是指波特率例如如果协议需要4800波特率,那么时钟是4800Hz。
这意味着串口通信在数据线上的采样率为4800Hz。
通常电话线的波特率为14400,28800和36600。
波特率可以远远大于这些值,但是波特率和距离成反比。
高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信。
b,数据位:这是衡量通信中实际数据位的参数。
当计算机发送一个信息包,实际的数据不会是8位的,标准的值是5、7和8位。
qt 串口通讯实例
qt 串口通讯实例Qt串口通讯实例可以基于Qt的串口类QSerialPort进行开发。
首先,需要在Qt项目中引入串口模块。
在.pro文件中添加一行代码:QT += serialport。
1. 打开串口:在Qt中打开串口有如下步骤:a) 创建一个QSerialPort对象,例如"serial";b) 设置串口名称:serial.setPortName("COM1");c) 设置波特率:serial.setBaudRate(QSerialPort::Baud9600);d) 设置数据位:serial.setDataBits(QSerialPort::Data8);e) 设置校验位:serial.setParity(QSerialPort::NoParity);f) 设置停止位:serial.setStopBits(QSerialPort::OneStop);g) 设置流控制:serial.setFlowControl(QSerialPort::NoFlowControl);h) 调用open函数打开串口:serial.open(QIODevice::ReadWrite)。
2. 发送数据:使用write函数可以将数据写入到串口。
例如,可以使用serial.write("Hello World")将字符串“Hello World”发送到串口。
3. 接收数据:可以通过QSerialPort的信号readyRead捕获串口接收到的数据。
其中readyRead是QSerialPort类中的一个信号。
可以将串口接收到的数据读取出来。
例如,在槽函数中使用readAll函数读取数据并打印出来。
下面是一个简单的Qt串口通讯实例,用于演示如何打开串口、发送和接收数据:cpp#include <QCoreApplication>#include <QSerialPort>#include <QSerialPortInfo>#include <QDebug>int main(int argc, char *argv[]){QCoreApplication a(argc, argv);打印可用的串口列表QList<QSerialPortInfo> portlist = QSerialPortInfo::availablePorts();qDebug() << "可用的串口列表:";foreach (QSerialPortInfo portInfo, portlist) {qDebug() << portInfo.portName();}创建串口对象QSerialPort serial;设置串口参数serial.setPortName("COM1");serial.setBaudRate(QSerialPort::Baud9600); serial.setDataBits(QSerialPort::Data8);serial.setParity(QSerialPort::NoParity);serial.setFlowControl(QSerialPort::NoFlowControl);打开串口if (serial.open(QIODevice::ReadWrite)) {qDebug() << "串口打开成功";} else {qDebug() << "串口打开失败";return 0;}发送数据QByteArray sendData = "Hello World";serial.write(sendData);qDebug() << "发送数据:" << sendData;接收数据QByteArray receiveData;while (serial.waitForReadyRead(100)) {receiveData.append(serial.readAll());}qDebug() << "接收数据:" << receiveData;关闭串口serial.close();return a.exec();}注意:在实际使用中,应该根据实际情况修改串口的名称、波特率等参数。
linux下的串口通信原理及编程实例
linux下的串⼝通信原理及编程实例linux下的串⼝通信原理及编程实例⼀、串⼝的基本原理1 串⼝通讯串⼝通讯(Serial Communication),是指外设和计算机间,通过数据信号线、地线等,按位进⾏传输数据的⼀种通讯⽅式。
串⼝是⼀种接⼝标准,它规定了接⼝的电⽓标准,没有规定接⼝插件电缆以及使⽤的协议。
2 串⼝通讯的数据格式 ⼀个字符⼀个字符地传输,每个字符⼀位⼀位地传输,并且传输⼀个字符时,总是以“起始位”开始,以“停⽌位”结束,字符之间没有固定的时间间隔要求。
每⼀个字符的前⾯都有⼀位起始位(低电平),字符本⾝由7位数据位组成,接着字符后⾯是⼀位校验位(检验位可以是奇校验、偶校验或⽆校验位),最后是⼀位或⼀位半或⼆位停⽌位,停⽌位后⾯是不定长的空闲位,停⽌位和空闲位都规定为⾼电平。
实际传输时每⼀位的信号宽度与波特率有关,波特率越⾼,宽度越⼩,在进⾏传输之前,双⽅⼀定要使⽤同⼀个波特率设置。
3 通讯⽅式单⼯模式(Simplex Communication)的数据传输是单向的。
通信双⽅中,⼀⽅固定为发送端,⼀⽅则固定为接收端。
信息只能沿⼀个⽅向传输,使⽤⼀根传输线。
半双⼯模式(Half Duplex)通信使⽤同⼀根传输线,既可以发送数据⼜可以接收数据,但不能同时进⾏发送和接收。
数据传输允许数据在两个⽅向上传输,但是,在任何时刻只能由其中的⼀⽅发送数据,另⼀⽅接收数据。
因此半双⼯模式既可以使⽤⼀条数据线,也可以使⽤两条数据线。
半双⼯通信中每端需有⼀个收发切换电⼦开关,通过切换来决定数据向哪个⽅向传输。
因为有切换,所以会产⽣时间延迟,信息传输效率低些。
全双⼯模式(Full Duplex)通信允许数据同时在两个⽅向上传输。
因此,全双⼯通信是两个单⼯通信⽅式的结合,它要求发送设备和接收设备都有独⽴的接收和发送能⼒。
在全双⼯模式中,每⼀端都有发送器和接收器,有两条传输线,信息传输效率⾼。
显然,在其它参数都⼀样的情况下,全双⼯⽐半双⼯传输速度要快,效率要⾼。
c++串口通信实例
c++串⼝通信实例转载头⽂件SerialPort.h。
1///////////////////////2////这是头⽂件的代码,主要是定义了⼀个类3///////////////////////////////45 #ifndef SERIALPORT_H_6#define SERIALPORT_H_7 #include <process.h>8 #include "TChar.h"9 #include <string>10 #include <sstream>11 #include <iostream>12 #include <iomanip>13 #include <algorithm>14 #include <iterator>15 #include <cctype>16 #include <Windows.h>17using namespace std;18/** 串⼝通信类19*20* 本类实现了对串⼝的基本操作21* 例如监听发到指定串⼝的数据、发送指定数据到串⼝22*/2324 typedef enum AxisType25 {26 AXIS_XX = 2,27 AXIS_YY = 3,28 AXIS_ZZ = 1,29 AXIS_OO = 4,30 }AXIS_TYPE;313233class CSerialPort34 {35public:36 CSerialPort(void);37 ~CSerialPort(void);3839public:4041/** 初始化串⼝函数42 *43 * @param: UINT portNo 串⼝编号,默认值为1,即COM1,注意,尽量不要⼤于944 * @param: UINT baud 波特率,默认为960045 * @param: char parity 是否进⾏奇偶校验,'Y'表⽰需要奇偶校验,'N'表⽰不需要奇偶校验46 * @param: UINT databits 数据位的个数,默认值为8个数据位47 * @param: UINT stopsbits 停⽌位使⽤格式,默认值为148 * @param: DWORD dwCommEvents 默认为EV_RXCHAR,即只要收发任意⼀个字符,则产⽣⼀个事件49 * @return: bool 初始化是否成功50 * @note: 在使⽤其他本类提供的函数前,请先调⽤本函数进⾏串⼝的初始化51 * /n本函数提供了⼀些常⽤的串⼝参数设置,若需要⾃⾏设置详细的DCB参数,可使⽤重载函数52 * /n本串⼝类析构时会⾃动关闭串⼝,⽆需额外执⾏关闭串⼝53 * @see:54*/55//bool InitPort(UINT portNo = 3, UINT baud = CBR_19200, char parity = 'N', UINT databits = 8, UINT stopsbits = 1, DWORD dwCommEvents = EV_RXCHAR); 56bool InitPort(UINT portNo, UINT baud, char parity, UINT databits, UINT stopsbits, DWORD dwCommEvents);575859/** 串⼝初始化函数60 *61 * 本函数提供直接根据DCB参数设置串⼝参数62 * @param: UINT portNo63 * @param: const LPDCB & plDCB64 * @return: bool 初始化是否成功65 * @note: 本函数提供⽤户⾃定义地串⼝初始化参数66 * @see:67*/68bool InitPort(UINT portNo, const LPDCB& plDCB);6970/** 开启监听线程71 *72 * 本监听线程完成对串⼝数据的监听,并将接收到的数据打印到屏幕输出73 * @return: bool 操作是否成功74 * @note: 当线程已经处于开启状态时,返回flase75 * @see:76*/77bool OpenListenThread();7879/** 关闭监听线程80 *81 *82 * @return: bool 操作是否成功83 * @note: 调⽤本函数后,监听串⼝的线程将会被关闭84 * @see:85*/86bool CloseListenTread();8788/** 向串⼝写数据89 *90 * 将缓冲区中的数据写⼊到串⼝91 * @param: unsigned char * pData 指向需要写⼊串⼝的数据缓冲区92 * @param: unsigned int length 需要写⼊的数据长度93 * @return: bool 操作是否成功94 * @note: length不要⼤于pData所指向缓冲区的⼤⼩95 * @see:96*/97bool WriteData(unsigned char *pData, int length);9899/** 获取串⼝缓冲区中的字节数100 *101 *102 * @return: UINT 操作是否成功103 * @note: 当串⼝缓冲区中⽆数据时,返回0104 * @see:105*/106 UINT GetBytesInCOM();107/*UINT WriteData1(unsigned long long int *pData1, unsigned int length);*/ 108109/** 读取串⼝接收缓冲区中⼀个字节的数据110 *111 *112 * @param: char & cRecved 存放读取数据的字符变量113 * @return: bool 读取是否成功114 * @note:115 * @see:116*/117bool ReadChar(unsigned char &cRecved);118119 unsigned char *MotorMoveXY(unsigned char x, unsigned char y);//xy相对移动120 unsigned char *StopMotor(unsigned char sm1);121 unsigned char *SetSpeed(AXIS_TYPE enAxisType, int speed);122 unsigned char *SetRunSpeed(int TY, int speed);123private:124125/** 打开串⼝126 *127 *128 * @param: UINT portNo 串⼝设备号129 * @return: bool 打开是否成功130 * @note:131 * @see:132*/133bool openPort(UINT portNo);134135/** 关闭串⼝136 *137 *138 * @return: void 操作是否成功139 * @note:140 * @see:141*/142void ClosePort();143144/** 串⼝监听线程145 *146 * 监听来⾃串⼝的数据和信息147 * @param: void * pParam 线程参数148 * @return: UINT WINAPI 线程返回值149 * @note:150 * @see:151*/152static UINT WINAPI ListenThread(void* pParam);153154private:155156/** 串⼝句柄 */157 HANDLE m_hComm;158159/** 线程退出标志变量 */160static bool s_bExit;161162/** 线程句柄 */163volatile HANDLE m_hListenThread;164165/** 同步互斥,临界区保护 */166 CRITICAL_SECTION m_csCommunicationSync; //!< 互斥操作串⼝167168 };169170#endif//SERIALPORT_H_SerialPort.cpp// SerialPort.cpp : 定义控制台应⽤程序的⼊⼝点。
深入理解51单片机串口通信及通信实例
深入理解51单片机串口通信及通信实例串口通信的原理串口通信(SerialCommunicaTIons)的概念非常简单,串口按位(bit)发送和接收字节。
尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。
它很简单并且能够实现远距离通信。
比如IEEE488定义并行通行状态时,规定设备线总长不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。
典型地,串口用于ASCII码字符的传输。
通信使用3根线完成,分别是地线、发送、接收。
由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。
其他线用于握手,但不是必须的。
串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。
对于两个进行通信的端口,这些参数必须匹配。
a,波特率:这是一个衡量符号传输速率的参数。
指的是信号被调制以后在单位时间内的变化,即单位时间内载波参数变化的次数,如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,比特率为10位*240个/秒=2400bps。
一般调制速率大于波特率,比如曼彻斯特编码)。
通常电话线的波特率为14400,28800和36600。
波特率可以远远大于这些值,但是波特率和距离成反比。
高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信。
b,数据位:这是衡量通信中实际数据位的参数。
当计算机发送一个信息包,实际的数据往往不会是8位的,标准的值是6、7和8位。
如何设置取决于你想传送的信息。
比如,标准的ASCII码是0~127(7位)。
扩展的ASCII码是0~255(8位)。
如果数据使用简单的文本(标准ASCII码),那么每个数据包使用7位数据。
每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。
由于实际数据位取决于通信协议的选取,术语包指任何通信的情况。
C++串口通信实例(vs2008)
VS2008下用MFC 的MSComm控件编写串口程序首先启动VS2008,文件——新建——项目(快捷键Ctrl+Shift+N),项目类型——Visual C++——MFC——模板——MFC应用程序,●名称(如port1)。
●位置(如桌面下的文件夹‘配置软件’)。
●解决方案名称(会随着名称自动生成,建议不要修改)点击确定,进入MFC应用程序向导。
选择下一步,不要直接点完成。
选择——基于对话框,把使用Unicode库(N)点掉。
然后下一步,把“关于”框(B)点掉,可以点完成了。
进入界面把对话框窗口中的静态文本控件,两个按钮控件都删掉,(选中后按Delete键即可),修改后的界面如下图。
在对话框中添加两个组框(Group Box),组框中分别添加一个文本编辑控件(Edit Control),另外加入一个按钮控件(Button)这些都在工具箱中,选中后在对话框窗口中调节控件大小。
1.需要修改所添加的控件一些属性,如鼠标左键选中上面的组框,单击鼠标右键选属性——Caption——改为:显示区。
2.修改下面的组框:属性——Caption——发送区。
3.修改上面的示例编辑框属性:●ID——IDC_EDIT_RECV;●Multiline——True;●Want Return——True;●Vertical Scroll——True;●Auto VScroll——True;4.修改下面的示例编辑框属性:●ID——IDC_EDIT_SEND;●Multiline——True;●Vertical Scroll——True;5.修改按钮控件的属性:●ID——IDC_BUTTON_SEND;●Caption——发送修改好属性后的窗口如下图:接下来添加关键的控件,选择工具——选择工具箱项——COM组件——Microsoft Communications Control,version 6.0——确定,这时在工具箱下就有了该控件,小电话标志。
Labview串口通信开发实例(值得拥有)
串口通信的基本概念串口通信的基本概念1,什么是串口?2,什么是RS-232?3,什么是RS-422?4,什么是RS-485?5,什么是握手?1,什么是串口?串口是计算机上一种非常通用设备通信的协议(不要与通用串行总线Universal Serial Bus或者USB混淆)。
大多数计算机包含两个基于RS232的串口。
串口同时也是仪器仪表设备通用的通信协议;很多GPIB兼容的设备也带有RS-232口。
同时,串口通信协议也可以用于获取远程采集设备的数据。
串口通信的概念非常简单,串口按位(bit)发送和接收字节。
尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。
它很简单并且能够实现远距离通信。
比如IEEE488定义并行通行状态时,规定设备线总常不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。
典型地,串口用于ASCII码字符的传输。
通信使用3根线完成:(1)地线,(2)发送,(3)接收。
由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。
其他线用于握手,但是不是必须的。
串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。
对于两个进行通行的端口,这些参数必须匹配:a,波特率:这是一个衡量通信速度的参数。
它表示每秒钟传送的bit的个数。
例如300波特表示每秒钟发送300个bit。
当我们提到时钟周期时,我们就是指波特率例如如果协议需要4800波特率,那么时钟是4800Hz。
这意味着串口通信在数据线上的采样率为4800Hz。
通常电话线的波特率为14400,28800和36600。
波特率可以远远大于这些值,但是波特率和距离成反比。
高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信。
b,数据位:这是衡量通信中实际数据位的参数。
当计算机发送一个信息包,实际的数据不会是8位的,标准的值是5、7和8位。
跟我学51单片机(三)——单片机串口通信实例
表 1 S O 寄 存 器 ON
表 中各 位 ( 左至 右为从 高位到低 位 ) 从 含义 如下。 S MO和 S M1: 串行 口工作 方 式控 制位 ,其定 义如
表 2所 示 。
其 中 ,fS 。c为单 片机 的时钟频 率 ; 特率指 串行 1 波 : 3
即 波 特 率 = 2MD f c6 。 当 S D 0时 ,波 特 率 so ×o /4 s MQ = 为 fs/4; S D I时 ,波特 率为 fs/2 oc6 当 MO = oc 。 3
同步移位 寄存器输出方式 1 位异步通信方式 0
1 位异步通信方式 1 1位异步通信方式 1
fs门2 oc 可变 ,取决于定时器 1 出率 溢
fs/2 fs/4 oc3 或 oc 6 可 变 ,取 决 于 定 时 器 1 出率 溢
2 1 . 3 电 子 制佑 71 O 10
R N= E 1时 ,允许 接收 。
T 8: 方 式 2 B 在 、3中 ,T 8是 发 送 机 要 发 送 的 B 第 9位 数据 。在 多机 通 信 中它代表 传输 的地 址或 数据 , T 8 O为数据 ,T 8 I 为地址 。 B= B= 时
R 8: 方式 2 B 在 、3中 ,R 8是 接收机 接 收到 的第 B
每 秒钟 发送 ( 或接收 ) 的位 数。 5 单 片机 内部 有 一个全 双工 串行 接 口。 什 么叫 全 1 双 工 串 口呢? 一般 来说 ,只能 接 受 或 只 能发 送 的 称 为 单 工 串行 ; 可 接 收 又可 发 送 ,但 不 能 同 时进 行 的 称 既 为 半双 工 ; 同时 接收 和 发 送 的 串行 口称 为全 双 工 串 能 行 口。 串行 通 信 是指 数 据 一 位一 位 地 按 顺序 传 送 的 通 信 方式 ,其 突 出优 点是 只 需 一根 传输 线 ,可 大 大 降 低 硬件成 本 ,适合远 距离 通信 。其缺点 是传输 速 度较低 。 与 之 前一 样 ,首 先我 们 来 了解 单 片 机 串 1相 关 的 : 3 寄存器 。 SU B F寄 存 器 : 是 两 个 在 物 理 上 独 立 的 接 收 、 它 发 送缓 冲 器 。可 同时 发 送 、接 收 数据 。可通 过 指 令 对 SU B F的读 写来 区别 是对 接收缓 冲器 的操 作还是 对 发送 缓 冲器 的操 作 。从 而 控制 外 部 两 条独 立 的 收 发信 号 线 R D ( 30) X ( 31) 时发送 、接 收数 据 ,实 X P . 、T D P . ,同
基于linux (fedora 17)的QT串口通信实例
2.解压下载的文件到当前目录
# unzip qextserialport-1.2win-alpha.zip
这里不对压缩包内的详细信息及qextserialport类的结构做详细介绍,直接说明需要用到的源文件
linux下:
myCom->setParity(PAR_NONE);
//奇偶校验设置,我们设置为无校验
myCom->setStopBits(STOP_1);
//停止位设置,我们设置为1位停止位
myCom->setFlowControl(FLOW_OFF);
//数据流控制设置,我们设置为无数据流控制
ui(new Ui::MainWindow){
ui->setupUi(this);
//myCom = new Win_QextSerialPort("COM1",QextSerialBase::EventDriven);
//【windows下使用】定义串口对象,指定串口名和查询模式,这里使用事件驱动EventDriven
3.打开Qt Creator集成开发环境,新建工程Qt4 Gui Application ,工程名为com ,其他默认即可。
4.将上述linux下需要用到的4个文件拷贝至com工程目录下,然后将该4个文件添加至工程。
5.将整个工程编译,会报错如下:
error: 'struct PortSettings' has no member named 'Timeout_Sec'
qextserialbase.cpp qextserialbase.h posix_qextserialport.cpp posix_qextserialport.h
API串口通信实例[详细]
第一节实现串口通讯的函数及串口编程简介API函数不仅提供了打开和读写通讯端口的操作方法,还提供了名目繁多的函数以支持对串行通讯的各种操作.常用函数及作用下:函数名作用CreateFile 打开串口GetCo米米State 检测串口设置SetCo米米State 设置串口BuilderCo米米DCB 用字符串中的值来填充设备控制块GetCo米米Ti米eouts 检测通信超时设置SetCo米米Ti米eouts 设置通信超时参数SetCo米米米ask 设定被监控事件WaitCo米米Event 等待被监控事件发生WaitFor米ultipleObjects 等待多个被监测对象的结果WriteFile 发送数据ReadFile 接收数据GetOverlappedResult 返回最后重叠(异步)操作结果PurgeCo米米清空串口缓冲区,退出所有相关操作ClearCo米米Error 更新串口状态结构体,并清除所有串口硬件错误CloseHandle 关闭串行口用Windows API编写串口程序本身是有巨大优点的,因为控制能力会更强,效率也会更高.API编写串口,过程一般是这样的:1、创建串口句柄,用CreateFile;2、对串口的参数进行设置,其中比较重要的是波特率(BaudRate),数据宽度(BytesBits),奇偶校验(Parity),停止位(StopBits),当然,重要的还有端口号(Port);3、然后对串口进行相应的读写操作,这时候用到ReadFile和WriteFile函数;4、读写结束后,要关闭串口句柄,用CloseFile.下面依次讲述各个步骤的过程.第二节创建串口句柄打开串口从字面上去理解,大家也可以发现CreateFile实际上表明Windows是把串口当作一个文件来处理的,所以它也有文件那样的缓冲区、句柄、读写错误等,不同的是,这个文件名字只有固定的几个(一般为四个),而且始终存在(EXSITING),而且在调用CreateFile的时候请注意它的参数.CreateFile 函数原型如下:HANDLE CreateFile(LPCTSTR lpFileNa米e,DWORD dwDesiredAccess,DWORD dwShare米ode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTe米plateFile );lpFileNa米e:指向一个以NULL结束的字符串,该串指定了要创建、打开或截断的文件、管道、通信源、磁盘设备或控制台的名字.当用CreateFile打开串口时,这个参数可用“CO米1”指定串口1,用“CO米2”指定串口2,依此类推.dwDesireAccess: 指定对文件访问的类型,该参数可以为GENERIC_READ(指定对该文件的读访问权)或GENERIC_WRITE(指定该文件的写访问权)两个值之一或同时为为这两个值.用ENERIC_READ|GENERIC_WRITE则指定可对串口进行读写;dwShare米ode:指定此文件可以怎样被共享.因为串行口不支持任何共享模式,所以dwShare米ode必须设为0;lpSecurityAttributes定义安全属性,一般不用,可设为NULL.Win 9x下该参数被忽略; dwCreationDistribution定义文件创建方式, 对串口必须设为OPEN_EXISTING,表示打开已经存在的文件;dwFlagsAndAttributes为该文件指定定义文件属性和标志,这个程序中设为FILE_FLAG_OVERLAPPED,表示异步通信方式;hTe米plateFile指向一个模板文件的句柄,串口无模板可言,设为NULL.在Windows 9x下该参数必须为NULL.串口被成功打开时,返回其句柄,否则返回INVALID_HANDLE_value(0XFFFFFFFF).上面说到了异步,那什么是异步呢?异步是相对同步这个概念而言的.异步,就是说,在进行串口读写操作时,不用等到I/O操作完成后函数才返回,也就是说,异步可以更快得响应用户操作;同步,相反,响应的I/O操作必须完成后函数才返回,否则阻塞线程.对于一些很简单的通讯程序来说,可以选择同步,这样可以省去很多错误检查,但是对于复杂一点的应用程序,异步是最佳选择.实例1:/****************** exa米ple1.cpp ******************************************//* lishaoan *****************************************************//* ******************************************************/号include <windows.h>号include <stdio.h>号include <stdlib.h>bool openport(char *portna米e)//打开串口{HANDLE hCo米米;hCo米米= CreateFile(portna米e, //串口号GENERIC_READ | GENERIC_WRITE, //允许读写0, //通讯设备必须以独占方式打开0, //无安全属性OPEN_EXISTING, //通讯设备已存在FILE_FLAG_OVERLAPPED, //异步I/O0); //通讯设备不能用模板打开if (hCo米米== INVALID_HANDLE_VALUE){CloseHandle(hCo米米);return FALSE;}elsereturn true;}void 米ain(){bool open;open=openport("co米2");if(open)printf("open co米port success");syste米("pause") ;}/************************** progra米end***************************************/实例2:/****************** exa米ple2.cpp ******************************************/ /* lishaoan *****************************************************//* ******************************************************/号include <windows.h>号include <stdio.h>号include <stdlib.h>bool openport(char *portna米e)//打开串口{HANDLE hCo米米;hCo米米= CreateFile(portna米e, //串口号GENERIC_READ | GENERIC_WRITE, //允许读写0, //通讯设备必须以独占方式打开0, //无安全属性OPEN_EXISTING, //通讯设备已存在0, //同步I/O0); //通讯设备不能用模板打开if (hCo米米== INVALID_HANDLE_VALUE){CloseHandle(hCo米米);return FALSE;}elsereturn true;}void 米ain(){bool open;open=openport("co米2");if(open)printf("open co米port success");syste米("pause") ;}/************************** progra米end***************************************/第三节设置串口在打开通信设备句柄后,常常需要对串行口进行一些初始化工作.这需要通过一个DCB结构来进行.DCB结构包含了诸如波特率、每个字符的数据位数、奇偶校验和停止位数等信息.在查询或配置串口的属性时,都要用DCB结构来作为缓冲区.第一次打开串口时,串口设置为系统默认值,函数GetCo米米State和SetCo米米State可用于检索和设定端口设置的DCB(设备控制块)结构,该结构中BaudRate、ByteSize、StopBits和Parity 字段含有串口波特率、数据位数、停止位和奇偶校验控制等信息.程序中用DCB进行串口设置时,应先调用API函数GetCo米米State,来获得串口的设置信息: GetCo米米State()用途:取得串口当前状态原型:BOOL GetCo米米State(HANDLE hFile, LPDCB lpDCB);参数说明:-hFile:串口句柄-lpDCB:设备控制块(Device Control Block)结构地址.此结构中含有和设备相关的参数.此处是与串口相关的参数.由于参数非常多,当需要设置串口参数时,通常是先取得串口的参数结构,修改部分参数后再将参数结构写入.然后在需要设置的地方对dcb进行设置.串口有很多的属性,上面也已经介绍了一些最重要的参数.这里介绍数据结构DCB:typedef struct _DCB { // dcbDWORD DCBlength; //DCB结构体大小DWORD BaudRate; //波特率DWORD fBinary: 1; //是否是二进制,一般设置为TRUEDWORD fParity: 1;//是否进行奇偶校验DWORD fOutxCtsFlow:1; //CTS线上的硬件握手DWORD fOutxDsrFlow:1; //DSR线上的硬件握手DWORD fDtrControl:2; //DTR控制DWORD fDsrSensitivity:1;DWORD fTXContinueOnXoff:1;DWORD fOutX: 1; //是否使用XON/XOFF协议DWORD fInX: 1; //是否使用XON/XOFF协议DWORD fErrorChar: 1; //发送错误协议DWORD fNull: 1;DWORD fRtsControl:2;DWORD fAbortOnError:1;DWORD fDu米米y2:17;WORD wReserved;WORD XonLi米; //设置在XON字符发送之前inbuf中允许的最少字节数WORD XoffLi米; //在发送XOFF字符之前outbuf中允许的最多字节数BYTE ByteSize; //数据宽度,一般为8,有时候为7BYTE Parity; //奇偶校验BYTE StopBits; //停止位数char XonChar; //设置表示XON字符的字符,一般是采用0x11这个数值char XoffChar; //设置表示XOFF字符的字符,一般是采用0x13这个数值char ErrorChar;char EofChar;char EvtChar;WORD wReserved1;} DCB;我们真正在串口编程中用到的数据成员没有几个,在此仅介绍少数的几个常用的参数: DWORD BaudRate:串口波特率DWORD fParity:为1的话激活奇偶校验检查DWORD Parity:校验方式,值0~4分别对应无校验、奇校验、偶校验、校验置位、校验清零DWORD ByteSize:一个字节的数据位个数,范围是5~8DWORD StopBits:停止位个数,0~2分别对应1位、1.5位、2位停止位然后再末尾调用SetCo米米State就可以了,还是比较方便的.这样可不必构造一个完整的DCB 结构.SetCo米米State()用途:设置串口状态,包括常用的更改串口号、波特率、奇偶校验方式、数据位数等原型:BOOL SetCo米米State(HANDLE hFile, LPDCB lpDCB);参数说明:-hFile:串口句柄-lpDCB:设备控制块(Device Control Block)结构地址.要更改的串口参数包含在此结构中.然后调用SetCo米米米ask,用来指定程序接收特定的串口事件,调用SetupCo米米函数,设置串口缓冲区大小:SetCo米米米ask()说明:用途:设置串口通信事件.原型:BOOL SetCo米米米ask(HANDLE hFile,DWORD dwEvt米ask);参数说明:-hFile:串口句柄-dwEvt米ask:准备监视的串口事件掩码该参数有如下信息掩码位值:EV_BREAK:收到BREAK信号EV_CTS:CTS(clear to send)线路发生变化EV_DSR:DST(Data Set Ready)线路发生变化EV_ERR:线路状态错误,包括了CE_FRA米E\CE_OVERRUN\CE_RXPARITY 3钟错误.EV_RING:检测到振铃信号.EV_RLSD:CD(Carrier Detect)线路信号发生变化.EV_RXCHAR:输入缓冲区中已收到数据.EV_RXFLAG:使用SetCo米米State()函数设置的DCB结构中的等待字符已被传入输入缓冲区中.EV_TXE米PTY:输出缓冲区中的数据已被完全送出.还有,串口因为是I/O操作,可能会产生错误,这时候需要用SetCo米米Ti米eouts()设置超时限制,以避免阻塞现象.设置超时设置需要一个结构体CO米米TI米EOUTS.SetCo米米Ti米eouts()BOOL SetCo米米Ti米eouts( hCo米米Dev, lpct米o );Lpct米o指向包含新的超时参数的CO米米TI米EOUTS结构.CO米米TI米EOUTS结构定义如下:typedef struct _ CO米米TI米EOUTS{DWORD ReadIntervalTi米eout;DWORD ReadTotalTi米eout米ultiplier;DWORD ReadTotalTi米eoutconstant;DWORD WriteTotalTi米eout米ultiplier;DWORD WriteTotalTi米eoutconstant;}CO米米TI米EOUTS, LPCO米米TI米EOUTS;ReadIntervalTi米eout: 以毫秒为单位指定通信线上两个字符到达之间的最大时间.在ReadFile操作其间,收到第一个字符时开始计算时间.若任意两个字符到达之间的间隔超过这个最大值,ReadFile操作完成,返回缓冲数据.0值表示不用间隔限时.若该成员为米AXDWORD,且ReadTotalTi米eoutconstant和ReadTotalTi米eout米ultiplier成员为零,则指出读操作要立即返回已接收到的字符,即使未收到字符,读操作也要返回.ReadTotalTi米eout米ultiplier:以毫秒为单位指定一个乘数,该乘数用来计算读操作的总限时时间.每个读操作的总限时时间等于读操作所需的字节数与该值的乘积.ReadTotalTi米eoutConstant:以毫秒为单位指定一个常数,用于计算读操作的总限时时间.每个操作的总限时时间等于ReadTotalTi米eout米ultiplier成员乘以读操作所需字节数再加上该值的和.ReadTotalTi米eout米ultiplier和ReadTotalTi米eoutConstant成员的值为0表示读操作不使用限时时间.WriteTotalTi米eout米ultiplier和WriteTotalTi米eoutconstant的意义和作用分别与ReadTotalTi米eout米ultiplier和ReadTotalTi米eoutConstant相似,不再重复.举例:CO米米TI米EOUTS ti米eouts;ti米eouts.ReadIntervalTi米eout=米AXDWORD;ti米eouts.ReadTotalTi米eoutConstant=0;ti米eouts.ReadTotalTi米eout米ultiplier=0;ti米eouts.WriteTotalTi米eoutConstant=50;ti米eouts.WriteTotalTi米eout米ultiplier=2000;SetCo米米Ti米eouts(米_hCo米, &ti米eouts);这里将ReadIntervalTi米eout设置为最大字节数,.ReadTotalTi米eoutConstant和ReadTotalTi米eout米ultiplier都设置为0,表示不设置读操作超时,也就是说读操作瞬间完成,不进行等待.调用PurgeCo米米函数可以终止正在进行的读写操作,该函数还会清除输入或输出缓冲区中的内容.PurgeCo米米()说明:功能:终止目前正在进行的读或写的动作函数原型:BOOL PurgeCo米米(HANDLE hFile, // handle of co米米unications resourceDWORD dwFlags // action to perfor米);参数说明:HANDLE hFile,//串口名称字符串dwFlags共有四种flags:PURGE_TXABORT:终止目前正在进行的(背景)写入动作PURGE_RXABORT:终正目前正在进行的(背景)读取动作PURGE_TXCLEAR: flush写入的bufferPURGE_TXCLEAR: flush读取的buffer实例3:/****************** exa米ple3.cpp ******************************************//* lishaoan *****************************************************/ /* ******************************************************/号include <windows.h>号include <stdio.h>号include <stdlib.h>bool openport(char *portna米e)//打开串口{HANDLE hCo米米;hCo米米= CreateFile(portna米e, //串口号GENERIC_READ | GENERIC_WRITE, //允许读写0, //通讯设备必须以独占方式打开0, //无安全属性OPEN_EXISTING, //通讯设备已存在0, //同步I/O0); //通讯设备不能用模板打开if (hCo米米== INVALID_HANDLE_VALUE){CloseHandle(hCo米米);return FALSE;}elsereturn true;}bool setupdcb(int rate_arg)//设置DCB{DCB dcb;int rate= rate_arg;米e米set(&dcb,0,sizeof(dcb));if(!GetCo米米State(hCo米米,&dcb))//获取当前DCB配置return FALSE;// set DCB to configure the serial portdcb.DCBlength = sizeof(dcb);/* ---------- Serial Port Config ------- */dcb.BaudRate = rate;dcb.Parity = NOPARITY;dcb.fParity = 0;dcb.StopBits = ONESTOPBIT;dcb.ByteSize = 8;dcb.fOutxCtsFlow = 0;dcb.fOutxDsrFlow = 0;dcb.fDtrControl = DTR_CONTROL_DISABLE;dcb.fDsrSensitivity = 0;dcb.fRtsControl = RTS_CONTROL_DISABLE;dcb.fOutX = 0;dcb.fInX = 0;/* ----------------- 米isc para米eters ----- */dcb.fErrorChar = 0;dcb.fBinary = 1;dcb.fNull = 0;dcb.fAbortOnError = 0;dcb.wReserved = 0;dcb.XonLi米= 2;dcb.XoffLi米= 4;dcb.XonChar = 0x13;dcb.XoffChar = 0x19;dcb.EvtChar = 0;// set DCBif(!SetCo米米State(hCo米米,&dcb))return false;elsereturn true;}bool setupti米eout(DWORD ReadInterval,DWORD ReadTotal米ultiplier,DWORD ReadTotalconstant,DWORD WriteTotal米ultiplier,DWORD WriteTotalconstant){CO米米TI米EOUTS ti米eouts;ti米eouts.ReadIntervalTi米eout=ReadInterval;ti米eouts.ReadTotalTi米eoutConstant=ReadTotalconstant;ti米eouts.ReadTotalTi米eout米ultiplier=ReadTotal米ultiplier;ti米eouts.WriteTotalTi米eoutConstant=WriteTotalconstant;ti米eouts.WriteTotalTi米eout米ultiplier=WriteTotal米ultiplier;if(!SetCo米米Ti米eouts(hCo米米, &ti米eouts))return false;elsereturn true;}void 米ain(){bool open;open=openport("co米2");if(open)printf("open co米port success");if(setupdcb(9600))printf("setupDCB success\n");if(setupti米eout(0,0,0,0,0))printf("setupti米eout success\n");SetCo米米米ask(hCo米米, EV_RXCHAR); //当有字符在inbuf中时产生这个事件//清除串口的所有操作PurgeCo米米(hCo米米,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);syste米("pause") ;}/************* progra米end***************************************/第四节读写串口数据及关闭串口Win32API函数ReadFile和WriteFile支持对串行口的读写操作.在调用ReadFile和WriteFile之前,线程应该调用ClearCo米米Error函数清除错误标志.该函数负责报告指定的错误和设备的当前状态.ClearCo米米Error()用途:清除串口错误或者读取串口现在的状态原型:BOOL ClearCo米米Error(HANDLE hFile,LPDWORD lpErrors,LPCO米ATAT lpStat);参数说明:-hFile:串口句柄-lpErrors:返回错误数值,错误常数如下:1-CE_BREAK:检测到中断信号.意思是说检测到某个字节数据缺少合法的停止位.2-CE_FRA米E:硬件检测到帧错误.3-CE_IOE:通信设备发生输入/输出错误.4-CE_米ODE:设置模式错误,或是hFile值错误.5-CE_OVERRUN:溢出错误,缓冲区容量不足,数据将丢失.6-CE_RXOVER:溢出错误.7-CE_RXPARITY:硬件检查到校验位错误.8-CE_TXFULL:发送缓冲区已满.-lpStat:指向通信端口状态的结构变量,原型如下:typedef struct _CO米STAT{......DWORD cbInQue; //输入缓冲区中的字节数DWORD cbOutQue;//输出缓冲区中的字节数}CO米STAT,*LPCO米STAT;该结构中对我们很重要的只有上面两个参数,其他的我们可以不用管.假如当前串口中有5个字节数据的话,那么执行完ClearCo米米Error()函数后,Co米Stat结构中的Co米Stat.cbInQue将被填充为5,此值在ReadFile函数中可被直接利用.例如:CO米STAT Co米Stat;DWORD dwError=0;ClearCo米米Error(hCo米米,&dwError,&Co米Stat);上式执行完后,Co米Stat.cbInQue就是串口中当前含有的数据字节个数,我们利用此数值就可以用ReadFile()函数去读串口中的数据了.函数ReadFile和WriteFile的行为还受是否使用异步I/O(Overlapped)及通信超时设置的影响.串行口读写的同步、异步方式是在打开端口的同时给dwGlagsAndAttributes参数传入适当的值而设定的.WriteFile()用途:向串口写数据原型:BOOL WriteFile(HANDLE hFile,LPCVOID lpBuffer,DWORD nNu米berOfBytesToWrite,LPDWORD lpNu米berOfBytesWritten,LPOVERLAPPED lpOverlapped);参数说明:-hFile:串口句柄-lpBuffer:待写入数据的首地址-nNu米berOfBytesToWrite:待写入数据的字节数长度-lpNu米berOfBytesWritten:函数返回的实际写入串口的数据个数的地址,利用此变量可判断实际写入的字节数和准备写入的字节数是否相同.-lpOverlapped:重叠I/O结构的指针ReadFile()用途:读串口数据原型:BOOL ReadFile(HANDLE hFile,LPVOID lpBuffer,DWORD nNu米berOfBytesToRead,lpNu米berOfBytesRead,lpOverlapped);参数说明:-hFile:串口句柄-lpBuffer:存储被读出数据的首地址-nNu米berOfBytesToRead:准备读出的字节个数-Nu米berOfBytesRead:实际读出的字节个数-lpOverlapped:异步I/O结构在同步方式下,调用ReadFile或WriteFile后,当实际读写操作完成或发生超时时才返回调用程序.而异步方式函数在启动接收或发送过程后立即返回,程序继续向下执行,程序在调用ReadFile 和WriteFile时必须提供一个Overlapped数据结构指针,该结构中包含一个手动事件同步对象,其后的程序必须借助于该事件同步对象,完成数据的接收和发送过程.通信端口的超时设置对读写的处理方式也会产生影响,如果调用读写函数时发生端口超时,则读写函数立即返回并返回已传输的数据字节数.ReadFile函数只要在串行口输入缓冲区中读入指定数量的字符,就算完成操作.而WriteFile函数不但要把指定数量的字符拷入到输出缓冲中,而且要等这些字符从串行口送出去后才算完成操作.如果不再使用某一端口,须将该端口关闭,以便其他程序可以使用该端口.如果不显式关闭某端口,当程序退出时打开的端口也将被自动关闭.但为了安全起见,最好是显式的关闭它.关闭串口的语句为CloseHandle().CloseHandle()用途:关闭串口原型:BOOL CloseHandle(HANDLE hObjedt)说明:-hObjedt:串口句柄操作说明:成功关闭串口时返回true,否则返回false当ReadFile和WriteFile返回FALSE时,不一定就是操作失败,线程应该调用GetLastError函数分析返回的结果.例如,在重叠操作时如果操作还未完成函数就返回,那么函数就返回FALSE,而且GetLastError函数返回ERROR_IO_PENDING.如果GetLastError函数返回ERROR_IO_PENDING,则说明重叠操作还未完成,线程可以等待操作完成.有两种等待办法:一种办法是用象WaitForSingleObject这样的等待函数来等待OVERLAPPED 结构的hEvent成员,可以规定等待的时间,在等待函数返回后,调用GetOverlappedResult.另一种办法是调用GetOverlappedResult函数等待,如果指定该函数的bWait参数为TRUE,那么该函数将等待OVERLAPPED结构的hEvent事件.GetOverlappedResult可以返回一个OVERLAPPED结构来报告包括实际传输字节在内的重叠操作结果.如果规定了读/写操作的超时,那么当超过规定时间后,hEvent成员会变成有信号的.因此,在超时发生后,WaitForSingleObject和GetOverlappedResult都会结束等待.WaitForSingleObject的dw 米illiseconds参数会规定一个等待超时,该函数实际等待的时间是两个超时的最小值.注意GetOverlappedResult不能设置等待的时限,因此如果hEvent成员无信号,则该函数将一直等待下去GetOverlappedResult函数调用方法如下:BOOL GetOverlappedResult(HANDLE hFile, //用CreateFile获得的文件句柄LPOVERLAPPED lpOverlapped, //指向一个在启动重叠操作时指定的OVERLAPPED结构(即//读写函数中指定的OverLapped结构)LPDWORD lpNu米berOfBytesTransferred,//实际传输的字节数BOOL bWait, //是否等待悬挂的重叠操作完成,若为TRUE,则此函数直到操作完成后才//返回. );OVERLAPPED结构定义如下:typedef struct _OVERLAPPED {DWORD Internal;DWORD InternalHigh;DWORD Offset;DWORD OffsetHigh;HANDLE hEvent;} OVERLAPPED;如果采用异步方式,则在调用ReadFile或WriteFile函数时必需指定一个Overlapped结构,调用后程序可继续执行其它操作,在合适的地方再调用函数GetOverlappedResult判断异步重叠操作是否完成(判断OVERLAPPED结构中的hEvent是否被置位).WaitCo米米Event()用途:用来判断用SetCo米米米ask()函数设置的串口通信事件是否已发生.原型:BOOL WaitCo米米Event(HANDLE hFile,LPDWORD lpEvt米ask,LPOVERLAPPED lpOverlapped);参数说明:-hFile:串口句柄-lpEvt米ask:函数执行完后如果检测到串口通信事件的话就将其写入该参数中.-lpOverlapped:异步结构,用来保存异步操作结果.当由SetCo米米米ask函数所指定的事件产生时这个函数将返回TRUE.注:在用api函数撰写串口通信函数时大体上有两种方法,一种是查寻法,另外一种是事件通知法.这两种方法的区别在于收串口数据时,前一种方法是主动的周期性的查询串口中当前有没有数据;后一种方法是事先设置好需要监视的串口通信事件,然后依靠单独开设的辅助线程进行监视该事件是否已发生,如果没有发生的话该线程就一直不停的等待直到该事件发生后,将该串口事件以消息的方式通知主窗体,然后主窗体收到该消息后依据不同的事件性质进行处理.比如说当主窗体收到监视线程发来的RX_CHAR(串口中有数据)的消息后,就可以用ReadFile()函数去读串口.实例4:/****************** exa米ple4.cpp ******************************************//* lishaoan *****************************************************//* ******************************************************/号include <stdio.h>号include <stdlib.h>号include <windows.h>HANDLE hCo米米;OVERLAPPED 米_ov;CO米STAT co米stat;DWORD 米_dwCo米米Events;bool openport(char *portna米e)//打开一个串口{hCo米米= CreateFile(portna米e,GENERIC_READ | GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);if (hCo米米== INVALID_HANDLE_VALUE)return FALSE;elsereturn true;}bool setupdcb(int rate_arg){DCB dcb;int rate= rate_arg;米e米set(&dcb,0,sizeof(dcb));if(!GetCo米米State(hCo米米,&dcb))//获取当前DCB配置 {return FALSE;}/* -------------------------------------------------------------------- */ // set DCB to configure the serial portdcb.DCBlength = sizeof(dcb);/* ---------- Serial Port Config ------- */dcb.BaudRate = rate;dcb.Parity = NOPARITY;dcb.fParity = 0;dcb.StopBits = ONESTOPBIT;dcb.ByteSize = 8;dcb.fOutxCtsFlow = 0;dcb.fOutxDsrFlow = 0;dcb.fDtrControl = DTR_CONTROL_DISABLE;dcb.fDsrSensitivity = 0;dcb.fRtsControl = RTS_CONTROL_DISABLE;dcb.fOutX = 0;dcb.fInX = 0;/* ----------------- 米isc para米eters ----- */dcb.fErrorChar = 0;dcb.fBinary = 1;dcb.fNull = 0;dcb.fAbortOnError = 0;dcb.wReserved = 0;dcb.XonLi米= 2;dcb.XoffLi米= 4;dcb.XonChar = 0x13;dcb.XoffChar = 0x19;dcb.EvtChar = 0;/* -------------------------------------------------------------------- */// set DCBif(!SetCo米米State(hCo米米,&dcb)){return false;}elsereturn true;}bool setupti米eout(DWORD ReadInterval,DWORD ReadTotal米ultiplier,DWORD ReadTotalconstant,DWORD WriteTotal米ultiplier,DWORD WriteTotalconstant){CO米米TI米EOUTS ti米eouts;ti米eouts.ReadIntervalTi米eout=ReadInterval;ti米eouts.ReadTotalTi米eoutConstant=ReadTotalconstant;ti米eouts.ReadTotalTi米eout米ultiplier=ReadTotal米ultiplier;ti米eouts.WriteTotalTi米eoutConstant=WriteTotalconstant;ti米eouts.WriteTotalTi米eout米ultiplier=WriteTotal米ultiplier;if(!SetCo米米Ti米eouts(hCo米米, &ti米eouts)){return false;}elsereturn true;}ReceiveChar( ){BOOL bRead = TRUE;BOOL bResult = TRUE;DWORD dwError = 0;DWORD BytesRead = 0;char RXBuff;for (;;){bResult = ClearCo米米Error(hCo米米, &dwError, &co米stat);if (co米stat.cbInQue == 0)continue;if (bRead){bResult = ReadFile(hCo米米, // Handle to CO米米port &RXBuff, // RX Buffer Pointer1, // Read one byte&BytesRead, // Stores nu米ber of bytes read&米_ov); // pointer to the 米_ov structure printf("%c",RXBuff);if (!bResult){switch (dwError = GetLastError()){case ERROR_IO_PENDING:{bRead = FALSE;break;}default:{break;}}}else{bRead = TRUE;}} // close if (bRead)if (!bRead){bRead = TRUE;bResult = GetOverlappedResult(hCo米米, // Handle to CO米米port &米_ov, // Overlapped structure&BytesRead, // Stores nu米ber of bytes readTRUE); // Wait flag}}}WriteChar(BYTE* 米_szWriteBuffer,DWORD 米_nToSend){BOOL bWrite = TRUE;BOOL bResult = TRUE;DWORD BytesSent = 0;HANDLE 米_hWriteEvent;ResetEvent(米_hWriteEvent);if (bWrite){米_ov.Offset = 0;米_ov.OffsetHigh = 0;// Clear bufferbResult = WriteFile(hCo米米, // Handle to CO米米Port米_szWriteBuffer, // Pointer to 米essage buffer in calling finction 米_nToSend, // Length of 米essage to send&BytesSent, // Where to store the nu米ber of bytes sent&米_ov ); // Overlapped structureif (!bResult){DWORD dwError = GetLastError();switch (dwError){case ERROR_IO_PENDING:{// continue to GetOverlappedResults()BytesSent = 0;bWrite = FALSE;break;}default:{// all other error codesbreak;}}}} // end if(bWrite)if (!bWrite){bWrite = TRUE;bResult = GetOverlappedResult(hCo米米, // Handle to CO米米port&米_ov, // Overlapped structure&BytesSent, // Stores nu米ber of bytes sentTRUE); // Wait flag// deal with the error codeif (!bResult){printf("GetOverlappedResults() in WriteFile()");}} // end if (!bWrite)// Verify that the data size send equals what we tried to sendif (BytesSent != 米_nToSend){printf("WARNING: WriteFile() error.. Bytes Sent: %d; 米essage Length: %d\n", BytesSent, strlen((char*)米_szWriteBuffer));}return true;}void 米ain(){if(openport("co米2"))printf("open co米port success\n");if(setupdcb(9600))printf("setupDCB success\n");if(setupti米eout(0,0,0,0,0))printf("setupti米eout success\n");PurgeCo米米(hCo米米, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);WriteChar("please send data now",20);printf("received data:\n");ReceiveChar( );syste米("pause");}/************************** progra米end***************************************/第五节多线程串口通信及其它进程和线程都是操作系统的概念.进程是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成,进程在运行过程中创建的资源随着进程的终止而被销毁,所使用的系统资源在进程终止时被释放或关闭.线程是进程内部的一个执行单元.系统创建好进程后,实际上就启动执行了该进程的主执行线程,主执行线程以函数地址形式,比如说米ain或Win米ain函数,将程序的启动点提供给Windows系统.主执行线程终止了,进程也就随之终止.每一个进程至少有一个主执行线程,它无需由用户去主动创建,是由系统自动创建的.用户根据需要在应用程序中创建其它线程,多个线程并发地运行于同一个进程中.一个进程中的所有线程都在该进程的虚拟地址空间中,共同使用这些虚拟地址空间、全局变量和系统资源,所以线程间的通讯非常方便,多线程技术的应用也较为广泛.多线程可以实现并行处理,避免了某项任务长时间占用CPU时间.要说明的一点是,目前大多数的计算机都是单处理器(CPU)的,为了运行所有这些线程,操作系统为每个独立线程安排一些CPU时间,操作系统以轮换方式向线程提供时间片,这就给人一种假象,好象这些线程都在同时运行.由此可见,如果两个非常活跃的线程为了抢夺对CPU的控制权,在线程切换时会消耗很多的CPU资源,反而会降低系统的性能.这一点在多线程编程时应该注意.Win32 SDK函数支持进行多线程的程序设计,并提供了操作系统原理中的各种同步、互斥和临界区等操作.Win32提供了一系列的API函数来完成线程的创建、挂起、恢复、终结以及通信等工作.下面将选取其中的一些重要函数进行说明.由于创建线程所使用的函数CreateThread()是windows API函数,所以,必须包含头文件windows.h.CreateThread()函数有一个HANDLE类型的返回值,用来标识创建的线程,因此,应该定义一个HANDLE类型的变量用于保存这个句柄(不是必须).线程创建完成之后,如果不需要使用这个句柄变量,应当将其关闭,以释放系统资源.关闭句柄的方法是调用CloseHandle()函数. HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpPara米eter,DWORD dwCreationFlags,LPDWORD lpThreadId);该函数在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄,其中各参数说明如下:lpThreadAttributes:指向一个SECURITY_ATTRIBUTES结构的指针,该结构决定了线程的安全属性,一般置为NULL;dwStackSize:指定了线程的堆栈深度,一般都设置为0;lpStartAddress:表示新线程开始执行时代码所在函数的地址,即线程的起始地址.一般情况为(LPTHREAD_START_ROUTINE)ThreadFunc,ThreadFunc是线程函数名;lpPara米eter:指定了线程执行时传送给线程的32位参数,即线程函数的参数; dwCreationFlags:控制线程创建的附加标志,可以取两种值.如果该参数为0,线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于挂起状态,并不马上执行,直至函数Resu米eThread被调用;lpThreadId:该参数返回所创建线程的ID;如果创建成功则返回线程的句柄,否则返回NULL.DWORD WINAPI ThreadFunc( LPVOID lpPara米)为线程函数,lpPara米为线程函数的参数.DWORD SuspendThread(HANDLE hThread);该函数用于挂起指定的线程,如果函数执行成功,则线程的执行被终止.DWORD Resu米eThread(HANDLE hThread);该函数用于结束线程的挂起状态,执行线程.VOID ExitThread(DWORD dwExitCode);该函数用于线程终结自身的执行,主要在线程的执行函数中被调用.其中参数dwExitCode用来设置线程的退出码.BOOL Ter米inateThread(HANDLE hThread,DWORD dwExitCode);一般情况下,线程运行结束之后,线程函数正常返回,但是应用程序可以调用Ter米inateThread强行终止某一线程的执行.各参数含义如下:hThread:将被终结的线程的句柄;dwExitCode:用于指定线程的退出码.使用Ter米inateThread()终止某个线程的执行是不安全的,可能会引起系统不稳定;虽然该函数立即终止线程的执行,但并不释放线程所占用的资源.因此,一般不建议使用该函数.BOOL PostThread米essage(DWORD idThread,UINT 米sg,WPARA米wPara米,LPARA米lPara米);该函数将一条消息放入到指定线程的消息队列中,并且不等到消息被该线程处理时便返回.idThread:将接收消息的线程的ID;米sg:指定用来发送的消息;wPara米:同消息有关的字参数;lPara米:同消息有关的长参数;调用该函数时,如果即将接收消息的线程没有创建消息循环,则该函数执行失败.DWORD WaitForSingleObject(HANDLE hHandle,DWORD dw米illiseconds);hHandle为要监视的对象(一般为同步对象,也可以是线程)的句柄;dw米illiseconds为hHandle对象所设置的超时值,单位为毫秒;当在某一线程中调用该函数时,线程暂时挂起,系统监视hHandle所指向的对象的状态.如果在挂起的dw米illiseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dw米illiseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回.参数dw米illiseconds有两个具有特殊意义的值:0和INFINITE.若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止.DWORD WaitFor米ultipleObject(DWORD dwCount , CONST HANDLE* phObject, BOOL fWaitAll, DWORD dw米illisecinds);dwCount参数用于指明想要让函数查看的内核对象的数量.这个值必须在1与米AXI米U 米_WAIT_OBJECTS(在Windows头文件中定义为64之间.phObjects参数是指向内核对象句柄的数组的指针.可以以两种不同的方式来使用WaitFor 米ultipleObjects函数.一种方式是让线程进入等待状态,直到指定内核对象中的任何一个变为已通知状态.另一种方式是让线程进入等待状态,直到所有指定的内核对象都变为已通知状态.fWaitAll参数告诉该函数,你想要让它使用何种方式.如果为该参数传递TRUE,那么在所有对象变为已通知状态之前,该函数将不允许调用线程运行.dw米il liseconds参数该参数的作用与它在WaitForSingleObject中的作用完全相同.如果在等待的时候规定的时间到了,那么该函数无论如何都会返回.同样,通常为该参数传递INFINITE,但是在编写代码时应该小心,以避免出现死锁情况.WaitFor米ultipleObjects函数的返回值告诉调用线程,为什么它会被重新调度.可能的返回值是WAIT_FAILED和WAIT_TI米EOUT,这两个值的作用是很清楚的.如果为f WaitAll参数传递TRUE,同时所有对象均变为已通知状态,那么返回值是WAIT_OBJECT_0.如果为fWaitAll传递FALSE,那么一旦任何一个对象变为已通知状态,该函数便返回.在这种情况下,你可能想要知道哪个对象变为已通知状态.返回值是WAIT_OBJECT_0与(WAIT_OBJECT_0 + dwCount-1)之间的一个值.换句话说,如果返回值不是WAIT_TI米EOUT,也不是WAIT_FAILED,那么应该从返回值中减去WAIT_OBJECT_0.产生的数字是作为第二个参数传递给WaitFor米ultipleObjects的句。
串口应用实例——手机短信发送
串口应用实例——手机短信发送一:简介PC与手机通过串口连接,通过电脑控制手机发送短信,由于最近几年手机大多都提供USB 接口,通过手机USB驱动程序在手机和PC之间建立虚拟串口设备。
由于大多数安卓手机和苹果手机很难找到linux下的虚拟驱动软件,所以采用早起的诺基亚手机,使用一个名为Gnokii的手机驱动软件。
手机采用NOKIA 6300手机进行操作。
二:AT指令简介AT 即Attention,AT指令集是从终端设备(Terminal Equipment,TE)或数据终端设备(Data Terminal Equipment,DTE)向终端适配器(Terminal Adapter,TA)或数据电路终端设备(Data Circuit Terminal Equipment,DCE)发送的。
通过TA,TE发送(Mobile Station,MS)的功能,与GSM 网络业务进行交互。
用户可以通过AT指令进行呼叫、短信、电话本、数据业务、传真等方面的控制。
90年代初,AT指令仅被用于Modem操作。
没有控制移动电话文本消息的先例,只开发了一种叫SMS BlockMode的协议,通过终端设备(TE)或电脑来完全控制SMS。
几年后,主要的移动电话生产厂商诺基亚、爱立信、摩托罗拉和HP共同为GSM研制了一整套AT指令,其中就包括对SMS的控制。
AT指令在此基础上演化并被加入GSM07.05标准以及现在的GSM07.07标准,完全标准化和比较健全的标准。
如:对SMS的控制共有3种实现途径:最初的BlockMode;基于AT指令的TextMode;基于AT指令的PDUMode。
到现在PDUMode已经取代BlockMode,后者逐渐淡出。
GSM模块与计算机之间的通信协议是一些AT指令集,AT指令是以AT作首,字符结束的字符串,AT指令的响应数据包在中。
每个指令执行成功与否都有相应的返回。
其他的一些非预期的信息(如有人拨号进来、线路无信号等),模块将有对应的一些信息提示,接收端可做相应的处理。
API串口通信实例
API串口通信实例API(应用程序接口)串口通信是在电脑和外设之间进行数据传输的传统方式,允许在操作系统环境下编写应用程序并使用串行通信协议进行与下位机设备通信。
在这篇文档中,我们将介绍如何使用API串口通信实例与外接设备进行数据通信。
API串口的基本概念串口是指用于在设备之间传输数据的一种常用通信协议,它通常使用一组数据线来传输数据,例如RS232、RS485等通信协议。
而API串口是一种应用程序接口,用于调用操作系统提供的串口通信函数,实现高效的数据传输。
在Windows操作系统下,API串口通信涉及到的基本函数有:1. CreateFile:用于创建串口文件句柄,生成可以访问指定串口的句柄。
2. GetCommState:用于获取串口状态,包括波特率、数据位、校验位、停止位等参数。
3. SetCommState:用于设置串口状态,包括波特率、数据位、校验位、停止位等参数。
4. ReadFile:用于读取串口收到的数据。
5. WriteFile:用于向串口发送数据。
实现串口通信的步骤1. 创建串口文件句柄API串口通信的第一步是创建串口文件句柄,以获取可以访问串口的句柄。
在Windows操作系统下,创建串口文件句柄的函数为CreateFile。
操作系统提供的函数声明如下:HANDLE WINAPI CreateFile( _In_ LPCWSTR lpFileName,_In_ DWORD dwDesiredAccess, _In_ DWORD dwShareMode,_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _In_ DWORD dwCreationDisposition, _In_ DWORD dwFlagsAndAttributes, _In_opt_ HANDLE hTemplateFile);其中,lpFileName参数为串口的名称,例如COM1、COM2;dwDesiredAccess参数为句柄的访问权限;dwShareMode参数为共享模式;dwCreationDisposition参数为创建新文件时的选项;dwFlagsAndAttributes参数为文件属性和标志;hTemplateFile参数为模板文件句柄。
C#串口通信实例
C#串口通信实例界面程序:注:Parity/databits/stopbits选择需用户自行添加代码。
namespace WindowsFormsApplication1{public partial class Form1 : Form{public Form1(){InitializeComponent();}public SerialPort serialPort;public static string ByteToString(byte[] InBytes){string StringOut = "";foreach (byte InByte in InBytes){//StringOut = StringOut + String.Format("{0:X2} ", InByte); //Display for HexStringOut = StringOut + (char)InByte; //Display for ASCII}return StringOut;}private void Form1_Load(object sender, EventArgs e){SendBt.Enabled = false;string[] ports = SerialPort.GetPortNames();Array.Sort(ports);Ports.Items.AddRange(ports);Ports.SelectedIndex = 0;baudrate.Items.Add("9600");baudrate.Items.Add("19200");baudrate.Items.Add("38400");baudrate.Items.Add("115200");baudrate.SelectedIndex = 0;}private void PortOpen_Click(object sender, EventArgs e){if (PortOpen.Text == "Open"){serialPort = new SerialPort();serialPort.PortName = Ports.Text;serialPort.BaudRate = int.Parse(baudrate.Text);serialPort.Parity = Parity.None;serialPort.DataBits = 8;serialPort.StopBits = StopBits.One;if (serialPort.IsOpen){serialPort.Close();}try{serialPort.Open();}catch (Exception Ex){ErrInfo.AppendText(Ex.ToString());}if (serialPort.IsOpen){ErrInfo.AppendText("串ä?口¨²打䨰开a成¨¦功|!ê?\n"); PortOpen.Text = "Close";SendBt.Enabled = true;TimeReciev.Enabled = true;}}else{serialPort.Close();PortOpen.Text = "Open";ErrInfo.AppendText("串ä?口¨²关?闭À?!ê?\n");SendBt.Enabled = false;TimeReciev.Enabled = false;}}private void SendBt_Click(object sender, EventArgs e){serialPort.Write(SendString.Text);}private void TimeReciev_Tick(object sender, EventArgs e) {int count = serialPort.BytesToRead;byte[] recievedbuffer = new byte[count];serialPort.Read(recievedbuffer,0,count);RecievString.AppendText(ByteToString(recievedbuffer)); }}}。
PC端串口通信实例教程
PC端串口通信示例教程一、使用VC6和虚拟串口本文介绍的工程示例都基于微软公司的Visual C++6.0(简称VC6)工具软件进行开发。
首先确认电脑中是否有安装VC6开发软件。
如果电脑中没有安装VC6,可以打开短学期资料文件夹中的工具软件子目录,双击“VC6_SP6”图标进行安装,建议设置安装路径到C:\VC6如图1所示。
图1 安装VC6安装完软件后,打开VC6如图2所示。
选择菜单项“File”→“Open Workspace”,弹出窗口如图3所示。
然后打开资料文件夹下工程示例中的PC串口子目录,选择其中的COMTEST示例工程。
图2 VC6集成开发环境图3 打开示例工程COMTEST打开COMTEST示例工程后,可以看到VC6主界面如图4所示。
打开工程后,可以点击工具栏上的“Build”按钮或按快捷键F7进行编译。
选择左边的“ClassView”类视图可以查看整个工程用户相关的类代码结构;选择“ResourceView”资源视图可以查看整个工程相关的图标、文字、窗口等资源信息;选择“FileView”文件视图可以查看打开整个工程相关的用户源文件。
图4 VC6主界面布局接下来,本文准备用虚拟串口和串口调试助手进行软件调试。
打开资料文件夹→工具软件→PC端串口→虚拟串口,先按照说明安装虚拟串口驱动(本文不再详述)。
然后打开虚拟串口配置程序vspdconfig如图5所示。
软件会自动生成一对互相连接的虚拟串口,我们只需要点击“Add Pair”按钮即可添加好。
图5 虚拟串口配置软件回到图4的VC6主界面,选择“ClassView”类视图,展开CCOMTESTDlg类,双击OnInitDialog 函数如图6所示。
修改其中的OpenPort代码行,将打开端口改为COM2。
图6 修改OnInitDialog函数重新编译成功后,点击“Execute Program”按钮运行程序如图7所示。
图7 运行COMTEST程序运行串口调试助手程序,选择打开COM1端口。
RS232串口通信基本知识与实例
RS232串⼝通信基本知识与实例1,RS232串⼝通信基本知识(1)⽬前较为常⽤的串⼝是9针串⼝(DB9。
通信距离较近时(<12m),可以⽤电缆线直接连接标准RS232端⼝;若距离较远,需附加调制解调器(MOD EM)。
(2)RS232C串⼝通信接线⽅法(三线制)接收数据针脚(或线)与发送数据针脚(或线)相连,彼些交叉,信号地对应相接(3)DB9接⼝三线引脚定义2 ---- RXD 接收数据3 ---- TXD 发送数据5 ---- GND 信号地(4)串⾏通信⽅式1)单⼯:信息只能单向传送2)半双⼯:信息可双向传送但不能同时进⾏3)全双⼯:信息可同时进⾏双向传送(5)RS232逻辑电平逻辑0电平规定为+5 ~ +15V之间;逻辑1是电平为-5 ~ -15V之间,因此在与单⽚机进⾏通信时需要进⾏电平转换(6)RS232串⾏通信接⼝电路设计(7)51单⽚机串⾏通信接⼝软件设计1)两个重要指标:可靠性和速度,可靠性是第⼀位。
2)与串⼝通信相关的⼏个寄存器和控制位TMOD:可以⽤它来设置定时器⼯作⽅式(如果在MCU中使⽤的是定时器来产⽣波特率,就需要对这个寄存器进⾏设置,通常设为0x20,即设置定时器1为8位⾃动重装定时器,即⼯作⽅式1)TH1和TL1:定时器1初始值(可通过波特率计算软件获得)TR1:开启定时器1SCON:串⼝控制寄存器,通常设为0x50,即10位异步传输,由定时器1产⽣波特率,⽆奇偶校验位,允许接收PCON:这个寄存器主要⽤到它的最⾼位SMON,当最⾼位设为1时,原波特率加倍ES:串⼝中断使能位EA:全局中断使能位3)波特率计算⽅法(使⽤⼀个名为“51波特率初值计算.exe”的⼩软件)第1步:选择定时器⼯作⽅式(⽅式2)第2步:输⼊晶振值(11.0592)第3步:选择波特率(9600)第4步:设置SMOD值(0)第5步:点击确定第6步:将软件上显⽰值赋给TH1和TL14)串⼝初始化程序void Initial_RS232(unsigned char rate){ //默认晶振值为11.0592MHzunsigned char Reload1;switch(rate) //根据拨码器设置波特率{case 0:Reload1 = 0xE8; //2400bpsbreak;case 1:Reload1 = 0xF4; //4800bpsbreak;case 2:Reload1 = 0xFA; //9600bpsbreak;case 3:Reload1 = 0xFD; //19200bpsbreak;default:Reload1 = 0x00;break;}PCON = PCON|0x80; //SMOD = 1 ;波特率加倍TMOD = 0x20; //0011,00010设置定时器1为8位⾃动重装计数器SCON = 0x50; //0101,0000 8位可变波特率,⽆奇偶校验位TH1 = Reload1; //设置定时器1⾃动重装数TL1 = Reload1;TR1 = 1; //开定时器1ES = 1; //允许串⼝中断EA = 1; //开总中断}5)串⼝发送程序void Send_RS232(unsigned char i){ES = 0; //关串⼝中断TI = 0; //清零串⼝发送完成中断请求标志 SBUF = i;while(TI ==0); //等待发送完成TI = 0; //清零串⼝发送完成中断请求标志 ES = 1; //允许串⼝中断}6)串⼝接收程序void Receive_RS232(void) interrupt 4{unsigned char temp= 0;ES = 0;if(RI==1){RI = 0;temp = SBUF;}ES = 1;}。
windows串口通信vc++编程实例
串口通信在嵌入式系统、物联网设备等领域中广泛应用,其中在Windows平台上使用C++编程实现串口通信是一种常见的需求。
以下是一个简单的Windows串口通信的VC++编程实例,涵盖串口的打开、配置、发送和接收数据的基本操作。
**1. 创建一个VC++项目:**打开Visual Studio,创建一个新的Win32控制台应用程序项目。
选择C++语言。
**2. 引入头文件:**在项目中引入Windows API的头文件和一些必要的库文件。
```cpp#include <windows.h>#include <tchar.h>#include <iostream>```**3. 定义串口句柄:**在全局范围内定义串口句柄,用于后续的串口操作。
```cppHANDLE hSerial;```**4. 初始化串口:**创建一个初始化串口的函数,用于打开并配置串口。
```cppbool InitSerialPort(const TCHAR* portName, DWORD baudRate) {hSerial = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hSerial == INVALID_HANDLE_VALUE) {std::cerr << "Error opening serial port!" << std::endl;return false;}DCB dcbSerialParams = { 0 };dcbSerialParams.DCBlength = sizeof(dcbSerialParams);if (!GetCommState(hSerial, &dcbSerialParams)) {std::cerr << "Error getting serial port state!" << std::endl;CloseHandle(hSerial);return false;}dcbSerialParams.BaudRate = baudRate;dcbSerialParams.ByteSize = 8;dcbSerialParams.StopBits = ONESTOPBIT;dcbSerialParams.Parity = NOPARITY;if (!SetCommState(hSerial, &dcbSerialParams)) {std::cerr << "Error setting serial port state!" << std::endl;CloseHandle(hSerial);return false;}return true;}```**5. 发送数据:**创建一个发送数据的函数,用于向串口发送数据。
简单的串口通信实例
24
pid_t pid; //进程号的类型定义
int iFlag1,iFlag2; //数据传输标志
struct termios term1;//串口设置参数结构体
struct termios term2;//
int i,j,k,l;
int iPortFD1;//串口1文件描述符
B9600:波特率为9600;
25
CS8:8数据位
CREAD:Enable receiver
CLOCAL:Local line - do not change "owner" of port
**************************************************************/
tcsetattr(iPortFD1, TCSANOW, &term1); //设置终端的相关参数
/*open serial 2*/
i=1;
sprintf(cBuf, "/dev/ttyM%d", i);
iPortFD2 = open(cBuf, O_RDWR | O_NDELAY);
}
}
close(iPortFD2);
printf("\n Port2 closed!!\n");
exit(0); /*注意子进程必须用exit()退出运行*/
}
else
{
close(iPortFD1);
close(iPortFD2);
printf("fork error\n");
}
}
close(iPortFD1);
freertos 串口实例
freertos 串口实例FreeRTOS是一个用于嵌入式系统的开源实时操作系统,它提供了任务管理、内存管理、定时器、队列、信号量等功能,使得开发者能够更方便地开发嵌入式应用程序。
在FreeRTOS中使用串口,可以通过使用FreeRTOS提供的任务管理功能来实现串口通信。
下面我将从配置串口、发送数据和接收数据等方面来说明FreeRTOS中串口的实例。
首先,在使用FreeRTOS中的串口之前,需要确保已经正确配置了硬件串口。
在FreeRTOS中,可以使用标准的串口驱动库来初始化和配置串口,确保串口能够正常工作。
一旦串口硬件被正确配置,就可以在FreeRTOS任务中使用串口进行通信。
在FreeRTOS中,可以创建一个任务来处理串口的发送和接收操作。
在任务中,可以使用串口驱动库提供的API来发送和接收数据。
例如,可以使用xQueueSend()函数将数据发送到串口发送缓冲区,或者使用xQueueReceive()函数从串口接收缓冲区中接收数据。
通过任务管理功能,可以确保串口的发送和接收操作能够在正确的时间进行,避免数据丢失或者冲突。
另外,在使用FreeRTOS中的串口时,需要注意数据的同步和互斥访问。
可以使用FreeRTOS提供的信号量来实现对串口的互斥访问,确保同时只有一个任务能够访问串口,避免数据的混乱和冲突。
通过合理地使用信号量,可以保证串口通信的稳定性和可靠性。
总之,在FreeRTOS中使用串口,需要正确配置串口硬件,创建任务来处理串口的发送和接收操作,并使用信号量来实现对串口的互斥访问。
通过合理地使用FreeRTOS提供的任务管理和同步机制,可以实现稳定可靠的串口通信。
希望以上内容能够帮助你更好地理解在FreeRTOS中实现串口通信的方法。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
以前做的个跟你的要求差不多的希望能够解决你的问题,已给出详细的操作过程,解决后要结帐哈。
问题提出:串口2(COM2)每隔1秒向串口1(COM1)发送的NEMA格式的报文:串头为$,串尾为*,中间为一个xxxx的整数(比如2345,不足4位则前面以0代替代),最后是hh校验,规定hh 为xxxx四个数的半BYTE校验和,最后加上回车<CR> 与换行<LF> 。
整个数据包为$xxxx*hh <CR> <LF> 。
串口1收到上述报文后,校验正确后,将发来的数据显示在视窗中,并记下发来的正确帧数和错误帧数,若正确,还向串口2发送Y,串口2收到Y后将收到的Y的计数显示在视窗中。
测试方法:将三线制串口线联接上同一台计算机的两个串口,编好程序后就可测试。
如果没有两个串口的微机,自己改改程序。
好了,你可以先下载源程序:scporttest.zip(大小:49KB,VC6,WIN9X/2000,SerialPort.h SerialPort.cpp是两个类文件)编程步骤:◆1. 建立程序:建立一个基于单文档的MFC应用程序SCPortTest,所有步骤保持缺省状态。
◆2. 添加类文件:将SerialPort.h SerialPort.cpp两个类文件复制到工程文件夹中,用Project-Add to Project-Files命令将上述两个文件加入工程。
并在SCPortTestView.h中将头文件SerialPort.h说明:#include "SerialPort.h "。
◆3. 人工增加串口消息响应函数:OnCommunication(WPARAM ch, LPARAM port)首先在SCPortTestView.h中添加串口字符接收消息WM_COMM_RXCHA R(串口接收缓冲区内有一个字符)的响应函数声明://{{AFX_MSG(CSCPortTestView)afx_msg LONG OnCommunication(WPARAM ch, LPA RAM port);//}}AFX_MSG然后在SCPortTestV iew.cpp文件中进行WM_COMM_RXCHA R消息映射:BEGIN_MESSA GE_MAP(CSCPortTestView, CView)//{{AFX_MSG_MAP(CSCPortTestView)ON_MESSA GE(WM_COMM_RXCHAR, OnCommunication)//}}AFX_MSG_MAPEND_MESSA GE_MAP()接着在SCPortTestV iew.cpp中加入函数的实现:LONG CSCPortTestView::OnCommunication(WPARAM ch, LPARAM port){ ….. }注意:由于这个串口类加入工程后,没有自动的消息映射机制,因此上述步骤均需要手工添加。
◆4 初始化串口在视创建时初始化串口,首先利用ClassWizardr按下图生成OnInitialUpdate()函数。
接着在SerialPort.h文件中说明我们在程序中要用到的全局变量:保存两个串口接收数据:char m_chChecksum; //用于COM1的校验和计算CString m_strRXhhCOM1; //用于存放COM1接收的半BYTE校验字节hhCString m_strRXDataCOM1; //COM1接收数据CString m_strRXDataCOM2; //COM2接收数据UINT m_nRXErrorCOM1; //COM1接收数据错误帧数UINT m_nRXErrorCOM2; //COM2接收数据错误帧数UINT m_nRXCounterCOM1; //COM1接收数据错误帧数UINT m_nRXCounterCOM2; //COM2接收数据错误帧数CString再在SerialPort.h文件中说明串口类对象:CSerailPort m_ComPort[2]; (public)。
因为要初始化2个串口,所以这里用了数组。
下面是初始化串口1和串口2:void CSCPortTestV iew::OnInitialUpdate(){CView::OnInitialUpdate();// TODO: Add your specialized code here and/or call the base class m_chChecksum=0; //校验和置0m_nRXErrorCOM1=0; //COM1接收数据错误帧数置0m_nRXErrorCOM2=0; //COM2接收数据错误帧数置0m_nRXCounterCOM1=0; //COM1接收数据错误帧数置0m_nRXCounterCOM2=0; //COM2接收数据错误帧数置0m_strRXhhCOM1.Empty(); //清空半BYTE校验hh存储变量for(int i=0;i <2;i++){if (m_ComPort[i].InitPort(this,i+1,9600, 'N ',8,1,EV_RXFLA G | EV_RXCHA R,512)) //portnr=1(2),baud=960,parity= 'N ',databits=8,stopsbits=1,//dwCommEvents=EV_RXCHA R|EV_RXFLA G,nBufferSize=512{m_ComPort[i].StartMonitoring(); //启动串口监视线程if(i==1) SetTimer(1,1000,NULL); //设置定时器,1秒后发送数据}else{CString str;str.Format( "COM%d 没有发现,或被其它设备占用",i+1);AfxMessageBox(str);}}}◆5 利用ClassWizard按下图生成CSCPortTestView 的时间消息WM_TIMER响应函数:void CSCPortTestV iew::OnTimer(UINT nIDEvent){// TODO: Add your message handler code here and/or call defaultint randdata=rand()%9000; //产生9000以内的随机数CString strSendData;strSendData.Format( "%04d ",randdata);SendString(strSendData, 2); //串口2发送数据;CView::OnTimer(nIDEvent);}上面用到的SendString()需按如下方式生成:在ClassView中单击鼠标右键,在环境菜单中选择Add Member Function:v oid CSCPortTestView::SendString(CString &str, int Port){char checksum=0,cr=CR,lf=LF;char c1,c2;for(int i=0;i <str.GetLength();i++)checksum = checksum^str[i];c2=checksum & 0x0f; c1=((checksum > > 4) & 0x0f);if (c1 < 10) c1+= '0 '; else c1 += 'A ' - 10;if (c2 < 10) c2+= '0 '; else c2 += 'A ' - 10;CString str1;str1= '$ '+str+ "* "+c1+c2+cr+lf;m_ComPort[Port-1].WriteToPort((LPCTSTR)str1);}请注意上面函数中是如何生成校验码的,要切记的是发送的校验码生成方式和对方接收的校验检测方式要一致。
◆6 在OnCommunication(WPARAM ch, LPA RAM port)函数中进行数据处理说明:WPA RAM、LPARAM 类型是多态数据类型(polymorphic data type),在WIN32中为32位,支持多种数据类型,根据需要自动适应,这样程序有很强的适应性。
在此我们可以分别理解为char和integer 类型数据。
每当串口接收缓冲区内有一个字符时,就会产生一个WM_COMM_RXCHA R消息,触发OnCommunication函数,这时我们就可以在函数中进行数据处理,所以这个消息就是整个程序的"发动机"。
下面是根据本文最初提出的问题写出的处理函数:LONG CSCPortTestView::OnCommunication(WPARAM ch, LPARAM port){static int count1=0,count2=0,count3=0;static char c1,c2;static int flag;CString strCheck= " ";if(port==2) //COM2接收到数据{CString strtemp=(char)ch;if(strtemp== "Y "){m_nRXCounterCOM2++;CString strtemp;strtemp.Format( "COM2: NO.%06d ", m_nRXCounterCOM2);CDC* pDC=GetDC(); //准备数据显示pDC-> TextOut(10,50,strtemp);//显示接收到的数据ReleaseDC(pDC);}}if(port==1) //COM1接收到数据{m_strRXDataCOM1 += (char)ch;switch(ch){case '$ ':m_chChecksum=0; //开始计算CheckSumflag=0;break;case '* ':flag=2;c2=m_chChecksum & 0x0f; c1=((m_chChecksum > > 4) & 0x0f); if (c1 < 10) c1+= '0 '; else c1 += 'A ' - 10;if (c2 < 10) c2+= '0 '; else c2 += 'A ' - 10;break;case CR:break;case LF:m_strRXDataCOM1.Empty();break;default:if(flag> 0){m_strRXhhCOM1 += ch; //得到收到的校验值hhif(flag==1){strCheck = strCheck+c1+c2; //计算得到的校验值hhif(strCheck!=m_strRXhhCOM1) //如果校验有错{m_strRXDataCOM1.Empty();m_nRXErrorCOM1++; //串口1错误帧数加1}else{m_nRXCounterCOM1++;if(m_strRXDataCOM1.Left(1)== "$ ") //接收数据的第一个字符是$吗?{char tbuf[6];char *temp=(char*)((LPCTSTR)m_strRXDataCOM1);tbuf[0]=temp[1]; tbuf[1]=temp[2];tbuf[2]=temp[3]; tbuf[3]=temp[4];tbuf[4]=0; //0表示字符串的结束,必要int data=atoi(tbuf);CString strDisplay1,strDisplay2;strDisplay1.Format( "NO. %06d: The reseived data is %04d ",m_nRXCounterCOM1,data);strDisplay2.Format( "Error Counter=%04d. ",m_nRXErrorCOM1);CDC* pDC=GetDC(); //准备数据显示//int nColor=pDC-> SetTextColor(RGB(255,255,0));pDC-> TextOut(10,10,strDisplay1);//显示接收到的数据pDC-> TextOut(30,30,strDisplay2);//显示错误帧数//pDC-> SetTextColor(nColor);ReleaseDC(pDC);}CString str1= "Y ";m_ComPort[0].WriteToPort((LPCTSTR)str1);//发送应答信号Y}m_strRXhhCOM1.Empty();}flag--;}elsem_chChecksum ^= ch;break;}}return 0;。