[原创] NXP ARM自动波特率的实现

zhaojun_xf   2012-8-6 07:21 楼主
       随着应用的需要,自动波特率已经不是什葱缕娴母拍盍恕T谝郧耙迪肿远ㄌ芈剩话愣蓟嵊酶龆ㄊ逼骼醇扑闶莩ざ龋佣袢〔ㄌ芈省T贜XP芯片的串口中直接添加了一个定时器,自动实现波特率的计算,只需要正确设置好寄存器就可以了,非常简单实用,下面我们就讲讲实现的方式以及注意事项。
       下面我们以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模式

    
提示词:如果您需要查看本帖隐藏内容,请登录或者注册
我的博客

回复评论 (4)

通过上面的介绍可以看出,自动波特率下,并没有使用小数波特率,那么在12MHz外部晶振下,将产生很大的误差,甚至有可能,自动设别的波特率根本不能应用。那么应该怎样解决这个问题呢?

      在前面的帖子《NXP ARM微处理器实现波特率的计算方法》中我们介绍了小数波特率的应用,那么我们能否把自动波特与小数波特率发生器结合以来呢?

当然答案是肯定的。下面我们就分别讲解这两种方法的结合使用。。。。。。。。。。。。。。。
  1. /********************************************************************************************************
  2. * FunctionName : UART_AutoBaud()
  3. * Description : 自动波特率
  4. * EntryParameter : num - 串口(0~3), mode - 模式(0-模式0, 1-模式1, 2-关闭自动波特)
  5. * ReturnValue : 返回自动识别的波特率
  6. ********************************************************************************************************/
  7. u32 UART_AutoBaud(u8 num, u8 mode)
  8. {
  9. 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. if (mode >= 2)
  14. {
  15. LPC_UART[num]->ACR = (0x00 << ACR_START); // 关闭自动波特率
  16. return 0;
  17. }
  18. else
  19. {
  20. LPC_UART[num]->ACR = (0x01 << ACR_START) | (mode << ACR_MODE); // 启动自动波特率
  21. while (LPC_UART[num]->ACR & (0x01 << ACR_START) != 0)
  22. {
  23. ; // 等等自动波特率完成
  24. }

  25. UART_Dlab(num, ENABLE);
  26. dlm = LPC_UART[num]->DLM; // 读波特率高8位
  27. dll = LPC_UART[num]->DLL; // 读波特率低8位
  28. tmpBaud = uartClock / (16 * (256*dlm + dll)); // 计算波特率
  29. UART_Dlab(num, DISABLE);

  30. k = 0;
  31. min = baud[10];
  32. for (i=0; i
  33. {
  34. tAbs = abs(baud[i]-tmpBaud); // 选择误差最小的设置
  35. if (min > tAbs)
  36. {
  37. k = i;
  38. min = tAbs;
  39. }
  40. }

  41. return (baud[k]); // 返回设置
  42. }
  43. }
上面是自动波特率识别的函数,由于再12MHz晶振情况下,识别的波特存在误差,所以我们会先把识别出来的波特率与我们常用的波特率进行比较,接近那个值,我们就认为实际使用的是那一个波特率。但是需要注意,如果用11.0592MHz或其倍数是晶振,识别出来的波特率应该是没有误差的,但是这个函数还是通用的。

[ 本帖最后由 zhaojun_xf 于 2012-8-6 07:55 编辑 ]
我的博客
点赞  2012-8-6 07:46
通过上面的自动波特率函数获取波特率,实际上串口已经设置成这个波特率了,但是如果用有误差的晶振,而且如果误差已经超出我们的允许范围,那么就算设置了也不能正确通讯的。所以这个时候我们在结合我们前面计算的小数波特率发生器,设置波特率,产生小数分频,使其通讯误差在我们的允许范围这内就可以充分解决了这个问题了。
  1. if (bps > 0)
  2. {
  3. tmpBps = bps; // 手动设置波特率
  4. }
  5. else
  6. {
  7. tmpBps = UART_AutoBaud(num, 1); // 自动波特率
  8. }

  9. if (UART_BaudSet(num, tmpBps) == TRUE) // 设置波特率
  10. {
  11. LPC_UART[num]->FCR = tri|LCR_FIFO_EN|LCR_RX_RST|LCR_TX_RST; // Enable and reset TX and RX FIFO.
  12. LPC_UART[num]->IER = mode; // 设置串口工作模式
  13. if (mode != UART_INQUIRY)
  14. {
  15. switch (num) // 使能中断
  16. {
  17. case UART0: NVIC_EnableIRQ(UART0_IRQn); break;
  18. case UART1: NVIC_EnableIRQ(UART1_IRQn); break;
  19. case UART2: NVIC_EnableIRQ(UART2_IRQn); break;
  20. case UART3: NVIC_EnableIRQ(UART3_IRQn); break;
  21. default: break;
  22. }
  23. }
  24. }
通过上面的函数,再进行一次波特率设置,那么就可以解决任何情况下的波特率误差问题,从而实现代码的通用性了。这里表明了我们这里把自动波特率设置应用成自动波特率识别了
我的博客
点赞  2012-8-6 07:53
有了以上的方法,你不防试试,效果非常不错啊
我的博客
点赞  2012-8-6 07:54
不太懂
点赞  2013-1-15 21:43
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复