#include "can.h"
#include "led.h"
#include "delay.h"
#include "usart.h"
u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{
u16 i=0;
if(tsjw==0||tbs2==0||tbs1==0||brp==0)return 1;
tsjw-=1;//先減去1.再用于設置
tbs2-=1;
tbs1-=1;
brp-=1;
RCC->APB2ENR|=1<<2; //使能PORTA時鐘
GPIOA->CRH&=0XFFF00FFF;
GPIOA->CRH|=0X000B8000; //PA11 RX,PA12 TX推挽輸出
GPIOA->ODR|=3<<11;
RCC->APB1ENR|=1<<25; //使能CAN時鐘 CAN使用的是APB1的時鐘(max:36M)
CAN1->MCR=0x0000; //退出睡眠模式(同時設置所有位為0)
CAN1->MCR|=1<<0; //請求CAN進入初始化模式
while((CAN1->MSR&1<<0)==0)
{
i++;
if(i>100)return 2; //進入初始化模式失敗
}
CAN1->MCR|=0<<7; //非時間觸發通信模式
CAN1->MCR|=0<<6; //軟件自動離線管理
CAN1->MCR|=0<<5; //睡眠模式通過軟件喚醒(清除CAN1->MCR的SLEEP位)
CAN1->MCR|=1<<4; //禁止報文自動傳送
CAN1->MCR|=0<<3; //報文不鎖定,新的覆蓋舊的
CAN1->MCR|=0<<2; //優先級由報文標識符決定
CAN1->BTR=0x00000000; //清除原來的設置.
CAN1->BTR|=mode<<30; //模式設置 0,普通模式;1,回環模式;
CAN1->BTR|=tsjw<<24; //重新同步跳躍寬度(Tsjw)為tsjw+1個時間單位
CAN1->BTR|=tbs2<<20; //Tbs2=tbs2+1個時間單位
CAN1->BTR|=tbs1<<16; //Tbs1=tbs1+1個時間單位
CAN1->BTR|=brp<<0; //分頻系數(Fdiv)為brp+1
//波特率:Fpclk1/((Tbs1+Tbs2+1)*Fdiv)
CAN1->MCR&=~(1<<0); //請求CAN退出初始化模式
while((CAN1->MSR&1<<0)==1)
{
i++;
if(i>0XFFF0)return 3;//退出初始化模式失敗
}
//過濾器初始化
CAN1->FMR|=1<<0; //過濾器組工作在初始化模式
CAN1->FA1R&=~(1<<0); //過濾器0不激活
CAN1->FS1R|=1<<0; //過濾器位寬為32位.
CAN1->FM1R|=0<<0; //過濾器0工作在標識符屏蔽位模式
CAN1->FFA1R|=0<<0; //過濾器0關聯到FIFO0
CAN1->sFilterRegister[0].FR1=0X00000000;//32位ID
CAN1->sFilterRegister[0].FR2=0X00000000;//32位MASK
CAN1->FA1R|=1<<0; //激活過濾器0
CAN1->FMR&=0<<0; //過濾器組進入正常模式
#if CAN_RX0_INT_ENABLE
//使用中斷接收
CAN1->IER|=1<<1; //FIFO0消息掛號中斷允許.
MY_NVIC_Init(1,0,USB_LP_CAN1_RX0_IRQn,2);//組2
#endif
return 0;
}
u8 CAN_Tx_Msg(u32 id,u8 ide,u8 rtr,u8 len,u8 *dat)
{
u8 mbox;
if(CAN1->TSR&(1<<26))mbox=0; //郵箱0為空
else if(CAN1->TSR&(1<<27))mbox=1; //郵箱1為空
else if(CAN1->TSR&(1<<28))mbox=2; //郵箱2為空
else return 0XFF; //無空郵箱,無法發送
CAN1->sTxMailBox[mbox].TIR=0; //清除之前的設置
if(ide==0) //標準幀
{
id&=0x7ff;//取低11位stdid
id<<=21;
}else //擴展幀
{
id&=0X1FFFFFFF;//取低32位extid
id<<=3;
}
CAN1->sTxMailBox[mbox].TIR|=id;
CAN1->sTxMailBox[mbox].TIR|=ide<<2;
CAN1->sTxMailBox[mbox].TIR|=rtr<<1;
len&=0X0F;//得到低四位
CAN1->sTxMailBox[mbox].TDTR&=~(0X0000000F);
CAN1->sTxMailBox[mbox].TDTR|=len; //設置DLC.
//待發送數據存入郵箱.
CAN1->sTxMailBox[mbox].TDHR=(((u32)dat[7]<<24)|
((u32)dat[6]<<16)|
((u32)dat[5]<<8)|
((u32)dat[4]));
CAN1->sTxMailBox[mbox].TDLR=(((u32)dat[3]<<24)|
((u32)dat[2]<<16)|
((u32)dat[1]<<8)|
((u32)dat[0]));
CAN1->sTxMailBox[mbox].TIR|=1<<0; //請求發送郵箱數據
return mbox;
}
u8 CAN_Tx_Staus(u8 mbox)
{
u8 sta=0;
switch (mbox)
{
case 0:
sta |= CAN1->TSR&(1<<0); //RQCP0
sta |= CAN1->TSR&(1<<1); //TXOK0
sta |=((CAN1->TSR&(1<<26))>>24);//TME0
break;
case 1:
sta |= CAN1->TSR&(1<<8)>>8; //RQCP1
sta |= CAN1->TSR&(1<<9)>>8; //TXOK1
sta |=((CAN1->TSR&(1<<27))>>25);//TME1
break;
case 2:
sta |= CAN1->TSR&(1<<16)>>16; //RQCP2
sta |= CAN1->TSR&(1<<17)>>16; //TXOK2
sta |=((CAN1->TSR&(1<<28))>>26);//TME2
break;
default:
sta=0X05;//郵箱號不對,肯定失敗.
break;
}
return sta;
}
u8 CAN_Msg_Pend(u8 fifox)
{
if(fifox==0)return CAN1->RF0R&0x03;
else if(fifox==1)return CAN1->RF1R&0x03;
else return 0;
}
void CAN_Rx_Msg(u8 fifox,u32 *id,u8 *ide,u8 *rtr,u8 *len,u8 *dat)
{
*ide=CAN1->sFIFOMailBox[fifox].RIR&0x04; //得到標識符選擇位的值
if(*ide==0)//標準標識符
{
*id=CAN1->sFIFOMailBox[fifox].RIR>>21;
}else //擴展標識符
{
*id=CAN1->sFIFOMailBox[fifox].RIR>>3;
}
*rtr=CAN1->sFIFOMailBox[fifox].RIR&0x02; //得到遠程發送請求值.
*len=CAN1->sFIFOMailBox[fifox].RDTR&0x0F; //得到DLC
//*fmi=(CAN1->sFIFOMailBox[FIFONumber].RDTR>>8)&0xFF;//得到FMI
//接收數據
dat[0]=CAN1->sFIFOMailBox[fifox].RDLR&0XFF;
dat[1]=(CAN1->sFIFOMailBox[fifox].RDLR>>8)&0XFF;
dat[2]=(CAN1->sFIFOMailBox[fifox].RDLR>>16)&0XFF;
dat[3]=(CAN1->sFIFOMailBox[fifox].RDLR>>24)&0XFF;
dat[4]=CAN1->sFIFOMailBox[fifox].RDHR&0XFF;
dat[5]=(CAN1->sFIFOMailBox[fifox].RDHR>>8)&0XFF;
dat[6]=(CAN1->sFIFOMailBox[fifox].RDHR>>16)&0XFF;
dat[7]=(CAN1->sFIFOMailBox[fifox].RDHR>>24)&0XFF;
if(fifox==0)CAN1->RF0R|=0X20;//釋放FIFO0郵箱
else if(fifox==1)CAN1->RF1R|=0X20;//釋放FIFO1郵箱
}
#if CAN_RX0_INT_ENABLE //使能RX0中斷
//中斷服務函數
void USB_LP_CAN1_RX0_IRQHandler(void)
{
u8 rxbuf[8];
u32 id;
u8 ide,rtr,len;
CAN_Rx_Msg(0,&id,&ide,&rtr,&len,rxbuf);
printf("id:%d\r\n",id);
printf("ide:%d\r\n",ide);
printf("rtr:%d\r\n",rtr);
printf("len:%d\r\n",len);
printf("rxbuf[0]:%d\r\n",rxbuf[0]);
printf("rxbuf[1]:%d\r\n",rxbuf[1]);
printf("rxbuf[2]:%d\r\n",rxbuf[2]);
printf("rxbuf[3]:%d\r\n",rxbuf[3]);
printf("rxbuf[4]:%d\r\n",rxbuf[4]);
printf("rxbuf[5]:%d\r\n",rxbuf[5]);
printf("rxbuf[6]:%d\r\n",rxbuf[6]);
printf("rxbuf[7]:%d\r\n",rxbuf[7]);
}
#endif
u8 CAN_Send_Msg(u8* msg,u8 len)
{
u8 mbox;
u16 i=0;
mbox=CAN_Tx_Msg(0X12,0,0,len,msg);
while((CAN_Tx_Staus(mbox)!=0X07)&&(i<0XFFF))i++;//等待發送結束
if(i>=0XFFF)return 1; //發送失敗?
return 0; //發送成功;
}
u8 CAN_Receive_Msg(u8 *buf)
{
u32 id;
u8 ide,rtr,len;
if(CAN_Msg_Pend(0)==0)return 0; //沒有接收到數據,直接退出
CAN_Rx_Msg(0,&id,&ide,&rtr,&len,buf); //讀取數據
if(id!=0x12||ide!=0||rtr!=0)len=0; //接收錯誤
return len;
}
本文章參考正點原子的CAN 通信實驗!!
|