串口通信4月18号

来源:互联网 发布:智能手机文件加密软件 编辑:程序博客网 时间:2024/06/05 17:20

学习朱友鹏老师嵌入式教程学习笔记之串口通信,部分文档转载之朱老师课堂笔记
推荐朱老师的视频网址;http://edu.51cto.com/roadmap/view/id-90.html
通信的概念;
通信过程有编码,传输,解码
1,同步通信和异步通信;按照发送方和接收方的时钟节拍是否一致
现在一般都采用异步通信。
2,电平信号和差分信号
(1)、电平信号和差分信号是用来描述通信线路传输方式的。也就是说如何在通信线路上表达1和0.
(2)、电平信号的传输线中有一个参考电平线(一般是GND),然后信号线上的信号值是由信号线电平和参考电平线的电压差决定。
(3)、差分信号的传输线中没有参考电平,所有都是信号线。然后1和0的表达靠信号线之间的电压差。
总结:电平信号的2根通信线之间的电平差异容易受到干扰,传输容易失败;差分信号不容易受到干扰因此传输质量比较稳定,现代通信一般都使用差分信号,电平信号几乎没有了。
总结2:看起来似乎相同根数的通信线下,电平信号要比差分信号要快;但是实际还是差分信号快,因为差分信号抗干扰能力强,因此1个发送周期更短。
串口通信的基本概念
特征 异步,串行,电平信号。
因为串口通信出现时间较早,cpu速率较低,传输距离近,所以干扰不明显,所以只规定了使用电平信号。
RS232电平和TTL电平
在RS232中,抗干扰强,传输距离小于15米,在串口使用rs232电平,但是芯片内部使用的是ttl电平,所以需要在开发板上在cpu和uart之间加一个电平转换芯片。
逻辑1(MARK)=-3V~-15V
逻辑0(SPACE)=+3~+15V
TTL电平 适合用在芯片内部。
+5V表示1,0V表示0.
工作模式;
单工通信;只能从A发送到B
全双工通信;能同时从两端发送和接受通信
半双工通信;两端都可以发通信,但是不可以同时发送
波特率
(1)波特率(bandrate),指的是串口通信的速率,也就是串口通信时每秒钟可以传输多少个二进制位。譬如每秒种可以传输9600个二进制位(传输一个二进制位需要的时间是1/9600秒,也就是104us),波特率就是9600.
(2)串口通信的波特率不能随意设定,而应该在一些值中去选择。一般最常见的波特率是9600或者115200(低端单片机如51常用9600,高端单片机和嵌入式SoC一般用115200).为什么波特率不可以随便指定?主要是因为:第一,通信双方必须事先设定相同的波特率这样才能成功通信,如果发送方和接收方按照不同的波特率通信则根本收不到,因此波特率最好是大家熟知的而不是随意指定的。第二,常用的波特率经过长久发展,就形成了共识,大家常用就是9600或者115200.

数据包的构成 ;起始位、数据位、奇偶校验位、停止位
(1)串口通信时,每个周期传输n个二进制位。这一个周期就叫做一个通信单元,一个通信单元是由:起始位+数据位+奇偶校验位+停止位组成的。
(2)起始位表示发送方要开始发送一个通信单元;数据位是一个通信单元中发送的有效信息位;奇偶校验位是用来校验数据位,以防止数据位出错的;停止位是发送方用来表示本通信单元结束标志的。
(3)起始位的定义是串口通信标准事先指定的,是由通信线上的电平变化来反映的。
(4)数据位是本次通信真正要发送的有效数据,串口通信一次发送多少位有效数据是可以设定的(一般可选的有6、7、8、9,99%情况下我们都是选择8位数据位。因为我们一般通过串口发送的文字信息都是ASCII码编码的,而ASCII码中一个字符刚好编码为8位。)
(5)奇偶校验位是用来给数据位进行奇偶校验(把待校验的有效数据逐个位的加起来,总和为奇数奇偶校验位就为1,总和为偶数奇偶校验位就为0)的,可以在一定程度上防止位反转。
(6)停止位的定义是串口通信标准事先指定的,是由通信线上的电平变化来反映的。常见的有1位停止位,1.5位停止位,2位停止位等。99%情况下都是用1位停止位。

总结:串口通信时因为是异步通信,所以通信双方必须事先约定好通信参数,这些通信参数包括:波特率、数据位、奇偶校验位、停止位(串口通信中起始位定义是唯一的,所以一般不用选择)
串口通信的基本原理;这次我们使用DB9来表示串口通信
三根通信线;Rx,Tx,GND
Rx为接收端,Tx为发送端。
串口控制器原理框图
这里写图片描述
1,整个串口控制器由接收端receiver,发送端transmitter构成
2,串口控制器挂在APB总线上,所以它的源时钟就是APB的总线时钟。
3,transmitter由发送缓冲区和发送移位器构成。我们要发送信息时,首先将信息进行编码(一般用ASCII码)成二进制流,然后将一帧数据(一般是8位)写入发送缓冲区(从这里以后程序就不用管了,剩下的发送部分是硬件自动的),发送移位器会自动从发送缓冲区中读取一帧数据,然后自动移位(移位的目的是将一帧数据的各个位分别拿出来)将其发送到Tx通信线上。
4,receiver由接收缓冲区和接收移位器构成。当通过串口线向soc发送信息时,信息通过Rx通信线进入接收移位器shifter,然后接收移位器自动移位将该二进制位保存入接收缓冲区buffer register,接收完一帧数据后receiver会产生一个中断给CPU,CPU收到中断后即可知道receiver接收满了一帧数据,就会来读取这帧数据。
总结:发送缓冲区和接收缓冲区是关键。发送移位器和接收移位器的工作都是自动的,不用编程控制的,所以我们写串口的代码就是:首先初始化(初始化的实质是读写寄存器)串口控制器(包括发送控制器和接收控制器),然后要发送信息时直接写入发送缓冲区,要接收信息时直接去接收缓冲区读取即可。软件工程师对串口操作的接口就是发送/接收缓冲区(实质就是寄存器,操作方式就是读写内存)
(5)串口控制器中有一个波特率发生器Buad-rate Generator,作用是产生串口发送/接收的节拍时钟。波特率发生器其实就是个时钟分频器,它的工作需要源时钟(APB总线来),然后内部将源时钟进行分频(软件设置寄存器来配置)得到目标时钟,然后再用这个目标时钟产生波特率(硬件自动的)。
串口功能的进化;
FIFO模式及其作用
(1)典型的串口设计,发送/接收缓冲区只有1字节,每次发送/接收只能处理1帧数据。这样在单片机中没什么问题,但是到复杂SoC中(一般有操作系统的)就会有问题,会导致效率低下,因为CPU需要不断切换上下文。
(2)解决方案就是想办法扩展串口控制器的发送/接收缓冲区,譬如将发送/接收缓冲器设置为64字节,CPU一次过来直接给发送缓冲区64字节的待发送数据,然后transmitter慢慢发,发完再找CPU再要64字节。但是串口控制器本来的发送/接收缓冲区是固定的1字节长度的,所以做了个变相的扩展,就是FIFO。
(3)FIFO就是first in first out,先进先出。fifo其实是一种数据结构,这里这个大的缓冲区叫FIFO是因为这个缓冲区的工作方式类似于FIFO这种数据结构。

DMA模式及其作用
(1)DMA direct memory access,直接内存访问。DMA本来是DSP中的一种技术,DMA技术的核心就是在交换数据时不需要CPU参与,模块可以自己完成。
(2)DMA模式要解决的问题和上面FIFO模式是同一个问题,就是串口发送/接收要频繁的折腾CPU造成CPU反复切换上下文导致系统效率低下。
(3)传统的串口工作方式(无FIFO无DMA)效率是最低的,适合低端单片机;高端单片机上CPU事物繁忙所以都需要串口能够自己完成大量数据发送/接收。这时候就需要FIFO或者DMA模式。FIFO模式是一种轻量级的解决方案,DMA模式适合大量数据迸发式的发送/接收时。

IrDA模式及其用法
(1)IrDA其实就是红外,红外就是红外线通信(电视机、空调遥控器就是红外通信的)。
(2)210的某个串口支持IrDA模式,开启红外模式后,我们只需要向串口写数据,这些数据就会以红外光的方式向外发射出去(当然是需要一些外部硬件支持的),然后接收方接收这些红外数据即可解码得到我们的发送信息。
串行通信与中断的关系
(1)串口通信分为发送/接收2部分。发送方一般不需要(也可以使用)中断即可完成发送,接收方必须(一般来说必须,也可以轮询方式接收)使用中断来接收。
(2)发送方可以选择使用中断,也可以选择不使用中断。使用中断的工作情景是:发送方先设置好中断并绑定一个中断处理程序,然后发送方丢一帧数据给transmitter,transmitter发送耗费一段时间来发送这一帧数据,这段时间内发送方CPU可以去做别的事情,等transmitter发送完成后会产生一个TXD中断,该中断会导致事先绑定的中断处理程序执行,在中断处理程序中CPU会切换回来继续给transmitter放一帧数据,然后CPU切换离开;有个状态寄存器,状态寄存器中有一个位叫发送缓冲区空标志,transmitter发送完成(发送缓冲区空了)就会给这个标志位置位,CPU就是通过不断查询这个标志位为1还是0来指导发送是否已经完成的。

210串行通信接口的时钟设计
(1)串口通信需要一个固定的波特率,所以transmitter和receiver都需要一个时钟信号。
(2)时钟信号从源时钟信号是外部APB总线(PCLK_PSYS,66MHz)提供给串口模块的,然后进到串口控制器内部后给波特率发生器(实质上是一个分频器),在波特率发生器中进行分频,分频后得到一个低频时钟,这个时钟就是给transmitter和receiver使用的。
(3)串口通信中时钟的设置主要看寄存器设置。重点的有:寄存器源设置(为串口控制器选择源时钟,一般选择为PCLK_PSYS,也可以是SCLK_UART),还有波特率发生器的2个寄存器。
(4)波特率发生器有2个重要寄存器:UBRDIVn和UDIVSLOTn,其中UBRDIVn是主要的设置波特率的寄存器,UDIVSLOTn是用来辅助设置的,目的是为了校准波特率的。
210开发板的串口初始化步骤;
1,初始化串口Tx和Rx的GPIO引脚功能。
2,关键寄存器的配置 ULCON,UCON,UMCON,UFCON,……
这里写图片描述
ULCON=0x03 //无校验位,8数据位,1停止位。
UCON=0x5 //收发都采用轮询模式
UMCON=0x0 //用于流控,我们不使用,可以全0
UFCON=0x0 //用于FIFO模式的设置,我们暂时不使用,所以可以全0设置
UBRDIV //波特率设置
UDIVSLOT //波特率辅助设置
波特率的计算和设置
(1)第一步,用PCLK_PSYS和目标波特率去计算DIV_VAL:
DIV_VAL = (PCLK / (bps x 16)) -1
(2)第二步,UBRDIV0寄存器中写入DIV_VAL的整数部分
(3)第三步,用小数部分*16得到1个个数,查表得uBDIVSLOT0寄存器的设置值
这里写图片描述
这里写图片描述
串口发送和接收函数的编写
注意;因为c速度比串口高很多,所以要先确定transmitter的缓冲区为空,才能再给数据。
UTXH寄存器保存缓冲区是否为空。
写发送函数,主要发送前要用while循环等待发送缓冲区为空才能发送。
void uart_init(void)
{
//首先先设置tx和rx的gpio
rGPA0CON = 0x00000000;
rGPA0CON = 0x00000022;
rULCON0 = 0x00000003;
rUCON0 = 0x00000005;
rUFCON0 = 0x0;
//设置波特率为115200
//rUBRDIV0 = 35; //DIV_VAL = (PCLK / (bps x 16)) -1
//rUDIVSLOT0 = 0x0888;//波特率是115200
//设置波特率为9600
rUBRDIV0 = 433; //DIV_VAL = (PCLK / (bps x 16)) -1
rUDIVSLOT0 = 0x2222;//波特率是9600
}
以上是uart串口的初始化程序
void main(void)
{
uart_init();
while(1)
{
while(!(rUTRSTAT0 & 0x2));//测试接收端缓冲区是否为空,等待空然后再送数据。
rUTXH0= c;
led_blink();
}
}

以上是对transmitter接收数据的测试,用secureCRT测试,注意波特率和去掉流控

0 0
原创粉丝点击