标题: STC89C52RC拓展串口(串口不够)的解决方法 [打印本页]
作者: 837877663 时间: 2018-1-19 22:10
标题: STC89C52RC拓展串口(串口不够)的解决方法
现在很多人拿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芯片等等。
-
图片1.png
(47.64 KB, 下载次数: 112)
-
图片3.png
(59.45 KB, 下载次数: 105)
-
图片4.png
(72.91 KB, 下载次数: 102)
作者: liuhu55 时间: 2018-11-18 22:57
没有过模拟串口试试看
作者: 121212121212123 时间: 2019-12-19 22:44
楼主你好,我也是SCT15 89C52RC的,程序和助手波特率都是9600,但每次在串口助手输入A,返回都是80的,找了很久找不出问题。。。。。
作者: lyseg 时间: 2019-12-20 09:57
谢谢分享!!!
作者: 啷里个浪 时间: 2019-12-20 11:35
每个人定义的端口不同,接法也不同,需要你自己去了解一下
作者: 121212121212123 时间: 2019-12-21 21:21
十分感谢楼主,可以搞定了,还做了个双字节模拟的
作者: 有心插花花木兰 时间: 2020-4-8 11:01
121212121212123 发表于 2019-12-19 22:44
楼主你好,我也是SCT15 89C52RC的,程序和助手波特率都是9600,但每次在串口助手输入A,返回都是80的,找了 ...
试试ASCII
作者: myemcu 时间: 2021-10-12 15:23
4052,分时扩4。
作者: wifingtta 时间: 2022-3-10 17:35
不错,试试楼主这些方法。之前都是用继电器通断通信线的。
作者: wifingtta 时间: 2022-3-10 18:06
程序完全没问题,可以实现单字节收发。自己改了下多字节,这次只要发,下次再试试多字收
//多字节发送
for(i=0;i<8;i++)
{
StartTXD(voice[i]);//发送接收数据
while(!TxdEnd); //发送完成
}
这样发送8个字节,完全没有问题。谢谢楼主,可以扩展简单的串口应用
欢迎光临 (http://www.51hei.com/bbs/) |
Powered by Discuz! X3.1 |