前面對CAN原理進行了講解,這里我用一個簡單的例子來說明CAN的使用。我使用的STM32芯片是STM32F103ZE,幾個基本的配置是:
1.配置CAN時鐘:
/* CAN Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN, ENABLE);
2.CAN管腳配置,這里使用的PB11,PB12管腳:
/* Configure CAN pin: RX */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure CAN pin: TX */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
3.中斷配置,這里打開CAN的接收和發(fā)送中斷:
/* CAN RX interrupt */
NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN_RX0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* CAN TX interrupt */
NVIC_InitStructure.NVIC_IRQChannel=USB_HP_CAN_TX_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 5;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
這里需要注意的是CAN的發(fā)送中斷,發(fā)送中斷是發(fā)送郵箱中數據發(fā)送完畢后產生的發(fā)送完畢郵箱空中斷--這和USART發(fā)送中斷不同。詳細點說CAN發(fā)送中斷是指CAN的三個發(fā)送郵箱中的其中一個由滿到發(fā)送數據完畢后空才產生的中斷,當原來發(fā)送郵箱本來就是空的則不會產生發(fā)送中斷。
4.CAN初始化配置:
void CAN_Ini(void)
{
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
/* CAN register init */
CAN_DeInit();
CAN_StructInit(&CAN_InitStructure);
/* CAN cell init */
CAN_InitStructure.CAN_TTCM=DISABLE; //禁止時間觸發(fā)通信模式
CAN_InitStructure.CAN_ABOM=DISABLE; //軟件對CAN_MCR寄存器的INRQ位進行置1隨后清0后,一旦硬件檢測
//到128次11位連續(xù)的隱性位,就退出離線狀態(tài)。
CAN_InitStructure.CAN_AWUM=DISABLE; //睡眠模式通過清除CAN_MCR寄存器的SLEEP位,由軟件喚醒
CAN_InitStructure.CAN_NART=DISABLE; //CAN報文只被發(fā)送1次,不管發(fā)送的結果如何(成功、出錯或仲裁丟失)
CAN_InitStructure.CAN_RFLM=DISABLE; //在接收溢出時FIFO未被鎖定,當接收FIFO的報文未被讀出,下一個收到的報文會覆蓋原有的報文
CAN_InitStructure.CAN_TXFP=ENABLE; //用來使能或者失能發(fā)送FIFO優(yōu)先級,由發(fā)送的請求順序決定
CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;//CAN硬件工作在正常模式
switch(CAN_BPP)
{
//總體配置保持,tBS1>=tBS2,tBS2>=1個CAN時鐘周期,tBS2>=2tSJW
case 100000:
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; //重新同步跳躍寬度
CAN_InitStructure.CAN_BS1=CAN_BS1_10tq; //設定時間段1的時間單位數目
CAN_InitStructure.CAN_BS2=CAN_BS2_7tq; //設定時間段2的時間單位數目
CAN_InitStructure.CAN_Prescaler=20; //一個時間單位的長度//(pclk1/((4+8+8)*9)) = 36Mhz/18/20 = 100Kbits
break;
case 50000:
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1=CAN_BS1_10tq;
CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;
CAN_InitStructure.CAN_Prescaler=40; //(pclk1/((4+8+8)*9)) = 36Mhz/18/40 = 50Kbits
break;
case 20000:
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1=CAN_BS1_10tq;
CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;
CAN_InitStructure.CAN_Prescaler=100; //(pclk1/((4+8+8)*9)) = 36Mhz/18/100 = 20Kbits
break;
case 250000:
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;
CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;
CAN_InitStructure.CAN_Prescaler=9; //(pclk1/((1+8+7)*9)) = 36Mhz/16/9 = 250Kbits
break;
case 500000:
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; //重新同步跳躍寬度1個時間單位
CAN_InitStructure.CAN_BS1=CAN_BS1_6tq; //時間段1為6個時間單位
CAN_InitStructure.CAN_BS2=CAN_BS2_5tq; //時間段2為5個時間單位
CAN_InitStructure.CAN_Prescaler=6; //(pclk1/((1+6+5)*6)) = 36Mhz/12/6 = 500Kbits設定了一個時間單位的長度9
break;
default:
break;
}
CAN_Init(&CAN_InitStructure);
/* CAN filter init */
CAN_FilterInitStructure.CAN_FilterNumber=0; //指定了待初始化的過濾器0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //指定了過濾器將被初始化到的模式為標識符屏蔽位模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //給出了過濾器位寬1個32位過濾器
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000; //用來設定過濾器標識符(32位位寬時為其高段位,16位位寬時為第一個)
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000; //用來設定過濾器標識符(32位位寬時為其低段位,16位位寬時為第二個
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000; //用來設定過濾器屏蔽標識符或者過濾器標識符(32位位寬時為其高段位,16位位寬時為第一個
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000; //用來設定過濾器屏蔽標識符或者過濾器標識符(32位位寬時為其低段位,16位位寬時為第二個
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_IT_FMP0; //設定了指向過濾器的FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //使能過濾器
CAN_FilterInit(&CAN_FilterInitStructure);
/* CAN FIFO0 message pending interrupt enable */
CAN_ClearITPendingBit(CAN_IT_FF0);
CAN_ClearITPendingBit(CAN_IT_FOV0);
CAN_ClearITPendingBit(CAN_IT_FF1);
CAN_ClearITPendingBit(CAN_IT_FOV1);
CAN_ClearITPendingBit(CAN_IT_RQCP0);
CAN_ClearITPendingBit(CAN_IT_RQCP1);
CAN_ClearITPendingBit(CAN_IT_RQCP2);
CAN_ITConfig(CAN_IT_FMP0, ENABLE); //使能接收中斷
//CAN_ITConfig(CAN_IT_TME, ENABLE); //TransmitMailbox empty,發(fā)送中斷在CAN_Transmit()后才能打開,用來判斷發(fā)送完畢發(fā)送下一個數據
}
5.實現CAN的發(fā)送中斷和接收中斷,這里我們只用了一個發(fā)送郵箱進行發(fā)送--簡單方便:
void USB_LP_CAN_RX0_IRQHandler(void) //接收中斷
{
CanRxMsg RxMessage;
U8 i=0;
U8 targetid=0;
//如果是標準幀
CAN_Receive(CAN_FIFO0, &RxMessage);
if(RxMessage.IDE==CAN_ID_STD)//只收標準幀數據
{
if((RxMessage.StdId&0x1F)==PCL_ID+bmqnum) //接收到ID是取后5位是自己的ID
{
//每個完整的數據,以|開頭,下面是ID
while(!QIn(&Qlinecanrx,'|')){}
targetid=(RxMessage.StdId>>6)&0x1F;
while(!QIn(&Qlinecanrx,targetid)){}
for(i=0;i
while(!QIn(&Qlinecanrx,RxMessage.Data[i])){}
}
}
}
CAN_ITConfig(CAN_IT_FMP0, ENABLE); //中斷退出
}
void USB_HP_CAN_TX_IRQHandler(void)
{
CAN_ClearITPendingBit(CAN_IT_RQCP0);
CAN_ClearITPendingBit(CAN_IT_RQCP1);
CAN_ClearITPendingBit(CAN_IT_RQCP2);
CAN_ITConfig(CAN_IT_TME, DISABLE);
CANSendStr(); //時刻查詢是否可以給上位發(fā)送數據
}
void CANSendStr()
{
CanTxMsg TxMessage;
TxMessage.StdId=PCL_ID+bmqnum; //用來設定標準標識符,0x08+2=0x0A
TxMessage.ExtId=0; //用來設定擴展標識符
TxMessage.RTR=CAN_RTR_DATA; //用來設定待傳輸消息的幀類型,它可以設置為數據幀或者遠程幀,使用數據幀
TxMessage.IDE=CAN_ID_STD; //用來設定消息標識符的類型,使用標準標識符
TxMessage.DLC = 8; //用來設定待傳輸消息的幀長度,它的取值范圍是0到0x8
//20160822----zhang
TxMessage.RTR=CAN_RTR_DATA; //數據幀
//20160822----zhang
TxMessage.Data[0]='~';
TxMessage.Data[1]='0';
TxMessage.Data[2]='1';
TxMessage.Data[3]='2';
TxMessage.Data[4]='3';
TxMessage.Data[5]='4';
TxMessage.Data[6]='5';
TxMessage.Data[7]='6';
CAN_Transmit(&TxMessage);
CAN_ITConfig(CAN_IT_TME, ENABLE); //TransmitMailbox empty,發(fā)送中斷在CAN_Transmit()后才能打開,用來判斷發(fā)送完畢發(fā)送下一個數據
}
6.使用中先使用CANSendStr()發(fā)送一條數據,則發(fā)送完畢后進入發(fā)送空中斷,則之后會循環(huán)發(fā)送數據
參考文章:
http://www.openedv.com/thread-38867-1-1.html
http://www.stmcu.org/module/forum/thread-565605-1-1.html
http://www.cnblogs.com/chris-cp/p/3961508.html
http://www.openedv.com/thread-51889-1-1.html
上一篇:STM32的CAN總線學習總結
下一篇:STM32之CAN通信
推薦閱讀
史海拾趣
1979年,Fabrimex AG接管了ARCO-Solar(美國)的代表處,標志著公司正式進入光伏領域。這一舉措為公司帶來了新的增長點,并推動了相關產品的研發(fā)和生產。隨著光伏技術的不斷發(fā)展,Fabrimex AG在光伏領域逐漸取得了顯著的成績,為公司帶來了可觀的收益。
1954年至1973年,Emerson在總裁帕森斯的領導下,開始實施多元化戰(zhàn)略。公司通過一系列并購活動,成功收購了包括威諾、美國電氣電機、里奇工具等在內的36家公司,進一步拓寬了業(yè)務范圍。同時,Emerson還注重研發(fā)和創(chuàng)新,通過不斷推出新產品和技術,鞏固了其在電氣行業(yè)的領先地位。在此期間,公司的規(guī)模迅速擴大,從最初的2家工廠、4000名員工和5600萬美元產值發(fā)展到82家工廠、31000名員工和8億美元產值。
隨著環(huán)保意識的提高,Diotec開始關注綠色發(fā)展和社會責任。公司積極采用環(huán)保材料和生產工藝,減少生產過程中的環(huán)境污染。同時,Diotec還參與了一系列公益活動,為當地社區(qū)和環(huán)境保護事業(yè)做出了貢獻。這些舉措不僅提升了公司的社會形象,也為公司的長期發(fā)展奠定了基礎。
虹冠電子自成立以來,一直將技術創(chuàng)新作為公司發(fā)展的核心動力。早期,虹冠電子就投入大量資源研發(fā)AC-DC模擬電源IC,成功推出了一系列高效能、低能耗的產品,迅速在市場上建立了良好的口碑。隨著技術的不斷迭代,虹冠電子在電源管理技術方面取得了顯著優(yōu)勢,尤其在電競電源供應器領域,憑借卓越的性能和穩(wěn)定性,贏得了眾多專業(yè)用戶和消費者的認可。
近年來,Eclipse Magnetics公司在電火花加工領域取得了顯著的成就。他們推出的Micromag磁過濾器產品在電火花加工過程中實現了巨大的成本節(jié)約。通過與ADM精密工具和Sodi-tech EDM有限公司的合作,Eclipse Magnetics成功提高了Sodick AQ600L線蝕機的效率,減少了停機時間,為客戶帶來了顯著的經濟效益。
隨著市場需求的不斷變化,Elec公司意識到單一產品已無法滿足客戶的多樣化需求。于是,Elec公司開始尋求與同行業(yè)公司的合作。在一次行業(yè)交流會上,Elec公司的代表與Eltek公司的代表相識,并發(fā)現雙方的產品具有很強的互補性。經過多次深入交流,Elec公司與Eltek公司決定開展合作,共同研發(fā)具有更高性能、更廣泛應用的電子產品。這一合作不僅增強了雙方的競爭力,也為客戶提供了更多樣化的選擇。
據說,這幾天有網友在玩網絡游戲時因鐵通網絡不穩(wěn)最終丟失虛擬裝備,于是有意起訴鐵通。原貼見此鏈接http://bbs2.wm090.com/dispbbs.asp?boardID=40&ID=918438&page=1。有部分網友對此表示疑惑,鐵通已被移動收購半年多,以移動的實力,鐵通的 ...… 查看全部問答∨ |
|
在3月份我們在論壇搞了一個按鍵專題活動的討論(http://bbs.eeworld.com.cn/viewthread.php?tid=97931 ),這個活動獲得了大家的廣泛支持,討論的很是熱烈根據討論內容,從大家的討論中,我們學習和了解到了更多的按鍵方面的知識。 俗話說的好:好 ...… 查看全部問答∨ |
|
不知道有沒有人弄過周工的IIC程序包?我在使用LPC2131讀寫AT24C02時,有時候可以進入中斷,有時候有不能進入中斷?希望高手指導一下!!!!!!!!… 查看全部問答∨ |
各位大俠,小弟剛接觸嵌入式。有些基本的問題還沒有搞清楚,請教一下 在一塊板子上,有sdram,nor flash,nand flash 哪個是用來存儲系統的, 這3個又有什么區(qū)別呢?… 查看全部問答∨ |
keil編譯時,提示入下錯誤:(我估計不應該是程序的錯誤,不知道哪里沒有設置正確) Build target \'Target 1\'assembling STARTUP.A51...compiling Lcd.c...C51 FATAL-ERROR - ACTION: GOBAL OPTIMIZATION ...… 查看全部問答∨ |
|
我收到的就一個SD卡,但帶了個SD大卡卡槽。并不是傳說中的,兩個SD卡。 我破不急等地插到USB口上,當然迷你SD卡也插上,發(fā)現硬件。我等著自動裝硬件。但顯示了一個虛擬的U盤。我又傻等一會兒,還是要驅動。 應是U轉串的驅動。 我查型號是FT2232H ...… 查看全部問答∨ |