51单片机模拟TTL串口(基于11.0592M)

问题说明:

在我们使用51单片机时会发现他就只有一个RX跟TX,但是要实现一个完整的数据采集、上传与管理,一个串口是完全不够的(采集装置一般需要一对串口,而通讯装置也需要一对串口)那么问题就产生了,51单片机只提供一个串口,我们应该怎么办?

  1. 本文的模拟TTL串口是利用51单片机的IO口来实现串口模拟。我们知道单片机的所有IO口我们都能控制它的高低电平(1/0),而我们要通过它来模拟TTL串口,我们首先得知道TTL串口的工作原理
    TTL串口数据传输这如上图所示
    起始位:由1个逻辑 0 的数据位表示

    结束位:由 0.5、 1、 1.5 或 2 个逻辑 1 的数据位表示

    有效数据:在起始位后紧接着的就是有效数据,有效数据的长度常被约定为 5、 6、 7 或 8、9位

    校验位:可选,为的是数据的抗干扰性(没用过)

  2. 串口通信的波特率,说到底只是每位电平持续的时间,波特率越高,持续的时间越短。如波特率为9600bps,即每一位传送时间为1000ms/9600=0.104ms,即位与位之间的延时为0.104毫秒。

  3. 单片机常用11.0592M的的晶振,传感器一般也使用11.0592M的波特率来通讯。用此频率则每个指令周期(取出指令并执行的时间)的时间为(12/11.0592)us,波特率为9600的指令周期s=(1000000/9600)/(12/11.0592)=96,刚好为一整数。如此便于我们用程序指令实现较为准确的延时。

  4. 现在进入主题!模拟串口一般有三种方法,我们以11.0592M晶振 9600波特率为例。以下方法皆通过本人测试可用。

    方法一: 延时法
    该方法使用指令周期延时的方法来模拟波特率实现串口通讯,较为简单,使用较为广泛也适用于模拟多串口通讯,但是对采样的精确度要求较高,需要重复调试其指令周期的延时,本人在51实验测试通过,有时传输的数据会出错,不稳定,所以不推荐。
    通过上述计算大家知道,串口的每位需延时0.104秒,中间可执行96个指令周期

#include "reg52.h"
#define uchar unsigned char
#define RXD P1_0 //接收脚
#define TXD P1_1 //发送脚
#define WRDYN 44 //写延时
#define RDDYN 43 //读延时
//延时程序*
void Delay2cp(unsigned char i)
{
while(--i); //i=1,两个指令周期。
}
//往串口发送一个字节
void WByte(uchar input)
{
uchar i=8;
TXD=(bit)0; //发送启始位
Delay2cp(39);
//发送8位数据位
while(i--)
{
TXD=(bit)(input&0x01); //先传低位
Delay2cp(36);
input=input>>1;
}
//发送校验位(无)
TXD=(bit)1; //发送结束位
Delay2cp(46);
}
//从串口接收一个字节
uchar RByte(void)
{
uchar Output=0;
uchar i=8;
uchar temp=RDDYN;
//接收8位数据位
Delay2cp(RDDYN*1.5); //此处注意,等过起始位
while(i--)
{
Output >>=1;
if(RXD) Output |=0x80; //先收低位
Delay2cp(35); //(96-26)/2,循环共占用26个指令周期
}
while(--temp) //在指定的时间内搜寻结束位。
{
Delay2cp(1);
if(RXD)break; //收到结束位便退出
}
return Output;
}

方法二: 计数法
该方法通过单片机的时钟计数来产生准确的波特率来实现串口模拟。该方法较为准确,只要波特率正确就可以实现通讯。(只有发送部分)


void S2INI(void)
{
TMOD |=0x02; //计数器0,方式2
TH0=0xA0; //预值为256-96=140,十六进制A0
TL0=TH0;
TR0=1; //开始计数
TF0=0;
}//计数器初始化


void WaitTF0( void )
{
while(!TF0);
TF0=0;
}//查询计数器溢出标志位

//向串口发送一个字节数据,过程同上
void WByte(uchar input)
{
uchar i=8;
TR0=1;
TXD=(bit)0;
WaitTF0();
while(i--)
{
TXD=(bit)(input&0x01);
WaitTF0();
input=input>>1;
}
TXD=(bit)1;
WaitTF0();
TR0=0;
}

方法三:中断法
与计数法大同小异,就不解释了。(只有接收)

#define TM0_FLAG P1_2 //设传输标志位
//计数器及中断初始化
void S2INI(void)
{
TMOD |=0x02; //计数器0,方式2
TH0=0xA0; //预值为256-96=140,十六进制A0
TL0=TH0;
TR0=0; //在发送或接收才开始使用
TF0=0;
ET0=1; //允许定时器0中断
EA=1; //中断允许总开关
}
//接收一个字符
uchar RByte()
{
uchar Output=0;
uchar i=8;
TR0=1; //启动Timer0
TL0=TH0;
WaitTF0(); //等过起始位
//接收8位数据位
while(i--)
{
Output >>=1;
if(RXD) Output |=0x80; //先收低位
WaitTF0(); //位间延时
}
while(!TM0_FLAG) if(RXD) break;
TR0=0; //停止Timer0
return Output;
}
//中断1处理程序
void IntTimer0() interrupt 1
{
TM0_FLAG=1; //设置标志位。
}
//查询传输标志位
void WaitTF0( void )
{
while(!TM0_FLAG) ;
TM0_FLAG=0; //清标志位
}

声明:该代码是网上截取,非本人代码,但方法确实可用。本人在此只分享方法以及学习过程、若无法实现可以联系本人互相交流学习。

  • 0
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值