串口通信的基本概念

串口通信的特点:异步、串行、电平信号

  • 异步:串口通信的发送方和接收方之间是没有统一的时钟信号的
  • 电平信号:串口通信出现的时间较早,速率较低,传输的距离教地
  • 串行通信:串口通信每次同时只能传输1个二进制位

RS232电平和TTL电平

  • 电平信号是用信号线电平减去参考线电平得到电压差,这个电压差决定了传输值是1还是0
  • RS232电平中-3V~-15V表示1;+3 ~ +15V表示0;TTL电平则是+5V表示1,0V表示0
  • 不管哪种电平都是为了在传输线上表示1和0,区别在于适用的环境和条件不同。RS232的电平定义比较大,适合干扰大、距离远的情况:TTL电平电压范围小,适合距离近且干扰小的情况
  • 我们台式电脑后面的串口插座就是RS232接口的,在工业上用串口时都用这个,传输距离小于15米;TTL电平一般用在电路板内部两个芯片之间
  • 对于编程来说,RS232电平传输还是TTL电平是没有差异的。所以电平标准对硬件工程师更有意义,软件工程师只要略懂即可。(把TTL和RS232电平混接是不可以的)

波特率

  • 串口通信的速率,也就是串口通信时每秒钟可以传输多少个二进制位,如每秒钟可以传输9600个二进制位(传输一个二进制位需要的时间时1/9600秒,也就是104微秒),波特率就是9600
  • 串口通信的波特率不能随意设定,而应该在一些值中选择。一般最常见的波特率是9600或者115200

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

  • 串口通信时,收发是一个周期一个周期进行的,每一个周期传输n个二进制位。这个周期就叫做一个通信单元,一个通信单元是由起始位+数据位+奇偶校验位+停止位组成
  • 起始位表示发送方要开始发送一个通信单元,数据位是一个通信单元中发送的有效信息位,奇偶校验位是用来校验数据位,以防止数据位出错的:停止位是发送方用来表示本通信单元结束表示的

单工通信和双工通信

单工通信就是单方向,双工通信就是双方同时收发,半双工是可以双向发送但是发送时不能接收,接收不能发送。

串口通信原理

  • 三根通信线:Rx Tx GND
  • 任何通信都要有信息传输载体,或者是有线的或者无线的。
  • 串口通信是有线通信
  • 串口通信线最少需要2根(GND和信号线),可以实现单工通信,也可以使用3根通信线(Tx Rx GND)来实现全双工
  • 一般开发板都会引出SoC上串口引脚直接输出的TTL电平的串口,插座用插针式插座,每个串口引出的都有3个线(Tx Rx GND),可以用这些插座直接连接外部的TTL电平的串口设备
  • 通信前规定通信参数(波特率、数据位、奇偶校验位、停止位)

S5PV210串口通信接口详解

  • 整个串口控制器包含transmitter和receiver两部分,两部分功能彼此独立,transmitter负责210向外部发送信息,receiver负责从外部接收信息到210内部
  • 总线角度来讲,串口控制器是接在APB总线上的。对于我们编程的影响是:将来计算串口控制器时钟源时是以APB总线来计算的
  • transmitter由发送缓存区和发送移位器构成。我要发送信息时,首先讲信息进行编码(一般时ASCII码)成二进制流,然后将一帧数据(一般时8位)写入发送缓冲区(以后程序就不用管了,剩下的发送部分时硬件自动的),发送移位器会自动从发送缓冲区中读取一帧数据,然后自动移位(移位的目的是将一帧数据的各个位分别拿出来)将其发送到Tx通信线上
  • receiver由接收缓冲区和移位器构成。当有人通过串口线向我发送信息时,信息通过Rx通信线进入我的接收移位器,然后接收移位器自动移位将二进制位保存入我的接收缓冲区,接受完一帧数据后我们receiver会产生一个中断给CPU,CPU收到中断后即可知道receiver接收满了一帧数据,就会来读取这一帧数据
  • 我们写串口的代码:首先初始化(初始化的实质时初始化寄存器)好串口控制器(包括发送控制器和接收控制器),然后要发送信息时直接写入发送缓冲区,要接收信息时直接去接收缓冲区读取即可。可见,串口底层的工作,程序员不用操心。软件工程师对串口操作的接口就是发送/接收缓冲区(实质就是寄存器,操作方式就是读写内存)
  • 串口控制器中有一个波特率发生器,作用时产生串口发送/接收的节拍时钟。波特率发送器其实就是一个时钟分频器,它的工作需要源时钟(APB总线来),然后内部将源时钟进行分频(软件设置寄存器来配置)得到目标时钟,然后再用这个目标时钟产生波特率(硬件自动的)

FIFO模式及作用

  • 典型的串口设计,发送/接收缓冲区只有1个字节,每次发送/接收只能处理一帧数据。这样单片机中没问题,但是在复杂的SoC中(一般有操作系统的)就会有问题,会导致效率低下,因为CPU需要不断切换上下文
  • 解决方案就是想办法扩展串口控制器的发送/接收缓冲区,如发送/接收缓冲器设置位64字节,CPU一次过来直接发送缓冲区64字节的待发送数据,然后transmitter慢慢发,发完再找CPU再要64字节。但是串口控制器本来的发送/接收缓冲区时固定的1字节长度的,所以做了一个变相的扩展,就是FIFO
  • FIFO就是先进先出,其实是一种数据结构,这里这个大的缓冲区叫做FIFO是因为这个缓冲区的工作方式类似于FIFO这种数据结构。

DMA模式及作用

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

IrDA模式及作用

  • IrDA其实就是红外,红外是一种通信。
  • 红外通信的原理是固定发送方固定间隔时间向接收方发送红外信号或者不发送红外信号,接收方每隔固定时间去判断有无红外线信号来接收1和0
  • 红外通信和串口通信非常像,都是每隔固定发送1或者0(判断1或0的物理方式不同)给接收方来通信。因此210就利用串口通信来实现了红外发送和接收。
  • 我们只需要像串口写数据,这些数据就会以红外光的方式向外发射出去,然后接收方接收这些红外数据即可解码得到我们的发送信息。

串口通信域中断的关系

  • 串口通信分为发送和接收2部分,发送方一般不需要中断。接收方一般使用中断,也可以使用轮询方式
  • 发送方可以选择使用中断,也可以选择不适用中断,使用中断的工作情景:发送方先设置好中断并绑定一个中断处理程序,然后发送方丢一帧数据给transmitter,然后transmitter发送耗费的时间来发送这一帧数据,这段时间内发送方CPU可以去做别的事情,等transmitter发送完成后会产生一个TXD中断,该中断会导致事前绑定的中断处理程序执行,在中断处理程序中CPU会切换回来继续给transmtter放一帧数据,然后CPU切换离开。
  • 不适用中断的工作情景:发送方事先禁止中断(当然也不需要给相应的中断处理程序了),发送方的CPU给一帧数据到transmitter,然后transmitter耗费一段时间来发送这一帧数据,这段时间CPU在这里等(CPU没有切换去做别的事情),待发送方发送完成后CPU再给它一帧数据继续发送直到所有数据发送完。

串口通信为什么需要时钟

  • 因为串口通信需要一个固定的波特率,所以transmitter和receiter都需要一个时钟信号。
  • 时钟信号从哪里来?APB总线提供,然后进到串口控制器内部后给波特率发生器(实质上是一个分频器),在波特率发送器中进行分频,分频后得到一个低频时钟,这个时钟就是给transmitter和receiver使用的
  • 串口通信中时钟的设置主要看寄存器设置。重点的有:寄存器源设置(为串口控制器选择源时钟,一般选择为PCLK_PSYS,也可以是SCLK_UART),还有波特率发生器的2个寄存器。
  • 波特率发生器的2个寄存器分别是UBRDIVn和UDIVSLOTn,其中UBRDIVn是主要设置波特率寄存器的,UDIVSLOTn是用来辅助设置的,目的是为了校准波特率的。

实际编程时

初始化uart寄存器(uart_init)

  • 初始化串口的Tx和Rx引脚所对应的GPIO(查原理图可知TX和RX对应的GPA0_0和GPA0_1)
  • GPA0CCON(0xE0200000),bit[3]~bit[0] = 0b0010,bit[7] ~ bit[4] = 0b0010
  • 关键寄存器UCON0 ULCON0 UMCON0 UFCON0 UBRDIV0 UDIVSLOT0
  • ULCON0 = 0x03 // 无校验位,8数据位,1停止位
  • UCON0 = 0x05 // 发送和接收都是polling mode轮询模式
  • UMCON0 = 0x00 //关闭流控
  • UFCON0 = 0x00 //禁止FIFO
  • UBRDIV0 = 36 //DIV_VAL = (PCLK / (bps x 16)) −1,写入整数部分
  • UDIVSLOT0 =

uart的发送和接收的寄存器

UTRSTAT0、UTXH0、URXH0

S5PV210串口设置源文件

// S5PV210串口设置源文件

#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)




// 串口初始化程序
void uart_init(void)
{
    // 初始化TX RX对应的初始化引脚
    rGPA0CON &= ~(0xff << 0);           // 把寄存器的bit0 ~ bit7全部清零
    rGPA0CON |= 0x00000022;             // 0b0010,RX TX
    rULCON0 = 0x03;
    rUCON0 = 0x05;
    rUMCON0 = 0x00;
    rUFCON0 = 0x00;

    // 波特率设置  DIV_VAL = (PCLK / (bps x 16)) −1
    // PCLK_VAL = 66M, 余数是0.8
    //rUBRDIV0 = 34;
    //rUDIVSLOT0 = 0xdfdd;

    // PCLK_VAL = 66.7M, 余数是0.18
    // (66700000/(115200*16)-1) = 35.18
    rUBRDIV0 = 35;
    //num of 1's in UDIVSLOTn)/16,然后查表
    rUDIVSLOT0 = 0x0888;
}


// 串口发送程序,发送一个字节
void putc(char c)
{
    // 串口发送一个字符,其实就是把一个字节发给缓冲区(实质是发送到UTXH0缓冲寄存器中)
    // 因为串口控制器发送1个字节的速度远远地域CPU的速度,所以CPU发送一个字节前必须确认串口控制器当前缓冲区是空的
    while(!(rUTRSTAT0 & (1 << 1)));
    rUTXH0 = c;

}

// 串口接收程序,轮询方式,接收一个字节
char getc(void)
{
    while(!(rUTRSTAT0 & (1 << 0)));
    return rURXH0;

}

主程序

// 主程序

#include "stdio.h"

void uart_init(void);
void delay(void);

int main(void)
{
    uart_init();

    int a = 1234;

    while(1)
    {
        printf("test for printf, a = %d\n", a);
        delay();
    }
    

    return 0;


    /*while (1)
    {
        uart_putc('a');
        delay();
    }*/
    
    

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值