# STM32F429 UART & CAN bus 整合 ###### tags: `Internship`,`NSPO` [TOC] ## Final Project Report 簡介工作細節 :::success 我負責為XTx資料傳輸,XTx在衛星電機次系統功能為向基地台傳送資料,並接受EUCC指令,此6U衛星為傳送圖像資料為主,以下為XTx在本實作整體程序(mode2-3)。 **註解:** 本說明為 **LOOPBACKMODE** 因此未與EUCC連接,是STM32自傳自收 ::: ![](https://i.imgur.com/S2cMkwz.png) ## 工作環境 * OS : Windows 10 * IDE: eclipse(luna版本) * 燒錄軟體: 內建ST-Link * Terminal: hercules_3-2-8.exe * 開發板:STM32F429 Discovery kit :::danger **最終目標 :** 實現CAN bus自傳自收(指令字串)並使用UART與電腦回應狀態。 ::: ## 成果截圖(Terminal): ![](https://i.imgur.com/rMtnQAL.png) ## 1. XTx 簡介 (X-Band Transmitter) 1. 高速資料傳輸 (10 Mbit/s以上) 2. 使用 X 頻段 (8175 – 8215 MHz) 3. 下傳經過壓縮與編碼後的資料至地面基地台 ## 2. 本實作流程 (LOOPBACK MODE) ![](https://i.imgur.com/BLLBy3T.png) ## 3. 本實作程序說明 (LOOPBACK MODE) 將依續說明需要撰寫的程式碼: ### (1) Receive user command using **UART RX_interrupt** :::warning **提醒** :以下啟動函式需要放入`while(1)`迴圈內,才可持續接收CPU指令。 ::: 1. `main.c`: ``` C= if(HAL_UART_Receive_IT(&UartHandle (uint8_t*) aRxBuffer, RXBUFFERSIZE)!= HAL_OK) { //Error_Handler(); } ``` 要注意的是:根據`RXBUFFERSIZE`決定**輸入資料長度**,若長度**小於**Size,則會繼續等待接收,最終會時間超過,很可能會return `HAL_Timeout`因此在一開始有提醒,只能輸入poweron或poweroff,在此專案長度為 **7 bytes**。 2. `HAL_UART_OUT.h`: ```c= #define TXBUFFERSIZE (7)//Unit:byte ``` ### (2) Send data to Earth Station using **RxCallback** (also print messages on terminal to inform user.) :::info 在`HAL_UART_OUT.c`的`HAL_UART_RxCpltCallback`中:將extern的UART_Rx_flag設成1,回到main.c中CPU會進入以下程式碼進行印出poweron動作並flag=1去執行**用CAN BUS傳送資料給地面台** ::: :::danger **注意** :在中斷底層盡量不要進行動作,如DELAY與print,理由如下: 1.中斷內的時間非同步主程式時間。 2.UART中斷也是使用同個暫存器,因此不適合在底層使用print()。 ::: 1. `HAL_UART_OUT.c`: ```c= void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { /* Set transmission flag: transfer complete*/ //UsartReady_0 = SET; UsartReady_Rx = SET; UART_Rx_flag = 1; /*只UART_Rx收到訊息*/ /* Turn LED4 on: Transfer in reception process is correct */ } ``` 2. 在`HAL_UART_out.c`的`STM32f4_UART_Init(UART_HandleTypeDef *huart)`內補上: ``` C= //============= /* NVIC configuration for USART TC interrupt */ HAL_NVIC_SetPriority(USART1_IRQn, 6, 2); HAL_NVIC_EnableIRQ(USART1_IRQn); //============= ``` 代表收到進入中斷 3. Terminal 收到開機指令(power on)->(UART_Rx_flag設成1)進行回報(power on)動作 `main.c`: ```C= if(UART_Rx_flag == 1) { if(aRxBuffer[6]==0x6E) { print_string("power on\r\n"); flag = 1; } else { print_string("power off"); } UART_Rx_flag = 0; } ``` 4. CAN_flag=1時CPU會透過**CAN bus**傳送給地面台(正在傳送DATA) `main.c`: ```C= if(flag == 1) { press_cnt = 0; CanHandle.pTxMsg->StdId = 0x302; CanHandle.pTxMsg->IDE = CAN_ID_STD; CanHandle.pTxMsg->DLC = 1; CanHandle.pTxMsg->Data[0] = TelID(0X01,0X01); if(HAL_CAN_Transmit(&CanHandle, 10) != HAL_OK)//ms { } press_cnt = 0; print_string("CAN TX(0x302):\r\n"); print_u32x(CanHandle.pTxMsg->StdId); if(CAN_flag==1) { BSP_LED_On(LED3); print_string("CAN RX(0x302):\r\n"); print_u32x(CanHandle.pRxMsg->StdId); print_string("DATA Loading.\r\n"); print_string("flag:"); print_u8x(flag); HAL_Delay(1000); BSP_LED_Off(LED3); } } ``` 5. CAN reciever收到訊息後會進入`CAN1_RX0_IRQHandler`並到`HAL_CAN_RxCpltCallback`進行動作 `stm32f4xx_it.c`: ```C= void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef *hcan) { static int digitStatus = 1; if(hcan->pRxMsg->StdId ==0x302) { CAN_flag = 1; flag = 2; } } ``` 注意要開啟中斷分別要有以下兩步驟(CAN bus) * Step1. In `main.c`,enable HAL_CAN_Receive_IT :::warning **注意** :以下啟動函式需要放入`HAL_CAN_RxCpltCallback`,中斷執行結束後,需重複開啟中斷。 ::: ```c= if(HAL_CAN_Receive_IT(&CanHandle, CAN_FIFO0) != HAL_OK) { /* Reception Error */ Error_Handler(); } ``` * Step2. In `stm32f4xx_it.c`: ```c= void CAN1_RX0_IRQHandler(void) { // Get data from CAN HAL_CAN_IRQHandler(&CanHandle); } ``` ### (3) When data loading over use CAN Transmit and CAN Reciever 1. CAN Transmit0x202 and CAN Reciever接收0x202並印出DATA loading over `main.c`: ```C= if(flag == 2) { press_cnt = 0; CanHandle.pTxMsg->StdId = 0x202; CanHandle.pTxMsg->IDE = CAN_ID_STD; CanHandle.pTxMsg->DLC = 1; CanHandle.pTxMsg->Data[0] = TelID(0X03,0X00); if(HAL_CAN_Transmit(&CanHandle, 10) != HAL_OK)//10ms { } press_cnt = 0; print_string("CAN TX(0x202):\r\n"); print_u32x(CanHandle.pTxMsg->StdId); print_string("CAN RX(0x202):\r\n"); print_u32x(CanHandle.pTxMsg->StdId); print_string("DATA loading over.\r\n"); flag = 0; } ``` ## 4. 實作 主要的`main.c`檔案: ```C= /*我的主要code*/ STM32f4_UART_Init(&UartHandle); print_string("UART init done.\r\n"); STM32f4_CAN_Init(&CanHandle, &sFilterConfig, &TxMessage, &RxMessage); print_string("CAN init done.\r\n"); /* Turn LED3 on: Transfer in transmission process is correct */ /* then Off for next transmission */ BSP_LED_On(LED3); HAL_Delay(200); BSP_LED_Off(LED3); print_string("please insert poweron or poweroff.\r\n"); if(HAL_CAN_Receive_IT(&CanHandle, CAN_FIFO0) != HAL_OK) { /* Reception Error */ Error_Handler(); } if(HAL_UART_Receive_IT(&UartHandle, (uint8_t*)aRxBuffer, RXBUFFERSIZE)!= HAL_OK) { //Error_Handler(); } extern int UART_Rx_flag; while(1) { if(flag == 1) { press_cnt = 0; CanHandle.pTxMsg->StdId = 0x302; CanHandle.pTxMsg->IDE = CAN_ID_STD; CanHandle.pTxMsg->DLC = 1; CanHandle.pTxMsg->Data[0] = TelID(0X01,0X01); if(HAL_CAN_Transmit(&CanHandle, 10) != HAL_OK)//0ms { } press_cnt = 0; print_string("CAN TX(0x302):\r\n"); print_u32x(CanHandle.pTxMsg->StdId); if(CAN_flag==1) { BSP_LED_On(LED3); print_string("CAN RX(0x302):\r\n"); print_u32x(CanHandle.pRxMsg->StdId); print_string("DATA Loading.\r\n"); print_string("flag:"); print_u8x(flag); HAL_Delay(1000); BSP_LED_Off(LED3); } } if(flag == 2) { press_cnt = 0; CanHandle.pTxMsg->StdId = 0x202; CanHandle.pTxMsg->IDE = CAN_ID_STD; CanHandle.pTxMsg->DLC = 1; CanHandle.pTxMsg->Data[0] = TelID(0X03,0X00); // print_string("CAN TX SECOND:\r\n"); if(HAL_CAN_Transmit(&CanHandle, 10) != HAL_OK)//0ms { } press_cnt = 0; print_string("CAN TX(0x202):\r\n"); print_u32x(CanHandle.pTxMsg->StdId); print_string("CAN RX(0x202):\r\n"); print_u32x(CanHandle.pTxMsg->StdId); print_string("DATA loading over.\r\n"); flag = 0; } if(UART_Rx_flag == 1) { if(aRxBuffer[6]==0x6E) { print_string("power on\r\n"); flag = 1; } else { print_string("power off"); } UART_Rx_flag = 0; } } /*我的主要code*/ ``` ## 5. 其他初始化或細節注意 :::warning **提醒**: 在使用模擬的Terminal console時: 1.baurate (此範例為9600) 2.STOP bit(此範例為1) 3.Parity bit(此範例為None) 設定要跟`UART_Init()`內的設定一樣才能有效! //// 4.Tx傳送尚未結束即會進行Rx中斷(因為中斷優先權較高),又在Rx中斷下又開Receive,因此Tx和Rx Receive會互鎖,因此修正方式即是將互鎖機制取消。 ::: 互鎖設定取消`HAL_CAN_INIT.h`: ```C= #define CAN_TRANSMIT_UNLOCK (1) #define CAN_RECEIVE_IRQ_UNLOCK (1) ``` ### 附錄:`print("str")` using UART ```c= void print_u8x(uint8_t int8){ uint8_t print_cnt=0; sprintf(UsartTxBuffer_0, "0x%02X\r\n", int8); while(UsartTxBuffer_0[print_cnt]!='\0'){print_cnt++;} HAL_UART_Transmit(&UartHandle, (uint8_t*)UsartTxBuffer_0, print_cnt, 5000); } void print_u32x(unsigned int int32){ uint8_t print_cnt=0; sprintf(UsartTxBuffer_0, "0x%08X\r\n", int32); while(UsartTxBuffer_0[print_cnt]!='\0'){print_cnt++;} HAL_UART_Transmit(&UartHandle, (uint8_t*)UsartTxBuffer_0, print_cnt, 5000); } void print_string_DMA(char str[]){ uint8_t print_cnt=0; sprintf(UsartTxBuffer_0, "%s", str); while(UsartTxBuffer_0[print_cnt]!='\0'){print_cnt++;} HAL_UART_Transmit_DMA(&UartHandle, (uint8_t*)UsartTxBuffer_0, print_cnt); while (UsartReady_0 != SET){} UsartReady_0 = RESET; ``` ###### tags: `NSPO`