接收用到的結構體如下:CAN概念:
? ? ? ? 全稱Controller Area Network,是一種半雙工,異步通訊。
物理層:
? ? ? ? 閉環:允許總線最長40m,最高速1Mbps,規定總線兩端各有一個120Ω電阻,閉環
? ? ? ?開環:最大傳輸距離1Km,最高速125Kbps,規定每根線串聯一個2.2kΩ的電阻,開環
CAN協議基本特點
? ? ? ?基本特點如下:
? ? ? ?可多主控制: 當CAN總線空閑時,所有在總線上的終端都可以發送報文,根據標識符(CAN ID)決定優先級,當總線上有兩個以上的終端發送消息時,對各消息CAN ID的每個位進行逐個仲裁比較。CAN ID值越低,報文優先級越高速度快,距離遠:CAN 協議最快可達1Mbps(距離小于40m),最遠可達10KM(速率小于 5Kbps)
? ? ? ?CAN 幀種類:CAN 通信中包含五種幀種類,數據幀、遙控幀、錯誤幀、過載幀、間隔幀。其中最重要的是數據幀,用于通訊節點向外傳送數據。數據幀中有數據段,用于承載數據的內容,一幀可發送0~8個字節的數據,MSB先行。
簡單了解上述基本特點即可快速上手CAN總線的配置。
? ? ? ?顯性電平對應“0”,隱性電平對應“1”。隱性電平(1)兩條線電壓都是2.5V,即壓差為0;顯性電平(0)CAN_High和CAN_Low分別為3.5V和1.5V,壓差為2V。
? ? ? ?總線上,只要有一個節點輸出顯性,則總線上為顯性電平;只有所有節點都是隱性電平,總線才為隱性電平
CAN網絡由CAN控制器和CAN收發器組成,STM32僅集成了CAN控制器。
1、硬件-芯片使用:STM32F103Cx系列
cubeMX配置時鐘
can外設掛載在APB1上。
?
一般通信都會打開接收中斷,在這里打開CAN1 RX0的中斷,優先級可以通過NVIC進行更改。?
CAN 的波特率及位同步
位時序分解
?Prescaler:預分頻,確定CAN最小時間單位Tq。
這里以F103C8T6為例,APB1時鐘為36Mhz
計算波特率的方法:36M/分頻系數/(BS1 + BS2 + 1)
如圖設置,波特率是1000Kbps,36M / 4 /(4 + 4 + 1) =1M = 1000K
波特率計算公式:
配置工作模式:
CAN數據幀格式
?CAN波特率計算小工具
STM32 CAN Baud Rate CalculatorV1.0-STM32 CAN Baud Rate Calculator官方下載_3DM軟件
STM32的CAN通信波特率計算器
?
?CANPro協議分析平臺軟件為CANalyst-II+的標配軟件
CAN基本函數
函數 ? ??? ? 功能
HAL_CAN_Start ??? ???????????????????????????????開啟CAN通訊
HAL_CAN_Stop? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 關閉CAN通訊
HAL_CAN_RequestSleep? ? ? ? ? ? ? ? ? ? ?使CAN模塊完成當前操作后嘗試進入休眠模式
HAL_CAN_WakeUp? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 從休眠模式中喚醒
HAL_CAN_IsSleepActive? ? ? ? ? ? ? ? ? ? ? 檢查是否成功處于休眠模式
HAL_CAN_AddTxMessage?? ? ??????????????向 Tx 郵箱中增加一個消息,并且激活對應的傳輸請求
HAL_CAN_AbortTxRequest ?? ? ????????????請求中斷傳輸
HAL_CAN_GetTxMailboxesFreeLevel ?查詢空閑的發送郵箱個數
HAL_CAN_IsTxMessagePending? ? ? ? ? 檢查是否有傳輸請求在指定的 Tx 郵箱上等待
HAL_CAN_GetRxMessage? ? ? ? ? ? ? ? ? ? 從Rx FIFO 收取一個 CAN 幀
HAL_CAN_GetRxFifoFillLevel ? ??? ????????查詢接收郵箱未讀郵箱的個數
STM32HAL庫學習——CAN筆記_hal庫can_jdhfusk的博客-CSDN博客
發送用到的結構體如下:
typedef struct
{
? uint32_t StdId; ? ?//標準ID
? uint32_t ExtId; ? ?//擴展ID
? uint32_t IDE; ? ? ?//用來決定報文是使用標準ID還是擴準ID
? uint32_t RTR; ? ? ?//用來決定報文是數據幀要是遙控幀
? uint32_t DLC; ? ? ?//數據長度,取值為0-8
? FunctionalState TransmitGlobalTime;?
//最后這個是時間觸發模式用的,開啟后會自動把時間戳添加到最后兩字節的數據中。目前沒有用到,選擇 DISABLE?
} CAN_TxHeaderTypeDef;StdId :如果將要發送的報文使用標準ID,那么這個成員便記錄標準ID的值
取值: 0x0 ~ 0x7FFExtId :如果將要發送的報文使用擴展ID,那么這個成員便記錄擴展ID的值
取值: 0x0 ~ 0x1FFFFFFFIDE :用來決定報文使用標準ID還是擴準ID
取值: CAN_ID_STD 或 CAN_ID_EXTRTR :用來決定報文是數據幀要是遙控幀
取值: CAN_RTR_DATA 或 CAN_RTR_REMOTEDLC :用來記錄數據幀的數據長度,單位字節(如果要發送的是遙控幀,該成員中的內容不起作用)
取值:0 ~ 8TransmitGlobalTime :目前沒有用到,選擇 DISABLE
取值: ENABLE 或 DISABLE
發送用到的函數如下:
HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox);
CAN_TxHeaderTypeDef can_Tx;
uint8_t sendBuf[5] = {"hello"};
uint32_t box;int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_CAN_Init();HAL_CAN_Start(&hcan1);can_Tx.StdId = 0x123;can_Tx.ExtId = 0;can_Tx.IDE = CAN_ID_STD;can_Tx.RTR = CAN_RTR_DATA;can_Tx.DLC = 5;can_Tx.TransmitGlobalTime = DISABLE;while (1){HAL_CAN_AddTxMessage(&hcan1, &can_Tx, sendBuf, &box);HAL_Delay(100);}
}
效果:每隔100ms發送一條報文
?篩選器
?typedef struct
{
? uint32_t FilterIdHigh; ? ? ? ? ?//CAN_FiR1寄存器的高16位
? uint32_t FilterIdLow; ? ? ? ? ? //CAN_FiR1寄存器的低16位
? uint32_t FilterMaskIdHigh; ? ? ?//CAN_FiR2寄存器的高16位
? uint32_t FilterMaskIdLow; ? ? ? //CAN_FiR2寄存器的低16位
? uint32_t FilterFIFOAssignment; ?//通過篩選器的報文存在FIFO0還是FIFO1中
? uint32_t FilterBank; ? ? ? ? ? ?//此次配置用的是哪個篩選器。用單CAN的取值為0-13
? uint32_t FilterMode; ? ? ? ? ? ?//掩碼模式或列表模式
? uint32_t FilterScale; ? ? ? ? ? //32位或16位
? uint32_t FilterActivation; ? ? ?//使能或失能
? uint32_t SlaveStartFilterBank; ?//CAN1和CAN2一起用的時候,為CAN2分配篩選器的個數
} CAN_FilterTypeDef;成員:
FilterIdHigh :CAN_FiR1寄存器的高16位,用于填寫篩選碼。具體的格式要根據16位、32位;掩碼模式、列表模式來確定。
取值: 0x0 ~ 0xFFFFFilterIdLow :CAN_FiR1寄存器的低16位
FilterMaskIdHigh :CAN_FiR2寄存器的高16位
FilterMaskIdLow :CAN_FiR2寄存器的低16位
FilterFIFOAssignment :通過篩選器的報文存在FIFO0還是FIFO1中
取值:CAN_FILTER_FIFO0 或 CAN_FILTER_FIFO1FilterBank :本次配置的篩選器號
取值:對于單CAN為 0 ~ 13;對于雙CAN為 0 ~ 27FilterMode :篩選模式,掩碼模式或列表模式。
取值:CAN_FILTERMODE_IDMASK 或 CAN_FILTERMODE_IDMASKFilterScale :篩選碼大小,16位或32位。
取值:CAN_FILTERSCALE_16BIT 或 CAN_FILTERSCALE_32BITFilterActivation :使能或失能此篩選器。
取值:CAN_FILTER_DISABLE 或 CAN_FILTER_ENABLESlaveStartFilterBank :為從CAN(CAN2)分配的篩選器個數。如果只使用單個CAN,可忽略此成員
取值:0 ~ 27
填好篩選器結構體,然后調用下面這個函數即可生效:
HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *sFilterConfig);
CAN_FilterTypeDef can_Filter = {0};can_Filter.FilterIdHigh = 0;
can_Filter.FilterIdLow = 0;
can_Filter.FilterMaskIdHigh = 0;
can_Filter.FilterMaskIdLow = 0;
can_Filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
can_Filter.FilterBank = 0;
can_Filter.FilterMode = CAN_FILTERMODE_IDMASK;
can_Filter.FilterScale = CAN_FILTERSCALE_32BIT;
can_Filter.FilterActivation = CAN_FILTER_ENABLE;HAL_CAN_ConfigFilter(&hcan1, &can_Filter);
效果:CAN總線上所有的報文都會被接收,并存入FIFO0中。
CAN_FilterTypeDef can_Filter = {0};can_Filter.FilterIdHigh = 0;
can_Filter.FilterIdLow = 0;
can_Filter.FilterMaskIdHigh = 0;
can_Filter.FilterMaskIdLow = 2;
can_Filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
can_Filter.FilterBank = 0;
can_Filter.FilterMode = CAN_FILTERMODE_IDLIST;
can_Filter.FilterScale = CAN_FILTERSCALE_32BIT;
can_Filter.FilterActivation = CAN_FILTER_ENABLE;HAL_CAN_ConfigFilter(&hcan1, &can_Filter);
效果:僅接收標準ID為0x0的數據幀和遙控幀,并存入FIFO0中。
接收
? CAN的接收通常是使用中斷方式來實現(因為沒有DMA,而查詢法又難以保證實時性),因此首先要在CubeMX中打開接收的全局中斷。
以看到有兩個中斷,一個是FIFO0收到數據的RX0中斷,另一個是FIFO1收到數據的RX1中斷,這里只用到了FIFO0,所以只勾選這個。(這里也說一說自己的理解,由于一個FIFO只能保存3條報文,有了兩個FIFO就能保存6條報文。我們可以通過篩選器把不同ID的報文裝進不同的FIFO,比如我們可以讓FIFO0來接收關鍵、重要的報文,用FIFO1來接收不那么重要的報文,并且這兩個中斷是獨立的,我們甚至可以給它們配置不一樣的中斷優先級。)
? 光打開全局中斷還不夠,我們還需要打開CAN的FIFO消息掛起中斷請求(也就是CAN外設的中斷使能位)。
HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
? 這樣,當CAN收到了符合篩選器的報文時,就會觸發這個中斷,我們便可以在這個中斷回調函數中接收并處理收到的報文。(由于FIFO0和FIFO1用到的中斷函數是獨立的,因此這里的回調函數也是不一樣的,大家要看清楚是FIFO0的還是1的)
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &can_Rx, recvBuf);/*下面是你用來處理收到數據的代碼,可以通過串口把內容發送出來,也可以用來控制某些外設*/
}
?接收用到的結構體如下:
typedef struct
{uint32_t StdId; uint32_t ExtId; uint32_t IDE; uint32_t RTR; uint32_t DLC; uint32_t Timestamp; uint32_t FilterMatchIndex;
} CAN_RxHeaderTypeDef;
和發送結構體非常類似,不過這個結構體并不需要我們來賦值,而是作為接收函數的輸出參數。這里僅介紹發送結構體沒有的成員:
Timestamp
?:只有使能了時間觸發模式才有用,記錄時間戳FilterMatchIndex
?:這條報文被接收是通過哪個篩選器
接收用到的函數如下:
HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, uint32_t RxFifo, CAN_RxHeaderTypeDef *pHeader, uint8_t aData[]);
參數:
*hcan
?:can的句柄,由CubeMX自動幫我們定義RxFifo
?:接收FIFO號。參數:?CAN_RX_FIFO0
?或?CAN_RX_FIFO1
pHeader
?:接收結構體,這里作為輸出參數aData[]
?:接收數組,這里作為輸出參數
示例:
#include <stdio.h>CAN_RxHeaderTypeDef can_Rx;
uint8_t recvBuf[8];uint8_t uartBuf[64];int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_CAN_Init();MX_USART1_UART_Init()CAN_FilterTypeDef can_Filter = {0};can_Filter.FilterIdHigh = 0;can_Filter.FilterIdLow = 0;can_Filter.FilterMaskIdHigh = 0;can_Filter.FilterMaskIdLow = 0;can_Filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;can_Filter.FilterBank = 0;can_Filter.FilterMode = CAN_FILTERMODE_IDMASK;can_Filter.FilterScale = CAN_FILTERSCALE_32BIT;can_Filter.FilterActivation = CAN_FILTER_ENABLE;HAL_CAN_ConfigFilter(&hcan1, &can_Filter);HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);HAL_CAN_Start(&hcan1);while (1){}
}void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{uint16_t len = 0;HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &can_Rx, recvBuf);if(can_Rx.IDE == CAN_ID_STD){len += sprintf((char *)&uartBuf[len], "標準ID:%#X; ", can_Rx.StdId);}else if(can_Rx.IDE == CAN_ID_EXT){len += sprintf((char *)&uartBuf[len], "擴展ID:%#X; ", can_Rx.ExtId);}if(can_Rx.RTR == CAN_RTR_DATA){len += sprintf((char *)&uartBuf[len], "數據幀; 數據為:");for(int i = 0; i < can_Rx.DLC; i ++){len += sprintf((char *)&uartBuf[len], "%X ", recvBuf[i]);}len += sprintf((char *)&uartBuf[len], "\r\n");HAL_UART_Transmit(&huart1, uartBuf, len, 100); }else if(can_Rx.RTR == CAN_RTR_REMOTE){len += sprintf((char *)&uartBuf[len], "遙控幀\r\n");HAL_UART_Transmit(&huart1, uartBuf, len, 100); }
}
效果:接收CAN總線上所有數據,并將內容通過串口打印出來
?
STM32 CAN初始化詳解
CAN是控制器域網 (Controller Area Network, CAN) 的簡稱,是由研發和生產汽車電子產品著稱的德國BOSCH公司開發了的,并最終成為國際標準(ISO11898)。是國際上應用最廣泛的現場總線之一。 在北美和西歐,CAN總線協議已經成為汽車計算機控制系統和嵌入式工業控制局域網的標準總線,并且擁有以CAN為底層協議專為大型貨車和重工機械車輛設計的J1939協議。近年來,其所具有的高可靠性和良好的錯誤檢測能力受到重視,被廣泛應用于汽車計算機控制系統和環境溫度惡劣、電磁輻射強和振動大的工業環境。
原文鏈接:https://blog.csdn.net/qq_20017379/article/details/125902421
u8 CAN1_Mode_Init(u8 tsjw, u8 tbs2,u8 tbs1, u16 brp, u8 mode)
{/* gpio結構體 */GPIO_InitTypeDef GPIO_InitStructure;/* can 初始化結構體 */CAN_InitTypeDef CAN_InitStructure;/* can過濾器結構體 */CAN_FilterInitTypeDef CAN_FilterInitStructure;/* 使能時鐘 */RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);/* 初始化gpio設置引腳復用模式推挽速率100上拉*/GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11| GPIO_Pin_12;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;GPIO_Init(GPIOA, &GPIO_InitStructure);/* 復用pa11 pa12為can功能 */GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_CAN1);GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_CAN1);/* 初始化can結構體 *//*事件觸發消息傳輸機制在TTCAN模式下,CAN硬件的內部定時器被激活,并且被用于產生發送與接收郵箱的)時間戳為了使can滿足,適合實時性和可靠性要求特別高或有安全性要求的場合路上各節點取得同步后, 消息只能根據調度表在規定的時間隙傳輸, 避免了消息傳輸的沖突、仲裁,消息傳 輸時延短, 且可預知*/CAN_InitStructure.CAN_TTCM=DISABLE;/* 軟件自動離線管理ENABLE:一旦硬件檢測到128 次11位連續的隱性位,則自動退出離線狀態將ABOM設1后,一旦檢測到條件會自動恢復的,不需要人工干預如果ABOM位為’1’,bxCAN進入離線狀態后,就自動開啟恢復過程。如果ABOM位為’0’,軟件必須先請求bxCAN進入然后再退出初始化模式,隨后恢復過程才被開啟*/CAN_InitStructure.CAN_ABOM=DISABLE;/* 睡眠模式禁用軟件通過對CAN_MCR寄存器的SLEEP位置’1’,來請求進入這一模式。在該模式下,bxCAN的時鐘停止了,但軟件仍然可以訪問郵箱寄存器。當bxCAN處于睡眠模式,軟件必須對CAN_MCR寄存器的INRQ位置’1’并且同時對SLEEP位清’0’,才能進入初始化模式。有2種方式可以喚醒(退出睡眠模式)bxCAN:通過軟件對SLEEP位清’1’,或硬件檢測到CAN總線的活動。如果CAN_MCR寄存器的AWUM位為’1’,一旦檢測到CAN總線的活動,硬件就自動對SLEEP位清’0’來喚醒bxCAN。如果CAN_MCR寄存器的AWUM位為’0’,軟件必須在喚醒中斷里對SLEEP位清’0’才能退出睡眠狀態。注: 如果喚醒中斷被允許(CAN_IER寄存器的WKUIE位為’1’),那么一旦檢測到CAN總線活動就會產生喚醒中斷,而不管硬件是否會自動喚醒bxCAN。在對SLEEP位清’0’后,睡眠模式的退出必須與CAN總線同步,當硬件對SLAK位清’0’時,就確認了睡眠模式的退出。*/CAN_InitStructure.CAN_AWUM=DISABLE;/* 自動重傳使能該模式主要用于滿足CAN標準中,時間觸發通信選項的需求。通過對CAN_MCR寄存器的NART位置’1’,來讓硬件工作在該模式。在該模式下,發送操作只會執行一次。如果發送操作失敗了,不管是由于仲裁丟失或出錯,硬件都不會再自動發送該報文。*/CAN_InitStructure.CAN_NART=ENABLE;/*報文不鎖定,新報文覆蓋舊報文*/CAN_InitStructure.CAN_RFLM=DISABLE;/* 優先級由報文標識符決定本成員用于選擇CAN報文發送優先級判定方法用于選擇CAN報文發送優先級判定方法*/CAN_InitStructure.CAN_TXFP=DISABLE;/*#define CAN_Mode_Normal 正常模式#define CAN_Mode_LoopBack 回環模式 自己發,自己收回環模式下,它自己的輸出端的所有內容都直接傳輸到自己的輸入端,輸出端的內容同時也會被傳輸到總線上,即也可使用總線監測它的發送內容。輸入端只接收自己發送端的內容,不接收來自總線上的內容。使用回環模式可以進行自檢。#define CAN_Mode_Silent 靜默模式靜默模式下,它自己的輸出端的邏輯 0 數據會直接傳輸到它自己的輸入端,邏輯1可以被發送到總線,所以它不能向總線發送顯性位(邏輯 0),只能發送隱性位(邏輯 1)。輸入端可以從總線接收內容。由于它只可發送的隱性位不會強制影響總線的狀態,所以把它稱為靜默模式。這種模式一般用于監測,它可以用于分析總線上的流量,但又不會因為發送顯性位而影響總線#define CAN_Mode_Silent_LoopBack 靜默回環模式回環靜默模式是以上兩種模式的結合,自己的輸出端的所有內容都直接傳輸到自己的輸入端,并且不會向總線發送顯性位影響總線,不能通過總線監測它的發送內容。輸入端只接收自己發送端的內容,不接收來自總線上的內容。這種方式可以在“熱自檢”時使用,即自我檢查的時候,不會干擾總線*/CAN_InitStructure.CAN_Mode= mode;/*重新同步跳躍寬度(SJW) 。定義了在每位中可以延長或縮短多少個時間單元的上限。其值可以編程為1到4個時間單元*/CAN_InitStructure.CAN_SJW=tsjw;/*時間段1(BS1):定義采樣點的位置。其值可以編程為1到16個時間單元,但也可以被自動延長,以補償因為網絡中不同節點的頻率差異所造成的相位的正向漂移。*/CAN_InitStructure.CAN_BS1=tbs1;/*時間段2(BS2):定義發送點的位置。其值可以編程為1到8個時間單元,但也可以被自動縮短以補償相位的負向漂移。*/CAN_InitStructure.CAN_BS2=tbs2;/*分頻率*/CAN_InitStructure.CAN_Prescaler=brp;/* 初始化結構體 */CAN_Init(CAN1, &CAN_InitStructure);/* 初始化過濾器 *//*選擇過濾器0~13 for one can register*/CAN_FilterInitStructure.CAN_FilterNumber = 0;/*屏蔽位模式和標識符列表模式#define CAN_FilterMode_IdMask ((uint8_t)0x00) #define CAN_FilterMode_IdList ((uint8_t)0x01)*/CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;/* 過濾器的位數#define CAN_FilterScale_16bit ((uint8_t)0x00)#define CAN_FilterScale_32bit ((uint8_t)0x01)*/CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;/*32位ID 高位*/CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;32??ID/*32位ID 低位*/CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;/* 屏蔽位高字節 */CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;/* 屏蔽位低字節 */CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;/* 設定接收FIFO */CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;/* 激活過濾組 */CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;/* 初始化過濾器 */CAN_FilterInit(&CAN_FilterInitStructure);/* 配置can中斷*/NVIC_InitTypeDef NVIC_InitStructure;CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);return 0;
}