C51实现串口1环形FIFO无阻塞数据发送和接收 并解析自定义协议
2023-12-25 13:42:30
串口的发送和接收数据,采用查询法, 会阻塞代码的运行, 效率比较低, 采用环形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
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!