DHHKa 发表于 2023-4-11 17:20:40

stm32 F1 串口通信 字符发送 第11个字符丢失

用的是给的库函数开发里的串口通讯实验例程,发现每到第11个字符发送出去的时候,就会被吞掉,也就是第10和第12个字符会正常输出且二者中间没有字符。

DHHKa 发表于 2023-4-12 23:08:35

有木有好的解决方法呀 顶顶顶

wj008 发表于 2023-6-4 23:32:45

DHHKa 发表于 2023-4-12 23:08
有木有好的解决方法呀 顶顶顶

接收数据 要用 DMA 接收比较好,不要一个一个字节的接收,因为中断处理的时候会耽误接收的时机不能接收完成。 还有DMA的通道优先级要高一些。串口优先级也稍微高一点,至少它们比定时器要高一些。
比如通道优先级2串口优先级3定时器优先级 9这样设置。
DMA 读取的时候要选择 重置计数器。写入的时候 默认即可。
在DMA 中设置 闲时中断,并使能闲时中断,也就是 如果 DMA 接收完一轮数据才通知你,不是一个 一个字节通知。 你需要给一定内存给他直接copy数据,但是这数据是很快就会被覆盖的,所以 你要在闲时中断中快速读取,并停止接收,读走后在清空缓存 标志位重新开启。
闲时中断的过程你不能处理其他事情,否则会耽误下一轮数据的接收,所以 你仅仅完成把数据取走即可, 那么取走的数据 一般放入一个 FIFO 队列(先进先出队列),保证数据不要被覆盖。 然后 由你的定时器 或者 while循环去检测 FIFO 队列的数据,这样可以保证数据不会读取丢失或者遗漏数据。
只是需要的内存会多一些。
对于写入也可以使用DMA 进行写入数据,写入数据 需要在写入之前 等待之前的数据发送完成可以写入才进行,否则 也会因为之前的数据没有发送完成,导致后面的数据发送不出去。

void Rx1CallHandler(void) {
    //判断闲时中断
    if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET) {
      //清理标志位
      __HAL_UART_CLEAR_IDLEFLAG(&huart1);
      HAL_UART_DMAStop(&huart1);
      //HAL_UART_AbortReceive(&huart1);
      uint16_t rxLen = RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
      if (rxLen > 0 && rxLen < 512 && rx1_buffer != 0) {
            //写入FIFO队列
            if (FifoDataLen(&fifo1) == 0) {
                FifoClear(&fifo1);
            }
            FifoWrite(&fifo1, (uint8_t *) rx1_buffer, rxLen);
      }
      //重置DMA的缓冲区
      memset(rx1_buffer, 0, RX_BUF_SIZE);
      //重新开启
      HAL_UART_Receive_DMA(&huart1, (uint8_t *) rx1_buffer, RX_BUF_SIZE);
    } else {
      //其他异常中断,可以重置
      __HAL_UART_CLEAR_IDLEFLAG(&huart1);
      HAL_UART_DMAStop(&huart1);
      memset(rx1_buffer, 0, RX_BUF_SIZE);
      HAL_UART_Receive_DMA(&huart1, (uint8_t *) rx1_buffer, RX_BUF_SIZE);
    }
}

在 stm32fixx.c

void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
    Rx1CallHandler();
/* USER CODE END USART1_IRQn 1 */
}

在 usart.c 中加入

void MX_USART1_UART_Init(void)
{

/* USER CODE BEGIN USART1_Init 0 */

/* USER CODE END USART1_Init 0 */

/* USER CODE BEGIN USART1_Init 1 */

/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
    Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
    //使能空闲中断
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
/* USER CODE END USART1_Init 2 */

}

在main.c 初始化 开始DMA

   HAL_UART_Receive_DMA(&huart1, (uint8_t *) rx1_buffer, RX_BUF_SIZE);


DMA发送数据 需要先检测之前的是否发送完成

while (huart1.gState != HAL_UART_STATE_READY);
            HAL_UART_Transmit_DMA(&huart1, (uint8_t *) res, rxLen);

wj008 发表于 2023-6-4 23:40:44

wj008 发表于 2023-6-4 23:32
接收数据 要用 DMA 接收比较好,不要一个一个字节的接收,因为中断处理的时候会耽误接收的时机不能接收完 ...


#include "fifo.h"
#include "string.h"

int FifoInit(Fifo *p, uint8_t *fifo_addr, uint32_t fifo_size) {
    if (fifo_addr == NULL || fifo_size == 0) {
      return -1;
    }
    memset((char *) p, 0, sizeof(Fifo));
    p->buf = fifo_addr; //数据地址
    p->in = 0;
    p->out = 0;
    p->size = fifo_size; //数据大小
    return 0;
}

int FifoDataLen(Fifo *p) {
    if (p->out > p->in) {
      FifoClear(p);
    }
    return (p->in - p->out);
}

int FifoSpaceLen(Fifo *p) {
    return (p->size - (p->in - p->out));
}

int FifoRead(Fifo *p, uint8_t *buf, uint32_t len) {
    __disable_irq();
    uint32_t i = 0, j = 0;
    j = (p->out % p->size);
    len = min(len, p->in - p->out);
    i = min(len, p->size - j);
    memcpy(buf, p->buf + j, i);
    memcpy(buf + i, p->buf, len - i);
    p->out += len;
    __enable_irq();
    return len;
}

int FifoWrite(Fifo *p, uint8_t *buf, uint32_t len) {
    __disable_irq();
    uint32_t i = 0, j = 0;
    j = p->in % p->size;
    len = min(len, p->size - p->in + p->out);
    i = min(len, p->size - j);
    memcpy(p->buf + j, buf, i);
    memcpy(p->buf, buf + i, len - i);
    p->in += len;
    __enable_irq();
    return len;
}

void FifoClear(Fifo *p) {
    p->in = 0;
    p->out = 0;
}
页: [1]
查看完整版本: stm32 F1 串口通信 字符发送 第11个字符丢失