??最近在使用can總線,由于這個(gè)以前接觸的比較少,所以調(diào)試代碼的時(shí)候直接是下載的正點(diǎn)原子的例程,在這個(gè)基礎(chǔ)上修改調(diào)試的。現(xiàn)在將調(diào)試中遇到的問題,總結(jié)一下,避免以后踩坑。目前寫了一個(gè)查詢方式的,一個(gè)中斷方式的。項(xiàng)目代碼下載地址:
https://download.csdn.net/download/qq_20222919/87793221
查詢方式
??首先說查詢模式,查詢模式直接使用原子的例程就可以使用。初始化代碼如下:
CAN_HandleTypeDef g_canx_handler; /* CANx句柄 */
CAN_TxHeaderTypeDef g_canx_txheader; /* 發(fā)送參數(shù)句柄 */
CAN_RxHeaderTypeDef g_canx_rxheader; /* 接收參數(shù)句柄 */
uint8_t can_init( uint32_t tsjw, uint32_t tbs2, uint32_t tbs1, uint16_t brp, uint32_t mode )
{
g_canx_handler.Instance = CAN1;
g_canx_handler.Init.Prescaler = brp; /* 分頻系數(shù)(Fdiv)為brp+1 */
g_canx_handler.Init.Mode = mode; /* 模式設(shè)置 */
g_canx_handler.Init.SyncJumpWidth = tsjw; /* 重新同步跳躍寬度(Tsjw)為tsjw+1個(gè)時(shí)間單位 CAN_SJW_1TQ~CAN_SJW_4TQ */
g_canx_handler.Init.TimeSeg1 = tbs1; /* tbs1范圍CAN_BS1_1TQ~CAN_BS1_16TQ */
g_canx_handler.Init.TimeSeg2 = tbs2; /* tbs2范圍CAN_BS2_1TQ~CAN_BS2_8TQ */
g_canx_handler.Init.TimeTriggeredMode = DISABLE; /* 非時(shí)間觸發(fā)通信模式 */
g_canx_handler.Init.AutoBusOff = DISABLE; /* 軟件自動(dòng)離線管理 */
g_canx_handler.Init.AutoWakeUp = DISABLE; /* 睡眠模式通過軟件喚醒(清除CAN->MCR的SLEEP位) */
//報(bào)文自動(dòng)傳送開啟后,當(dāng)數(shù)據(jù)發(fā)送失敗時(shí),can芯片會(huì)自動(dòng)重發(fā)數(shù)據(jù),直到數(shù)據(jù)發(fā)送成功,會(huì)造成程序假死狀態(tài)。
g_canx_handler.Init.AutoRetransmission = DISABLE; /* 禁止報(bào)文自動(dòng)傳送 */
g_canx_handler.Init.ReceiveFifoLocked = DISABLE; /* 報(bào)文不鎖定,數(shù)據(jù)溢出后新的數(shù)據(jù)覆蓋舊的,如果使能鎖定,數(shù)據(jù)溢出后新的數(shù)據(jù)會(huì)被丟掉 */
g_canx_handler.Init.TransmitFifoPriority = DISABLE; /* 優(yōu)先級(jí)由報(bào)文標(biāo)識(shí)符決定 */
if ( HAL_CAN_Init( &g_canx_handler ) != HAL_OK )
{
return 1;
}
CAN_FilterTypeDef sFilterConfig;
/*配置CAN過濾器*/
sFilterConfig.FilterBank = 0; /* 過濾器0 */
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000; /* 32位ID */
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000; /* 32位MASK */
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; /* 過濾器0關(guān)聯(lián)到FIFO0 */
sFilterConfig.FilterActivation = CAN_FILTER_ENABLE; /* 激活濾波器0 */
sFilterConfig.SlaveStartFilterBank = 14;
/* 過濾器配置 */
if ( HAL_CAN_ConfigFilter( &g_canx_handler, &sFilterConfig ) != HAL_OK )
{
return 2;
}
/* 啟動(dòng)CAN外圍設(shè)備 */
if ( HAL_CAN_Start( &g_canx_handler ) != HAL_OK )
{
return 3;
}
return 0;
}
void HAL_CAN_MspInit( CAN_HandleTypeDef *hcan )
{
if ( CAN1 == hcan->Instance )
{
CAN_RX_GPIO_CLK_ENABLE(); /* CAN_RX腳時(shí)鐘使能 */
CAN_TX_GPIO_CLK_ENABLE(); /* CAN_TX腳時(shí)鐘使能 */
__HAL_RCC_CAN1_CLK_ENABLE(); /* 使能CAN1時(shí)鐘 */
GPIO_InitTypeDef gpio_init_struct;
gpio_init_struct.Pin = CAN_TX_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_AF_PP;
gpio_init_struct.Pull = GPIO_PULLUP;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
gpio_init_struct.Alternate = GPIO_AF9_CAN1;
HAL_GPIO_Init( CAN_TX_GPIO_PORT, &gpio_init_struct ); /* CAN_TX腳 模式設(shè)置 */
gpio_init_struct.Pin = CAN_RX_GPIO_PIN;
HAL_GPIO_Init( CAN_RX_GPIO_PORT, &gpio_init_struct ); /* CAN_RX腳 必須設(shè)置成輸入模式 */
}
}
?? 接收函數(shù)使用查詢的方式,在接收函數(shù)值會(huì)不停的查詢FIFO中數(shù)據(jù)的長度,如果數(shù)據(jù)長度不為0,說明就接收到了數(shù)據(jù)。在主函數(shù)中不停地讀取接收函數(shù)返回的數(shù)據(jù)長度,通過數(shù)據(jù)長度判斷是否接收到了數(shù)據(jù)。
uint8_t can_receive_msg( uint32_t id, uint8_t *buf )
{
if ( HAL_CAN_GetRxFifoFillLevel( &g_canx_handler, CAN_RX_FIFO0 ) == 0 ) /* 沒有接收到數(shù)據(jù) */
{
return 0;
}
if ( HAL_CAN_GetRxMessage( &g_canx_handler, CAN_RX_FIFO0, &g_canx_rxheader, buf ) != HAL_OK ) /* 讀取數(shù)據(jù) */
{
return 0;
}
return g_canx_rxheader.DLC;
}
?? 發(fā)送函數(shù)
uint8_t can_send_msg( uint32_t id, uint8_t *msg, uint8_t len )
{
uint32_t TxMailbox = CAN_TX_MAILBOX0;
g_canx_txheader.StdId = id; /* 標(biāo)準(zhǔn)標(biāo)識(shí)符 */
g_canx_txheader.ExtId = id; /* 擴(kuò)展標(biāo)識(shí)符(29位) */
// g_canx_txheader.IDE = CAN_ID_STD; /* 使用標(biāo)準(zhǔn)幀 */
g_canx_txheader.IDE = CAN_ID_EXT; /* 使用擴(kuò)展幀 */
g_canx_txheader.RTR = CAN_RTR_DATA; /* 數(shù)據(jù)幀 */
g_canx_txheader.DLC = len;
if ( HAL_CAN_AddTxMessage( &g_canx_handler, &g_canx_txheader, msg, &TxMailbox ) != HAL_OK ) /* 發(fā)送消息 */
{
return 1;
}
while (HAL_CAN_GetTxMailboxesFreeLevel(&g_canx_handler) != 3); /* 等待發(fā)送完成,所有郵箱為空 */
return 0;
}
?? 在主函數(shù)中不停的查詢接收數(shù)據(jù)長度,如果接收到了數(shù)據(jù),就把接收到的數(shù)據(jù)發(fā)送出去。
int main( void )
{
uint8_t i = 0, t = 0;
uint8_t cnt = 0;
uint8_t canbuf[8];
uint8_t rxlen = 0;
uint8_t res;
uint8_t mode = 1; /* CAN工作模式: 0,普通模式; 1,環(huán)回模式 */
uint16_t count = 0;
HAL_Init(); /* 初始化HAL庫 */
sys_stm32_clock_init( 336, 10, 2, 7 ); /* 設(shè)置時(shí)鐘,168Mhz */
delay_init( 168 ); /* 延時(shí)初始化 */
usart_init( 115200 ); /* 串口初始化為115200 */
// can_init(CAN_SJW_1TQ, CAN_BS2_6TQ, CAN_BS1_7TQ, 6, CAN_MODE_LOOPBACK); /* CAN初始化, 環(huán)回模式, 波特率500Kbps 采樣點(diǎn)位置占57% */
can_init( CAN_SJW_1TQ, CAN_BS2_6TQ, CAN_BS1_7TQ, 24, CAN_MODE_NORMAL ); /* CAN初始化, 正常模式, 波特率125Kbps 采樣點(diǎn)位置占 57.1% */
RE_DE( 1 ); /* 485 設(shè)置為發(fā)送模式 */
printf( "stm32f407 can test! \r\n" );
while ( 1 )
{
rxlen = can_receive_msg( 0x12, canbuf ); /* CAN ID = 0x12, 接收數(shù)據(jù)查詢 */
if ( rxlen ) /* 接收到有數(shù)據(jù) */
{
printf( "接收到數(shù)據(jù) %d : ID:0x%08X data: ", count++, g_canx_rxheader.ExtId );
for ( i = 0; i < 8; i++ )
{
printf( "%02X ", canbuf[i] ); /* 輸出接收到的數(shù)據(jù) */
}
printf( "\r\n" );
can_send_msg( 0x02A300F0 + t, canbuf, 8 ); /* ID = 0x12, 發(fā)送8個(gè)字節(jié) */
}
t++;
delay_ms( 10 );
if ( t == 200 )
{
t = 0;
cnt++;
for ( i = 0; i < 8; i++ )
{
canbuf[i] = cnt + i; /* 填充發(fā)送緩沖區(qū) */
}
// res = can_send_msg(0x12, canbuf, 8); /* ID = 0x12, 發(fā)送8個(gè)字節(jié) */
}
}
}
??這里需要注意一個(gè)小問題,在初始化的時(shí)候,有一個(gè)報(bào)文自動(dòng)傳送的的屬性g_canx_handler.Init.AutoRetransmission,原子在這里設(shè)置的是ENABLE。
??經(jīng)過測(cè)試后發(fā)現(xiàn),如果這個(gè)屬性設(shè)置為ENABLE,那么發(fā)送數(shù)據(jù)的過程中,如果硬件電路上出現(xiàn)了故障,比如單片機(jī)can口上的連接線松動(dòng)了,或者是連接線斷了。can控制發(fā)送數(shù)據(jù)時(shí)就會(huì)失敗,此時(shí)控制器就會(huì)一直嘗試著繼續(xù)發(fā)送,can口上就會(huì)一直有高低電平變化,此時(shí)代碼就會(huì)卡在等待數(shù)據(jù)發(fā)送完成這條語句位置處。
while (HAL_CAN_GetTxMailboxesFreeLevel(&g_canx_handler) != 3);
??此時(shí)程序就會(huì)處于假死狀態(tài),如果發(fā)送函數(shù)后面還要執(zhí)行其他代碼的話,就執(zhí)行不了了,除非can控制器將數(shù)據(jù)成功發(fā)送出去。
??如果不想要這種一直等待發(fā)送成功的方式,就將自動(dòng)傳送的屬性設(shè)置為DISABLE,這樣發(fā)送數(shù)據(jù)失敗后,還會(huì)繼續(xù)執(zhí)行下面的代碼。程序不會(huì)形成假死狀態(tài)。
g_canx_handler.Init.AutoRetransmission = DISABLE;
中斷方式
??中斷模式原子的代碼中雖然有一個(gè)宏定義可以開啟中斷,但是宏定義開啟后,中斷的功能依然使用不了。
??相當(dāng)于使用中斷接收的功能沒有實(shí)現(xiàn),于是就自己邊查資料邊測(cè)試,摸索著將中斷功能實(shí)現(xiàn)了。
??首先進(jìn)行初始化。
CAN_HandleTypeDef g_canx_handler; /* CANx句柄 */
CAN_TxHeaderTypeDef g_canx_txheader; /* 發(fā)送參數(shù)句柄 */
CAN_RxHeaderTypeDef g_canx_rxheader; /* 接收參數(shù)句柄 */
uint8_t can_init( uint32_t tsjw, uint32_t tbs2, uint32_t tbs1, uint16_t brp, uint32_t mode )
{
g_canx_handler.Instance = CAN1;
g_canx_handler.Init.Prescaler = brp; /* 分頻系數(shù)(Fdiv)為brp+1 */
g_canx_handler.Init.Mode = mode; /* 模式設(shè)置 */
g_canx_handler.Init.SyncJumpWidth = tsjw; /* 重新同步跳躍寬度(Tsjw)為tsjw+1個(gè)時(shí)間單位 CAN_SJW_1TQ~CAN_SJW_4TQ */
g_canx_handler.Init.TimeSeg1 = tbs1; /* tbs1范圍CAN_BS1_1TQ~CAN_BS1_16TQ */
g_canx_handler.Init.TimeSeg2 = tbs2; /* tbs2范圍CAN_BS2_1TQ~CAN_BS2_8TQ */
g_canx_handler.Init.TimeTriggeredMode = DISABLE; /* 非時(shí)間觸發(fā)通信模式 */
g_canx_handler.Init.AutoBusOff = DISABLE; /* 軟件自動(dòng)離線管理 */
g_canx_handler.Init.AutoWakeUp = DISABLE; /* 睡眠模式通過軟件喚醒(清除CAN->MCR的SLEEP位) */
//報(bào)文自動(dòng)傳送開啟后,當(dāng)數(shù)據(jù)發(fā)送失敗時(shí),can芯片會(huì)自動(dòng)重發(fā)數(shù)據(jù),直到數(shù)據(jù)發(fā)送成功,會(huì)造成程序假死狀態(tài)。
g_canx_handler.Init.AutoRetransmission = DISABLE; /* 禁止報(bào)文自動(dòng)傳送 */
g_canx_handler.Init.ReceiveFifoLocked = DISABLE; /* 報(bào)文不鎖鎖定,FIFO裝滿后新的覆蓋舊的,如果設(shè)置報(bào)文鎖定后,F(xiàn)IFO裝滿后新的就會(huì)被丟棄*/
g_canx_handler.Init.TransmitFifoPriority = DISABLE; /* 優(yōu)先級(jí)由報(bào)文標(biāo)識(shí)符決定 */
if ( HAL_CAN_Init( &g_canx_handler ) != HAL_OK )
{
return 1;
}
/* 使用中斷接收 */
__HAL_CAN_ENABLE_IT( &g_canx_handler, CAN_IT_RX_FIFO0_MSG_PENDING ); /* FIFO0消息掛號(hào)中斷允許 */
HAL_NVIC_EnableIRQ( CAN1_RX0_IRQn ); /* 使能CAN中斷 */
HAL_NVIC_SetPriority( CAN1_RX0_IRQn, 7, 0 ); /* 搶占優(yōu)先級(jí)7,子優(yōu)先級(jí)0 */
/* HAL_CAN_ActivateNotification() 函數(shù)中會(huì)調(diào)用 __HAL_CAN_ENABLE_IT(hcan, ActiveITs);來開啟指定的中斷,
所以如果使用了__HAL_CAN_ENABLE_IT()函數(shù)開啟了中斷,就不需要使用HAL_CAN_ActivateNotification()這個(gè)函數(shù)激活中斷 */
/* 如果不使用 __HAL_CAN_ENABLE_IT()函數(shù) 也可以單獨(dú)使用HAL_CAN_ActivateNotification()函數(shù) */ /* 啟動(dòng)CAN1 */
// HAL_CAN_ActivateNotification(&g_canx_handler,CAN_IT_RX_FIFO0_MSG_PENDING); /* 啟動(dòng)CAN接收中斷-FIFO0接收新消息*/
CAN_FilterTypeDef sFilterConfig;
/*配置CAN過濾器*/
sFilterConfig.FilterBank = 0; /* 過濾器0 */
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000; /* 32位ID */
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000; /* 32位MASK */
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; /* 過濾器0關(guān)聯(lián)到FIFO0 */
sFilterConfig.FilterActivation = CAN_FILTER_ENABLE; /* 激活濾波器0 */
sFilterConfig.SlaveStartFilterBank = 14;
/* 過濾器配置 */
if ( HAL_CAN_ConfigFilter( &g_canx_handler, &sFilterConfig ) != HAL_OK )
{
return 2;
}
/* 啟動(dòng)CAN外圍設(shè)備 */
if ( HAL_CAN_Start( &g_canx_handler ) != HAL_OK )
{
return 3;
}
return 0;
}
??中斷模式初始化比查詢模式初始化多了下面三行代碼。
__HAL_CAN_ENABLE_IT( &g_canx_handler, CAN_IT_RX_FIFO0_MSG_PENDING ); /* FIFO0消息掛號(hào)中斷允許 */
HAL_NVIC_EnableIRQ( CAN1_RX0_IRQn ); /* 使能CAN中斷 */
HAL_NVIC_SetPriority( CAN1_RX0_IRQn, 7, 0 ); /* 搶占優(yōu)先級(jí)7,子優(yōu)先級(jí)0 */
?? 首先使用 __HAL_CAN_ENABLE_IT
函數(shù)設(shè)置中斷源,接收中斷有下面幾種方式。
/* Receive Interrupts */
#define CAN_IT_RX_FIFO0_MSG_PENDING ((uint32_t)CAN_IER_FMPIE0) /*!< FIFO 0 message pending interrupt */
#define CAN_IT_RX_FIFO0_FULL ((uint32_t)CAN_IER_FFIE0) /*!< FIFO 0 full interrupt */
#define CAN_IT_RX_FIFO0_OVERRUN ((uint32_t)CAN_IER_FOVIE0) /*!< FIFO 0 overrun interrupt */
#define CAN_IT_RX_FIFO1_MSG_PENDING ((uint32_t)CAN_IER_FMPIE1) /*!< FIFO 1 message pending interrupt */
#define CAN_IT_RX_FIFO1_FULL ((uint32_t)CAN_IER_FFIE1) /*!< FIFO 1 full interrupt */
#define CAN_IT_RX_FIFO1_OVERRUN ((uint32_t)CAN_IER_FOVIE1) /*!< FIFO 1 overrun interrupt */
?? 這幾種中斷的差異就不一一解釋了,這里使用FIFO0的消息掛起中斷。還有一個(gè)函數(shù) HAL_CAN_ActivateNotification
也可以設(shè)置中斷源。
HAL_CAN_ActivateNotification(&g_canx_handler,CAN_IT_RX_FIFO0_MSG_PENDING);
HAL_NVIC_EnableIRQ( CAN1_RX0_IRQn ); /* 使能CAN中斷 */
HAL_NVIC_SetPriority( CAN1_RX0_IRQn, 7, 0 ); /* 搶占優(yōu)先級(jí)7,子優(yōu)先級(jí)0 */
?? 其實(shí)HAL_CAN_ActivateNotification
函數(shù)內(nèi)部也是通過調(diào)用 __HAL_CAN_ENABLE_IT
函數(shù)來設(shè)置中斷源的。
?? 接下來在初始化回調(diào)函數(shù)中配置IO口。
void HAL_CAN_MspInit( CAN_HandleTypeDef* hcan )
{
if ( CAN1 == hcan->Instance )
{
CAN_RX_GPIO_CLK_ENABLE(); /* CAN_RX腳時(shí)鐘使能 */
CAN_TX_GPIO_CLK_ENABLE(); /* CAN_TX腳時(shí)鐘使能 */
__HAL_RCC_CAN1_CLK_ENABLE(); /* 使能CAN1時(shí)鐘 */
GPIO_InitTypeDef gpio_init_struct;
gpio_init_struct.Pin = CAN_TX_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_AF_PP;
gpio_init_struct.Pull = GPIO_PULLUP;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
gpio_init_struct.Alternate = GPIO_AF9_CAN1;
HAL_GPIO_Init( CAN_TX_GPIO_PORT, &gpio_init_struct ); /* CAN_TX腳 模式設(shè)置 */
gpio_init_struct.Pin = CAN_RX_GPIO_PIN;
HAL_GPIO_Init( CAN_RX_GPIO_PORT, &gpio_init_struct ); /* CAN_RX腳 必須設(shè)置成輸入模式 */
}
}
?? 初始化完成之后,下面就該設(shè)置中斷函數(shù)的入口了,這個(gè)中斷函數(shù)的名稱可以在startup_stm32f407xx.s 文件里面找。
?? 在匯編代碼的中斷向量表里面有中斷函數(shù)的名稱,這里有個(gè)CAN1_RX0_IRQHandler 還有個(gè) CAN1_RX1_IRQHandler,那么要使用哪個(gè)呢?
在網(wǎng)上找到相關(guān)資料如下
?? 經(jīng)過驗(yàn)證,紅線里面圈出來的說法是正確的,同時(shí)要注意如果要使用FIFO1,那么程序中所有設(shè)置FIFO的地方都得寫成FIFO1.
?? 其中包括中斷號(hào),中斷名稱,中斷入庫函數(shù)名稱,中斷回調(diào)函數(shù)名稱。
?? 由于上面初始化的時(shí)候設(shè)置的是使用FIFO0,那么這里的函數(shù)入口名稱就選擇CAN1_RX0_IRQHandler。
void CAN1_RX0_IRQHandler( void )
{
/* 調(diào)用HAL庫 CAN 中斷入口函數(shù)*/
}
?? 接下來就需要在這個(gè)中斷入口函數(shù)中調(diào)用HAL庫的通用CAN中斷處理函數(shù),那這個(gè)函數(shù)在哪去找呢? 直接打開 stm32f4xx_hal_can.h
頭文件在里面搜索以 IRQHandler
結(jié)尾的函數(shù)名。
?? 查找后發(fā)現(xiàn)這個(gè)里面只有一個(gè)函數(shù) HAL_CAN_IRQHandler
符合,那么這個(gè)函數(shù)肯定就是HAL庫中CAN中斷的通用入口函數(shù)了。直接在中斷函數(shù)里面添加這個(gè)通用函數(shù)。
void CAN1_RX0_IRQHandler( void )
{
HAL_CAN_IRQHandler( &g_canx_handler ); /* 調(diào)用HAL庫 CAN 中斷入口函數(shù)*/
}
?? 接下來根據(jù)HAL庫的慣例,在中斷函數(shù)里面肯定還有一個(gè)回調(diào)函數(shù)。接下來就需要去找這個(gè)中斷回調(diào)函數(shù)??梢灾苯犹D(zhuǎn)到 HAL_CAN_IRQHandler
函數(shù)內(nèi)部進(jìn)行查看。
?? 但是這個(gè)函數(shù)內(nèi)部的代碼有些長,找起來不是很方便,那么就可以在 stm32f4xx_hal_can.h
頭文件里直接去找。由于回掉函數(shù)都是以Callback
結(jié)尾的,那么就可以直接在 stm32f4xx_hal_can.h
文件中搜索 Callback
結(jié)尾的函數(shù)。
?? 可以找到一個(gè)Callbacks functions
的注釋,那么下面這些函數(shù)就是中斷回調(diào)函數(shù),如果程序?qū)懙帽容^多的時(shí)候,可以不用查找的方法,直接用鼠標(biāo)拖動(dòng)右邊的滾動(dòng)條就可以定位到回調(diào)函數(shù)這一塊。
?? 但是這么多函數(shù),到底是哪一個(gè)呢?別著急,還記得在初始化的時(shí)候,使能中斷時(shí)開啟了一個(gè)FIFO0的消息掛起中斷,可以根據(jù)這個(gè)中斷使能的名字去對(duì)比,可以發(fā)現(xiàn)在右邊HAL_CAN_RxFifo0MsgPendingCallback
這個(gè)函數(shù)的名字和CAN_IT_RX_FIFO0_MSG_PENDING
名稱基本一樣,那么HAL_CAN_RxFifo0MsgPendingCallback
這個(gè)函數(shù)肯定就是FIFO0消息掛起中斷的回調(diào)函數(shù)。
?? 接下來就可以編寫中斷回調(diào)函數(shù)了。
void HAL_CAN_RxFifo0MsgPendingCallback( CAN_HandleTypeDef* hcan )
{
uint8_t rxbuf[8];
uint32_t id;
uint8_t i;
HAL_CAN_GetRxMessage( hcan, CAN_RX_FIFO0, &g_canx_rxheader, rxbuf ); /* 讀取數(shù)據(jù) */
printf( "接收到 %d 位數(shù)據(jù) : ID:0x%08X data: ", g_canx_rxheader.DLC, g_canx_rxheader.ExtId );
for ( i = 0; i < 8; i++ )
{
printf( "%02X ", rxbuf[i] ); /* 輸出接收到的數(shù)據(jù) */
}
printf( "\r\n" );
}
?? 在中斷回調(diào)函數(shù)里面使用HAL_CAN_GetRxMessage
函數(shù)讀取接收到的數(shù)據(jù),并打印出來。到此中斷函數(shù)的代碼就編寫完成了。文章來源:http://www.zghlxwxcb.cn/news/detail-697394.html
?? 接下來就是下載驗(yàn)證的過程了,這里就不一一列舉了。中斷部分的函數(shù),需要注意的地方,在上面基本都分析過了。在調(diào)試的過程中,暫時(shí)也沒發(fā)現(xiàn)其他需要注意的地方。文章來源地址http://www.zghlxwxcb.cn/news/detail-697394.html
到了這里,關(guān)于stm32f407單片機(jī)上通過HAL庫實(shí)現(xiàn)can總線數(shù)據(jù)的收發(fā)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!