0

0

0

修罗

站点介绍

只有了解事实才能获得真正的自由

UART(四)发送多字节命令

修罗 2025-08-04 45 0条评论 51单片机

首页 / 正文

UART(四)发送多字节命令

1.1 具体要求

  1. 当PC向单片机发送字符串turn on时,单片机需要令LED亮起,并向PC回复:OK: LED turned on\r\n
  2. 当PC向单片机发送字符串off时,单片机需要令LED熄灭,并向PC回复:OK: LED turned off\r\n
  3. 当PC向单片机发送其他字符串时,单片机不做任何操作,只需向PC回复:Error:Unknown command

1.2 实现方式1

特定结束符判断是否接收完毕数据,如回车符:

  1. 定义接收缓冲区和接收到的数据索引以及是否接收完毕的变量:
u8 buffer_str[32]; // 接收缓冲区
u8 buffer_str_len = 0;
bit recv_line_ready;
  1. 中断函数, 接收到\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. 外界循环调用一个函数判断是否接收完毕的变量置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; // 没有接收到完整的字符串
    }
    
}
  1. 外界循环调用,收到完整字符串后判断是否为需要的内容,并做相应的处理逻辑:
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");
        }
    }
}

image-20250804104637418.png

完整代码

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");
            }
        }
    }
}

评论(0)


最新评论

  • 1

    1

  • 1

    1

  • -1' OR 2+158-158-1=0+0+0+1 or 'TKCTZnRa'='

    1

  • 1

    1

  • 1

    1

  • 1

    1

  • 1

    1

  • @@5Qa2D

    1

  • 1

    1

  • 1

    1

日历

2025年09月

 123456
78910111213
14151617181920
21222324252627
282930    

文章目录

推荐关键字: Linux webpack js 算法 MongoDB laravel JAVA jquery javase redis