软件模拟串口实现51自收自发

描述:用软件模拟串口实现自收自发(单片机接收到什么数据,也会发回电脑)

本质是用定时器、中断来产生相应的波特率

只要解决以下三个问题
**
1.UART原理
2.理解波特率,用定时器配置波特率
3.没有SBUF寄存器,怎么解决,数据缓冲区**

1.UART原理

在这里插入图片描述
在这里插入图片描述

2.理解波特率

在这里插入图片描述

波特率
波特率=发送二进制数据位的速率
1/波特率=发送一位二进制数据持续的时间

定时器计数时间
计时器计数频率可以选择时钟源/12,且时钟源为12 MHz。那么,定时器0的计数频率为:12MHz / 12 = 1 kHz。
定时器的计数频率确定了每秒计数的次数,因此计数一次的时间可以通过倒数计算得出。

配置定时器与波特率关系
定时器从重装载值到溢出的时间,其实就是1/波特率(发送一位二进制数据持续的时间)

3.解决没有SBUFF寄存器的问题

在这里插入图片描述
简而言之就是通过一些特殊的按位与或操作,详见后续代码注释(比如PIN_TXD = TxdBuf & 0x01; 部分)

#include<reg52.h>

sbit PIN_RXD = P1^2;
sbit PIN_TXD = P1^3;

bit RxdEnd = 0;         //接收完成标志
bit RxdOrTxd = 0;		//RXD = 0,TXD = 1 判断是发送还是接收
bit TxdEnd = 0;			//发送完成标志
unsigned char RxdBuf = 0;		//数据接收缓冲区,相当于SBUF
unsigned char TxdBuf = 0;		//数据发送缓冲区,相当于SBUF

void ConfigUART(unsigned int baud);		//配置串口
void StartRXD();						//开始接收
void StartTXD(unsigned char dat);		//开始发送

void main()
{
	EA = 1;				//开总中断
	ConfigUART(4800);	//波特率4800
	
	while(1)
	{
		while(PIN_RXD==1);         //检测到起始位0进入下一步
		StartRXD();				//开始接收
		while(!RxdEnd);	//RxdEnd==1退出循环	表示接收完毕	
		StartTXD(RxdBuf);//把单片机接收到的数据 再发送回电脑
		while(!TxdEnd);//TxdEnd==1退出循环	表示发送完毕	
	}
	
}

void ConfigUART(unsigned int baud)
{
	TMOD &= 0xF0;			//清除定时器低四位
	TMOD |= 0x02;			//定时器0, 模式2, 8位自动重装载模式
	TH0 = 256 - (12000000/12)/baud;			//高位预装载值 
}
//从计时到溢出的次数为=(12000000/12/)/baud,一次的时间是12/12000000,1/baud 是发送一位二进制数持续的时间x

//定时器0, 模式2, 8位自动重装载模式
//计数值存在TL0中,自动重装载值存在TH0中
void StartRXD()
{
	TL0 = 256 - ((256 - TH0)>>1);	//从计数值TL0到溢出的时间是(256 - TH0)>>1
	//256 - TH0对应了一个波特周期,右移一位相当于/2,就是半个波特周期
	ET0 = 1;//使能T0中断
	TR0 = 1;//启动TO
	RxdEnd = 0;//清零接收结束标志
	RxdOrTxd = 0;//接收模式
}

void  StartTXD(unsigned char dat)
{
	TxdBuf = dat;
	TL0 = TH0;//T0计数初值
	ET0 = 1;//使能T0中断
	TR0 = 1;//启动TO
	PIN_TXD = 0;//发送起始位
	TxdEnd = 0;//清零发送结束标志
	RxdOrTxd = 1;//发送模式
}

void InterruptTimer0() interrupt 1
{
	static unsigned char cnt = 0;		// 接收/发送 到第几位计数

	if(RxdOrTxd==1)			//发送部分
	{
		cnt++;
		if(cnt <= 8)
		{
			PIN_TXD = TxdBuf & 0x01;		//每次发一位,从低位发起
			//TxdBuf和0x01(也就是00000001)与的效果是除了最低位其他都清0
			//所以就将最低位发送
			TxdBuf >>= 1;                  	//右移一位,次低位为低位
		}
		else if(cnt == 9)       
		{
		 	PIN_TXD = 1;			//发送停止位
		}
		else
		{
			cnt = 0;				//清除计数
			TR0 = 0;				//关闭定时器
			TxdEnd = 1;				//置发送完成标
		}
	}
	
	else					//接收部分
	{
		if(cnt == 0)				
		{
			if(!PIN_RXD)		//检测到接收起始位0
			{
				RxdBuf = 0;//先把数据缓冲区清0
				cnt++;
			}
			else//如果接收起始位不为0,表示未开始接收
			{
				TR0 = 0;//关闭定时器
			}
		}
		else if(cnt <= 8)
		{
			RxdBuf >>= 1;		//数据右移一位
			if(PIN_RXD)		//如果接收到的数据为1,就或上0x80让高位为1 
			{
				RxdBuf |= 0x80;		//或0x80只会改变最高位,其他位都不变
			}
			cnt++;
		}
		else
		{
			cnt = 0;
			TR0 = 0;
			if(PIN_RXD)			//检测到接收停止位
			{
				RxdEnd = 1;		//置接收完成标志位		
			}
		}
	}
}


  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
c8051可以通过以下步骤实现串口通信自发自收: 1. 配置串口工作模式:通过设置串口控制寄存器(SCON)的相关位,选择串口的工作模式、波特率等参数。 2. 发送数据:将要发送的数据写入串口数据寄存器(SBUF)中,串口会自动将数据发送出去。 3. 接收数据:当有数据从串口发送过来时,串口会自动将数据存储到SBUF中,并触发串口中断。在中断服务函数中,可以将接收到的数据读取出来,进行处理。 4. 自发自收:为了实现自发自收,需要在中断服务函数中实现一个循环,不断地将读取到的数据写入SBUF中,以实现自发自收的功能。 下面是一个简单的c8051串口通信自发自收代码示例: ```c #include <c8051f020.h> void main() { // 串口配置 SCON = 0x50; // 选择工作模式为模式1 TMOD = 0x20; // 定时器1工作在模式2 TH1 = 0xfd; // 波特率设置为9600bps TL1 = 0xfd; // 定时器1启动 TR1 = 1; // 中断配置 IE = 0x90; // 允许串口中断和定时器1中断 IP = 0x10; // 将串口中断优先级设为高 // 启用全局中断 EA = 1; // 循环发送和接收数据 while(1) { // 发送数据 SBUF = 0x55; // 接收数据 // 数据将在中断服务函数中处理 } } // 串口中断服务函数 void serial_ISR() __interrupt 4 { // 发送和接收数据 SBUF = SBUF; } ``` 在该代码中,我们通过设置SCON和TMOD寄存器来配置串口的工作模式和波特率,然后启动定时器1,并开启中断。在主循环中,我们通过不断地向SBUF中写入数据来实现自发自收的功能。在中断服务函数中,我们将读取到的数据再次写入SBUF中,实现自发自收的功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值