51单片机 | UART | 接收数据 | 判定字符串接收完毕

KDRNN6个月前 (08-28)编码146

实现思路:
每接收一个字符,重置定时器,若定时器达到设定值则判定为字符串完整接收。


实现过程:

定义一个变量记录空闲时间,

static unsigned char s_idle_count = 0;

现阶段思路:每毫秒加一,每收到一个字符置零。


定义定时器0回调:

void Dri_UART_Timer0Callback()
{
    s_idle_count++;
}


在初始化函数Dri_UART_Init中注册空闲检测函数:

Dri_Timer0_RegisterCallback(Dri_UART_Timer0Callback);

此时s_idle_count每毫秒加一。


每收到一个新字符,重新计时(重置s_idle_count),

在串口中断中重置:

void Dri_UART_Handler() interrupt 4
{
  if(RI == 1) {
    s_idle_count = 0;
    RI = 0;
  }
}

判断:当s_idle_count > 10时处理逻辑,


定义数组用于接收SBUF:

static char idata s_buffer[16];

(最长16字符)

定义索引:

static unsigned char s_index;


修改串口中断逻辑,给s_buffer的索引位赋值并自增索引位:

void Dri_UART_Handler() interrupt 4
{
  if(RI == 1) {
    s_buffer[s_index++] = SBUF;
    RI = 0;
  }
}


修改Dri_UART_Timer0Callback(),判断空闲时间大于十毫秒,同时数组应不为空(s_index不为0):

s_idle_count++;
if (s_index > 0 && s_idle_count >=10)
{
    //数据处理逻辑
}

需要ReceiveString方法,在main中重复调用ReceiveString函数,

如果字符串接收完毕,函数返回1,将s_buffer内容赋给字符串,否则返回0。


判断是否接收完毕,定义标志位并赋初始值:

static bit s_is_complete = 0;

完善空闲计时方法,一旦接收完毕,标志位置1,

void Dri_UART_Timer0Callback()
{
  s_idle_count++;
  if (s_index > 0 && s_idle_count >= 10)
  {
    s_is_complete = 1;
  }
}

定义方法,将s_buffer数组内容赋给str,

并将标志位和索引清零:

bit Dri_UART_ReceiveString(char *str)
{
  if (s_is_complete == 1)
  {
    for (i = 0; i < s_index; i++)
    {
      str[i] = s_buffer[i];
    }
    s_is_complete = 0;
    s_index = 0;
    return 1;
  }
  return 0;
}


在main.c中:

#include <STRING.H>

声明数组:

unsigned char idata str[16];

初始化定时器和串口:

Dri_Timer0_Init();
Dri_UART_Init();

(先初始化定时器以设置NULL,否则无法正常注册)


使用STRING.H的strcmp比较字符串:

strcmp(str,"on") == 0

main方法:

void main()
{
  unsigned char idata str[16];
  Dri_Timer0_Init();
  Dri_UART_Init();
  while(1)
  {
    if (Dri_UART_ReceiveString(str))
    {
      if (strcmp(str,"on"))
      {
        P00 = ~P00;
        Dri_UART_SendString("LED1 IS ON");
      } else if (strcmp(str,"off")) {
        P01 = ~P01;
        Dri_UART_SendString("LED2 IS ON");
      } else {
        Dri_UART_SendString("UNKNOWN COMMAND")
      }
    }
  }
}


此时应可以正常接收命令,但若上一条命令长于本条,则无法正确识别,

原因:

短命令无法完全覆写长命令,而strcmp检测"\0",故将无法检测正确内容

解决方式:

  1. 每次接受命令后后清空str[]数组

  2. 每次收到完整字符串,在最后一个字符后加"\0"


方式2的实现:

修改Dri_UART_ReceiveString方法,在for循环后于i位设'\0':

bit Dri_UART_ReceiveString(char *str)
{
    if (s_is_complete == 1)
  {
    for (i = 0; i < s_index; i++)
    {
      str[i] = s_buffer[i];
    }
    str[i] = '\0';
    s_is_complete = 0;
    s_index = 0;
    return 1;
  }
  return 0;
}


    相关文章

    51单片机 | IIC | 软件模拟 | 基础驱动

    在Dri_IIC中先定义SCL和SDA:#define SCL P17 #define SDA P161.初始化/开始信号当SCL高电平时,SDA由高电平变为…

    发表评论

    访客

    ◎欢迎参与讨论,请在这里发表您的看法和观点。