CAN通讯原理与配置

参考资料
探索者STM32F407开发板
《STM32F4开发指南-库函数版本》——CAN通讯实验
CAN参考资料
《STM32中文参考手册_V10》-第22章 控制器局域网(bxCAN)
《STM32F4xx中文参考手册》-第24章 控制器区域网络(bxCAN)
《CAN入门教程》,见光盘:软件资料→ CAN学习资料→ can入门教程.pdf

注意:本案例基于STM32F407
注意:正点原子mini板需要添加TJA1050模块才可以进行CAN实验

一、CAN基础知识介绍

1.什么是CAN

CAN是Controller Area Network 的缩写(以下称为CAN),是ISO国际标准化的串行通信协议。由德国电气商博世公司在1986 年率先提出。此后,CAN 通过ISO11898 及ISO11519 进行了标准化。现在在欧洲已是汽车网络的标准协议。
CAN协议经过ISO标准化后有两个标准:ISO11898标准和ISO11519-2标准。其中ISO11898是针对通信速率为25Kbps~1Mbps的高速通信标准,而ISO11519-2是针对通信速率为125Kbps以下的低速通信标准。
CAN具有很高的可靠性,广泛应用于:汽车电子、工业自动化、船舶、医疗设备、工业设备等方面。

2.CAN协议的特点

①,多主控制。总线空闲时,所有单元都可发送消息,而两个以上的单元同时开始发送消息时,根据标识符(ID,非地址)决定优先级。两个以上的单元同时开始发送消息时,对各消息ID 的每个位进行逐个仲裁比较。仲裁获胜(优先级最高)的单元可继续发送消息,仲裁失利的单元则立刻停止发送而进行接收工作。
②,系统柔软性。连接总线的单元,没有类似“地址”的信息,因此,在总线上添加单元时,已连接的其他单元的软硬件和应用层都不需要做改变。
③,速度快,距离远。最高1Mbps(距离<40M),最远可达10KM(速率<5Kbps)。
④ ,具有错误检测、错误通知和错误恢复功能。所有单元都可以检测错误(错误检测功能),检测出错误的单元会立即同时通知其他所有单元(错误通知功能),正在发送消息的单元一旦检测出错误,会强制结束当前的发送。强制结束发送的单元会不断反复地重新发送此消息直到成功发送为止(错误恢复功能)。
⑤,故障封闭功能。CAN 可以判断出错误的类型是总线上暂时的数据错误(如外部噪声等)还是持续的数据错误(如单元内部故障、驱动器故障、断线等)。由此功能,当总线上发生持续数据错误时,可将引起此故障的单元从总线上隔离出去。
⑥,连接节点多。CAN 总线是可同时连接多个单元的总线。可连接的单元总数理论上是没有限制的。但实际上可连接的单元数受总线上的时间延迟及电气负载的限制。降低通信速度,可连接的单元数增加;提高通信速度,则可连接的单元数减少。

正是因为CAN协议的这些特点,使得CAN特别适合工业过程监控设备的互连,因此,越来越受到工业界的重视,并已公认为最有前途的现场总线之一。

3.CAN物理层特征

使用ISO11898标准,物理层特征如图所示

CAN 控制器根据CAN_L和CAN_H上的电位差来判断总线电平。总线电平分为显性电平和隐性电平,二者必居其一。发送方通过使总线电平发生变化,将消息发送给接收方。
显性电平对应逻辑:0
CAN_H和CAN_L之差为2V左右。
隐性电平对应逻辑:1
CAN_H和CAN_L之差为0V。

显性电平具有优先权,只要有一个单元输出显性电平,总线上即为显性电平。而隐形电平则具有包容的意味,只有所有的单元都输出隐性电平,总线上才为隐性电平(显性电平比隐性电平更强)。另外,在CAN总线的起止端都有一个120Ω的终端电阻,来做阻抗匹配,以减少回波反射。

4.帧种类介绍

CAN通信是以以下5种类型的帧进行的

其中,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID 。
这里只介绍数据帧,其他帧格式,请参考《can入门教程.pdf》

5.数据帧介绍

数据帧的组成(7段)
①,帧起始。
表示数据帧开始的段。
②,仲裁段。
表示该帧优先级的段。
③,控制段。
表示数据的字节数及保留位的段。
④,数据段。
数据的内容,一帧可发送0~8个字节的数据。
⑤,CRC段。
检查帧的传输错误的段。
⑥,ACK段。
表示确认正常接收的段。
⑦,帧结束。
表示数据帧结束的段。

  • 1,帧起始。标准帧和扩展帧都是由1个位的显性电平表示帧起始。

  • 2,仲裁段。表示数据优先级的段,标准帧和扩展帧格式在本段有所区别,如图所示:

  • 3,控制段。由6个位构成,表示数据段的字节数。标准帧和扩展帧的控制段稍有不同,如图所示:

  • 4,数据段。该段可包含0~8个字节的数据,从最高位(MSB)开始输出。标准帧和扩展帧在这个段的格式完全一样:

  • 5,CRC段。该段用于检查帧传输错误。由15个位的CRC顺序和1个位的CRC界定符(用于分隔的位)组成,标准帧和扩展帧在这个段的格式也是相同的:

  • 6,ACK段。此段用来确认是否正常接收。由ACK槽(ACK Slot)和ACK界定符2个位组成。标准帧和扩展帧在这个段的格式也是相同的:

  • 7,帧结束。由7个位的隐性位组成。标准帧和扩展帧在这个段格式完全一样。

6.总线总裁

同时多个单元发送数据时,总线仲裁过程:

规律:1,总线空闲时,最先发送的单元获得发送优先权,一但发送,其他单元无法抢占。2,如果有多个单元同时发送,则连续输出显性电平多的单元,具有较高优先级。
从ID开始比较,如果ID相同,还可能会比较RTR和SRR等位。

7.位时序

  • 位速率。由发送单元在非同步的情况下发送的每秒钟的位数称为位速率。一个位一般可以分为如下四段:
    同步段(SS)
    传播时间段(PTS)
    相位缓冲段1(PBS1)
    相位缓冲段2(PBS2)
    这些段又由可称为 Time Quantum(以下称为Tq)的最小时间单位构成。1 位分为4 个段,每个段又由若干个Tq 构成,这称为位时序。
    位时间=1/波特率,因此,知道位时间,我们就可以知道波特率。
    1 位由多少个Tq 构成、每个段又由多少个Tq 构成等,可以任意设定位时序。通过设定位时序,多个单元可同时采样,也可任意设定采样点。

  • 位时序各段的作用和 Tq 数如下表:

  • 一个位的构成:

图中采样时间加大或减少量的最大值就是SJW

二、STM32 CAN控制器简介

1.bxCAN

STM32自带了基本扩展CAN外设,又称bxCAN,bxCAN的特点如下:

  • 支持CAN协议2.0A和2.0B主动模式
  • 波特率最高达1Mbps
  • 支持时间触发通信
  • 具有3个发送邮箱
  • 具有3级深度的2个接收FIFO
  • 可变的筛选器组(也称过滤器组,最多28个)

2.模式

  • 工作模式
    ①初始化模式(INRQ=1,SLEEP=0)
    ②正常模式(INRQ=0,SLEEP=0)
    ③睡眠模式(SLEEP=1)
    通过CAN_MCR寄存器控制INRQ和SLEEP

  • 测试模式
    ①静默模式( LBKM=0,SILM=1 )

静默模式下,bxCAN可以接收CANRX的数据,但是不会发送任何数据到CANTX,可以用来监控总线数据而不影响总线(只接收不发送)。

②环回模式( LBKM=1,SILM=0 )

环回模式下,bxCAN不接收CANRX的数据,但是会发送数据到CANTX,因为内部有个环路,即实现了自己发送的数据同时又可以自己接收(自发自收)。

③环回静默模式(LBKM=1,SILM=1)

自发自收,与总线数据无关。

通过CAN_BTR寄存器控制LBKM和SILM

  • 调试模式
    少用,这里不介绍。

3.bxCAN框图

4.标识符筛选器

  • CAN的标识符不表示目的地址而是表示发送优先级。接收节点根据标识符的值,来决定是否接收对应消息。

  • STM32 CAN控制器,提供了28个可配置的筛选器组(F1仅互联型才有28个,其他的只有14个),可降低CPU处理CAN通信的开销。

  • STM32 CAN控制器每个筛选器组由2个32位寄存器组成(CAN_FxR1和CAN_FxR2,x=0~27)。根据位宽不同,每个筛选器组可提供:

    • 1个32位筛选器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
    • 2个16位筛选器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
  • 筛选器可配置为:屏蔽位模式标识符列表模式。在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟筛选器标识符相同。

  • 通过CAN_FM1R和CAN_FS1R可配置筛选器的位宽和模式

  • 为了过滤出一组标识符,应该设置筛选器组工作在屏蔽位模式。

  • 为了过滤出一个标识符,应该设置过滤器组工作在标识符列表模式。

  • 应用程序不用的筛选器组,应该保持在禁用状态(通过CAN_FA1R设置)。

  • 筛选器组中的每个筛选器,都被编号为(即:筛选器编号)从0开始,到某个最大数值-取决于筛选器组的模式和位宽的设置。

  • 通过CAN_FFA1R的设置,可以将筛选器组关联到FIFO0/FIFO1
    例:设置筛选器组0工作在:1个32位筛选器-标识符屏蔽模式,然后设置CAN_F0R1=0XFFFF0000,CAN_F0R2=0XFF00FF00。其中存放到CAN_F0R1的值就是期望收到的ID,即(STID+EXTID+IDE+RTR)最好是:0XFFFF0000。而0XFF00FF00就是设置我们需要必须关心的ID,表示收到的映像,其位[31:24]和位[15:8]这16个位的必须和CAN_F0R1中对应的位一模一样,而另外的16个位则不关心,可以一样,也可以不一样,都认为是正确的ID,即收到的映像必须是0XFFxx00xx,才算是正确的(x表示不关心)。
    关于标识符筛选器的其他介绍,请看《STM32中文参考手册》,CAN相关章节。

5.发送流程

CAN发送流程为:
程序选择1个空置的邮箱(TME=1)→设置标识符(ID),数据长度和发送数据→设置CAN_TIxR的TXRQ位为1,请求发送→邮箱挂号(等待成为最高优先级)→预定发送(等待总线空闲)→发送→邮箱空置。

6.接收流程

CAN接收流程为:
FIFO空→收到有效报文→挂号_1(存入FIFO的一个邮箱,这个由硬件控制,我们不需要理会)→收到有效报文→挂号_2→收到有效报文→挂号_3→收到有效报文→溢出。

CAN收到的有效报文,存储在3级邮箱深度的FIFO中。FIFO接收到的报文数,我们可以通过查询CAN_RFxR的FMP寄存器来得到,只要FMP不为0,我们就可以从FIFO读出收到的报文。
报文FIFO具有锁定功能(由CAN_MCR,RFLM位控制),锁定后,新数据将丢弃,不锁定则新数据将替代老数据

7.位时序

提示:STM32的CAN将传播时间段和相位缓冲时间段1合并成时间段1

STM32F103,设TS1=8、TS2=7、BRP=3,波特率=36000/[(9+8+1)*4]=500Kbps。
STM32F407,设TS1=6、TS2=5、BRP=5,波特率=42000/[(7+6+1)*6]=500Kbps。

三、寄存器简介

1.CAN主控制寄存器(CAN_MCR)

该寄存器的我们仅介绍下INRQ位,该位用来控制初始化请求。
设置INRQ=0,可使CAN从初始化模式进入正常工作模式。
设置INRQ=1,可使CAN从正常工作模式进入初始化模式 。
CAN初始化时,先设置INRQ=1 ,进入初始化模式,进行初始化(尤其是CAN_BTR的设置,该寄存器,必须在CAN正常工作之前设置),之后再设置INRQ=0,进入正常工 作模式。

2.CAN位时序寄存器(CAN_BTR)

3.CAN接收FIFO寄存器(CAN_RF0R/CAN_RF1R)

4.CAN发送邮箱标识符寄存器(CAN_TIxR)(x=0~2)

5.CAN发送邮箱数据长度和时间戳寄存器 (CAN_TDTxR) (x=0~2)

TIME[15:0]和TGT位,用于时间戳相关设置,这里不做介绍。请大家参考《STM32中文参考手册》相关章节。

6.CAN发送邮箱数据寄存器(CAN_TDLxR/CAN_TDHxR) (x=0~2)

7.CAN接收FIFO邮箱标识符寄存器(CAN_RIxR)(x=0/1)

8.CAN接收FIFO邮箱数据长度和时间戳寄存器(CAN_RDTxR) (x=0/1)

TIME[15:0],用于时间戳相关设置,FMI用于存储筛选器匹配索引,这里不做介绍。请大家参考《STM32中文参考手册》相关章节。

9.CAN接收FIFO邮箱邮箱数据寄存器(CAN_RDLxR/CAN_RDHxR) (x=0/1)

10.CAN筛选器模式寄存器(CAN_FM1R)

该寄存器设置筛选器的工作模式,必须在CAN_FMR寄存器FINIT=1时配置,对于STM32F103ZET6,只有[13:0]位有效,对于互联性STM32F1或者STM32F407,则全部有效。

11.CAN筛选器尺度寄存器(CAN_FS1R)

该寄存器用于设置筛选器的位宽,必须在CAN_FMR寄存器FINIT=1时配置,对于STM32F103ZET6,只有[13:0]位有效,对于互联性STM32F1或者STM32F407,则全部有效。

12.CAN筛选器FIFO关联寄存器(CAN_FFA1R)

该寄存器设置报文通过筛选器组之后,被存入的FIFO,如果对应位为0,则存放到FIFO0;如果为1,则存放到FIFO1。该寄存器也只能在过滤器处于初始化模式( CAN_FMR 寄存器的FINIT=1 )下配置。

13.CAN筛选器激活寄存器(CAN_FA1R)

该寄存器用于设置筛选器组的开启和关闭。对对应位置1,即开启对应的筛选器组;置0则关闭该筛选器组。

14.CAN筛选器组i寄存器x(CAN_FiRx)(i=0~27,x=1/2)

每个筛选器组的CAN_FiRx都由2个32位寄存器构成,即:CAN_FiR1和CAN_FiR2。根据过滤器位宽和模式的不同设置,这两个寄存器的功能也不尽相同。关于过筛选器的映射,功能描述和屏蔽寄存器的关联,在前面已经介绍过了。

四、源码讲解

1.初始化流程

①配置相关引脚的复用功能,使能CAN时钟。
要用CAN,先要使能CAN的时钟,CAN的时钟通过APB1ENR的第25位来设置。其次要设置CAN的相关引脚为复用输出,这里我们需要设置PA11为上拉输入(CAN_RX引脚)PA12为复用输出(CAN_TX引脚),并使能PA口的时钟

②设置CAN工作模式及波特率等。
通过先设置CAN_MCR寄存器的INRQ位,让CAN进入初始化模式,然后设置CAN_MCR的其他相关控制位。再通过CAN_BTR设置波特率和工作模式(正常模式/环回模式)等信息。 最后设置INRQ为0,退出初始化模式。

③设置滤波器。
本例程,我们将使用筛选器组0,并工作在32位标识符屏蔽位模式下。先设置CAN_FMR的FINIT位,进入初始化模式,然后设置筛选器组0的工作模式以及标识符ID和屏蔽位。最后激活筛选器,并退出初始化模式。

2.重点掌握以下内容

1,标识符筛选器
2,数据收发流程
3,位时序(波特率设置)
4,了解相关寄存器及其作用
5,了解CAN初始化流程

五、CAN实验测试

1.硬件连接

用跳线帽将指定GPIO与CAN_RX和CAN_TX连接在一起

2.can.c函数

#include "can.h"
#include "usart.h"
#include "delay.h"
#include "led.h"CAN_HandleTypeDef CAN1_Handler;   //CAN1句柄
CAN_TxHeaderTypeDef TxHeader;      //发送
CAN_RxHeaderTypeDef RxHeader;      //接收CAN初始化
//tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1TQ~CAN_SJW_4TQ
//tbs2:时间段2的时间单元.   范围:CAN_BS2_1TQ~CAN_BS2_8TQ;
//tbs1:时间段1的时间单元.   范围:CAN_BS1_1TQ~CAN_BS1_16TQ
//brp :波特率分频器.范围:1~1024; tq=(brp)*tpclk1
//波特率=Fpclk1/((tbs1+tbs2+1)*brp); 其中tbs1和tbs2我们只用关注标识符上标志的序号,例如CAN_BS2_1TQ,我们就认为tbs2=1来计算即可。
//mode:CAN_MODE_NORMAL,普通模式;CAN_MODE_LOOPBACK,回环模式;
//Fpclk1的时钟在初始化的时候设置为42M,如果设置CAN1_Mode_Init(CAN_SJW_1tq,CAN_BS2_6tq,CAN_BS1_7tq,6,CAN_MODE_LOOPBACK);
//则波特率为:42M/((6+7+1)*6)=500Kbps
//返回值:0,初始化OK;
//    其他,初始化失败; u8 CAN1_Mode_Init(u32 tsjw,u32 tbs2,u32 tbs1,u16 brp,u32 mode)
{CAN_InitTypeDef        CAN1_InitConf;CAN1_Handler.Instance=CAN1;CAN1_Handler.Init = CAN1_InitConf;CAN1_Handler.Init.Prescaler=brp;              //分频系数(Fdiv)为brp+1CAN1_Handler.Init.Mode=mode;                    //模式设置 CAN1_Handler.Init.SyncJumpWidth=tsjw;           //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQCAN1_Handler.Init.TimeSeg1=tbs1;              //tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQCAN1_Handler.Init.TimeSeg2=tbs2;               //tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQCAN1_Handler.Init.TimeTriggeredMode=DISABLE;    //非时间触发通信模式 CAN1_Handler.Init.AutoBusOff=DISABLE;          //软件自动离线管理CAN1_Handler.Init.AutoWakeUp=DISABLE;            //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)CAN1_Handler.Init.AutoRetransmission=ENABLE; //禁止报文自动传送 CAN1_Handler.Init.ReceiveFifoLocked=DISABLE;    //报文不锁定,新的覆盖旧的 CAN1_Handler.Init.TransmitFifoPriority=DISABLE; //优先级由报文标识符决定 if(HAL_CAN_Init(&CAN1_Handler)!=HAL_OK)          //初始化return 1;return 0;
}//CAN底层驱动,引脚配置,时钟配置,中断配置
//此函数会被HAL_CAN_Init()调用
//hcan:CAN句柄
void HAL_CAN_MspInit(CAN_HandleTypeDef* hcan)
{GPIO_InitTypeDef GPIO_Initure;__HAL_RCC_CAN1_CLK_ENABLE();                //使能CAN1时钟__HAL_RCC_GPIOA_CLK_ENABLE();              //开启GPIOA时钟GPIO_Initure.Pin=GPIO_PIN_11|GPIO_PIN_12;   //PA11,12GPIO_Initure.Mode=GPIO_MODE_AF_PP;          //推挽复用GPIO_Initure.Pull=GPIO_PULLUP;              //上拉GPIO_Initure.Speed=GPIO_SPEED_FAST;         //快速GPIO_Initure.Alternate=GPIO_AF9_CAN1;       //复用为CAN1HAL_GPIO_Init(GPIOA,&GPIO_Initure);         //初始化
}void CAN_Config(void)
{CAN_FilterTypeDef  sFilterConfig;/*##-2- Configure the CAN Filter ###########################################*/sFilterConfig.FilterBank = 0;sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;sFilterConfig.FilterIdHigh = 0x0000;sFilterConfig.FilterIdLow = 0x0000;sFilterConfig.FilterMaskIdHigh = 0x0000;sFilterConfig.FilterMaskIdLow = 0x0000;sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;sFilterConfig.FilterActivation = ENABLE;sFilterConfig.SlaveStartFilterBank = 14;if (HAL_CAN_ConfigFilter(&CAN1_Handler, &sFilterConfig) != HAL_OK){/* Filter configuration Error */while(1){}}/*##-3- Start the CAN peripheral ###########################################*/if (HAL_CAN_Start(&CAN1_Handler) != HAL_OK){/* Start Error */while(1){}}/*##-4- Activate CAN RX notification #######################################*/if (HAL_CAN_ActivateNotification(&CAN1_Handler, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK){/* Notification Error */while(1){}}/*##-5- Configure Transmission process #####################################*/TxHeader.StdId = 0x321;TxHeader.ExtId = 0x01;TxHeader.RTR = CAN_RTR_DATA;TxHeader.IDE = CAN_ID_STD;TxHeader.DLC = 2;TxHeader.TransmitGlobalTime = DISABLE;
}//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)
//len:数据长度(最大为8)
//msg:数据指针,最大为8个字节.
//返回值:0,成功;
//       其他,失败;
u8 CAN1_Send_Msg(u8* msg,u8 len)
{   u8 i=0;u32 TxMailbox;u8 message[8];TxHeader.StdId=0X12;        //标准标识符TxHeader.ExtId=0x12;        //扩展标识符(29位)TxHeader.IDE=CAN_ID_STD;    //使用标准帧TxHeader.RTR=CAN_RTR_DATA;  //数据帧TxHeader.DLC=len;                for(i=0;i<len;i++){message[i]=msg[i];}if(HAL_CAN_AddTxMessage(&CAN1_Handler, &TxHeader, message, &TxMailbox) != HAL_OK)//发送{return 1;}while(HAL_CAN_GetTxMailboxesFreeLevel(&CAN1_Handler) != 3) {}return 0;
}//can口接收数据查询
//buf:数据缓存区;
//返回值:0,无数据被收到;
//       其他,接收的数据长度;
u8 CAN1_Receive_Msg(u8 *buf)
{u32 i;u8   RxData[8];if(HAL_CAN_GetRxFifoFillLevel(&CAN1_Handler, CAN_RX_FIFO0) != 1){return 0xF1;}if(HAL_CAN_GetRxMessage(&CAN1_Handler, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK){return 0xF2;}for(i=0;i<RxHeader.DLC;i++)buf[i]=RxData[i];return RxHeader.DLC;
}

**注意:**在CAN文件里面有对应的注释

其对里面参数值进行了宏定义处理,对要填入寄存器的数据用变量进行替代

3.初始化函数:CAN1_Mode_Init

CAN初始化函数名:u8 CAN1_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
详细配置流程看代码注释和参考文档

4.数据发送函数:

//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)
//len:数据长度(最大为8)
//msg:数据指针,最大为8个字节.
//返回值:0,成功;
//       其他,失败;
u8 CAN1_Send_Msg(u8* msg,u8 len)
{   u16 i=0;CAN1_Handler.pTxMsg->StdId=0X12;        //标准标识符CAN1_Handler.pTxMsg->ExtId=0x12;        //扩展标识符(29位)CAN1_Handler.pTxMsg->IDE=CAN_ID_STD;    //使用标准帧CAN1_Handler.pTxMsg->RTR=CAN_RTR_DATA;  //数据帧CAN1_Handler.pTxMsg->DLC=len;           //要发送的数据的长度       for(i=0;i<len;i++)CAN1_Handler.pTxMsg->Data[i]=msg[i];if(HAL_CAN_Transmit(&CAN1_Handler,10)!=HAL_OK) return 1;     //发送return 0;
}

下面为CAN发送邮箱的位置

4.数据接收函数:

//can口接收数据查询
//buf:数据缓存区;
//返回值:0,无数据被收到;
//       其他,接收的数据长度;
u8 CAN1_Receive_Msg(u8 *buf)
{                  u32 i;if(HAL_CAN_Receive(&CAN1_Handler,CAN_FIFO0,0)!=HAL_OK) return 0;//接收数据,超时时间设置为0    for(i=0;i<CAN1_Handler.pRxMsg->DLC;i++)buf[i]=CAN1_Handler.pRxMsg->Data[i];return CAN1_Handler.pRxMsg->DLC;
}

5.main.c函数:

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "sdram.h"
#include "can.h"int main(void)
{u8 key;u8 i=0,t=0;u8 cnt=0;u8 canbuf[8];u8 res;u8 mode=1; HAL_Init();                     //初始化HAL库   Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhzdelay_init(180);                //初始化延时函数uart_init(115200);              //初始化USARTLED_Init();                     //初始化LED KEY_Init();                     //初始化按键SDRAM_Init();                   //初始化SDRAMLCD_Init();                     //初始化LCDCAN1_Mode_Init(CAN_SJW_1TQ,CAN_BS2_6TQ,CAN_BS1_8TQ,6,CAN_MODE_LOOPBACK); //CAN初始化,波特率500Kbps      POINT_COLOR=RED;LCD_ShowString(30,50,200,16,16,"Apollo STM32F4/F7"); LCD_ShowString(30,70,200,16,16,"CAN TEST");    LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");LCD_ShowString(30,110,200,16,16,"2016/1/16");          LCD_ShowString(30,130,200,16,16,"LoopBack Mode");  LCD_ShowString(30,150,200,16,16,"KEY0:Send WK_UP:Mode");//显示提示信息     POINT_COLOR=BLUE;//设置字体为蓝色   LCD_ShowString(30,170,200,16,16,"Count:");          //显示当前计数值   LCD_ShowString(30,190,200,16,16,"Send Data:");        //提示发送的数据   LCD_ShowString(30,250,200,16,16,"Receive Data:"); //提示接收到的数据      while(1){key=KEY_Scan(0);if(key==KEY0_PRES)//KEY0按下,发送一次数据{for(i=0;i<8;i++){canbuf[i]=cnt+i;//填充发送缓冲区if(i<4)LCD_ShowxNum(30+i*32,210,canbuf[i],3,16,0X80);   //显示数据else LCD_ShowxNum(30+(i-4)*32,230,canbuf[i],3,16,0X80);  //显示数据}res=CAN1_Send_Msg(canbuf,8);//发送8个字节 if(res)LCD_ShowString(30+80,190,200,16,16,"Failed");        //提示发送失败else LCD_ShowString(30+80,190,200,16,16,"OK    ");           //提示发送成功                                   }else if(key==WKUP_PRES)//WK_UP按下,改变CAN的工作模式{      mode=!mode;if(mode==0)  CAN1_Mode_Init(CAN_SJW_1TQ,CAN_BS2_6TQ,CAN_BS1_8TQ,6,CAN_MODE_NORMAL);        //回环模式,波特率500Kbpselse if(mode==1) CAN1_Mode_Init(CAN_SJW_1TQ,CAN_BS2_6TQ,CAN_BS1_8TQ,6,CAN_MODE_LOOPBACK);  //回环模式,波特率500KbpsPOINT_COLOR=RED;//设置字体为红色 if(mode==0)//普通模式,需要2个开发板{LCD_ShowString(30,130,200,16,16,"Nnormal Mode ");        }else //回环模式,一个开发板就可以测试了.{LCD_ShowString(30,130,200,16,16,"LoopBack Mode");}POINT_COLOR=BLUE;//设置字体为蓝色 }      key=CAN1_Receive_Msg(canbuf);if(key)//接收到有数据{         LCD_Fill(30,270,160,310,WHITE);//清除之前的显示for(i=0;i<key;i++){                                       if(i<4)LCD_ShowxNum(30+i*32,270,canbuf[i],3,16,0X80);   //显示数据else LCD_ShowxNum(30+(i-4)*32,290,canbuf[i],3,16,0X80);  //显示数据}}t++; delay_ms(10);if(t==20){LED0=!LED0;//提示系统正在运行  t=0;cnt++;LCD_ShowxNum(30+48,170,cnt,3,16,0X80);    //显示数据}        }
}

38.CAN通讯原理与配置相关推荐

  1. 紫金桥组态软件和厦门四信DTU通讯原理及配置

    四信的DTU又称为无线IP MODEM,是一种无线数据终端(以下都称为无线 IP MODEM).在实际应用中紫金桥作为服务器端,无线IP MODEM作为客户端把数据通过无线网络转发给紫金桥软件,为用户 ...

  2. 第五章 路由器的工作原理及其配置

    第五章 路由器的工作原理及其配置 5.1 广域网服务 WAN连接的目的是在两个远离的网络之间尽可能高效率传递数据.连接的效率越高,到最终用户的连接就越透明.WAN连接通常比L A N连接要慢.例如,一 ...

  3. Spring MVC原理及配置详解

    转载自 http://blog.csdn.net/jianyuerensheng/article/details/51258942 [Spring]Spring MVC原理及配置 1.Spring M ...

  4. 开源纯C#工控网关+组态软件(四)上下位机通讯原理

    一.   网关的功能:承上启下 最近有点忙,更新慢了.感谢园友们给予的支持,现在github上已经有.目标是最好的开源组态,看来又近一步^^ 之前有提到网关是物联网的关键环节,它的作用就是承上启下. ...

  5. 使用长角牛演示:防止ARP协议被攻击原理和配置

    使用长角牛演示:防止ARP协议被攻击原理和配置 1. *实验环境* 虚拟机window7.window10.长角牛软件.ensp软件,关闭真机.虚拟机win7和win8的防火墙. 2. *实验描述* ...

  6. 使用长角牛演示:防止ARP被攻击的原理和配置----------划水也别忘记学着玩

    使用长角牛演示:防止ARP被攻击的原理和配置 Hero 即兴随笔第一篇 实验开始 实验环境 虚拟机window7.window10.长角牛软件.ensp软件,关闭真机.虚拟机win7和win8的防火墙 ...

  7. 9、RH850 SPI(CSIH) 通讯功能和配置

    前言: SPI是最常见的串行通讯之一,其通信速率比较高,适合需要传输大量数据的应用.常见的有SPI FLASH,无线模块等.这里IIC的具体原理讲解就不做介绍,不清楚的朋友可移步up主的个人专栏 -- ...

  8. 安全L1-AD.3-DNS代理原理及配置

    一.DNS代理原理 1.DNS代理介绍:         DNS代理主要应用于实现DNS流量的负载,同时可以针对指定域名返回指定结果,或者指定域名指向特定DNS服务器解析等.       代理过程:( ...

  9. LPC1788单沿pwm原理和配置

    LPC1788单沿pwm原理和配置 pwm的基本功能:以一定的周期频率,输出不同占空比可调的方波. Lpc1788中的pwm的时钟(频率)来源于APB总线的时钟(频率),首先要进行分频,或者说预分频, ...

最新文章

  1. linux自学笔记——RAID级别特性以及软RAID的实现
  2. 解决ASP.NET Core部署到IIS,更新项目另一个程序正在使用此文件,进程无法访问...
  3. 使用sqlserver搭建高可用双机热备的Quartz集群部署【附源码】
  4. wndows程序设计之书籍知识与代码摘录-封装一个类似printf的messagebox
  5. 【每日SQL打卡】​​​​​​​​​​​​​​​DAY 5丨至少有5名直接下属的经理【难度中等】
  6. LeetCode-116. 填充每个节点的下一个右侧节点指针
  7. pycharm console日志如何输出到txt_Django实战2-自动化运维之配置管理-04:知识扩展-logging日志模块...
  8. LINUX 安装 PHP5.6.13
  9. node mysql 搭建博客_node.js+Hexo+Git搭建个人博客
  10. 什么专业的会学python语言_还在纠结学什么编程语言吗?Python可能会“教”你做人...
  11. 解决用root用户及密码可以直接登陆某LINUX系统,但是用ssh登陆,系统却总是提示密码不对...
  12. SPI(Service Provider Interface)机制
  13. sola病毒批量恢复工具 —— 大一的回忆
  14. win10计算机护眼,win10系统设置护眼模式的三种方法
  15. 盗火:硅谷、海豹突击队和疯狂科学家如何变革我们的工作和生活
  16. 上座部佛教的佛陀略传
  17. bochs运行xp_bochs xp镜像完整免费版
  18. SQL的概述及DDL
  19. 图观——渲染一个简易的三维场景
  20. 南京邮电大学操作系统实验四:简单文件系统模拟实验

热门文章

  1. 机械硬盘vs固态硬盘
  2. 饥荒机器人升级上限多少_饥荒里机器人属性最高升级到多少
  3. GEF基础入门(1)
  4. 树莓派组装成linux电脑,可放进口袋基于树莓派的GNU/Linux电脑
  5. 高斯消元法 思路及模板代码
  6. descriptor理解和例程
  7. promise封装小程序api请求
  8. 目标检测--RFBNet环境配置、训练及验证 (血和泪的教训)
  9. 自动修复你的电脑未正确启动
  10. 研究报告称开源软件正在吞食企业软件市场