上两篇文章中,已经实现了GPIO的通用输出以及通用输出模式,从本文开始,笔者将开始有关GPIO的复用功能的介绍,首先是最常用复用功能——串口,本文主要是介绍一些关于通信以及串口的基本概念。
通信协议:通信双方进行信息交换(接收或发送)要满足的规则,而这个规则,不仅有如下图所的软件层的规则(软件层主要是双方互相约定了数据每一位的具体含义,以及 ‘断句’ 位置),还需要规定硬件层怎么连接,用多少线连接,每个线是什么功能等等。就比如常见的单总线协议,就只使用了一个数据线连接主从机,当然是在共地的情况下;而最常见的串口就是两个线,一个TX,一个RX,双方连接过程中还需要交叉连接,这些都是属于硬件层,或者说是物理连接的规则。
关于通信协议的分类有着多种分法,这里选用几种常见的分类方式来做个说明。
所谓的同步异步通信,主要区分在于通信双方在通信过程中是使用的同一个时钟,一根绳上的蚂蚱;还是双方各自使用自己的时钟,自顾自的。如下图所示,就是一种常见的同步通信,通信双方使用同一个时钟线,按照时钟线上的频率来传输和接收数据。
同步通信协议:**通信双方在同一个时钟脉冲作用下工作(时钟线)**如:IIC SPI
而异步通信,通信双方没有共同的时钟线,只有数据线;双方通过约定数据发送的速率以及起始位,停止位数据位的方式来实现数据传输。
异步通信协议:通信双方不在同一个时钟脉冲作用下工作
如:UART USB can 单总线
这种分类方法的区别方式就是看通信双方有没有同步的时钟线,有就是同步通信,没有就是异步通信。
全双工通信,就是说同一时间,设备A既可以给设备B发送数据,也可以接收从设备B发送过来的数据。全双工最少要求有两个数据线,发送和接收走的不同的数据线,且互不干涉,可以同时进行。
全双工:有两个数据线,发送线和接收线
如:UART SPI
半双工一般就只有一根数据了,也就是同一时间,只能一个设备发送数据,另一个设备接收数据,不能两个设备同时发送和同时接收数据。半双工既能实现接收也能实现发送,但是同一时刻同一设备只能接收或者只能发送,不能同时进行。
半双工:有一根数据线,可以发可以收,但不能同时进行
如:单总线
单工 :有一根数据线,要么只能发送,要么只能接收(一般很少遇到,大多数的外设都是需要发送和接收的)
现场协议主要是应用在工业控制现场,由于使用环境变得复杂,各种干扰会出现并对通信造成影响,所以这类通信协议一般采用差分信号或者提高高低电压范围的方式来提高抗干扰能力,不同协议有不同的电压信号代表逻辑值0和1。
此图来自百度百科关于现场总线的解释。
现场总线:工业控制现场总线(可远距离传输数据)
如:485总线—千米级别
can总线—十千米级
板级通信见名知意,就是应用在PCB板上的的通信协议,主要是指SPI、IIC、UART、1-Wire这一类。
例如下图中白色的SCL与SDA这两个线就属于板级总线。
板级总线:芯片之间通信(距离长会被干扰)
如:IIC/SPI/8080
按位传输,一位一位的发送,其优势在于传输数据所用的线极少,一个数据线即可完成数据传输。但是速度不如并行通信。
并行:一次发多位, 多根线,其优势是传输数据的速度快,但是需要占用较多的IO口。
有线通信就是通过线缆进行传输数据,其优势在于可靠性强,但缺点也在于对于复杂项目,线缆过长会造成现场混乱。
而无线通信好处在于不需要线缆,会比较方便,但是相对也没有有线通信的稳定性高。GSM , 蓝牙, 433(500m),2.4G,wifi这些都是常用的无线通信。
使用STM32实现上面的那些通信协议时一般有两种方案,一种是使用IO口模拟协议的时序,另一种就是配置对应通信协议的片上外设,通过片上外设来处理和获取数据。
配置好对应协议控制的功能
协议控制器会自己发送
不需要看相应时序
看框图,找配置流程,写初始化函数
IO口配置成复用功能
通过IO口模仿对应协议的控制器
通过高低电平实现通信时序的功能
相对于控制器来说不是很稳定
IO口配置成通用功能
需要看时序图
在了解了上面那么多有关通信的内容后,现在开始进入主题,什么是串口通信,串口通信能干什么,串口通信要怎么使用。
串口通信是一种设备间常用的串行通信方式,串口按位(bit)发送和接收字节。尽管比特字(byte)的串行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。
通用同步异步收发器 (USART) 也就是STM32上的串口,注意还有另外一种名称——UART;二者的区别在于,USART内部有智能卡协议、红外协议,而UART则没有。
这里的命名既说了同步又说了异步收发,按照上面的协议分类,他应该只能属于一种协议才对,是这样的,STM32的USART设置的有同步时钟线,如果硬件连接这个时钟线,那就是同步通信,如果不连接这个线,那么就是异步通信,在实际应用中,大多使用异步通信。
所以参照上面的协议介绍,串口通信属于,异步、串行、全双工、有线通信。
那么STM32F407的串口一共有多少组呢,这个在数据手册是有介绍的,一共有六组,其中USART有四组,UART有两组。
既然看了数量,那在顺便瞅一眼他们各自挂接的时钟线,可以发现,对于F407来说,USART1与USART6挂接在APB2上,而USART2、USART3、USAR4、USART5则是挂接在APB1上的,每个串口对应在哪个时钟线上,这点是需要知道的,因为后买编程需要使用。
所谓数据帧就是串口每次发出的数据包内容,前面提到了,串口通信在发送数据的时候是按照一位一位去发送的,也就是单次发送的只有0或者1,为了将这些“00100110101”解析成对应的数据,通信双方需要约定帧格式。
例如上图这个传输过程就是传输了一个ascll 码为0x4D的字符 ‘M’ ;
在STM32的串口通信中常用的数据帧格式为:
一个起始位 八位数据位 一个停止位,没有使用奇偶校验,例如我们发送一个字符A的数据帧就是如下图所示:STM32 使用的是小端模式,也就是说,当我们给一个int型的变量存入0x12345678时,其低地址存放的就是78h,高地址存放的是12h。
数据帧:传输一包数据 一帧数据
一帧发一个字节数据(只能发送字符char类型的)
起始位(1) 数据位(8-9)可配置 停止位(0.5/1/2)可配置
由于STM32的串口输出是TTL电平的,如果要与其他工控机通信的话,需要使用到SP3232IDR的电平转换芯片才可以通信。
我们平时与PC机通信使用的大多是USB口,USB的电平与TTL也不一样,所以还也需要有电平转换的IC来实现中转,这里常用的就是USB—TTL的CH340芯片,在使用CH340之前需要我们安装其对应的驱动,这也是为什么在之前搭建开发环境时需要安装这个驱动的原因。
一般的开发板外接USB转串口都是用使用的PA9和PA10这一组管脚,没有统一的标准,但是很多板子都是这么做的。
前面说了一堆关于串口的知识,在这里做个小结, 串口收发的本质实际上就是 接收和发送字符,需要掌握的无非也就是串口的四个要素:
串口的四要素分为:波特率 数据位 停止位 奇偶校验位
串口通信的必要条件:
两台设备进行通信要确保双方的四要素保持一致才能通信,下图是PC端得四要素配置,也就是说,如果板子要和PC能够通信,那么板子端的四要素也得跟PC端的配置一样。
那么怎么配置板子端的四要素呢,继续往下看。
在弄清了STM32串口的硬件连接方式以及通信数据帧格式后,就该选取配置方案了,对于串口这个模块,绝大多数都是用的USART的控制器来实现的,几乎没有人使用IO口模拟来做,只有I2C、单总线才会更多的偏向使用IO口模拟通信。
关于怎么配置的问题,参考前面学习GPIO的配置流程,首先肯定要去查看其对应的框图,根据框图搞清楚大致的通信流程,然后再去查看对应的寄存器,最后根据流程编写代码。
那么接下来开始分析USART的框图:
串口的整体框图如下图所示,一共分为了三个部分:
1.最上端叫做串口数据的收发过程;
2.中间叫做串口的控制过程;
3.最下面叫做波特率的计算过程。
和之前的GPIO一样,为了方便理解,还是将框图拆开来一个个的分析。
如下图所示:其中的TX、RX就是STM32的串口通信管脚,TX对应的是STM32的发送脚,从图中可以看出,TX的数据来自发送移位寄存器,而且是通过串行传输方式,一位一位的传输的,而方位移寄存器的数据又是来自上方的发送数据寄存器,且是并行传输,也就是说,需要发送数据时,CPU通过总线将数据写入到发送数据寄存器中,发送数据寄存器直接并行传输,一次性将一个字符存入发送位移寄存器,然后发送位移寄存器一位一位的将数据传输到外接通信设备。
这里有几个需要注意和思考的点
1.CPU写数据到发送数据寄存器之前要检测之前的发送是否完成,上一帧数据发送完成了才可以写到发送数据寄存器,如果上一帧数据发送未完成则要等待发送完成;
2.那么CPU如何检测之前的数据是否发送完成?这是由于在内部有相应的发送完成标志位,当数据发送完成后会有对应的寄存器被置位,具体的到后面的寄存器讲解部分再做介绍。
然后是接收部分,同样的,外界的数据通过RX一位一位的进入接收移位寄存器,当接收移位寄存器检测到接收完成时,会将数据传输给接收数据寄存器,然后CPU再从接收数据寄存器中将接收到的数据读走。
注意:CPU在读数据前要检测是否接收完成, 接收完成就可以读到变量中,如果没有接收完成,要等待接收完成再读到变量中。
思考:如何检测是否接收完成?与发送一样内部也有相应的接收完成标志位,通过检测对应的寄存器即可,这个在后面的寄存器介绍中会详细描述。
开发人员需要做的工作:
如果是发送数据,判断上一帧有没有发送完,发送完了就往发送数据寄存器中写入数据(1帧),没有发送完就继续等待接收完成。
如果是接收数据,判断上一帧数据有没有接收完毕,接收完毕了就从接收数据寄存器中读取数据(1帧),没有接收完毕就等待接收完毕。
这一块的伪代码:
发送数据的过程
{
等待发送移位寄存器为空 (确保每一帧 每一帧是分开的)
发送数据
}
接收过程
{
等待接收移位寄存器为满
接收数据
}
如下图所示:图中看得出来有很多的寄存器对发送控制和接收控制单元进行配置了,具体的配置放到后面的寄存器介绍再说,然后两个橙色框内的硬件流以及同步时钟引脚这些我们都用不到,所以暂时也不看。
这部分我们需要知道就是以下三点:
1.此部分是配置串口发送和接收的使能以及前面提到的四要素中的绝大部分,具体怎么配置再下一篇的寄存器中描述,只需要知道这部分就是代码中初始化串口所需要进行配置的就行了。
2.上一步的发送位移寄存器是受到本部分的发送控制器控制的;
3.上一步接收移位寄存器实受到本部分的接收控制器控制的。
伪代码以及配置了流程也留到下一篇的寄存器介绍中。
最后是框图的第三部分,也就是波特率的计算过程,
所谓的波特率就是表示数据的传输速率,常用的就是115200与9600,使用的时候注意将通信双方配置为波特率一致即可,上一步骤配置了四要素中的三个,这一步是专门用来管理第四个要素波特率的。
这个框图也不需要看的太过认真,需要了解的就是DIV_Mantissa存放的是USARTDIV的整数位,DIV_Fraction存放的是USARTDIV的小数位,
这个计算过程参考下面的这个公式即可,,实际上也就是上图下方的公式做了变形:
整个公式中,fck是对应时钟线的频率,这个是通过数据手册可以查到的,就用USART1来说,它在APB2上,时钟频率为86 000 000HZ;
然后波特率我们也知道,要与上位机一致,这里设置为115200,
然后是OVER8这个是串口的8倍过采和16倍过采,在寄存器中有介绍,我们一般选择16倍超采,也就是OVER8的值为0,
这样一替换就只剩下了USARTDIV是一个未知数,也就是说,我们需要对应配置的只有这个USARTDIV,上面提到了由于它有小数,所以在写入USART_BRR寄存器时需要做一点处理,这里我们举个栗子,以串口USART1 16倍过采来做个计算,看最终USART_BRR的数据如何写入。
公式转换:
USARTDIV=FCK/过采样/波特率
USARTDIV=fck/(过采样*波特率)
使用串口1
波特率:115200 时钟大小:84000000 过采样:16
float USARTDIV;
unsigned int DIV_M;
unsigned int DIV_F;
USARTDIV=84000000/16/115200; // 45.57291666666667
DIV_M =(u32) USARTDIV;//读取整数部分
DIV_F = (USARTDIV- DIV_M)*16+0.5 f //考虑四舍五入
USART1->BRR = DIV_M<<4 | DIV_F;
关于串口的基础概述就写到这,下一篇分析寄存器以及编写初始化代码实现串口的通信。文中如有不妥之处欢迎大家批评指正。
嵌入式学习笔记——概述http://t.csdn.cn/mxfw3
嵌入式学习笔记——基于Cortex-M的单片机介绍http://t.csdn.cn/HOQ14
嵌入式学习笔记——STM32单片机开发前的准备http://t.csdn.cn/268iD
嵌入式学习笔记——STM32硬件基础知识http://t.csdn.cn/eulBl
嵌入式学习笔记——认识STM32的 GPIO口http://t.csdn.cn/wdAkx
嵌入式学习笔记——使用寄存器编程操作GPIOhttp://t.csdn.cn/n26Ur
嵌入式学习笔记——寄存器实现控制LED小灯http://t.csdn.cn/M2VmM
嵌入式学习笔记——使用寄存器编程实现按键输入功能http://t.csdn.cn/1bMRP
嵌入式学习笔记——STM32的USART通信概述http://t.csdn.cn/BQ3ag