日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STM32CubeMX与HAL库学习--简单的CAN回环测试

發布時間:2024/1/1 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32CubeMX与HAL库学习--简单的CAN回环测试 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

STM32CubeMX與HAL庫學習--簡單的CAN回環測試

  • 前言
  • STM32CubeMX生成初始化代碼
  • 在MDK-ARM里編輯代碼
  • 其他
  • 后續

前言

本人小白,最近看了CAN協議與STM32的bxCAN外設的一些資料,簡單地做個CAN回環測試練習一下。這只是一個初學者的簡單練習記錄,學習的話還是要看對應的教程啦。

使用到的工具及版本:
STM32CubeMX版本:6.3.0
HAL庫:STM32CubeF4 Firmware Package V1.26.1
MDK-ARM:V5.32.0.0
開發板:野火的霸天虎開發板V2(主控芯片是STM32F407ZGT6)

大概的框圖如下:

STM32CubeMX生成初始化代碼

時鐘、串口配置之類的略過。
關于CAN配置:

在NVIC那里打開CAN1 RX0中斷允許,并設定一下優先級。

在MDK-ARM里編輯代碼

CAN的設置尚未完成,CubeMX那里只是設置了模式,打開can.c,接下來設置篩選器。我配置的是列表模式,篩選了拓展ID 0x2233和標準ID 0。

/** 函數名:CAN_Filter_Config* 描述 :CAN的過濾器 配置* 輸入 :無* 輸出 : 無* 調用 :內部調用*/ static void CAN_Filter_Config(void) {CAN_FilterTypeDef CAN_FilterTypeDef;/*CAN篩選器初始化*/CAN_FilterTypeDef.FilterBank=0; //篩選器組0CAN_FilterTypeDef.FilterMode=CAN_FILTERMODE_IDLIST; //工作在列表模式CAN_FilterTypeDef.FilterScale=CAN_FILTERSCALE_32BIT; //篩選器位寬為單個32位。/* 使能篩選器,按照標志的內容進行比對篩選,擴展ID不是如下的就拋棄掉,是的話,會存入FIFO0。 */CAN_FilterTypeDef.FilterIdHigh= ((((uint32_t)0x2233<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF0000)>>16; //要篩選的ID高位 CAN_FilterTypeDef.FilterIdLow= (((uint32_t)0x2233<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要篩選的ID低位 CAN_FilterTypeDef.FilterMaskIdHigh= 0; //第二個ID的高位CAN_FilterTypeDef.FilterMaskIdLow= 0; //第二個ID的低位CAN_FilterTypeDef.FilterFIFOAssignment=CAN_FILTER_FIFO0 ; //篩選器被關聯到FIFO0CAN_FilterTypeDef.FilterActivation=ENABLE; //使能篩選器HAL_CAN_ConfigFilter(&hcan1,&CAN_FilterTypeDef); }

發送或者接收數據都有對應的結構體對幀的ID、幀類別、數據長度等進行了描述(CAN_RxHeaderTypeDef、CAN_TxHeaderTypeDef),發送時需要根據數據特性配置發送結構體,接收則是把接收數據的特性存儲到指定的接收結構體。
消息發送函數

獲取接收消息函數

因為只是簡單的測試,我就在初始化階段把他們設置好。
用一個CAN_Config把CAN的功能完整。

__IO uint32_t CAN_RxFlag = 0; //用于標志是否接收到數據,在中斷函數中賦值CAN_TxHeaderTypeDef TxMes; //發送結構體 CAN_RxHeaderTypeDef RxMes; //接收結構體uint8_t CAN_TxDate[9]="CAN LOOP"; //發送緩沖區 uint8_t CAN_RxDate[9]; //接收緩沖區uint32_t TxMailbox; //用于指示CAN消息發送函數HAL_CAN_AddTxMessage使用了哪個郵箱來發送數據/*** @brief 初始化 Rx Message數據結構體* @param RxMessage: 指向要初始化的數據結構體* @retval None*/ void CAN_RxMesInit(CAN_RxHeaderTypeDef* RxMessage) {/*把接收結構體清零*/(*RxMessage).StdId = 0x00;(*RxMessage).ExtId = 0x00;(*RxMessage).IDE = CAN_ID_STD;(*RxMessage).DLC = 0;(*RxMessage).RTR = 0;(*RxMessage).FilterMatchIndex = 0;(*RxMessage).Timestamp = 0; }/** 函數名:CAN_TxMsgInit* @brief 初始化TxMessage數據結構體* @param TxMessage: 指向要初始化的數據結構體* @retval None*/ void CAN_TxMsgInit(CAN_TxHeaderTypeDef* TxMessage) { (*TxMessage).StdId=0x00; (*TxMessage).ExtId=0x2233; //使用的擴展ID(*TxMessage).IDE=CAN_ID_EXT; //擴展模式(*TxMessage).RTR=CAN_RTR_DATA; //發送的是數據(*TxMessage).DLC=8; //數據長度為8字節 }/** 函數名:CAN_Config* 描述 :完整配置CAN的功能* 輸入 :無* 輸出 : 無* 調用 :MX的CAN初始化調用*/ void CAN_Config(void) {CAN_Filter_Config();CAN_TxMsgInit(&TxMes); CAN_RxMesInit(&RxMes);HAL_CAN_ActivateNotification(&hcan1,CAN_IT_RX_FIFO0_MSG_PENDING); //使能FIFO0接收到數據中斷HAL_CAN_Start(&hcan1); //開啟CAN1 }

在CubeMX生成的CAN1初始化函數中調用自己寫的CAN_Config(),完成CAN的設置并開啟它。

FIFO0接收到數據的中斷回調函數與CAN錯誤回調函數如下。

/*** @brief CAN接收完成中斷(非阻塞) * @param hcan: CAN句柄指針* @retval 無*/ void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef* hcan) {/* 比較ID是否為0x2233 */HAL_CAN_GetRxMessage(&hcan1,CAN_RX_FIFO0,&RxMes,CAN_RxDate);if((RxMes.ExtId==0x2233) && (RxMes.IDE==CAN_ID_EXT) && (RxMes.DLC==8) ){CAN_RxFlag = 1; //接收成功 }else{CAN_RxFlag = 0; //接收失敗} } /*** @brief CAN錯誤回調函數* @param hcan: CAN句柄指針* @retval 無*/ void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan) {printf("\r\nCAN出錯\r\n"); }

main函數。

/* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ extern __IO uint32_t CAN_RxFlag; //用于標志是否接收到數據,在中斷函數中賦值extern uint8_t CAN_TxDate[9]; //發送緩沖區 extern uint8_t CAN_RxDate[9]; //接收緩沖區extern CAN_TxHeaderTypeDef TxMes; //發送結構體 extern CAN_RxHeaderTypeDef RxMes; //接收結構體 extern uint32_t TxMailbox; //用于指示CAN消息發送函數HAL_CAN_AddTxMessage使用了哪個郵箱來發送數據 /* USER CODE END 0 *//*** @brief The application entry point.* @retval int*/ int main(void) {/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();MX_CAN1_Init();/* Initialize interrupts */MX_NVIC_Init();/* USER CODE BEGIN 2 */printf("CAN LOOP TEST\r\n");HAL_CAN_AddTxMessage(&hcan1, &TxMes, CAN_TxDate, &TxMailbox); //發送數據/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */if(CAN_RxFlag){CAN_RxFlag = 0;printf("Transmit message:%s\r\n",CAN_TxDate);printf("Receive message:%s\r\n",CAN_RxDate);}/* USER CODE BEGIN 3 */}/* USER CODE END 3 */ }

效果

其他

最初,我把發送數組和接收數組的長度設為8

uint8_t CAN_TxDate[8]="CAN LOOP"; //發送緩沖區 uint8_t CAN_RxDate[8]; //接收緩沖區

結果是這樣:

不出意外的話這兩個數組在內存中是這樣的(注:其實可以在map文件里查看具體地址):

如果只是用來存儲CAN數據這倒是沒什么問題,但是用printf把它們作為字符數組輸出的話就可能會像圖中一樣越界了。
所以我把這兩個數組長度定義為9,0~7字節是數據,第8字節一直是0(編譯器給它初始化為0),這樣就可以防止printf輸出越界。

后續

接下來,在原來的基礎上增加一個按鍵,把按鍵按下次數轉換為字符串存儲到CAN_TxDate數組,并在按鍵按下的中斷里通過CAN發送,其他基本與上文無異,我的實現步驟如下:
首先打開原來的CubeMX工程文件,找到按鍵的引腳,把它配置為外部中斷

使能中斷

然后就可以生成代碼了,別忘了勾選保留用戶代碼

寫在用戶區域的代碼會得以保留,寫的時候注意一下位置,我前面while循環里的代碼寫錯位置了,重新生成文件時就被刪了。
正確的位置

/* Infinite loop *//* USER CODE BEGIN WHILE */while (1){if(CAN_RxFlag){CAN_RxFlag = 0;printf("Transmit message:%s\r\n",CAN_TxDate);printf("Receive message:%s\r\n",CAN_RxDate);}/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}

錯誤的位置

/* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */if(CAN_RxFlag){CAN_RxFlag = 0;printf("Transmit message:%s\r\n",CAN_TxDate);printf("Receive message:%s\r\n",CAN_RxDate);}/* USER CODE BEGIN 3 */}/* USER CODE END 3 */

其實看注釋名字就知道了。
在main.c里增加了按鍵中斷的回調函數。

//按鍵中斷 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {static uint16_t KeyTime = 0;if(GPIO_Pin == KEY1_Pin){KeyTime++;sprintf((char*)CAN_TxDate,"%d",KeyTime);HAL_CAN_AddTxMessage(&hcan1, &TxMes, CAN_TxDate, &TxMailbox); //發送數據} }

刪除了main函數里的CAN數據發送HAL_CAN_AddTxMessage(&hcan1, &TxMes, CAN_TxDate, &TxMailbox);
這樣,數據只在按鍵按下時發送,其他不變。
結果

總結

以上是生活随笔為你收集整理的STM32CubeMX与HAL库学习--简单的CAN回环测试的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。