这个是在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