STM32F407的串口編程經驗
串口是嵌入式開發中最常前的外設設備,既可以用作不同單片機之間的通信,也可以用作在STM32 MCU和PC機之間的通信,STM32F407的串口功能非常強大,可以接紅外,可以接流控,也可以接SIM卡接口,但我這里只介紹我們最常用的UART通信的一點調試經驗,以STM32F407為例,對其它STM32芯片也適用,希望對大家有所幫助,如有錯誤不當之處歡迎大家聯系指正。
一、串口的三種工作方式操作串口一般有兩種方式:查詢和中斷;STM32還支持第三種DMA方式。(1)查詢:串口程序不斷地循環查詢標志,看看當前有沒有數據要它傳送或接收。如果有的話進行相應的寫操作和讀操作進行傳送或接收數據。(2)中斷:平時串口只要打開中斷即可。如果發現有一個中斷來,則意味著有數據需要接收(接收中斷)或數據已經發送完成(發送中斷)。(3)DMA方式,設置好DMA工作方式,由DMA來自動接收或發送數據。一般來說,查詢方式的效率是比較低的,并且由于STM32的UART硬件上沒有FIFO,如果程序功能比較多,查詢不及時的話很容易出現數據丟失的現象, 故實際項目中這種方式用的并不多。中斷方式的話我們可以分別設置接收中斷和發送中斷,當串口有數據需要接收時才進入中斷程序進行讀讀操,這種方式占用CPU資源比較少,實際項目中比較常用,但需要注意中斷程序不要太復雜使執行時間太長,如果執行時間超過一個字符的時間的話也會出現數據丟失的現象,這個波特率比較高的串口編程中比較容易出現,可以考慮用循環BUF方法,在中斷程序中只負責實時地接收實數數和發送時的填數(寫發送寄存器),其它操作放在中斷外處理。STM32還提供了第三種DMA方式用來支持高速地串口傳輸。這種方式只要設置好接收和發送緩沖位置,可以由DMA來自動接收和發送數據,這可以最小化占用CPU時間。
二、串口的使用步驟(1)中斷方式基本步驟是初試化時鐘,腳位、波特率設置、安裝中斷服務程序、開中斷等,參考代碼如下:
1. voiduart_init(void)
2. {
3. USART_InitTypeDef USART_InitStructure;
4. NVIC_InitTypeDefNVIC_InitStructure;
5. GPIO_InitTypeDef GPIO_InitStructure;
6.
7. /*Enable GPIO clock */
8. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
9.
10. /* Enable USART clock */
11. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
12.
13. /* Connect USART pins to AF7 */
14. GPIO_PinAFConfig(GPIOC, GPIO_PinSource10,GPIO_AF_USART3);
15. GPIO_PinAFConfig(GPIOC,GPIO_PinSource11, GPIO_AF_USART3);
16.
17. /* Configure USART Tx and Rx as alternatefunction push-pull */
18. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
19. GPIO_InitStructure.GPIO_Speed= GPIO_Speed_100MHz;
20. GPIO_InitStructure.GPIO_OType =GPIO_OType_PP;
21. GPIO_InitStructure.GPIO_PuPd= GPIO_PuPd_UP;
22. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
23. GPIO_Init(GPIOC, &GPIO_InitStructure);
24.
25. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
26. GPIO_Init(GPIOC, &GPIO_InitStructure);
27. /* USARTxconfiguration ----------------------------------------------------*/
28. /* USARTx configured as follow:
29. - BaudRate =3750000 baud
30. - Maximum BaudRate that can be achievedwhen using the Oversampling by 8
31. is: (USART APB Clock / 8)
32. Example:
33. - (USART3 APB1 Clock / 8) = (30MHz / 8) = 3750000 baud
34. - (USART1 APB2 Clock / 8) = (60 MHz / 8) =7500000 baud
35. - Maximum BaudRate that can beachieved when using the Oversampling by 16
36. is: (USART APB Clock / 16)
37. Example: (USART3 APB1 Clock / 16) = (30 MHz /16) = 1875000 baud
38. Example: (USART1 APB2 Clock / 16) = (60 MHz /16) = 3750000 baud
39. - Word Length = 8Bits
40. - one Stop Bit
41. - No parity
42. - Hardware flowcontrol disabled (RTS and CTS signals)
43. - Receiveand transmit enabled
44. */
45. USART_InitStructure.USART_BaudRate = 115200;
46. USART_InitStructure.USART_WordLength= USART_WordLength_8b;
47. USART_InitStructure.USART_StopBits =USART_StopBits_1;
48. USART_InitStructure.USART_Parity= USART_Parity_No;
49. USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
50. USART_InitStructure.USART_Mode =USART_Mode_Rx | USART_Mode_Tx;
51. USART_Init(USART3, &USART_InitStructure);
52.
53. /* NVIC configuration */
54. /* Configure the Priority Group to2 bits */
55. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
56.
57. /* Enable the USARTx Interrupt */
58. NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
59. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
60. NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0;
61. NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;
62. NVIC_Init(&NVIC_InitStructure);
63.
64. /* Enable USART */
65. USART_Cmd(USART3, ENABLE);
66. USART_ITConfig(USART3, USART_IT_RXNE,ENABLE);
67. }
68.
復制代碼
中斷服務程序如下:
1. voidUSART3_IRQHandler(void)
2. {
3. unsigned charch;
4. if(USART_GetITStatus(USART3, USART_IT_RXNE)!= RESET)
5. {
6. /* Read one byte from the receive data register */
7. ch = (USART_ReceiveData(USART3));
8.
9. printf("in[%c].\r\n",ch);
10. }
11. }
復制代碼
直接把接收到的字符打印出來。
(2)DMA方式基本步驟同中斷方式,額外需要DMA的初始化配置,參考代碼如下:
1. void uart_init(void)
2. {
3. USART_InitTypeDef USART_InitStructure;
4. NVIC_InitTypeDef NVIC_InitStructure;
5. GPIO_InitTypeDefGPIO_InitStructure;
6. DMA_InitTypeDefDMA_InitStruct;
7.
8. /*Enable GPIO clock */
9. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
10.
11. /* Enable USART clock */
12. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
13.
14. /* Connect USART pins to AF7 */
15. GPIO_PinAFConfig(GPIOC, GPIO_PinSource10,GPIO_AF_USART3);
16. GPIO_PinAFConfig(GPIOC,GPIO_PinSource11, GPIO_AF_USART3);
17.
18. /* Configure USART Tx and Rx as alternatefunction push-pull */
19. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
20. GPIO_InitStructure.GPIO_Speed= GPIO_Speed_100MHz;
21. GPIO_InitStructure.GPIO_OType =GPIO_OType_PP;
22. GPIO_InitStructure.GPIO_PuPd= GPIO_PuPd_UP;
23. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
24. GPIO_Init(GPIOC, &GPIO_InitStructure);
25.
26. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
27. GPIO_Init(GPIOC, &GPIO_InitStructure);
28. /* USARTxconfiguration ----------------------------------------------------*/
29. /* USARTx configured as follow:
30. - BaudRate =3750000 baud
31. - Maximum BaudRate that can be achievedwhen using the Oversampling by 8
32. is: (USART APB Clock / 8)
33. Example:
34. - (USART3 APB1 Clock / 8) = (30MHz / 8) = 3750000 baud
35. - (USART1 APB2 Clock / 8) = (60 MHz / 8) =7500000 baud
36. - Maximum BaudRate that can beachieved when using the Oversampling by 16
37. is: (USART APB Clock / 16)
38. Example: (USART3 APB1 Clock / 16) = (30 MHz /16) = 1875000 baud
39. Example: (USART1 APB2 Clock / 16) = (60 MHz /16) = 3750000 baud
40. - Word Length = 8Bits
41. - one Stop Bit
42. - No parity
43. - Hardware flowcontrol disabled (RTS and CTS signals)
44. - Receiveand transmit enabled
45. */
46. USART_InitStructure.USART_BaudRate = 115200;
47. USART_InitStructure.USART_WordLength= USART_WordLength_8b;
48. USART_InitStructure.USART_StopBits =USART_StopBits_1;
49. USART_InitStructure.USART_Parity= USART_Parity_No;
50. USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
51. USART_InitStructure.USART_Mode =USART_Mode_Rx | USART_Mode_Tx;
52. USART_Init(USART3, &USART_InitStructure);
53.
54. /* DMA_Configuration */
55. DMA_DeInit(DMA1_Stream1);
56.
57. DMA_InitStruct.DMA_Channel= DMA_Channel_4;
58. DMA_InitStruct.DMA_PeripheralBaseAddr= (u32)&USART3->DR; //source buf
59. DMA_InitStruct.DMA_Memory0BaseAddr =(u8)pdata; //target buf
60.
61. DMA_InitStruct.DMA_DIR= DMA_DIR_PeripheralToMemory;
62. DMA_InitStruct.DMA_BufferSize =lenght; //BuffSize;
63. DMA_InitStruct.DMA_PeripheralInc= DMA_PeripheralInc_Disable;
64. DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
65. DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
66. DMA_InitStruct.DMA_MemoryDataSize= DMA_MemoryDataSize_Byte;
67. DMA_InitStruct.DMA_Mode =DMA_Mode_Circular; //DMA_Mode_Normal;
68. DMA_InitStruct.DMA_Priority = DMA_Priority_High;
69. DMA_InitStruct.DMA_FIFOMode= DMA_FIFOMode_Disable;
70. DMA_InitStruct.DMA_FIFOThreshold =DMA_FIFOThreshold_HalfFull;
71. DMA_InitStruct.DMA_MemoryBurst= DMA_MemoryBurst_Single;
72. DMA_InitStruct.DMA_PeripheralBurst =DMA_PeripheralBurst_Single;
73. DMA_Init(DMA1_Stream1, &DMA_InitStruct);
74.
75. /* NVIC configuration */
76. /* Configure the Priority Group to2 bits */
77. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
78.
79. /* Enable the USARTx Interrupt */
80. NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream1_IRQn;
81. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
82. NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0;
83. NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;
84. NVIC_Init(&NVIC_InitStructure);
85.
86. /* Open DMA interrupt*/
87. DMA_ITConfig(DMA1_Stream1, DMA_IT_TC,ENABLE);
88. DMA_Cmd(DMA1_Stream1, ENABLE);
89. USART_Cmd(USART3, ENABLE);
90. USART_DMACmd(USART3,USART_DMAReq_Rx,ENABLE);
91. }
復制代碼
DMA中斷服務程序如下:
1. voidDMA1_Stream1_IRQHandler(void) //UART3_RX
2. {
3. static short i;
4.
5. //Whena Transfer Complete
6. if(SET== DMA_GetITStatus(DMA1_Stream1, DMA_IT_TCIF1))
7. {
8. DMA_ClearITPendingBit(DMA1_Stream1,DMA_IT_TCIF1);
9. i++;
10. }
11. }
復制代碼
上面程序只配了DMA接收,發送類似。
三、實現DMX512協議DMX512 協議是美國劇場技術協會( United States Institute for TheaterTechnology, USITT) 制定的數字多路復用協議, 其制定的初衷是為了使舞臺、劇場等地所使用的眾多的調光器和控制器能相互兼容。雖然它不是一個行業或國家標準, 但是由于它的簡單性和實用性, 自從出臺以來, 得到了世界各地生產商和使用者普遍承認,這個協議在LED控制方面應用很廣泛,利用STM32 USART可以高速傳輸的特性,我們很容易用STM32來實現DMX512協議。(1)數據的格式及傳輸DMX512 協議規定數據以數據包的形式通過異步通訊的方式進行傳輸。每個數據包由若干數據幀組成, 每幀數據包括1 位低電平起始位、8 位數據位和2 位高電平停止位。DMX 協議要求數據傳輸的波特率為250kb/s, 亦即每位的傳輸時間為4us, 每幀數據的傳輸時間為44us, 它支持多達512 幀數據傳輸, 每幀數據與相應的控制支路相對應。數據包的傳送要符合一定的格式和時序要求。為了使接收器能夠分辨出第一幀數據, 每一個數據包以一個不短于88us 的低電平信號為起始信號, 即所謂的“Break”信號, 接收器接收到“Break”信號就準備接受隨后而來的數據幀; 緊接著“Break”信號之后是不短于8us 的高電平信號M. a. b ( Mark after Break) ; 之后就是數據幀。在DMX512 協議中, M. a. b 之后的第一幀數據被稱為“Star-t code”, 在協議中規定其為零, 但在實際應用中可以由生產廠家自己確定其具體的值, 以傳遞特殊消息。“Star-t code”標明其后面的數據是8 位控制信號數據幀。數據幀之間可以有時間間隔, 也可以沒有; 同樣, 數據包之間可以有時間間隔, 也可以沒有。DMX512 協議規定“Break”信號、M. a. b 信號的最短時間, 并規定“Break”信號、M. a. b 信號、數據幀之間及數據包之間的時間間隔的最大值不得超過1s, 否則做出錯處理, 但是DMX512 協議并未對出錯處理做任何規定。為了嚴格實現DMX512 數據的時序要求,“Break”和M. a. b信號我們可以用定時器來實現。具體的UART配置如下:
1. USART_InitStructure.USART_BaudRate= 250000;
2. USART_InitStructure.USART_WordLength = USART_WordLength_8b;
3. USART_InitStructure.USART_StopBits= USART_StopBits_2;
4. USART_InitStructure.USART_Parity = USART_Parity_No;
5. USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
6. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
7. USART_Init(USART1, &USART_InitStructure);
復制代碼
發送DMX512信號過程如下,先把UART的TX腳配置為普通的GPIO并輸出低電平,然后啟動定時器計時88us, 時器到后把TX腳置為高電平并計時8us, 時器到了后在配為UART模式用DMA方式把數據發出。DMX512信號的接收是個難點,一般直接配為UART接收就行,不需要在UART模式和GPIO模式間切換,但需要在接收過程中檢查接收到“Break”信號時的狀態是有幀錯誤出現,并且接收數據全為零,這樣的話可以確認已經收到“Break”信號,隨后數據正常DMA接收就行了。
|