现在很多人拿51单片机起步,其中用的最多的当属STC89C52RC,但随着学习的深入,越来越感觉到这款单片机功能的落后,再加上现在物联网技术的发展,通信成了重要的一环,而许多模块比如蓝牙模块,串口屏,无线模块,GSM模块,串口语言模块等等都用串口通信,而这款单片机的串口就只有一个,远远不能满足功能复杂的大型应用,所以有些人就转向12,15,AVR,STM32等等,但这些单片机的学习资源远不如STC89C52RC,编程复杂了很多,但实际作品并不一定需要这么高级的单片机怎么办,本文将介绍几种常见的方法帮你扩展51单片机的串口: 1:先发一个常用的传统串口程序,里面包含了各种收发程序。 #include <reg52.h> #define MAIN_Fosc 11059200UL /*使用11.0592M晶体,UL相当于无符号整型,也就是unsigned int*/ //函数声明 void ConfigUART(unsigned int baud); void SendByte(unsigned char d); void SendString(unsigned char * pd); //定义一个全局变量a存储接受到的数据 unsigned int a; void main() { EA = 1; //使能总中断 ConfigUART(9600); //配置波特率为9600 SendByte(0x03); SendString("ok"); while(1); } //串口初始化程序 void ConfigUART(unsigned int baud) { SCON = 0x50; //配置串口为模式1 TMOD &= 0x0F; //清零T1的控制位 TMOD |= 0x20; //配置T1为模式2 TH1 = 256 - (MAIN_Fosc/12/32)/baud; //计算T1重载值 TL1 = TH1; //初值等于重载值 ET1 = 0; //禁止T1中断 ES = 1; //使能串口中断 TR1 = 1; //启动T1 } //发送一个字节的数据,形参d即为待发送数据。 void SendByte(unsigned char d) { SBUF=d; //将数据写入到串口缓冲 while(!TI); //等待发送完毕 TI=0; } //发送一个字符串 void SendString(unsigned char * pd) { while((*pd)!='\0') //发送字符串,直到遇到0才结束 { SendByte(*pd); //发送一个字符 pd++; //移动到下一个字符 } } //串口中断函数 void InterruptUART() interrupt 4 { if(RI) { RI = 0; a= SBUF; } } 2:其实不用单片机自带的串口,用定时器可以让任意两个IO口模拟串口 #include<reg52.h> sbit PIN_RXD = P3^0; sbit PIN_TXD = P3^1; bit RxdEnd = 0; bit RxdOrTxd = 0; bit TxdEnd = 0; unsigned char RxdBuf = 0; unsigned char TxdBuf = 0; void ConfigUART(unsigned int baud); void StartRXD(); void StartTXD(unsigned char dat); void main() { EA = 1; ConfigUART(9600); while(1) { while(PIN_RXD); StartRXD(); while(!RxdEnd); StartTXD(RxdBuf); while(!TxdEnd); } } void ConfigUART(unsigned int baud) { TMOD &= 0xF0; TMOD |= 0x02; TH0 = 256 - (11059200/12)/baud; } void StartRXD() { TL0 = 256 - ((256 - TH0)>>1)+4;//之所以加4是因为实地测试发送数据还行,但接收数据误差率太大,估计是51速度太慢,中断中语句太多,当波特率低于9600时可不加4,波特率等于9600则加3以上 ET0 = 1; TR0 = 1; RxdEnd = 0; RxdOrTxd = 0; } void StartTXD(unsigned char dat) { TxdBuf = dat; TL0 = TH0; ET0 = 1; TR0 = 1; PIN_TXD = 0; TxdEnd = 0; RxdOrTxd = 1; } void InterruptTimer0() interrupt 1 { static unsigned char cnt = 0; if(RxdOrTxd) { cnt++; if(cnt <= 8) { PIN_TXD = TxdBuf & 0x01; TxdBuf >>= 1; } else if(cnt == 9) { PIN_TXD = 1; } else { cnt = 0; TR0 = 0; TxdEnd = 1; } } else { if(cnt == 0) { if(!PIN_RXD) { RxdBuf = 0; cnt++; } else { TR0 = 0; } } else if(cnt <= 8) { RxdBuf >>= 1; if(PIN_RXD) { RxdBuf |= 0x80; } cnt++; } else { cnt = 0; TR0 = 0; if(PIN_RXD) { RxdEnd = 1; } } } } 3:有些模块只需要接收单片机发送的数据,那就只接单片机的Txd,同理有些模块只需要给单片机发送数据只接Rxd; 4:多用几块单片机,我们的原则是能用低级的单品机解决的绝不用高级单片机解决。单片机与单片机之间可以用IIC通信或者原始的检测IO口电平。 5:把所有需要用到串口通信的模块都接到单片机的串口上,然后用三极管控制什么时间段什么模块供电工作。 6 :通过SPI串口拓展芯片,比如VK3224芯片,CH432T芯片,GM8142芯片,8251芯片等等。
|