CAN通讯
CAN(Control Area Network,控制器局域网简称CAN或者CAN Bus)。是功能丰富的车用总线标准。有一根CAN-Bus总线,所有的装置可以挂在这条总线上。1.1 物理层一种功能丰富的车用总线标准。设计在于不需要主机的情况下,允许网络上的单片机和设备相互通信。基于消息传递协议。CAN拥有良性的弹性调整功能,可以在现有网络中增加节点,而不用在软、硬键上调整。消息的传递不基于任何的
声明:此为本人学习(尚硅谷)过程中的笔记
1 介绍
CAN(Control Area Network,控制器局域网 简称CAN或者CAN Bus)。是功能丰富的车用总线标准。
有一根CAN-Bus总线,所有的装置可以挂在这条总线上。
1.1 物理层
- 一种功能丰富的车用总线标准。
- 设计在于不需要主机的情况下,允许网络上的单片机和设备相互通信。
- 基于消息传递协议。
- CAN拥有良性的弹性调整功能,可以在现有网络中增加节点,而不用在软、硬键上调整。
- 消息的传递不基于任何的特殊结点。
CAN的网络节点:
一个CAN控制器:
一般由MCU提供,STM32内部提供了一个CAN控制器。
一个CAN收发器:
由 专门的芯片提供,如PD1050收发器芯片。
CAN网络节点发数据:
当设备需要发数据时,CAN控制器会通过CAN_TX将要发送的二进制编码发送到CAN收发器。
CAN收发器会把收到的逻辑信号转换为差分信号,通过CAN_High和CAN_Low将信号传输到CAN总线网络。
CAN网络节点收数据:
过程与发数据相反,通过CAN收发器接收总线上的信号,然后将信号转换成逻辑电平向CAN控制器发送。
CAN总线网络
当CAN总线上挂载多个设备时,就形成了CAN总线网络。
根据接法不同,总线网络分成两种:
闭环总线网络:传输距离40m,速度最高1Mbps;
开环总线网络:
最长1km,速度125kbps;
差分信号:
CAN_High及CAN_Low 中走的是一对差分信号。
差分传输是一种信号传输的技术,差分传输在这两根线上都传输信号,这两个信号的振幅相同,相位相反。
信号接收端比较这两个电压的差值来判断发送端发送的逻辑状态。
在电路板上,差分走线必须是等长、等宽、紧密靠近、且在同一层面的两根线。
差分信号相比传统的单端信号传输具有以下优势:
麻烦的点在于差分信号需严格匹配走线(等长、等距,等宽),布局复杂度较高。
2.协议层
2.1 数据帧介绍
2.1.1 CAN的帧(报文)种类
CAN总线是广播类型的总线。这意味着所有节点都可以侦听到所有传输的报文。
数据帧:发送方向接收方发送数据的格式。
遥控帧:接收方向具有相同ID的发送单元发送请求接收数据的请求。
错误帧:检测出错误时向其他单元通知错误的帧。
过载帧:不常见。
帧间隔:用于将数据帧及遥控帧与前面的帧分离开来的帧。
2.1.2 标准帧

帧起始:与I2C类似,表明我要开始发送数据了。
仲裁段:11位ID+1位RTR:ID是高位先行的;RTR是判断数据帧还是遥控帧的依据,RTR=0时是数据帧,1时是遥控帧。
控制段:1位IDE+1位R0+4位DLC:1位IDE是说明这个是标准帧还是扩展帧;1位R0是保留位;4位DLC是说明数据位的长度。
数据段:高位先行;
CRC段:CRC校验有关,SPI也有CRC校验,不过SPI可以选择不开启,而CAN必须开启。
2.1.2 扩展帧

与标准帧不一样的就是11位ID后面的 SRR位,这个只是一个占位符,当IDE说明这是个扩展帧时,后面跟18位扩展的ID,然后与标准帧一样,只不过后面说明扩展的IDE位变成了R1保留位。
2.1.3 总线仲裁
开始发送数据时,如果有两个设备同时发送数据,先发一个帧起始0。
CAN总线同一时间只能允许一个信号,现在就会产生谁先发的问题。
此时仲裁段开始仲裁谁先发。
000和001是000占据总线,11位ID通过这个比较来判断,如果设备1(0001)和设备2(001)同时发送,总线数据呈现出0001的数据,此时设备2停止发送,进入接收状态,此时设备2 的数据也没有遭到破环(优点)。所以id小的优先级越高。
如果遥控帧和数据帧的ID相同,那是数据帧先发送,因为数据帧的RTR=0,遥控帧的RTR=1;所以可以解释为什么RTR也在仲裁段。
2.1.4 CAN的位时序
串行,半双工,异步
CAN中提出了位同步的方式来确保通讯时序。
一帧中包含了很多个位
CAN把每1位分成4段(时间角度划分):
- 同步段(SS):一般是上升沿或者下降沿所在的位置,时间为1Tq.
- 传播时间段(PTS):传输可能会有各种延时,相当于延时缓冲段,1—8Tq.
- 相位缓冲段1(PBS1)
- 相位缓冲段2(PBS2)
采样时间在相位缓冲段1和相位缓冲段2的交界处。
4段的总时间构成了位时间(Bit Time),就是传输一个位所需的总时间。
位时间通常被分为若干段等长的时间单元,称为时间量化器(Tq)。
一个Tq的长度可以根据传输速率的需要设置。
在STM32的CAN外设中,通过设置波特率分频器的值来确定Tq的大小。

根据数据同步的差异,将数据同步分成硬同步和再同步。
硬同步:当一个结点检测到起始位时,他会执行硬同步,以便将其内部的时间基准与数据帧的时间基准对齐。
再同步:在检测到总线上的时序与节点使用的时序有相位差时(即总线的跳变沿不在节点时序的SS段范围),通过延长PBS1段或者缩短PBS2段,来获得同步。
上面的同步都是由CAN控制器硬件自动完成的!!!
问题:就是当传输的数据是000000或者111111时,此时判断不了同步情况,会不会出现数据传输错误?
解决方法:位填充, 当连续出现6个0或1时,每5个0或1后加一个相反的位。即
0000010 1111101
3.CAN外设(CAN控制器)介绍
3.1CAN控制器的3种工作模式
初始化,睡眠,正常模式

上电复位后CAN控制器默认会进入睡眠模式,作用是降低功耗。当需要将进行初始的时候(配置寄存器),会进入初始化模式。当需要通讯的时候,就进入正常模式(退出初始化模式)。
三种工作模式的转化:复位进入睡眠模式,此时SLAK=1(SL=sleep),INAK=0(IN=init)。
3.2 三种测试模式
静默模式,环回模式,环回静默模式。
1.静默模式:

把CANTX拉高,CANRX正常接收。而且里面的发送接到接收,因为如果发生错误帧等所有状态的报告需要发送到接收段。


静默模式可以用于检测总线的数据流量。
环回模式可以用于自检(影响总线)。
环回静默模式也是用于自检,不会影响到总线。
既不是静默模式也不是环回模式时就是正常模式。
3.4 接收滤波器(过滤器)
作用:对接到的报文进行过滤,最后放入FIFO0或FIFO1。
如果总线上有很多设备都发送信号,单纯几个邮箱根本就不足以容纳那么多信息,我们可以检验这个信息是否是我们需要的,需要的信息就拿过来。这样就大大减少CPU的工作。
这个可以由硬件来控制。
有两种过滤模式来检验:
1.标识符列表模式:就是我们把需要接收信息的ID列一个列表,只要符合这个列表的信息就可以拿过来。相当于白名单。
2.掩码模式(屏蔽位模式):可以选择ID的前几位,比如要筛选电话开头为158566的号码,就可以用这个,此时ID位可以设置158566*****,(*代表随意数)。屏蔽位设置为11111100000,屏蔽位是1表示来的ID的这位必须和其中对应的位一致,屏蔽位位是0,表示ID的这位不关心。
3.5 STM32中 CAN的位时序
STM32的位时序:把传播时间段和相位缓冲段1做了合并。

变成了:

如果是36M的总线,BRP[9:0]设置为35,一个tq就是1us。
如果我们设置的位时序一共为10个Tq,一位就需要10us。
4.代码实现(静默环回的测试模式)
can.c
#include"can.h"
#include"usart.h"
void can_init(void)
{
//1.时钟的开启
RCC->APB1ENR|=RCC_APB1ENR_CAN1EN;
RCC->APB2ENR|=RCC_APB2ENR_IOPBEN;
RCC->APB2ENR|=RCC_APB2ENR_AFIOEN;
//引脚重映射
AFIO->MAPR|=AFIO_MAPR_CAN_REMAP_1;
AFIO->MAPR&=~AFIO_MAPR_CAN_REMAP_0;
//2.GPIO的配置 PB8浮空输入 mode 00 cnf 01 PB9复用推挽输出 MODE11 CNF10
GPIOB->CRH&=~GPIO_CRH_MODE8;
GPIOB->CRH&=~GPIO_CRH_CNF8_1;
GPIOB->CRH|=GPIO_CRH_CNF8_0;
GPIOB->CRH|=GPIO_CRH_MODE9;
GPIOB->CRH&=~GPIO_CRH_CNF9_0;
GPIOB->CRH|=GPIO_CRH_CNF9_1;
//3.配置CAN
//3.1进入初始化模式
CAN1->MCR|=CAN_MCR_INRQ;
while ((CAN1->MSR & CAN_MSR_INAK)==0) //等待
{
}
//退出睡眠模式
CAN1->MCR&=~CAN_MCR_SLEEP;
while ((CAN1->MSR & CAN_MSR_SLAK)!=0)
{
}
//自动唤醒还有自动离线管理打开
CAN1->MCR|=CAN_MCR_AWUM;
CAN1->MCR|=CAN_MCR_ABOM;
//设置静默环回模式
CAN1->BTR|=CAN_BTR_LBKM;
CAN1->BTR|=CAN_BTR_SILM;
//设置波特率和位时序
CAN1->BTR&=~CAN_BTR_BRP;
CAN1->BTR|=(35<<0);
CAN1->BTR&=~CAN_BTR_TS1;
CAN1->BTR|=(2<<16);
CAN1->BTR&=~CAN_BTR_TS2;
CAN1->BTR|=(5<<20);
CAN1->BTR&=~CAN_BTR_SJW;
CAN1->BTR|=(1<<24);
//退出初始化模式相当于进入正常模式
CAN1->MCR&=~CAN_MCR_INRQ;
while ((CAN1->MSR & CAN_MSR_INAK)!=0)
{
/* code */
}
//4.对过滤器进行配置
//进入过滤器初始化模式
CAN1->FMR|=CAN_FMR_FINIT;
//屏蔽位模式
CAN1->FM1R&=~CAN_FM1R_FBM0;
//32位
CAN1->FS1R|=CAN_FS1R_FSC0;
//过滤器分配给FIFO0
CAN1->FFA1R&=~CAN_FFA1R_FFA0;
//过滤的id设置
CAN1->sFilterRegister[0].FR1=0x0000;
CAN1->sFilterRegister[0].FR2=0x0000;
//激活过滤器
CAN1->FA1R|=CAN_FA1R_FACT0;
//退出过滤器初始化模式
CAN1->FMR &= ~CAN_FMR_FINIT;
}
void can_tx(uint16_t id,uint8_t *data,uint8_t len)
{
while ((CAN1->TSR&CAN_TSR_TME0)==0)
{
/* code */
}
CAN1->sTxMailBox[0].TIR&=~CAN_TI0R_IDE;
CAN1->sTxMailBox[0].TIR&=~CAN_TI0R_RTR;
CAN1->sTxMailBox[0].TIR&=~CAN_TI0R_STID;
CAN1->sTxMailBox[0].TIR|=(id<<21);
CAN1->sTxMailBox[0].TDTR&=~CAN_TDT0R_DLC;
CAN1->sTxMailBox[0].TDTR|=len<<0;
uint8_t i;
CAN1->sTxMailBox[0].TDHR=0;
CAN1->sTxMailBox[0].TDLR=0;
for ( i = 0; i < len; i++)
{
if(i<4)
{
CAN1->sTxMailBox[0].TDLR|=(data[i]<<(i*8));
}
else
{
CAN1->sTxMailBox[0].TDHR|=(data[i]<<((i-4)*8));
}
}
CAN1->sTxMailBox[0].TIR|=CAN_TI0R_TXRQ;
while((CAN1->TSR&CAN_TSR_TXOK0)==0)
{
}
}
void can_rx(rx_msg m_msg[],uint8_t * length)
{
*length = (CAN1->RF0R & CAN_RF0R_FMP0)>>0;
printf("%d***********\n",*length);
for (uint8_t i = 0; i < *length; i++)
{
rx_msg *msg=&m_msg[i];
msg->stdid=((CAN1->sFIFOMailBox[0].RIR>>21)&0x7ff);
msg->len=((CAN1->sFIFOMailBox[0].RDTR>>0) & 0x0f);
uint32_t low=CAN1->sFIFOMailBox[0].RDLR;
uint32_t high=CAN1->sFIFOMailBox[0].RDHR;
for (uint8_t j = 0; j < msg->len; j++)
{
if(j<4)
{
msg->data[j]=((low>>(j*8)) & 0xff);
}
else
{
msg->data[j]=((high>>((j-4)*8))&0xff);
}
}
CAN1->RF0R|=CAN_RF0R_RFOM0;
}
}
对于接收和发送,只要把静默环回去掉就行,在HAL库中设置为NORMAL;
更多推荐







所有评论(0)