什么可以用手机蓝牙控制LED???#串口通信【中】

什么可以用手机蓝牙控制LED???#串口通信【中】

前言

  本篇博文介绍的是用51单片机的串口通信【中】,包含串口编程01_自己实现串口初识化,串口编程02_发送字符串,串口编程03_PC发送指令控制LED,串口编程04_串口中断控制LED。看到这篇博文的朋友,可以先赞再看吗?

预备知识

  一、数学分数计算。
  二、数字电子时序图

  三、数字电子中与或运算
  四、计算机中的进制转换
  五、C变量
  六、基本输入输出
  七、流程控制
  八、函数

  九、指针
  十,字符串

  如果以上知识不清楚,请自行学习后再来浏览。如果我有没例出的,请在评论区写一下。谢谢啦!

1.串口编程01_自己实现串口初识化

1.1实现串口初始化核心思路

  • 配置串口工作方式为方式1,只收不发
  • 配置辅助寄存器,减少电磁辐射,稳定晶振频率
  • 设置定时器工作方式为定时器1的8位自动重装
  • 设置串口波特率为9600,0误差
  • 打开定时器1

1.2配置串口工作方式为方式1,只收不发

1.2.1手册介绍

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

1.2.2使用用代码实现
依据上图可以这样配
  8 4 2 1   8 4 2 1
  0 1 0 0   0 0 0 0
=           0 x 4 0
也就是除了SM1(bit6)等于1,其他都为0;
故:SCON = 0x40;

1.3配置辅助寄存器,减少电磁辐射,稳定晶振频率

1.3.1手册介绍

在这里插入图片描述

1.3.2依据上面手册可以直接写出代码
AUXR = 0x01;

1.4设置定时器工作方式为定时器1的8位自动重装

1.4.1手册介绍

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

1.4.2依据上面手册配置代码
使用的寄存器为 TMOD定时器/计数器工作模式寄存器
TMOD = 8 4 2 1   8 4 2 1
       0 0 1 0   * * * *
    =            0 x 2 *
采用 '&=' '|='运算实现高位清零,低位不变,高位置2,低位不变
若 TMOD = 0xFF;
先高位清零
TMOD = 8 4 2 1   8 4 2 1
       1 1 1 1   1 1 1 1
    &= 0 0 0 0   1 1 1 1
    &=           0 x 0 F
     = 0 0 0 0   1 1 1 1
再高位置2
TMOD = 8 4 2 1   8 4 2 1
       0 0 0 0   1 1 1 1
    |= 0 0 1 0   0 0 0 0
    |=           0 x 2 0
     = 0 0 1 0   0 0 0 0
故代码为
TMOD &= 0x0F;
TMOD |= 0x20;

1.5设置串口波特率为9600,0误差

1.5.1手册内容

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

1.5.2计算过程

在这里插入图片描述

1.5.3 计算后的代码
TH1   = 0xFD;
TL1   = 0xFD;

1.6打开定时器1

1.6.1手册内容


在这里插入图片描述

1.6.2依据上面手册可以直接写出代码
TR1   = 1;

1.7完整程序代码

void UartInit(void)		//自己配
{
	//配置串口工作方式为方式1,只发不收
	SCON =  0x40;
  //配置辅助寄存器,减少电磁辐射,稳定晶振频率  
	AUXR =  0x01;
	//设置定时器工作方式为定时器1的8位自动重装
	TMOD &= 0x0F;
	TMOD |= 0x20;
	//设置串口波特率为9600,0误差
	TH1   = 0xFD;
	TL1   = 0xFD;
	//打开定时器1
	TR1   = 1;

2串口编程02_发送字符串

2.1实现串口发送字符串的核心思路

  • 构建发送一个字节函数
  • 运用指针构建发送字符串函数
  • 主函数中每个一秒调用发送字符串函数

2.2构建发送一个字节函数

  • 定义一个空类型的名为发送字节的函数,形参为字符型的数据ms
  • 让SBUF等于数据ms

  注意:这里会出现如下图问题

  出现问题的原因是移位寄存器工作需要时间,由于单片机执行代码速度很快,导致乱序

  手册中移位寄存器示意图

在这里插入图片描述

  解决办法为:在函数中添加延时函数,延时10ms

  延时函数如下

void Delay10ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 18;
	j = 235;
	do
	{
		while (--j);
	} while (--i);
}

  这时又会出现如下图问题:
在这里插入图片描述

  解决办法为:需要注意发送中断TI,故用while(!TI);等待,后接语句TI = 0;软件置零,这里必须软件置零,不然会出现乱序

  手册中对TI的介绍

在这里插入图片描述

  • 添加while(!TI)等待和TI=0;软件置零

  • 函数代码

void sendByte(char data_mas)
{
    SBUF = data_mas;
    while(!TI);
    TI   = 0;
}

2.3运用指针构建发送字符串函数

  • 定义一个空类型名为发送字符串的函数,形参为字符型指针变量str

  • 利用while循环来反复调用发送字节函数,循环条件为*str不等于\0,\0为字符串结束标志

  • while循环内调用sendByte函数,实参为*str,然后指针偏移。str++

  • 函数代码

void sendString(char *str)
{
	while(*str != '\0')
	{
		sendByte(*str);
		str++;
	}
}

2.4主函数中每个一秒调用发送字符串函数

while(1)
{
    Delay1000ms();		
    sendString("Hello Word\r\n");  //\r\n 为串口中的换行,缺一不可
}

2.5完整程序代码

#include "reg52.h"

sfr AUXR = 0x8e; //声明AUXR寄存器地址

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void UartInit(void)		//自己配
{
	//配置串口工作方式为方式1,只发不收
	SCON =  0x40;
  //配置辅助寄存器,减少电磁辐射,稳定晶振频率  
	AUXR =  0x01;
	//设置定时器工作方式为定时器1的8位自动重装
	TMOD &= 0x0F;
	TMOD |= 0x20;
	//设置串口波特率为9600,0误差
	TH1   = 0xFD;
	TL1   = 0xFD;
	//打开定时器1
	TR1   = 1;
}

/*void Delay10ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 18;
	j = 235;
	do
	{
		while (--j);
	} while (--i);
}
*/

void sendByte(char data_mas)
{
	SBUF = data_mas;
//  Delay10ms();     延时的原因是移位寄存器工作需要时间 
//上述延时虽然解决了乱序问题,但是是一个字母一个字母的发送,解决这个问题需要注意发送中断TI,故用while()等待
	while(!TI);
	TI = 0;          //一定要软件置零,不然会出现乱序
}

void sendString(char *str)
{
	while(*str != '\0')
	{
		sendByte(*str);
		str++;
	}
}

void main()
{
	
	//初始化串口,配置波特率
	UartInit();
	
	//每延时1秒向电脑发送数据a
	while(1)
	{
		Delay1000ms();		
		sendString("Hello Word\r\n");  //\r\n 为串口中的换行,缺一不可
	}
} 

2.5特别注意在串口中,\r\n为换行符

2.6串口发送字符串可以发送中文,只需要将双引号内添加中文即可

3.串口编程03_PC发送指令控制LED

3.1实现PC发送指令控制LED的核心思路

  • 配置SCON串行控制寄存器REN(bit4)位

  • 看手册确定串口接收标志

  • 使用查询法来判断是否开灯

  • 建立接收电脑开关灯的指令变量

  • 声明LED1并初始化

  • 把SUBF赋给接收电脑开关灯的指令变量实现接收数据

3.2配置SCON串行控制寄存器REN(bit4)位

  • 手册内容
    在这里插入图片描述
    在这里插入图片描述

  • 代码配置

在串口初始化函数中,配的是只发不收,现在要配成能收能发
SCON = 8 4 2 1   8 4 2 1
       0 1 0 0   0 0 0 0
       0 1 0 1   0 0 0 0
     =           0 x 5 0
SCON = 0x50;

3.3看手册确定串口接收标志

  • 手册内容

  • 接收标志为 RI = 1;

3.4使用查询法来判断是否开灯

  • 查询法即if语句的使用
if(RI == 1)
{
    RI = 0;     //必须软件置零
    LEDStatus = SBUF;
    if(LEDStatus == 'o') //o代表打开
    {
        LED1 = 0;
    }
    if(LEDStatus == 'c') //c代表关闭
    {
        LED1 = 1;
    }
}

3.5建立接收电脑开关灯的指令变量

char LEDStatus;

3.6声明LED1并初始化

sbit LED1 = P3^7;  //使用位定义声明LED1
主函数中初始化
LED1 = 1;          //关灯

3.7把SUBF赋给接收电脑开关灯的指令变量实现接收数据

LEDStatus = SBUF;

3.8完整程序代码

#include "reg52.h"

sfr AUXR = 0x8e;   //声明AUXR寄存器地址
sbit LED1 = P3^7;  //使用位定义声明LED1

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void UartInit(void)		//自己配
{
	//配置串口工作方式为方式1,从只收不发改为能收能发
	SCON =  0x50;
  //配置辅助寄存器,减少电磁辐射,稳定晶振频率  
	AUXR =  0x01;
	//设置定时器工作方式为定时器1的8位自动重装
	TMOD &= 0x0F;
	TMOD |= 0x20;
	//设置串口波特率为9600,0误差
	TH1   = 0xFD;
	TL1   = 0xFD;
	//打开定时器1
	TR1   = 1;
}

void sendByte(char data_mas)
{
	SBUF = data_mas;
	while(!TI);
	TI = 0;          //一定要软件置零,不然会出现乱序
}

void sendString(char *str)
{
	while(*str != '\0')
	{
		sendByte(*str);
		str++;
	}
}

void main()
{
	//建立接收电脑开关灯的指令变量
	char LEDStatus;
	//初始化灯的状态
	LED1 = 1;
	//初始化串口,配置波特率
	UartInit();
	
	//每延时1秒向电脑发送数据a
	while(1)
	{
		Delay1000ms();		
		sendString("一起来学串口通信!!!\r\n");  //\r\n 为串口中的换行,缺一不可
		//怎么知道PC发了数据:由手册可知RI位为接受中断标志位,所以用查询的方法来判断RI是否等于1来开关灯
		if(RI == 1)
		{
			RI = 0;     //必须软件置零
			LEDStatus = SBUF;
			if(LEDStatus == 'o')
			{
				LED1 = 0;
			}
			if(LEDStatus == 'c')
			{
				LED1 = 1;
			}
		}
	}
} 

4.串口编程04_串口中断控制LED

4.1实现串口中断控制LED的核心思路

  • 查阅手册,确定串口中断函数的中断号,了解中断寒函数的作用域
  • 查阅手册,确定使用串口中断需要配置的寄存器

4.2查阅手册,确定串口中断函数的中断号,了解中断寒函数的作用域

  • 手册内容
    在这里插入图片描述
    在这里插入图片描述

  • 确定中断号为interrupt 4

  • 根据手册所提供的信息,并没有说明中断函数的作用域,故中断函数的作用域为收发中断都能执行

4.3查阅手册,确定使用串口中断需要配置的寄存器

  • 手册内容

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

  • 根据手册可知,在串口初始化函数中的配置代码为
//打开总中断
EA = 1;
//打开串口中断
ES = 1;

4.3串口中断函数执行的操作

  • 执行RI接收中断标志
  • 执行软件置零RI
  • 执行开关灯
  • 接收电脑开关灯的指令变量char LEDStatus定义为全局变量
  • 代码为
void UART_handler() interrupt 4
{
	//在串口中段函数中可以对发送接收中断标志进行处理
	if(RI == 1)
		{
			RI = 0;     //必须软件置零
			LEDStatus = SBUF;
			if(LEDStatus == 'o')
			{
				LED1 = 0;
			}
			if(LEDStatus == 'c')
			{
				LED1 = 1;
			}
		}
		
	
	if(TI);
		
}

4.4 特别注意要把主函数中的RI位为接收中断标志位的操作代码删除

4.5完整程序代码

#include "reg52.h"

sfr AUXR = 0x8e;   //声明AUXR寄存器地址
sbit LED1 = P3^7;  //使用位定义声明LED1

//建立接收电脑开关灯的指令变量
char LEDStatus;

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void UartInit(void)		//自己配
{
	//配置串口工作方式为方式1,从只收不发改为能收能发
	SCON =  0x50;
  //配置辅助寄存器,减少电磁辐射,稳定晶振频率  
	AUXR =  0x01;
	//设置定时器工作方式为定时器1的8位自动重装
	TMOD &= 0x0F;
	TMOD |= 0x20;
	//设置串口波特率为9600,0误差
	TH1   = 0xFD;
	TL1   = 0xFD;
	//打开定时器1
	TR1   = 1;
	//打开总中断
	EA = 1;
	//打开串口中断
	ES = 1;
}

void sendByte(char data_mas)
{
	SBUF = data_mas;
	while(!TI);
	TI = 0;          //一定要软件置零,不然会出现乱序
}

void sendString(char *str)
{
	while(*str != '\0')
	{
		sendByte(*str);
		str++;
	}
}

void main()
{
	//初始化灯的状态
	LED1 = 1;
	//初始化串口,配置波特率
	UartInit();
	
	//每延时1秒向电脑发送数据a
	while(1)
	{
		Delay1000ms();		
		sendString("一起来学串口通信!!!\r\n");  //\r\n 为串口中的换行,缺一不可
		//怎么知道PC发了数据:由手册可知RI位为接收中断标志位,所以用查询的方法来判断RI是否等于1来开关灯
	}
} 

void UART_handler() interrupt 4
{
	//在串口中段函数中可以对发送接收中断标志进行处理
	if(RI == 1)
		{
			RI = 0;     //必须软件置零
			LEDStatus = SBUF;
			if(LEDStatus == 'o')
			{
				LED1 = 0;
			}
			if(LEDStatus == 'c')
			{
				LED1 = 1;
			}
		}
		
	
	if(TI);
		
}

结束语

  很高兴您能看到这里,点个赞再走呗。谢谢您啦!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值