STM32F7xx —— CAN通信
生活随笔
收集整理的這篇文章主要介紹了
STM32F7xx —— CAN通信
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? STM32F7xx —— CAN通信
?
目錄
STM32F7xx —— CAN通信
一、CAN基礎
二、幾個重要的CAN函數
三、幾個重要的結構
四、接口設計
?
?
一、CAN基礎
差分信號:顯性電平對應邏輯0,CAN_H和CAN_L差為2.5V;隱形電平對應邏輯1,CAN_H和CAN_L差為0V。
CAN總線的開始和結束都有一個120Ω的終端電阻。
數據幀:標準幀11位,? 擴展幀29位。
其他的一些理論知識就不再贅述了,可以參考維基百科對于CAN的描述。
STM32F7xx的bxCAN主要特點:支持CAN2.0A和CAN2.0B,波特率高達1Mbps,支持時間觸發,具有3個發送郵箱,2個接收郵箱,可變的過濾器組等。
?
二、幾個重要的CAN函數
HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef* hcan); // CAN初始化HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout); // CAN發送HAL_StatusTypeDef HAL_CAN_Receive(CAN_HandleTypeDef *hcan, uint8_t FIFONumber, uint32_t Timeout); // CAN接收三、幾個重要的結構
// CAN操作句柄 包含CAN基地址(CAN1/CAN2/CAN3) 初始化結構 發送接收結構體 其余三個是過程變量 typedef struct {CAN_TypeDef *Instance; /*!< Register base address */CAN_InitTypeDef Init; /*!< CAN required parameters */CanTxMsgTypeDef* pTxMsg; /*!< Pointer to transmit structure */CanRxMsgTypeDef* pRxMsg; /*!< Pointer to reception structure */__IO HAL_CAN_StateTypeDef State; /*!< CAN communication state */HAL_LockTypeDef Lock; /*!< CAN locking object */__IO uint32_t ErrorCode; /*!< CAN Error code */}CAN_HandleTypeDef; // CAN配置結構體 // 前5個參數來設置 CAN_BTR —— 波特率 // 后6個參數用來設置 CAN_MCR —— 通信相關的控制位 typedef struct {uint32_t Prescaler; /*!< Specifies the length of a time quantum.This parameter must be a number between Min_Data = 1 and Max_Data = 1024 */uint32_t Mode; /*!< Specifies the CAN operating mode.This parameter can be a value of @ref CAN_operating_mode */uint32_t SJW; /*!< Specifies the maximum number of time quantathe CAN hardware is allowed to lengthen orshorten a bit to perform resynchronization.This parameter can be a value of @ref CAN_synchronisation_jump_width */uint32_t BS1; /*!< Specifies the number of time quanta in Bit Segment 1.This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_1 */uint32_t BS2; /*!< Specifies the number of time quanta in Bit Segment 2.This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_2 */uint32_t TTCM; /*!< Enable or disable the time triggered communication mode.This parameter can be set to ENABLE or DISABLE. */uint32_t ABOM; /*!< Enable or disable the automatic bus-off management.This parameter can be set to ENABLE or DISABLE */uint32_t AWUM; /*!< Enable or disable the automatic wake-up mode.This parameter can be set to ENABLE or DISABLE */uint32_t NART; /*!< Enable or disable the non-automatic retransmission mode.This parameter can be set to ENABLE or DISABLE */uint32_t RFLM; /*!< Enable or disable the receive FIFO Locked mode.This parameter can be set to ENABLE or DISABLE */uint32_t TXFP; /*!< Enable or disable the transmit FIFO priority.This parameter can be set to ENABLE or DISABLE */ }CAN_InitTypeDef; // 過濾器設置 typedef struct {uint32_t FilterIdHigh; /*!< Specifies the filter identification number (MSBs for a 32-bitconfiguration, first one for a 16-bit configuration).This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */uint32_t FilterIdLow; /*!< Specifies the filter identification number (LSBs for a 32-bitconfiguration, second one for a 16-bit configuration).This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */uint32_t FilterMaskIdHigh; /*!< Specifies the filter mask number or identification number,according to the mode (MSBs for a 32-bit configuration,first one for a 16-bit configuration).This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */uint32_t FilterMaskIdLow; /*!< Specifies the filter mask number or identification number,according to the mode (LSBs for a 32-bit configuration,second one for a 16-bit configuration).This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */uint32_t FilterFIFOAssignment; /*!< Specifies the FIFO (0 or 1) which will be assigned to the filter.This parameter can be a value of @ref CAN_filter_FIFO */uint32_t FilterNumber; /*!< Specifies the filter which will be initialized.This parameter must be a number between Min_Data = 0 and Max_Data = 27 */uint32_t FilterMode; /*!< Specifies the filter mode to be initialized.This parameter can be a value of @ref CAN_filter_mode */uint32_t FilterScale; /*!< Specifies the filter scale.This parameter can be a value of @ref CAN_filter_scale */uint32_t FilterActivation; /*!< Enable or disable the filter.This parameter can be set to ENABLE or DISABLE. */uint32_t BankNumber; /*!< Select the start slave bank filter.This parameter must be a number between Min_Data = 0 and Max_Data = 28 */}CAN_FilterConfTypeDef; // 模式 我們使用普通模式 #define CAN_MODE_NORMAL ((uint32_t)0x00000000U) /*!< Normal mode */ #define CAN_MODE_LOOPBACK ((uint32_t)CAN_BTR_LBKM) /*!< Loopback mode */ #define CAN_MODE_SILENT ((uint32_t)CAN_BTR_SILM) /*!< Silent mode */ #define CAN_MODE_SILENT_LOOPBACK ((uint32_t)(CAN_BTR_LBKM | CAN_BTR_SILM)) /*!< Loopback combined with silent mode */ // 標準幀 擴展幀 #define CAN_ID_STD ((uint32_t)0x00000000U) /*!< Standard Id */ #define CAN_ID_EXT ((uint32_t)0x00000004U) /*!< Extended Id */ // 數據幀 遠程幀 #define CAN_RTR_DATA ((uint32_t)0x00000000U) /*!< Data frame */ #define CAN_RTR_REMOTE ((uint32_t)0x00000002U) /*!< Remote frame */ // CAN中斷使能 __HAL_CAN_ENABLE_IT(__HANDLE__, __INTERRUPT__) // 接收中斷 #define CAN_IT_FMP0 ((uint32_t)CAN_IER_FMPIE0) /*!< FIFO 0 message pending interrupt */ #define CAN_IT_FF0 ((uint32_t)CAN_IER_FFIE0) /*!< FIFO 0 full interrupt */ #define CAN_IT_FOV0 ((uint32_t)CAN_IER_FOVIE0) /*!< FIFO 0 overrun interrupt */ #define CAN_IT_FMP1 ((uint32_t)CAN_IER_FMPIE1) /*!< FIFO 1 message pending interrupt */ #define CAN_IT_FF1 ((uint32_t)CAN_IER_FFIE1) /*!< FIFO 1 full interrupt */ #define CAN_IT_FOV1 ((uint32_t)CAN_IER_FOVIE1) /*!< FIFO 1 overrun interrupt */四、接口設計
與串口類似,使用中斷接收。先封裝單路CAN需要的幾個小接口,再頂一個列表,最后使用統一的接口掃描這個列表。
typedef enum {CAN_CHANNEL_NONE,CAN_CHANNEL_1,CAN_CHANNEL_2,CAN_CHANNEL_NUM } can_channel_t;#define CAN1_CHANNEL CAN1 #define CAN1_PREEMPT_PRIO CAN1_RX_PRIORITY #define CAN1_RX_IRQ CAN1_RX0_IRQn #define CAN1_RX_IRQ_FUNC CAN1_RX0_IRQHandler #define CAN1_CLK_ENABLE() __HAL_RCC_CAN1_CLK_ENABLE() #define CAN1_TX_PORT GPIOA #define CAN1_TX_PIN GPIO_PIN_12 #define CAN1_TX_AF GPIO_AF9_CAN1 #define CAN1_TX_CONFIG() GPIOConfigExt(CAN1_TX_PORT, CAN1_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_TX_AF) #define CAN1_RX_PORT GPIOA #define CAN1_RX_PIN GPIO_PIN_11 #define CAN1_RX_AF GPIO_AF9_CAN1 #define CAN1_RX_CONFIG() GPIOConfigExt(CAN1_RX_PORT, CAN1_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_RX_AF)#define CAN2_CHANNEL CAN2 #define CAN2_PREEMPT_PRIO CAN2_RX_PRIORITY #define CAN2_RX_IRQ CAN2_RX0_IRQn #define CAN2_RX_IRQ_FUNC CAN2_RX0_IRQHandler #define CAN2_CLK_ENABLE() __HAL_RCC_CAN2_CLK_ENABLE() #define CAN2_TX_PORT GPIOB #define CAN2_TX_PIN GPIO_PIN_6 #define CAN2_TX_AF GPIO_AF9_CAN2 #define CAN2_TX_CONFIG() GPIOConfigExt(CAN2_TX_PORT, CAN2_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN2_TX_AF) #define CAN2_RX_PORT GPIOB #define CAN2_RX_PIN GPIO_PIN_5 #define CAN2_RX_AF GPIO_AF9_CAN2 #define CAN2_RX_CONFIG() GPIOConfigExt(CAN2_RX_PORT, CAN2_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN2_RX_AF) // 抽象出一個CAN設備結構體 typedef struct {CAN_HandleTypeDef handle; // CAN操作句柄CanTxMsgTypeDef tx; // CAN發送CanRxMsgTypeDef rx; // CAN接收can_queue_t recv; // 接收隊列} can_dev_t; // 將每路CAN封裝成幾個小函數 static can_dev_t can1_dev, can2_dev;static void can1_var_init(void) {can1_dev.recv = can1_queue_recv;CanQueueInit(&can1_dev.recv); }static void can1_gpio_init(void) {CAN1_TX_CONFIG();CAN1_RX_CONFIG(); }// 波特率 = Fpclk1 / ((ts1+ts2+3) * brp) Fpclk1 = 54M static void can1_mode_init(void) {CAN1_CLK_ENABLE();can1_dev.handle.Instance = CAN1_CHANNEL;can1_dev.handle.pTxMsg = &can1_dev.tx;can1_dev.handle.pRxMsg = &can1_dev.rx;can1_dev.handle.Init.Prescaler = 6;can1_dev.handle.Init.Mode = CAN_MODE_NORMAL;can1_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳躍寬度(Tsjw)為tsjw+1個時間單位 CAN_SJW_1TQ~CAN_SJW_4TQcan1_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范圍CAN_BS1_1TQ~CAN_BS1_16TQcan1_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范圍CAN_BS2_1TQ~CAN_BS2_8TQcan1_dev.handle.Init.TTCM = DISABLE; // 非時間觸發通信模式can1_dev.handle.Init.ABOM = ENABLE; // 軟件自動離線管理can1_dev.handle.Init.AWUM = DISABLE; // 睡眠模式通過軟件喚醒(清除CAN->MCR的SLEEP位)can1_dev.handle.Init.NART = ENABLE; // 禁止報文自動傳送can1_dev.handle.Init.RFLM = DISABLE; // 報文不鎖定,新的覆蓋舊的can1_dev.handle.Init.TXFP = DISABLE; // 優先級由報文標識符決定HAL_CAN_Init(&can1_dev.handle); }static void can1_filter_init(void) {CAN_FilterConfTypeDef filter;filter.FilterNumber = 0; // 過濾器0filter.FilterMode = CAN_FILTERMODE_IDMASK;filter.FilterScale = CAN_FILTERSCALE_32BIT;filter.FilterIdHigh = 0;filter.FilterIdLow = 0;filter.FilterMaskIdHigh = 0;filter.FilterMaskIdLow = 0;filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 過濾器0關聯到FIFO0filter.FilterActivation = ENABLE; //激活濾波器0//filter.BankNumber=14;HAL_CAN_ConfigFilter(&can1_dev.handle, &filter); }static void can1_nvic_init(void) {__HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0); //FIFO0消息掛號中斷允許.HAL_NVIC_SetPriority(CAN1_RX_IRQ, CAN1_RX_PRIORITY, 0);HAL_NVIC_EnableIRQ(CAN1_RX_IRQ); }static void can2_var_init(void) {can2_dev.recv = can2_queue_recv;CanQueueInit(&can2_dev.recv); }static void can2_gpio_init(void) {CAN2_TX_CONFIG();CAN2_RX_CONFIG(); }// 波特率 = Fpclk1 / ((ts1+ts2+3) * brp) Fpclk1 = 54M static void can2_mode_init(void) {CAN2_CLK_ENABLE();can2_dev.handle.Instance = CAN2_CHANNEL;can2_dev.handle.Init.Prescaler = 6;can2_dev.handle.Init.Mode = CAN_MODE_LOOPBACK;can2_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳躍寬度(Tsjw)為tsjw+1個時間單位 CAN_SJW_1TQ~CAN_SJW_4TQcan2_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范圍CAN_BS1_1TQ~CAN_BS1_16TQcan2_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范圍CAN_BS2_1TQ~CAN_BS2_8TQcan2_dev.handle.Init.TTCM = DISABLE; // 非時間觸發通信模式can2_dev.handle.Init.ABOM = ENABLE; // 軟件自動離線管理can2_dev.handle.Init.AWUM = DISABLE; // 睡眠模式通過軟件喚醒(清除CAN->MCR的SLEEP位)can2_dev.handle.Init.NART = ENABLE; // 禁止報文自動傳送can2_dev.handle.Init.RFLM = DISABLE; // 報文不鎖定,新的覆蓋舊的can2_dev.handle.Init.TXFP = DISABLE; // 優先級由報文標識符決定HAL_CAN_Init(&can2_dev.handle); }static void can2_filter_init(void) {CAN_FilterConfTypeDef CAN_FilterInitStructure;CAN_FilterInitStructure.FilterNumber = 14;CAN_FilterInitStructure.FilterMode = CAN_FILTERMODE_IDMASK;CAN_FilterInitStructure.FilterScale = CAN_FILTERSCALE_32BIT;CAN_FilterInitStructure.FilterIdHigh = 0;CAN_FilterInitStructure.FilterIdLow = 0;CAN_FilterInitStructure.FilterMaskIdHigh = 0;CAN_FilterInitStructure.FilterMaskIdLow = 0;CAN_FilterInitStructure.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 過濾器0關聯到FIFO0CAN_FilterInitStructure.FilterActivation = ENABLE; //激活濾波器0//CAN_FilterInitStructure.BankNumber=14;HAL_CAN_ConfigFilter(&can2_dev.handle, &CAN_FilterInitStructure); }static void can2_nvic_init(void) {__HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0); //FIFO0消息掛號中斷允許1HAL_NVIC_SetPriority(CAN2_RX_IRQ, CAN2_RX_PRIORITY, 0);HAL_NVIC_EnableIRQ(CAN2_RX_IRQ); } // 每路CAN都有的幾個操作,使用列表包含,然后統一掃描處理 typedef struct {uint8_t channel;can_dev_t *dev;void (* var_init_cb)(void);void (* gpio_init_cb)(void);void (* mode_init_cb)(void);void (* filter_init_cb)(void);void (* nvic_init_cb)(void); } can_config_t;static const can_config_t can_configs[] = {{CAN_CHANNEL_1, &can1_dev, can1_var_init, can1_gpio_init, can1_mode_init, can1_filter_init, can1_nvic_init},{CAN_CHANNEL_2, &can2_dev, can2_var_init, can2_gpio_init, can2_mode_init, can2_filter_init, can2_nvic_init}, };static can_dev_t *can_dev_get(uint8_t channel) {uint8_t i;for(i = 0; i < ARRAY_SIZE(can_configs); ++i){if(channel == can_configs[i].channel){return can_configs[i].dev;}}return 0; }static void can_var_init(uint8_t channel) {uint8_t i;for(i = 0; i < ARRAY_SIZE(can_configs); ++i){if(channel == can_configs[i].channel){can_configs[i].var_init_cb();return;}} }static void can_gpio_init(uint8_t channel) {uint8_t i;for(i = 0; i < ARRAY_SIZE(can_configs); ++i){if(channel == can_configs[i].channel){can_configs[i].gpio_init_cb();return;}} }static void can_mode_init(uint8_t channel) {uint8_t i;for(i = 0; i < ARRAY_SIZE(can_configs); ++i){if(channel == can_configs[i].channel){can_configs[i].mode_init_cb();return;}} }static void can_filter_init(uint8_t channel) {uint8_t i;for(i = 0; i < ARRAY_SIZE(can_configs); ++i){if(channel == can_configs[i].channel){can_configs[i].filter_init_cb();return;}} }static void can_nvic_init(uint8_t channel) {uint8_t i;for(i = 0; i < ARRAY_SIZE(can_configs); ++i){if(channel == can_configs[i].channel){can_configs[i].nvic_init_cb();return;}} } // 對外的接口 初始化 發送和接收 void CanInit(uint8_t channel) {can_var_init(channel);can_gpio_init(channel);can_mode_init(channel);can_filter_init(channel);can_nvic_init(channel); }void CanSend(uint8_t channel, can_frame_t *frame) {can_dev_t *dev = can_dev_get(channel);if(dev == 0){return;}dev->handle.pTxMsg->StdId = frame->StdId;dev->handle.pTxMsg->IDE = frame->IDE;dev->handle.pTxMsg->RTR = frame->RTR;dev->handle.pTxMsg->DLC = frame->DLC;memcpy(dev->handle.pTxMsg->Data, frame->Data, frame->DLC);HAL_CAN_Transmit(&dev->handle, 10); }uint8_t CanRecv(uint8_t channel, can_frame_t *frame) {can_dev_t *dev = can_dev_get(channel);if(dev == 0){return 0;}return CanQueueRead(&can1_dev.recv, frame); } // CAN中斷 void CAN1_RX_IRQ_FUNC(void) {HAL_CAN_IRQHandler(&can1_dev.handle); }void CAN2_RX_IRQ_FUNC(void) {HAL_CAN_IRQHandler(&can2_dev.handle); }void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef *hcan) {if(hcan == (&can1_dev.handle)){//CAN_Receive_IT()函數會關閉FIFO0消息掛號中斷,因此我們需要重新打開__HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0);//重新開啟FIF00消息掛號中斷CanQueueWrite(&can1_dev.recv, can1_dev.handle.pRxMsg);}else if(hcan == (&can2_dev.handle)){//CAN_Receive_IT()函數會關閉FIFO0消息掛號中斷,因此我們需要重新打開__HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0);//重新開啟FIF00消息掛號中斷CanQueueWrite(&can2_dev.recv, can2_dev.handle.pRxMsg);} }? ? ? ? 之所以使用列表的形式,是為了方便增加和刪除CAN通道和使對外的接口更統一,不會出現CAN1Init() CAN2Init(),個人習慣問題。
CAN隊列可參考:CAN隊列
?
?
?
總結
以上是生活随笔為你收集整理的STM32F7xx —— CAN通信的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pythontuple([1、2、3)_
- 下一篇: linux java远程调试_idea远