这个是在12T的8051上面用的模拟串口程序,配合22.1184M的晶振,加上6T的双倍速,波特率可以上38400……但是我认为和某些STC的芯片比,还是差了一点,所以说,看官门看注释吧。开启帧请发送没有连续低电平的字符,类似0×55,0xff,0x7f如此等等,如果有连续低电平很容易造成判断失误……这个程序可以用在STC的自动冷启动模块里(STC15F101系列就行,很便宜的,注意是八位装载模式顺便把T1X12关了~然后补偿可以顺便减小一点,顺便说一句,用AT89C51来做也行)。这个在24M/22.1184M/11.0592M均工作正常,11.0592能到9600,24能到38400。不过,我提个醒,如果看官们真拿这个做STC冷启的时候一定要限制波特率小于等于4800。要不然的话。串口正常通讯的时候,这个模块同步上去,把你的电断了,连接掐了,然后估计你会拼命找程序是不是跑飞,浪费很多时间,……
顺便说一句,这个程序也有另外一个用途,在晶振不准的时候仍然可以和电脑以标准波特率通讯。方法就是规定好帧格式,然后上位机不停换波特率找到没有误码率的波特率,然后根据下位机的应答计算出下位机的时钟频率,这个是受了老妖ISP的启发才想到的~大家可以参考我发布的另2篇文章:模拟串口自动测量波特率的单片机程序http://www.51hei.com/mcu/1537.html ,下面这个网页是用11.0592兆的晶振模拟串口接收发发送的已经通过本人测试http://www.51hei.com/mcu/1418.html
上代码:
/*
* 自适应波特率模拟串口程序,
* BY 万致远@rwzy.co.cc
* CRYSTAL:任意
*/
#include <hwconfig.h>
#include <type-def.h>
#include <stdio.h>
#define MIS_0 0
#define MIS_2 1
#define MIS_4 2
#define MIS_8 3
#define MIS_16 4
BYTE min_mode;//减倍模式
void WaitTF1()
{
while(!TF1);
TF1=0;
if(min_mode==MIS_2)
{// /2
while(!TF1);
TF1=0;
}
else if(min_mode == MIS_4)
{// /4
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
}
else if(min_mode == MIS_8)
{// /8
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
}
else if(min_mode == MIS_16)
{// /16
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
while(!TF1);
TF1=0;
}
}
void WByte(BYTE out)
{
//发送启始位
BYTE i=8;
BYTE tmp=out;
TR1=1;//开定时器
TX1=0;
WaitTF1();
//发送8位数据位
while(i--)
{
TX1=(tmp&0x01); //先传低位
tmp=tmp>>1;
WaitTF1();
}
//发送校验位(无)
//发送结束位
TX1=1;
WaitTF1();
TR1=0;
}
void putchar(char ch)
{
WByte(ch);
}
BYTE RByte()
{
BYTE in=0;
BYTE cnt;
while(RX1==1);//等待RXD变低,启动定时器,这个是阻塞模式
TR1=1;//同步开定时器//这里……
//while(!TF1);
//TF1=0;
WaitTF1();
if(min_mode !=0)
{
while(!TF1);//注意这里的周期稍微长。要补偿
TF1=0;
}
for(cnt=0;cnt<8;cnt++)
{
in=in >>1;//从高移到低
if(RX1==1) in = in | 0x80;//如果RXD=1,则最高置位
WaitTF1();//等待一位过去
}
while(!TF1);//注意这里的周期稍微长。要补偿
TF1=0;
TR1=0;//关闭定时器
return in;
}
UINT f_Test(void)//测试脉宽
{
TMOD=0x10;//设置计数器1为方式一计数器模式
TH1=0;
TL1=0;//定时器CLR
while(!RX1);//等待频率脚变高,这个是测低电平的
while(RX1);//等待脚变低,更换符号可以测正脉冲
TR1=1;//开启定时器
while(!RX1);//等待变高
TR1=0;//停止计数
//cyc=TH0<<8;
//cyc=cyc+TL0;
return (TH1<<8)+TL1;
}
void baud_t()
{
BYTE k;//复用变量
ULONG frq=0; //周期变量
for(k=0;k<5;k++)// 变量复用大法
{
frq=frq+f_Test();//测试
}//测量5次取平均
frq=frq/5;
if(frq<0xff)
{
k=0x100-(frq&0xff);
min_mode=MIS_0;
}
else
{
if(frq / 2 < 0xff)
{//2400baud
k=0x100-((frq/2)&0xff); //2分频
min_mode=MIS_2;
}
else if(frq / 4 < 0xff)
{//1200baud
k=0x100-((frq/4)&0xff);//4分频
min_mode=MIS_4;
}
else if(frq / 8 < 0xff)
{//1200baud
k=0x100-((frq/8)&0xff);//8分频
min_mode=MIS_8;
}
else if(frq / 16 < 0xff)
{//1200baud
k=0x100-((frq/16)&0xff);//16分频
min_mode=MIS_16;
}
}
if(k > 0x50)
{
k=k+6;//加补偿,因为if语句让机器周期加长
//如果对于STC的新MCU,这里要按照情况调整
}
TMOD=0x20;//设置定时器1为自动装载模式
TH1=k;//载入新波特率
TL1=k;
}
void main()
{
while(1)
{
baud_t();//测量波特率,阻塞模式
printf("Hello world!\n");
printf("Here:mode=%d,T1=0x%X\r\n",min_mode,TH1);
printf("Could you please test another baudrate?\r\n");
printf("But I think that I couldn't to do.....\r\n");
}
}
完整的源代码下载:http://www.51hei.com/f/molic.rar
转自:万致远的博客http://www.rwzy.co.cc
顺便说一下,根据重载值计算波特率的公式是:
R=重载值
Clock=系统时钟(HZ)
B=波特率
Clock=12(256-R)*B
