串口通信

来源:互联网 发布:国家药监局数据网查询 编辑:程序博客网 时间:2024/06/16 07:26

通信基础

通信中的两个重要方面:

  • 信息的表示和解析方式,通信双方需要事先约定好,应该保持一致
  • 信息的传递方式,信息在传输介质上的传输过程

通信过程分为编码,传输,解码三个基本步骤。

电子通信概念

同步通信和异步通信

同步:

发送方和接收方按照同一个时钟节拍工作,这种方式配合很好,但是,需要发送方需要同时发送时钟信号给接收方,接收方根据时钟信号安排自己的工作节拍,需要一根时钟线来传递时钟信号,用在信息交换频率固定,或者通信频率较固定的情况,

异步:

发送方和接收方没有统一的时钟节拍,各自按照自己的节拍工作,在双方通信频率不固定的情况下适合进行异步通信,接收方不必一直等待发送方,发送方在发送信息时,会首先发送一个信息开始的起始信号,接收方接收到该起始信号,就开始接受后面紧跟着的有效信息,直到收到发送方发过来的结束信号,才认为信息结束

电平信号和差分信号

用于描述通信线路的传输方式,指如何在通信线路上表达1和0

电平信号

传输线中有一个参考电平线GND(GROUND),信号线上的值由信号电平和参考电平线的电压差决定的

差分信号

传输线中没有参考电平,都是信号线,用信号线的电压差表示0和1
电平信号两根通信线之间的电平差异容易受到干扰,容易传输失败,而差分信号则没有该问题,传输比较稳定,现代通信基本都使用差分信号

并行通信和串行通信

区别在于通信线的根数,发送方和接收方同时可以传递的信息量的多少

现代通信大部分都是异步,串行,差分通信,而串口则是异步,串行,电平通信。

串口通信概念

串口通信特点

  • 异步:发送和接收方没有统一的时钟信号
  • 电平信号:有一个参考电平GND和通信电平,速率较低,传输距离近,干扰不明显
  • 串行:同一时间只能传输一个二进制位,

RS232和TTL

电平信号是信号线电平减去参考线电平得到的电压差,决定了传输的是0还是1,代表0和1的电压不是固定的,取决于电平标准。

  • RS232,-3~-15V代表1,3~15V代表0,适合干扰大,距离远的场合
  • TTL,+5V表示1,0V表示0,适合距离近干扰小的场合,例如开发板内部两个芯片之间就是使用TTL进行通信

波特率

bandrate指的是串口通信的速度,每秒钟可以传输的二进制位,不能随意设置,只能在一些固定值中选择,常见的有9600和115200。

起始位,数据位,奇偶校验位,停止位

每个周期可以传输n个二进制位,一个周期叫做一个通信单元,每个通信单元由起始位,数据位,奇偶校验位和停止位组成

  • 起始位:表示发送方要发送一个通信单元,由串口通信标准来定义,由通信线上的电平变化来反映
  • 数据位:该通信单元中的有效信息位,可选6,7,8,9位
  • 奇偶校验位:用来校验数据位,防止数据位出错。或者位反转
  • 停止位:表示发送方通信单元结束,1,1.5,2位停止位都有,常用1位

串口通信原理

通信线

任何通信都需要载体,在串口中载体是串口线进行的无线通信,串口线有很多种,串口通信线最少需要两根(GND,信号线),从而可以实现单工通信,三根线(GND,RX,TX)可以实现全双工通信,一般开发板会引出Soc上串口引脚直接输出TTL电平的串口,使用杜邦线可以接到USB转串口控制器上,但是X210上没有。
串口通信本身不会协商通信参数,需要在通信前双方事先约定好,最重要的有波特率,数据位,奇偶校验,停止位4个参数,串口数据以二进制的方式在信道上传输,发送发每隔一定时间将数据放到通信线上去,时间固定为(1/波特率) 秒,接收方通过读取通信线上的电平高低区分接收到的数据是1还是0,起始时间按照接收到起始位的时间开始,每隔(1/波特率) 秒读一次,停止时间按照收到停止位的时间截止,中间接收到的是数据位和奇偶校验位,这样读完第一帧数据,以后的数据帧都是这样读取的,串口上所有的数据都需要编码成二进制数据来发送和接收。
X210上的DB9串口是一种早期串口通信接口,其中有9根通信线,其中的GND,TX,RX最重要,剩余的和流控有关,一般不适用,因为我们主要使用串口做调试,需要禁用流控。

S5PV210串口

串口分析

用户手册8.1讲解UART,串口框图:
这里写图片描述

总线

Peripheral BUS属于外设总线,所有的外设通信模块挂载在该总线,包括SPI,I2C等,该总线还负责提供时钟,属于APB域。
串口包括发送器和接收器组成,彼此独立工作。

发送器和接收器

Transmit Buffer Register是一个缓冲器,待发送的数据会被放在这里,然后通过Transmit Shifter按位向外发送,接收器通过Receive Shifter按位接收数据,并存储在Receive Buffer Register缓冲区中,接收一帧数据后产生中断信号,CPU收到中断信号就知道串口接收到了一帧数据,从而提取该数据。

波特率生成器

Buad-rateGenerator作用是产生串口发送和接收的节拍时钟,同时控制发送器和接收器的移位器,它其实是一个分频器,需要APB总线提供源时钟,将其分频后得到目标时钟,从而产生波特率,分频需要设置寄存器来配置。

自动流控AFC

流控用于保持数据收发的稳定性,在双方速度不一致的时候可以保证发送和接收不会漏掉数据,现在的串口通常用于调试,而不是数据传输,基本上不用流控。

FIFO模式

Transmit/Receive FIFO Register,该寄存器用于控制串口通信模式中的FIFO模式,在典型的串口中,发送和接收缓冲区只有8Bit(byte),每次只能发送和接收只能处理一个字节的帧数据,在大数据量通信时,CPU需要反复切换上下文,导致效率低下,所以可以将发送/接收缓冲区设置为64个Byte,这样就提高了效率,FIFO就是将别的寄存器当做发送/接收缓冲区使用,缓冲区中数据都是FIFO模式进出的。

DMA模式

DMA是将别的内存当做发送/接收缓冲区使用,是DSP技术一部分,核心是缓冲区在交换数据时不需要CPU参与,由模块自己完成,相比FIFO,DMA适合大量并发式的数据传输。

IrDA模式

红外通信,210上的某个串口支持红外模式,开启了之后只需要向串口写数据,这些数据就会以红外光的形式发送出去,接收方接收到红外光数据则可解码这些数据。

串口和中断

串口分为发送和接收两部分,发送方一般不需要中断,接收方就必须使用中断。
中断有接收中断,发送中断以及出错中断几种类型.

串口的时钟

因为串口需要固定的波特率,所以需要时钟信号,这个时钟信号来自于APB总线,所以说串口挂在APB总线上的,属于PLCK_PSYS的66MHz,进入串口之后到波特率发生器,在这里分频得到低频时钟来产生波特率,供发送器和接收器使用,时钟配置主要有两个:

  • 寄存器源设置,为串口控制器选择时钟,一般为PLCK_PSYS或者SCLK_UART
  • 波特率发生器UBRDIVn,设置波特率
  • 波特率发生器UDIVSLOTn,辅助校准波特率

串口编程

串口初始化程序

#define GPA0CON 0xE0200000#define UCON0 0xE2900004#define ULCON0 0xE2900000#define UMCON0 0xE290000C#define UFCON0 0xE2900008#define UBRDIV0 0xE2900028#define UDIVSLOT0 0xE290002C#define UTRSTAT0 0xE2900010#define UTXH0 0xE2900020#define URXH0 0xE2900024#define rGPA0CON (*(volatile unsigned int *)GPA0CON))#define rUCON0 (*(volatile unsigned int *)UCON0))#define rULCON0 (*(volatile unsigned int *)ULCON0))#define rUMCON0 (*(volatile unsigned int *)UMCON0))#define rUFCON0 (*(volatile unsigned int *)UFCON0))#define rUBRDIV0 (*(volatile unsigned int *)UBRDIV0))#define rUDIVSLOT0 (*(volatile unsigned int *)UDIVSLOT0))#define rUTRSTAT0 (*(volatile unsigned int *)UTRSTAT0))#define rUTXH0 (*(volatile unsigned int *)UTXH0))#define rURXH0 (*(volatile unsigned int *)URXH0))// 串口初始化程序,以串口0为例void uart_init(void) {    // 初始化串口Tx和Rx引脚对应的GPIO(GPA0_0和GPA0_1)    //  配置GPA0CON寄存器(0xE0200000),bit0-3配置为0010,表示启用UART_0_RXD    //  配置GPA0CON寄存器(0xE0200000),bit4-7配置为0010,表示启用UART_0_TXD    // 加起来是00100010,就是0x22    rGPA0CON &=~(0xff<<0);    rGPA0CON |= 0x22;    // 初始化关键寄存器    // UCON0:0x5    //  第10位配置时钟源,0表示使用PCLK,1表示使用SCLK_UART,我们选择使用0    //  2-3位配置发送模式,我们配置为01表示使用polling模式    //  0-1位配置接收模式,我们配置为01表示使用polling模式    //  加起来是0101,就是0x5    rUCON0 = 0x5;    // ULCON0:0x3    //  第6为配置为0,表示使用普通模式,配置为1表示红外模式    //  3-5位配置奇偶校验位,000无校验    //  第2为表示停止位,配置为0表示1位停止位    //  0-1位表示数据位,配置为11表示8个数据位    //  加起来是00000011 = 0x3.所以ULCON0配置为0x3    rULCON0 = 0x3;    // UMCON0:全部配置为0,禁止modem    rUMCON0 = 0x0;    // UFCON0:FIFO相关,全部配置为0表示不使用FIFO    rUFCON0 = 0x0;    // UBRDIV0:和波特率相关,要根据公式计算 DIV_VAL = (PCLK / (bps x 16)) - 1    rUBRDIV0 = 34;    // UDIVSLOT0:和波特率相关,要根据公式计算    rUDIVSLOT0 = 0xdfdd;}

串口发送代码

// 串口发送程序,发送一个字节void uart_putc(char c) {    // 把字节放到发送缓冲区寄存器UTXH0中,只有0-7前8位可供放入数据    // 读取状态寄存器UTRSTAT0,只有当发送缓冲区为空的时候才放进去数据    // 第2位,0表示发送缓冲区非空,1表示发送缓冲区为空    while(!(rUTRSTAT0 & (1<<2)));    rUTXH0 = c;}

串口接收代码

// 串口接收程序,接收一个字节char uart_getc(void) {    while(!(rUTRSTAT0 & (1<<0)));    return rUTXH0;}

串口调用程序

// 串口程序void uart_prog(void) {    // 执行串口初始化    uart_init();    // 执行串口发送    while(1) {        uart_putc('a');        sleep();    }}

uart-stdio

串口的标准输入输出移植,是和printf和scanf是绑定的,读取和发送就会走标准输入输出通道,在这里我们的标准输出是串口,标准入是串口,我们要做到从串口输入,打印到串口。

printf函数工作原理

printf内部实际调用了两个重要函数:

  • vsprintf负责格式化打印信息,最终得到串字符串,等待输出
  • putc负责操控硬件,将信息发送出去

printf函数使用了C语言的可变参数,重要的概念有va_start/va_arg/va_end.
我们本地移植的基本概念就是,使用移植好的printf和scanf,将我们已经写好的putc放进去编译即可。

0 0
原创粉丝点击