2021-06-20 CAN总线基础知识一

1】CAN总线为什么要有两个120Ω的终端电阻?
高频信号传输时,信号波长先对传输线较短,信号在传输线终端会形成放射波,干扰原信号,所以需要在传输线末端加终端电阻,使信号到达传输线末端后不放射。对于低频信号则不用。
2】CAN总线远距离通讯接120Ω的终端电阻,有时候通讯不上?
CAN的终端要加120Ω,那是短距离的阻抗匹配结果,如果在长距离上还是加120Ω是会对信号有极大危害的,因为CAN收发器的驱动能力是一定的,传了5公里后,回路线阻抗(CAN_H+CAN_L)将近250Ω,如果加上120Ω电阻,那么终端接收节点的收发器所能收到的电压只有1V左右。这样的的电压幅值的抗干扰能力极差的,通讯呈现为时好时坏的现象。故在远距离通讯中,终端电阻建议加到300Ω-500Ω左右,可以保证信号幅值在1.2V之上。
3】CAN2.0B 协议帧格式

标准帧
在这里插入图片描述
字节 1为帧信息。第 7位( FF )表示帧格式,在标准帧中 FF =0;第 6位( RTRRTR)表 示帧的类型, RTR=0 表示为数据帧, RTR=1 表示为远程帧; DLC 表示在数据帧时实际的数据长度。 最高只能为8位即0x00XX 0111
字节 2、3为报文识别码, ,11 位有效。最高只能位0x07FF 即最大只能为2047
字节 4~11 为数据帧的实际数据,远程帧无效。只能发8个字节数据帧

扩展帧
在这里插入图片描述
字节 1为帧信息。第 7位( FF )表示帧格式,在扩展帧中 FF = 1;第 6位( RTRRTR) 表示帧的类型, RTR=0 表示为数据帧, RTR=1 表示为远程帧; DLC 表示在数据帧时实际的数据长度。
字节 2~5为报文识别码,其高 29 位有效。
字节 6~13 为数据帧的实际数据,远程帧无效。

标准帧与扩展帧得区别在于扩展帧的ID比标准帧多了18位。

CAN发送程序

扩展帧发送
一、

u8 CAN1_Send_Msg(u8* msg, u8 len)//**扩展帧配置为远程帧**
{
    u8 mbox;
    u16 i = 0;
    CanTxMsg TxMessage;
    TxMessage.ExtId = 0xFAFFF2;	 // 设置扩展标示符(29位)
	TxMessage.RTR = CAN_RTR_REMOTE;//该帧为远程帧
    TxMessage.IDE = CAN_ID_EXT;   //帧为扩展帧
    TxMessage.DLC = len;							 // 发送两帧信息
    for(i = 0; i < len; i++)
       TxMessage.Data[i] = msg[i];				 // 第一帧信息
    mbox = CAN_Transmit(CAN1, &TxMessage);
    i = 0;
    while((CAN_TransmitStatus(CAN1, mbox) == CAN_TxStatus_Failed) && (i < 0XFFF))i++;	//等待发送结束
    if(i >= 0XFFF)return 1;
    return 0;

}
CAN1_Send_Msg(Can_txbuffer, 8);

注意:扩展帧配置为远程帧,远程帧不带数据,只有ID号,可以有数据长度,但是无数据。

**

二、

u8 CAN1_Send_Msg(u8* msg, u8 len)**扩展帧配置为数据帧**
{
    u8 mbox;
    u16 i = 0;
    CanTxMsg TxMessage;
    TxMessage.ExtId = 0xFAFFF2;	 // 设置扩展标示符(29位)
    
	TxMessage.RTR = CAN_RTR_DATA;//发送帧类型为数据帧
    TxMessage.IDE = CAN_ID_EXT;   //帧为扩展帧
    
    TxMessage.DLC = len;							 // 发送两帧信息
    for(i = 0; i < len; i++)
        TxMessage.Data[i] = msg[i];				 // 第一帧信息
    mbox = CAN_Transmit(CAN1, &TxMessage);
    i = 0;
    while((CAN_TransmitStatus(CAN1, mbox) == CAN_TxStatus_Failed) && (i < 0XFFF))i++;	//等待发送结束
    if(i >= 0XFFF)return 1;
    return 0;
}

注意:扩展帧配置为数据帧的只需要配置 TxMessage.RTR = CAN_RTR_DATA;

标志帧发送

三、
标准帧数据帧

u8 CAN1_Send_Msg(u8* msg, u8 len)
{
    u8 mbox;
    u16 i = 0;
    CanTxMsg TxMessage;
    TxMessage.StdId =  0xEA;	 // 标准标识符为0
	TxMessage.RTR = CAN_RTR_DATA;//发送帧类型为数据帧
	TxMessage.IDE = CAN_ID_STD;//该帧为标志帧格式
    TxMessage.DLC = len;							 // 发送两帧信息
    for(i = 0; i < len; i++)
        TxMessage.Data[i] = msg[i];				 // 第一帧信息
    mbox = CAN_Transmit(CAN1, &TxMessage);
    i = 0;
    while((CAN_TransmitStatus(CAN1, mbox) == CAN_TxStatus_Failed) && (i < 0XFFF))i++;	//等待发送结束
    if(i >= 0XFFF)return 1;
    return 0;
}

四、标志帧远程帧

u8 CAN1_Send_Msg(u8* msg, u8 len)
{
    u8 mbox;
    u16 i = 0;
    CanTxMsg TxMessage;
    TxMessage.StdId =  0xEA;	 // 标准标识符为0
	TxMessage.RTR = CAN_RTR_REMOTE;//发送帧类型为远程帧
	TxMessage.IDE = CAN_ID_STD;//该帧为标志帧格式
    TxMessage.DLC = len;							 // 发送两帧信息
    for(i = 0; i < len; i++)
        TxMessage.Data[i] = msg[i];				 // 第一帧信息
    mbox = CAN_Transmit(CAN1, &TxMessage);
    i = 0;
    while((CAN_TransmitStatus(CAN1, mbox) == CAN_TxStatus_Failed) && (i < 0XFFF))i++;	//等待发送结束
    if(i >= 0XFFF)return 1;
    return 0;
}

总结:标准帧与扩展帧的配置TxMessage.IDE 相关,帧的ID由TxMessage.StdId与TxMessage.ExtId 控制,stdid为标准帧ID,EXtid为扩展帧的ID。TxMessage.RTR控制该帧的类型使数据帧还是远程帧,CAN_RTR_REMOTE为远程帧,CAN_RTR_DATA为数据帧。

CANJ接收程序

u8  can_rxIDE=0xff;//帧类型:标准帧/扩展帧
u8  can_rxRTR=0xff;//帧形式:数据帧/远程帧
u8  can_rxLEN=0;//数据帧长度
u8  can_rxbuf[8]={0};//数据缓存
u32 can_rxID=0;//帧ID

#define CAN1_RX0_INT_ENABLE	 1		//0,不使能;1,使能.

#if CAN1_RX0_INT_ENABLE	//使能RX0中断
//中断服务函数
void CAN1_RX0_IRQHandler(void)
{
    CanRxMsg RxMessage;
    if(CAN_GetITStatus(CAN1,CAN_IT_FMP0)==SET)
	{
        CAN_Receive(CAN1, 0, &RxMessage);
        memcpy(can_rxbuf,&RxMessage.Data[0],RxMessage.DLC);
		can_rxIDE=RxMessage.IDE;//0为标准帧  0x04为扩展帧
		can_rxRTR=RxMessage.RTR;//0为数据帧  0x02为远程帧
		if(can_rxIDE)
			can_rxID=RxMessage.ExtId;
		else can_rxID=RxMessage.StdId;
	}
	CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);

}
#endif
u8 CAN1_Mode_Init(u8 tsjw, u8 tbs2, u8 tbs1, u16 brp, u8 mode)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    CAN_InitTypeDef        CAN_InitStructure;
    CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    #if CAN1_RX0_INT_ENABLE
    NVIC_InitTypeDef  NVIC_InitStructure;
    #endif
    //使能相关时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能PORTA时钟

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟

    //初始化GPIO
    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;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化PA11,PA12

    //引脚复用映射配置
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_CAN1); //GPIOA11复用为CAN1
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_CAN1); //GPIOA12复用为CAN1

    //CAN单元设置
    CAN_InitStructure.CAN_TTCM = DISABLE;	//非时间触发通信模式
    CAN_InitStructure.CAN_ABOM = DISABLE;	//软件自动离线管理
    CAN_InitStructure.CAN_AWUM = DISABLE; //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
    CAN_InitStructure.CAN_NART = ENABLE;	//禁止报文自动传送
    CAN_InitStructure.CAN_RFLM = DISABLE;	//报文不锁定,新的覆盖旧的
    CAN_InitStructure.CAN_TXFP = DISABLE;	//优先级由报文标识符决定
    CAN_InitStructure.CAN_Mode = mode;	 //模式设置
    CAN_InitStructure.CAN_SJW = tsjw;	//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq
    CAN_InitStructure.CAN_BS1 = tbs1; //Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq
    CAN_InitStructure.CAN_BS2 = tbs2; //Tbs2范围CAN_BS2_1tq ~	CAN_BS2_8tq
    CAN_InitStructure.CAN_Prescaler = brp; //分频系数(Fdiv)为brp+1
    CAN_Init(CAN1, &CAN_InitStructure);   // 初始化CAN1

    //配置过滤器
    CAN_FilterInitStructure.CAN_FilterNumber = 0;	 //过滤器0
    CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
    CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; //32位
    CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000; 32位ID
    CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000; //32位MASK
    CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; //过滤器0关联到FIFO0
    CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; //激活过滤器0
    CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化

    #if CAN1_RX0_INT_ENABLE

    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); //FIFO0消息挂号中断允许.

    NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 7;     // 主优先级为1
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // 次优先级为0
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    #endif
    return 0;
}

CAN过滤器

只针对标准CAN ID只接收标准的CAN ID以及指定的CAN ID ,只接收StdIdArray[10]的标准ID

u8 CAN1_Mode_Init(u8 tsjw, u8 tbs2, u8 tbs1, u16 brp, u8 mode)
{
   uint16_t StdIdArray[10] ={0x7e0,0x7e1,0x7e2,0x7e3,0x7e4,
                             0x7e5,0x7e6,0x7e7,0x7e8,0x7e9}; //定义一组标准CAN ID
   uint16_t mask,num,tmp,i;
	
    GPIO_InitTypeDef GPIO_InitStructure;
    CAN_InitTypeDef        CAN_InitStructure;
    CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    #if CAN1_RX0_INT_ENABLE
    NVIC_InitTypeDef  NVIC_InitStructure;
    #endif
    //使能相关时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能PORTA时钟

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟

    //初始化GPIO
    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;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化PA11,PA12

    //引脚复用映射配置
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_CAN1); //GPIOA11复用为CAN1
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_CAN1); //GPIOA12复用为CAN1

    //CAN单元设置
    CAN_InitStructure.CAN_TTCM = DISABLE;	//非时间触发通信模式
    CAN_InitStructure.CAN_ABOM = DISABLE;	//软件自动离线管理
    CAN_InitStructure.CAN_AWUM = DISABLE; //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
    CAN_InitStructure.CAN_NART = ENABLE;	//禁止报文自动传送
    CAN_InitStructure.CAN_RFLM = DISABLE;	//报文不锁定,新的覆盖旧的
    CAN_InitStructure.CAN_TXFP = DISABLE;	//优先级由报文标识符决定
    CAN_InitStructure.CAN_Mode = mode;	 //模式设置
    CAN_InitStructure.CAN_SJW = tsjw;	//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq
    CAN_InitStructure.CAN_BS1 = tbs1; //Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq
    CAN_InitStructure.CAN_BS2 = tbs2; //Tbs2范围CAN_BS2_1tq ~	CAN_BS2_8tq
    CAN_InitStructure.CAN_Prescaler = brp; //分频系数(Fdiv)为brp+1
    CAN_Init(CAN1, &CAN_InitStructure);   // 初始化CAN1

    //配置过滤器
    CAN_FilterInitStructure.CAN_FilterNumber = 0;	 //过滤器0
    CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
    CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; //16位
    CAN_FilterInitStructure.CAN_FilterIdHigh = (StdIdArray[0]<<5); 32位ID
    CAN_FilterInitStructure.CAN_FilterIdLow = 0;
	mask =0x7ff;						//下面开始计算屏蔽码
    num =sizeof(StdIdArray)/sizeof(StdIdArray[0]);
    for(i =0; i<num; i++)		//屏蔽码位StdIdArray[]数组中所有成员的同或结果
    {
       tmp =StdIdArray[i] ^ (~StdIdArray[0]);	//所有数组成员与第0个成员进行同或操作
       mask &=tmp;
    }
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh = (mask<<5); //32位MASK
    CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0|0x02;
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; //过滤器0关联到FIFO0
    CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; //激活过滤器0
    CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化

    #if CAN1_RX0_INT_ENABLE

    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); //FIFO0消息挂号中断允许.

    NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 7;     // 主优先级为1
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // 次优先级为0
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    #endif
    return 0;
}

16位宽的列表模式 将需要接收的CANID写如下图的四个寄存器,则只能接收定义的4个标准ID且只能是数据帧
在这里插入图片描述

uint32_t StdId1 =0x123;						//这里采用4个标准CAN ID作为例子
uint32_t StdId2 =0x124;
uint32_t StdId3 =0x125;
uint32_t StdId4 =0x126;
    //配置过滤器
CAN_FilterInitStructure.CAN_FilterNumber = 0;	 //过滤器0
CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdList;
CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_16bit; //16位
CAN_FilterInitStructure.CAN_FilterIdHigh = (StdId1<<5); 32位ID
CAN_FilterInitStructure.CAN_FilterIdLow = (StdId2<<5);
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = (StdId3<<5); //32位MASK
CAN_FilterInitStructure.CAN_FilterMaskIdLow = (StdId4<<5);
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; //过滤器0关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; //激活过滤器0
CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值