我需要实现已极高的速度用串口往上位机发送数据, 并且还不能占用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 Interrupt
DMA_UR1T_STA = 0x00;
DMA_UR1T_AMT = Uart1_sendGroupSize[groupIndex] - 1; // 设置传输总字节数(低8位):n+1
DMA_UR1T_AMTH = 0x00; // 设置传输总字节数(高8位):n+1
DMA_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; // 重置
}
}
}