這個是在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.zg4o1577.cn/mcu/1537.html ,下面這個網頁是用11.0592兆的晶振模擬串口接收發發送的已經通過本人測試http://www.zg4o1577.cn/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.zg4o1577.cn/f/molic.rar
轉自:萬致遠的博客http://www.rwzy.co.cc
順便說一下,根據重載值計算波特率的公式是:
R=重載值
Clock=系統時鐘(HZ)
B=波特率
Clock=12(256-R)*B