什么可以用手机蓝牙控制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);
}
结束语
很高兴您能看到这里,点个赞再走呗。谢谢您啦!!!