娇小w搡bbbb搡bbb,《第一次の人妻》,中国成熟妇女毛茸茸,边啃奶头边躁狠狠躁视频免费观看

歷史上的今天

今天是:2025年06月08日(星期日)

2018年06月08日 | RS485通訊中使用STM32串口以DMA方式發送數據丟失字節的問題

發布者:chwwdch 來源: eefocus關鍵字:RS485通訊  STM32串口  DMA方式  發送數據  丟失字節 手機看文章 掃描二維碼
隨時隨地手機看文章

1、開發平臺

計算機操作系統:WIN7 64位;

開發環境:Keil MDK 5.14;

MCU:STM32F407ZET6;

STM32F4xx固件庫:STM32F4xx_DSP_StdPeriph_Lib_V1.4.0;

串口調試助手;

2、問題描述

    在測試用STM32F4xx芯片的串口USART1以DMA方式進行RS485收發通訊時,出現數據字節丟失的現象,一般丟失1~2個字節。

    出現問題時測試的簡單收發機制:使能串口USART1的DMA收發功能,開啟了DMA發送完成中斷和USART1空閑中斷。通過串口調試助手發送N個字節給MCU,當MCU產生USART1空閑中斷時,在USART1空閑中斷服務程序中將DMA接收到的N個字節數據從接收緩存拷貝到發送緩存,準備好數據后,RS485切換為發送模式,通過啟動一次DMA發送,將N個字節數據原樣回送到串口調試助手。最后,在DMA發送完成中斷服務程序中判斷到有DMA發送完成標志TCIF7置位時,立即將RS485再次切換為接收模式。

3、原因分析

        在STM32F4xx英文參考手冊(RM0090)中,USART章節的使用DMA發送小節給出了如下時序圖:

        由圖可見,當DMA將第3個字節Frame 3寫到USART數據寄存器USART_DR時,TX線上才剛準備出現第2個字節Frame 2的時序,并且DMA發送完成中斷標志在TX線還未出現第2個字節Frame 2時序時就由硬件置1了,所以,如果軟件中在DMA發送完成中斷服務程序中檢測到DMA TCIF標志置1后馬上將RS485切換為接收模式,則后面的字節數據將會丟失。

        所以,需要讓數據字節不丟失的話,必須讓所有字節(包括字節的停止位)在TX線上穩定發送完成后,才能將RS485切換為接收模式。

4、解決方法

        如上圖所示,有一個關鍵點是:當所有字節(包括字節的停止位)在TX線上穩定發送完成后,串口發送完成標志(TC flag)置1。所以,有兩個解決方法:

      方法一:用DMA發送完成中斷,不用USART1發送完成中斷。在DMA發送完成中斷服務程序中檢測到有TCIF7置1時,再等待USART1發送完成標志TC置1,直到USART1發送完成標志TC置1后,清零USART1發送完成標志TC,然后再將RS485切換為接收模式。

      方法二:用USART1發送完成中斷,不用DMA發送完成中斷。在USART1中斷服務程序USART1_IRQHandler()中,檢測到有USART1發送完成標志TC置1時,清零USART1發送完成標志TC,并且要清零DMA發送完成標志DMA_FLAG_TCIF7,最好同時清零DMA_FLAG_FEIF7、DMA_FLAG_DMEIF7、DMA_FLAG_TEIF7 、DMA_FLAG_HTIF7,然后再將RS485切換為接收模式。

5、參考源代碼

Usart.h頭文件


  1. /*---------------------------------------------------------------------------------------------------- 

  2. *Copyright: SXD Tech. Co., Ltd.  

  3. *開發 環境: Keil MDK 5.14 && STM32F407ZET6 

  4. *文件 名稱: USART串行通信驅動頭文件                       

  5. *作     者: 順信德 

  6. *版     本: V1.0 

  7. *日     期: 2018-2-6 

  8. *說     明:           

  9. *修改 日志: (1)  

  10. ----------------------------------------------------------------------------------------------------*/  

  11. #ifndef _USART_H_  

  12. #define _USART_H_  

  13.   

  14. #include "Global.h"   

  15.   

  16. /*---------------------------------------------宏定義(S)---------------------------------------------*/  

  17. #define RS485_Recv();   {PFout(11)=0;}  //SP485接收模式,低電平有效  

  18. #define RS485_Send();   {PFout(11)=1;}  //SP485發送模式,高電平有效  

  19.   

  20. #define USART1_SEND_MAXLEN  512 /*串口1最大發送字節長度*/  

  21. #define USART1_RECV_MAXLEN  512 /*串口1最大接收字節長度*/  

  22. /*---------------------------------------------宏定義(E)---------------------------------------------*/  

  23.   

  24.   

  25. /*--------------------------------------------端口定義(S)--------------------------------------------*/  

  26.   

  27. /*--------------------------------------------端口定義(E)--------------------------------------------*/  

  28.   

  29.   

  30. /*--------------------------------------------變量聲明(S)--------------------------------------------*/  

  31. extern u32 G_u32RS485BaudRate;              //RS485通訊波特率  

  32. extern u8 G_u8Usart1SendBuf[USART1_SEND_MAXLEN];    //發送數據緩沖區  

  33. extern u8 G_u8Usart1RecvBuf[USART1_RECV_MAXLEN];    //接收數據緩沖區     

  34. extern u16 G_u16CommRecvLen;                        //通訊接收的一幀數據長度  

  35. /*--------------------------------------------變量聲明(E)--------------------------------------------*/  

  36.   

  37.   

  38. /*--------------------------------------------函數聲明(S)--------------------------------------------*/  

  39. extern void USART1_Init(u32 baud);                                                  //USART1串口初始化  

  40. extern void USART_DMA_SendStart(DMA_Stream_TypeDef *DMA_Streamx, u16 m_u16SendCnt); //串口USART1啟動一次DMA傳輸  

  41. extern void USART1_DMA_SendNByte(u8 *m_pSendBuf, u16 m_u16SendCnt);         //串口USART1以DMA方式發送多字節  

  42. /*--------------------------------------------函數聲明(E)--------------------------------------------*/  

  43.   

  44. #endif  

Usart.c源文件

方法一:用DMA發送完成中斷


  1. /*---------------------------------------------------------------------------------------------------- 

  2. *Copyright: SXD Tech. Co., Ltd.  

  3. *開發 環境: Keil MDK 5.14 && STM32F407ZET6 

  4. *文件 名稱: USART串行通信驅動源文件                       

  5. *作     者: 順信德 

  6. *版     本: V1.0 

  7. *日     期:   2018-2-6 

  8. *說     明:           

  9. *修改 日志: (1)  

  10. ----------------------------------------------------------------------------------------------------*/  

  11. #include "Usart.h"     

  12.   

  13. /*--------------------------------------------變量定義(S)--------------------------------------------*/  

  14. u32 G_u32RS485BaudRate = 9600;                  //RS485通訊波特率  

  15. u8 G_u8Usart1SendBuf[USART1_SEND_MAXLEN]={0,};  //發送數據緩沖區  

  16. u8 G_u8Usart1RecvBuf[USART1_RECV_MAXLEN]={0,};  //接收數據緩沖區  

  17. u16 G_u16CommRecvLen=0;         //通訊接收的一幀數據長度  

  18. /*--------------------------------------------變量定義(E)--------------------------------------------*/  

  19.   

  20.   

  21. /*--------------------------------------------函數聲明(S)--------------------------------------------*/  

  22. void USART1_Init(u32 baud);                                                     //USART1串口初始化  

  23. void USART_DMA_SendStart(DMA_Stream_TypeDef *DMA_Streamx, u16 m_u16SendCnt);    //串口USART1啟動一次DMA傳輸  

  24. void USART1_DMA_SendNByte(u8 *m_pSendBuf, u16 m_u16SendCnt);                    //串口USART1以DMA方式發送多字節  

  25. /*--------------------------------------------函數聲明(E)--------------------------------------------*/  

  26.   

  27. /*----------------------------------------------------------------------------------------------------  

  28. *函數名稱:void USART1_Init(u32 baud) 

  29. *函數功能:USART1串口初始化函數   

  30. *入口參數:u32 baud - 波特率(單位bps) 

  31. *出口參數:無 

  32. *說    明:用于RS485通信; 

  33. ----------------------------------------------------------------------------------------------------*/  

  34. void USART1_Init(u32 baud)  

  35. {  

  36.     GPIO_InitTypeDef GPIO_InitStructure;  

  37.     USART_InitTypeDef USART_InitStructure;  

  38.     NVIC_InitTypeDef NVIC_InitStructure;  

  39.     DMA_InitTypeDef  DMA_InitStructure;  

  40.     u16 mid_u16RetryCnt = 0;  

  41.       

  42.     USART_DeInit(USART1);  

  43.       

  44.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);       //使能GPIOA時鐘  

  45.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);      //使能USART1時鐘  

  46.    

  47.     //USART1對應引腳復用映射  

  48.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);   //GPIOA9復用為USART1_TX  

  49.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);  //GPIOA10復用為USART1_RX  

  50.       

  51.     //USART1端口配置  

  52.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;     //GPIOA9與GPIOA10  

  53.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;                //復用功能  

  54.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;           //速度25MHz  

  55.     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;              //推挽輸出  

  56.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;                //上拉  

  57.     GPIO_Init(GPIOA, &GPIO_InitStructure);                      //初始化PA9,PA10  

  58.   

  59.     //USART1初始化設置  

  60.     USART_InitStructure.USART_BaudRate = baud;                  //波特率設置  

  61.     USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字長為8位數據格式  

  62.     USART_InitStructure.USART_StopBits = USART_StopBits_1;      //一個停止位  

  63.     USART_InitStructure.USART_Parity = USART_Parity_No;         //無奇偶校驗位  

  64.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //無硬件數據流控制  

  65.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                 //收發模式  

  66.     USART_Init(USART1, &USART_InitStructure);                   //初始化USART1  

  67.       

  68.     USART_Cmd(USART1, ENABLE);                                  //使能USART1   

  69.       

  70.     USART_ClearFlag(USART1, USART_FLAG_TC); //清除發送完成標志    

  71.     while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //等待空閑幀發送完成后再清零發送完成標志  

  72.     USART_ClearFlag(USART1, USART_FLAG_TC); //清除發送完成標志  

  73.        

  74.     USART_ITConfig(USART1, USART_IT_TC, DISABLE);               //禁止USART1傳輸完成中斷  

  75.     USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);             //禁止USART1接收不為空中斷  

  76.     USART_ITConfig(USART1, USART_IT_TXE, DISABLE);              //禁止USART1發送空中斷  

  77.     USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);              //開啟USART1空閑中斷   

  78.            

  79.     //USART1 NVIC配置    

  80.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;           //串口1中斷通道    

  81.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;     //搶占優先級3    

  82.     NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;           //子優先級3    

  83.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //IRQ通道使能    

  84.     NVIC_Init(&NVIC_InitStructure);   

  85.     

  86.     USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);              //使能串口1的DMA發送       

  87.     USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);              //使能串口1的DMA接收    

  88.       

  89.     // - USART1發送DMA配置  

  90.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);         //DMA2時鐘使能  

  91.       

  92.     DMA_DeInit(DMA2_Stream7);    

  93.     while ((DMA_GetCmdStatus(DMA2_Stream7) != DISABLE) && (mid_u16RetryCnt++ < 500));    //等待DMA可配置     

  94.     //配置DMA2_Stream7   

  95.     DMA_InitStructure.DMA_Channel = DMA_Channel_4;                          //通道選擇    

  96.     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;         //DMA外設地址    

  97.     DMA_InitStructure.DMA_Memory0BaseAddr = (u32)G_u8Usart1SendBuf;         //DMA 存儲器0地址    

  98.     DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                 //存儲器到外設模式    

  99.     DMA_InitStructure.DMA_BufferSize = USART1_SEND_MAXLEN;                  //數據傳輸量     

  100.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;        //外設非增量模式    

  101.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                 //存儲器增量模式    

  102.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外設數據長度:8位    

  103.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;         //存儲器數據長度:8位    

  104.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                           //使用普通模式     

  105.     DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                   //中等優先級    

  106.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;             

  107.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;    

  108.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;             //存儲器突發單次傳輸    

  109.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;     //外設突發單次傳輸    

  110.     DMA_Init(DMA2_Stream7, &DMA_InitStructure);                             //初始化DMA Stream    

  111.   

  112.     //DMA2_Stream7的NVIC配置      

  113.     NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn;      

  114.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;      

  115.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;      

  116.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;      

  117.     NVIC_Init(&NVIC_InitStructure);  

  118.       

  119.     DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7);  //清除DMA發送完成中斷標志  

  120.     DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, ENABLE);      //使能DMA發送完成中斷  

  121.   

  122.     DMA_Cmd(DMA2_Stream7, ENABLE);  //使能DMA2_Stream7  

  123.     

  124.     // - USART1接收DMA配置   

  125.     mid_u16RetryCnt = 0;  

  126.     DMA_DeInit(DMA2_Stream5);         

  127.     while ((DMA_GetCmdStatus(DMA2_Stream5) != DISABLE) && (mid_u16RetryCnt++ < 500));    //等待DMA可配置     

  128.     //配置DMA2_Stream5    

  129.     DMA_InitStructure.DMA_Channel = DMA_Channel_4;                          //通道選擇    

  130.     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;         //DMA外設地址    

  131.     DMA_InitStructure.DMA_Memory0BaseAddr = (u32)G_u8Usart1RecvBuf;         //DMA 存儲器0地址    

  132.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                 //外設到存儲器模式    

  133.     DMA_InitStructure.DMA_BufferSize = USART1_RECV_MAXLEN;                  //數據傳輸量     

  134.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;        //外設非增量模式    

  135.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                 //存儲器增量模式    

  136.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外設數據長度:8位    

  137.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;         //存儲器數據長度:8位    

  138.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                           //使用普通模式     

  139.     DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                   //中等優先級    

  140.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;             

  141.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;    

  142.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;             //存儲器突發單次傳輸    

  143.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;     //外設突發單次傳輸    

  144.     DMA_Init(DMA2_Stream5, &DMA_InitStructure);                             //初始化DMA Stream    

  145.       

  146.     DMA_Cmd(DMA2_Stream5, ENABLE);  //使能DMA2_Stream5        

  147. }  

  148.   

  149. /*--------------------------------------------------------------------------------------  

  150. 函數名稱:void USART_DMA_SendStart(DMA_Stream_TypeDef *DMA_Streamx, u16 m_u16SendCnt) 

  151. 函數功能:串口USART1啟動一次DMA傳輸函數   

  152. 入口參數:DMA_Stream_TypeDef DMA_Streamx - DMA數據流(DMA1_Stream0~7/DMA2_Stream0~7); 

  153.          u16 m_u16SendCnt - 待傳輸數據字節數 

  154. 出口參數:無 

  155. 說    明:無 

  156. ---------------------------------------------------------------------------------------*/  

  157. void USART_DMA_SendStart(DMA_Stream_TypeDef *DMA_Streamx, u16 m_u16SendCnt)    

  158. {      

  159.     u16 l_u16RetryCnt = 0;  

  160.       

  161.     DMA_Cmd(DMA_Streamx, DISABLE);                      //關閉DMA傳輸             

  162.     while ((DMA_GetCmdStatus(DMA_Streamx) != DISABLE) && (l_u16RetryCnt++ < 500));   //等待DMA可配置    

  163.     DMA_SetCurrDataCounter(DMA_Streamx, m_u16SendCnt);  //數據傳輸量          

  164.     DMA_Cmd(DMA_Streamx, ENABLE);                       //開啟DMA傳輸     

  165. }          

  166.   

  167. /*--------------------------------------------------------------------------------------  

  168. 函數名稱:void USART1_DMA_SendNByte(u8 *m_pSendBuf, u16 m_u16SendCnt)  

  169. 函數功能:串口USART1以DMA方式發送多字節函數   

  170. 入口參數:u8 *m_pSendBuf - 待發送數據緩存, u16 m_u16SendCnt - 待發送數據個數 

  171. 出口參數:無 

  172. 說    明:無 

  173. ---------------------------------------------------------------------------------------*/    

  174. void USART1_DMA_SendNByte(u8 *m_pSendBuf, u16 m_u16SendCnt)    

  175. {      

  176.     memcpy(G_u8Usart1SendBuf, m_pSendBuf, m_u16SendCnt);        

  177.     USART_DMA_SendStart(DMA2_Stream7, m_u16SendCnt); //啟動一次DMA傳輸        

  178. }    

  179.     

  180. /*--------------------------------------------------------------------------------------  

  181. 函數名稱:void DMA2_Stream7_IRQHandler(void)  

  182. 函數功能:串口USART1以DMA方式發送完成中斷服務程序   

  183. 入口參數:無 

  184. 出口參數:無 

  185. 說    明:無 

  186. ---------------------------------------------------------------------------------------*/  

  187. void DMA2_Stream7_IRQHandler(void)    

  188. {      

  189.     if(DMA_GetFlagStatus(DMA2_Stream7, DMA_FLAG_TCIF7) != RESET)    //DMA發送完成?    

  190.     {     

  191.         DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7 | DMA_FLAG_FEIF7 |   

  192.                       DMA_FLAG_DMEIF7 | DMA_FLAG_TEIF7 | DMA_FLAG_HTIF7);   //清除標志位           

  193.           

  194.         while(!USART_GetFlagStatus(USART1, USART_FLAG_TC)); //等待USART1發送完成標志TC置1  

  195.         USART_ClearFlag(USART1, USART_FLAG_TC);     //清除發送完成標志  

  196.           

  197.         RS485_Recv();       //切換為RS485接收模式        

  198.     }    

  199. }  

  200.   

  201. /*--------------------------------------------------------------------------------------  

  202. 函數名稱:void USART1_IRQHandler(void) 

  203. 函數功能:USART串口1中斷服務程序   

  204. 入口參數:無 

  205. 出口參數:無 

  206. 說    明:無 

  207. ---------------------------------------------------------------------------------------*/  

  208. void USART1_IRQHandler(void)    

  209. {    

  210.     u16 l_u16Temp = 0;  

  211.       

  212.     if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)   //若有空閑中斷    

  213.     {    

  214.         DMA_Cmd(DMA2_Stream5, DISABLE); //關閉DMA2_Stream5,防止處理期間有數據   

  215.           

  216.         DMA_ClearFlag(DMA2_Stream5, DMA_FLAG_TCIF5 | DMA_FLAG_FEIF5 |   

  217.                       DMA_FLAG_DMEIF5 | DMA_FLAG_TEIF5 | DMA_FLAG_HTIF5);   //清除標志位       

  218.     

  219.         //清除USART總線空閑中斷標志(只要讀USART1->SR和USART1->DR即可)  

  220.         l_u16Temp = USART1->SR;        

  221.         l_u16Temp = USART1->DR;  

  222.             

  223.         G_u16CommRecvLen = USART1_RECV_MAXLEN - DMA_GetCurrDataCounter(DMA2_Stream5);   //求出接收到數據的字節數   

  224.         if(G_u16CommRecvLen <= USART1_RECV_MAXLEN)  

  225.         {  

  226.             RS485_Send();       //RS485發送模式  

  227.             USART1_DMA_SendNByte(G_u8Usart1RecvBuf, G_u16CommRecvLen);  //回送接收到的數據  

  228.         }  

  229.             

  230.         DMA_SetCurrDataCounter(DMA2_Stream5, USART1_RECV_MAXLEN);  //設置傳輸數據長度  

  231.         DMA_Cmd(DMA2_Stream5, ENABLE);     //使能DMA2_Stream5    

  232.     }     

  233. }  

方法二:用USART1發送完成中斷


  1. /*---------------------------------------------------------------------------------------------------- 

  2. *Copyright: SXD Tech. Co., Ltd.  

  3. *開發 環境: Keil MDK 5.14 && STM32F407ZET6 

  4. *文件 名稱: USART串行通信驅動源文件                       

  5. *作     者: 順信德 

  6. *版     本: V1.0 

  7. *日     期:   2018-2-6 

  8. *說     明:           

  9. *修改 日志: (1)  

  10. ----------------------------------------------------------------------------------------------------*/  

  11. #include "Usart.h"     

  12.   

  13. /*--------------------------------------------變量定義(S)--------------------------------------------*/  

  14. u32 G_u32RS485BaudRate = 9600;                  //RS485通訊波特率  

  15. u8 G_u8Usart1SendBuf[USART1_SEND_MAXLEN]={0,};  //發送數據緩沖區  

  16. u8 G_u8Usart1RecvBuf[USART1_RECV_MAXLEN]={0,};  //接收數據緩沖區  

  17. u16 G_u16CommRecvLen=0;                         //通訊接收的一幀數據長度  

  18. /*--------------------------------------------變量定義(E)--------------------------------------------*/  

  19.   

  20.   

  21. /*--------------------------------------------函數聲明(S)--------------------------------------------*/  

  22. void USART1_Init(u32 baud);                                                     //USART1串口初始化  

  23. void USART_DMA_SendStart(DMA_Stream_TypeDef *DMA_Streamx, u16 m_u16SendCnt);    //串口USART1啟動一次DMA傳輸  

  24. void USART1_DMA_SendNByte(u8 *m_pSendBuf, u16 m_u16SendCnt);                    //串口USART1以DMA方式發送多字節  

  25. /*--------------------------------------------函數聲明(E)--------------------------------------------*/  

  26.   

  27. /*----------------------------------------------------------------------------------------------------  

  28. *函數名稱:void USART1_Init(u32 baud) 

  29. *函數功能:USART1串口初始化函數   

  30. *入口參數:u32 baud - 波特率(單位bps) 

  31. *出口參數:無 

  32. *說    明:用于RS485通信; 

  33. ----------------------------------------------------------------------------------------------------*/  

  34. void USART1_Init(u32 baud)  

  35. {  

  36.     GPIO_InitTypeDef GPIO_InitStructure;  

  37.     USART_InitTypeDef USART_InitStructure;  

  38.     NVIC_InitTypeDef NVIC_InitStructure;  

  39.     DMA_InitTypeDef  DMA_InitStructure;  

  40.     u16 mid_u16RetryCnt = 0;  

  41.       

  42.     USART_DeInit(USART1);  

  43.       

  44.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);       //使能GPIOA時鐘  

  45.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);      //使能USART1時鐘  

  46.    

  47.     //USART1對應引腳復用映射  

  48.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);   //GPIOA9復用為USART1_TX  

  49.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);  //GPIOA10復用為USART1_RX  

  50.       

  51.     //USART1端口配置  

  52.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;     //GPIOA9與GPIOA10  

  53.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;                //復用功能  

  54.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;           //速度25MHz  

  55.     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;              //推挽輸出  

  56.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;                //上拉  

  57.     GPIO_Init(GPIOA, &GPIO_InitStructure);                      //初始化PA9,PA10  

  58.   

  59.     //USART1初始化設置  

  60.     USART_InitStructure.USART_BaudRate = baud;                  //波特率設置  

  61.     USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字長為8位數據格式  

  62.     USART_InitStructure.USART_StopBits = USART_StopBits_1;      //一個停止位  

  63.     USART_InitStructure.USART_Parity = USART_Parity_No;         //無奇偶校驗位  

  64.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //無硬件數據流控制  

  65.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                 //收發模式  

  66.     USART_Init(USART1, &USART_InitStructure);                   //初始化USART1  

  67.       

  68.     USART_Cmd(USART1, ENABLE);                                  //使能USART1   

  69.       

  70.     USART_ClearFlag(USART1, USART_FLAG_TC); //清除發送完成標志    

  71.     while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //等待空閑幀發送完成后再清零發送完成標志  

  72.     USART_ClearFlag(USART1, USART_FLAG_TC); //清除發送完成標志  

  73.       

  74.     USART_ITConfig(USART1, USART_IT_TC, ENABLE);                //使能USART1傳輸完成中斷   

  75.     USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);             //禁止USART1接收不為空中斷  

  76.     USART_ITConfig(USART1, USART_IT_TXE, DISABLE);              //禁止USART1發送空中斷  

  77.     USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);              //開啟USART1空閑中斷   

  78.            

  79.     //USART1 NVIC配置    

  80.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;           //串口1中斷通道    

  81.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;     //搶占優先級3    

  82.     NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;           //子優先級3    

  83.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //IRQ通道使能    

  84.     NVIC_Init(&NVIC_InitStructure);   

  85.     

  86.     USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);              //使能串口1的DMA發送       

  87.     USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);              //使能串口1的DMA接收    

  88.       

  89.     // - USART1發送DMA配置  

  90.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);         //DMA2時鐘使能  

  91.       

  92.     DMA_DeInit(DMA2_Stream7);    

  93.     while ((DMA_GetCmdStatus(DMA2_Stream7) != DISABLE) && (mid_u16RetryCnt++ < 500));            //等待DMA可配置     

  94.     //配置DMA2_Stream7   

  95.     DMA_InitStructure.DMA_Channel = DMA_Channel_4;                          //通道選擇    

  96.     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;         //DMA外設地址    

  97.     DMA_InitStructure.DMA_Memory0BaseAddr = (u32)G_u8Usart1SendBuf;         //DMA 存儲器0地址    

  98.     DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                 //存儲器到外設模式    

  99.     DMA_InitStructure.DMA_BufferSize = USART1_SEND_MAXLEN;                  //數據傳輸量     

  100.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;        //外設非增量模式    

  101.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                 //存儲器增量模式    

  102.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外設數據長度:8位    

  103.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;         //存儲器數據長度:8位    

  104.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                           //使用普通模式     

  105.     DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                   //中等優先級    

  106.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;             

  107.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;    

  108.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;             //存儲器突發單次傳輸    

  109.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;     //外設突發單次傳輸    

  110.     DMA_Init(DMA2_Stream7, &DMA_InitStructure);                             //初始化DMA Stream    

  111.   

  112.     DMA_Cmd(DMA2_Stream7, ENABLE);  //使能DMA2_Stream7  

  113.     

  114.     // - USART1接收DMA配置   

  115.     mid_u16RetryCnt = 0;  

  116.     DMA_DeInit(DMA2_Stream5);         

  117.     while ((DMA_GetCmdStatus(DMA2_Stream5) != DISABLE) && (mid_u16RetryCnt++ < 500));    //等待DMA可配置     

  118.     //配置DMA2_Stream5    

  119.     DMA_InitStructure.DMA_Channel = DMA_Channel_4;                          //通道選擇    

  120.     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;         //DMA外設地址    

  121.     DMA_InitStructure.DMA_Memory0BaseAddr = (u32)G_u8Usart1RecvBuf;         //DMA 存儲器0地址    

  122.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                 //外設到存儲器模式    

  123.     DMA_InitStructure.DMA_BufferSize = USART1_RECV_MAXLEN;                  //數據傳輸量     

  124.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;        //外設非增量模式    

  125.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                 //存儲器增量模式    

  126.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外設數據長度:8位    

  127.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;         //存儲器數據長度:8位    

  128.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                           //使用普通模式     

  129.     DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                   //中等優先級    

  130.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;             

  131.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;    

  132.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;             //存儲器突發單次傳輸    

  133.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;     //外設突發單次傳輸    

  134.     DMA_Init(DMA2_Stream5, &DMA_InitStructure);                             //初始化DMA Stream    

  135.       

  136.     DMA_Cmd(DMA2_Stream5, ENABLE);  //使能DMA2_Stream5        

  137. }  

  138.   

  139. /*--------------------------------------------------------------------------------------  

  140. 函數名稱:void USART_DMA_SendStart(DMA_Stream_TypeDef *DMA_Streamx, u16 m_u16SendCnt) 

  141. 函數功能:串口USART1啟動一次DMA傳輸函數   

  142. 入口參數:DMA_Stream_TypeDef DMA_Streamx - DMA數據流(DMA1_Stream0~7/DMA2_Stream0~7); 

  143.          u16 m_u16SendCnt - 待傳輸數據字節數 

  144. 出口參數:無 

  145. 說    明:無 

  146. ---------------------------------------------------------------------------------------*/  

  147. void USART_DMA_SendStart(DMA_Stream_TypeDef *DMA_Streamx, u16 m_u16SendCnt)    

  148. {      

  149.     u16 l_u16RetryCnt = 0;  

  150.       

  151.     DMA_Cmd(DMA_Streamx, DISABLE);                      //關閉DMA傳輸             

  152.     while ((DMA_GetCmdStatus(DMA_Streamx) != DISABLE) && (l_u16RetryCnt++ < 500));   //等待DMA可配置    

  153.     DMA_SetCurrDataCounter(DMA_Streamx, m_u16SendCnt);  //數據傳輸量          

  154.     DMA_Cmd(DMA_Streamx, ENABLE);                       //開啟DMA傳輸     

  155. }          

  156.   

  157. /*--------------------------------------------------------------------------------------  

  158. 函數名稱:void USART1_DMA_SendNByte(u8 *m_pSendBuf, u16 m_u16SendCnt)  

  159. 函數功能:串口USART1以DMA方式發送多字節函數   

  160. 入口參數:u8 *m_pSendBuf - 待發送數據緩存, u16 m_u16SendCnt - 待發送數據個數 

  161. 出口參數:無 

  162. 說    明:無 

  163. ---------------------------------------------------------------------------------------*/    

  164. void USART1_DMA_SendNByte(u8 *m_pSendBuf, u16 m_u16SendCnt)    

  165. {      

  166.     memcpy(G_u8Usart1SendBuf, m_pSendBuf, m_u16SendCnt);        

  167.     USART_DMA_SendStart(DMA2_Stream7, m_u16SendCnt); //啟動一次DMA傳輸        

  168. }  

  169.   

  170. /*--------------------------------------------------------------------------------------  

  171. 函數名稱:void USART1_IRQHandler(void) 

  172. 函數功能:USART串口1中斷服務程序   

  173. 入口參數:無 

  174. 出口參數:無 

  175. 說    明:無 

  176. ---------------------------------------------------------------------------------------*/  

  177. void USART1_IRQHandler(void)    

  178. {    

  179.     u16 l_u16Temp = 0;  

  180.       

  181.     if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)   //若有空閑中斷    

  182.     {    

  183.         DMA_Cmd(DMA2_Stream5, DISABLE); //關閉DMA2_Stream5,防止處理期間有數據       

  184.         DMA_ClearFlag(DMA2_Stream5, DMA_FLAG_TCIF5 | DMA_FLAG_FEIF5 |   

  185.                       DMA_FLAG_DMEIF5 | DMA_FLAG_TEIF5 | DMA_FLAG_HTIF5);//清零標志位          

  186.     

  187.         //清除USART總線空閑中斷標志(只要讀USART1->SR和USART1->DR即可)  

  188.         l_u16Temp = USART1->SR;        

  189.         l_u16Temp = USART1->DR;  

  190.             

  191.         G_u16CommRecvLen = USART1_RECV_MAXLEN - DMA_GetCurrDataCounter(DMA2_Stream5);   //求出接收到數據的字節數   

  192.         if(G_u16CommRecvLen <= USART1_RECV_MAXLEN)  

  193.         {  

  194.             RS485_Send();       //RS485發送模式  

  195.             USART1_DMA_SendNByte(G_u8Usart1RecvBuf, G_u16CommRecvLen);  

  196.         }  

  197.             

  198.         DMA_SetCurrDataCounter(DMA2_Stream5, USART1_RECV_MAXLEN);  //設置傳輸數據長度  

  199.         DMA_Cmd(DMA2_Stream5, ENABLE);     //使能DMA2_Stream5    

  200.     }   

  201.   

  202.     if(USART_GetITStatus(USART1, USART_IT_TC) != RESET) //若有發送完成中斷    

  203.     {    

  204.         USART_ClearITPendingBit(USART1, USART_IT_TC);   //清除USART1發送完成中斷標志  

  205.         DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7 | DMA_FLAG_FEIF7 |   

  206.                       DMA_FLAG_DMEIF7 | DMA_FLAG_TEIF7 | DMA_FLAG_HTIF7);//清零標志位  

  207.               

  208.         RS485_Recv();       //切換為RS485接收模式  

  209.     }     

  210. }  

6、聲明

    本程序的收發機制只是簡單的處理機制,只是為了說明解決數據丟失字節問題的方法,對進行快速大數據通訊時會出現亂碼。所以,用于實際項目中,需對此程序的收發處理機制進行重新設計。兩種方法中,個人認為方法二更好,因為方法一在中斷里面等待白白耗費了時間。


關鍵字:RS485通訊  STM32串口  DMA方式  發送數據  丟失字節 引用地址:RS485通訊中使用STM32串口以DMA方式發送數據丟失字節的問題

上一篇:STM32串口接收使用DMA雙緩沖
下一篇:STM32串口通信USART(二)---DMA方式

推薦閱讀

6月7日,根據中怡康發布的2018年一季度冰箱市場分析報告顯示,今年一季度線下冰箱市場的整體均價為4106元,較去年同期的3582元上漲524元,同比增幅高達14.63%,領跑白電市場。與之對比,其他白電產品中洗衣機均價同比上漲7.1%,空調均價同比上漲4.6%?! 〈送?,從彩電市場表現來看,以概念吸引用戶、以低價收割銷量的互聯網電視模式,已經遇到“天花板”...
蘋果在汽車領域的野心被稱為“泰坦計劃”, 蘋果一直不愿公開討論自己的這一堪稱神秘的計劃,實際上,自成立以來它已經面臨了一系列重組。近來這個項目計劃又發生了一些很重大的變化,據《紐約時報》最新報道,由于領導層面的變化,蘋果在開啟“重啟”戰略并關閉部分項目后,將不再致力于制造真正的汽車,而是開發自動駕駛汽車的基礎技術。  這一報道與...
半導體電容一般是皮法 (pF) 級或納法(nF) 級。許多商用 LCR 或電容表可以使用適當的測量技術測量這些值,包括補償技術。但是,某些應用要求飛法 (fF) 或 1e-15級的非常靈敏的電容測量,包括測量金屬到金屬電容、晶圓上的互連電容、MEMS器件如開關、或者納米器件上端子間的電容。如果沒有使用適當的儀器和測量技術,我們很難測量這些非常小的電容。 通過使...
貿澤開售HarwinKona高可靠性電源連接器在惡劣環境中確保電源連接可靠2021年6月8日 –專注于引入新品的全球電子元器件授權分銷商貿澤電子(Mouser Electronics)即日起備貨Harwin全新的Kona高可靠性電源連接器。該系列連接器非常堅固耐用,并且每個觸頭均可傳輸60A連續電流,因而在支持電池充電應用時無需采用多個觸頭進行分流。貿澤分銷的Harwin Kona連接...

史海拾趣

問答坊 | AI 解惑

電子元器件基礎知識——集成電路

集成電路是一種采用特殊工藝,將晶體管、電阻、電容等元件集成在硅基片上而形成的具有一定功能的器件,英文為縮寫為IC,也俗稱芯片。集成電路是六十年代出現的,當時只集成了十幾個元器件。 后來集成度越來越高,也有了今天的P-III。 集成電路根 ...…

查看全部問答∨

面試時求完美還是求真實?

現在都大家都在找工作,找工作就面臨著要面試,你面試時是追求完美還是真實性呢?…

查看全部問答∨

每日無線詞匯----射線跟蹤模型 Ray Tracing Model(zt)

類比:每天有成千上萬的人從北京出發去往全國各地,假若現在想知道每天有多少乘客從北京出發到上海。理論上我們只要把每天從北京到上海所有可能的交通工具包括飛機、火車、汽車所能運輸的人加起來便可以了。但是你有可能少考慮一部分人,他們可能跑 ...…

查看全部問答∨

觸摸屏無法校準~~

大家好,     遇到新問題。觸摸屏無法校準。就是校準之后又開始校準,反復校準。。。。。。     提示是Maximum Allowed Error 7: Maximum error 60890 exceeds calibration threshold 7     這段log應該是pubilc ...…

查看全部問答∨

[急!]OV9650攝像頭 視頻傳輸問題

在程序的前面用 m_hled=CreateFile(_T(\"CIS1:\"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,0);//打開驅動 ret = DeviceIoControl(m_hled,CAM_IOCTL_SAMSUNG_PREVIEW_START,NULL,NULL,NULL,NULL,NULL,NULL); 在開發板上LCD已經實時顯 ...…

查看全部問答∨

求友善之臂SBC2410光盤資料包含vivi等內核源碼

如題“ 求友善之臂SBC2410光盤資料包含vivi等內核源碼” 在線等待,急用........ 哪個兄弟有, 懇請您給我發一個 ,在下不勝感激, 資料內容比較大,所以請您發到我的郵箱:804763993@qq.com 請注明您的eeworld號 我給你再追加100分 謝謝.....…

查看全部問答∨

尋找WIN CE 開發人員

正在找人開發基于WIN CE平臺的PDA應用程序,有意者請聯系QQ40326822 …

查看全部問答∨

wince6.0 R3 IE Data Abort

最近將wince6從 R2升級到了R3, 發現ie在打開網頁后出現Data Abort. 網頁還是能打開。但是CPU占用率變化很大。經常上升到%100. 從MS的官方論壇發現了打了R3 09年12月份的補丁是必然會出現Data Abort的, 但是我安裝的是R3沒有添加任何補丁的也會出現 ...…

查看全部問答∨

上班的那點事2

工作中,方案的選定總不是那么完美,所以上班都免不了開會來解決諸如此類的問題; 如:LED T8燈管有長的120cm,也有短的60cm;為了方便庫存,設計的時候 鋁基板只設計成60公分的那一款,并用2塊60公分的鋁基板拼接成120公分的,同時共用; 但是 ...…

查看全部問答∨

指示表全自動檢定儀會用到MSP430的那一款單片機呀

各位大俠 ,有誰知道指示表全自動檢定儀會用到MSP430的那一款單片機呀?   有知道的請聯系我0755-28168418  QQ:754181079…

查看全部問答∨
小廣播
設計資源 培訓 開發板 精華推薦

最新單片機文章
何立民專欄 單片機及嵌入式寶典

北京航空航天大學教授,20余年來致力于單片機與嵌入式系統推廣工作。

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發圈

 
機器人開發圈

電子工程世界版權所有 京ICP證060456號 京ICP備10001474號-1 電信業務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 宣恩县| 大安市| 陆良县| 磐安县| 嘉鱼县| 常德市| 台北县| 陇南市| 彭州市| 松潘县| 富民县| 民乐县| 玉溪市| 夏津县| 湛江市| 上思县| 平阴县| 望江县| 石楼县| 岫岩| 西乡县| 吴堡县| 弋阳县| 额济纳旗| 普兰店市| 扶余县| 红原县| 绥中县| 东阳市| 射洪县| 大田县| 邯郸市| 重庆市| 乐至县| 安福县| 长顺县| 南安市| 井研县| 木里| 南澳县| 通化县|