CAN通信入门
1CAN总线简介
CAN总线(Controller Area Network Bus)控制器局域网总线
CAN总线是由BOSCH公司开发的一种简洁易用、传输速度快、易扩展、可靠性高的串行通信总线,广泛应用于汽车、嵌入式、工业控制等领域
CAN总线特征:
两根通信线(CAN_H、CAN_L),线路少
差分信号通信,抗干扰能力强
高速CAN(ISO11898):125k~1Mbps, <40m
低速CAN(ISO11519):10k~125kbps, <1km
异步,无需时钟线,通信速率由设备各自约定
半双工,可挂载多设备,多设备同时发送数据时通过仲裁判断先后顺序
11位/29位报文ID,用于区分消息功能,同时决定优先级
可配置1~8字节的有效载荷
可实现广播式和请求式两种传输方式 应答、CRC校验、位填充、位同步、错误处理等特性
1.1常见的通信协议对比
1.2CAN硬件电路
1.3CAN电平标准
1.4CAN总线帧格式
1数据帧
数据帧各个部分用途简介
2遥控帧
3错误帧
4过载帧
5帧间隔
1.5位填充
波形示例
接收方数据采样
1.6错误类型
2STM32CAN外设的简介
2.1CAN收发器电路
2.2CAN框图
2.3CAN的基本结构
2.4发送流程
RQCP:请求完成
TXOK:发送成功
TME:发送邮
TXRQ:请求发送控制位
NART: 自动重传控制位
1接收过程
2发送和接收的配置位
3标识符过滤器
屏蔽模式就是只看哪些位就可以通过,比如大量的温度数据进入
屏蔽寄存器里面写1就是必须匹配,写0可以不匹配
过滤器配置示例(映像右边有几位就左移几位)
2.5测试模式
2.6工作模式
STM32的位时间特性(与协议有些不同)
收数据之间要看队列里面是否有报文
CAN.c
void My_CANInit(void)
{//初始化时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);//GPIOGPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//CAN初始化CAN_InitTypeDef CAN_InitStructure;CAN_InitStructure.CAN_ABOM = DISABLE;CAN_InitStructure.CAN_AWUM = DISABLE;CAN_InitStructure.CAN_NART = DISABLE;CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;CAN_InitStructure.CAN_BS1 = CAN_BS1_2tq;CAN_InitStructure.CAN_BS2 = CAN_BS2_3tq;CAN_InitStructure.CAN_Prescaler = 48;CAN_InitStructure.CAN_RFLM = DISABLE;CAN_InitStructure.CAN_SJW = CAN_SJW_2tq;CAN_InitStructure.CAN_TTCM = DISABLE;CAN_InitStructure.CAN_TXFP = DISABLE;CAN_Init(CAN1,&CAN_InitStructure);//过滤器初始化CAN_FilterInitTypeDef CAN_FilterInitStructure;CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;CAN_FilterInitStructure.CAN_FilterNumber = 0;CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;CAN_FilterInit(&CAN_FilterInitStructure);
}
//发送函数
void MyCAN_Transmit(uint32_t ID,uint8_t Length,uint8_t* Data)
{CanTxMsg Txmessage;for(uint8_t i = 0;i<Length;i++){Txmessage.Data[i] = Data[i];}Txmessage.DLC = Length;//数据个数Txmessage.ExtId = ID;Txmessage.IDE = CAN_Id_Standard;Txmessage.RTR = CAN_RTR_Data;Txmessage.StdId = ID;uint8_t TransmitMailbox = CAN_Transmit(CAN1,&Txmessage);//等待发送完成uint32_t Timeout = 0;while(CAN_TransmitStatus(CAN1,TransmitMailbox)!=CAN_TxStatus_Ok){Timeout++;if(Timeout>100000){break;}}
}
//是否接收到数据判断函数
uint8_t MyCAN_ReceiveFlah(void)
{if(CAN_MessagePending(CAN1,CAN_FIFO0)>0)//看队列是否有数据,有的话,main.c里面取{return 1;}return 0;}
//接收函数
void MyCAN_Receive(uint32_t * ID,uint8_t* Length,uint8_t* Data)
{CanRxMsg Rxmessage;CAN_Receive(CAN1,CAN_FIFO0,&Rxmessage);if(Rxmessage.IDE==CAN_Id_Standard){*ID=Rxmessage.StdId;}else{*ID=Rxmessage.ExtId;}if(Rxmessage.RTR==CAN_RTR_Data){*Length = Rxmessage.DLC;for(uint8_t i = 0;i<*Length;i++){Data[i] = Rxmessage.Data[i];}}else{//}
}
本文章只是介绍基础的CAN总线通信,还有各种功能,等到实际需求的时候再去实现