1.7.6.S5PV210串行通信接口详解3
1.7.6.1、串行通信与中断的关系
(1)串口通信分为发送/接收2部分。发送方一般不需要(也可以使用)中断即可完成发送,接收方必须(一般来说必须,也可以轮询方式接收)使用中断来接收。
(2)发送方可以选择使用中断,也可以选择不使用中断。使用中断的工作情景是:发送方先设置好中断并绑定一个中断处理程序,然后发送方丢一帧数据给transmitter,transmitter发送耗费一段时间来发送这一帧数据,这段时间内发送方CPU可以去做别的事情,等transmitter发送完成后会产生一个TXD中断,该中断会导致事先绑定的中断处理程序执行,在中断处理程序中CPU会切换回来继续给transmitter放一帧数据,然后CPU切换离开;不使用中断的工作情景是:发送方事先禁止TXD中断(当然也不需要给相应的中断处理程序了),发送方CPU给一帧数据到transmitter,然后transmitter耗费一段时间来发送这帧数据,这段时间CPU在这等着(CPU没有切换去做别的事情),待发送方发送完成后CPU再给它一帧数据继续发送直到所有数据发完。CPU是怎么知道transmitter已经发送完了?原来是有个状态寄存器,状态寄存器中有一个位叫发送缓冲区空标志,transmitter发送完成(发送缓冲区空了)就会给这个标志位置位,CPU就是通过不断查询这个标志位为1还是0来指导发送是否已经完成的。
(3)因为串口通信是异步的,异步的意思就是说发送方占主导权。也就是说发送方随时想发就能发,但是接收方只有时刻等待才不会丢失数据。所以这个差异就导致发送方可以不用中断,而接收方不得不使用中断模式。
1.7.6.2、210串行通信接口的时钟设计
(1)串口通信为什么需要时钟?因为串口通信需要一个固定的波特率,所以transmitter和receiver都需要一个时钟信号。
(2)时钟信号从哪里来?源时钟信号是外部APB总线(PCLK_PSYS,66MHz)提供给串口模块的(这就是为什么我们说串口是挂在APB总线上的),然后进到串口控制器内部后给波特率发生器(实质上是一个分频器),在波特率发生器中进行分频,分频后得到一个低频时钟,这个时钟就是给transmitter和receiver使用的。
(3)串口通信中时钟的设置主要看寄存器设置。重点的有:寄存器源设置(为串口控制器选择源时钟,一般选择为PCLK_PSYS,也可以是SCLK_UART),还有波特率发生器的2个寄存器。
(4)波特率发生器有2个重要寄存器:
UBRDIVn和UDIVSLOTn,其中UBRDIVn是主要的设置波特率的寄存器,UDIVSLOTn是用来辅助设置的,目的是为了校准波特率的。
1.7.7.S5PV210串行通信编程实战1
1.7.7.1、整个程序流程分析
(1)整个串口通信相关程序包含2部分:uart_init负责初始化串口,uart_putc负责发送一个字节
1.7.7.2、串口控制器初始化关键步骤
(1)初始化串口的Tx和Rx引脚所对应的GPIO(查原理图可知Rx和Rx分别对应GPA0_1和GPA0_0)
(2)GPA0CON(0xE0200000),bit[3:0] = 0b0010
bit[7:4] = 0b0010
(3)初始化这几个关键寄存器UCON0 ULCON0 UMCON0 UFCON0 UBRDIV0 UDIVSLOT0
1.7.7.3、主要的几个寄存器
(1
)ULCON0 = 0x3 // 0校验位、8数据位、1停止位
(2)UCON = 0x5 // 发送和接收都是polling mode
(3)UMCON0 = 0x0 // 禁止modem、afc
(4)UFCON0 = 0x0 // 禁止FIFO模式
(5)UBRDIV0和UDIVSLOT0和波特率有关,要根据公式去算的
1.7.7.4、在C源文件中定义访问寄存器的宏
定义好了访问寄存器的宏之后,将来写代码时直接使用即可。
1.7.8.S5PV210串行通信编程实战2
1.7.8.1、串口Tx、Rx对应的GPIO的初始化
给GPA0CON的相应bit位赋值为相应值,用C语言位操作来完成。
1.7.8.2、UCON、ULCON、UMCON、UFCON等主要控制寄存器
依据上节中分析的值进行依次设置即可。
1.7.8.3、波特率的计算和设置
(1)第一步,用PCLK_PSYS和目标波特率去计算DIV_VAL: DIV_VAL = (PCLK / (bps x 16)) ?1
(2)第二步,UBRDIV0寄存器中写入DIV_VAL的整数部分
(3)第三步,用小数部分*16得到1个个数,查表得uBDIVSLOT0寄存器的设置值
PS:计算公式: 波特率设置 DIV_VAL = (PCLK / (bps x 16))-1
// PCLK_PSYS用66.7MHz算 余数0.18
// DIV_VAL = (66700000/(9600*16)-1) = 432.244
rUBRDIV0 = 432;
// (rUDIVSLOT中的1的个数)/16=上一步计算的余数=0.18
// (rUDIVSLOT中的1的个数 = 16*0.244= 3.9 = 4
rUDIVSLOT0 = 0x2222;// 3个1,查官方推荐表得到这个数字
1.7.8.4、串口发送和接收函数的编写
(1)写发送函数,主要发送前要用while循环等待发送缓冲区为空才能发送。
注意:注意程序中改了波特率后,SecureCRT也要相应修改,不然收不到东西。