CAN基礎(chǔ)知識介紹文中介紹了CAN協(xié)議相關(guān)的基礎(chǔ)知識,以及STM32F4芯片的CAN控制器相關(guān)知識,下面將通過實例,利用STM32CubeMX圖形化配置工具,并配合CAN盒,來實現(xiàn)CAN通訊的中斷收發(fā)測試
1. STM32CubeMX配置
? CAN是掛載在APB1總線上,設(shè)置PCLK1時鐘頻率到最大45MHz
? 激活CAN1,配置位時序參數(shù),其他基本參數(shù)以及工作模式(此處設(shè)置為Normal普通模式)
CAN波特率的計算公式:只需要知道BS1和BS2的設(shè)置,以及APB1的時鐘頻率,就可以方便的計算出波特率。比如設(shè)置TS1=8、TS2=6和BRP=6,在APB1頻率為45Mhz的條件下,即可得到CAN通信的波特率=45000/6/(8+6+1)=500Kbps
? 激活USART1作為調(diào)試串口,配置相關(guān)LED對應(yīng)的GPIO引腳作為指示燈
2.?MDK-ARM編程
2.1 幾個重要的結(jié)構(gòu)體
? CAN 初始化結(jié)構(gòu)體:此結(jié)構(gòu)體內(nèi)容,可由STM32CubeMX工具進行配置
typedef?struct
{
??uint32_t?Prescaler;???????/*?配置?CAN?外設(shè)的時鐘分頻,可設(shè)置為?1-1024*/
??uint32_t?Mode;????????????/*?配置?CAN?的工作模式,回環(huán)或正常模式?*/
??uint32_t?SyncJumpWidth;???/*?配置?SJW?極限值?*/
??uint32_t?TimeSeg1;????????/*?配置?BS1?段長度?*/
??uint32_t?TimeSeg2;????????/*?配置?BS2?段長度?*/
??FunctionalState?TimeTriggeredMode;????/*?是否使能?TTCM?時間觸發(fā)功能?*/
??FunctionalState?AutoBusOff;???????????/*?是否使能?ABOM?自動離線管理功能?*/
??FunctionalState?AutoWakeUp;????????? /*?是否使能?AWUM?自動喚醒功能?*/
??FunctionalState?AutoRetransmission;???/*?是否使能?NART?自動重傳功能?*/
??FunctionalState?ReceiveFifoLocked;????/*?是否使能?RFLM?鎖定?FIFO?功能?*/
??FunctionalState?TransmitFifoPriority;?/*?配置?TXFP?報文優(yōu)先級的判定方法?*/
}?CAN_InitTypeDef;
? 發(fā)送及接收頭結(jié)構(gòu)體:主要用于構(gòu)造發(fā)送報文,以及接收報文。收發(fā)發(fā)文時,需要自定義頭結(jié)構(gòu)體變量
typedef?struct
{
??uint32_t?StdId;??????/*?存儲報文的標準標識符?11?位,0-0x7FF?*/
??uint32_t?ExtId;??????/*?存儲報文的擴展標識符?29?位,0-0x1FFFFFFF?*/
??uint32_t?IDE;????????/*?存儲?IDE?擴展標志?*/
??uint32_t?RTR;????????/*?存儲?RTR?遠程幀標志?*/
??uint32_t?DLC;????????/*?存儲報文數(shù)據(jù)段的長度,0-8?*/
??FunctionalState?TransmitGlobalTime;?
}?CAN_TxHeaderTypeDef;
typedef?struct
{
??uint32_t?StdId;??????/*?存儲報文的標準標識符?11?位,0-0x7FF.?*/
??uint32_t?ExtId;??????/*?存儲報文的擴展標識符?29?位,0-0x1FFFFFFF?*/
??uint32_t?IDE;????????/*?存儲?IDE?擴展標志?*/
??uint32_t?RTR;????????/*?存儲?RTR?遠程幀標志?*/
??uint32_t?DLC;????????/*?存儲報文數(shù)據(jù)段的長度,0-8?*/
??uint32_t?Timestamp;?
??uint32_t?FilterMatchIndex;?
}?CAN_RxHeaderTypeDef;
? 過濾器結(jié)構(gòu)體:STM32CubeMX不會初始化過濾器的相關(guān)內(nèi)容,需要自己添加
typedef?struct
{
??uint32_t?FilterIdHigh;?????????/*CAN_FxR1?寄存器的高?16?位?*/
??uint32_t?FilterIdLow;??????????/*CAN_FxR1?寄存器的低?16?位?*/
??uint32_t?FilterMaskIdHigh;?????/*CAN_FxR2?寄存器的高?16?位?*/
??uint32_t?FilterMaskIdLow;??????/*CAN_FxR2?寄存器的低?16?位?*/
??uint32_t?FilterFIFOAssignment;?/*?設(shè)置經(jīng)過篩選后數(shù)據(jù)存儲到哪個接收?FIFO?*/
??uint32_t?FilterBank;???????????/*?篩選器編號,范圍0-27,CAN1是0-13,CAN2是14-27?*/
??uint32_t?FilterMode;???????????/*?篩選器模式?*/
??uint32_t?FilterScale;??????????/*?設(shè)置篩選器的尺度?*/
??uint32_t?FilterActivation;?????/*?是否使能本篩選器?*/
??uint32_t?SlaveStartFilterBank;?/*?CAN2起始過濾器組?*/
}?CAN_FilterTypeDef;
2.2 程序編寫
? 生成工程后,打開can.c文件,可見STM32CubeMX已經(jīng)對位時序參數(shù)、其他基本參數(shù)以及工作模式進行了初始化。但是并沒有初始化過濾器的相關(guān)內(nèi)容,因此需要我們自己添加,并在CAN初始化時調(diào)用
//下面的設(shè)置只使能了FIFO0,并不過濾任何消息
void?CAN_Filter_Config(){
? CAN_FilterTypeDef?sFilterConfig;
?
?sFilterConfig.FilterBank?=?0;??????//篩選器編號,?CAN1是0-13,?CAN2是14-27
?sFilterConfig.FilterMode?=?CAN_FILTERMODE_IDMASK;?//采用掩碼模式
?sFilterConfig.FilterScale?=?CAN_FILTERSCALE_32BIT;?//設(shè)置篩選器的尺度,?采用32位
?sFilterConfig.FilterIdHigh?=?0X0000;????//過濾器ID高16位,即CAN_FxR1寄存器的高16位
?sFilterConfig.FilterIdLow?=?0X0000;?????//過濾器ID低16位,即CAN_FxR1寄存器的低16位
?sFilterConfig.FilterMaskIdHigh?=?0X0000;???//過濾器掩碼高16位,即CAN_FxR2寄存器的高16位
?sFilterConfig.FilterMaskIdLow?=?0X0000;????//過濾器掩碼低16位,即CAN_FxR2寄存器的低16位
?sFilterConfig.FilterFIFOAssignment?=?CAN_RX_FIFO0;?//設(shè)置經(jīng)過篩選后數(shù)據(jù)存儲到哪個接收FIFO
? sFilterConfig.FilterActivation?=?ENABLE;???//是否使能本篩選器
? sFilterConfig.SlaveStartFilterBank?=?14;???//指定為CAN1分配多少個濾波器組
?
?if(HAL_CAN_ConfigFilter(&hcan1,?&sFilterConfig)?!=?HAL_OK)
? {
?? Error_Handler();
? }
}
? 編寫發(fā)送和接收數(shù)據(jù)函數(shù):此處將格式固定為標準數(shù)據(jù)幀,ID為12
uint8_t?CAN1_Send_Msg(uint8_t?*msg,?uint8_t?len){
? uint16_t?i?=?0;
? uint32_t?txMailBox;
? uint8_t?send_buf[8];
?
?txHeader.StdId?=?12;
?txHeader.ExtId?=?12;
? txHeader.IDE?=?CAN_ID_STD;
? txHeader.RTR?=?CAN_RTR_DATA;
? txHeader.DLC?=?len;
?
? for(i?=?0;?i?<?len;?i++)
?? send_buf[i]?=?msg[i];
?
? if(HAL_CAN_AddTxMessage(&hcan1,?&txHeader,?send_buf,?&txMailBox)?!=?HAL_OK)
?? return?1;?
? return?0;
}
void?HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef?*hcan){
? uint16_t?i?=?0;
? uint8_t?buf[8]?=?{0};
?
? if(hcan->Instance?==?CAN1){
?? printf("*******************************rn");
?? printf("Recv?via?STM32F429?Interruptrn");
?
?? HAL_CAN_GetRxMessage(&hcan1,?CAN_RX_FIFO0,?&rxHeader,?buf);
?
?? if(rxHeader.IDE?==?CAN_ID_STD)
??? printf("StdId?ID:?%dn",?rxHeader.StdId);
?? else
??? printf("ExtId?ID:?%dn",?rxHeader.ExtId);
?? printf("rn");
?? printf("CAN?IDE:?%dn",?rxHeader.IDE);printf("rn");
?? printf("CAN?RTR:?%dn",?rxHeader.RTR);printf("rn");
?? printf("CAN?DLC:?%dn",?rxHeader.DLC);printf("rn");
?? printf("Recv?Data:?");
?
?? for(i?=?0;?i?<?rxHeader.DLC;?i++)
??? printf("%c?",buf[i]);
?
?? printf("rn");
?? printf("*******************************rn");
? }
}
? 默認Cubemx生成的代碼并沒有can start,沒有調(diào)用HAL_CAN_Start(&hcan1) 來使能CAN,因此需要在CAN初始化代碼中添加
void?MX_CAN1_Init(void){
?......
?/*?USER?CODE?BEGIN?CAN1_Init?2?*/
?CAN_Filter_Config();
? HAL_CAN_Start(&hcan1);?
?HAL_CAN_ActivateNotification(&hcan1,?CAN_IT_RX_FIFO0_MSG_PENDING);
??/*?USER?CODE?END?CAN1_Init?2?*/
}
? 主函數(shù)main.c中,代碼如下
int?main(void){
??HAL_Init();
??SystemClock_Config();
??MX_GPIO_Init();
??MX_CAN1_Init();
??MX_USART1_UART_Init();
???/*?USER?CODE?BEGIN?2?*/
? uint8_t?ret;
? printf("CAN?Testing....!rn");
? uint8_t?txdata[8]?=?{78,?79,?82,?77,?65,?76,?33,?32};
??/*?USER?CODE?END?2?*/
??/*?Infinite?loop?*/
??/*?USER?CODE?BEGIN?WHILE?*/
??while?(1)
??{
?? HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_1);
?? printf("Start?Send?data...rn");
??
?? ret?=?CAN1_Send_Msg(txdata,?8);
?? if(ret?==?0)
??? printf("STM32F429?CAN?Send?success!rn");
?? else?
??? printf("STM32F429?CAN?Send?failed!rn");
??
?? HAL_Delay(3000);
????/*?USER?CODE?END?WHILE?*/
????/*?USER?CODE?BEGIN?3?*/
??}
??/*?USER?CODE?END?3?*/
}
3. 下載測試
將CAN盒與STM32的CAN接口連接起來,CAN盒連接電腦,使用CAN調(diào)試軟件接收和發(fā)送數(shù)據(jù),如下圖示
STM32工程編譯無誤后,下載到開發(fā)板,可以看到系統(tǒng)運行時D1指示燈不斷閃爍,串口不斷的打印STM32發(fā)送CAN消息成功的信息。使用CAN調(diào)試軟件,可以看到CAN盒接收到了STM32發(fā)出的數(shù)據(jù)。使用調(diào)試軟件,發(fā)送CAN數(shù)據(jù)給STM32
串口調(diào)試助手中可以看到,STM32通過中斷接收到了CAN盒發(fā)來的數(shù)據(jù)