對(duì)于一部分坑爹的51單片機(jī)來說,壓根就米有串口啊!!特別是用來做小東西的利器:STC15F100系列的,坑爹到串口都米有的地步。當(dāng)然,我們可以使用軟件來模擬串口。可惜,軟件模擬的串口速度那個(gè)慢(12T單片機(jī)),誤碼率比硬件串口那個(gè)高……但是總比沒有的好。這個(gè)玩意不像硬件一樣能支持全雙工(12T的。1T的可以,畢竟12T的定時(shí)器中斷頻率快了主程序直接會(huì)被阻塞了……)。
另外STC的手冊(cè)上面說的8位自動(dòng)重載定時(shí)器竟然TMOD等于6!導(dǎo)致我搞了一下午都調(diào)不通,沒想到老妖寫錯(cuò)了……定時(shí)器重載模式應(yīng)該是=2.我現(xiàn)在想把TMOD寄存器的O去掉,再用這個(gè)詞問候他們?nèi)遥。?/p>
順便說一句,1T的51單片機(jī)足夠在定時(shí)器里實(shí)現(xiàn)全雙工,這就是為什么老妖說真實(shí)波特率要/3的原因。有RCNT=3這個(gè)語句在,所以可以實(shí)現(xiàn)同時(shí)接收發(fā)送……老妖寫程序不寫注釋是出了名的……但是至于普通的12T單片機(jī)。如果也用老妖得的程序,要注意定時(shí)器模式?jīng)]有16位自動(dòng)重裝模式。如果/3的話,9600就成3200的波特率了……還是非標(biāo)準(zhǔn)的,這個(gè)程序在89C52上最高波特率只能到9600,繼續(xù)往上加就嚴(yán)重誤碼……所以模擬串口還是用1T單片機(jī)或者12T降3倍速吧,(但是速度能卡的可怕,我感覺9600都卡)。要不然誤碼率能搞死人。
對(duì)了,順便說明一下,這個(gè)程序在keil c51上通不過,因?yàn)镵eil內(nèi)置putchar……會(huì)提示重復(fù)定義。能過keil的程序請(qǐng)參考 http://www.zg4o1577.cn/mcu/1541.html, 而且似乎keil的printf函數(shù)有毛病……
#include <hwconfig.h> #include <type-def.h> #include <stdio.h> void WaitTF0() { while(!TF0); TF0=0; } void WByte(BYTE out) { //發(fā)送啟始位 BYTE i=8; BYTE tmp=out; TR0=1;//開定時(shí)器 TX1=0; WaitTF0(); //發(fā)送8位數(shù)據(jù)位 while(i--) { TX1=(tmp&0x01); //先傳低位 tmp=tmp>>1; WaitTF0(); } //發(fā)送校驗(yàn)位(無) //發(fā)送結(jié)束位 TX1=1; WaitTF0(); TR0=0; } void putchar(char ch) { WByte(ch); } BYTE RByte() { BYTE in=0; BYTE cnt; while(RX1==1);//等待RXD變低,啟動(dòng)定時(shí)器,這個(gè)是阻塞模式 TR0=1;//同步開定時(shí)器 WaitTF0();//等到周期過去 for(cnt=0;cnt<8;cnt++) { in=in >>1;//從高移到低 if(RX1==1) in = in | 0x80;//如果RXD=1,則最高置位 WaitTF0();//等待一位過去 } //等待停止位 //WaitTF0(); TR0=0;//關(guān)閉定時(shí)器 return in; } void Init_VSer() { //指令周期=(1000000/Baud)/(12/SysClock) //定時(shí)器值=0x100-指令周期 TMOD |=0x02; //計(jì)數(shù)器0,方式2 TH0=0xa0; TL0=0xa0; TR0=0; //停止計(jì)數(shù) //TF0=0; //ET0=0; //T1中斷關(guān) //EA=0; //總中斷關(guān) } void main() { BYTE a; Init_VSer(); printf("Hello,world!\n"); while(1) { a=RByte();//阻塞模式 putchar(a); } }
順便附上老妖的減掉三倍速的1T單片機(jī)模擬串口程序。穩(wěn)定得多,當(dāng)然效率也低的多。那個(gè)是靠定時(shí)器中斷實(shí)現(xiàn)的。不過至少不會(huì)象在12T上到主程序幾乎跑不動(dòng)的地步。強(qiáng)烈要求老妖出有串口的C版本!
/*----------------------------------------------------*/ /* --- STC MCU International Limited -----------------*/ /* --- 演示STC 15 系列單片機(jī)利用定時(shí)器1實(shí)現(xiàn)模擬串口功能-----*/ /* --- Mobile: (86)13922809991 -----------------------*/ /* --- Fax: 86-755-82905966 --------------------------*/ /* --- Tel: 86-755-82948412 --------------------------*/ /* --- Web: www.STCMCU.com ---------------------------*/ /* 如果要在程序中使用或在文章中引用該程序, -----------------*/ /* 請(qǐng)?jiān)诔绦蛑谢蛭恼轮凶⒚魇褂昧薙TC的資料及程序 -------------*/ /*----------------------------------------------------*/ #include "reg51.h" //define baudrate const //BAUD = 256 - SYSclk/3/BAUDRATE/M (1T:M=1; 12T:M=12) //NOTE: (SYSclk/3/BAUDRATE) must be greater than 98, (RECOMMEND GREATER THAN 110) //開始一直看不懂為什么要除三 //#define BAUD 0xF400 // 1200bps @ 11.0592MHz //#define BAUD 0xFA00 // 2400bps @ 11.0592MHz //#define BAUD 0xFD00 // 4800bps @ 11.0592MHz //#define BAUD 0xFE80 // 9600bps @ 11.0592MHz //#define BAUD 0xFF40 //19200bps @ 11.0592MHz //#define BAUD 0xFFA0 //38400bps @ 11.0592MHz //#define BAUD 0xEC00 // 1200bps @ 18.432MHz //#define BAUD 0xF600 // 2400bps @ 18.432MHz //#define BAUD 0xFB00 // 4800bps @ 18.432MHz //#define BAUD 0xFD80 // 9600bps @ 18.432MHz //#define BAUD 0xFEC0 //19200bps @ 18.432MHz #define BAUD 0xFF60 //38400bps @ 18.432MHz //#define BAUD 0xE800 // 1200bps @ 22.1184MHz //#define BAUD 0xF400 // 2400bps @ 22.1184MHz //#define BAUD 0xFA00 // 4800bps @ 22.1184MHz //#define BAUD 0xFD00 // 9600bps @ 22.1184MHz //#define BAUD 0xFE80 //19200bps @ 22.1184MHz //#define BAUD 0xFF40 //38400bps @ 22.1184MHz //#define BAUD 0xFF80 //57600bps @ 22.1184MHz //define UART TX/RX port typedef bit BOOL; typedef unsigned char BYTE; typedef unsigned int WORD; BYTE TBUF,RBUF; BYTE TDAT,RDAT; BYTE TCNT,RCNT; BYTE TBIT,RBIT; BOOL TING,RING; BOOL TEND,REND; void UART_INIT(); BYTE t, r; BYTE buf[16]; void main() { TMOD = 0x00;//timer1 in 16-bit auto reload mode AUXR = 0x40;//timer1 working at 1T mode TL1 = BAUD;//initial timer1 and set reload value TH1 = BAUD>>8; TR1 = 1;//timer1 start running[原文有錯(cuò)誤],感覺這個(gè)代碼不像老妖寫的。注釋都英文…… ET1 = 1;//enable timer1 interrupt PT1 = 1;//improve timer1 interrupt priority EA = 1;//open global interrupt switch UART_INIT(); while (1) { //user's function if (REND) { REND = 0; buf[r++ & 0x0f] = RBUF; } if (TEND) { if (t != r) { TEND = 0; TBUF = buf[t++ & 0x0f]; TING = 1; } } } } //----------------------------------------- //Timer interrupt routine for UART void tm1() interrupt 3 using 1 { if (RING) { if (--RCNT == 0) { RCNT = 3;//直到我看到了這里…… //reset send baudrate counter if (--RBIT == 0) { RBUF = RDAT; //save the data to RBUF RING = 0; //stop receive REND = 1; //set receive completed flag } else//這TM不是坑爹吧 { RDAT >>= 1; if (RXB) RDAT |= 0x80; //shift RX data to RX buffer } } } else if (!RXB) { RING = 1; //set start receive flag RCNT = 4; //initial receive baudrate counter RBIT = 9; //initial receive bit number (8 data bits + 1 stop bit) } if (--TCNT == 0) { TCNT = 3; //reset send baudrate counter if (TING) //judge whether sending { if (TBIT == 0) { TXB = 0; //send start bit TDAT = TBUF; //load data from TBUF to TDAT TBIT = 9; //initial send bit number (8 data bits + 1 stop bit) } else { TDAT >>= 1; //shift data to CY if (--TBIT == 0) { TXB = 1; TING = 0; //stop send TEND = 1; //set send completed flag } else { TXB = CY; //write CY to TX port } } } } } //----------------------------------------- //initial UART module variable void UART_INIT() { TING = 0; RING = 0; TEND = 1; REND = 0; TCNT = 0; RCNT = 0; }
唉,串口之爭(zhēng)告一段落。我還是希望有硬件串口。
另外就是我實(shí)在不知道詭異的STC ISP串口是怎么在11.0592下面跑到115200的。本來加倍是溢出/16,那么它就算加倍的加倍,也就是/8……既然軟件模擬不可能實(shí)現(xiàn)如此高的波特率。而且6T模式能到230400,我就認(rèn)為他的SFR有串口四倍速選項(xiàng)。可惜老妖沒有拿出來吹,或者說他也不知道。ISP程序也讀不出。實(shí)在不知道是為啥……
順便說一句,STC15系列的片子只要RAM越界就復(fù)位……
順便提一個(gè)老妖的坑爹之處:
ISP定時(shí)常數(shù)不在表格中寫出來……
而是:
/*Define ISP/IAP/EEPROM operation const for IAP_CONTR*/
//#define ENABLE_IAP 0x80
//if SYSCLK<30MHz
//#define ENABLE_IAP 0x81
//if SYSCLK<24MHz
#define ENABLE_IAP 0x82
//if SYSCLK<20MHz
//#define ENABLE_IAP 0x83
//if SYSCLK<12MHz
//#define ENABLE_IAP 0x84
//if SYSCLK<6MHz
//#define ENABLE_IAP 0x85
//if SYSCLK<3MHz
//#define ENABLE_IAP 0x86
//if SYSCLK<2MHz
//#define ENABLE_IAP 0x87
//if SYSCLK<1MHz
暈死……但是我為什么發(fā)現(xiàn)似乎0×83這個(gè)ISP常數(shù)到處可以用,1M的RC設(shè)置照樣0×83下……
本文轉(zhuǎn)自:http://www.rwzy.co.cc