当前位置: 首页 > ai >正文

stc32单片机实现串口2M波特率满带宽传输

我需要实现已极高的速度用串口往上位机发送数据, 并且还不能占用mcu资源, 使用的单片机位stc32g8K64

我的方法是串口接收采用中断接收, 发送采用dma自动发送, 预先初始化16个64字节的缓冲区, 每次通过串口发送时, 先找到当前的空闲缓冲区, 然后往缓冲区里填充数据, 在dma传输完成一帧数据时释放缓冲区, 在主循环里检测是否有需要发送的数据, 然后调用dma自动发送

高速USB转串口采用AI8H2K12U实现的USB转串口, 以前采用ch340, ch343USB转串口, 在1M及以上波特率下通信会导致电脑偶尔蓝屏, 尤其是ch340, 1个小时左右电脑有很大的概率蓝屏, 我实锤就是USB转串口引起的, 用AI8H2K12U后就没出现过蓝屏的问题了

//========================================================================
// ---------------------- 串口发送接收部分 --------------------------------
//========================================================================
#define Uart1_ReceiveSize 128
#define Uart1_SendBufferSize 255
#define Uart1_SendDMABufferSize 64
#define Uart1_SendDMAGroupCount 16
#define Uart1_CommandBufferSize 255
uint8 Uart1_receiveBuffer[Uart1_ReceiveSize] = {0};
uint8 Uart1_sendGroupState[Uart1_SendDMAGroupCount] = {0}; // DMA空闲状态 0:空闲 1:等待发送 2:发送中
uint8 Uart1_sendGroupSize[Uart1_SendDMAGroupCount] = {0};  // DMA每组数据长度的数据长度, 最长255
uint8 Uart1_sendGroupOrder[Uart1_SendDMAGroupCount] = {0};
uint8 xdata Uart1_sendBuffer[Uart1_SendBufferSize] = {0};                                  // DMA按组发送顺序
uint8 xdata Uart1_sendDMABuffer[Uart1_SendDMAGroupCount][Uart1_SendDMABufferSize] = {{0}}; // DMA发送缓冲区
uint8 Uart1_commandBuffer[Uart1_CommandBufferSize] = {0};
uint8 UART1_isSend = 0;                // 是否正在发送数据
uint8 UART1_isDMASend = 0;             // 是否使用DMA发送
uint8 UART1_enable = 1;                // 是否启用串口
int8 Uart1_sendCurrentGroupIndex = -1; // 当前发送的组
uint32 UART1_sendCount = 0;            // 发送字节计数void UART1_sendData();// FIFO环形缓冲队列
typedef struct FIFOBuffer
{unsigned int headPos;    // 缓冲区头部位置unsigned int tailPos;    // 缓冲区尾部位置unsigned int bufferSize; // 缓冲区长度unsigned char *buffer;   // 缓冲区数组
};
struct FIFOBuffer uartReceiveFIFO;
struct FIFOBuffer uartSendFIFO;
struct FIFOBuffer uartSendGroupFIFO;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;
}#define FIFOBUFFER_PUSH(fifo, buf)               \do                                             \{                                              \(fifo).buffer[(fifo).tailPos] = (buf);       \if (++(fifo).tailPos >= (fifo).bufferSize)   \{                                            \(fifo).tailPos = 0;                        \}                                            \if ((fifo).tailPos == (fifo).headPos)        \{                                            \if (++(fifo).headPos >= (fifo).bufferSize) \{                                          \(fifo).headPos = 0;                      \}                                          \}                                            \} while (0)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...,dataLength,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...,dataLength,End1,End2}void (*resolveCommandCallback)(unsigned char *buffer, unsigned char length);
};
struct MyCommand uartCommand;unsigned char getCheckSum(unsigned char *buffer, unsigned int start, unsigned int end)
{unsigned int i = 0;unsigned char sum = 0;for (i = start; i < end; i++){sum += buffer[i];}return sum;
}
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;}}}
}
void UART1_Isr(void) interrupt 4
{if (TI){TI = 0;// 队列中还有数据, 继续发送if (uartSendFIFO.headPos != uartSendFIFO.tailPos){SBUF = FIFOBuffer_read(&uartSendFIFO);}else{UART1_isSend = 0;}}if (RI){RI = 0;// 接收到数据, 放入队列// FIFOBuffer_push(&uartReceiveFIFO, SBUF);FIFOBUFFER_PUSH(uartReceiveFIFO, SBUF);}
}
void UART1_initCommand(void (*commandCallback)(uint8 *buffer, uint8 length))
{ES = 1; // 允许串行口中断uartReceiveFIFO.headPos = 0;uartReceiveFIFO.tailPos = 0;uartReceiveFIFO.bufferSize = Uart1_ReceiveSize;uartReceiveFIFO.buffer = Uart1_receiveBuffer;uartSendFIFO.headPos = 0;uartSendFIFO.tailPos = 0;uartSendFIFO.bufferSize = Uart1_SendBufferSize;uartSendFIFO.buffer = Uart1_sendBuffer;// DMA按组发送uartSendGroupFIFO.headPos = 0;uartSendGroupFIFO.tailPos = 0;uartSendGroupFIFO.bufferSize = Uart1_SendDMAGroupCount;uartSendGroupFIFO.buffer = Uart1_sendGroupOrder;uartCommand.Start1 = 0xf2;uartCommand.Start2 = 0xf3;uartCommand.End1 = 0xe2;uartCommand.End2 = 0xe3;uartCommand.isStart = 0;uartCommand.count = 0;uartCommand.bufferSize = Uart1_CommandBufferSize;uartCommand.buffer = Uart1_commandBuffer;uartCommand.resolveCommandCallback = commandCallback;
}
uint8 UART1_getIdleGroupIndex()
{uint8 i = 0;for (i = 0; i < Uart1_SendDMAGroupCount; i++){if (Uart1_sendGroupState[i] == 0){return i;}}return -1;
}
void UART1_DMA_Config(uint8 groupIndex)
{UART1_sendCount++;DMA_UR1T_CFG = 0x80; // bit7 1:Enable InterruptDMA_UR1T_STA = 0x00;DMA_UR1T_AMT = Uart1_sendGroupSize[groupIndex] - 1;                     // 设置传输总字节数(低8位):n+1DMA_UR1T_AMTH = 0x00;                                                   // 设置传输总字节数(高8位):n+1DMA_UR1T_TXAH = (uint8)((uint16)&Uart1_sendDMABuffer[groupIndex] >> 8); // 缓冲区地址DMA_UR1T_TXAL = (uint8)((uint16)&Uart1_sendDMABuffer[groupIndex]);DMA_UR1T_CR = 0xc0; // bit7 1:使能 UART1_DMA, bit6 1:开始 UART1_DMA 自动发送
}
void UART1_writeBuffer(uint8 *buffer, uint8 length)
{uint8 i = 0;if (UART1_enable == 0){return;}for (i = 0; i < length; i++){FIFOBuffer_push(&uartSendFIFO, buffer[i]);}if (UART1_isSend == 0 && UART1_isDMASend == 0){UART1_isSend = 1;SBUF = FIFOBuffer_read(&uartSendFIFO);}
}
void UART1_writeBufferByDMA(uint8 groupIndex, uint8 length)
{if (UART1_enable == 0){return;}Uart1_sendGroupSize[groupIndex] = length;if (UART1_isSend == 0 && UART1_isDMASend == 0){UART1_isDMASend = 1;Uart1_sendCurrentGroupIndex = groupIndex;Uart1_sendGroupState[groupIndex] = 2;UART1_DMA_Config(groupIndex);}else{Uart1_sendGroupState[groupIndex] = 1;FIFOBuffer_push(&uartSendGroupFIFO, groupIndex);}
}
void UART1_DMA_Interrupt(void) interrupt 50
{if (DMA_UR1T_STA & 0x01) // 发送完成{DMA_UR1T_STA &= ~0x01;if (Uart1_sendCurrentGroupIndex > -1){Uart1_sendGroupState[Uart1_sendCurrentGroupIndex] = 0; // 发送完成, 设置空闲}UART1_isDMASend = 0;Uart1_sendCurrentGroupIndex = -1;// 继续发送下一帧数据if ((uartSendGroupFIFO.headPos != uartSendGroupFIFO.tailPos)){Uart1_sendCurrentGroupIndex = FIFOBuffer_read(&uartSendGroupFIFO);if (Uart1_sendGroupSize[Uart1_sendCurrentGroupIndex] > 0){UART1_isDMASend = 1;Uart1_sendGroupState[Uart1_sendCurrentGroupIndex] = 2;UART1_DMA_Config(Uart1_sendCurrentGroupIndex);}else{Uart1_sendGroupState[Uart1_sendCurrentGroupIndex] = 0;Uart1_sendCurrentGroupIndex = -1;UART1_isDMASend = 0;}}}if (DMA_UR1T_STA & 0x04) // 数据覆盖{DMA_UR1T_STA &= ~0x04;}
}
void UART1_sendData()
{if (UART1_enable == 0){return;}// 中断发送数据if (UART1_isSend == 0 && UART1_isDMASend == 0 && uartSendFIFO.headPos != uartSendFIFO.tailPos){UART1_isSend = 1;SBUF = FIFOBuffer_read(&uartSendFIFO);return;}// DMA发送数据while (UART1_isSend == 0 && UART1_isDMASend == 0 && (uartSendGroupFIFO.headPos != uartSendGroupFIFO.tailPos)){Uart1_sendCurrentGroupIndex = FIFOBuffer_read(&uartSendGroupFIFO);if (Uart1_sendGroupSize[Uart1_sendCurrentGroupIndex] > 0){UART1_isDMASend = 1;Uart1_sendGroupState[Uart1_sendCurrentGroupIndex] = 2;UART1_DMA_Config(Uart1_sendCurrentGroupIndex);break;}else{Uart1_sendGroupState[Uart1_sendCurrentGroupIndex] = 0;Uart1_sendCurrentGroupIndex = -1;UART1_isDMASend = 0;}}
}
//========================================================================
// ---------------------- 串口发送接收部分  结束----------------------------
//========================================================================

使用伪代码: 

// 发送ADC数据
void sendADCSampleSimple()
{uint8 i = 0;uint8 j = 0;uint8 size = adcCurrentIndex;uint8 *buffer = NULL;     // DMA缓存int8 dmaBufferIndex = -1; // DMA缓存的索引dmaBufferIndex = UART1_getIdleGroupIndex();if (dmaBufferIndex == -1){return;}buffer = &Uart1_sendDMABuffer[dmaBufferIndex][0];i = 0;buffer[i++] = uartCommand.Start1;buffer[i++] = uartCommand.Start2;buffer[i++] = 0x20;buffer[i++] = size;              // 数据个数buffer[i++] = compareValue >> 8; // 触发值buffer[i++] = compareValue;// 拼接各个通道的数据for (j = 0; j < size; j++){buffer[i++] = adc1Array[j] >> 8;buffer[i++] = adc1Array[j] & 0x00ff;}buffer[i++] = getCheckSum(buffer, 2, i); // 校验和buffer[i++] = i - 2;buffer[i++] = uartCommand.End1;buffer[i++] = uartCommand.End2;UART1_writeBufferByDMA(dmaBufferIndex, i);
}void main(void)
{UART1_initCommand(receiveUartDataCallback);while (1){// uart1接收数据while (uartReceiveFIFO.headPos != uartReceiveFIFO.tailPos){MyCommand_addData(&uartCommand, FIFOBuffer_read(&uartReceiveFIFO));}// 发送数据UART1_sendData();// 发送ADC数据, 20个数据一起发送if (adcCurrentIndex >= 20){sendADCSampleSimple();adcCurrentIndex = 0; // 重置}}
}

http://www.xdnf.cn/news/940.html

相关文章:

  • C#接口开发异常:System.Web.HttpRequestValidationException
  • Linux421用户、组
  • qt画一朵花
  • ​001-内网穿透工具
  • 20250421在荣品的PRO-RK3566开发板的Android13下使用io命令控制GPIO
  • ArcGIS、ArcMap查看.shp文件时属性表中文乱码
  • 软件工程师中级考试-上午知识点总结(下)
  • Linux内核开发常用函数
  • Git创建空分支并推送到远程仓库
  • 大模型中超参数TopK是什么
  • 密码明文放在请求体是否有安全隐患?
  • 前端实战-AJAX
  • Spark(19)Yarn-tool接口
  • 力扣热题100——矩阵
  • 安卓的桌面 launcher是什么
  • 【AI】SpringAI 第三弹:接入通用大模型平台
  • CSS字体
  • 什么是SPA,SPA与MAP区别
  • redis-7 安装
  • 机器学习中,什么叫监督学习?什么叫非监督学习?
  • MCP(Minecraft Coder Pack)完全指南:从入门到精通
  • JavaScript 渲染内容爬取:Puppeteer 入门
  • PCIE Spec ---Base Address Registers
  • 每日算法-250421
  • 应急物资管理系统DW-S300|构建应急物资保障体系
  • Netdata 监控多台服务器
  • 树莓派5+L298N控制电机
  • Linux:进程控制
  • 《Learning Langchain》阅读笔记5-RAG(1)
  • 《作用域大冒险:从闭包到内存泄漏的终极探索》