C51实现串口1环形FIFO无阻塞数据发送和接收 并解析自定义协议

发布时间:2023年12月25日

串口的发送和接收数据,采用查询法, 会阻塞代码的运行, 效率比较低, 采用环形FIFO来缓冲发送和接收的数据, 再配合中断自动发送和接收, 效率会提升极大, 能把波特率带宽跑满

1.实现FIFO结构

// FIFO环形缓冲队列
typedef struct FIFOBuffer {
  unsigned char headPos;    //缓冲区头部位置
  unsigned char tailPos;    //缓冲区尾部位置
  unsigned char bufferSize; // 缓冲区长度
  unsigned char *buffer;    //缓冲区数组
};

unsigned char FIFOBuffer_available(struct FIFOBuffer *fifo_buffer) {
  return fifo_buffer->headPos != fifo_buffer->tailPos;
}

void FIFOBuffer_flush(struct FIFOBuffer *fifo_buffer) {
  fifo_buffer->headPos = 0;
  fifo_buffer->tailPos = 0;
}

unsigned char FIFOBuffer_read(struct FIFOBuffer *fifo_buffer) {
  unsigned char buf = 0;
  //如果头尾接触表示缓冲区为空
  if (fifo_buffer->headPos != fifo_buffer->tailPos) {
    buf = fifo_buffer->buffer[fifo_buffer->headPos];
    if (++fifo_buffer->headPos >= fifo_buffer->bufferSize) {
      fifo_buffer->headPos = 0;
    }
  }
  return buf;
}

void FIFOBuffer_push(struct FIFOBuffer *fifo_buffer, unsigned char buf) {
  fifo_buffer->buffer[fifo_buffer->tailPos] = buf;         //从尾部追加
  if (++fifo_buffer->tailPos >= fifo_buffer->bufferSize) { //尾节点偏移
    fifo_buffer->tailPos = 0;
  }
  if (fifo_buffer->tailPos == fifo_buffer->headPos) {
    if (++fifo_buffer->headPos >= fifo_buffer->bufferSize) {
      fifo_buffer->headPos = 0;
    }
  }
}

2.实现串口中断发送和接收

#define UartReceiveSize 128
#define UartSendSize 128
uint8 uartReceiveBuffer[UartReceiveSize] = {0};
uint8 uartSendBuffer[UartSendSize] = {0};
struct FIFOBuffer uartReceiveFIFO;
struct FIFOBuffer uartSendFIFO;
uint8 isSend = 0;

void UART1_Isr(void) interrupt 4 {
  if (TI) {
    TI = 0;
    // 队列中还有数据, 继续发送
    if (uartSendFIFO.headPos != uartSendFIFO.tailPos) {
      SBUF = FIFOBuffer_read(&uartSendFIFO);
    } else {
      isSend = 0;
    }
  }
  if (RI) {
    RI = 0;
    // 接收到数据, 放入队列
    FIFOBuffer_push(&uartReceiveFIFO, SBUF);
  }
}
void uart1Write(uint8 dat) {
  FIFOBuffer_push(&uartSendFIFO, dat);
  if (isSend == 0) {
    isSend = 1;
    SBUF = FIFOBuffer_read(&uartSendFIFO);
  }
}
void uart1WriteBuf(uint8 *buffer, uint8 length) {
  uint8 i = 0;
  for (i = 0; i < length; i++) {
    FIFOBuffer_push(&uartSendFIFO, buffer[i]);
  }
  if (isSend == 0) {
    isSend = 1;
    SBUF = FIFOBuffer_read(&uartSendFIFO);
  }
}
void uart1WriteString(uint8 *str) {
  while (*str) {
    FIFOBuffer_push(&uartSendFIFO, *str++);
  }
  if (isSend == 0) {
    isSend = 1;
    SBUF = FIFOBuffer_read(&uartSendFIFO);
  }
}

3.自定义指令解析

// 检测命令格式 {Start1,Start2, data... ,len,End1,End2}
struct MyCommand {
  unsigned char Start1;
  unsigned char Start2;
  unsigned char End1;
  unsigned char End2;
  unsigned char isStart;
  unsigned char count;
  unsigned char bufferSize;
  unsigned char *buffer;

  // 检测命令格式 {Start1,Start2, data... ,len,End1,End2}
  void (*resolveCommandCallback)(unsigned char *buffer, unsigned char length);
};
#define UartCommandBufferSize 64
uint8 uartCommandBuffer[UartCommandBufferSize] = {0};
struct MyCommand uartCommand;

void MyCommand_addData(struct MyCommand *command, unsigned char tempData) {
  if (!command->isStart) {
    if (command->count == 0 && tempData != command->Start1) {
      return;
    }
    command->count++;
    if (command->count == 2) {
      if (command->Start2 == tempData) {
        command->isStart = true;
        command->count = 0;
      } else {
        command->count = 0;
        if (tempData == command->Start1) {
          command->count++;
        }
      }
    }
    if (command->count > 2) {
      command->count = 0;
      command->isStart = false;
    }
    return;
  }

  if (command->count >= command->bufferSize) {
    command->count = 0;
    command->isStart = false;
  }

  command->buffer[command->count] = tempData;
  command->count++;

  if (command->isStart && command->count >= 4) {
    // 检测结束
    if (tempData == command->End2 &&
        command->buffer[command->count - 2] == command->End1) {
      // 长度位
      if (command->buffer[command->count - 3] == command->count - 3) {
        if (command->resolveCommandCallback) {
          command->resolveCommandCallback(command->buffer, command->count - 3);
        }
        command->isStart = false;
        command->count = 0;
      }
    }
  }
}

4. 初始化结构体数据

void initUartCommand(void (*commandCallback)(uint8 *buffer, uint8 length)) {
  uartReceiveFIFO.headPos = 0;
  uartReceiveFIFO.tailPos = 0;
  uartReceiveFIFO.bufferSize = UartReceiveSize;
  uartReceiveFIFO.buffer = uartReceiveBuffer;

  uartSendFIFO.headPos = 0;
  uartSendFIFO.tailPos = 0;
  uartSendFIFO.bufferSize = UartSendSize;
  uartSendFIFO.buffer = uartSendBuffer;

  uartCommand.Start1 = 0xf0;
  uartCommand.Start2 = 0xf1;
  uartCommand.End1 = 0xe0;
  uartCommand.End2 = 0xe1;
  uartCommand.isStart = 0;
  uartCommand.count = 0;
  uartCommand.bufferSize = UartCommandBufferSize;
  uartCommand.buffer = uartCommandBuffer;
  uartCommand.resolveCommandCallback = commandCallback;
}

全部代码MyCommand.h


// FIFO环形缓冲队列
typedef struct FIFOBuffer {
  unsigned char headPos;    //缓冲区头部位置
  unsigned char tailPos;    //缓冲区尾部位置
  unsigned char bufferSize; // 缓冲区长度
  unsigned char *buffer;    //缓冲区数组
};

unsigned char FIFOBuffer_available(struct FIFOBuffer *fifo_buffer) {
  return fifo_buffer->headPos != fifo_buffer->tailPos;
}

void FIFOBuffer_flush(struct FIFOBuffer *fifo_buffer) {
  fifo_buffer->headPos = 0;
  fifo_buffer->tailPos = 0;
}

unsigned char FIFOBuffer_read(struct FIFOBuffer *fifo_buffer) {
  unsigned char buf = 0;
  //如果头尾接触表示缓冲区为空
  if (fifo_buffer->headPos != fifo_buffer->tailPos) {
    buf = fifo_buffer->buffer[fifo_buffer->headPos];
    if (++fifo_buffer->headPos >= fifo_buffer->bufferSize) {
      fifo_buffer->headPos = 0;
    }
  }
  return buf;
}

void FIFOBuffer_push(struct FIFOBuffer *fifo_buffer, unsigned char buf) {
  fifo_buffer->buffer[fifo_buffer->tailPos] = buf;         //从尾部追加
  if (++fifo_buffer->tailPos >= fifo_buffer->bufferSize) { //尾节点偏移
    fifo_buffer->tailPos = 0;
  }
  if (fifo_buffer->tailPos == fifo_buffer->headPos) {
    if (++fifo_buffer->headPos >= fifo_buffer->bufferSize) {
      fifo_buffer->headPos = 0;
    }
  }
}

// 检测命令格式 {Start1,Start2, data ,len,End1,End2}
struct MyCommand {
  unsigned char Start1;
  unsigned char Start2;
  unsigned char End1;
  unsigned char End2;
  unsigned char isStart;
  unsigned char count;
  unsigned char bufferSize;
  unsigned char *buffer;

  // 检测命令格式 {Start1,Start2, data... ,len,End1,End2}
  void (*resolveCommandCallback)(unsigned char *buffer, unsigned char length);
};
#define UartCommandBufferSize 64
uint8 uartCommandBuffer[UartCommandBufferSize] = {0};
struct MyCommand uartCommand;

void MyCommand_addData(struct MyCommand *command, unsigned char tempData) {
  if (!command->isStart) {
    if (command->count == 0 && tempData != command->Start1) {
      return;
    }
    command->count++;
    if (command->count == 2) {
      if (command->Start2 == tempData) {
        command->isStart = true;
        command->count = 0;
      } else {
        command->count = 0;
        if (tempData == command->Start1) {
          command->count++;
        }
      }
    }
    if (command->count > 2) {
      command->count = 0;
      command->isStart = false;
    }
    return;
  }

  if (command->count >= command->bufferSize) {
    command->count = 0;
    command->isStart = false;
  }

  command->buffer[command->count] = tempData;
  command->count++;

  if (command->isStart && command->count >= 4) {
    // 检测结束
    if (tempData == command->End2 &&
        command->buffer[command->count - 2] == command->End1) {
      // 长度位
      if (command->buffer[command->count - 3] == command->count - 3) {
        if (command->resolveCommandCallback) {
          command->resolveCommandCallback(command->buffer, command->count - 3);
        }
        command->isStart = false;
        command->count = 0;
      }
    }
  }
}

#define UartReceiveSize 128
#define UartSendSize 128
uint8 uartReceiveBuffer[UartReceiveSize] = {0};
uint8 uartSendBuffer[UartSendSize] = {0};
struct FIFOBuffer uartReceiveFIFO;
struct FIFOBuffer uartSendFIFO;
uint8 isSend = 0;

void UART1_Isr(void) interrupt 4 {
  if (TI) {
    TI = 0;
    // 队列中还有数据, 继续发送
    if (uartSendFIFO.headPos != uartSendFIFO.tailPos) {
      SBUF = FIFOBuffer_read(&uartSendFIFO);
    } else {
      isSend = 0;
    }
  }
  if (RI) {
    RI = 0;
    // 接收到数据, 放入队列
    FIFOBuffer_push(&uartReceiveFIFO, SBUF);
  }
}
void uart1Write(uint8 dat) {
  FIFOBuffer_push(&uartSendFIFO, dat);
  if (isSend == 0) {
    isSend = 1;
    SBUF = FIFOBuffer_read(&uartSendFIFO);
  }
}
void uart1WriteBuf(uint8 *buffer, uint8 length) {
  uint8 i = 0;
  for (i = 0; i < length; i++) {
    FIFOBuffer_push(&uartSendFIFO, buffer[i]);
  }
  if (isSend == 0) {
    isSend = 1;
    SBUF = FIFOBuffer_read(&uartSendFIFO);
  }
}
void uart1WriteString(uint8 *str) {
  while (*str) {
    FIFOBuffer_push(&uartSendFIFO, *str++);
  }
  if (isSend == 0) {
    isSend = 1;
    SBUF = FIFOBuffer_read(&uartSendFIFO);
  }
}

void initUartCommand(void (*commandCallback)(uint8 *buffer, uint8 length)) {
  uartReceiveFIFO.headPos = 0;
  uartReceiveFIFO.tailPos = 0;
  uartReceiveFIFO.bufferSize = UartReceiveSize;
  uartReceiveFIFO.buffer = uartReceiveBuffer;

  uartSendFIFO.headPos = 0;
  uartSendFIFO.tailPos = 0;
  uartSendFIFO.bufferSize = UartSendSize;
  uartSendFIFO.buffer = uartSendBuffer;

  uartCommand.Start1 = 0xf0;
  uartCommand.Start2 = 0xf1;
  uartCommand.End1 = 0xe0;
  uartCommand.End2 = 0xe1;
  uartCommand.isStart = 0;
  uartCommand.count = 0;
  uartCommand.bufferSize = UartCommandBufferSize;
  uartCommand.buffer = uartCommandBuffer;
  uartCommand.resolveCommandCallback = commandCallback;
}

5.使用demo, 运行芯片为stc32g8k64, 编译环境基于天问block工具, 关于JSTime.h看上篇上篇博客

#define IRC_24M
#define PLL_NO
#define boolean unsigned char
#define true 1
#define false 0
#define HIGH 1
#define LOW 0

#include <STC32G.h>
uint32 sys_clk = 24000000; // 设置PWM、定时器、串口、EEPROM频率参数
#include <stdio.h>
#include "lib/rcclock.h"
#include "lib/UART.h"
#include "lib/ADC.h"
#include "lib/delay.h"
#include "lib/eeprom.h"
#include "myLib/MyCommand.h"
#include "myLib/JSTime.h"

#define LED_PIN P2_1

uint32 loopCount = 0; // 程序循环次数
uint32 answerTimeoutId = 0;

// 编写一个方法计算字节的校验和
uint8 getCheckSum(uint8 *buffer, uint8 start, uint8 end)
{
  uint8 i = 0;
  uint8 sum = 0;
  for (i = start; i < end; i++)
  {
    sum += buffer[i];
  }
  return sum;
}

void answerOk()
{
  uint8 i = 0;
  uint8 cmdData[20] = {0};
  uint32 curTime = micros();
  cmdData[i++] = uartCommand.Start1;
  cmdData[i++] = uartCommand.Start2;
  cmdData[i++] = '0';
  cmdData[i++] = 'k';
  cmdData[i++] = i - 2;
  cmdData[i++] = uartCommand.End1;
  cmdData[i++] = uartCommand.End2;
  uart1WriteBuf(cmdData, i);
}

// 接收到指令回调
// 返回的buffer, 会去掉帧头f0 f1
void receiveUartDataCallback(uint8 *buffer, uint8 length)
{
  // 测试发送
  // f0 f1 01 02 00 00 05 e0 e1
  if (buffer[0] == 0x01 && buffer[1] == 0x02)
  {
    // 延时1000ms回复
    clearTime(answerTimeoutId);
    answerTimeoutId = setTimeout(answerOk, 1000);
  }
}

void sendDemo()
{
  uint8 i = 0;
  uint8 cmdData[20] = {0};
  uint32 curTime = micros();
  cmdData[i++] = uartCommand.Start1;
  cmdData[i++] = uartCommand.Start2;
  cmdData[i++] = 0x02;
  cmdData[i++] = 0x01;
  // loopCount
  cmdData[i++] = loopCount >> 24;
  cmdData[i++] = loopCount >> 16;
  cmdData[i++] = loopCount >> 8;
  cmdData[i++] = loopCount & 0x000000ff;
  // curTime
  cmdData[i++] = curTime >> 24;
  cmdData[i++] = curTime >> 16;
  cmdData[i++] = curTime >> 8;
  cmdData[i++] = curTime & 0x000000ff;

  cmdData[i++] = getCheckSum(cmdData, 2, i); // 校验和
  cmdData[i++] = i - 2;
  cmdData[i++] = uartCommand.End1;
  cmdData[i++] = uartCommand.End2;

  uart1WriteBuf(cmdData, i);
}

void mytask1()
{
  LED_PIN = !LED_PIN;
}

void mytask2()
{
  sendDemo();
}

void setup()
{
  rcclock_set_irc(1);
  P2M1 &= ~0x01;
  P2M0 |= 0x01; // 推挽输出
  P2M1 &= ~0x02;
  P2M0 |= 0x02; // 推挽输出
  P2M1 &= ~0x04;
  P2M0 |= 0x04; // 推挽输出
  P2M1 &= ~0x08;
  P2M0 |= 0x08; // 推挽输出
  P3M1 |= 0x04;
  P3M0 &= ~0x04;                                                 // P3.2 高阻输入
  uart_init(UART_1, UART1_RX_P30, UART1_TX_P31, 1000000, TIM_1); // 初始化串口
  JSTime_init();
  initUartCommand(receiveUartDataCallback);
  ES = 1; // 允许串行口中断
  EA = 1; // 允许总中断
  delay(200);
  setInterval(mytask1, 500);
  setInterval(mytask2, 1000);
}

void ispDowbload()
{
  if (P3_2 == LOW)
  {
    if (P3_2 == LOW)
    {
      IAP_CONTR = 0x60; // 进入ISP下载
    }
  }
}

void uartLoopRead()
{
  while (uartReceiveFIFO.headPos != uartReceiveFIFO.tailPos)
  {
    MyCommand_addData(&uartCommand, FIFOBuffer_read(&uartReceiveFIFO));
  }
}

void loop()
{
  JSTime_refresh();
  ispDowbload();
  uartLoopRead();
  loopCount++;
}

void main(void)
{
  setup();
  while (1)
  {
    loop();
  }
}

我就是做web前端开发的, 用javascript的思想来开发C51用来diy个小东西, 我发现专业人员是不乐意分享代码的, 那我就来分享, web前端是所有编程领域内最具分享精神的

文章来源:https://blog.csdn.net/cxgasd/article/details/135193668
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。