| **银杏科技有限公司旗下技术文档发布平台** |||| |技术支持电话|**0379-69926675-801**||| |技术支持邮件|Gingko@vip.163.com||| ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | V1.0 | 2020-12-03 | gingko | 初次建立 | \\ \\ ===== STM32CubeMX教程四十三——CAN通信实验 ===== 1.在主界面选择File-->New Project或者直接点击ACCEE TO MCU SELECTOR {{ :icore3l:icore3l_cube_47_1.png?direct |}} 2.出现芯片型号选择,搜索自己芯片的型号,双击型号,或者点击Start Project进入配置在搜索栏的下面,提供的各 种查找方式,可以选择芯片内核,型号等等,可以帮助你查找芯片。本实验选取的芯片型号为:STM32F429IGHx。 {{ :icore3l:icore3l_cube_47_2.png?direct |}} 3.配置RCC,使用外部时钟源 {{ :icore3l:icore3l_cube_47_3.png?direct |}} 4.Debug选择Serial Wire,时基源选择SysTick {{ :icore3l:icore3l_cube_47_4.png?direct |}} {{ :icore3l:icore3l_cube_47_5.png?direct |}} 5.将PI3,PI4,PH14设置为GPIO_Output {{ :icore3l:icore3l_cube_47_6.png?direct |}} 6.引脚模式配置 {{ :icore3l:icore3l_cube_47_7.png?direct |}} 7.配置CAN {{ :icore3l:icore3l_cube_47_8.png?direct |}} 在NVIC Settings一栏使能接收中断 {{ :icore3l:icore3l_cube_47_9.png?direct |}} 8.时钟源设置,选择外部高速时钟源,配置为最大主频 {{ :icore3l:icore3l_cube_47_10.png?direct |}} 9.工程文件的设置, 这里就是工程的各种配置 我们只用到有限几个,其他的默认即可IDE我们使用的是MDK V5.27 {{ :icore3l:icore3l_cube_47_11.png?direct |}} 10.点击Code Generator,进行进一步配置 {{ :icore3l:icore3l_cube_47_12.png?direct |}} * **Copy all used libraries into the project folder** * 将HAL库的所有.C和.H都复制到所建工程中 * 优点:这样如果后续需要新增其他外设又可能不再用STM32CubeMX的时候便会很方便 * 缺点:体积大,编译时间很长 * **Copy only the necessary library files** * 只复制所需要的.C和.H(推荐) * 优点:体积相对小,编译时间短,并且工程可复制拷贝 * 缺点:新增外设时需要重新用STM32CubeMX导入 * **Add necessary library files as reference in the toolchain project configuration file** * 不复制文件,直接从软件包存放位置导入.C和.H * 优点:体积小,比较节约硬盘空间 * 缺点:复制到其他电脑上或者软件包位置改变,就需要修改相对应的路径 * 自行选择方式即可 11.然后点击GENERATE CODE创建工程 {{ :icore3l:icore3l_cube_47_13.png?direct |}} 创建成功,打开工程。 \\ \\ \\ \\ ===== 实验四十三:CAN通信实验——回环测试 ===== ==== 一、实验目的与意义 ==== - 了解STM32的CAN结构 - 了解STM32的CAN特征 - 掌握STM32的CAN的使用方法 - 掌握KEILMDK集成开发环境使用方法 ==== 二、实验设备及平台 ==== - iCore3L 双核心板 - USBCAN设备 - JLINK(或相同功能)仿真器 - Micro USB线缆 - Keil MDK 开发平台 - STM32CubeMX开发平台 - 装有WIN XP(及更高版本)系统的计算机 ==== 三、实验原理 ==== === 1.CAN简介 === * CAN是Controller Area Network的缩写(简称为CAN),是由以研发和生产汽车电子产品著称的德国BOSCH公司开发的,并最终成为国际标准(ISO 11898),是国际上应用最广泛的现场总线之一。 * CAN总线协议已经成为汽车计算机控制系统和嵌入式工业控制局域网的标准总线,并且拥有以CAN为底层协议专为大型货车和重工机械车辆设计的J1939协议。 * CAN的可靠性已经得到广泛认可,被应用于工业自动化、船舶、医疗设备、工业设备等方面。 * **CAN 协议具有以下特点:** * 1)多主控制。 在总线空闲时,所有单元都可以发送消息(多主控制),而两个以上的单元同时开始发送消息时, 根据标识符( Identifier 以下称为 ID)决定优先级。 ID 并不是表示发送的目的地址,而是表示访问总线的消息的优先级。两个以上的单元同时开始发送消息时,对各消息 ID 的每个位进行逐个仲裁比较。仲裁获胜(被判定为优先级最高)的单元可继续发送消息,仲裁失利的单元则立刻停止发送而进行接收工作。 * 2)系统的柔软性。 与总线相连的单元没有类似于“地址”的信息。因此在总线上增加单元时,连接在总线上的其它单元的软硬件及应用层都不需要改变。 * 3)通信速度较快,通信距离远。 最高 1Mbps(距离小于 40M),最远可达 10KM(速率低于 5Kbps)。 * 4)具有错误检测、错误通知和错误恢复功能。 所有单元都可以检测错误(错误检测功能),检测出错误的单元会立即同时通知其他所有单元(错误通知功能), 正在发送消息的单元一旦检测出错误,会强制结束当前的发送。强制结束发送的单元会不断反复地重新发送此消息直到成功发送为止(错误恢复功能)。 * 5)故障封闭功能。 CAN 可以判断出错误的类型是总线上暂时的数据错误(如外部噪声等)还是持续的数据错误(如单元内部故障、驱动器故障、断线等)。由此功能,当总线上发生持续数据错误时,可将引起此故障的单元从总线上隔离出去。 * 6)连接节点多。 CAN 总线是可同时连接多个单元的总线。可连接的单元总数理论上是没有限制的。但实际上可连接的单元数受总线上的时间延迟及电气负载的限制。降低通信速度,可连接的单元数增加;提高通信速度,则可连接的单元数减少。 * **CAN物理层:** * CAN是一种异步通讯,只有CAN_High和CAN_Low两条信号线,共同构成一组差分信号线,以差分信号的形式进行通讯。 * **闭环总线网络:** * CAN物理层的形式主要有两种,如下图是其中的一种“闭环网络”,它允许总线最大长度为40m,最高速度为1Mbps,可以看到总线的两端各有一个120欧的电阻,这是规定。节点就是不同的设备,连接到一个闭环总线上面。 {{ :icore3l:icore3l_arm_hal_47_1.png?direct |}} * **开环总线网络:** {{ :icore3l:icore3l_arm_hal_47_2.png?direct |}} * **通讯节点:** * CAN节点是指能够挂接在CAN总线上的单元,并能通过CAN总线实现各个节点间的通信,以实现复杂的控制过程。理论上CAN总线连接的节点可达110个,但实际上收到总线上的时间延迟及电气负载的限制。当连接多节点时,降低通信速率,可连接的节点增加;提高通信速率,则可连接的节点数减少。 * CAN通讯节点由一个CAN控制器及CAN收发器,CAN控制器用于实现实现CAN总线的协议底层以及数据链路层,用于生成CAN帧并以二进制码流的方式发送,在此过程中进行位填充、添加CRC校验、应答检测等操作;将接收到的二进制码流进行解析并接收,在此过程中进行收发比对、去位填充、执行CRC校验等操作。此外还需要进行冲突判断、错误处理等诸多任务。 * CAN收发器(有时也叫做驱动器),用于将二进制码流转换为差分信号发送,将差分信号转换为二进制码流接收。 * 我们已经知道CAN控制器和收发器的概念,观察上面2张图,为接线方式,控制器和收发器通过普通的类似TTL逻辑信号来连接,CAN_Low和CAN_High是一对差分信号线。 * 当CAN节点需要发送数据时,控制器把要发送的二进制编码通过通过CAN_Tx线发送到收发器,然后由收发器把这个普通的逻辑电平信号转换成差分信号,通过差分线CAN_High和CAN_Low线输出到CAN总线网络。而通过收发器接收总线上的数据的到控制器时,是相反的过程。 * **CAN协议中的差分信号:** * 差分信号又称为差模信号,具体的含义这里不多介绍了。CAN协议中对它使用的CAN_High以及CAN_Low表示的差分信号做了规定,如下图,可以看到,显性电平对应逻辑“0”,隐性电平对应逻辑“1”。当表示为隐性电平(逻辑“1”)时,CAN_High和CAN_Low的电压均为2.5V,此时它们的电压差为0V;当表示显性电平(逻辑“0”)时,CAN_High的电压为3.5V,CAN_Low的电压为1.5V,它们的电压差为2V。举个例子:当CAN收发器从CAN_Tx线接收到来自CAN控制器的低电平信号(逻辑“0”)时,它会使CAN_High输出3.5V,同时CAN_Low输出1.5V。在总线上显性电平具有优先权,只要有一个单元(也就是节点)输出显性电平,总线上即为显性电平。而隐性电平则具有包容的含义,只有所有的单元都输出隐性电平,总线上才为隐性电平。那么可以知道,CAN通讯是半双工的,收发数据需要分开来进行,由于是公用总线,在整个网络中,同一时刻只能由一个通讯节点发送信号,其余的节点在该时刻只能接收。 {{ :icore3l:icore3l_arm_hal_47_3.png?direct |}} === 2.协议层 === * **CAN的位时序以及同步:** * 由于CAN属于异步通讯,没有时钟信号线,那么节点间就需要约定好波特率进行通讯。同时,为实现正确的总线电平采样,确保通讯正常,由此引出“位时序”的概念。 * **位时序的组成:** * CAN协议将每一个数据位的时序分解成4段,即:SS段、PTS段、PBS1段、PBS2段,这4段加起来就是一个CAN数据位的长度。而分解后的最小时间单位是Tq,一个完整的位由8~25个Tq组成。如下图是总线电平下每个位分解。 {{ :icore3l:icore3l_arm_hal_47_4.png?direct |}} * **SS段:**称为同步段,用于使总线上的各个节点同步,要求有一个跳变沿位于此段内,该段的长度为1Tq; * **PTS段:**称为传播时间段,用于补偿网络内的物理延时,它是信号在总线上传播时间,输入比较器延时和输出驱动器延时之和的两倍,该段长可以为1~8Tq; * **PBS1段:**称为相位缓冲段,主要用来补偿变压阶段的误差,它的实际长度在重新同步的时候可以加长,该段大小可以为1~8Tq; * **PBS2段:**称为另一个相位缓冲段,也是用来补偿边沿阶段的误差,它的时间长度在重新同步的时候可以加长,该段大小可以为2~8Tq。 * **通讯的波特率:** * 总线上的各个通讯节点只要约好1个Tq的时间长度以及每一个数据位占据多少个Tq,就可以确定CAN通讯的波特率。 * 假设图30-4中1Tq=1us,而有19个Tq,则传输一位数据需要的实际为19us。 * 这样每秒可以传输的数据位个数为:1*106/19=52631.6(bps),即为波特率。 * **CAN同步机制:** * CAN规范定义了自己独有的同步方式:硬同步和重同步。同步与位时序密切相关。同步是由节点自身完成的,节点将检测到来自总线的沿与其自身的位时序相比较,并通过硬同步或重同步适配(调整)位时序。 * CAN总线的位同步只有在节点检测到“隐性位(逻辑1)”到“显性位(逻辑0)”的跳变时才会产生,我们知道在同步段需要跳变沿,当跳变沿不处于此同步段内时,那么就会产生相位误差,该相位误差就是跳变沿与同步段结束位置直接的距离,产生误差的原因有多种,那么针对此种误差,也就是上面说到的硬同步和重同步。 * 硬同步只在总线空闲时通过一个下降沿(下面将讲到的帧起始)来完成,此时不管有没有相位误差,所有节点的位时序将重新开始。强迫引起硬同步的跳变沿位于重新开始的位时间的同步段之内。 * 重同步,在消息帧的随后位中,每当有从“隐性位”到“显性位”的跳变,并且该跳变段落在了同步段之外,就会引起一次重同步。重同步机制可以根据跳变沿增长或者缩短位时序以调整采样点的位置,保证正确采样。 * **CAN报文:** * 和SPI和串口协议不同的是,CAN使用两条差分信号线,因而只能表示一个信号,于是为了实现完整的传输信号功能,CAN协议便对数据、操作命令以及同步信号进行打包,打包后的内容便称为报文。 * **CAN报文格式:** * CAN一共规定了5种类型的帧,分别是:数据帧、遥控帧、错误帧、过载帧、帧间隔,作用见下表。另外,数据帧和遥控帧有标准格式和扩展格式两个,唯一的区别是标识符(ID)不同,在下面数据帧的结构讲解中,我们会对两个格式进行介绍。 {{ :icore3l:icore3l_arm_hal_47_5.png?direct |}} * **数据帧的结构** * 数据帧是CAN通信中最中意、最复杂的报文,以一个显性位(逻辑0)开始,以一个7个连续隐性位(逻辑1)结束。在它们之间分为仲裁段、控制段、数据段、CRC段和ACK段,加上起始和结束总共有7个段。 * 在下图中,在标准帧和扩展帧除了ID和DLC之外,还有RTR、IDE、SRR位。首先是RTR位,翻译为远程传输请求位,用显性电平和隐性电平来区分数据帧和遥控帧。然后是IDE位,为标识符扩展位,用显性电平和隐性电平来区分标准格式还是扩展格式。最后是SRR位,只存在于扩展格式,它用于替代标准格式中的RTR位,由于扩展帧中的SRR位为隐性位,RTR是数据帧为显性位,所以在两个ID相同的标准格式报文与扩展格式报文中,标准格式的优先级更高。 {{ :icore3l:icore3l_arm_hal_47_6.png?direct |}} * **帧起始** * SOF段(Start Of Frame),翻译为帧起始,标准帧和扩展帧都是通过一个显性电平表示帧起始。它用于通知各个节点将有数据传输,其它节点通过帧起始信号的电平跳变沿来进行硬同步。 * **仲裁段** * 简单来说就是表示优先级的段。仲裁段的内容主要为本数据帧的ID信息,数据帧具有标志格式和扩展格式两种,具体的区别就是ID信息的长度,标准格式的ID为11位,扩展格式的ID为29位,观察上图应该也发现了。 * 在CAN协议中,ID起着重要的作用,它决定着数据帧发送的优先级,也决定着其它节点是否会接收到这个数据帧。CAN的数据通信没有主从之分,任意一个节点可以向其他(一个或多个)节点发起数据通信,而对总线的占有权是由信息的重要性决定的,也就是说重要的信息,对它打包上一个优先级高的ID,使它能够及时地发送出去,也正是由于这样优先级的分配原则,使CAN的扩展性大大加强,在总线上增加或减少节点并不会影响其它的设备。 * 那么怎么仲裁呢?让我们联系前面的内容,显性电平的优先权和隐性电平的包容性,CAN正是利用这个特性进行仲裁。若两个节点同时竞争CAN总线的占有权,当它们发送报文时,若首先出现隐性电平,则会失去对总线的占有权,进入接收状态。 * **控制段** * r1和r0为保留位,默认置为显性,它最主要的是由4位组成的DLC段,MSB先行,DLC段表示的数字为0~8。 * **数据段** * 为数据帧的核心内容,它是节点要发送的原始信息,由0~8个字节组成,MSB先行。 * **CRC段** * 为保证报文的正确传输,CAN的报文包含了一段15位的CRC校验码,若检验出错则向发送节点反馈出错信息,利用错误帧请求它重新发送。CRC计算一般由CAN控制器硬件完成,而出错时处理由软件控制最大的重发数。在CRC校验码之后,有一个CRC界定符,为隐性,将CRC校验码与后面的ACK段分隔开。 * **ACK段** * 包括一个ACK槽位和ACK界定符,在ACK槽位中,发送端发送的为隐性位,接收端在这一位中发送显性位以表示应答,在ACK界定槽和帧结束之间由ACK界定符分隔开。 * **帧结束段** * 由发送节点发送7个隐性位表示结束。 === 3.STM32的CAN外设简介 === * STM32具有bxCAN,是基本扩展CAN,它支持CAN协议2.0A和2.0B。它的设计目标是以最小的CPU负荷来高效处理大量接收到的报文。也支持报文发送的优先级要求(通过软件配置)。bxCAN提供所有支持时间触发通信模式所需的硬件功能。 * 该CAN控制器支持最高的通讯速率为1Mb/s;它可以自动地接收和发送CAN报文,支持使用标准ID和扩展ID的报文;外设中具有3个发送邮箱;具有2个3级深度的接收FIFO,可使用过滤功能只接收或不接收某些ID号的报文。具有双CAN,CAN1是主bxCAN,CAN2为从bxCAN。 * STM32有两组CAN控制器,其中CAN1为主设备,负责管理bxCAN和512字节的SRAM存储器之间的通信;CAN2为从设备,它不能直接访问SRAM存储器。在使用CAN2的时候必须先使能CAN1外设的时钟。 {{ :icore3l:icore3l_arm_hal_47_7.png?direct |}} * **CAN控制内核:** * 框图中标号①处的CAN控制内核包含了各种控制器及状态寄存器,通过这些寄存器可以配置CAN的参数,如波特率;请求发送报文;处理报文的接收;管理相关中断、获取诊断信息等。由于篇幅原因,这里主要讲解的是主控制器寄存器和位时序控制器。 * **主控制寄存器(CAN_MCR)** * **DBF调试冻结(DBF)** * 可设置为调试时的工作状态或者禁止收发的状态,禁止收发时仍然可以访问接收FIFO的中的数据。 * **时间触发通信模式(TTCM)** * 用于运行和禁止时间触发通信模式。在该模式下,CAN硬件的内部定时器被激活,并且产生时间戳,分别存储在CAN_RDTxR/CAN_TDTxR寄存器中。内部定时器在接收和发送的帧起始位的采样点位置被采样,并生成时间戳。 * **自动离线管理(ABOM)** * 该位决定CAN硬件在什么条件下可以退出离线状态,为“1”时,一旦硬件检测到128次11位的连续隐性位,则自动退出离线状态;为“0”时,软件对CAN_MCR寄存器的INRQ位进行置‘1’随后清‘0’后,一旦硬件检测到128次11位连续的隐性位,则退出离线状态。 * **自动唤醒(AWUM)** * CAN外设可以使用软件进入低功耗的睡眠模式,使能此功能后,当CAN检测到总线活动的时候,会自动唤醒。 * **自动重传(NART)** * 设置为“0”时,CAN硬件发送报文时会一直重传,直达成功为止;为“1”时,CAN报文只被发送一次,不管有没成功。 * **接收FIFO锁定模式(RFLM)** * 该功能用于锁定接收FIFO,锁定时,接收FIFO溢出时,会丢弃下一个接收到的报文;不锁定,则下一个接收到的报文会覆盖原报文。 * **发送FIFO优先级(TXFP)** * 当发送邮箱中有多个报文同时在等待发送时,该位控制是报文的ID来决定还是发送请求的顺序来决定。 * **CAN位时序寄存器(CAN_BTR)** * 为了方便用于调试,CAN通过设置SILM和LBKM位可以将模式设置为正常模式、静默模式、回环模式和禁止回环模式。 {{ :icore3l:icore3l_arm_hal_47_8.png?direct |}} * **CAN发送邮箱** * 在上图中的标号②是CAN外设的发送邮箱,它一共有3个发送邮箱,即可以缓存3个待发送的报文。由发送跳段根据优先级决定哪个邮箱的报文先被发送。 * 每个发送邮箱含有标记符寄存器(CAN_TIxR)、数据长度控制寄存器(CAN_TDTxR)和两个数据寄存器CAN_TDLxR、CAN_TDHxR。 * 当我们要发送报文时,把报文的各个段分解,按位置写入到这些寄存器中,并将CAN_TIxR中的发送请求寄存器位TMIDxR_TXRQ置1,即可完成发送。 * **CAN接收FIFO** * CAN外设有2个接收FIFO,每个FIFO有3个邮箱,即可以缓存6个接收到的报文。当接收到报文时,FIFO的报文计数器会自增,而STM32内部读取FIFO数据之后,报文计数器会自减,我们便可以通过状态寄存器获知报文计数器的值。 * 和发送邮箱类似,也有4个寄存器,类型也是一样的。通过中断或者状态寄存器知道接收FIFO有数据后,再读取这些寄存器的值即可把接收到的报文加载到STM32的内存中。 * **接收过滤器** * 在CAN协议中,消息的标识符与节点地址无关,但是和消息的内容有关。因此,接收节点会根据标识符的值来确定软件是否需要该消息。STM32在的CAN外设接收报文前会嫌使用接收过滤器进行检查,只接收需要的报文到FIFO中。 * CAN过滤器的寄存器有多个,可以自己看手册进行相应的配置,这里就不多讲解了。过滤的方法有两种模式分别是ID列表模式和掩码模式。 * 在本实验中,iCore3L使用XL1050作为CAN驱动,通过CAN助手发送数据并能接收数据。 * **原理图:** {{ :icore3l:icore3l_arm_hal_47_9.png?direct |}} ==== 四、实验程序 ==== 1.主函数 int main(void) { int i; HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_CAN1_Init(); can.initialize(); for(i = 0;i < 8;i++) { TxData[i] = i; } LED_GREEN_ON; while (1) { if(can.receive_ok_flag == 1) { can.receive_ok_flag = 0; HAL_CAN_AddTxMessage(&hcan1,&TxHeader,RxData,&TxMailbox); } } } 2.CAN初始化 void MX_CAN1_Init(void) { hcan1.Instance = CAN1; hcan1.Init.Prescaler = 15; hcan1.Init.Mode = CAN_MODE_NORMAL; hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; hcan1.Init.TimeSeg1 = CAN_BS1_1TQ; hcan1.Init.TimeSeg2 = CAN_BS2_1TQ; hcan1.Init.TimeTriggeredMode = DISABLE; hcan1.Init.AutoBusOff = DISABLE; hcan1.Init.AutoWakeUp = DISABLE; hcan1.Init.AutoRetransmission = DISABLE; hcan1.Init.ReceiveFifoLocked = DISABLE; hcan1.Init.TransmitFifoPriority = DISABLE; if (HAL_CAN_Init(&hcan1) != HAL_OK) { Error_Handler(); } } 3.HAL_CAN_RxFifo0MsgPendingCallback函数 void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan1) { if (HAL_CAN_GetRxMessage(hcan1, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK) { Error_Handler(); } if (HAL_CAN_ActivateNotification(hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) { /* Notification Error */ Error_Handler(); } can.receive_ok_flag = 1; } ==== 五、实验步骤 ==== - 把仿真器与iCore3L的SWD调试口相连(直接相连或者通过转接器相连); - 把iCore3L通过Micro USB线与计算机相连,为iCore3L供电; - 打开 Keil MDK 开发环境,并打开本实验工程; - 烧写程序到 iCore3L 上; - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑; - 将USBCAN设备连接到iCore3L上; - CAN 接口需要安装自带的 CANtest 测试工具(根据文件夹内安装说明安装),安装完毕后,打开并选择设备 USBCANE-U,波特率设置为 1000K,并启动。 ==== 六、实验现象 ==== 通过CAN助手,点击发送能够接收到数据说明测试通过。 {{ :icore3l:icore3l_arm_hal_47_10.png?direct |}} {{ :icore3l:icore3l_arm_hal_47_11.png?direct |}} {{ :icore3l:icore3l_arm_hal_47_12.png?direct |}} {{ :icore3l:icore3l_arm_hal_47_13.png?direct |}}