[STM32F1] stm32f103 uart+DMA发送接收

[复制链接]
498|3
 楼主| 工程师犹饿死 发表于 2022-4-29 15:03 | 显示全部楼层 |阅读模式
  1. //stm32f1 串口通信

  2. // 串口通信模块会为串口划分256字节的uart缓存区,缓存中断接收的数据,
  3. // 处理串口接收数据的任务会每50ms按协议处理解析缓存区里的数据。当然,
  4. // 如果没有处理完缓存区的数据,而又接收到新的数据,那新的数据将会被
  5. // 舍弃。

  6. // 串口的接收数据和发送数据都用到DMA处理器,其中串口接收用了串口
  7. // 空闲中断。串口连续接收数据后检测到串口接收空闲,产生一个空闲中断,
  8. // 这时候将接收到的数据缓存到uart缓存区中,等待解析。

  9. // 1. 配置串口IO口以及串口功能配置

  10. // 这里使用的是uart1

  11. #define FIFOLEN 256

  12. static uint8_t  dma_buf[FIFOLEN];
  13. static uint8_t  dma_rx[FIFOLEN];
  14. static u8 fifo_buf[FIFOLEN];
  15. static u16 fifo_in = 0;
  16. static u16 fifo_out = 0;
  17. static u16 fifo_used = 0;

  18. void uart1_func_init(void)
  19. {
  20.     GPIO_InitTypeDef io;
  21.     USART_InitTypeDef uart;

  22.     //UART1 IO口配置
  23.     io.GPIO_Pin = GPIO_Pin_9;
  24.     io.GPIO_Mode= GPIO_Mode_AF_PP;
  25.     io.GPIO_Speed= GPIO_Speed_50MHz;
  26.     GPIO_Init(GPIOA, &io);
  27.     io.GPIO_Pin = GPIO_Pin_10;
  28.     io.GPIO_Mode= GPIO_Mode_IN_FLOATING;
  29.     io.GPIO_Speed= GPIO_Speed_50MHz;;
  30.     GPIO_Init(GPIOA, &io);

  31.    //USART1 功能配置 波特率115200,8位数据位,1位停止位,无校验,无硬件流控制
  32.     uart.USART_BaudRate = 115200;
  33.     uart.USART_WordLength = USART_WordLength_8b;
  34.     uart.USART_StopBits = USART_StopBits_1;
  35.     uart.USART_Parity = USART_Parity_No;
  36.     uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  37.     uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

  38.     USART_Init(USART1, &uart);
  39.     USART_ITConfig(USART1,USART_IT_TC,DISABLE);//使能串口空闲中断
  40.     USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);//失能接收中断
  41.     USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);//使能发送中断

  42.     USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);//使能串口发送DMA
  43.     USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);//使能串口接收DMA
  44.     USART_Cmd(USART1, ENABLE);
  45. }



  46. // 2. 配置DMA功能
  47. // stm32f103手册里可以了解到,uart1-uart4有相关的DMA通道,对应如下
  48. // uart1_tx-->DMA1_Channel4 uart1_rx-->DMA1_Channel5
  49. // uart2_tx-->DMA1_Channel7 uart2_rx-->DMA1_Channel6
  50. // uart3_tx-->DMA1_Channel2 uart3_rx-->DMA1_Channel3
  51. // uart4_tx-->DMA2_Channel5 uart4_rx-->DMA2_Channel2


  52. static void uart1_dma_init(void)
  53. {
  54.     DMA_InitTypeDef   dma;

  55.     //DMA 配置
  56.     dma.DMA_BufferSize          = 1;                            //初始化为1个字节
  57.     dma.DMA_DIR                 = DMA_DIR_PeripheralDST;        //从内存到外设
  58.     dma.DMA_M2M                 = DMA_M2M_Disable;              //内存到内存,失能
  59.     dma.DMA_MemoryBaseAddr      = (uint32_t)dma_buf;            //内存地址
  60.     dma.DMA_MemoryDataSize      = DMA_MemoryDataSize_Byte;      //数据宽度
  61.     dma.DMA_MemoryInc           = DMA_MemoryInc_Enable;         //使能自增
  62.     dma.DMA_Mode                = DMA_Mode_Normal;              //普通模式,不连续模式
  63.     dma.DMA_PeripheralBaseAddr  = (uint32_t)&USART1->DR; //外设地址
  64.     dma.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_Byte;  //数据宽度
  65.     dma.DMA_PeripheralInc       = DMA_PeripheralInc_Disable;    //外设地址不自增
  66.     dma.DMA_Priority            = DMA_Priority_High;            //优先级
  67.     DMA_DeInit(DMA1_Channel4);
  68.     DMA_Init(DMA1_Channel4, &dma);
  69.     DMA_Cmd(DMA1_Channel4, ENABLE);


  70.     dma.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
  71.     dma.DMA_MemoryBaseAddr = (uint32_t)dma_rx;
  72.     dma.DMA_DIR = DMA_DIR_PeripheralSRC;
  73.     dma.DMA_BufferSize = FIFOLEN;
  74.     dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  75.     dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
  76.     dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  77.     dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  78.     dma.DMA_Mode = DMA_Mode_Normal;
  79.     dma.DMA_Priority = DMA_Priority_VeryHigh;
  80.     dma.DMA_M2M = DMA_M2M_Disable;
  81.     DMA_DeInit(DMA1_Channel5);
  82.     DMA_Init(DMA1_Channel5,&dma);
  83.     DMA_Cmd(DMA1_Channel5,ENABLE);
  84. }



  85. void uart1_init(void)
  86. {
  87.     uart1_dma_init();
  88.     uart1_func_init();
  89. }


  90. //3. uart 缓存区用fifo方式存取
  91. u16 uart1_read(u8* data, u16 len)
  92. {
  93.     u16 i;
  94.     u16 ret;
  95.     ret = (len < fifo_used) ? len : fifo_used;
  96.     for(i = 0; i < ret; i++)
  97.     {
  98.         data[i] = fifo_buf[fifo_out];
  99.         if(++fifo_out == FIFOLEN)
  100.         {
  101.             fifo_out = 0;
  102.         }
  103.     }
  104.     fifo_used -= ret;
  105.     return ret;
  106. }


  107. void uart1_write(uint8_t* data, uint16_t len)
  108. {
  109.     uint16_t i;
  110.     while(!DMA_GetFlagStatus(DMA1_FLAG_TC4));
  111.     DMA_Cmd(DMA1_Channel4, DISABLE);

  112.     for(i=0; i
  113.     {
  114.         dma_buf[i] = data[i];
  115.     }
  116.     DMA_ClearFlag(DMA1_FLAG_TC4);
  117.     DMA_SetCurrDataCounter(DMA1_Channel4, len);
  118.     DMA_Cmd(DMA1_Channel4, ENABLE);
  119. }

  120. //打印调试信息
  121. void uart1_puts(char* s)
  122. {
  123.     u16 i;
  124.     for(i=0;s[i]!=0;i++)
  125.     {
  126.         while(!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
  127.         USART_SendData(USART1, s[i]);
  128.     }
  129. }

  130. void USART1_IRQHandler(void)
  131. {
  132.     u16 temp;
  133.     u16 i;
  134.     if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
  135.     {
  136.         temp = USART1->SR;//----清除空闲标志位
  137.         temp = USART1->DR;
  138.         DMA_Cmd(DMA1_Channel5,DISABLE);

  139.         temp = FIFOLEN - DMA_GetCurrDataCounter(DMA1_Channel5);
  140.         for(i=0; i
  141.         {
  142.             if(fifo_used
  143.             {
  144.                 fifo_buf[fifo_in] = dma_rx[i];
  145.                 if(++fifo_in == FIFOLEN)
  146.                 {
  147.                     fifo_in = 0;
  148.                 }
  149.                 fifo_used++;
  150.             }
  151.         }

  152.         DMA_SetCurrDataCounter(DMA1_Channel5,FIFOLEN);
  153.         DMA_Cmd(DMA1_Channel5,ENABLE);
  154.     }
  155.     else
  156.     {
  157.         USART_ReceiveData(USART1);
  158.         USART_ClearFlag(USART1, USART_FLAG_ORE);
  159.     }
  160. }


 楼主| 工程师犹饿死 发表于 2022-4-29 15:05 | 显示全部楼层
上面是c文件,在h文件的接口如下


  1. void uart1_init(void);
  2. u16 uart1_read(u8* data, u16 len);
  3. void uart1_write(u8* data, u16 len);
  4. void uart1_puts(char* s);
 楼主| 工程师犹饿死 发表于 2022-4-29 15:06 | 显示全部楼层
  完成了上面的配置,就可以在解析数据包的任务里调用uart1_read函数了。长度一般为缓存区长度。
这里有两个发送函数,一个是uart1_put,一个是uart1_write,前者没有dma发送,不需要指定长度,发送完整的字符串出去,适合**调试信息到上位机。后者是dma方式发送,可以一定程度上减轻cpu负担,需要指定发送长度。
kiwis66 发表于 2022-5-2 15:41 | 显示全部楼层
DMA是必须发送固定数据么?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

78

主题

967

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部