UART(四)发送多字节命令
1.1 具体要求
- 当PC向单片机发送字符串turn on时,单片机需要令LED亮起,并向PC回复:OK: LED turned on\r\n
- 当PC向单片机发送字符串off时,单片机需要令LED熄灭,并向PC回复:OK: LED turned off\r\n
- 当PC向单片机发送其他字符串时,单片机不做任何操作,只需向PC回复:Error:Unknown command
1.2 实现方式1
特定结束符判断是否接收完毕数据,如回车符:
- 定义接收缓冲区和接收到的数据索引以及是否接收完毕的变量:
u8 buffer_str[32]; // 接收缓冲区
u8 buffer_str_len = 0;
bit recv_line_ready;
- 中断函数, 接收到
\r
时将是否接收完毕的变量
置1
void Dri_UART_Func() interrupt 4
{
// 收到命令,将数据放入缓冲区
if (RI == 1) {
unsigned char ch = SBUF;
// 避免数组越界
if (buffer_str_len < sizeof(buffer_str) - 1) {
if (ch == '\r') {
recv_line_ready = 1;
// 不处理'\n'
} else if (ch != '\n') {
buffer_str[buffer_str_len++] = ch;
}
}
RI = 0;
}
...
}
- 外界循环调用一个函数判断
是否接收完毕的变量
置1情况,外界提供数组,函数内部将接收到的数组内容循环赋值给外部数组:
bit Dri_UART_RecvStr(char *str)
{
if(recv_line_ready == 1){
u8 i = 0;
while (i < buffer_str_len) {
str[i] = buffer_str[i];
i++;
}
str[i] = '\0';
buffer_str_len = 0; // 清空缓冲区
recv_line_ready = 0; // 重置接收状态
return 1;
}else {
return 0; // 没有接收到完整的字符串
}
}
- 外界循环调用,收到完整字符串后判断是否为需要的内容,并做相应的处理逻辑:
while (1) {
if(Dri_UART_RecvStr(buffer_strs) == 1){
if (strcmp(buffer_strs, "turn on") == 0) {
Dri_UART_SendStr("OK: LED turned on\r\n");
} else if (strcmp(buffer_strs, "off") == 0) {
Dri_UART_SendStr("OK: LED turned off\r\n");
} else {
Dri_UART_SendStr("ERROR: Unknown command\r\n");
}
}
}
完整代码
Dri_UART.h
#ifndef __DRI_UART_H__
#define __DRI_UART_H__
#include <STC89C5xRC.H>
#include "Util.h"
void Dri_UART_Init();
void Dri_UART_Func();
void Dri_UART_SendChar(char str);
void Dri_UART_SendStr(char *str);
bit Dri_UART_RecvStr(char *str);
#endif
Dri_UART.c
#include "Dri_UART.h"
u8 buffer_str[32]; // 接收缓冲区
u8 buffer_str_len = 0;
bit recv_line_ready;
// 发送状态,1:正在发送,0:未在发送
static bit is_sending;
void Dri_UART_Init()
{
// 1.设置串口工作模式
SM0 = 0;
SM1 = 1;
// 2.设置波特率
// 2.1 设置SMOD控制位
PCON &= ~0x80;
// 2.2设置定时器1工作模式
TMOD &= 0x0F;
TMOD |= 0x20;
// 2.3 设置定时器1初值
TH1 = 0xFD;
TL1 = 0xFD;
// 2.4 启动定时器1
TR1 = 1;
// 3.串口接收相关配置
REN = 1;
SM2 = 0;
// 打开中断总开关和串口中断开关
EA = 1;
ES = 1;
TI = 0;
RI = 0;
is_sending = 0;
}
void Dri_UART_SendChar(char ch)
{
// 如果有数据在发送,等待发送完成
while (is_sending);
is_sending = 1;
SBUF = ch;
}
void Dri_UART_SendStr(char *str)
{
while (*str) {
Dri_UART_SendChar(*str);
str++;
}
}
bit Dri_UART_RecvStr(char *str)
{
if(recv_line_ready == 1){
u8 i = 0;
while (i < buffer_str_len) {
str[i] = buffer_str[i];
i++;
}
str[i] = '\0';
buffer_str_len = 0; // 清空缓冲区
recv_line_ready = 0; // 重置接收状态
return 1;
}else {
return 0; // 没有接收到完整的字符串
}
}
/**
* @brief 串口中断函数,进入这个函数有两个触发条件:发送完成和接收完成
*
*/
void Dri_UART_Func() interrupt 4
{
// 收到命令,将数据放入缓冲区
if (RI == 1) {
unsigned char ch = SBUF;
if (buffer_str_len < sizeof(buffer_str) - 1) {
if (ch == '\r') {
recv_line_ready = 1;
} else if (ch != '\n') {
buffer_str[buffer_str_len++] = ch;
}
}
RI = 0;
}
// 发送完成,将发送状态置为0
if (TI == 1) {
is_sending = 0;
TI = 0; // 清除发送中断标志
}
}
main.c
#include "Dri_Timer0.h"
#include "Dri_UART.h"
#include <STRING.H>
#define BUZZ P46
#define LED P00
#define LED_OPEN P34
void Int_Buzzer_Buzz()
{
unsigned char counter = 50;
// 500Hz的方波
while (counter) {
BUZZ = ~BUZZ;
Delay_1MS(1);
--counter;
}
}
void main()
{
u8 i = 0;
u8 buffer_strs[32];
BUZZ = 1; // 打开蜂鸣器
LED_OPEN = 1;
Dri_UART_Init();
while (1) {
if(Dri_UART_RecvStr(buffer_strs) == 1){
if (strcmp(buffer_strs, "turn on") == 0) {
// 点亮LED
P0 = 0x00;
Dri_UART_SendStr("OK: LED turned on\r\n");
} else if (strcmp(buffer_strs, "off") == 0) {
// 熄灭LED
P0 = 0xFF;
Dri_UART_SendStr("OK: LED turned off\r\n");
} else {
Dri_UART_SendStr("ERROR: Unknown command\r\n");
}
// 蜂鸣器响一声
Int_Buzzer_Buzz();
}
}
}
1.3 实现方式2
空闲超过特定时间就表示接收完毕,特点时间内接收数据,每收到一个字符开启新的计时;
Dri_UART.h
#ifndef __DRI_UART_H__
#define __DRI_UART_H__
#include <STC89C5xRC.H>
#include "Util.h"
/**
* @brief 串口初始化
*
*/
void Dri_UART_Init(void);
/**
* @brief 发送字符串
*
* @param str 待发送字符串
*/
void Dri_UART_SendStr(char *str);
/**
* @brief 接收字符串
*
* @param str 用于接收字符串的数组
* @return bit 0为读取失败,1为读取成功
*/
bit Dri_UART_ReceiveStr(char str[]);
#endif /* __DRI_UART_H__ */
Dri_UART.c
#include "Dri_UART.h"
#include "Dri_Timer0.h"
#define BAUD_RATE 9600
#define T2TEMP 256 - (FOSC / NT / 32 / BAUD_RATE)
#include <STDIO.H>
/ 0:未在发送 1:正在发送
static bit s_is_sending = 0;
static char s_buffer[10] = {0};
static u8 s_index = 0;
static bit s_is_complete = 0;
static u8 s_idle_count = 0;
void Dri_UART_Timer0Callback()
{
s_idle_count++;
if (s_index > 0 && s_idle_count >= 10) {
s_is_complete = 1;
s_idle_count = 0;
}
}
void Dri_UART_Init()
{
// 1.选择工作模式
SM0 = 0;
SM1 = 1;
// 2.波特率
// 2.1 SMOD
PCON &= 0x7F;
// 2.2 Timer1
// 2.2.1 工作模式
TMOD &= 0x0F;
TMOD |= 0x20;
// 2.2.2 初始值
TH1 = 0xFD;
TL1 = 0xFD;
// 2.2.3 开启
TR1 = 1;
// 3.接受相关
REN = 1;
SM2 = 0;
// 4. 中断相关
EA = 1;
ES = 1;
RI = 0;
TI = 0;
// 5. 注册空闲监测回调
Dri_Timer0_RegisterCallback(Dri_UART_Timer0Callback);
}
void Dri_UART_SendChar(char c)
{
while (s_is_sending == 1);
s_is_sending = 1;
SBUF = c;
}
void Dri_UART_SendStr(char *str)
{
while (*str != 0) {
Dri_UART_SendChar(*str);
str++;
}
}
bit Dri_UART_ReceiveStr(char *cmd)
{
u8 i;
if (s_is_complete) {
for (i = 0; i < s_index; i++) {
cmd[i] = s_buffer[i];
}
cmd[s_index] = '\0';
s_index = 0;
s_is_complete = 0;
return 1;
} else {
return 0;
}
}
void Dri_UART_Handler() interrupt 4
{
if (RI == 1) {
// 接收数据的逻辑
s_idle_count = 0;
s_buffer[s_index++] = SBUF;
RI = 0;
}
if (TI == 1) {
// 发送数据的逻辑
s_is_sending = 0;
TI = 0;
}
}
main.c
#include "Dri_UART.h"
#include <STRING.H>
void main()
{
char command[10] = {0};
Dri_UART_Init();
while (1) {
if (Dri_UART_ReceiveStr(command)) {
if (strcmp(command, "on") == 0) {
P0 = 0x00;
Dri_UART_SendStr("Ok:LED is on");
} else if (strcmp(command, "off") == 0) {
P0 = 0xFF;
Dri_UART_SendStr("Ok:LED is off");
} else {
Dri_UART_SendStr("Error:Unhnown command");
}
}
}
}
1
1
1
1
1
1
1
1
1
1