串口裸机程序设计

来源:互联网 发布:淘宝发货地址在哪里填 编辑:程序博客网 时间:2024/06/06 20:39

我们要写串口逻辑程序,那么我们要先连接串口的基本功能

串口无外乎就是两个基本功能,一个是发,一个是收。当然我们在串口的收和发之前,我们首先的进行串口的初始化,让他处于一个正确的工作状态

我们站在学生的角度上去考虑串口逻辑程序怎么写

假如说我也不知道串口的初始化怎么做,串口的发送怎么做,串口的接收怎么做

我们可以去模仿别人怎么做

我们随便找一份代码可以发现,串口的初始化做了如下几个工作

1.配置了引脚用于RX/TX:因为我们的RX与TX经常和我们的GPIO共用的

2.1设置数据的格式:有没有校验位,停止位是多少位,数据是多少位

2.2设置工作模式

3.设置波特率


首先我们配置引脚的时候,我们在底板原理图上找到我们的这个模块

我们可以在这张图上看到串口0的发送引脚叫做TXD0

然后打开我核心板的原理图


很容易可以看到,我们TXD0这个脚和我们的GPA0_1是共用的,因此我们要设置这个脚为TXD0的这么一个功能

同样我们的TXD0也是一样的


就是设置这两位



设置数据格式就是设置如下寄存器


第二位是设置停止位的位数,从第三位到第五位是设置我们的校验位的方式的。所以我们这个寄存器就是用来设置数据格式的


设置工作模式

这里所说的工作模式是指串口收发的工作模式

我们串口可以工作在DMA,中断,轮询等工作模式。
如果我们在操作系统的情况一下,一般下DMA和中断模式下
先设置为轮询模式吧


这个寄存器的第0位第一位第二位第三位就是控制模式的寄存器

如果采用的是DMA的方式就设置为10

如果你使用中断或者轮询就设置为01


这个寄存器还有一个地方还要设置,那就是我们的时钟源



波特率设置


根据上面的公式我们计算如下

DIV_VAL = (PCLK / (bps x 16)) −1
         66.7*10^6 / (115200*16) -1 
         66700000/115200/16 -1
         36.2 - 1
         35.2

所以我们的UBRDIV0寄存器填入35


x/16=0.2
x = 3


我们的UDIVSLOT0寄存器填入3对应的值 0x0888

初始化大概就是这样


接下来的函数是我们发送一个字符的函数,有人会问:串口发送的时候是以一个字符包的形式完成的么。还有停止位,还有校验位这些东西,但是这些东西是我们硬件帮我们添加的。对于我们的驱动程序而言,我们只需要把我们的数据位交给我们的串口,交给我们的硬件。我们的硬件会把停止位,校验位等加上去

我们也不知道这部分代码怎么写,同样的,我们参考别人的代码。你会发现,它会去检测一个寄存器


我们发送就要检测第二位 就是Transmit buffer empty这一位,看是不是等于0。这里等于0表示我们的串口的那个寄存器不是等于空的,什么意思呢?我们串口是一位一位的发送的,我们需要等到前一次数据发送完才能发送下一次的数据。所以我们这个寄存器就是判断前一次的数据发送完没有



我们把要传输的数据写到这个寄存器就行了。


接收的功能也非常简单


同样是这个寄存器,这个寄存器的第0位就是我们的判断有没有收到数据


然后会把收到的数据放到这个寄存器里面来


这里还要提两个东西

1.串口的FIFO

FIFO是先进先出缓冲区的意思,即串口接收到的数据可以先进入FIFO,不必马上进入中断服务程序接收,这样可节省CPU时间。对于发送数据也一样,可以把要发送的数据一起写入FIFO,串口控制器可按写入顺序依次发送出去。

fifo只是一个缓冲器而已如果你的cpu没什么别的工作或完全处理的过来uart数据的话,可以用nonfifo模式如果你的cpu有一些耗时的工作要处理,也许uart数据来了很多才开始处理,这样就需要fifo做缓冲了。

串口设置的触发等级,就是预先设定的一个值。每当传输了这个值的数据量就触发一次中断。比如设置了8字节,那么每传8字节数据就会触发一次中断了。

看来许多人还没有真正理解FIFO的作用和优点,仍然停留在每收发一个字符就要中断处理一次的老思路上。UART收发FIFO主要是为了解决收发中断过于频繁而导致的CPU效率不高的问题。

FIFO的必要性。在进行UART通信时,中断方式比轮询方式要简便且效率高。但是,如果没有收发FIFO,则每传输一个数据(5~8位)都要中断处理一次,效率仍然不高。如果有了收发FIFO,则可以在连续收发若干个数据(可多至14个)后才产生一次中断,然后一起处理。这就大大提高了收发效率。

接收超时问题。如果没有接收超时功能,则在对方已经发送完毕而接收FIFO未填满时并不会触发中断(FIFO满才会触发中断),结果造成最后接收的有效数据得不到处理的问题。有了接收超时功能后,如果接收FIFO未填满而对方发送已经停,则在不超过3个数据的接收时间内就会触发超时中断,因此数据会照常得到处理。

总之,FIFO的设计是优秀而合理的,它已经帮你想到了收发过程中存在的任何问题,只要初始化配置UART后,就可以放心收发了,FIFO和中断例程会自动搞定一切!

完全不必要担心FIFO大大减少了中断产生的次数而“可能”造成数据丢失的问题!

 发送时,只要发送FIFO不满,数据只管往里连续放,放完后就直接退出发送子程序。随后,FIFO真正发送完成后会自动产生中断,通知主程序说:我已经完成真正的发送。

接收时,如果对方是连续不间断发送,则填满FIFO后会以中断的方式通知主程序说:现在有一批数据来了,请处理。

如果对方是间断性发送,也不要紧,当间隔时间过长时(2~3个字符传输时间),也会产生中断,这次是超时中断,通知主程序说:对方可能已经发送完毕,但FIFO未满,也请处理。


2.串口的流控

流控可以使数据接收设备在不能接收数据时通知数据发送设备,使其停止发送。串口的流控经常采用硬件流控和软件流控两种方式。


控制fifo的寄存器如下图



控制流控的寄存器如下图





裸机代码如下

#define GPHA0 (*(volatile unsigned long *)0xe0200000)
#define ULCON0 (*(volatile unsigned long *)0xe2900000)
#define UCON0 (*(volatile unsigned long *)0xe2900004)
#define UBRDIV0 (*(volatile unsigned long *)0xe2900028)
#define UDIVSLOT0 (*(volatile unsigned long *)0xe290002c)
#define UTRSTAT0 (*(volatile unsigned long *)0xe2900010)
#define UTXH0 (*(volatile unsigned long *)0xe2900020)
#define URXH0 (*(volatile unsigned long *)0xe2900024)
void uart_init()
{
//1. 配置引脚功能
GPHA0 &=~0xff;
GPHA0 |=0x22;
//2.1设置数据格式
//设置数据位为8-bit,停止位为一位,没有校验位
ULCON0 = 0x3;
//2.2设置工作模式
//这里所说的工作模式是指串口收发的工作模式
//我们串口可以工作在DMA,中断,轮询等工作模式。
//如果我们在操作系统的情况一下,一般下DMA和中断模式下
//先设置为轮询模式吧
//设置时钟源
UCON0 |=0x305;


UFCON  =0x00;   //不使用fifo
UMCON  =0x00;   //不使用流控


//3.配置波特率
UBRDIV0=35;
UDIVSLOT0=0x0888;
}


void uart_put(unsigned char val)
{
while((UTRSTAT0 & (1<<2)) == 0);   //有数据正在传输的时候等待
UTXH0 = val;


}
unsigned char  uart_get(void)
{
while((UTRSTAT0 & 1)==1);
return URXH0;
}





原创粉丝点击