DMA+USART+stm32

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DMA+USART+stm32相关的知识,希望对你有一定的参考价值。

众所周知,串口是按照字节传输的,每一次传输一个字节。要传一帧数据,需要按照协议,帧头,帧尾,长度等信息,从字节流里面去分离。或者按照超时去分离。
STM32里面提供了DMA传输方式,整个过程有硬件控制。不占用处理器时间,高效。
发包:采用DMA方式,DMA发包完成会生成一个DMA发包完成中断。
收包:采用DMA+串口空闲中断方式,DMA空闲中断在,收到串口数据,串口空闲1个字节,自动触发。
代码如下:
第一步:引脚和时钟初始化
  1. void GPIO_Configuration(void)
  2. {
  3. GPIO_InitTypeDef GPIO_InitStructure;
  4. /* 使能USART1 时钟和所在端口时钟 */
  5. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
  6. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
  7. /*初始化USART1_TX端口*/
  8. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  9. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  10. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  11. GPIO_Init(GPIOA, &GPIO_InitStructure);
  12. /*初始化USART1_RX端口 */
  13. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  14. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  15. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  16. GPIO_Init(GPIOA, &GPIO_InitStructure);
  17. /* 使能USART2时钟和USART2所占用引脚的时钟 */
  18. //RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
  19. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
  20. /* 初始化USART2_Tx时钟 */
  21. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  22. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  23. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  24. GPIO_Init(GPIOA, &GPIO_InitStructure);
  25. /* 初始化USART2_Rx时钟 */
  26. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  27. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  28. GPIO_Init(GPIOA, &GPIO_InitStructure);
  29. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  30. GPIO_Init(GPIOA, &GPIO_InitStructure);
/*初始化RS485引脚 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init ( GPIOA, & GPIO_InitStructure );
  1. }
第二步:串口配置
  1. void USART_Configuration(void)
  2. {
  3. USART_InitTypeDef USART_InitStructure;
  4. /* USART1 115200 n 8 1 */
  5. USART_InitStructure.USART_BaudRate = 115200;
  6. USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  7. USART_InitStructure.USART_StopBits = USART_StopBits_1;
  8. USART_InitStructure.USART_Parity = USART_Parity_No;
  9. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  10. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  11. USART_Init(USART1, &USART_InitStructure);
  12. //开串口空闲中断
  13. USART_ITConfig(USART1, USART_IT_IDLE , ENABLE);
  14. //使能USART1
  15. USART_Cmd(USART1, ENABLE);
  16. USART_ClearFlag(USART1, USART_FLAG_TC);
  17. /*usart2 115200 n 8 1*/
  18. USART_InitStructure.USART_BaudRate = 115200;
  19. USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  20. USART_InitStructure.USART_StopBits = USART_StopBits_1;
  21. USART_InitStructure.USART_Parity = USART_Parity_No;
  22. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  23. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  24. USART_Init(USART2, &USART_InitStructure);
  25. //开串口空闲中断
  26. USART_ITConfig(USART2, USART_IT_IDLE , ENABLE);
  27.     //使能USART2
  28. USART_Cmd(USART2, ENABLE);
  29. USART_ClearFlag(USART2, USART_FLAG_TC);
  30. }
第三步:DMA设置
  1. void DMA_Configuration(void)
  2. {
  3. DMA_InitTypeDef DMA_InitStructure;
  4. /* DMA clock enable */
  5. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//DMA1
  6. /* DMA1 Channel4 (triggered by USART1 Tx event) Config */
  7. DMA_DeInit(DMA1_Channel4);
  8. DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40013804;
  9. DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_SEND_DATA;
  10. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  11. DMA_InitStructure.DMA_BufferSize = 128;
  12. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  13. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  14. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  15. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  16. DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  17. DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  18. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  19. DMA_Init(DMA1_Channel4, &DMA_InitStructure);
  20. DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
  21. DMA_ITConfig(DMA1_Channel4, DMA_IT_TE, ENABLE);
  22. /* Enable USART1 DMA TX request */
  23. USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
  24. DMA_Cmd(DMA1_Channel4, DISABLE);
  25. /* DMA1 Channel7 (triggered by USART2 Tx event) Config */
  26. DMA_DeInit(DMA1_Channel7);
  27. DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004404;
  28. DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART2_SEND_DATA;
  29. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  30. DMA_InitStructure.DMA_BufferSize = 128;
  31. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  32. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  33. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  34. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  35. DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  36. DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  37. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  38. DMA_Init(DMA1_Channel7, &DMA_InitStructure);
  39. DMA_ITConfig(DMA1_Channel7, DMA_IT_TC, ENABLE);
  40. DMA_ITConfig(DMA1_Channel7, DMA_IT_TE, ENABLE);
  41. /* Enable USART1 DMA TX request */
  42. USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
  43. DMA_Cmd(DMA1_Channel7, DISABLE);
  44. /* DMA1 Channel5 (triggered by USART1 Rx event) Config */
  45. DMA_DeInit(DMA1_Channel5);
  46. DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40013804;
  47. DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_RECEIVE_DATA;
  48. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  49. DMA_InitStructure.DMA_BufferSize = 128;
  50. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  51. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  52. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  53. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  54. DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  55. DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  56. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  57. DMA_Init(DMA1_Channel5, &DMA_InitStructure);
  58. DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
  59. DMA_ITConfig(DMA1_Channel5, DMA_IT_TE, ENABLE);
  60. /* Enable USART1 DMA RX request */
  61. USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
  62. DMA_Cmd(DMA1_Channel5, ENABLE);
  63. /* DMA1 Channel6 (triggered by USART1 Rx event) Config */
  64. DMA_DeInit(DMA1_Channel6);
  65. DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004404;
  66. DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART2_RECEIVE_DATA;
  67. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  68. DMA_InitStructure.DMA_BufferSize = 128;
  69. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  70. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  71. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  72. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  73. DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  74. DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
  75. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  76. DMA_Init(DMA1_Channel6, &DMA_InitStructure);
  77. DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);
  78. DMA_ITConfig(DMA1_Channel6, DMA_IT_TE, ENABLE);
  79. /* Enable USART2 DMA RX request */
  80. USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);
  81. DMA_Cmd(DMA1_Channel6, ENABLE);
  82. }
第四步:NVIC中断配置
  1. void NVIC_Configuration(void)
  2. {
  3. NVIC_InitTypeDef NVIC_InitStructure;
  4. /* Configure one bit for preemption priority */
  5. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  6. /* Enable the USART1 Interrupt串口空闲中断 */
  7. NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  8. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  9. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  10. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  11. NVIC_Init(&NVIC_InitStructure);
  12. /* Enable the USART2 Interrupt 串口空闲中断 */
  13. NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  14. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  15. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  16. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  17. NVIC_Init(&NVIC_InitStructure);
  18. //Enable DMA Channel4 Interrupt DMA 发包完成中断
  19. NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
  20. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  21. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  22. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  23. NVIC_Init(&NVIC_InitStructure);
  24. //Enable DMA Channel7 Interrupt DMA 发包完成中断
  25. NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn;
  26. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  27. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  28. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  29. NVIC_Init(&NVIC_InitStructure);
  30. }
第五步:串口空闲中断配置
  1. void USART1_IRQHandler(void)
  2. {
  3. u16 DATA_LEN;
  4. if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)//收包完成,触发空闲中断
  5. {
  6. DMA_Cmd(DMA1_Channel5, DISABLE);//关掉DMA防干扰
  7. DATA_LEN=128-DMA_GetCurrDataCounter(DMA1_Channel5); //计算长度
  8. if(DATA_LEN > 0)
  9. {
  10. //数据处理
  11. }
  12. DMA_ClearFlag(DMA1_FLAG_GL5 | DMA1_FLAG_TC5 | DMA1_FLAG_TE5 | DMA1_FLAG_HT5);//清楚中断标志位,方便下一次接收
  13. DMA1_Channel5->CNDTR = 128;//
  14. USART1->SR;
  15. USART1->DR;
  16. DMA_ClearITPendingBit(DMA1_IT_TC5);
  17. DMA_ClearITPendingBit(DMA1_IT_TE5);
  18. DMA_Cmd(DMA1_Channel5, DISABLE);//
  19. DMA1_Channel5->CNDTR = 128;//?
  20. DMA_Cmd(DMA1_Channel5, ENABLE);//
  21. }
  22. if(USART_GetITStatus(USART1, USART_IT_PE | USART_IT_FE | USART_IT_NE) != RESET)//
  23. {
  24. USART_ClearITPendingBit(USART1, USART_IT_PE | USART_IT_FE | USART_IT_NE);
  25. }
  26. USART_ClearITPendingBit(USART1, USART_IT_TC);
  27. USART_ClearITPendingBit(USART1, USART_IT_IDLE);
  28. }
  29. void USART2_IRQHandler(void)
  30. {
  31. u16 DATA_LEN;
  32. if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET) //?????????
  33. {
  34. DMA_Cmd(DMA1_Channel6, DISABLE);
  35. DATA_LEN=512-DMA_GetCurrDataCounter(DMA1_Channel6);
  36. if(DATA_LEN > 0)
  37. {
  38. }
  39. //DMA_Cmd(DMA1_Channel5, DISABLE);//??DMA,?????????
  40. DMA_ClearFlag(DMA1_FLAG_GL6 | DMA1_FLAG_TC6 | DMA1_FLAG_TE6 | DMA1_FLAG_HT6);//???
  41. DMA1_Channel6->CNDTR = 512;//???
  42. DMA_Cmd(DMA1_Channel6, ENABLE);//???,??DMA
  43. //?SR??DR??Idle
  44. USART2->SR;
  45. USART2->DR;
  46. DMA_ClearITPendingBit(DMA1_IT_TC6);
  47. DMA_ClearITPendingBit(DMA1_IT_TE6);
  48. DMA_Cmd(DMA1_Channel6, DISABLE);//
  49. DMA1_Channel6->CNDTR = 128;//?
  50. DMA_Cmd(DMA1_Channel6, ENABLE);//
  51. }
  52. if(USART_GetITStatus(USART2, USART_IT_PE | USART_IT_FE | USART_IT_NE) != RESET)//??
  53. {
  54. USART_ClearITPendingBit(USART2, USART_IT_PE | USART_IT_FE | USART_IT_NE);
  55. }
  56. USART_ClearITPendingBit(USART2, USART_IT_TC);
  57. USART_ClearITPendingBit(USART2, USART_IT_IDLE);
  58. }
第六步:DMA发包
  1. void usart1_DMA_send_data(int DATA_LEN)
  2. {
  3. DMA_Cmd(DMA1_Channel4, DISABLE);
  4. DMA1_Channel4->CNDTR=DATA_LEN; //DMA1
  5. DMA_Cmd(DMA1_Channel4, ENABLE);
  6. }
  7. void usart2_DMA_send_data(int DATA_LEN)
  8. {
  9. DMA_Cmd(DMA1_Channel7, DISABLE); //
  10. DMA1_Channel7->CNDTR=DATA_LEN; //DMA1,?????
  11. DMA_Cmd(DMA1_Channel7, ENABLE);
  12. }
第7步: 配置发包完成中断
  1. //DMA1_Channel4
  2. void DMA1_Channel4_IRQHandler(void)
  3. {
  4. DMA_ClearITPendingBit(DMA1_IT_TC4);
  5. DMA_ClearITPendingBit(DMA1_IT_TE4);
  6. DMA_Cmd(DMA1_Channel4, DISABLE);//
  7. }
  8. //DMA1_Channel7
  9. void DMA1_Channel7_IRQHandler(void)
  10. {
  11. DMA_ClearITPendingBit(DMA1_IT_TC7);
  12. DMA_ClearITPendingBit(DMA1_IT_TE7);
  13. DMA_Cmd(DMA1_Channel7, DISABLE);
  14. }
第8步:RS485首发引脚配置
  1. void set_RS485_TX_mode()
  2. {
  3. int cnt = 72000;
  4. PAout(8) =1;
  5. while(cnt--);
  6. }
  7. void set_RS485_Rx_mode()
  8. {
  9. int cnt = 72000;
  10. while(cnt--);
  11. PAout(8) =0;
  12. }
第9步 DMA发包封装:
  1. void rs485_DMA_send_data(uint8_t* data,uint8_t size)
  2. {
  3. set_RS485_TX_mode();
  4. memcpy(USART1_SEND_DATA,data,size);
  5. usart1_DMA_send_data(size);
  6. set_RS485_Rx_mode();
  7. }
  8. void USART_DMA_send_data(uint8_t* data,uint8_t size)
  9. {
  10. memcpy(USART2_SEND_DATA,data,size);
  11. usart2_DMA_send_data(size);
  12. }
以上就是全部的API。经测试收发数据都正常。








以上是关于DMA+USART+stm32的主要内容,如果未能解决你的问题,请参考以下文章

stm32f4 dma + uart idle + double 调试小记

STM32:将 USART 与字符匹配 ISR 和 DMA 缓冲区一起使用

STM32cubeMX+DMA+USART 接收任意长度的数据

STM32cubeMX+DMA+USART 接收任意长度的数据

STM32F429 定时器触发 USART DMA 传输问题

STM32的usart的DMA方式发送 一个数 ,程序怎么写?