串⼝通信基础,接收,发送数据
通信接⼝背景知识
设备之间通信的⽅式
⼀般情况下,设备之间的通信⽅式可以分成并⾏通信和串⾏通信两种。它们的区别是:
串⾏通信的分类
1、按照数据传送⽅向,分为:
单⼯:数据传输只⽀持数据在⼀个⽅向上传输;
半双⼯:允许数据在两个⽅向上传输。但是,在某⼀时刻,只允许数据在⼀个⽅向上传输,它实际上是⼀种切换⽅向的单⼯通信;它不需要独⽴的接收端和发送端,两者可以合并⼀起使⽤⼀个端⼝。
全双⼯:允许数据同时在两个⽅向上传输。因此,全双⼯通信是两个单⼯通信⽅式的结合,需要独⽴的接收端和发送端。
2、按照通信⽅式,分为:
同步通信:带时钟同步信号传输。⽐如:SPI,IIC通信接⼝。
异步通信:不带时钟同步信号。⽐如:UART(通⽤异步收发器),单总线。
在同步通讯中,收发设备上⽅会使⽤⼀根信号线传输信号,在时钟信号的驱动下双⽅进⾏协调,同步数据。例如,通讯中通常双⽅会统⼀规定在时钟信号的上升沿或者下降沿对数据线进⾏采样。
在异步通讯中不使⽤时钟信号进⾏数据同步,它们直接在数据信号中穿插⼀些⽤于同步的信号位,或者将主题数据进⾏打包,以数据帧的格式传输数据。通讯中还需要双⽅规约好数据的传输速率(也就是波特率)等,以便更好地同步。常⽤的波特率有4800bps、9600bps、115200bps等。
在同步通讯中,数据信号所传输的内容绝⼤部分是有效数据,⽽异步通讯中会则会包含数据帧的各种标识符,所以同步通讯效率⾼,但是同步通讯双⽅的时钟允许误差⼩,稍稍时钟出错就可能导致数据错乱,异步通讯双⽅的时钟允许误差较⼤。
常见的串⾏通信接⼝
STM32串⼝通信基础
STM32的串⼝通信接⼝有两种,分别是:UART(通⽤异步收发器)、USART(通⽤同步异步收发器)。⽽对于⼤容量STM32F10x系列芯⽚,分别有3个USART和2个UART。
UART引脚连接⽅法
RXD:数据输⼊引脚,数据接受;
TXD:数据发送引脚,数据发送。
对于两个芯⽚之间的连接,两个芯⽚GND共地,同时TXD和RXD交叉连接。这⾥的交叉连接的意思就是,芯⽚1的RxD连接芯⽚2的TXD,芯⽚2的RXD连接芯⽚1的TXD。这样,两个芯⽚之间就可以进⾏TTL电平通信了。
若是芯⽚与PC机(或上位机)相连,除了共地之外,就不能这样直接交叉连接了。尽管PC机和芯⽚都有TXD和RXD引脚,但是通常PC机
(或上位机)通常使⽤的都是RS232接⼝(通常为DB9封装),因此不能直接交叉连接。RS232接⼝是9针(或引脚),通常是TxD和RxD 经过电平转换得到的。故,要想使得芯⽚与PC机的RS232接⼝直接通信,需要也将芯⽚的输⼊输出端⼝也电平转换成rs232类型,再交叉连接。
经过电平转换后,芯⽚串⼝和rs232的电平标准是不⼀样的:
单⽚机的电平标准(TTL电平):+5V表⽰1,0V表⽰0;
Rs232的电平标准:+15/+13 V表⽰1,-15/-13表⽰0。
RS-232通讯协议标准串⼝的设备间通讯结构图如下:
所以单⽚机串⼝与PC串⼝通信就应该遵循下⾯的连接⽅式:在单⽚机串⼝与上位机给出的rs232⼝之间,通过电平转换电路(如下⾯图中的Max232芯⽚) 实现TTL电平与RS232电平之间的转换。
具体要了解RS232串⼝的,可以查看链接RS232串⼝简介。
STM32的UART特点
全双⼯异步通信;
分数波特率发⽣器系统,提供精确的波特率。发送和接受共⽤的可编程波特率,最⾼可达4.5Mbits/s;
可编程的数据字长度(8位或者9位);
可配置的停⽌位(⽀持1或者2位停⽌位);
可配置的使⽤DMA多缓冲器通信;
单独的发送器和接收器使能位;
检测标志:①接受缓冲器②发送缓冲器空③传输结束标志;同步通信和异步通信的区别
多个带标志的中断源,触发中断;
其他:校验控制,四个错误检测标志。
串⼝通信过程
STM32中UART参数
串⼝通讯的数据包由发送设备通过⾃⾝的TXD接⼝传输到接收设备的RXD接⼝,通讯双⽅的数据包格式要规约⼀致才能正常收发数据。STM32中串⼝异步通信需要定义的参数:起始位、数据位(8位或者9位)、奇偶校验位(第9位)、停⽌位(1,15,2位)、波特率设置。UART串⼝通信的数据包以帧为单位,常⽤的帧结构为:1位起始位+8位数据位+1位奇偶校验位(可选)+1位停⽌位。如下图所⽰:
奇偶校验位分为奇校验和偶校验两种,是⼀种简单的数据误码校验⽅法。奇校验是指每帧数据中,包括数据位和奇偶校验位的全部9个位中1的个数必须为奇数;偶校验是指每帧数据中,包括数据位和奇偶校验位的全部9个位中1的个数必须为偶数。
校验⽅法除了奇校验(odd)、偶校验(even)之外,还可以有:0 校验(space)、1 校验(mark)以及⽆校验(noparity)。 0/1校验:不管有效数据中的内容是什么,校验位总为0或者1。
UART(USART)框图
这个框图分成上、中、下三个部分。本⽂⼤概地讲述⼀下各个部分的内容,具体的可以看《STM32中⽂参考⼿册》中的描述。
框图的上部分,数据从RX进⼊到接收移位寄存器,后进⼊到接收数据寄存器,最终供CPU或者DMA来进⾏读取;数据从CPU或者DMA传递过来,进⼊发送数据寄存器,后进⼊发送移位寄存器,最终通过TX发送出去。
然⽽,UART的发送和接收都需要波特率来进⾏控制的,波特率是怎样控制的呢?
这就到了框图的下部分,在接收移位寄存器、发送移位寄存器都还有⼀个进⼊的箭头,分别连接到接收器控制、发送器控制。⽽这两者连接的⼜是接收器时钟、发送器时钟。也就是说,异步通信尽管没有时
钟同步信号,但是在串⼝内部,是提供了时钟信号来进⾏控制的。⽽接收器时钟和发送器时钟有是由什么控制的呢?
可以看到,接收器时钟和发送器时钟⼜被连接到同⼀个控制单元,也就是说它们共⽤⼀个波特率发⽣器。同时也可以看到接收器时钟(发⽣器时钟)的计算⽅法、USRRTDIV的计算⽅法。
这⾥需要知道⼀个知识点:
UART1的时钟:PCLK2(⾼速);
UART2、UART3、UART4的时钟:PCLK1(低速)。
原⽂:
vc++6.0使⽤串⼝控件例程
:
打开VC++6.0,建⽴⼀个基于对话框的MFC应⽤程序SCommTest;
选择Project菜单下Add To Project⼦菜单中的 Components and Controls…选项,在弹出的对话框中双
击Registered ActiveX Controls项(稍等⼀会,这个过程较慢),则所有注册过的ActiveX控件出现在列表框中。选择Microsoft Communications Control, version 6.0,,单击Insert按钮将它插⼊到我们的Project中来,接受缺省的选项。(如果你在控件列表中看不到Microsoft Communications Control, version 6.0,
那可能是你在安装VC6时没有把ActiveX⼀项选上,重新安装VC6,选上ActiveX就可以了),
这时在ClassView视窗中就可以看到CMSComm类了,(注意:此类在ClassWizard中看不到,重构clw⽂件也⼀样),并且在控件⼯具栏Controls中出现了电话图标(如图1所⽰),现在要做的是⽤⿏标将此图标拖到对话框中,程序运⾏后,这个图标是看不到的。
打开ClassWizard->Member Viariables选项卡,选择CSCommTestDlg类,为IDC_MSCOMM1添加控制变量:m_ctrlComm,这时你可以看⼀看,在对话框头⽂件中⾃动加⼊了//{{AFX_INCLUDES() #include "mscomm.h" //}}AFX_INCLUDES 。
向主对话框中添加两个编辑框,⼀个⽤于接收显⽰数据ID为IDC_EDIT_RXDATA,另⼀个⽤于输⼊发送数据,ID为IDC_EDIT_TXDATA,再添加⼀个按钮,功能是按⼀次就把发送编辑框中的内容发送⼀次,将其ID设为IDC_BUTTON_MANUALSEND。别忘记了将接收编辑框的Properties->Styles中把Miltiline和Vertical Scroll属性选上,发送编辑框若你想输⼊多⾏⽂字,也可选上Miltiline。
再打开ClassWizard->Member Viariables选项卡,选择CSCommTestDlg类,为IDC_EDIT_RXDATA添加CString变量m_strRXData,为IDC_EDIT_TXDATA添加CString变量m_strTXData。说明: m_strRXData和m_strTXData分别⽤来放⼊接收和发送的字符数据。
打开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++)
{
BYTE bt=*(char*)(rxdata+k); //字符型
strtemp.Format("%c",bt); //将字符送⼊临时变量strtemp存放
m_strRXData+=strtemp; //加⼊接收编辑框对应字符串
}
}
UpdateData(FALSE); //更新编辑框内容
}
到⽬前为⽌还不能在接收编辑框中看到数据,因为我们还没有打开串⼝,但运⾏程序不应该有任何错误,不然,你肯定哪⼉没看仔细,因为我是打开VC6对照着做⼀步写⼀⾏的,运⾏试试。没错吧?那么做下⼀步:
你可以在你需要的时候打开串⼝,例如在程序中做⼀个开始按钮,在该按钮的处理函数中打开串⼝。现
在我们在主对话框的CSCommTestDlg::OnInitDialog()打开串⼝,加⼊如下代码:
// TODO: Add extra initialization here
if(m_ctrlComm.GetPortOpen())
m_ctrlComm.SetPortOpen(FALSE);
m_ctrlComm.SetCommPort(4); //选择com4
if( !m_ctrlComm.GetPortOpen())
m_ctrlComm.SetPortOpen(TRUE);//打开串⼝
else
AfxMessageBox("cannot open serial port");
m_ctrlComm.SetSettings("115200,n,8,1"); //波特率9600,⽆校验,8个数据位,1个停⽌位
m_ctrlComm.SetInputMode(1); //1:表⽰以⼆进制⽅式检取数据
m_ctrlComm.SetRThreshold(1);
//参数1表⽰每当串⼝接收缓冲区中有多于或等于1个字符时将引发⼀个接收数据的OnComm事件
m_ctrlComm.SetInputLen(0); //设置当前接收区数据长度为0
m_ctrlComm.GetInput();//先预读缓冲区以清除残留数据
现在你可以试试程序了,将串⼝线接好后,打开,并将串⼝设在com2,选上⾃动发送,也可以等会⼿动发送。再执⾏你编写的程序,接收框⾥应该有数据显⽰了。
先为发送按钮添加⼀个单击消息即BN_CLICKED处理函数,打开ClassWizard->Message Maps,选择类CSCommTestDlg,选择
IDC_BUTTON_MANUALSEND,双击BN_CLICKED添加OnButtonManualsend()函数,并在函数中添加如下代码:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论