一、前言
06 蓝桥杯单片机设计与开发_基础模块_PWM-CSDN博客,承接上文,本文将继续介绍剩余蓝桥杯涉及模块(串口通信、NE555以及超声波测距),为大家做出详细编程指导。
二、串口通信
串口通信是一种用于在计算机系统和外部设备之间传输数据的通信方式。它通过串行传输数据,也就是按照一个位接一个位的顺序进行传输。
1、串口通信原理剖析
本文将编写程序,实现单片机串口接收数据,并根据接收的不同数据回传不同数据。如:(此功能为某届蓝桥杯比赛题目)
- 若接收到
ST
,则回传 dat1 和 dat2 数据; - 若接受到
PARA
,则回传 dat3 和 dat4 数据; - 若接受到其他数据,则回传
ERROR
。
具体实现思路:使用单片机上的串口1不断接收串口数据,若接收到则判断接收的数据类型,回传对应形式的数据。
2、核心代码
串口初始化函数 可借助 STC-ISP 软件生成,选择 波特率计算器
,配置好所需参数,如 串口1 、 8位自动重载,即可自动生成串口初始化程序。只需在后面补上 ES = 1, EA = 1
,允许访问内部RAM和打开总中断。
// 串口1初始化函数,8位自动重装
void UartInit(void) //4800bps@12.000MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器1时钟为Fosc,即1T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xB2; //设定定时初值
TH1 = 0xB2; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
ES = 1; // 允许外部总线访问内部RAM
EA = 1; // 打开总中断
}
串口发送函数 也很简单,只需要将发送内容存入 SBUF 缓冲区,然后等待发送(通过 TI
标志实现,若发送结束,TI
将置1,故将跳出 while 循环。
//发送数据函数
void Uart_send(u8 *str)
{
u8 *s;
s = str;
// 遍历待发送的字符串
while(*s != '\0')
{
SBUF = *s; // 发送内容存入 SBUF 缓冲区
while(!TI); // 等待发送,发送结束 TI = 1 跳出循环
TI = 0; // 清除 TI 标志
s++; // 指向下一位
}
}
串口接收函数 接收数据函数只需判断 RI
标志是否为1,若为1,即可从 SBUF
缓冲区中读取接收到的数据。
// 串口中断服务函数
void Uart() interrupt 4
{
// 接收到谁
if(RI)
{
RI = 0; // 标志清零
Uart_rec[Uart_count++] = SBUF; // 将接收数据存入 Uart_rec 数组,并将 Uart_count 统计接收个数+1
}
}
3、整体代码
由于考虑初学者基础较为薄弱,因此将完整的 main.cpp 代码贴出来,包含中断函数、矩阵键盘、数码管显示等,并且在关键处进行了注释,希望对大家有所帮助。
// 包含头文件
#include "STC15F2K60S2.h"
#include "stdio.h"
// 数据类型定义
#define u8 unsigned char
#define u16 unsigned int
u8 Uart_rec[10] = "",Uart_out[15] = "",Uart_count = 0; // 串口接收数组、串口发送数组、串口接收个数
u8 dat_1 = 20,dat_3 = 35,dat_4 = 30; // 整形发送数据
float dat_2 = 24.32; // 浮点型发送数据
//串口1、8位自动重装
void UartInit(void) //4800bps@12.000MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器1时钟为Fosc,即1T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xB2; //设定定时初值
TH1 = 0xB2; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
ES = 1;
EA = 1;
}
//发送数据函数
void Uart_send(u8 *str)
{
u8 *s;
s = str;
// 遍历待发送的字符串
while(*s != '\0')
{
SBUF = *s; // 发送内容存入 SBUF 缓冲区
while(!TI); // 等待发送,发送结束 TI = 1 跳出循环
TI = 0; // 清除 TI 标志
s++; // 指向下一位
}
}
// 串口处理函数
void Uart_pro()
{
if(Uart_count > 0)
{
if(Uart_rec[Uart_count-1] == '\n')
{
// 根据接收数据类型,为发送数组 Uart_out 赋不同值
if((Uart_rec[0]=='S') && (Uart_rec[1]=='T')) // ST
sprintf(Uart_out, "$%02u,%04.2f\r\n",(unsigned int)dat_1,(float)dat_2); // 注意 sprintf 传送的是int型数据,要用unsigned int
else if((Uart_rec[0]=='P') && (Uart_rec[1]=='A') && (Uart_rec[2]=='R') && (Uart_rec[3]=='A')) // PARA
sprintf(Uart_out, "#%02u,%02u\r\n",(unsigned int)dat_3, (unsigned int)dat_4);
else
sprintf(Uart_out, "ERROR\r\n"); // 同时有"\r\n"才能换行
// 发送数据
Uart_send(Uart_out);
Uart_count = 0; // 清空接收个数
}
}
}
void main()
{
// 串口初始化
UartInit();
while(1)
{
// 串口处理函数
Uart_pro();
}
}
// 串口中断服务函数
void Uart() interrupt 4
{
// 接收到谁
if(RI)
{
RI = 0; // 标志清零
Uart_rec[Uart_count++] = SBUF; // 将接收数据存入 Uart_rec 数组,并将 Uart_count 统计接收个数+1
}
}
至此,本次 串口通信 已介绍完毕。