LPC2148串口高波特率通信解决方案文档格式.docx
- 文档编号:22357006
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:13
- 大小:201.50KB
LPC2148串口高波特率通信解决方案文档格式.docx
《LPC2148串口高波特率通信解决方案文档格式.docx》由会员分享,可在线阅读,更多相关《LPC2148串口高波特率通信解决方案文档格式.docx(13页珍藏版)》请在冰豆网上搜索。
{
Uart0SetFDR(bps);
}
Uart0SetDLML(bps);
可保证程序在高波特率时会设置小数波特率发生器,且低速率时也能正常工作。
下面的等式用于计算UART1波特率:
UART1baudrate=PCLK/(16*(256*U1DLM+U1DLL))*(MulVal/MulVal+DivAddVal)
其中PCLK为VPB总线时钟,U1DLM和U1DLL为标准的UART1波特率除数寄存器,
DivAddVal和MulVal为UART1小数波特率发生器特定的参数。
DivAddVal和MulVal的值应遵循以下的条件:
1.1<
=MulVal<
=15
2.0<
=DivAddVal<
3.如果U1FDR寄存器值不遵循这两个要求,那么小数分频输出未定义。
如果DivAddVal为0,那么小数分频禁止且时钟将不会分频。
第二节使用小数波特率发生器——校准系数的确定
根据以上公式很容易计算串口波特率,但是实际应用中,更多的是在使用非标准晶振的时候确定波特率校准系数,即设定U1FDR寄存器DivAddVal和MulVal的值。
确定波特率校准系数可以分如下3步进行:
(1)确定除数锁存器的值:
根据需要的波特率bps,按照没有校准系数的波特率计算公式确定除数锁存器的值(DLM,DLL)。
由于采用非标准晶振,得到的结果通常为小数。
无论小数值大小,均舍弃小数部分的值,对结果进行取整操作(不是四舍五入),得到除数锁存器的值。
(2)确定校准前的波特率:
将
(1)得到的除数值(DLM,DLL)代入不带校准系数的串口波特率计算公式,得到不经过校准的波特率BPS
(3)确定校准系数p:
p=bps/BPS=MulVal /(MulVal + DivAddVal)
根据限制条件1<
=15和0<
=15,寻找合适的值,使得到误差尽可能小的校准系数。
第三节具体实例
作者采用的实验CPU为LPC2148,晶振为12MHz,拟设定波特率bps为115200,使用UART0,根据前面所述的校准系数的确定过程,第一步得到除数锁存器的值:
12000000/(16*115200)=6.51,取整后得到除数为6.
将6代入没有校准系数的波特率计算公式,得到没有校准的波特率
BPS=12000000/(16*(256*0+6))=12500.
那么校准系数p=bps/BPS=115200/125000=0.9216,
即MulVal/(MulVal+DivAddVal)=0.9216
现在问题转化成为如何在限制的范围内找到两个整数,使得上式最贴近0.9216
第四节传统获取MulVal和DivAddVal整数值的方法
传统获取MulVal和DivAddVal整数值的方法大多依靠经验技巧或者反复试验的手段。
如参考文献二《深入浅出ARM7–LPC214x下》中,第77页描述的那样:
根据1<
=15的限制,由于系数接近1,因而DivAddVal取尽可能小的整数,多次试验取值得到12/(1+12)=0.9231与期望的系数0.9216最接近,能够使波特率误差最小,因而最后确定MulVal=12,DivAddVal=1.
显然,按照这种方法是无法完成程序自动化的,必须在每次编程之前根据波特率来人工推算出MulVal和DivAddVal的值,并且还需要大量的误差分析和反复试验,导致工作效率的降低。
下表是MulVal和DivAddVal取值的一些具体例子,可以看出,它们的取值确实没有什么简单规律,都是靠工程师的经验和反复试验结果得到的。
而在本文中,作者将引入数学方法,实现程序计算得出MulVal和DivAddVal整数值,而彻底抛弃传统的人工计算方法,不仅节省人力,而且更加科学可靠。
第三章数学引入——多位小数的分数逼近算法
我们的问题在于寻找一个分数,它能够尽可能的接近校准系数。
那么我们可以使用这样一种多位小数的分数逼近法,该算法认为:
任何一个多位小数,无论是无理数还是有理数,均可以用一个分数来近似表示它,并可用一定的程序使其误差越来越小,直至达到所需的精确度。
第一节算法描述:
多位小数的分数逼近法的程序描述如下:
程序1 确定两个起始项。
起始项是分数逼近的出发项,它们是两个简单的分数。
两个起始项比被逼近的小数p必须一个较大,称A项;
另一个较小,称B项。
起始项的分子和分母均为极简单的整数,如1,2,3等,应越小越好,可按以下方法选取。
当被逼近的小数p<
1时,A项和B项的分子均选为1。
A项的分母从1,2,3等中选取,使A项略大于p;
B项的分母从2,3,4中选择,使B项略小于p,显然B项的分母比A项的分母大1。
当被逼近的小数p>
1,A、B两项的分母均选为1时,A项的分子选用比p较大的整数,B项的分子选用比p较小的整数,显然B项的分子比A项的分子小1。
程序2 逼近法———分式运算
为了使误差逐步减小,可将有正误差的A项和有负误差的B项这两个分数,
分别将其分母相加作为新的分母,分子相加作为新的分子,于是得到一个新的分数。
如果得到的分数比p大,即有正误差,则作为新的A项;
如果得到的分数比p小,即有负误差,则作为新的B项。
程序3 循环或加权循环
把新的A项与上一次的B项,或新的B项与上一次的A项,重复执行程序2,称为循环。
有时A项与B项的误差相差较大,为了避免循环次数过多,可将误差小的分数的分子和分母各乘以一定的整数,再重复执行程序2。
这个乘数称为权,这样的重复程序2,称为加权循环。
程序4 达到逼近目的
多次进行程序2和3,即多次进行循环或加权循环,可得到与给定小数中相逼近的分数,其误差可满足预定精确度的要求。
逼近法的几点说明:
1)无论是起始项,还是以后得到的各项,始终是A项具有正误差,B项具有负误差。
逼近法———分式运算的目的就是把正、负误差相补偿,使得到的新的分数具有较小的误差。
2)用分式运算得到的新分数的误差,若为正,它一定比原来的A项的误差小;
若为负,它的绝对值一定比原来的B项误差的绝对值小。
3)每次用新的分数进行逼近法的分式运算,就可得到逐次逼近,使误差越来越小。
4)要得到精确的分数近似,必须有精确的被逼近的小数,即该小数的有效数字位数应较多。
第二节算法分析与修改
上面是一个通用的分数逼近算法描述,而我们在实际应用中可以根据应用进行适当裁减和修改。
通过分析程序1,我们知道由于我们的p值一定小于1,故而初始化时A项和B项的分子均选为1。
另外原算法关于加权循环适合在大分母高精确度的情况下使用,例如循环计算圆周率,精确到像355/113甚至208341/66317这样的大分母时,而我们由于MulVal和DivAddVal值被限定在0到15之间,几次循环即可获得最优解,故而可以完全不用权实现。
第四章应用分数逼近算法对小数波特率发生器进行设置的程序实现
第一节校准系数P的计算
采用C语言的整数除法特点自动取整,而不需要像某些语言使用floor函数取整。
P=115200.0/Uart0GetBps(Uart0GetFdiv(115200));
由于P是浮点数,故而分子使用了115200.0这个浮点表达式,
这里Uart0GetFdiv(bps)和Uart0GetBps(Fdiv)是两个宏函数,其定义如下:
//用波特率得到除数因子,并且自动丢弃小数部分
#defineUart0GetFdiv(bps)((Fpclk/16)/bps)
//用除数因子得到波特率
#defineUart0GetBps(Fdiv)(Fpclk/(16*Fdiv))
本例中P=0.9216
第二节计算逼近P的分数最优解
假设用A1/A2来表示A,B1/B2来表示B,
按照我们刚才的分析,由于P<
1,那么初始化时A1=B1=1
另外,因为分母最大不超过16,所以用一个循环来找到最接近P的B值分母B2(B<
P),由于分母都是整数,所以得到最接近P的A值分母A2=B2–1。
voidUart0BaudFix(floatP)
{
intA1,A2,B1,B2;
A1=B1=1;
for(B2=1;
B2<
=16;
++B2)
if((float)B1/B2<
=P)
break;
A2=B2-1;
printf("
IntialStatus\nP=%fA=%d/%dB=%d/%d\n\n"
P,A1,A2,B1,B2);
Uart0BaudFixCal(P,A1,A2,B1,B2);
}
算法描述中的程序3是通过递归函数Uart0BaudFixCal来实现的,它接受当前的B、P、A值,并检验它们是否达到要求,若没有达到则产生新的分数(A1+ B1)/(A2+B2)继续迭代;
若达到了要求,则函数返回,该程序实现了两个返回条件。
一个是分母超出了限制的范围,代码中的常数16可以根据应用修改
if(A2>
16)
%d/%d为最优A2\n"
B1,B2);
return;
if(B2>
%d/%d为最优B2\n"
A1,A2);
}
另一个是A或者B与P的接近精度达到了指定的误差,代码中的常数0.0001可以根据应用修改
A=(float)A1/A2;
B=(float)B1/B2;
BP=P-B;
PA=A-P;
if(BP<
PA)
if(BP<
0.0001)
{
printf("
%d/%d为最优BP\n"
return;
}
else
if(PA<
%d/%d为最优PA\n"
迭代的部分代码如下:
if((float)(A1+B1)/(A2+B2)<
P)
Uart0BaudFixCal(P,A1,A2,A1+B1,A2+B2);
Uart0BaudFixCal(P,A1+B1,A2+B2,B1,B2);
如果新产生的值小于P,那么将它作为新的B值,反之则作为新的A值,该算法结构类似二分法。
至此,我们得到了最优解MulVal=B1,而DivAddVal=B2–B1
第三节设置小数分频寄存器
用得到的MulVal和DivAddVal设置U0FDR很简单,根据其寄存器的位描述,可以用如下代码来实现:
U0FDR=(MulVal<
<
4)|DivAddVal;
第四节其他
其他必须的代码,如串口UART0初始化、除数锁存器的设置以及发送字符和字符串的函数和通常情况下的代码大同小异,就不做详细介绍了。
只要记得在初始化的时候为了高低波特率增加一个逻辑判断结构就行。
//UART0串口初始化函数,接受波特率作为参数
voidUart0Init(uint32bps)
{
PINSEL0=0x00000005;
//设置I/O连接到UART0
if(bps>
//设置除数因子函数,接受波特率作为参数
voidUart0SetDLML(uint32bps)
uint32Fdiv;
Fdiv=Uart0GetFdiv(bps);
U0LCR=0x83;
//DLAB=1,可设置波特率
U0DLM=Fdiv/256;
U0DLL=Fdiv%256;
U0LCR=0x03;
…………………………(其他代码省略)
第五章总结
当由于某些原因使用12MHz晶振代替标准的11.0592MHz晶振时,串口通信波特率会有误差,本文对该误差进行了实验研究,得出一些有用的结论:
1、当期望波特率在57600以下时,实际波特率与其误差较小,可以正常通信;
而当期望波特率为115200时,实际波特率为125000,在这样大的误差下如果不修正实际波特率根本无法进行正确的通信;
2、通过设置LPC214xCPU的小数波特率发生器可以校准非标准频率晶振所引起的波特率误差,这可以让期望波特率高达115200时可以正常通信。
如图,此时的实际波特率为115384,误差较小,传送数据完全正常。
另外,本文首次在计算小数分频寄存器中的设置值时引入了科学的数学算法,摒弃了传统工程师使用经验技巧和反复试验获取MulVal和DivAddVal值的人工方法,实现了由程序自动、正确、快速地获取设置寄存器参数值,不仅提高了工作效率,更重要的是完全自动化了程序,无需再人工干预。
希望本文对嵌入式开发同行有一定的参考价值,如有错误,不吝赐教。
参考文献
1、《ARM控制器基础与实战》周立功等
2、《深入浅出ARM7-LPC214x》周立功等
3、《深入浅出ARM7-LPC213x》周立功等
4、《ARM基础实验教程》周立功等
5、《8051微控制器和嵌入式系统》
6、《多位小数的分数逼近法》陈其翔北京联合大学学报1997年9月
第11卷第3期总29期
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- LPC2148 串口 波特率 通信 解决方案