STM32F407的串口采用DMA收发数据

STM32F407的串口采用DMA收发数据


本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.


环境:

主机:WIN8

开发环境:MDK5.13

mcu: stm32f407VGT6


说明:

之前用STM32F103实现DMA收发串口数据,现在项目中采用STM32F407,所以将此机制移植到F4上。

STM32F103上用DMA收发串口数据文章:

STM32的串口采用DMA方式发送数据测试

STM32的串口采用DMA方式接收数据测试


源代码:

串口初始化代码:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /********************************************************************* 
  2. *                           初始化串口 
  3. **********************************************************************/  
  4.   
  5. static void init_uart(void)  
  6. {  
  7.     //定义中断结构体  
  8.     NVIC_InitTypeDef NVIC_InitStructure ;  
  9.     //定义IO初始化结构体  
  10.     GPIO_InitTypeDef GPIO_InitStructure;  
  11.     //定义串口结构体    
  12.     USART_InitTypeDef USART_InitStructure;  
  13.     //定义DMA结构体  
  14.     DMA_InitTypeDef DMA_InitStructure;  
  15.   
  16.     //打开串口对应的外设时钟    
  17.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);  
  18.        
  19.     //串口发DMA配置    
  20.     //启动DMA时钟  
  21.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);  
  22.     //DMA发送中断设置  
  23.     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn;  
  24.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  
  25.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
  26.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
  27.     NVIC_Init(&NVIC_InitStructure);  
  28.     //DMA通道配置  
  29.     DMA_DeInit(DMA1_Stream6);  
  30.     DMA_InitStructure.DMA_Channel = DMA_Channel_4;   
  31.     //外设地址  
  32.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART2->DR);  
  33.     //内存地址  
  34.     DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Tx_Buf_Gsm;  
  35.     //dma传输方向  
  36.     DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;  
  37.     //设置DMA在传输时缓冲区的长度  
  38.     DMA_InitStructure.DMA_BufferSize = TX_LEN_GSM;  
  39.     //设置DMA的外设递增模式,一个外设  
  40.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  
  41.     //设置DMA的内存递增模式  
  42.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  
  43.     //外设数据字长  
  44.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  
  45.     //内存数据字长  
  46.     DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;  
  47.     //设置DMA的传输模式  
  48.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  
  49.     //设置DMA的优先级别  
  50.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;  
  51.       
  52.     //指定如果FIFO模式或直接模式将用于指定的流 : 不使能FIFO模式    
  53.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;      
  54.     //指定了FIFO阈值水平  
  55.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;          
  56.     //指定的Burst转移配置内存传输   
  57.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;         
  58.     //指定的Burst转移配置外围转移 */    
  59.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;   
  60.   
  61.     //配置DMA1的通道           
  62.     DMA_Init(DMA1_Stream6, &DMA_InitStructure);    
  63.     //使能中断  
  64.     DMA_ITConfig(DMA1_Stream6,DMA_IT_TC,ENABLE);     
  65.   
  66.     //串口收DMA配置    
  67.     //启动DMA时钟  
  68.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);  
  69.     //DMA通道配置  
  70.     DMA_DeInit(DMA1_Stream5);  
  71.     DMA_InitStructure.DMA_Channel = DMA_Channel_4;  
  72.     //外设地址  
  73.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART2->DR);  
  74.     //内存地址  
  75.     DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Rx_Buf_Gsm;  
  76.     //dma传输方向  
  77.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;  
  78.     //设置DMA在传输时缓冲区的长度  
  79.     DMA_InitStructure.DMA_BufferSize = RX_LEN_GSM;  
  80.     //设置DMA的外设递增模式,一个外设  
  81.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  
  82.     //设置DMA的内存递增模式  
  83.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  
  84.     //外设数据字长  
  85.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  
  86.     //内存数据字长  
  87.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;  
  88.     //设置DMA的传输模式  
  89.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  
  90.     //设置DMA的优先级别  
  91.     DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;  
  92.       
  93.     //指定如果FIFO模式或直接模式将用于指定的流 : 不使能FIFO模式    
  94.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;      
  95.     //指定了FIFO阈值水平  
  96.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;          
  97.     //指定的Burst转移配置内存传输   
  98.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;         
  99.     //指定的Burst转移配置外围转移 */    
  100.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;   
  101.       
  102.     //配置DMA1的通道           
  103.     DMA_Init(DMA1_Stream5, &DMA_InitStructure);    
  104.     //使能通道  
  105.     DMA_Cmd(DMA1_Stream5,ENABLE);  
  106.       
  107.     //初始化串口参数    
  108.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;    
  109.     USART_InitStructure.USART_StopBits = USART_StopBits_1;    
  110.     USART_InitStructure.USART_Parity = USART_Parity_No;    
  111.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;    
  112.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;      
  113.     USART_InitStructure.USART_BaudRate = DEFAULT_BAUD_GSM;   
  114.     //初始化串口   
  115.     USART_Init(USART2,&USART_InitStructure);    
  116.       
  117.     //中断配置  
  118.     USART_ITConfig(USART2,USART_IT_TC,DISABLE);  
  119.     USART_ITConfig(USART2,USART_IT_RXNE,DISABLE);  
  120.     USART_ITConfig(USART2,USART_IT_IDLE,ENABLE);    
  121.   
  122.     //配置中断    
  123.     //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);  
  124.     NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;               //通道设置为串口中断    
  125.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;       //中断占先等级  
  126.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;              //中断响应优先级   
  127.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 //打开中断    
  128.     NVIC_Init(&NVIC_InitStructure);     
  129.           
  130.     //采用DMA方式发送  
  131.     USART_DMACmd(USART2,USART_DMAReq_Tx,ENABLE);  
  132.     //采用DMA方式接收  
  133.     USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE);  
  134.   
  135.     //中断配置  
  136.     USART_ITConfig(USART2,USART_IT_TC,DISABLE);  
  137.     USART_ITConfig(USART2,USART_IT_RXNE,DISABLE);  
  138.     USART_ITConfig(USART2,USART_IT_TXE,DISABLE);  
  139.     USART_ITConfig(USART2,USART_IT_IDLE,ENABLE);    
  140.     //启动串口    
  141.     USART_Cmd(USART2, ENABLE);      
  142.   
  143.     //设置IO口时钟        
  144.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);   
  145.     GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2);    
  146.     GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2);  
  147.   
  148.     //管脚模式:输出口  
  149.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;      
  150.     //类型:推挽模式  
  151.     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;    
  152.     //上拉下拉设置  
  153.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;      
  154.     //IO口速度  
  155.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  
  156.     //管脚指定  
  157.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;  
  158.     //初始化  
  159.     GPIO_Init(GPIOA, &GPIO_InitStructure);  
  160.       
  161.     //管脚模式:输入口  
  162.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;      
  163.     //上拉下拉设置  
  164.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;      
  165.     //管脚指定  
  166.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;  
  167.     //初始化  
  168.     GPIO_Init(GPIOA, &GPIO_InitStructure);        
  169. }  


发送数据:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /********************************************************************* 
  2. *                           接口函数:向gsm模块发送数据 
  3. *参数:data:发送数据存放地址 
  4. *     size:发送数据字节数 
  5. **********************************************************************/  
  6.   
  7. void drv_gsm_tx(uint8_t *data,uint16_t size)  
  8. {  
  9.     //等待空闲  
  10.     while (Flag_Tx_Gsm_Busy);  
  11.     Flag_Tx_Gsm_Busy = 1;  
  12.     //复制数据  
  13.     memcpy(Tx_Buf_Gsm,data,size);  
  14.     //设置传输数据长度  
  15.     DMA_SetCurrDataCounter(DMA1_Stream6,size);  
  16.     //打开DMA,开始发送  
  17.     DMA_Cmd(DMA1_Stream6,ENABLE);  
  18. }  


中断处理函数:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /********************************************************************* 
  2. *                           接口函数:DMA发送中断处理函数 
  3. **********************************************************************/  
  4.   
  5. void drv_gsm_deal_irq_dma_tx(void)  
  6. {  
  7.     if(DMA_GetITStatus(DMA1_Stream6,DMA_IT_TCIF6) != RESET)   
  8.     {  
  9.         //清除标志位  
  10.         DMA_ClearFlag(DMA1_Stream6,DMA_FLAG_TCIF6);  
  11.         //关闭DMA  
  12.         DMA_Cmd(DMA1_Stream6,DISABLE);  
  13.         //打开发送完成中断,发送最后两个字节  
  14.         USART_ITConfig(USART2,USART_IT_TC,ENABLE);  
  15.     }  
  16. }  
  17.   
  18. /********************************************************************* 
  19. *                           处理发送完成中断 
  20. *返回:0:未产生,1:已经产生 
  21. **********************************************************************/  
  22.   
  23. uint8_t drv_gsm_deal_irq_tx_end(void)  
  24. {  
  25.     if(USART_GetITStatus(USART2, USART_IT_TC) != RESET)  
  26.     {  
  27.         //关闭发送完成中断  
  28.         USART_ITConfig(USART2,USART_IT_TC,DISABLE);  
  29.         //发送完成  
  30.         Flag_Tx_Gsm_Busy = 0;  
  31.           
  32.         return 1;  
  33.     }   
  34.       
  35.     return 0;  
  36. }  
  37.   
  38. /********************************************************************* 
  39. *                           处理接收完成中断 
  40. *参数:buf:接收的数据 
  41. *     len:接收的数据长度 
  42. *返回:0:未产生,其他:已经产生,此值为接收的数据长度 
  43. **********************************************************************/  
  44.   
  45. uint8_t drv_gsm_deal_irq_rx_end(uint8_t *buf)  
  46. {     
  47.     uint16_t len = 0;  
  48.       
  49.     //接收完成中断  
  50.     if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)  
  51.     {  
  52.         USART2->SR;  
  53.         USART2->DR; //清USART_IT_IDLE标志  
  54.         //关闭DMA  
  55.         DMA_Cmd(DMA1_Stream5,DISABLE);  
  56.         //清除标志位  
  57.         DMA_ClearFlag(DMA1_Stream5,DMA_FLAG_TCIF5);  
  58.           
  59.         //获得接收帧帧长  
  60.         len = RX_LEN_GSM - DMA_GetCurrDataCounter(DMA1_Stream5);  
  61.         memcpy(buf,Rx_Buf_Gsm,len);  
  62.           
  63.         //设置传输数据长度  
  64.         DMA_SetCurrDataCounter(DMA1_Stream5,RX_LEN_GSM);  
  65.         //打开DMA  
  66.         DMA_Cmd(DMA1_Stream5,ENABLE);  
  67.   
  68.         return len;  
  69.     }   
  70.       
  71.     return 0;  
  72. }  


中断函数:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /********************************************************************* 
  2. *                           GSM模块:DMA发送中断处理函数 
  3. **********************************************************************/  
  4.   
  5. void DMA1_Stream6_IRQHandler(void)  
  6. {  
  7.     gsm_dma_tx_irq_handler();  
  8. }  
  9.      
  10. /********************************************************************* 
  11. *                           GSM模块:串口中断处理函数 
  12. **********************************************************************/  
  13.   
  14. void USART2_IRQHandler(void)   
  15. {  
  16.     gsm_irq_handler();  
  17. }  

注意:

接收完成中断中必须要清除标志位

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //清除标志位  
  2.         DMA_ClearFlag(DMA1_Stream5,DMA_FLAG_TCIF5);  
并且必须在关闭DMA之后,这个语句在F103中并非必须的


中断处理函数:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /********************************************************************* 
  2. *                           接口函数:DMA发送中断处理函数 
  3. **********************************************************************/  
  4.   
  5. void gsm_dma_tx_irq_handler(void)  
  6. {  
  7.     inf_gsm_deal_irq_dma_tx();  
  8. }  
  9.      
  10. /********************************************************************* 
  11. *                           接口函数:串口中断处理函数 
  12. *参数:data:接收数据存放地址 
  13. *返回:接收数据长度 
  14. **********************************************************************/  
  15.   
  16. void gsm_irq_handler(void)                                
  17. {     
  18.     struct _Gsm_Rx rx;  
  19.     uint8_t i = 0;  
  20.       
  21.     //发送完成中断处理  
  22.     inf_gsm_deal_irq_tx_end();  
  23.       
  24.     //接收完成中断处理  
  25.     rx.len = inf_gsm_deal_irq_rx_end(rx.buf);  
  26.     if (rx.len != 0)  
  27.     {  
  28.         //通知观察者  
  29.         for (i = 0;i < Len_Observer;i++)  
  30.         {  
  31.             Observer[i](rx);  
  32.         }  
  33.     }   
  34. }   


接口函数定义:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /********************************************************************* 
  2. *                           接口函数:DMA发送中断处理函数 
  3. **********************************************************************/  
  4.   
  5. void inf_gsm_deal_irq_dma_tx(void)  
  6. {  
  7.     drv_gsm_deal_irq_dma_tx();  
  8. }  
  9.   
  10. /********************************************************************* 
  11. *                           处理发送完成中断 
  12. *返回:0:未产生,1:已经产生 
  13. **********************************************************************/  
  14.   
  15. uint8_t inf_gsm_deal_irq_tx_end(void)  
  16. {  
  17.     return drv_gsm_deal_irq_tx_end();  
  18. }  
  19.   
  20. /********************************************************************* 
  21. *                           处理接收完成中断 
  22. *参数:buf:接收的数据 
  23. *     len:接收的数据长度 
  24. *返回:0:未产生,其他:已经产生,此值为接收的数据长度 
  25. **********************************************************************/  
  26.   
  27. uint8_t inf_gsm_deal_irq_rx_end(uint8_t *buf)  
  28. {  
  29.     return drv_gsm_deal_irq_rx_end(buf); 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值