1.概述
在之前的GSM模块学习过程中与单片机进行连接时,要充分考虑波特率之间的对应关系,我们在以下程序中设置了定时器1的工作模式,采用了2:8自动重载。因为部分51单片机采用11.0592MHZ的晶振频率,而也有一部分采用12MHZ的晶振频率,这里为了提高程序的可移植性,故采用了#ifdef条件编译语句,通过我们设定的晶振频率设置不同的数值初始化串口。
2.波特率计算原理
在串行通信中,收发双方对发送或接收的数据速率要有一定的约定,我们通过软件对51串行口编程可约定四种工作方式。其中,方式0和方式2的波特率是固定的,而方式1和方式3的波特率是可变的,由定时器T1的溢出率决定。 串行口的四种工作方式对应着三种波特率。由于输人的移位时钟的来源不同,所以,各种方式的波特率计算公式也不同,方式0时,移位时钟脉冲由56(即第6个状态周期,第12个节拍)给出,即每个机器周期产生一个移位时钟,发送或接收一位数据。所以,波特率为振荡频率的十二分之一,并不受PCON寄存器中SMOD的影响。
方式1和方式3的波特率方式1和方式3的移位时钟脉冲由定时器T1的溢出率决定,故波特宰由定时器T1的溢出率与SMOD值同时决定,即方式1和方式3的波特率=2SMOD/32·T1溢出率 其中,溢出率取决于计数速率和定时器的预置值。计数速率与TMOD寄存器中C/T的状态有关。当C/T=0时,计数速率=fosc/2;当C/T=1时,计数速率取决于外部输入时钟频率。
3.代码
void SerialInti()//初始化程序(必须使用,否则无法收发)
{
TMOD=0x20;//定时器1操作模式2:8位自动重载定时器
#ifdef FOSC_12M //在这里根据晶振大小设置不同的数值初始化串口
TH1=0xf3;//装入初值,波特率2400
TL1=0xf3;
#else
TH1=0xfd;//装入初值,波特率9600
TL1=0xfd;
#endif //end of SOC_12M
4.问题总结
1.如何根据晶振大小设置不同的初值?
通过在定时器串口学习过程中我们知道,波特率的计算公式为(2SMOD/32)*(OSC_FREQ(Hz)/((256-TH1)12))。
2400=20/32*(12*106/12(256-初值))由此可以算出THI=TL1=0xf3,当我们采用的波特率为2400时才能既保证误差小同时也能保证一定的速率(当然在波特率为1200时误差同样,但是速度明显降低)。同理,我们在采用11.0592MHZ的晶振时同样使用相同的方法可以得出TH1=TL1=0xfd;
2.如何根据波特率对应的初值大小计算误差?
实践表明,当波特率的相对误差小于4.5%时,不会影响数据的正确接收,一般要保证传输的可靠性,要求误差不大于2.5%。
当定时器Tl作波特率发生器使用时,通常选用可自动装入初值模式(工作方式2),在工作方式2中,TLl作为计数用,而自动装入的初值放在THl中,设计数初值为x,则每过“256一x”个机器周期,定时器T1就会产生一次溢出。为了避免因溢出而引起中断,此时应禁止T1中断。这时,溢出周期为:
根据计算公式可以得出:
由此可得出在晶振为12MHZ,波特率为2400,初值设定为0xf3时,所造成的误差在0.16%,在误差允许范围2.5%以内,符合我们的传输要求。
同理当我们的晶振为11.0592MHZ时,我们选用9600bps,根据计算公式所得出的初值大小为0xfd(16进制)
上面的计算可以看出使用12M晶体的时候计算出来的TH1不为整数,而TH1的值只能取整数,这样它就会有一定的误差存在不能产生精确的9600波特率。当然一定的误差是可以在使用中被接受的,就算使用11.0592M的晶体振荡器也会因晶体本身所存在的误差使波特率产生误差,但晶体本身的误差对波特率的影响是十分之小的,可以忽略不计。
3.GSM模块为什么能在2400的波特率下正常与单片机进行通信?
这里建议大家在学习一个新的模块时一定要首先了解他的官方数据手册,而这个问题就是属于GSM模块的属性问题。我通过阅读数据手册了解到GSM模块的通信速率支持从1200-115200bps。这也就是为什么GSM模块在2400bps下依然能够正常工作。如图:
另外大家需要注意的是,我们在设置了不同工作模式的波特率后,一定要在串口调试助手端匹配相应的波特率,否则在接收数据过程中容易出现乱码及通信不成功的现象。