#include "CAN.h"
#define CAN_Tx_Port GPIOH
#define CAN_Tx_Pin GPIO_Pin_13
#define CAN_Rx_Port GPIOI
#define CAN_Rx_Pin GPIO_Pin_9
CanTxMsg CAN_Tx_Msg;
CanRxMsg CAN_Rx_Msg;
u8 msg_box;
u8 std;
/*
CAN 總線GPIO配置
*/
void CAN_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_init;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH|RCC_AHB1Periph_GPIOI,ENABLE);
GPIO_PinAFConfig(CAN_Tx_Port,GPIO_PinSource13,GPIO_AF_CAN1);
GPIO_PinAFConfig(CAN_Rx_Port,GPIO_PinSource9,GPIO_AF_CAN1);
GPIO_init.GPIO_Mode = GPIO_Mode_AF;
GPIO_init.GPIO_OType = GPIO_OType_PP;
GPIO_init.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_init.GPIO_Pin = CAN_Tx_Pin;
GPIO_Init(CAN_Tx_Port,&GPIO_init);
GPIO_init.GPIO_Pin = CAN_Rx_Pin;
GPIO_Init(CAN_Rx_Port,&GPIO_init);
}
void CAN_Config(void)
{
CAN_InitTypeDef CAN_init;
CAN_FilterInitTypeDef CAN_Filter_init;
CAN_DeInit(CAN1);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
//工作模式的設定
CAN_init.CAN_Mode = CAN_Mode_Normal;
//工作模式的配置:可配置為正常模式,靜默模式,回環模式,靜默回環模式;
//發送FIFO使能
CAN_init.CAN_TXFP = DISABLE;
//自動重發功能使能
CAN_init.CAN_NART = DISABLE;//不使能
//FIFO鎖定功能
/*
FIFO鎖定功能主要用于管理接收郵箱
如果不使能FIFO鎖定功能,當FIFO使能時,則在FIFO郵箱已滿之後,後續的資訊将會覆寫最後接收的資訊
如果使能FIFO鎖定功能,則在FIFO郵箱已滿之後,将丢棄最新的消息,保留最原始的三則消息
*/
CAN_init.CAN_RFLM = DISABLE;
//總線自動恢複功能
/*
當 TEC 大于 255 時,達到總線關閉狀态,該狀态由 CAN_ESR 寄存器的 BOFF 位訓示。在總線關閉狀态下, bxCAN 不能再發送和接收消息。
bxCAN 可以自動或者應軟體請求而從總線關閉狀态中恢複(恢複錯誤主動狀态),具體取決于 CAN_MCR 寄存器的 ABOM 位。但在兩種情況下, bxCAN 都必須至少等待 CAN 标準中指定的恢複序列完成(在 CANRX 上監測到 128 次 11 個連續隐性位)。
如果 ABOM 位置 1, bxCAN 将在進入總線關閉狀态後自動啟動恢複序列。
如果 ABOM 位清零,則軟體必須請求 bxCAN 先進入再退出初始化模式,進而啟動恢複序列。
注意: 在初始化模式下, bxCAN 不會監視 CANRX 信号,是以無法完成恢複序列。 要進行恢複,bxCAN 必須處于正常模式。
*/
CAN_init.CAN_ABOM = DISABLE;
//---------------
CAN_init.CAN_AWUM = DISABLE;
CAN_init.CAN_TTCM = DISABLE;
//--------------------------
//關于CAN總線比特率計算
/*
NominalBitTime = 1*Tq +tBS1 + tBS2
tBS1 = tq x (TS1[3:0] + 1);
tBS2 = tq x (TS2[2:0] + 1),
Tq = (BRP[9:0] + 1) x TPCLK;
TPCLK = APB 時鐘的時間周期;
BRP[9:0], TS1[3:0] 和 TS2[2:0] 在 CAN_BTR 寄存器中定義;
//-------------------------------------------------------------
CAN 波特率 = RCC_APB1Periph_CAN1 / Prescaler / (SJW + BS1 + BS2);
SJW = synchronisation_jump_width
BS = bit_segment
本例中,設定CAN波特率為500Kbps
CAN 波特率 = 420000000 / 2 / (1 + 12 + 8) / = 1 MBps
*/
CAN_init.CAN_BS1 = CAN_BS1_12tq;
CAN_init.CAN_BS2 = CAN_BS2_8tq;
CAN_init.CAN_SJW = CAN_SJW_1tq;
CAN_init.CAN_Prescaler = 4;
CAN_Init(CAN1,&CAN_init);
//------------------------------------
CAN_Filter_init.CAN_FilterActivation = ENABLE;//過濾器使能
//選擇使用哪個FIFO,可為CAN_FilterFIFO0,CAN_FilterFIFO1;
CAN_Filter_init.CAN_FilterFIFOAssignment = CAN_FilterFIFO0;
CAN_Filter_init.CAN_FilterMode = CAN_FilterMode_IdMask;//掩碼模式,此處可配置為掩碼模式和清單模式
CAN_Filter_init.CAN_FilterScale = CAN_FilterScale_16bit;//
CAN_Filter_init.CAN_FilterNumber = 0;
CAN_Filter_init.CAN_FilterIdHigh = 0x0000;
CAN_Filter_init.CAN_FilterMaskIdHigh = 0x0000;
CAN_Filter_init.CAN_FilterIdLow = 0x0000;
CAN_Filter_init.CAN_FilterMaskIdLow = 0x0000;
CAN_FilterInit(&CAN_Filter_init);
}
void CAN_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_init;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
NVIC_init.NVIC_IRQChannel = CAN1_RX0_IRQn;
NVIC_init.NVIC_IRQChannelCmd =ENABLE;
NVIC_init.NVIC_IRQChannelPreemptionPriority =0x00;
NVIC_init.NVIC_IRQChannelSubPriority = 0x00;
NVIC_Init(&NVIC_init);
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
}
u8 CAN_send_massage(u8 *data,u8 leng,u32 massage_id)
{
u8 tx_cnt;
u32 tx_time_out_cnt = 0;
/*
當資料幀的ID大于0x7FF時就認為是拓展幀,否則都為标準幀
*/
if(massage_id > 0x7FF)
{
CAN_Tx_Msg.IDE = CAN_ID_EXT ;//發送幀的類型:CAN_Id_Standard 标準幀; CAN_Id_Extended 拓展幀
}
else
{
CAN_Tx_Msg.IDE = CAN_ID_STD ;//發送幀的類型:CAN_Id_Standard 标準幀; CAN_Id_Extended 拓展幀
}
CAN_Tx_Msg.DLC = leng;//發送資料長度
CAN_Tx_Msg.RTR = CAN_RTR_DATA;//發送幀的類型:CAN_RTR_DATA 發送資料幀;CAN_RTR_REMOTE 遠端幀,遠端幀中沒有資料;
CAN_Tx_Msg.StdId = massage_id;//标準幀的ID,11位
CAN_Tx_Msg.ExtId = massage_id;//拓展幀的ID,29位
for(tx_cnt = 0;tx_cnt < leng;tx_cnt++)
{
CAN_Tx_Msg.Data[tx_cnt] = data[tx_cnt];
}
do
{
tx_time_out_cnt++;
msg_box = CAN_Transmit(CAN1,&CAN_Tx_Msg);
}
while(((CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP0) !=RESET) || \
(CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP1) !=RESET) || \
(CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP2) !=RESET))&&(tx_time_out_cnt < 10000));
tx_time_out_cnt++;
if(tx_time_out_cnt > 10000)
{
return 0;
}
else
{
return 1;
}
}
void CAN1_RX0_IRQHandler(void)
{
if(CAN_GetITStatus(CAN1,CAN_IT_FMP0) == SET)
{
CAN_Receive(CAN1,CAN_FIFO0,&CAN_Rx_Msg);
CAN_send_massage(&CAN_Rx_Msg.Data[0],CAN_Rx_Msg.DLC,CAN_Rx_Msg.ExtId);
// CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
}
}
以上是關于CAN的基本配置,主要是波特率相關配置
2016年7月17日
今天在對STM32F4的CAN總線進行學習,更加深刻的了解了SMT32的CAN總線子產品功能。具體描述如下所示:
主要是關于CAN總線濾波器的設定的問題,STM32的CAN總線接收濾波器可以設定為掩碼模式和辨別符清單模式,兩種模式都容易了解,關鍵是在參數設定時需要注意,在實驗過程中采用的16位辨別符清單模式那麼一個濾波器可以設定4個辨別符,27個濾波器就可以設定27*4=108個辨別符,足夠今後的應用;
注意上圖所對應的辨別符和參數設定的問題,
假如我現在隻需要接收ID為0x0321的标準資料幀,那麼對應上圖參數設定就應該為
CAN_Filter_init.CAN_FilterIdHigh = 0x321<<5;為何要将資料右移5位??
解釋如下所述:在上面的截圖中可以看出這16位資料中不僅僅包括資料ID還有遠端幀和資料幀選擇位(RTR)及其
标準幀和擴充幀選擇位(IDE),今天 今天白天的測試一直不通過問題就在這兒,當時僅僅将該設定參數了解為資料ID的,導緻一直無法成功。
最後的測試程式如下所示:(程式是16位清單模式)
#include "CAN.h"
#define CAN_Tx_Port GPIOH
#define CAN_Tx_Pin GPIO_Pin_13
#define CAN_Rx_Port GPIOI
#define CAN_Rx_Pin GPIO_Pin_9
CanTxMsg CAN_Tx_Msg;
CanRxMsg CAN_Rx_Msg;
u8 msg_box;
u8 std;
void CAN_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_init;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH|RCC_AHB1Periph_GPIOI,ENABLE);
GPIO_PinAFConfig(CAN_Tx_Port,GPIO_PinSource13,GPIO_AF_CAN1);
GPIO_PinAFConfig(CAN_Rx_Port,GPIO_PinSource9,GPIO_AF_CAN1);
GPIO_init.GPIO_Mode = GPIO_Mode_AF;
GPIO_init.GPIO_OType = GPIO_OType_PP;
GPIO_init.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_init.GPIO_Pin = CAN_Tx_Pin;
GPIO_Init(CAN_Tx_Port,&GPIO_init);
GPIO_init.GPIO_Pin = CAN_Rx_Pin;
GPIO_Init(CAN_Rx_Port,&GPIO_init);
}
void CAN_Config(void)
{
CAN_InitTypeDef CAN_init;
CAN_FilterInitTypeDef CAN_Filter_init;
CAN_DeInit(CAN1);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
//工作模式的設定
CAN_init.CAN_Mode = CAN_Mode_Normal;//工作模式的配置:可配置為正常模式,靜默模式,回環模式,靜默回環模式;
//發送FIFO使能
CAN_init.CAN_TXFP = DISABLE;
//自動重發功能使能
CAN_init.CAN_NART = DISABLE;//不使能
//FIFO鎖定功能
/*
FIFO鎖定功能主要用于管理接收郵箱
如果不使能FIFO鎖定功能,當FIFO使能時,則在FIFO郵箱已滿之後,後續的資訊将會覆寫最後接收的資訊
如果使能FIFO鎖定功能,則在FIFO郵箱已滿之後,将丢棄最新的消息,保留最原始的三則消息
*/
CAN_init.CAN_RFLM = DISABLE;
//總線自動恢複功能
/*
當 TEC 大于 255 時,達到總線關閉狀态,該狀态由 CAN_ESR 寄存器的 BOFF 位訓示。在總線關閉狀态下, bxCAN 不能再發送和接收消息。
bxCAN 可以自動或者應軟體請求而從總線關閉狀态中恢複(恢複錯誤主動狀态),具體取決于 CAN_MCR 寄存器的 ABOM 位。但在兩種情況下, bxCAN 都必須至少等待 CAN 标準中指定的恢複序列完成(在 CANRX 上監測到 128 次 11 個連續隐性位)。
如果 ABOM 位置 1, bxCAN 将在進入總線關閉狀态後自動啟動恢複序列。
如果 ABOM 位清零,則軟體必須請求 bxCAN 先進入再退出初始化模式,進而啟動恢複序列。
注意: 在初始化模式下, bxCAN 不會監視 CANRX 信号,是以無法完成恢複序列。 要進行恢複,bxCAN 必須處于正常模式。
*/
CAN_init.CAN_ABOM = DISABLE;
//---------------
CAN_init.CAN_AWUM = DISABLE;
CAN_init.CAN_TTCM = DISABLE;
//--------------------------
//關于CAN總線比特率計算
/*
NominalBitTime = 1*Tq +tBS1 + tBS2
tBS1 = tq x (TS1[3:0] + 1);
tBS2 = tq x (TS2[2:0] + 1),
Tq = (BRP[9:0] + 1) x TPCLK;
TPCLK = APB 時鐘的時間周期;
BRP[9:0], TS1[3:0] 和 TS2[2:0] 在 CAN_BTR 寄存器中定義;
//-------------------------------------------------------------
CAN 波特率 = RCC_APB1Periph_CAN1 / Prescaler / (SJW + BS1 + BS2);
SJW = synchronisation_jump_width
BS = bit_segment
本例中,設定CAN波特率為500Kbps
CAN 波特率 = 420000000 / 4/ (1 + 12 + 8) / = 500kBps
*/
CAN_init.CAN_BS1 = CAN_BS1_12tq;
CAN_init.CAN_BS2 = CAN_BS2_8tq;
CAN_init.CAN_SJW = CAN_SJW_1tq;
CAN_init.CAN_Prescaler = 4;
CAN_Init(CAN1,&CAN_init);
//------------------------------------
CAN_Filter_init.CAN_FilterActivation = ENABLE;//過濾器使能
CAN_Filter_init.CAN_FilterFIFOAssignment = CAN_FilterFIFO0;//選擇使用哪個FIFO,可為CAN_FilterFIFO0,CAN_FilterFIFO1;
CAN_Filter_init.CAN_FilterMode = CAN_FilterMode_IdList;//辨別符清單模式
CAN_Filter_init.CAN_FilterScale = CAN_FilterScale_16bit;//
CAN_Filter_init.CAN_FilterNumber = 0;
/*
以下配置CAN總線可以接收資料幀,标準幀同時幀ID僅僅是0x321,0x322,0x7AE及其0x000才能接收。
*/
CAN_Filter_init.CAN_FilterIdHigh = 0x321<<5;
CAN_Filter_init.CAN_FilterIdLow = 0x0000;
CAN_Filter_init.CAN_FilterMaskIdHigh = 0x0322<<5;
CAN_Filter_init.CAN_FilterMaskIdLow = 0x07AE<<5;
CAN_FilterInit(&CAN_Filter_init);
}
void CAN_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_init;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
NVIC_init.NVIC_IRQChannel = CAN1_RX0_IRQn;
NVIC_init.NVIC_IRQChannelCmd =ENABLE;
NVIC_init.NVIC_IRQChannelPreemptionPriority =0x00;
NVIC_init.NVIC_IRQChannelSubPriority = 0x00;
NVIC_Init(&NVIC_init);
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
}
u8 CAN_send_massage(u8 *data,u8 leng,u32 massage_id)
{
u8 tx_cnt;
u32 tx_time_out_cnt = 0;
/*
當資料幀的ID大于0x7FF時就認為是拓展幀,否則都為标準幀
*/
if(massage_id > 0x7FF)
{
CAN_Tx_Msg.IDE = CAN_ID_EXT ;//發送幀的類型:CAN_Id_Standard 标準幀; CAN_Id_Extended 拓展幀
}
else
{
CAN_Tx_Msg.IDE = CAN_ID_STD ;//發送幀的類型:CAN_Id_Standard 标準幀; CAN_Id_Extended 拓展幀
}
CAN_Tx_Msg.DLC = leng;//發送資料長度
CAN_Tx_Msg.RTR = CAN_RTR_DATA;//發送幀的類型:CAN_RTR_DATA 發送資料幀;CAN_RTR_REMOTE 遠端幀,遠端幀中沒有資料;
CAN_Tx_Msg.StdId = massage_id;//标準幀的ID,11位
CAN_Tx_Msg.ExtId = massage_id;//拓展幀的ID,29位
for(tx_cnt = 0;tx_cnt < leng;tx_cnt++)
{
CAN_Tx_Msg.Data[tx_cnt] = data[tx_cnt];
}
do
{
tx_time_out_cnt++;
msg_box = CAN_Transmit(CAN1,&CAN_Tx_Msg);
}
while(((CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP0) !=RESET) || \
(CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP1) !=RESET) || \
(CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP2) !=RESET))&&(tx_time_out_cnt < 10000));
tx_time_out_cnt++;
if(tx_time_out_cnt > 10000)
{
return 0;
}
else
{
return 1;
}
}
void CAN1_RX0_IRQHandler(void)
{
if(CAN_GetITStatus(CAN1,CAN_IT_FMP0) == SET)
{
CAN_Receive(CAN1,CAN_FIFO0,&CAN_Rx_Msg);
CAN_send_massage(&CAN_Rx_Msg.Data[0],CAN_Rx_Msg.DLC,CAN_Rx_Msg.StdId);
// CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
}
}
這幾天一直困惑在32位辨別符清單模式的配置,昨天晚上通過尋找相關例程問題解決詳細講程式說明:
#include "CAN.h"
#define CAN_Tx_Port GPIOH
#define CAN_Tx_Pin GPIO_Pin_13
#define CAN_Rx_Port GPIOI
#define CAN_Rx_Pin GPIO_Pin_9
CanTxMsg CAN_Tx_Msg;
CanRxMsg CAN_Rx_Msg;
u8 msg_box;
u8 std;
void CAN_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_init;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH|RCC_AHB1Periph_GPIOI,ENABLE);
GPIO_PinAFConfig(CAN_Tx_Port,GPIO_PinSource13,GPIO_AF_CAN1);
GPIO_PinAFConfig(CAN_Rx_Port,GPIO_PinSource9,GPIO_AF_CAN1);
GPIO_init.GPIO_Mode = GPIO_Mode_AF;
GPIO_init.GPIO_OType = GPIO_OType_PP;
GPIO_init.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_init.GPIO_Pin = CAN_Tx_Pin;
GPIO_Init(CAN_Tx_Port,&GPIO_init);
GPIO_init.GPIO_Pin = CAN_Rx_Pin;
GPIO_Init(CAN_Rx_Port,&GPIO_init);
}
void CAN_Config(void)
{
CAN_InitTypeDef CAN_init;
u32 temp;
CAN_FilterInitTypeDef CAN_Filter_init;
CAN_DeInit(CAN1);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
//工作模式的設定
CAN_init.CAN_Mode = CAN_Mode_Normal;//工作模式的配置:可配置為正常模式,靜默模式,回環模式,靜默回環模式;
//發送FIFO使能
CAN_init.CAN_TXFP = DISABLE;
//自動重發功能使能
CAN_init.CAN_NART = DISABLE;//不使能
//FIFO鎖定功能
/*
FIFO鎖定功能主要用于管理接收郵箱
如果不使能FIFO鎖定功能,當FIFO使能時,則在FIFO郵箱已滿之後,後續的資訊将會覆寫最後接收的資訊
如果使能FIFO鎖定功能,則在FIFO郵箱已滿之後,将丢棄最新的消息,保留最原始的三則消息
*/
CAN_init.CAN_RFLM = DISABLE;
//總線自動恢複功能
/*
當 TEC 大于 255 時,達到總線關閉狀态,該狀态由 CAN_ESR 寄存器的 BOFF 位訓示。在總線關閉狀态下, bxCAN 不能再發送和接收消息。
bxCAN 可以自動或者應軟體請求而從總線關閉狀态中恢複(恢複錯誤主動狀态),具體取決于 CAN_MCR 寄存器的 ABOM 位。但在兩種情況下, bxCAN 都必須至少等待 CAN 标準中指定的恢複序列完成(在 CANRX 上監測到 128 次 11 個連續隐性位)。
如果 ABOM 位置 1, bxCAN 将在進入總線關閉狀态後自動啟動恢複序列。
如果 ABOM 位清零,則軟體必須請求 bxCAN 先進入再退出初始化模式,進而啟動恢複序列。
注意: 在初始化模式下, bxCAN 不會監視 CANRX 信号,是以無法完成恢複序列。 要進行恢複,bxCAN 必須處于正常模式。
*/
CAN_init.CAN_ABOM = DISABLE;
//---------------
CAN_init.CAN_AWUM = DISABLE;
CAN_init.CAN_TTCM = DISABLE;
//--------------------------
//關于CAN總線比特率計算
/*
NominalBitTime = 1*Tq +tBS1 + tBS2
tBS1 = tq x (TS1[3:0] + 1);
tBS2 = tq x (TS2[2:0] + 1),
Tq = (BRP[9:0] + 1) x TPCLK;
TPCLK = APB 時鐘的時間周期;
BRP[9:0], TS1[3:0] 和 TS2[2:0] 在 CAN_BTR 寄存器中定義;
//-------------------------------------------------------------
CAN 波特率 = RCC_APB1Periph_CAN1 / Prescaler / (SJW + BS1 + BS2);
SJW = synchronisation_jump_width
BS = bit_segment
本例中,設定CAN波特率為500Kbps
CAN 波特率 = 420000000 / 2 / (1 + 12 + 8) / = 1 MBps
*/
CAN_init.CAN_BS1 = CAN_BS1_12tq;
CAN_init.CAN_BS2 = CAN_BS2_8tq;
CAN_init.CAN_SJW = CAN_SJW_1tq;
CAN_init.CAN_Prescaler = 4;
CAN_Init(CAN1,&CAN_init);
//------------------------------------
CAN_Filter_init.CAN_FilterActivation = ENABLE;//過濾器使能
CAN_Filter_init.CAN_FilterFIFOAssignment = CAN_FilterFIFO0;
//選擇使用哪個FIFO,可為CAN_FilterFIFO0,CAN_FilterFIFO1;
CAN_Filter_init.CAN_FilterNumber = 2;
CAN_Filter_init.CAN_FilterMode = CAN_FilterMode_IdList;//辨別符清單模式
CAN_Filter_init.CAN_FilterScale = CAN_FilterScale_32bit;//
/*
以下是關于辨別符清單模式的配置,需要将擴充幀的辨別符的高16位指派給
CAN_Filter_init.CAN_FilterIdHigh;
低13位指派給CAN_Filter_init.CAN_FilterMaskIdLow;具體的程式如下所示
*/
CAN_Filter_init.CAN_FilterIdHigh = 0x07909ADC>>13;
CAN_Filter_init.CAN_FilterIdLow = ((0x07909ADC<<3)&0xFFFF)|0x04;
CAN_Filter_init.CAN_FilterMaskIdHigh = (0x07909AD0>>13)&0xFFFF;
CAN_Filter_init.CAN_FilterMaskIdLow = ((0x07909AD0<<3)&0xFFFF)|0x4;
CAN_FilterInit(&CAN_Filter_init);
}
void CAN_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_init;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
NVIC_init.NVIC_IRQChannel = CAN1_RX0_IRQn;
NVIC_init.NVIC_IRQChannelCmd =ENABLE;
NVIC_init.NVIC_IRQChannelPreemptionPriority =0x00;
NVIC_init.NVIC_IRQChannelSubPriority = 0x00;
NVIC_Init(&NVIC_init);
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
}
u8 CAN_send_massage(u8 *data,u8 leng,u32 massage_id)
{
u8 tx_cnt;
u32 tx_time_out_cnt = 0;
/*
當資料幀的ID大于0x7FF時就認為是拓展幀,否則都為标準幀
*/
if(massage_id > 0x7FF)
{
CAN_Tx_Msg.IDE = CAN_ID_EXT ;//發送幀的類型:CAN_Id_Standard 标準幀; CAN_Id_Extended 拓展幀
}
else
{
CAN_Tx_Msg.IDE = CAN_ID_STD ;//發送幀的類型:CAN_Id_Standard 标準幀; CAN_Id_Extended 拓展幀
}
CAN_Tx_Msg.DLC = leng;//發送資料長度
CAN_Tx_Msg.RTR = CAN_RTR_DATA;//發送幀的類型:CAN_RTR_DATA 發送資料幀;CAN_RTR_REMOTE 遠端幀,遠端幀中沒有資料;
CAN_Tx_Msg.StdId = massage_id;//标準幀的ID,11位
CAN_Tx_Msg.ExtId = massage_id;//拓展幀的ID,29位
for(tx_cnt = 0;tx_cnt < leng;tx_cnt++)
{
CAN_Tx_Msg.Data[tx_cnt] = data[tx_cnt];
}
do
{
tx_time_out_cnt++;
msg_box = CAN_Transmit(CAN1,&CAN_Tx_Msg);
}
while(((CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP0) !=RESET) || \
(CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP1) !=RESET) || \
(CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP2) !=RESET))&&(tx_time_out_cnt < 10000));
tx_time_out_cnt++;
if(tx_time_out_cnt > 10000)
{
return 0;
}
else
{
return 1;
}
}
void CAN1_RX0_IRQHandler(void)
{
if(CAN_GetITStatus(CAN1,CAN_IT_FMP0) == SET)
{
CAN_Receive(CAN1,CAN_FIFO0,&CAN_Rx_Msg);
if(CAN_Rx_Msg.IDE == CAN_ID_STD)
{
CAN_send_massage(&CAN_Rx_Msg.Data[0],CAN_Rx_Msg.DLC,CAN_Rx_Msg.StdId);
}
else if(CAN_Rx_Msg.IDE == CAN_ID_EXT)
{
CAN_send_massage(&CAN_Rx_Msg.Data[0],CAN_Rx_Msg.DLC,CAN_Rx_Msg.ExtId);
}
// CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
}
}
CAN_FilterInitStructure.CAN_FilterIdLow=(can_addr<<(CMD_WIDTH+3))|0x04;
0x04是設定ID為擴充ID,3表示寄存器中的最低有3bit不是過濾器的ID,指令放在ID的低bit位,一共CMD_WIDTH個bit,是以這裡一共要左移CMD_WIDTH+3個bit
注意,一個寄存器是16bit,CAN_FilterIdLow中有效位址位數為16-3-CMD_WIDTH,是以有了第一行的代碼:
CAN_FilterInitStructure.CAN_FilterIdHigh=can_addr>>(16-CMD_WIDTH-3);
因為can_addr的低16-3-CMD_WIDTH位已經放到CAN_FilterIdLow中,是以CAN_FilterIdHigh位就放can_addr>>(16-CMD_WIDTH-3)
0xF8FA7FFF