[TOC]

CAN通讯配置

最近做项目需要用到can通信,这里分享一下自己的can通信学习代码,我使用的是正点原子的精英开发板,参考的资料也是正点原子的库函数指南,此外我也看完了can入门手册(21ic电子网可以下载到),对can通信原理了解了不少,can的内容还是很多的,这里我也不说原理,毕竟内容太多,只分享一下自己的代码,本来是跟着正点原子的例程走的,结果我的tft屏幕坏了(特容易坏),而且自己也只有一块开发板,没有办法,就仿真吧,(插一条:仿真来找小虫子简直不要太爽,我后面分享一下自己用仿真的一些小经验吧),学习32后面基本上要用到按键和LED,建议大家只看原理图自己写一遍,有自己的代码,方便以后调用,显示屏也是OLED和TFT两个在后面的代码调试中结合仿真器可以很快解决一些看起来无从下手的代码。
不说太多,直接上can的代码。

配置的基本流程很容易理解,第一步配置IO口,二、can初始化。三、filter(过滤器初始化)。这三个配置好之后,再封装两个函数发送和接收函数就可以了,接收的话也可以使用接收终端来接收,当FIFO里面有数据时产生标志,进入中断处理数据。

配置IO口:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);

gpio.GPIO_Mode=GPIO_Mode_IPU;
gpio.GPIO_Pin=GPIO_Pin_11;
GPIO_Init(GPIOA,&gpio);

gpio.GPIO_Mode=GPIO_Mode_AF_PP;
gpio.GPIO_Pin=GPIO_Pin_12;
gpio.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&gpio);

can初始化:

//can初始化
can.CAN_TTCM=DISABLE;//以下为枚举类型
can.CAN_ABOM=DISABLE;
can.CAN_AWUM=DISABLE;
can.CAN_RFLM=DISABLE;
can.CAN_NART=ENABLE;
can.CAN_TXFP=DISABLE;

can.CAN_Mode=CAN_Mode_LoopBack;//模式选择
//波特率配置,该计算公式在can入门手册里面有不多说(21ic电子网可以下载到)
can.CAN_BS1=CAN_BS1_8tq;
can.CAN_BS2=CAN_BS2_7tq;
can.CAN_Prescaler=5;
can.CAN_SJW=CAN_SJW_1tq;
CAN_Init(CAN1,&can);

filter配置:

//过滤器配置
filter.CAN_FilterIdHigh=0x0000;//id配置
filter.CAN_FilterIdLow=0x0000;
filter.CAN_FilterMaskIdHigh=0x0000;
filter.CAN_FilterMaskIdLow=0x0000;

filter.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0; //关联到FIFOo
filter.CAN_FilterNumber=0;
filter.CAN_FilterMode=CAN_FilterMode_IdMask; //模式选择
filter.CAN_FilterScale=CAN_FilterScale_32bit;//单32位还是双16位选择
filter.CAN_FilterActivation=ENABLE;
CAN_FilterInit(&filter);

发送信息函数:

u8 can_send(u8 *msg,u8 len){
u8 mbox;
u16 i=0;
CanTxMsg TX;//发送ID
TX.StdId=0X12;
TX.ExtId=0x12;
TX.DLC=len;//发送长度
TX.IDE=CAN_Id_Standard; 
TX.RTR=CAN_RTR_Data;
for(i=0;i<len;i++)
TX.Data[i]=msg[i];//数据参数传递
mbox=CAN_Transmit(CAN1,&TX);
i=0;
while((CAN_TransmitStatus(CAN1,mbox)!=CAN_TxStatus_Ok)&&(i<0xfff))i++;
if(i>=0xfff)
    return 1;
return 0;
}

接收信息函数:

u8 can_rec(u8 *buf)
{
u32 i;
CanRxMsg RxMessage;
if( CAN_MessagePending(CAN1,CAN_FIFO0)==0)return 0;        //没有接收到数据,直接退出 
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//读取数据    
for(i=0;i<8;i++)
buf[i]=RxMessage.Data[i];  
return RxMessage.DLC;    
}

接受中断配置:

我没有使能,使参考时要注意一下

CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
nvic.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;
nvic.NVIC_IRQChannelCmd=DISABLE;
nvic.NVIC_IRQChannelPreemptionPriority=1;
nvic.NVIC_IRQChannelSubPriority=0;
NVIC_Init(&nvic);

当然还有接收中断:

void USB_LP_CAN1_RX0_IRQHandler(void)
{
CanRxMsg RxMessage;
int i=0;
CAN_Receive(CAN1, 0, &RxMessage);
for(i=0;i<8;i++)
printf("rxbuf[%d]:%d\r\n",i,RxMessage.Data[i]);
}

主函数

现象:KEY0按下发送数据第一位为‘1’,发送成功红灯亮,接收成功且判断第一位为‘1’则亮绿灯,key1灭掉所以灯。

 int main(void)
{
 u8 key,res;
 u8 canbuf[8],buf[8];
 led_init();
 key_init();
 delay_init();
 can_init();
 canbuf[0]='1';
while(1)
 {
    key=key_scan(1);
    if(key==1)
    {
        res=can_send(canbuf,8);
        if(!res)
            LED_RED_ON;
    }
    if(key==2)
    {
        LED_RED_OFF;
        LED_GREEN_OFF;
    }            
    can_rec(buf);
    if(buf[0]=='1')
    {
        LED_GREEN_ON;
        buf[0]='0';
    }
  }
}

wechat