[原创] NXP微处理器小数波特率设置

zhaojun_xf   2012-8-4 07:14 楼主

对于波特率的计算,想必大家都非常清楚,在51时代,我们常用11.0592MHz晶振或其整数倍的晶振来实现精确的波特率。但是随着ARM的出现,以及ARM外设的丰富、倍频的应用,想获取精确的波特率好像不容易实现了,特别是在需要使用USB的情况下,我们必须选择能够参数480MHz频率的晶振,那么12MHz晶振就成为我们不二的选择,波特率计算公式:


BPS = PCLK / (16×(256xUnDLM+UnDLL))

      通过以上的计算公式,我们不难发现,要想获取精确的波特率是不可能的,虽然在速度不高的情况下,我们可以取近似值也可以进行正常的串口通信,但是如果要在波特率特别高的情况下,我们还用这种方法是不能正常通信的。那么怎么来解决这个问题呢?

       其实厂商在设计芯片的时候已经为我们想到了,在选择波特率时候,当实际波特率与目标波特率之间存在的误差在1.1%范围内是可以正常通信的。所以,我们只要能够用一个寄存器来实现波特率的误差调节,使其误差在允许的范围以内就可以了。为实现这一目标,NXP设计了一个叫做小数分频的寄存器FDR。这里也LPC1700为例来说明,其寄存器描述如小表:

1.jpg


[ 本帖最后由 zhaojun_xf 于 2012-8-6 13:15 编辑 ]
我的博客

回复评论 (13)

2推荐 使者0123 

NXP的小数分频器的作用是不是为了得到更为精确的波特率(相比较未使用小数分频器的情况),是这样的吗?
点赞  2016-5-19 14:25

2推荐 zhaojun_xf 

我的博客
点赞  2012-8-6 06:03

2推荐 zhaojun_xf 

仿真验证一下代码:


1.png




仿真可以看到,设置9600时实际值为9644。虽然有误差0.469%,但是在有效范围。下面我们用软件计算一下:

2.png


通过软件计算出来一共有多种设置,而且这一组也不是误差最小的,这主要跟算法有关,我们这中计算出一组可使用的设置,而不是最佳设置。。。


[ 本帖最后由 zhaojun_xf 于 2012-8-4 19:54 编辑 ]
我的博客
点赞  2012-8-4 08:16
UART的波特率计算公式:
2.png
通过上面的公式我们就可以计算出波特率了,但是我们发现,上面这个等式中一共有4个未知,所以根本无法实现波特率的设置,我们必须得使用一些方法。

说明:

其中PCLK为外设时钟,U1DLM和U1DLL为标准UART1波特率分频器寄存器,而DIVADDVAL和MULVAL为UART1小数波特率发生器的制定参数。
ULVAL和DIVADDVAL的值应符合以下条件:
a) 0 < MULVAL ≤ 15;
b) 0 ≤ DIVADDVAL < 15;
c) DIVADDVAL

       根据上面的说明,我们可以看出,要想设置串口,那么只能实现逐一验证了,以就是说,只能通过设定DIVADDVAL和MULVAL的值来找出满足我们需要的值了。这种方法虽然能够实现计算出我们需要的波特率,但是非常复杂,计算量也特别大,所以NXP已经为我们考虑好计算的算法已经取值表格了。

波特率计算:
UART可以与小数分频器一起工作,也可以不使用小数分频器。在实际应用中,使用几种不同的小数分频器设置很可能会获得目标波特率。下面的算法给出了一个得到DLM、DLL、MULVAL以及DIVADDVAL参数集的方法。该参数集允许实际波特率与目标波特率之间存在小于1.1%的相对误差。
我的博客
点赞  2012-8-4 07:38
波特率计算流程:


3.png

4.png


[ 本帖最后由 zhaojun_xf 于 2012-8-4 07:45 编辑 ]
我的博客
点赞  2012-8-4 07:43
通过上面的算法和表格我们不难找出一个比较有效是设置,下面几说几个例子:

(1)范例1:PCLK = 14.7456 MHz,BR = 9600
根据所提供的算法,DLest=PCLK/(16×BR) = 14.7456MHz/(16×9600) = 96。因为这里的DLest是一个整型数,所以DIVADDVAL = 0,MULVAL = 1,DLM = 0且DLL = 96。

(2)范例2:PCLK = 12 MHz,BR = 115200
根据所提供的算法DLest=PCLK/(16×BR) = 12MHz/(16×115200)  = 6.51。该算式中的DLest并不是整型数,因此下一步就要对FR参数进行估算。使用FRest = 1.5进行首次估算,得到新的DLest = 4,然后计算出FRest = 1.628。由于FRest = 1.628是在1.1到1.9的指定范围之内,因此DIVADDVAL和MULVAL的值可通过附带的查找表获得。最接近FRest = 1.628的值为FR = 1.625。也就是说DIVADDVAL = 5而MULVAL = 8。
       基于这些查找结果,建议UART设置为DLM = 0,DLL = 4,DIVADDVAL = 5和MULVAL = 8。根据公式12-2,UART的波特率为115384。该速率与原来指定的115200之间存在0.16%的相对误差。

       上面这两个例子是NXP资料上讲解的,如果大家能够看明白,下面我们要实现起来就简单了。我们把上面的计算算法用一个函数来实现,那么以后我们只需用调用这个函数就可以了,不用在去理会这么复杂的算法了。
我的博客
点赞  2012-8-4 07:52
实现波特率设置函数:

要实现这个函数,需用注意几点:

1. 先是从1.1到1.9中取出一个FRest值来计算出DLest,然后在计算出FRest,看其是否在1.1都1.9之间,如果在表示计算出的FRest是有效的。

2. 取FRest是从1.5开始,这样做可以减少FRest的取值,如果取大了,我们减少;如果取小了,我们增加。从而减少了取值的个数,加快了计算速度。

3. 计算出来的结果并不一定是误差最小的,因为我们是从1.5开始,而不是去1.1~1.9中所有值进行计算,找出误差最小的值。

4. 设置值可能有很多种,我们这里只计算出了一种可以接受的值。
  1. typedef struct _UART_DCM_TBL
  2. {
  3. fp32 FR; // 小数值
  4. u8 Div; // 分频
  5. u8 Mul; // 乘数

  6. } UART_DCM_TBL;
  1. /********************************************************************************************************
  2. * FunctionName : UART_BaudSet()
  3. * Description : 波特率设置
  4. * EntryParameter : bps - 波特率
  5. * ReturnValue : 成功返回TRUE,否则FALSE
  6. ********************************************************************************************************/
  7. u8 UART_BaudSet(u8 num, u32 bps)
  8. {
  9. u32 fDiv; //
  10. u32 uartClock = SystemCoreClock / 4; // 外设时钟与内核时钟的比例
  11. fp32 fFRest = 1.5, tFRest = 1.5, tAbs, min;
  12. u8 i, k;
  13. u32 uDLest;
  14. u8 tmpStr[64];

  15. UART_DCM_TBL const tbl[] =
  16. {
  17. {1.000, 0, 1}, {1.067, 1, 15}, {1.071, 1, 14}, {1.077, 1, 13},
  18. {1.083, 1, 12}, {1.091, 1, 11}, {1.100, 1, 10}, {1.111, 1, 9},
  19. {1.125, 1, 8}, {1.133, 2, 15}, {1.143, 1, 7}, {1.154, 2, 13},
  20. {1.167, 1, 6}, {1.182, 2, 11}, {1.200, 1, 5}, {1.214, 3, 14},
  21. {1.222, 2, 9}, {1.231, 3, 13}, {1.250, 1, 4}, {1.267, 4, 15},
  22. {1.273, 3, 11}, {1.286, 2, 7}, {1.300, 3, 10}, {1.308, 4, 13},
  23. {1.333, 1, 3}, {1.357, 5, 14}, {1.364, 4, 11}, {1.375, 3, 8},
  24. {1.385, 5, 13}, {1.400, 2, 5}, {1.417, 5, 12}, {1.429, 3, 7},
  25. {1.444, 4, 9}, {1.455, 5, 11}, {1.462, 6, 13}, {1.467, 7, 15},
  26. {1.500, 1, 2}, {1.533, 8, 15}, {1.538, 7, 13}, {1.545, 6, 11},
  27. {1.556, 5, 9}, {1.571, 4, 7}, {1.583, 7, 12}, {1.600, 3, 5},
  28. {1.615, 8, 13}, {1.625, 5, 8}, {1.636, 7, 11}, {1.643, 9, 14},
  29. {1.667, 2, 3}, {1.692, 9, 13}, {1.700, 7, 10}, {1.714, 5, 7},
  30. {1.727, 8, 11}, {1.733, 11, 15}, {1.750, 3, 4}, {1.769, 10, 13},
  31. {1.778, 7, 9}, {1.786, 11, 14}, {1.800, 4, 5}, {1.818, 9, 11},
  32. {1.833, 5, 6}, {1.846, 11, 13}, {1.857, 6, 7}, {1.867, 13, 15},
  33. {1.875, 7, 8}, {1.889, 8, 9}, {1.900, 9, 10}, {1.909, 10, 11},
  34. {1.917, 11, 12}, {1.923, 12, 13}, {1.929, 13, 14}, {1.933, 14, 15},
  35. };

  36. if (uartClock % (16*bps) == 0) // PCLK / (16*bps)为整数
  37. {
  38. fDiv = uartClock / (16*bps); // baud rate
  39. LPC_UART[num]->DLM = fDiv / 256;
  40. LPC_UART[num]->DLL = fDiv % 256;
  41. LPC_UART[num]->FDR = 0x10;
  42. } // 关闭小数分频
  43. else
  44. {
  45. do
  46. {
  47. uDLest = (u32)(uartClock / (16*bps*fFRest));
  48. fFRest = (fp32)uartClock / (fp32)(16*bps*uDLest);
  49. if ((1.100
  50. {
  51. k = 0;
  52. min = tbl[0].FR;
  53. for (i=0; i
  54. {
  55. tAbs = fabs(tbl[i].FR-fFRest);
  56. if (min > tAbs)
  57. {
  58. k = i;
  59. min = tAbs;
  60. }
  61. }

  62. UART_Dlab(num, ENABLE);
  63. LPC_UART[num]->FDR = (tbl[k].Mul << 4) + tbl[k].Div; // 得出小数分频值
  64. LPC_UART[num]->DLM = uDLest / 256;
  65. LPC_UART[num]->DLL = uDLest % 256;
  66. UART_Dlab(num, DISABLE);

  67. sprintf((char *)(tmpStr), "Hello! Baud is %4d bps\n", bps);
  68. UARTSendStr(num, tmpStr);
  69. return TRUE;
  70. }
  71. else // 从1.1到1.9中选择其他tFRest的值
  72. {
  73. if (fFRest <= 1.1)
  74. {
  75. tFRest += 0.1;
  76. fFRest = tFRest;
  77. }
  78. else
  79. {
  80. tFRest -= 0.1;
  81. fFRest = tFRest;
  82. }
  83. }

  84. } while ((1.1<=fFRest) && (fFRest<=1.9));
  85. }

  86. return FALSE;
  87. }
上面的函数并不难,如果看不懂,请对照上面的算法看,应该很容易明白。。。。。。。。。。。

[ 本帖最后由 zhaojun_xf 于 2012-8-6 07:13 编辑 ]
我的博客
点赞  2012-8-4 08:02
其实这个算法已经有网友用上位机软件实现了,在这里先感谢这个网友。这个软件已经把所有可能的选择值都列出来了,非常全面。。。

无标题.png

LPC1700波特率计算工具.rar (5.32 MB)
(下载次数: 378, 2012-8-4 08:15 上传)
LPC1700波特率计算工具.rar (5.32 MB)
(下载次数: 378, 2012-8-4 08:15 上传)


我的博客
点赞  2012-8-4 08:15
刚好用上,谢谢版主!
点赞  2013-8-30 14:35
版主,你好,我看了你写的书,我在写串口通讯时,采用了波特率设置的代码,为什么仿真到“UART_DCM_TBL const tbl[] = ”这行代码时(就是小数分频器设置查找表位置),
就跳到这里了“HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler         [WEAK]
                B       .
                ENDP”
这是为什么啊?
点赞  2014-7-11 17:05
你好!程序里面有一个for语句和一个if语句显示的不完整,希望您能完善一下!谢谢!
点赞  2015-8-13 16:10
后续的波尔率的设置没有了?
点赞  2018-1-24 20:42
学习了
点赞  2018-6-24 23:05
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复