51单片机IO模拟UART

一、 IO模拟UART发送

串口通信属于 串行 异步 半双工的通信模式

1、 最近在调试一个IO模拟UART的程序,把调试过程中遇到的问题总结一下。对于UART的发送部分(主机模式)还是比较容易实现的。比较麻烦的做从机时,UART接收还在调试,可以接收数据,但还存在很多问题。

(1) 起始位:总线没通信是高电平状态,要进行通信时,总线拉低发出“逻辑0”信号,表示开始传输数据

(2) 数据位:通常以1byte数据为标准,从低位开始传输,通过时钟频率来定位数据的传输

(3) 奇偶校验位:通过在数据末尾加上1位,使得数据包中的1的个数为偶数(偶校验)或者是奇数(奇校验),来确定数据的准确性。

(4) 停止位:在通信结束时,将总线拉高发出“逻辑1”信号,表示传输结束,也给下次进行通信提供了校准时间的机会

2、波特率

波特率表示每秒钟传送的码元符号的个数,是衡量数据传输速率的指标,它用单位时间内载波调制状态改变的次数来表示,1波特即指每秒传输1个符号。

若 波特率为9600bps,那么传输一位数据的时间是在1000ms/9600bps=0.104ms

3、串口发送数据组成

数据由:1bit起始位+8bit数据+1bit停止位构成;

所以,搞懂这些原理,串口发送并不难,主要把单片机的定时器配置在104us左右溢出中断,保证每一位时间间隔在104us 左右即可。

我用的是51单片机,51本身自带一个串口,但自己想用IO模拟一个串口出来,便于自己更好的理解串口,也作为自己的一个技术储备。

UART 源文件

#include "reg52.h"
#include "type.h"
#include "uart.h"
#include "timer.h"

void UART_INIT(void)
{
    TX_D=1;
    Timer1Init();    //T1 初始化
}

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

//写数据很快的话,定时器不稳定而导致发送的数据会有错码,发送时应适当延时降低错码概率

void Write_DATA(uint8_t input) 
{
    uint8_t i=8;  //写入1byte数据
    TR1=1;        //开始计时
    TX_D=0;        //拉低信号线准备发送数据  起始信号
    WAIT_TF1();    //106us溢出一次,溢出进行下一位的传输 
    while(i--)    //开始写数据
    {
        TX_D=input&0X01;
        WAIT_TF1();
        input>>=1;
    }
    TX_D=1;      //8位数据发完拉高信号线  停止信号
    WAIT_TF1();
    TR1=0;        //停止计时
}

//发送字符串
void Send_Char(uint8_t *buf)

{
    while(*buf != '\0')
    {
    Write_DATA(*buf);
    buf++;
    }
}

//发送数字
void Send_Num(uint8_t *buf,uint16_t s)
{
    while(s--)
    {
        Write_DATA(*buf+48);    //ASCII 将字符转换成数字
        buf++;
    }
}

//发送多个数据

void Send_ND(uint8_t *buf,uint16_t len)
{
    while(len--)
    {
        Write_DATA(*buf);   
        buf++;
    }
}

UART头文件

#include "type.h"
#ifndef  __UART_H__
#define  __UART_H__

sbit TX_D=P0^6;

extern uint8_t flag2;

extern void Send_Char(uint8_t *buf);                //发送字符
extern void Send_ND(uint8_t *buf,uint16_t len);    //发送N个数据
extern void Send_Num(uint8_t *buf,uint16_t s);      //发送数字
extern void UART_INIT(void);                        //串口初始化
extern void WAIT_TF1(void);                        //等待TF1溢出
extern void Write_DATA(uint8_t input);              //写数据

#endif

TIMER源文件

#include "reg52.h"
#include "type.h"
#include "timer.h"

uint8_t flag1=0;

void Timer1Init()

{
  	TMOD = 0x10;  //T1  方式1
    TH1 = 0xFF;    //波特率9600bps 1000ms/9600bps=0.104ms 
    TL1 = 0xA0;    //定时器误差2us左右  106us
    EA = 1;
    ET1 = 1;
    TR1 = 1;
    TF1=0;
}

void Time1() interrupt 3
{
	if(TR1==1)
	{
		TH1=0XFF;
		TL1=0xA0;
		flag1=1;
	}
}

TIMER头文件

#include "type.h"
#ifndef   __TIMER_H__
#define   __TIMER_H__

extern uint8_t flag1;
extern void Timer1Init(void);
#endif

TYPE头文件

#ifndef   __TYPE_H__
#define   __TYPE_H__

#define uint8_t   unsigned char
#define uint16_t  unsigned int 
#endif

main测试程序

#include "reg52.h"
#include "type.h"
#include "timer.h"
#include "uart.h"


uint8_t Buff[5]={1,2,3,4,5};

void main(void)
{
	UART_INIT();
	Write_DATA('A');
	Send_Char("testuart");
	Send_Num(Buff,5);
	while(1);

/***************************************************************************************************************/

二、 IO模拟UART接收

1、模拟串口接收部分是可以接收,但存在很多问题

2、我对问题进行了总结以便后期改进

3、读数据 接收数据的效果不是很好,需要连续的点击发送字符才会成功

 问题解析:估计是等到单片机扫描时,串口helper已经把数据发送完了,单片机这边对不上起始信号从而导致错峰,所以串口helper需要不停的点击发送在这个期间对上了就进去了。
 最近调试了一下,现在接收部分已经可以正常接收了。

接收部分

uint8_t Receive_Data(void)
{
	uint8_t receive=0,t=0;
	uint8_t i=8;
	while(RX_D);    //等待起始信号,超时自动退出
	TR1=1;    //开始计时
	WAIT_TF1();
	while(i--)
	{
		receive>>=1;
		if(RX_D)receive|=0x80;
		WAIT_TF1();
	}
	TR1=0;
	return receive;
}

void Recevice(uint8_t *temp,uint8_t data_size)    
{
	while(data_size--)
	{
		*temp++=Receive_Data();
	}

}

TEST

uint8_t recv[20]={0};
void main(void)
{
	UART_INIT();
	while(1)
	{
	  Recevice(recv,5);
	  Send_ND(recv,5);
	}
}

2020年11月17日

  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单片机IO模拟UART通讯是通过软件编程的方式,利用单片机IO模拟实现UART通信的功能。在实际应用中,由于某些特定的需求或不具备硬件资源的情况下,采用IO模拟UART通讯成为一种常见的解决方案。 实现IO模拟UART通讯的一般步骤如下: 1. 初始化IO:首先通过配置单片机IO为输入或输出模式,并设置相应的引脚作为发送和接收数据的引脚。 2. 设置波特率:根据需求,选择合适的波特率,通过计算器或查表的方式,设置单片机的定时器或延时函数,以控制数据的发送和接收速度。 3. 数据发送:通过对发送引脚输出高低电平来模拟数据发送。根据需要发送的数据,将数据拆分为位,并通过IO依次输出到发送引脚上,加上起始位、停止位等协议要求的约定位。 4. 数据接收:通过对接收引脚的电平变化进行监测,判断是否有数据到达。当接收引脚电平发生变化时,通过IO将接收到的数据存储在单片机的内部缓冲区中。 5. 数据处理:在数据接收完毕后,可以在单片机中进行相应的数据处理,例如解析协议、校验数据等操作。 需要注意的是,IO模拟UART通讯在一些特殊情况下可能会存在一些局限性,例如通信速率较低,可靠性较差等。因此,在实际应用中,应根据具体需求和条件选择合适的通信方式。如果有必要,也可以通过外部模块或芯片来实现更稳定和高速的UART通讯。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值