51单片机———串口向电脑发送数据&电脑通过串口控制LED灯

本文详细解释了如何在单片机中配置串口通信,包括SCON和PCON寄存器设置,选择合适的波特率,以及如何避免因误差导致的数据问题。同时介绍了如何通过串口控制LED灯,涉及中断配置和处理过程。
摘要由CSDN通过智能技术生成

我们需要在串口通信前告诉CPU相应的内容,所以我们要在主程序初始化位置配置好寄存器:

以上寄存器中,在此次程序中(单片机向电脑发送数据)我们只需要配置SCON和PCON即可,不需要开启中断,所以不需要配置中断部分

SCON和PCON的格式如下:

以上这些都不需要记忆,只是为了让你清楚如何去配置。

如果我们要根据配置模式1,其各数据位的操作如图所示:

转化为16进制就是0x40;

其中,TI、RI和SMOD在串口模式图中的位置如下图所示:

也就是说SMOD如果给1(打到1的位置)就是波特率不加倍,如果给0就是波特率➗2,波特率减半。其中SBUF不需要配置,TI和RI分别控制是否去中断系统。


其实这些东西不需要我们一个一个去根据手册去配置出来,STC-ISP会给我们生成程序,我们可以直接照搬:

可以看到:我们这里的定时器选择的是8位自动重载,而我们之前定时器时钟部分我们选择的是16位定时器,两者的区别是:

16位定时器有65535个数据位,我们在使用的时候需要赋予初值,比较浪费时间;而8位自动重载定时器把16位拆成2部分,两部分分别(也就是8位)只有255个数据位,但我们使用时不需要赋予初值,它会自动赋初值,不需要程序进行操作;

这里为什么选择波特率为4800而不是9600?可以看到上面生成的代码是存在一定的误差的,如果把波特率设置为960会发现这个误差值增加,这个误差可能会导致数据错误甚至无法正常工作。但4800的波特率还是会有百分之6.99的误差率,这时候我们需要让开启波特率倍速,让误差大大减小:

代码复制过来后,我们需要将红色圈起部分删除,因为高系列单片机可能可以进行选择,但89C82系列根本没得选。

注意:这里为什么禁止定时器1中断?

在定时器时钟部分时,定时器中断是指到点了就中断,而在串口发送数据这里,定时器起到的作用是控制单片机的波特率,使单片机的波特率一致,我们需要用到的是串口中断,而非定时器中断,串口中断是指接收到数据了就中断。而我们这个程序是单片机向电脑发送数据,所以也用不到串口中断。接下来的电脑通过串口控制LED会用到串口中断。

配置完成后,我们开始发送数据:首先定义一个发送字节的函数,往Byte的值赋予SBUF。

这里通过判断TI是否等于0的一个循环,是为了检测数据是否发送完成。也就是说发送数据前TI本身就为0,如果没发送完成就一直在循环里面,直到8位数据全部发送完成后,硬件自动置1,TI = 1,跳出循环,去中断系统,然后这时候我们需要软件置0,让它能够再次重新判断下一个数据发送是否完成。

然后我们烧录一下看看现象:

可以看到电脑成功接受到数据AA

这里有几点需要注意(1)串口选择应该要与我们是扫描串口一致(2)电脑波特率要和单片机的波特率保持一致,均为4800(3)我这里选择了编程完成后自动打开串口,程序下载完成之后,需要按下单片机的复位键(晶振旁边的红色小按键)才能接受到,否则会出现串口打开失败或者接受区空白的情况。

还有一种情况:同样的数据我放入循环当中,使它循环发送,就会出现明明发送的是AA,但显示的却是35的情况:

如果把发送的数据放入循环当中,循环发送,就可能会出现数据接受错误的情况。这是因为发送速率太快加上有误差,这时候我们只需要在循环后面加上一个延时就能解决这个问题,加上延时给它一个缓冲的时间,如果误差率大的话,为了不出差,延时的时间也应该延长一些。

1、串口向电脑发送数据的完整代码如下:

#include <REGX52.H>
#include "DELAY.H"

	void Uart_Init(void)		
{
	PCON |= 0x80;		
	SCON = 0x40;		
	TMOD &= 0x0F;		
	TMOD |= 0x20;		
	TL1 = 0xF3;			
	TH1 = 0xF3;			
	ET1 = 0;			
	TR1 = 1;			
}

void Uart_SendByte(unsigned char Byte)
{
   SBUF = Byte;
	 while(TI == 0){};
	 TI = 1;
}

void main()
{  
	 Uart_Init();
	 

   while(1)
		{
			Uart_SendByte(0xAA);
			Delay(10);
		}

}

2、串口向电脑逐一发送数据代码如下:(前面已模块化)

#include <REGX52.H>
#include "DELAY.H"
#include "Uart.H"

unsigned char Sec;

void main()
{  
	 Uart_Init();
	 

   while(1)
		{
			Uart_SendByte(Sec);
			Sec++;
			Delay(1000);
		}

}

3、电脑通过串口控制LED灯

EA(Enable All):

       CPU的总中断允许控制位,从上面的中断电路图可以看出,当EA = 1时,开关闭合,线路接通,CPU开放中断,反之EA  = 0,CPU屏蔽所有中断申请,各中断源首先受EA控制,其次还受各中断源自己的中断允许控制位控制

上面的程序有说到:如果串口只需要发送数据(只发不收),那么我们不需要开启定时器中断以及串口中断,现在我们想要实现电脑通过串口控制LED(即发又收),那么我们需要开启串口中断,也就是当有数据传输给串口的时候,就会进入中断,读取数据。如果没有串口中断,我们需要时时刻刻准备着,因为不知道什么时候电脑会传输数据过来。

为什么有数据进来了就会进入中断呢?可以看到上图中只要TI = 1或者RI = 1时,我们只需要把ES和EA控制好,这条电路就能连通就会进入中断。

所以我们需要在前面程序的基础上,对串口中断进行配置:

串口中断配置好后,我们需要写串口中断函数:

这里我们检测一下,看看是否能够进入中断,如果进入中断了,LED将会被点亮:

这里我们在发送缓冲区随便发送一个数据f0,使数据传输给串口,这样才能触发中断,实施中断里面的代码,使灯全部点亮。

想要实现电脑通过串口控制LED,我们只需要让P3 = SBUF即可:

这里为什么要加一个判断if呢?因为TI = 1和RI = 1 占用同一个通道,也就是说触发指令的也可能是TI而不是RI 。这时候我们在发送缓冲区发送相应的数据,就能直接控制LED灯,如果发00,那就是全部灯亮,发f0就是只有一半亮。

注意!选择的LED的I/O口不要与UART的两个引脚相互冲突!否则就会出现错误的现象!

串口助手里面的文本和EX模式

文本模式就是显示的是所对应的ASCII码   ;EX模式显示的就是二进制或者十六进制。

电脑通过串口控制LED灯的完整代码如下:

#include <REGX52.H>
#include "Delay.h"
#include "Uart.h"

void main()
{
	Uart_Init();
    while(1)
	{

	}
}

void Uart_Routine() interrupt 4
{
  if(RI == 1)
  {
    
		P0 = SBUF;
		Uart_SendByte(SBUF);
	    RI = 0;
  
  }

}

其中模块化程序如下:

#include <REGX52.H>

/**
   *  @brief 串口初始化
   *  @param 无
   *  @retval 无
   */
void Uart_Init(void)		//4800bps@12.000MHz
{
	PCON |= 0x80;		//使能波特率倍速位SMOD
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xF3;			//设置定时初始值
	TH1 = 0xF3;			//设置定时重载值
	ET1 = 0;			//禁止定时器中断
	TR1 = 1;			//定时器1开始计时
	EA = 1;
	ES = 1;
}

/**
   *  @brief  串口要发送的一个字节数据
   *  @param  Byte一个要发送的字节数据
   *  @retval 无
   */

void Uart_SendByte(unsigned char Byte)
{
   SBUF = Byte;
	 while(TI == 0){};
	 TI = 0;
}
#ifndef ___Uart_H__
#define ___Uart_H__

void Uart_Init(void);		
void Uart_SendByte(unsigned char Byte);


#endif

  • 31
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值