CAN通信

基础知识

1.异步,半双工,差分信号传输(CAN_H,CAN_L),可以绑定多个主控。
在这里插入图片描述

2.高速CAN(iso11898):125K~1Mbps。距离<40M。闭环网络,在两端添加120R的终端电阻。(终端电阻的作用:1.阻抗匹配,防止回波反射。2.给CAN_H,CAN_L提供一个收紧的力)
低速CAN(iso11519):10K~125K。距离<1KM。开环网络,在其中一段加入2.2K的终端电阻。在这里插入图片描述
高速CAN:显示电平:两线电压差为2V时,表示逻辑0。隐形电平:电压差为0V时,表示逻辑1。
低速CAN:显示电平:两线电压差为3V时,表示逻辑0。隐形电平:电压差为-1.5V时,表示逻辑1。

在这里插入图片描述

报文

CAN发送一次消息,这个消息称为报文。报文分为5种类型:数据帧 ,遥控帧 ,错误帧 ,过载帧,帧间隔

帧类型用途
数据帧发送设备主动发送数据(广播式)
遥控帧接收设备主动请求数据(请求式)
错误帧某个设备检测出错误时向其他设备通知错误
过载帧接收设备通知其尚未做好接收准备
帧间隔用于数据帧及遥控帧与前面的帧分开

数据帧

数据帧有标准格式,扩展格式两种类型。格式里包含:帧起始,仲裁段,控制段,数据段,CRC校验,ACK段,帧结束。

在这里插入图片描述
帧起始:
SOF:帧起始。数据的开始,此时电平为显性电平(0),两线差为2V。
仲裁段:
ID:表示后面数据的功能,和用来区分优先级。(多设备同时发送)
RTR:远程请求标志位。用来区分数据帧还是遥控帧。数据帧位为显性电平0,遥控帧为隐形电平1。
(数据帧和遥控帧的ID可以相同,数据帧的优先级高于遥控帧)
控制段:
IDE:用来表示是标准帧还是扩展帧。标准格式为显示0,扩展格式为隐形1。
R0/R1:显性0。保留位。
DLC:指定数据段有多少个字节。
数据段:
Data:要发送的数据。0~64个字节。
CRC段:
CRC:CRC校验。
CRC界定符:隐形电平1.
ACK段:
ACK槽:当发送方发完一帧数据的主要内容后,在应答这一位,发送方释放总线,总线回归默认状态隐形1。如果接收方收到这个数据了,将电平拉开,使总线呈现显性0。发送方在释放完,开始读取总线的状态,来确定接收方有没有收到。
ACK界定符:
帧结束:
EOF:帧结束。总线为隐性1。
扩展帧:
把标准帧中的11位ID改成11+18位的ID的格式。在IDE(判断是标准帧还是遥控帧)的后面续上18位的ID,为了保持ID的优先级大于帧类型,所以把原来的RTR(帧类型)放到ID的后面,使ID发送完再发送帧类型。在原来的RTR位放入SRR(固定为隐性电平1)。

简记:
想要发送一串数据,首先要有帧起始,接着进行仲裁给多个设备排一个顺序,按照ID号和要发的数据类型RTR进行排序,排过顺序后在进行设置你要传的数据的格式IDE长度DLC好让接收方做好准备。这时开始传入数据Data,传数据时需要注意,要与前面设备的保持一致。数据后面跟一个CRC校验,确保数据在传输中没有出错。接收等待接收方的应答信号ACK,看接收方有没有接收到,最后告诉接收方我发完了帧结束

遥控帧

没有数据段,RTR为隐形电平1,其他部分与数据帧都一样。
在这里插入图片描述
发送方会定一个周期,定时广播自己的数据。当发送方没有及时的发送数据或者使用频率太低一直发浪费总线资源时。这时可以规定发送方不要主动广播这个数据,当接收方需要时,发一个遥控帧(包含报文ID),其他设备如果有这个ID的数据时,该设备再通过数据帧发送出来。
相当于遥控帧是一个申请报告,发送方收到这个申请报告时,把相应的数据(ID)发出去。

错误帧

总线上所有的设备都会监督总线上的数据,一旦总线出现“位错误”,“填充错误”,“CRC错误”,“格式错误”,“应答错误”。这些设备就会发出错误帧来破坏数据传输。

过载帧

当接收方收到大量的数据而无法处理时,接收方会发出过载帧,破坏总线上的数据,使发送方重新发送该数据,以达到延缓数据的发送。

帧间隔

在连续发出的数据帧或遥控帧之间保留三位帧间隔,将每帧数据分开。

位填充

当发送方连续发送5个相同电平后,自动追加一个相反电平的填充位。
接收方检测到这个位填充时,会自动的移除这个填充位,恢复原来的数据。

> 如:要发送0x106  
> 原电平 :       1 0000  0 110 
> 实际发送:      1 0000  0111 0 
> 接收移除后为:   1 0000  0 110

作用:
1.增加波形的定时信息,利于接收方执行“再同步”,防止波形长时间无变化,导致接收方不能精确掌握数据采样时机。
2.将正常数据流与“错误帧”,“过载帧”区分开,标志“错误帧”,“过载帧“的特异性。
3.保持CAN总线在发送正常数据流时的火焰状态,防止被误认为总线空闲。

位同步

CAN属于异步通信,没有时钟线。和串口一样需要规定相同波特率来确定双方的发生和采样时间。
发送方以约定的位时长每隔固定时间输出一个数据位。
接收方以约定的位时长每隔固定时间采样总线的电平。

位时序

位时序:即一位数据的时间
为了灵活调整每个采样点的位置,使采样点对齐数据位中心附近,CAN总线对每一个数据位的时长进行了更细致的划分,分为同步段(SS),传播时间段(PTS),相位缓冲段1(PBS1),和相位缓冲段2(PBS2),每个段又由若干个最小时间单位(Tq)构成。
在这里插入图片描述
SS段:同步段。总线上各个节点通过检测总线上的电平变化来确定一个位的开始。为了让各个节点准确地找到这个起始时刻,它使得接收节点的采样时刻能够与发送时刻的位起始时刻对齐,确保数据传输的稳定性。(通常为一个Tq)
PTS段:传播段。用来补偿信号在总线上传播的物理延迟。不同节点在总线上的位置不同,收发器传输时间延迟等。加入此段可以使不同位置的节点都可以正确地接收数据。(通常为1~8个Tq)
PBS1:相位缓冲段 1。
PBS2: 相位缓冲段 2。
接收采样点在PBS1和PBS2之间,调整两者的长短,可以确定接收采样点的位置。

硬同步

每个设备都有一个位时序计时周期。当某个设备(发送方)率先发送报文,其他所有的设备(接收方)收到SOF的下降沿(差分电平的张开沿)时,接收方会将自己的位时序计时周期拨到SS段,与发送方的位时序计时周期保持同步

在这里插入图片描述

再同步

经过上面的硬同步,接收方统一将SS段作为计数的开始。由于硬件的时钟有可能出现误差,造成数据采集在前面一样,后面误差的不断累积,使采集点逐渐偏离。
此时接收方可以根据再同步补偿宽度值(SJW)通过加长PBS1段或缩短PBS2段,以调整采集点的位置实现再同步。
再同步可以发生再第一个下降沿之后的每个数据跳变沿。通常SJW为1到4个Tq。

波特率

由上面可知,一个数据位的时长由同步段(SS),传播段(RTS),相位缓冲段(PBS1,PBS2)组成。
波特率(mbps) = 1/一个数据位的时长=1/(SS+PTS+PBS1+PBS2)。

例如:
	SS=1Tq,	RTS=3Tq,	PBS1=3Tq,	PBS2=3Tq
	Tq=0.5us
	则波特率等于 1/(0.5+0.5*3+0.5*3+0.5*3)=200kbps

仲裁

为了避免数据在发送时,另一个数据在发送造成数据的败坏,以及多个设备同时发送的情况,CAN总线设计了以下仲裁规则。
规则1: 先占先得。
任何设备检测到总线存在11个连续的隐性电平时,即认为当前总线处于空闲的状态。
若当前已经有设备在发送数据帧/遥控帧时,其他设备则不能再同时发送数据帧/遥控帧。(可以发生错误帧/过载帧)。
规则2:非破坏性仲裁。
若多个设备发送需求同时到来或因等待同时到来时,CAN总线协议会根据仲裁段来进行非破坏性仲裁,ID号小的先进行发送,其次(RTR)数据帧比遥控帧先行发送。

错误处理

错误类型共有5种:位错误,填充错误,CRC错误,格式错误,ACK错误。

位错误

比较输出电平和总线上的电平是否一样,不一样时视为位错误。
检测单元:发送单元,接收单元。

填充错误

在需要填充的段内,检测到有6个或以上的连续相同的电平视为填充错误。
检测单元:发送单元,接收单元。

CRC错误

从接收到的数据计算出CRC结果是否与接收到的CRC一致,不一致视为CRC错误。
检测单元:接收单元。

格式错误

检测出与固定格式的位段相反的格式时视为格式错误。
检测单元:接收单元。

ACK错误

发送单元在ACK槽中没有检测到显性电平(即接收方没有做出接收后的反应)视为ACK错误。
检测单元:发送单元。

错误状态

CAN总线中规定了三种错误状态分别为:主动错误状态,被动错误状态,总线关闭状态。
主动错误状态:每个设备初始都为这个状态,正常参与通信并在检测到错误时发出主动错误帧。(主动错误帧可以打破其他设备的数据)
被动错误状态:设备频繁的报告错误(设备本身不可靠),将转为被动错误状态。被动设备状态可以正常参与通信,但检测错误时只能发出被动错误帧(被动错误帧不可以打破其他设备的数据)。
总线关闭状态:处在被动错误状态时,仍报告大量的错误,将转为总线关闭状态。处在总线关闭状态下不能参与通信。
每个设备都有一个TEC和REC,而这两个正是决定设备处于哪个状态。
TEC:发送错误计数器,设备在发送时,每发送一个错误,TEC就会增加一次。每进行一次正常的发送后,TEC也会减小一次。
REC:接收错误计数器,设备在接收时,每发现一次错误,REC就会增加一次,同样进行正常接收后,REC就会减少一次。
在这里插入图片描述

STM32使用CAN

外设简介:

STM32内置bxCAN外设(CAN控制器,bx表示支持CAN扩展格式),支持CAN2.0A和CAN2.0B,可以自动发送CAN报文和按照过滤器自动的接收指定的CAN报文。
波特率最高可达1M位/秒
3个可配置优先级的发送邮箱。
2个3级深度的接收FIFO
14个过滤器
支持时间触发唤醒,自动离线恢复,自动唤醒,禁止自动重传,接收FIFO溢出处理方式可配置,发送优先级可配置,双CAN模式。
在这里插入图片描述

发送和接收

发送:
把报文的各个参数(ID,扩展ID,IDE,RTR,DLC,Dat)写入到一个发送邮箱里,然后给一个请求发送的命令,之后控制器就会等待总线空闲然后自动将数据发送出去。当多个报文都在邮箱里准备发送时,根据仲裁规则先后发送。
在这里插入图片描述
TXRQ:发送请求控制位。
PQCP:请求完成标志位。
TXOK:发送成功标志位。
TME:发送邮箱为空标志位。
NART:禁止自动重传标志位。
接收
当总线上出现波形时,控制器会将报文收下了,然后经过过滤器(ID号过滤),将需要的数据传至FIFO邮箱,0~2个邮箱依次传入。当3个邮箱都被占满时,可以配置FIFO的锁定状态,锁定时FIFO满之后,新的数据将被丢弃。不锁定时,新数据刷新邮箱2的位置。
在这里插入图片描述
FMP:报文数目。
FOVR:FIFO溢出。
发送/接收配置位
NART:置一,关闭自动重传,不论发生结果如何,CAN只发送一次。置零,开启自动重传,CAN硬件在发送报文失败时会一直自动的重新发送直到发送成功。
TXFP:置一:优先级由发送请求的顺序来决定,先请求先发送。置零,优先级由报文标识符(ID)来决定,标识符小的先发送。(相等时,邮箱号小的先发送)
RFLE:置一:接收FIFO锁定,FIFO邮箱满时,新报文将丢弃。置0:禁用FIFO锁定,满时,新报文替换邮箱2的数据。

过滤器

每个过滤器的核心都用两个32位的寄存器组成:R1[31:0]和R2[31:0]。
FSCx:位宽设置。
置0,16位;置1,32位。
FBMx:模式设置。
置0,屏蔽模式;置1,列表模式。
FFAx:关联邮箱设置
置0,FIFO 0;置1,FIFO 1。
FACTx:激活过滤器设置
置0,禁用;置1,启动。
在这里插入图片描述
R1,R2寄存器:
这两个寄存器完全一样控制过滤器要过滤的内容。
(左对齐)
STID[10:3],STDID[2:0]:里面放入标准ID。
EXID[17:13],EXID[12:5]:里面放入扩展ID。
(右对齐)
IDE:标准ID填0,扩展ID填1;
RTR:数据帧填0,遥控帧填1;

扩展ID:一般使用(FSCx=1,IDE=1)模式一,模式二。
标准ID:一般使用(FSCx=0,IDE=0)模式二,模式三。
该模式下,将R1,R2两个寄存器分别分成两个。可以同时设置4个。

通常把同一类别的数据,高位设置一样,这样可以方便我们进行过滤。
要在各种ID中取出一组高位相同的ID,我们可以将过滤器配置成屏蔽模式,R1寄存器写ID号,R2写ID号中的哪些位必须一样,哪些位可以任意。这样就可以过滤出一组ID号了。

标识符列表模式
一般用于过滤出指定的ID
如:要过滤出ID号为0x234,0x345标准ID,则选用16位位宽,列表模式。(FSCx=0,FBMx=1)。
在这里插入图片描述
R1[15:0] = 0x234<<5;
R2[31:16] = 0x345<<5;
在该寄存器中ID号在最前面因此要将ID号进行左对齐(0x234<<5),左对齐后面默认补零。此时RTR=0,IDE=0,也就是标准ID,数据帧。如果想要遥控帧的话可以加上“|(0x1<<3)”将IDE位置一。

RTR:帧类型。数据帧还是控制帧。
IDE:数据模式。标准帧还是控制帧。

计算过程:
分别在R1,R2寄存器里填写想要过滤通过的ID,然后16位位宽左移5位(32位位宽左移21位),放到ID号位置上。
接着“并”上要设置的帧类型RTR(遥控帧/数据帧),数据模式IDE(标准帧/扩展帧)。

标识屏蔽模式
一般用于过滤一组的ID
如果想过滤出大量的数据的话,使用列表就有点不够用了,这时可以使用屏蔽模式(FBMx=0)。通过我们会把同一类型数据的ID高位保持一致。
在这里插入图片描述
R1[15:0]: 【15:5】填写ID号。一般取这一组ID的相同高位,低位补零。

R1[31:16]: 【31:20】屏蔽位。取R1[15:5]上的哪几位作为过滤标准。
总线上的ID满足时进来,不满足时舍弃。

计算过程:
R1[15:0]: 【15:5】 填写ID号。一般取这一组ID的相同高位,低位补零。
         
R1[31:16]:【31:20】 屏蔽位。取R1[15:5]上的哪几位作为过滤标准。
           总线上的ID满足时进来,不满足时舍弃。
最后将结果左移5位,给R1[15:0]。   
        
例1: 想要0x200 ~ 0x2FF 这一组ID时。
R1[15:5]  在这一组0x200~0x2FF中,相同的高位是2低位补零,即填0x200。
R1[31:20] 取R1[15:5]上的前4位作为总线上ID通过的过滤标准,即0xF00。
          0010 0000 0000 (让2保持不变,其他位任意。)
          1111 0000 0000 (取前4位)
          
例2:想要0x4515 0000 ~ 0x4515 FFFF这一组ID时。
R1[15:5]  在这一组0x4515 0000 ~ 0x4515 FFFF中,相同的高位是4515低位补零,
		  即填0x45100。
R1[31:20] 取R1[15:5]上的前16位作为总线上ID通过的过滤标准,即0xFFFF 0000。

测试模式

静默模式:自发自收,同时接收总线传来的数据。
环回模式:自发自收,同时将数据发送到总线上。
环回静默模式:自发自收,不接收总线上的数据也不发送数据。
在这里插入图片描述

工作模式

初始化:配置CAN外设,禁止报文的接收和发送。
正常模式:配置CAN外设后进入正常模式,以便正常接收和发送报文。
睡眠模式:低功耗,CAN外设时钟停止,可使用软件唤醒或硬件自动唤醒。
AWUM:置一,自动唤醒,一旦检测到CAN总线活动,硬件就会自动清零SLEEP,唤醒CAN外设。置零,手动唤醒,软件清零SLEEP,唤醒CAN外设。
在这里插入图片描述

波特率计算

波特率 = APB1时钟频率/分配系数/一位的Tq的数量。
=36MHz/(BRP[9:0]+1)/(1+(TS1[3:0]+1)+(TS2[2:0]+1))
在这里插入图片描述

中断

拥有4个专用的中断向量。
发送中断:发送邮箱空时产生。
FIFO 0中断:收到一个报文或FIFO 0满或FIFO 0溢出时产生。
FIFO 1中断:收到一个报文或FIFO 1满或FIFO 1溢出时产生。
状态改变错误中断:出错/唤醒/进入睡眠时产生。

程序

程序一:
1.不进行过滤。全部ID都进行接收;
2.模式:
回环测试(自发自收,发送到总线):CAN_Mode_LoopBack
静默模式(自发自收,接收总线消息):CAN_Mode_Silent
正常模式:CAN_Mode_Normal
3.波特率:
波特率 = 36M / CAN_Prescaler / (1 + CAN_BS1 + CAN_BS2)

void MyCAN_Init(void)
{
//开时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //CAN_TX
	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; //CAN_RX
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	CAN_InitTypeDef CAN_InitStructure;
	CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; //正常模式
	//位时序
	//波特率 = 36M / 48 / (1 + 2 + 3) = 125K
	CAN_InitStructure.CAN_Prescaler = 48;		
	CAN_InitStructure.CAN_BS1 = CAN_BS1_2tq;
	CAN_InitStructure.CAN_BS2 = CAN_BS2_3tq;
	CAN_InitStructure.CAN_SJW = CAN_SJW_2tq;
	
//使能或失能 不自动重传	
	CAN_InitStructure.CAN_NART = DISABLE; 
//发送邮箱优先级; ENABLE,先请求先发送,DISABLE ID号小的先发送
	CAN_InitStructure.CAN_TXFP = DISABLE;	
//FIFO 锁定; ENABLE,邮箱满时新报文舍弃,DISABLE 邮箱满时新报文刷新邮箱2
	CAN_InitStructure.CAN_RFLM = DISABLE;
//自动唤醒; ENABLE 自动唤醒。DISABLE 手动唤醒
	CAN_InitStructure.CAN_AWUM = DISABLE;
//时间触发通信模式; ENABLE 开启。DISABLE 关闭
	CAN_InitStructure.CAN_TTCM = DISABLE;
//离线自动恢复;ENABLE自动恢复。 DISABLE 手动恢复
	CAN_InitStructure.CAN_ABOM = DISABLE;
	CAN_Init(CAN1, &CAN_InitStructure);

//过滤器配置	全通模式 16位位宽 列表模式 关联到FIFO 0
	CAN_FilterInitTypeDef CAN_FilterInitStructure;
	CAN_FilterInitStructure.CAN_FilterNumber = 0;		
	CAN_FilterInitStructure.CAN_FilterIdHigh = 0;
	CAN_FilterInitStructure.CAN_FilterIdLow = 0;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0;
	CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0;
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_16bit; //位宽
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdList;	//列表模式
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
	CAN_FilterInit(&CAN_FilterInitStructure);
}
// 发送函数
void MyCAN_Transmit(CanTxMsg *TxMessage)
{
	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_ReceiveFlag(void)
{
//读FIFO 0的长度。如果大于0,说明邮箱里面有数据。
	if (CAN_MessagePending(CAN1, CAN_FIFO0) > 0)
	{
		return 1;
	}
	return 0;
}
//接收函数
void MyCAN_Receive(CanRxMsg *RxMessage)
{
	CAN_Receive(CAN1, CAN_FIFO0, RxMessage);
}

//报文
CanTxMsg TxMsgArray[] = {
//  StdId     ExtId         IDE             RTR        DLC         Data[8]          
	{0x555, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
	{0x000, 0x12345678, CAN_Id_Extended, CAN_RTR_Data,   4, {0xAA, 0xBB, 0xCC, 0xDD}},
	{0x666, 0x00000000, CAN_Id_Standard, CAN_RTR_Remote, 0, {0x00, 0x00, 0x00, 0x00}},
	{0x000, 0x0789ABCD, CAN_Id_Extended, CAN_RTR_Remote, 0, {0x00, 0x00, 0x00, 0x00}},
};
//发送第几个报文
uint8_t pTxMsgArray = 0;
//接收报文
CanRxMsg RxMsg;
void main()
{
	OLED_Init();
	Key_Init();
	MyCAN_Init();
	
	OLED_ShowString(1, 1, " Rx :");
	OLED_ShowString(2, 1, "RxID:");
	OLED_ShowString(3, 1, "Leng:");
	OLED_ShowString(4, 1, "Data:");
	while(1)
	{
		KeyNum = Key_GetNum();
		
		if (KeyNum == 1)
		{
			MyCAN_Transmit(&TxMsgArray[pTxMsgArray]);
			
			pTxMsgArray ++;
			if (pTxMsgArray >= sizeof(TxMsgArray) / sizeof(CanTxMsg))
			{
				pTxMsgArray = 0;
			}
		}
		if (MyCAN_ReceiveFlag())
		{
			MyCAN_Receive(&RxMsg);
			if (RxMsg.IDE == CAN_Id_Standard)
			{
				OLED_ShowString(1, 6, "Std");	
				OLED_ShowHexNum(2, 6, RxMsg.StdId, 8);
			}
			else if (RxMsg.IDE == CAN_Id_Extended)
			{
				OLED_ShowString(1, 6, "Ext");	
				OLED_ShowHexNum(2, 6, RxMsg.ExtId, 8);
			}
						
			if (RxMsg.RTR == CAN_RTR_Data)
			{
				OLED_ShowString(1, 10, "Data  ");	
				OLED_ShowHexNum(3, 6, RxMsg.DLC, 1);
				OLED_ShowHexNum(4, 6, RxMsg.Data[0], 2);
				OLED_ShowHexNum(4, 9, RxMsg.Data[1], 2);
				OLED_ShowHexNum(4, 12, RxMsg.Data[2], 2);
				OLED_ShowHexNum(4, 15, RxMsg.Data[3], 2);
			}
			else if (RxMsg.RTR == CAN_RTR_Remote)
			{
				OLED_ShowString(1, 10, "Remote");		
				OLED_ShowHexNum(3, 6, RxMsg.DLC, 1);		
				OLED_ShowHexNum(4, 6, 0x00, 2);
				OLED_ShowHexNum(4, 9, 0x00, 2);
				OLED_ShowHexNum(4, 12, 0x00, 2);
				OLED_ShowHexNum(4, 15, 0x00, 2);
			}
		}
	}
]

程序二,过滤器-16位列表:
接收ID-0x234,0x345,0x567

CanTxMsg TxMsgArray[] = {
/*   StdId     ExtId         IDE             RTR        DLC         Data[8]          */
	{0x123, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
	{0x234, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
	{0x345, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
	{0x456, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
	{0x567, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
	{0x678, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
};
void glq_init()
{
	CAN_FilterInitTypeDef CAN_FilterInitStructure;
	CAN_FilterInitStructure.CAN_FilterNumber = 0;
	CAN_FilterInitStructure.CAN_FilterIdHigh = 0x234 << 5;
	CAN_FilterInitStructure.CAN_FilterIdLow = 0x345 << 5;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x567 << 5;
	CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x000 << 5;
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_16bit;
	//列表
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdList;
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
	CAN_FilterInit(&CAN_FilterInitStructure);
}

程序三,过滤器-16位屏蔽:
接收ID-0x200~ 0x2FF

CanTxMsg TxMsgArray[] = {
/*   StdId     ExtId         IDE             RTR        DLC         Data[8]          */
	{0x100, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
	{0x101, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
	{0x1FE, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
	{0x1FF, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
	
	{0x200, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
	{0x201, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
	{0x2FE, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
	{0x2FF, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
};

void glq_init()
{
	CAN_FilterInitTypeDef CAN_FilterInitStructure;
	CAN_FilterInitStructure.CAN_FilterNumber = 0;
//R1	
	CAN_FilterInitStructure.CAN_FilterIdHigh = 0x200 << 5;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = (0x700 << 5) | 0x10 | 0x8;
//R2	
	CAN_FilterInitStructure.CAN_FilterIdLow = 0x320 << 5;
	CAN_FilterInitStructure.CAN_FilterMaskIdLow = (0x7F0 << 5) | 0x10 | 0x8;
	
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_16bit;
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
	CAN_FilterInit(&CAN_FilterInitStructure);
}

程序四 过滤器-只要遥控帧:

程序五 中断接收

CanTxMsg TxMsgArray[] = {
/*   StdId     ExtId         IDE             RTR        DLC         Data[8]          */
	{0x555, 0x00000000, CAN_Id_Standard, CAN_RTR_Data,   4, {0x11, 0x22, 0x33, 0x44}},
	{0x000, 0x12345678, CAN_Id_Extended, CAN_RTR_Data,   4, {0xAA, 0xBB, 0xCC, 0xDD}},
	{0x666, 0x00000000, CAN_Id_Standard, CAN_RTR_Remote, 0, {0x00, 0x00, 0x00, 0x00}},
	{0x000, 0x0789ABCD, CAN_Id_Extended, CAN_RTR_Remote, 0, {0x00, 0x00, 0x00, 0x00}},
};

void can_irq()
{
	CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
}
void USB_LP_CAN1_RX0_IRQHandler(void)
{
	if (CAN_GetITStatus(CAN1, CAN_IT_FMP0) == SET)
	{
		CAN_Receive(CAN1, CAN_FIFO0, &MyCAN_RxMsg);
		MyCAN_RxFlag = 1;.
		
	}
}

程序六 中断接收

	CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	void USB_LP_CAN1_RX0_IRQHandler(void)
	{
		if (CAN_GetITStatus(CAN1, CAN_IT_FMP0) == SET)
		{
			CAN_Receive(CAN1, CAN_FIFO0, &MyCAN_RxMsg);
			MyCAN_RxFlag = 1;
		}
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值