打印
[8/16-bit MCU]

NXP ARM自动波特率的实现

[复制链接]
1099|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Roderman_z|  楼主 | 2016-1-17 20:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
NXP ARM自动波特率的实现:随着应用的需要,自动波特率已经不是什么新奇的概念了。在以前要实现自动波特率,一般都会用个定时器来计算数据长度,从而获取波特率。在NXP芯片的串口中直接添加了一个定时器,自动实现波特率的计算,只需要正确设置好寄存器就可以了,非常简单实用,下面我们就讲讲实现的方式以及注意事项。

下面我们以LPC1700系列芯片为例进行详细介绍说明:
  lpc1700的四个UART都有UARTn Auto-baud控制寄存器寄存器,这个寄存器用于对自动波特率的设置,用户可以自由地读写。具体描述如下:



1.自动波特率(Auto-baud)
UARTn auto-baud功能可用于测量基于“AT”协议(Hayes命令)的输入波特率。如果auto-baud功能被使能,那么auto-baud功能部件将测量接收数据流中的1位所消耗的时间,并根据这个结果来设置除数锁存寄存器UnDLM和UnDLL。
       Auto-baud功能是通过置位UnACR起始位来启动的,并通过清零UnACR起始位来停止。Auto-baud一旦结束,起始位就将自动清零,并且对该起始位进行读取将会返回auto-baud的状态(挂起/完成)。
       可通过设置UnACR模式位来使用两种auto-baud测量模式。在模式0下,波特率是通过对UARTn RX管脚上两个连续的下降沿进行测量(起始位的下降沿和第一位的下降沿)来得到的。而在模式1下,波特率则是通过测量UARTn RX管脚上的下降沿和后续的上升沿之间的时间(起始位的长度)来得到的。
如果出现超时(速率测量计数器溢出),UnACR AutoRestart位可用于自动重启波特率测量。如果该位被置位,速率测量将会在UARTn RX管脚的下一个下降沿重新启动。
Auto-baud功能会产生两种中断:
     UnIIR ABTOInt中断(UnIER ABToIntEn置位且自动波特率测量寄存器溢出);
     UnIIR ABEOInt中断(UnIER ABEOIntEn置位且auto-baud已经成功完成)。
     Auto-baud中断必须通过置位相应的UnACR ABTOIntClr位和ABEOIntEn位来清零。在auto-baud期间,小数波特率发生器通常被禁用(即DIVADDVAL = 0)。但是,如果波特率发生器被启动(即DIVADDVAL > 0),那么它将影响UARTn Rx管脚波特率的测量,但UnFDR寄存器的值在速率测量后不会被修改。此外,当使用auto-baud时,任何对UnDLM和UnDLL寄存器的写操作都必须在写UnACR寄存器之前完成。UARTn支持的最小和最大波特率受PCLK、数据的位数、停止位以及校验位的影响。

通过公式我们不难算出,外部晶振12MHz,CUP内核频率100MHz,外设频率为25MHz时,最小波特率为95,最大为142045。完全满足我们的所有需要。。。

2.Auto-baud模式
当软件执行“AT”命令时,它采用期望的字符格式对UARTn进行配置,并置位UnACR起始位。用户不必关心除数锁存器UnDLM和UnDLM内的初始值。由于字母“A”或“a”的ASCII编码(“A”= 0x41,“a”= 0x61)的关系,UART1 Rx管脚所发送的起始位以及期望字符的LSB是由两个下降沿来限定的。当UnACR起始位被置位时,auto-baud协议将执行以下阶段:
     a) UnACR起始位一置位,波特率测量计数器立即复位,同时UARTn UnRSR复位。UnRSR波特率切换为最高速率。
     b) UARTn Rx管脚上的下降沿触发起始位的开始。波特率测量计数器将开始对PCLK(可选择被小数波特率发生器预分频)进行计数。
     c) 在接收起始位的过程中,RSR波特率输入端会产生16个脉冲,脉冲频率和(小数波特率发生器预分频)UARTn输入时钟相同,这样,保证了起始位存放在UnRSR中。
    d) 在接收起始位的过程中(以及模式0下的字符LSB),速率计数器将随着被预分频的UART1输入时钟(PCLK)递增。
    e) 如果是模式0,那么速率计数器将会在UARTn RX管脚的下一个下降沿停止。如果是模式1,那么速率计数器将会在UARTn RX管脚的下一个上升沿停止。
    f) 速率计数器的值被载入到UnDLM/UnDLL中,并且波特率将会切换到正常操作模式。在设置完UnDLM/UnDLL后,如果auto-baud结束中断被使能,UnIIR ABEOInt将会被置位。接着UnRSR继续接受“A/a”字符剩下的其它位。

相关帖子

沙发
Roderman_z|  楼主 | 2016-1-17 20:49 | 只看该作者
通过上面的介绍可以看出,自动波特率下,并没有使用小数波特率,那么在12MHz外部晶振下,将产生很大的误差,甚至有可能,自动设别的波特率根本不能应用。那么应该怎样解决这个问题呢?
      在前面的帖子《NXP ARM微处理器实现波特率的计算方法》中我们介绍了小数波特率的应用,那么我们能否把自动波特与小数波特率发生器结合以来呢?
当然答案是肯定的。下面我们就分别讲解这两种方法的结合使用
01./********************************************************************************************************
02.* FunctionName : UART_AutoBaud()
03.* Description : 自动波特率
04.* EntryParameter : num - 串口(0~3), mode - 模式(0-模式0, 1-模式1, 2-关闭自动波特)
05.* ReturnValue : 返回自动识别的波特率
06.********************************************************************************************************/
07.u32 UART_AutoBaud(u8 num, u8 mode)
08.{
09.u8 i, k, dlm, dll;
10.u32 tmpBaud, tAbs, min;
11.u32 uartClock = SystemCoreClock / 4; // 外设时钟与内核时钟的比例
12.u32 baud[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 43000, 57600, 115200};
13.
14.if (mode >= 2)
15.{
16.LPC_UART[num]->ACR = (0x00 << ACR_START); // 关闭自动波特率
17.return 0;
18.}
19.else
20.{
21.LPC_UART[num]->ACR = (0x01 << ACR_START) | (mode << ACR_MODE); // 启动自动波特率
22.while (LPC_UART[num]->ACR & (0x01 << ACR_START) != 0)
23.{
24.; // 等等自动波特率完成
25.}
26.
27.UART_Dlab(num, ENABLE);
28.dlm = LPC_UART[num]->DLM; // 读波特率高8位
29.dll = LPC_UART[num]->DLL; // 读波特率低8位
30.tmpBaud = uartClock / (16 * (256*dlm + dll)); // 计算波特率
31.UART_Dlab(num, DISABLE);
32.
33.k = 0;
34.min = baud[10];
35.for (i=0; i
36.{
37.tAbs = abs(baud-tmpBaud); // 选择误差最小的设置
38.if (min > tAbs)
39.{
40.k = i;
41.min = tAbs;
42.}
43.}
44.
45.return (baud[k]); // 返回设置
46.}
47.}

使用特权

评论回复
板凳
Roderman_z|  楼主 | 2016-1-17 20:50 | 只看该作者
上面是自动波特率识别的函数,由于再12MHz晶振情况下,识别的波特存在误差,所以我们会先把识别出来的波特率与我们常用的波特率进行比较,接近那个值,我们就认为实际使用的是那一个波特率。但是需要注意,如果用11.0592MHz或其倍数是晶振,识别出来的波特率应该是没有误差的,但是这个函数还是通用的。
通过上面的自动波特率函数获取波特率,实际上串口已经设置成这个波特率了,但是如果用有误差的晶振,而且如果误差已经超出我们的允许范围,那么就算设置了也不能正确通讯的。所以这个时候我们在结合我们前面计算的小数波特率发生器,设置波特率,产生小数分频,使其通讯误差在我们的允许范围这内就可以充分解决了这个问题了。
1.if (bps > 0)
02.{
03.tmpBps = bps; // 手动设置波特率
04.}
05.else
06.{
07.tmpBps = UART_AutoBaud(num, 1); // 自动波特率
01.}
09.
10.if (UART_BaudSet(num, tmpBps) == TRUE) // 设置波特率
01.{
12.LPC_UART[num]->FCR = tri|LCR_FIFO_EN|LCR_RX_RST|LCR_TX_RST; // Enable and reset TX and RX FIFO.
13.LPC_UART[num]->IER = mode; // 设置串口工作模式
14.if (mode != UART_INQUIRY)
15.{
16.switch (num) // 使能中断
17.{
18.case UART0: NVIC_EnableIRQ(UART0_IRQn); break;
19.case UART1: NVIC_EnableIRQ(UART1_IRQn); break;
20.case UART2: NVIC_EnableIRQ(UART2_IRQn); break;
21.case UART3: NVIC_EnableIRQ(UART3_IRQn); break;
22.default: break;
23.}
24.}
25.}

通过上面的函数,再进行一次波特率设置,那么就可以解决任何情况下的波特率误差问题,从而实现代码的通用性了。这里表明了我们这里把自动波特率设置应用成自动波特率识别了。

使用特权

评论回复
地板
500days| | 2016-1-18 20:30 | 只看该作者
实现自动波特率的话最高是不是也只是115200啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

41

主题

354

帖子

2

粉丝