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 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; // 重置
    }
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值