本篇博文介绍的是用51单片机的串口通信【中】,包含串口编程01_自己实现串口初识化,串口编程02_发送字符串,串口编程03_PC发送指令控制LED,串口编程04_串口中断控制LED。看到这篇博文的朋友,可以先赞再看吗?
一、数学分数计算。
二、数字电子时序图
三、数字电子中与或运算
四、计算机中的进制转换
五、C变量
六、基本输入输出
七、流程控制
八、函数
九、指针
十,字符串
如果以上知识不清楚,请自行学习后再来浏览。如果我有没例出的,请在评论区写一下。谢谢啦!
配置串口工作方式为方式1,只收不发
配置辅助寄存器,减少电磁辐射,稳定晶振频率
设置定时器工作方式为定时器1的8位自动重装
设置串口波特率为9600,0误差
打开定时器1
依据上图可以这样配
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;
AUXR = 0x01;
使用的寄存器为 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;
TH1 = 0xFD;
TL1 = 0xFD;
TR1 = 1;
void UartInit(void) //自己配
{
//配置串口工作方式为方式1,只发不收
SCON = 0x40;
//配置辅助寄存器,减少电磁辐射,稳定晶振频率
AUXR = 0x01;
//设置定时器工作方式为定时器1的8位自动重装
TMOD &= 0x0F;
TMOD |= 0x20;
//设置串口波特率为9600,0误差
TH1 = 0xFD;
TL1 = 0xFD;
//打开定时器1
TR1 = 1;
构建发送一个字节函数
运用指针构建发送字符串函数
主函数中每个一秒调用发送字符串函数
注意:这里会出现如下图问题
出现问题的原因是:移位寄存器工作需要时间,由于单片机执行代码速度很快,导致乱序
手册中移位寄存器示意图
解决办法为:在函数中添加延时函数,延时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;
}
定义一个空类型名为发送字符串的函数,形参为字符型指针变量str
利用while循环来反复调用发送字节函数,循环条件为*str不等于\0,\0为字符串结束标志
while循环内调用sendByte函数,实参为*str,然后指针偏移。str++
函数代码
void sendString(char *str)
{
while(*str != '\0')
{
sendByte(*str);
str++;
}
}
while(1)
{
Delay1000ms();
sendString("Hello Word\r\n"); //\r\n 为串口中的换行,缺一不可
}
#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 为串口中的换行,缺一不可
}
}
特别注意在串口中,\r\n为换行符
串口发送字符串可以发送中文,只需要将双引号内添加中文即可
配置SCON串行控制寄存器REN(bit4)位
看手册确定串口接收标志
使用查询法来判断是否开灯
建立接收电脑开关灯的指令变量
声明LED1并初始化
把SUBF赋给接收电脑开关灯的指令变量实现接收数据
在串口初始化函数中,配的是只发不收,现在要配成能收能发
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;
RI = 1;
if(RI == 1)
{
RI = 0; //必须软件置零
LEDStatus = SBUF;
if(LEDStatus == 'o') //o代表打开
{
LED1 = 0;
}
if(LEDStatus == 'c') //c代表关闭
{
LED1 = 1;
}
}
char LEDStatus;
sbit LED1 = P3^7; //使用位定义声明LED1
主函数中初始化
LED1 = 1; //关灯
LEDStatus = SBUF;
#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;
}
}
}
}
查阅手册,确定串口中断函数的中断号,了解中断寒函数的作用域
查阅手册,确定使用串口中断需要配置的寄存器
//打开总中断
EA = 1;
//打开串口中断
ES = 1;
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);
}
特别注意要把主函数中的RI位为接收中断标志位的操作代码删除
#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);
}
很高兴您能看到这里,点个赞再走呗。谢谢您啦!!!