当前位置: 首页 > news >正文

细说STM32F407单片机CAN基础知识及其HAL驱动程序

目录

一、CAN总线结构和传输协议

1、 CAN总线结构

(1)闭环结构的CAN总线网络

(2)开环结构的CAN总线网络

(3)隐性电平和显性电平

2、CAN总线传输协议

(1)CAN总线传输特点

(2)位时序和波特率

1)同步段(SYNC_SEG)

2)位段1(Bit Segment 1,BS1)

3)位段2(Bit Segment 2,BS2)

3.帧的种类

4.标准格式数据帧和遥控帧

5.扩展格式数据帧和遥控帧

6.优先级法则

二、CAN外设工作原理和HAL驱动程序

1、片上CAN外设的功能概述

2、 CAN模块的基本控制

3、 CAN模块的测试模式

(1)静默模式(silent mode)

(2)回环模式(loop back mode)

(3)回环与静默组合模式(loop back combined with silent mode)

4、消息发送

5、消息接收

6、标识符筛选

(1)标识符筛选原理

1)1个32位筛选器——标识符掩码模式

2)2个32位筛选器——标识符列表模式

3)2个16位筛选器——标识符掩码模式

4)个16位筛选器——标识符列表模式

(2)函数HAL_CAN_ConfigFilter()

7、中断及处理

(1)中断和中断事件

(2)发送中断的事件源和回调函数

(3)FIFO0的中断事件源和回调函数

(4)FIFO1的中断事件源和回调函数

(5)状态改变或错误的中断事件源和回调函数


        CAN是控制器区域网络(Controller Area Network)的缩写。CAN总线是一种适用于工业设备的高性能总线网络。STM32F407有2个CAN控制器,开发板上有2个CAN收发器,可以进行CAN总线网络的通信试验。本文使用旺宝红龙STM32F407ZGT6 KIT V1.0开发板。

        CAN的高性能和可靠性已被普遍认可,并被广泛应用于船舶、医疗设备、工业设备等方面,特别是在汽车的控制方面,已经成为汽车网络的标准协议。 

一、CAN总线结构和传输协议

        作为一种串行通信总线,如同I2C总线协议一样,CAN总线也有物理层定义和传输协议定义。

1、 CAN总线结构

        CAN总线网络的结构有闭环和开环两种形式

(1)闭环结构的CAN总线网络

        总线两端各连接一个120Ω的电阻,两根信号线形成回路。这种CAN总线网络由ISO 11898标准定义,是高速、短距离的CAN网络,通信速率为125kbit/s到1Mbit/s。在1Mbit/s通信速率时,总线最长达40m。

 

(2)开环结构的CAN总线网络

        两根信号线独立,各自串联一个2.2k的电阻。这种CAN总线网路由ISO11519-2标准定义,是低速、远距离的CAN网络,通信速率最高为125kbit/s。

 

(3)隐性电平和显性电平

        CAN总线只有两根信号线CANH和CANL,没有时钟同步信号。所以CAN是一种异步通信方式,与UART的异步通信方式类似,而SPI、I2C是以时钟信号同步的同步通信方式。

       CAN总线的两根信号线通常采用双绞线,传输的是差分信号,通过两根信号线的电压差CANH-CANL来表示总线电平。以差分信号传输信息具有抗干扰能力强,能有效抑制外部电磁干扰等优点,这也是CAN总线在工业上应用广泛的一个原因。使用差分信号表示总线电平的还有RS485网络,也是一种常用的工业现场总线。

        两根信号线的电压差CANH-CANL表示CAN总线的电平,与传输的逻辑信号1或0对应。对应于逻辑1的称为隐性(Recessive)电平,对应于逻辑0的称为显性(Dominant)电平。对应于逻辑1和逻辑0,开环结构和闭环结构CAN网络的CANH和CANL的电压值不一样,隐性电平和显性电平的电压值也不一样。

典型电压

C A N  

闭环(高速)

开环(低速)

隐性(逻辑1)

显性(逻辑0 )

隐性(逻辑1)

显性(逻辑0)

CANH/V

2.5

3.5

1.75

4.0

CANL/V

2.5

1.5

3.25

1.0

CANH-CANL/V

0

2.0

-1.5

3.0

        在CAN总线网络中,CAN总线上的一个终端设备称为一个节点(Node),在CAN网络中,没有主设备和从设备的区别。一个CAN节点的硬件部分一般由CAN控制器和CAN收发器两个部分组成。CAN控制器负责CAN总线的逻辑控制,实现CAN传输协议;CAN收发器主要负责MCU逻辑电平与CAN总线电平之间的转换。

        CAN控制器一般是MCU的片上外设,例如,STM32F407有两个CAN控制器。CAN收发器一般是单独的芯片,并且根据CAN总线的结构不同,需要使用不同的CAN收发器芯片,例如,旺宝红龙STM32F407ZGT6 KIT V1.0开发板上使用的CAN收发器芯片是SN65HVD230,只能构成闭环网络结构

2、CAN总线传输协议

(1)CAN总线传输特点

        CAN总线的数据传输有其自身的特点,主要有以下几点。

  • CAN总线上的节点既可以发送数据又可以接收数据,没有主从之分。但是在同一个时刻,只能有一个节点发送数据,其他节点只能接收数据。
  • CAN总线上的节点没有地址的概念。CAN总线上的数据是以帧为单位传输的,帧又分为数据帧、遥控帧等多种帧类型,帧包含需要传输的数据或控制信息。
  • CAN总线具有"线与"的特性,也就是当有两个节点同时向总线发送信号时,一个发送显性电平(逻辑0),另一个发送隐性电平(逻辑1),则总线呈现为显性电平。这个特性被用于总线仲裁,也就是哪个节点优先占用总线进行发送操作。
  • 每个帧有一个标识符(Identifier,以下简称ID)。ID不是地址,它表示传输数据的类型,也可以用于总线仲裁时确定优先级。例如,在汽车的CAN总线上,假设用于碰撞检测的节点输出数据帧的ID为01,车内温度检测节点发送数据帧的ID为05等。
  • 每个CAN节点都接收数据,但是可以对接收的帧根据ID进行过滤。只有节点需要的数据才会被接收并进一步处理,不需要的数据会被自动舍弃。例如,假设安全气囊控制器只接受碰撞检测节点发出的ID为01的帧,这种ID的过滤是由硬件完成的,以便安全气囊控制器在发生碰撞时能及时响应。
  • CAN总线通信是半双工的,即总线不能同时发送和接收。在多个节点竞争总线进行发送时,通过ID的优先级进行仲裁,竞争胜出的节点继续发送,竞争失败的节点立刻转入接收状态。
  • CAN总线没有用于同步的时钟信号,所以需要规定CAN总线通信的波特率,所有节点都使用相同的波特率进行通信。

(2)位时序和波特率

        一个CAN网络需要规定一个通信的波特率,各节点都以相同的波特率进行数据通信。位时序指的是一个节点采集CAN总线上的一个位数据的时序,通过位时序的控制,CAN总线可以进行位同步,以吸收节点时钟差异产生的波特率误差,保证接收数据的准确性。 

        图中的标称位时间(Nominal Bit Time,NBT)指的是传输一个位数据的时间,用于确定CAN总线的波特率。这个时间被分成了3段。

1)同步段(SYNC_SEG)

        在这个时间段内,总线上应该发生一次位信号的跳变。如果节点在同步段检测到总线上的一个跳变沿,就表示节点与总线是同步的。同步段长度固定为1个tq。

        tq(time quantum [ˈkwɑ:ntəm])被称为时间片,tq由CAN控制器的时钟频率f_{CAN}决定。在STM32F407中,两个CAN控制器在APB1总线上,CAN控制器有预分频器,APB1总线的时钟信号PCLK1经分频后得到f_{CAN}

2)位段1(Bit Segment 1,BS1)

        定义了采样点的位置。在BS1结束的时间点对总线采样,得到的电平就是这个位的电平。BS1的初始长度是1到16个tq,但它的长度可以在再同步(resynchronization)的时候被自动加长,以补偿各节点频率差异导致的正相位漂移。

3)位段2(Bit Segment 2,BS2)

        定义了发送点的位置。BS2的初始长度是1到8个tq,再同步时可以被自动缩短,以补偿负相位漂移。

        CAN控制器可以自动对位时序进行再同步,再同步时自动调整BS1和BS2的长度,位段加长或缩短的上限称为再同步跳转宽度(Resynchronization Jump Width,SJW),SJW的取值是1到4个tq。

CAN总线的波特率就由标称位时间长度NBT决定,而NBT是位时序3个段的时间长度和,即

NBT=(1+m+n)×tq。
Baudrate=1/NBT

3.帧的种类

        CAN网络通信是通过5种类型的帧(frame)进行的,这5种帧及其用途如表:

帧类型

帧用途

数据帧(Data frame)

节点发送的包含ID和数据的帧

遥控帧(Remote frame)

节点向网络上的其他节点发出的某个ID的数据请求,发送节点收
到遥控帧后就可以发送相应ID的数据帧

错误帧(Error frame)

节点检测出错误时,向其他节点发送的通知错误的帧

过载帧(Overload frame)

接收单元未做好接收数据的准备时发送的帧,发送节点收到过载帧
后可以暂缓发送数据帧

帧间空间(Inter-frame space)

用于将数据帧、遥控帧与前后的帧分隔开的帧

        其中,数据帧和遥控帧有ID,并且有标准格式和扩展格式两种格式,标准格式的ID是11位,扩展格式的ID是29位。

4.标准格式数据帧和遥控帧

        标准格式数据帧和遥控帧的结构如下图所示,它们都有11位的ID。数据帧传输带有ID的0到8字节的数据;遥控帧只有ID,没有数据,用于请求数据。

数据帧可以分为以下几段。

  • 帧起始(Start Of Frame,SOF)。帧起始只有一个位,是一个显性电平(逻辑0),表示一个帧的开始。
  • 仲裁段(Arbitration Field)。仲裁段包括11位的ID和RTR位,共12位。多个节点竞争总线发送数据时,根据仲裁段的数据决定哪个节点优先占用总线。哪个ID先出现显性电平(逻辑0),对应的节点就占用总线。所以,ID数值小的优先级更高。如果两个节点发送数据帧的ID相同,再根据仲裁段最后的RTR位裁决。RTR(Remote Transmit Request)是远程传输请求,RTR位用于区分数据帧和遥控帧。数据帧的RTR位是显性电平(逻辑0),遥控帧的RTR位是隐性电平(逻辑1)。所以,具有相同ID的数据帧和遥控帧竞争总线时,数据帧优先级更高。 
  • 控制段。控制段包括IDE位、RB0位和4位的DLC,共6位。IDE是标识符扩展位(Identifier Extension Bit),用于表示帧是标准格式,还是扩展格式。标准格式帧的IDE是显性电平(逻辑0),扩展格式帧的IDE是隐性电平(逻辑1)。RB0是保留位,默认为显性电平。DLC是4个位的数据长度编码(Data Length Code),编码数值为0到8,表示后面数据段的字节数。遥控帧的DLC编码数值总是0,因为遥控帧不传输数据。
  • 数据段。数据段里是数据帧需要传输的数据,可以是0到8字节,数据的字节个数由DLC编码确定。遥控帧没有数据段。
  • CRC段。CRC段共16位,其中前15位是CRC校验码,最后一位总是隐性电平,是CRC段的界定符(Delimiter)。
  • ACK段。ACK段包括一个ACK位(Acknowledge Bit)和一个ACK段界定符。发送节点发送的ACK位是隐性电平,接收节点接收的ACK位是显性电平。
  • 帧结束(End Of Frame,EOF)。帧结束是帧结束段,由7个隐性位表示EOF。数据帧或遥控帧结束后,后面一般是帧间空间或过载帧,用于分隔开数据帧或遥控帧。

5.扩展格式数据帧和遥控帧

        扩展格式数据帧和遥控帧的结构如下图。扩展格式的ID总共是29位,扩展格式帧与标准格式帧的差异在于仲裁段和控制段。

  • 仲裁段。扩展格式数据帧的仲裁段总共32位,包括11位标准ID、SRR位、IDE位、18位扩展ID、RTR位。SRR位(Substitute Remote Request Bit)只存在于扩展格式帧中,用于替代标准格式帧中的RTR位。SRR位总是隐性电平,相当于是一个占位符,真正的RTR位在仲裁段的最后一位。RTR位还是用于区分数据帧和遥控帧。扩展格式帧中的IDE位总是隐性电平,表示这是扩展格式的帧。
  • 控制段。控制段由RB1位、RB0位和4位DLC组成。RB1位和RB0位是保留位,总是显性电平。4位的DLC编码表示数据的长度,从0到8字节。

6.优先级法则

        数据帧和遥控帧的仲裁段用于多个节点竞争总线时进行仲裁,优先级高的帧获得在总线上发送数据的权利。优先级的确认总结为以下几条法则。

  • 在总线空闲时,最先开始发送消息的节点获得发送权。
  • 多个节点同时开始发送时,从仲裁段的第一位开始进行仲裁,第一次出现各节点的位电平互异时,输出显性电平的节点获得发送权。
  • 相同ID和格式的数据帧和遥控帧,数据帧具有更高优先级,因为数据帧的RTR位是显性电平,而遥控帧的RTR位是隐性电平。
  • 对于11位标准ID相同的标准数据帧和扩展数据帧,标准数据帧具有更高的优先级,因为标准数据帧的IDE位是显性电平,而扩展数据帧的IDE位是隐性电平。

二、CAN外设工作原理和HAL驱动程序

1、片上CAN外设的功能概述

        STM32F4系列器件上有两个基本扩展CAN,支持2.0A和2.0B的CAN协议。两个CAN外设是CAN1和CAN2,称它们为CAN模块。

        STM32F4系列器件的两个CAN模块的结构如图所示。CAN1是带有512字节SRAM的主CAN控制器,CAN2无法直接访问SRAM存储器,是从CAN控制器。两个CAN控制器共享512字节SRAM

        STM32F4的CAN外设的主要特点如下:

  • 波特率最高为1Mbit/s。
  • 每个CAN模块有3个发送邮箱,可自动重发。
  • 具有16位自由运行的定时器,可以定时触发通信,可以在最后两个数据字节发送时间戳。
  • 每个CAN模块有两个FIFO单元,每个FIFO有3个接收邮箱,每个FIFO有独立的中断地址。
  • 两个CAN模块共用28个筛选器组,筛选器用于配置可接收ID列表或掩码。数据帧和遥控帧根据ID被筛选,只有通过筛选的帧才进入接收邮箱。帧的筛选完全由硬件完成,减少处理器的负担。

        STM32F4系列MCU上的CAN模块只是CAN控制器,要构成一个CAN节点,MCU还需要外接一个CAN收发器芯片,实现MCU逻辑电平到CAN总线物理层的电平转换和控制。

2、 CAN模块的基本控制

        CAN模块有3种主要的工作模式:初始化、正常和睡眠。硬件复位后,CAN模块处于睡眠模式;在初始化模式下,可以对CAN模块进行初始化设置;在正常模式下,可以进行数据的接收与发送。通过配置CAN主控制寄存器CAN_MCR的SLEEP、INRQ等位,用户可以实现在3种工作模式之间的转换。

        HAL驱动程序中用于CAN模块初始化、工作模式转换、启动和停止的函数如下表:

函数名

功能描述

HAL_CAN_Init()

CAN模块初始化,主要是配置CAN总线通信参数

HAL_CAN_MspInit()

CAN模块初始化MSP弱函数,在HAL_CAN_Init()里被调用。需要用户
程序重新实现,用于引脚GPIO配置,中断优先级配置

HAL_CAN_Start()

启动CAN模块

HAL_CAN_Stop()

停止CAN模块,允许重新访问配置寄存器

HAL_CAN_RequestSleep()

使CAN模块在完成当前操作后进入睡眠模式

HAL_CAN_WakeUp()

将CAN模块从睡眠模式唤醒

HAL_CAN_IsSleepActive()

查询CAN模块是否处于睡眠模式,返回值为1表示模块处于睡眠模式

        CAN模块的初始化函数是HAL_CAN_Init(),其原型定义如下:

HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef *hcan);

        其中,hcan是CAN_HandleTypeDef结构体类型指针,是CAN模块对象指针。       

        CAN_HandleTypeDef的成员变量Init是结构体类型CAN_InitTypeDef,用于存储CAN通信参数。在CubeMX生成的代码中,会为启用的CAN模块定义外设对象变量,例如:

CAN_HandleTypeDef hcan1;	//表示CAN1的外设对象变量

         其他函数的原型定义如下:

void HAL_CAN_MspInit(CAN_HandleTypeDef *hcan);				//MSP初始化函数
HAL_StatusTypeDef HAL_CAN_Start(CAN_HandleTypeDef *hcan);	//启动CAN模块
HAL_StatusTypeDef HAL_CAN_Stop(CAN_HandleTypeDef *hcan);	//停止CAN模块
HAL_StatusTypeDef HAL_CAN_Requestsleep(CAN_HandleTypeDef *hcan);	//进入睡眠模式
HAL_StatusTypeDef HAL_CAN_WakeUp(CAN_HandleTypeDef *hcan);	//从睡眠模式唤醒
uint32_t HAL_CAN_IsSleepActive(CAN_HandleTypeDef *hcan);	//返回1表示模块处于睡眠模式

        一个CAN模块需要先用函数HAL_CAN_Init()进行外设初始化,模块处于初始化模式,可以进行筛选器组的配置。执行函数HAL_CAN_Start()启动CAN模块进入正常模式,模块可以在正常模式和睡眠模式之间切换。执行HAL_CAN_Stop()将停止CAN模块。

3、 CAN模块的测试模式

        在对CAN模块进行初始化设置时,通过设置位时序寄存器CAN_BTR的SILM和LBKM位,可以使CAN模块进入测试模式。在测试模式下,我们将主控制寄存器CAN_MCR中的INRQ位复位,可以进入正常模式。要进入测试模式,必须在CAN模块初始化时进行设置。在测试模式下,CAN模块可以自发自收,以测试CAN模块的功能是否正常。CAN模块的3种测试模式如图:

(1)静默模式(silent mode)

        在静默模式下,CAN模块可以接收有效的数据帧和遥控帧,但是只能向总线发送隐性位,发送的显性位都被自己接收,所以在静默模式下,CAN模块无法启动发送操作。这种模式一般用于监测总线流量。 

(2)回环模式(loop back mode)

        在回环模式下,CAN模块可以正常地向总线发送数据,但不能接收总线上的数据,只能接收自己发送的数据(需要通过筛选规则)。这种模式可用于自检测试。为了不受外部事件的影响,CAN内核在此模式下不会对数据帧或遥控帧的ACK段采样,这样可以忽略ACK错误。

(3)回环与静默组合模式(loop back combined with silent mode)

        这是回环与静默模式的组合,可用于“热自检”。在这种模式下,CAN模块不能接收总线上的数据,只能接收自己发送的数据;只能向总线上发送隐性位,因而不会影响CAN总线。

        使CAN模块进入某种测试模式是在初始化函数HAL_CAN_Init()中,通过设置CAN模块的属性实现的,在示例代码里会具体介绍。

4、消息发送

        一个CAN模块有3个发送邮箱。发送数据时,用户需要选择一个空闲的发送邮箱,将标识符ID、数据长度和数据(最多8字节)写入邮箱,然后CAN模块会自动控制将邮箱内的数据发送出去。

        用户可以设置自动重发,也就是在出现错误后自动重发,直到成功发送出去。如果禁止自动重发,则发送失败后不再重发,会通过发送状态寄存器CAN_TSR相应的位指示错误原因,如仲裁丢失或发送错误。

        用户可以终止邮箱数据的发送,终止发送后邮箱会变成空闲状态。

        用户可以设置时间触发通信模式(time triggered communication mode)。在此模式下,会激活CAN模块内部的一个硬件计数器,CAN总线每收发一个位数据,计数器都会递增。在发送或接收时,在帧的起始位时刻捕获计数值,作为发送或接收数据帧的时间戳数据。在CAN的HAL驱动程序中,与发送消息相关的函数如表:

函数名

功能描述

HAL_CAN_GetTxMailboxesFreeLevel()

查询空闲的发送邮箱个数,空闲邮箱个数大于0时就可以发送

HAL_CAN_AddTxMessage()

向一个邮箱写入一条消息,由CAN模块自动控制邮箱内消息
的发送

HAL_CAN_AbortTxRequest()

中止发送一个被挂起(等待发送)的消息

HAL_CAN_IsTxMessagePending()

判断一个消息是否在等待发送

HAL_CAN_GetTxTimestamp()

如果使用了时间触发通信模式,此函数读取发送消息的时间戳

        函数HAL_CAN_GetTxMailboxesFreeLevel()用于查询一个CAN模块空闲的发送邮箱个数,如果有空闲的发送邮箱,就可以使用函数HAL_CAN_AddTxMessage()向发送邮箱写入一条消息,然后由CAN模块启动发送过程。这个函数只能发送数据帧或遥控帧,其函数原型定义如下:

HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan,CAN_TxHeaderTypeDef*pHeader,uint8_t aData[],uint32_t *pTxMailbox)

        其中,参数hcan是CAN模块外设对象指针;参数pHeader是CAN_TxHeaderTypeDef结构体类型指针,定义了消息的一些参数;aData是发送数据的数组,最多8字节的数据;参数pTxMailbox用于返回实际使用的发送邮箱号。

        结构体CAN_TxHeaderTypeDef用于定义消息的一些参数,用于CAN模块组装成数据帧,该结构体完整定义如下:

typedef struct
{uint32_t StdId;	//11位的标准标识符,设置范围是0~0x7FFuint32_t ExtId;	//29位的扩展标识符,设置范围是0~0x1FFFFFFFuint32_t IDE;	//帧格式类型,标准ID(CAN_ID_STD)或扩展ID(CAN_ID_EXT)uint32_t RTR;	//RTR位,消息类型:数据帧(CAN_RTR_DATA)或遥控帧(CAN_RTR_REMOTE)uint32_t DLC;	//数据字节数,最多8字节,设置范围是0~8FunctionalState TransmitGlobalTime;	//是否使用时间戳,取值ENABLE或DISABLE
}CAN_TxHeaderTypeDef;

        其中,成员变量IDE表示帧格式类型,有两个宏定义表示标准ID和扩展ID。

#define CAN_ID_STD (0x00000000U) //标准ID
#define CAN_ID_EXT (0x00000004U) //扩展ID

        成员变量RTR表示消息类型,只能是数据帧或遥控帧,有两个宏定义用于此变量的取值。

#define CAN_RTR_DATA     (0x00000000U) //数据帧
#define CAN_RTR_REMOTE   (0x00000002U) //遥控帧

        CAN模块发送数据是将消息写入模块的发送邮箱,然后由CAN控制器将邮箱内的消息发送出去。CAN模块发送消息只有HAL_CAN_AddTxMessage()这一个函数,不像串口、SPI等其他外设有中断模式、DMA方式的专用函数。

        将消息写入邮箱后,可以用函数HAL_CAN_IsTxMessagePending(查询邮箱里的消息是否发送出去了,这个函数的原型定义是:

uint32_t HAL_CAN_IsTxMessagePending(CAN_HandleTypeDef *hcan,uint32_t TxMailboxes);

        其中,参数TxMailboxes是发送邮箱号。函数返回值如果是0,则表示没有等待发送的消息,也就是消息已经被发送出去了;如果返回值为1,则表示邮箱里的消息仍然在等待发送。CAN总线上可能有很多个节点,需要通过总线仲裁获得CAN总线使用权之后,节点才能将邮箱里的消息发送出去。

        CAN模块也有表示消息发送出去的中断事件,如果打开了相应的中断事件使能控制位,也可以在中断里做出响应。在后面会专门介绍CAN的中断。

5、消息接收

        每个CAN模块有两个接收FIFO(Receive FIFO),每个FIFO有3个邮箱。FIFO完全由硬件管理,当有邮箱接收到有效消息时,就会产生相应的事件中断标志,可以产生CAN RX硬件中断。FIFO0和FIFO1有各自的中断地址。从邮箱中读出消息后,邮箱就自动释放。如果一个FIFO的3个邮箱都接收到消息而没有及时读出,再有消息进入时就会产生上溢。根据是否设置FIFO锁定,有两种处理情况。

  • 如果禁止FIFO锁定,则新传入的消息会覆盖FIFO中存储的最后一条消息。
  • 如果启用FIFO锁定,则新传入的消息会被舍弃。

        用户可以通过轮询方式或中断方式读取接收邮箱中的消息。CAN模块接收消息的相关函数如表:

函数名

功能描述

HAL_CAN_GetRxFifoFillLevel()

查询一个FIFO中存在未读消息的邮箱个数

HAL_CAN_GetRxMessage()

读取一个接收邮箱中的消息

        函数HAL_CAN_GetRxFifoFillLevel()用于查询某个FIF()存在未读消息的邮箱个数,函数原型定义如下:

uint32_t HAL_CAN_GetRxFifoFillLevel(CAN_HandleTypeDef *hcan,uint32_t RxFifo)

        其中,参数RxFifo是FIFO编号,一个CAN模块有两个FIFO,可使用如下的两个宏作为此参数的取值。

#define CAN_RX_FIFO0(0x00000000U) //CAN模块FIFO0
#define CAN_RX_FIFO1(0x00000001U) //CAN模块FIFO1

        如果查询到有未读取的消息,就用函数HAL_CAN_GetRxMessage(读取接收的消息,此函数的原型定义如下:

HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan,uint32_t RxFifo,CAN_RxHeaderTypeDef *pHeader,uint8_t aData[])

        其中,参数RxFifo是FIFO编号,用宏CAN_RX_FIFO0和CAN_RX_FIFO1分别表示FIFO0和FIFO1;参数pHeader是CAN_RxHeaderTypeDef结构体类型指针,记录了帧的一些信息;aData[]是接收数据的数组,最多8字节。

        记录帧信息的结构体CAN_RxHeaderTypeDef的定义如下:

typedef struct
{uint32_t StdId;		//11位的标准标识符,范围是0~0x7FFuint32_t ExtId;		//29位的扩展标识符,范围是0~0x1FFFFFFFuint32_t IDE;		//帧格式类型,标准ID(CAN_ID_STD)或扩展ID(CAN_ID_EXT)uint32_t RTR;		//RTR位,消息类型:数据帧或遥控帧uint32_t DLC;		//数据字节数,最多8字节uint32_t Timestamp;	//时间戳数据,数值范围是0~0xFFFEuint32_t FilterMatchIndex;	//匹配的筛选器索引
}CAN_RxHeaderTypeDef;

        结构体CAN_RxHeaderTypeDef的部分成员变量与结构CAN_TxHeaderTypeDef的相同,只有后面两个成员变量CAN_RxHeaderTypeDef特有的。

6、标识符筛选

(1)标识符筛选原理

        在CAN网络中,发送节点是以广播方式发送消息的,所有CAN节点都可以收到消息。数据帧和遥控帧带有标识符,标识符一般表示了消息的类型。一个CAN节点一般只对特定的消息感兴趣,如果用软件对接收的帧ID进行判别,将消耗接收节点的大量CPU时间。STM32F4的两个CAN控制器有28个共用的标识符筛选器组(Filter Bank),可以完全用硬件方式对接收的帧ID进行筛选,只允许符合条件的帧进入接收邮箱,自动放弃不符合条件的帧。

        每个筛选器组包含两个32位寄存器,分别是CAN_FxR1和CAN_FxR2。这两个寄存器可以被配置为两个32位长度筛选器或4个16位长度筛选器,筛选器可以是掩码模式或列表模式,所以一个筛选器组有4种配置模式:

 

1)1个32位筛选器——标识符掩码模式

        在这种模式下,寄存器CAN_FxR1存储一个32位ID,这个ID与11位标准ID(STID[10:0])、18位扩展ID(EXID[17:0])、IDE位、RTR位的位置对应关系如图中所示。IDE为0时表示标准格式帧,否则表示扩展格式帧。

        CAN_FxR2存储一个32位掩码,如果掩码为1,则表示该位必须与ID中的位一致,如果为0,则表示不用一致。

        例如,如果让一个CAN节点只接收标准ID为奇数的标准格式数据帧,则设置寄存器CAN_FxR1表示的ID时,STID[0]位必须设置为1,IDE位必须设置为0(表示标准格式帧),RTR位必须设置为0(表示数据帧)。设置寄存器CAN_FxR2表示的掩码时,对应的这些位必须设置为1,其他位设置为0。

映射

STID[10:3]

STID[2:0]

EXID[17:13]

EXID[12:5]

EXID[4:0]

I

D

E

R

T

R

0

ID

×

×

×

×

×

×

×

×

×

×

1

×

×

×

×

×

×

×

×

×

×

×

×

×

×

×

×

×

×

0

0

0

掩码

0

0

0

0

0

0

0

0

0

0

1

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

1

1

1

2)2个32位筛选器——标识符列表模式

        在这种模式下,寄存器CAN_FxR1和CAN_FxR2各存储一个32位ID,ID的组成与模式(1)相同。只有匹配这两个ID的帧才能通过筛选。

3)2个16位筛选器——标识符掩码模式

        在这种模式下,寄存器CAN_FxR1的高16位组成一个ID,低16位组成一个掩码;寄存器CAN_FxR2的高16位组成一个ID,低16位组成一个掩码。

4)个16位筛选器——标识符列表模式

        在这种模式下,寄存器CAN_FxR1表示2个16位ID,寄存器CAN_FxR2表示2个16位ID。用户可以为一个FIFO设置多个筛选器组,但是一个筛选器组只能配置给一个FIFO。如果为FIFO设置了筛选器,并且接收的帧与所有筛选器都不匹配,那么该帧会被丢弃。只要通过了一个筛选器,帧就会被存入接收邮箱。

(2)函数HAL_CAN_ConfigFilter()

        函数HAL_CAN_ConfigFilter()用于设置CAN模块的标识符筛选器,应该在执行HAL_CAN_Start()启动一个CAN模块之前调用这个函数。其原型定义如下:

HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan,CAN_FilterTypeDef *sFilterConfig)

        其中,参数sFilterConfig是结构体CAN_FilterTypeDef类型指针,它保存了筛选器的设置。这个结构体定义如下:

typedef struct
{uint32_t FilterIdHigh;		//CAN_FxR1寄存器的高16位,取值范围为0~0xFFFFuint32_t FilterIdLow;		//CAN_FxR1寄存器的低16位,取值范围为0~0xFFFEuint32_t FilterMaskIdHigh;	//CAN_FxR2寄存器的高16位,取值范围为0~0xFFFFuint32_t FilterMaskIdLow;	//CAN_FxR2寄存器的低16位,取值范围为0~0xFFFF/*筛选器应用于哪个FIFO,使用宏CAN_FILTER_FIFO0或CAN_FILTER_FIFO1 */uint32_t FilterFIFOAssignment;/*筛选器组编号,具有双CAN模块的MCU有28个筛选器组,编号范围为0~27*/uint32_t FilterBank;/*筛选器模式,ID掩码模式(CAN_FILTERMODE_IDMASK)或ID列表模式(CAN_FILTERMODE_IDLIST)*/uint32_t FilterMode;/*筛选器长度,即32位(CAN_FILTERSCALE_32BIT)或16位(CAN_FILTERSCALE_16BIT)*/uint32_t FilterScale;uint32_t FilterActivation;		//是否启用此筛选器,ENABLE或者DISABLEuint32_t SlaveStartFilterBank;	//设置应用于从CAN控制器的筛选器的起始编号
}CAN_FilterTypeDef;

        某些变量的取值具有相应的宏定义,例如,FilterMode是筛选器模式,有两个宏定义可用于此变量的取值,宏定义如下:

#define CAN_FILTERMODE_IDMASK	(0x00000000U)	//ID掩码模式
#define CAN_FILTERMODE_IDLIST	(0×00000001U)	//ID列表模式

        总之,筛选器的设置是CAN模块使用中比较复杂的环节

7、中断及处理

(1)中断和中断事件

        一个CAN模块有4个中断,对应4个ISR。例如,CAN1的4个中断及其ISR。

中断名称

中断中文名称

说明

ISR名称

CAN1_TX

发送中断

任何一个发送邮箱发送完成时产生的中断

CAN1_TX_IRQHandler()

CAN1_RX0

FIFO0接收中断

FIFO0接收消息、满或上溢时产生的中断

CAN1_RX0_IRQHandler()

CAN1_RX1

FIFO1接收中断

FIFO1接收消息、满或上溢时产生的中断

CAN1_RX1_IRQHandler()

CAN1_SCE

状态改变和错误
中断

状态改变或发生错误时产生的中断

CAN1_SCE_IRQHandler()

        每个中断又有1个或多个中断事件源,HAL驱动程序中为每个中断事件源定义了中断类型宏定义,也就是中断事件使能控制位的宏定义。例如,CAN1_TX只有一个中断事件源,为其定义中断事件类型的宏定义如下:

#define CAN_IT_TX_MAILBOX_EMPTY  ((uint32_t)CAN_IER_TMEIE)

        HAL驱动程序中有两个宏函数可以开启或禁止某个具体的中断事件源。

__HAL_CAN_ENABLE_IT(__HANDLE__,__INTERRUPT__) //开启某个中断事件源__HAL_CAN_DISABLE_IT(__HANDLE__,__INTERRUPT__) //禁用某个中断事件源

        其中,_HANDLE_是CAN模块对象指针,__INTERRUPT__是表示中断事件类型的宏,例如CAN_IT_TX_MAILBOX_EMPTY。

        在CubeMX为CAN模块的4个硬件中断生成的ISR中,都调用了函数HAL_CAN_IRQHandler(),这是CAN中断处理通用函数。函数HAL_CAN_IRQHandler()会根据中断使能寄存器、中断标志寄存器的内容判断具体发生了哪个中断事件,再调用相应的回调函数。CAN的HAL驱动程序中为常用的中断事件定义了回调函数,只要搞清楚中断事件与回调函数的对应关系,编程时重新实现关联的回调函数,就可以对某个中断事件做出处理。

(2)发送中断的事件源和回调函数

        发送中断(CAN1_TX)只有一个中断事件源CAN_IT_TX_MAILBOX_EMPTY,在3个发送邮箱中任何一个发送完成时都产生该事件中断,但是3个邮箱有各自的回调函数:

中断事件类型宏

中断事件说明

回调函数

CAN_IT_TX_MAILBOX_EMPTY

邮箱0发送完成

HAL_CAN_TxMailbox0CompleteCallback()

邮箱1发送完成

HAL_CAN_TxMailbox1CompleteCallback()

邮箱2发送完成

HAL_CAN_TxMailbox2CompleteCallback()

        另外,调用函数HAL_CAN_AbortTxRequestO中止某个邮箱的发送后,也会调用相应的回调函数,只是这几个回调函数不是由中断引起的,而是由函数HAL_CAN_AbortTxRequest()引起的。

(3)FIFO0的中断事件源和回调函数

        FIFO0接收中断(CAN1_RX0)是在FIFO0接收消息、满或上溢时触发的中断。这个中断有3个中断事件源,对应的回调函数如表所示:

中断事件类型宏

中断事件说明

回调函数

CAN_IT_RX_FIFO0_MSG_PENDING

FIFO0接收新消息

HAL_CAN_RxFifo0MsgPendingCallback()

CAN_IT_RX_FIFO0_FULL

FIFO0满

HAL_CAN_RxFifo0FullCallback()

CAN_IT_RX_FIFO0_OVERRUN

FIFO0发生上溢

_

         其中,接收新消息的中断事件是比较有用的,因为CAN模块接收消息一般是使用中断方式。

(4)FIFO1的中断事件源和回调函数

        FIFO1接收中断(CAN1_RX1)是在FIFO1接收消息、满或上溢时触发的中断。这个中断也有3个中断事件源,对应的回调函数如表所示:

中断事件类型宏

中断事件说明

回调函数

CAN_IT_RX_FIFO1_MSG_PENDING

FIFO1接收新消息

HAL_CAN_RxFifo1MsgPendingCallback()

CAN_IT_RX_FIFO1_FULL

FIFO1满

HAL_CAN_RxFifolFullCallback()

CAN_IT_RX_FIFO1_OVERRUN

FIFO1发生上溢

——

(5)状态改变或错误的中断事件源和回调函数

        状态改变或错误中断(CAN1_SCE)在CAN模块发生状态改变或错误时触发,例如,CAN模块进入睡眠状态或从睡眠状态被唤醒,或出现总线错误等。CAN1_SCE的中断事件源和回调函数如表所示:

中断事件宏定义

中断事件说明

回调函数

CAN_IT_SLEEP_ACK

CAN模块进入睡眠状态

HAL_CAN_SleepCallback()

CAN_IT_WAKEUP

监测到消息,被唤醒

HAL_CAN_WakeUpFromRxMsgCallback()

CAN_IT_ERROR
CAN_IT_BUSOFF等多种

有多种错误事件源,通过错
误状态寄存器CAN_ESR的
内容判断具体错误类型

HAL_CAN_ErrorCallback()

相关文章:

细说STM32F407单片机CAN基础知识及其HAL驱动程序

目录 一、CAN总线结构和传输协议 1、 CAN总线结构 (1)闭环结构的CAN总线网络 (2)开环结构的CAN总线网络 (3)隐性电平和显性电平 2、CAN总线传输协议 (1)CAN总线传输特点 &am…...

Ubuntu 22.04 升级 24.04 问题记录

一台闲置笔记本使用的 ubuntu 还是 18.04,最近重新使用,发现版本过低,决定升级,于是完成了 18.04 -> 20.04 -> 22. 04 -> 24.04 的三连跳。 一、升级过程中黑屏 主要问题是在 22.04 升级到 24.04 过程中出现了黑屏仅剩…...

模型选择+过拟合欠拟合

训练误差和泛化误差 训练误差:模型在训练数据上的误差 泛化误差:模型在新数据上的误差 验证数据集:一个用来评估模型好坏的数据集 例如拿出50%的数据作为训练 测试数据集:只能用一次 K则交叉验证 在没有足够数据时使用 算法…...

Leetcode 3404. Count Special Subsequences

Leetcode 3404. Count Special Subsequences 1. 解题思路2. 代码实现 题目链接:3404. Count Special Subsequences 1. 解题思路 这道题是事实上这次的周赛最难的一道题目,不过也是有点巧思在内。 最开始我的想法就是按照乘积构成pair,然后…...

萌萌哒的八戒

萌萌哒的八戒 下载压缩包后,打开发现有一张照片 既然是关于猪的,那就用猪圈密码解码 flag{whenthepigwanttoeat}...

开启家具组装新方式:产品说明书智能指导

在快节奏的现代生活中,人们越来越追求便捷与高效。无论是新房装修还是家具换新,家具组装已成为许多家庭不可避免的一项任务。然而,面对复杂多变的家具图纸和冗长的产品说明书,许多人常常感到无从下手,甚至因操作不当而…...

【连续学习之ResCL算法】2020年AAAI会议论文:Residual continual learning

1 介绍 年份:2020 会议: AAAI Lee J, Joo D, Hong H G, et al. Residual continual learning[C]//Proceedings of the AAAI Conference on Artificial Intelligence. 2020, 34(04): 4553-4560. 本文提出的算法是Residual Continual Learning (ResC…...

【网络协议】路由信息协议 (RIP)

未经许可,不得转载。 路由信息协议(Routing Information Protocol,简称 RIP)是一种使用跳数(hop count)作为路由度量标准的路由协议,用于确定源网络和目标网络之间的最佳路径。 文章目录 什么是…...

Linux 终端查看 nvidia 显卡型号

文章目录 写在前面1. 需求描述2. 实现方法方法一:方法二方法三: 参考链接 写在前面 自己的测试环境: Ubuntu20.04 1. 需求描述 Linux 终端查看 nvidia 显卡型号 2. 实现方法 方法一: 执行下列指令: sudo update…...

基于neurokit2的心电仿真数据生成实例解析

一 概念 NeuroKit2是一个开源的、社区驱动的、以用户为中心的Python库,可用于多种生理信号的分析处理(例如ECG、PPG、EDA、EMG、RSP),还包括用于特定处理步骤(如频率)的工具提取和过滤方法,并在…...

AMBA-APB

目录 1.APB 协议 2.APB信号列表 3.数据传输 3.1写传输(2种) 3.1.1 无等待状态的写传输 3.1.2有等待状态的写传输 3.2写选通信号 (PSTRB) 字节通道映射 3.3读传输(2种) 3.3.1 无等待状态的读传输 3.3.2有等待状态的读传…...

网安入门之PHP后端基础

PHP 基本概念详解 PHP是一种服务器端脚本语言,常用于动态网站开发和 web 应用程序。以下是 PHP 的基本概念与特点的详细说明: 1. PHP 文件的默认文件扩展名 PHP 文件的扩展名通常为 .php,例如 index.php。PHP 文件可以包含 PHP 代码、HTML…...

windows系统安装完Anaconda之后怎么激活自己的虚拟环境并打开jupyter

1.在win主菜单中找到Anaconda安装文件夹并打开终端 文件夹内有所有安装后的Anaconda的应用软件和终端窗口启动窗口 点击Anaconda Prompt(Anaconda)就会打开类似cmd的命令终端窗口,默认打开的路径是用户名下的路径 2.激活虚拟环境 使用命令…...

【C#特性整理】C#特性及语法基础

1. C#特性 1.1 统一的类型系统 C#中, 所有类型都共享一个公共的基类型. 例如,任何类型的实例都可以通过调用ToString方法将自身转换为一个字符串 1.2 类和接口 接口: 用于将标准与实现隔离, 仅仅定义行为,不做实现. 1.3 属性、方法、事件 属性: 封装了一部分对…...

龙蜥 配置本地yum源8.6----亲测

系统版本: 说明:丫丫的,内网服务安装了个龙蜥操作系统。内网不能访问互联网,所以就需要挂载yum源 用的以前的方法挂载,一直报错 [Couldnt open file /mnt/anolisos/repodata/repomd.xml] yum挂载的时候报错,奇葩!!!,龙蜥的挂载方法好像不一样。 解决: 一、上传并挂…...

Xshell日志录制

步骤 1:设置日志文件位置 打开 Xshell 软件,选择目标会话(或者创建一个新的会话)。右键点击会话名称,选择“属性”。在会话属性窗口中,找到“日志”选项卡。勾选“启用日志记录”。在“文件名”中设置日志…...

vue下载和上传的地址动态ip地址配置方法

vue3结合element-plus实现【下载文件】和【上传文件】的动态ip地址配置 效果图 一、修改【文件上传】静态地址 1、首先引入axios import axios from "/utils/request"; import { getToken } from "/utils/auth"; 定义 const importDialogVisible ref(…...

动手做计算机网络仿真实验入门学习

打开软件 work1 添加串行接口模块,先关电源,添加之后再开电源 自动选择连接 所有传输介质 自动连接 串行线 绿色是通的,红色是不通的。 显示接口。se是serial串行的简写。 Fa是fast ethernet的简写。 为计算机配置ip地址: 为服…...

LeetCode 面试题 17.10. 主要元素

LeetCode 面试题 17.10. 主要元素 数组中占比超过一半的元素称之为主要元素。给你一个 整数 数组,找出其中的主要元素。若没有,返回 -1 。请设计时间复杂度为 O(N) 、空间复杂度为 O(1) 的解决方案。 示例 1: 输入:[1,2,5,9,5,9,5…...

Hive之import和export使用详解

在hive-0.8.0后引入了import/export命令。 Export命令可以导出一张表或分区的数据和元数据信息到一个输出位置,并且导出数据可以被移动到另一个hadoop集群或hive实例,并且可以通过import命令导入数据。 当导出一个分区表,原始数据可能在hdf…...

SpringBoot数据字典字段自动生成对应code和desc

效果:接口会返回orderType,但是这个orderType是枚举的类型(1,2,3,4),我想多返回一个orderTypeDesc给前端展示,这样前端就可以直接拿orderTypeDesc使用了。 1. 定义注解 …...

HTML——16.相对路径

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title></head><body><a href"../../fj1/fj2/c.html" target"_blank">链接到c</a><!--相对路径&#xff1a;-->…...

字——位级运算与有无符号数之间的比较

前言 本文整理和归纳《深入理解计算机系统》这本书的内容&#xff0c;但本文不会继续长篇大论地去将所有内容都总结&#xff0c;而是总结笔者认为容易遗忘或混淆或表述不清的内容。 字 首先字这个概念对于学习过《计算机体系结构》或《操作系统》的同学都不陌生&#xff0c;…...

Python爬虫教程——7个爬虫小案例(附源码)_爬虫实例

本文介绍了7个Python爬虫小案例&#xff0c;包括爬取豆瓣电影Top250、猫眼电影Top100、全国高校名单、中国天气网、当当网图书、糗事百科段子和新浪微博信息&#xff0c;帮助读者理解并实践Python爬虫基础知识。 包含编程资料、学习路线图、源代码、软件安装包等&#xff01;【…...

‘Optional. get()‘ without ‘isPresent()‘ check

在Java中&#xff0c;Optional类被引入主要是为了解决NullPointerException的问题&#xff0c;它提供了一种更优雅的方式来处理可能为null的情况。Optional.get()方法用于获取Optional实例中包含的值&#xff0c;但如果Optional实例是空的&#xff08;即没有值&#xff09;&…...

015-spring-动态原理、AOP的xml和注解方式

强制使用cglib动态代理 spring-AOP的使用...

统计颜色Count Color(POJ2777)题解

有一个长度为L厘米板&#xff0c;L是一个正整数&#xff0c;所以我们可以把它均匀地划分成L个部分&#xff0c;分别从左到右编号为1&#xff0c;2……L&#xff0c;每一个部分长度都为1厘米。现在我们必须给每个部分涂色&#xff0c;一个部分一种颜色&#xff0c;要求完成以下两…...

Nginx 配置 SSL(HTTPS)详解

Nginx作为一款高性能的HTTP和反向代理服务器&#xff0c;自然支持SSL/TLS加密通信。本文将详细介绍如何在Nginx中配置SSL&#xff0c;实现HTTPS的访问。 随着互联网安全性的日益重要&#xff0c;HTTPS协议逐渐成为网站加密通信的标配。Nginx作为一款高性能的HTTP和反向代理服务…...

Day10补代码随想录 理论基础|232.用栈实现队列|225.用队列实现栈|20.有效的括号|1047.删除字符串中的所有相邻重复项

栈和队列理论基础 抽象认识 栈是先进后出(FIFO)&#xff0c;队列是先进先出(LIFO) 队首(先进))队尾(后进)栈顶(后进)栈底(先进) 栈(Stack) 只在一端进行进出操作(只在一端进一端出)像个篮球框&#xff0c;取用篮球从一端进出。 /进栈 int a[1000];//足够大的栈空间 int top-1…...

pytorch基础之注解的使用--003

Title 1.学习目标2.定义3.使用步骤4.结果 1.学习目标 针对源码中出现一些注解的问题&#xff0c;这里专门写一篇文章进行讲解。包括如何自定义注解&#xff0c;以及注意事项&#xff0c;相信JAVA中很多朋友业写过&#xff0c;但是今天写的是Python哦。。。 2.定义 在 Python…...

2024-12-30-g++

title: 探秘 g&#xff1a;C 编程的得力编译器 date: ‘2024-12-30’ category: blog tags: gC 编程编译器技术代码生成与优化 sig: compiler archives: ‘2024-12’ author:way_back summary: g 作为专门用于 C 语言的编译器&#xff0c;在 C 开发领域占据关键地位。它凭借对…...

互联网十万个为什么之什么是微服务

微服务&#xff08;Microservices&#xff09;是一种软件架构设计模式&#xff0c;它将应用程序分解为小型、自治的服务单元&#xff0c;这些服务单元可以独立部署、扩展和维护&#xff0c;其中每一个服务单元也都是一个微服务。 基于微服务形成的软件架构风格称为微服务架构&…...

mysql子查询

子查询是嵌套在另一个 SELECT, INSERT, UPDATE, 或 DELETE查询的 SQL 查询。子查询可以在 WHERE 子句中、FROM 子句或 SELECT 列表中出现。 以下是一些使用 MySQL 子查询的常见示例&#xff1a; 1.在 WHERE 子句中使用子查询&#xff1a; SELECT * FROM Employees WHERE s…...

智能故障诊断和寿命预测期刊推荐

往期精彩内容&#xff1a; Python-凯斯西储大学&#xff08;CWRU&#xff09;轴承数据解读与分类处理 基于FFT CNN - BiGRU-Attention 时域、频域特征注意力融合的轴承故障识别模型-CSDN博客 基于FFT CNN - Transformer 时域、频域特征融合的轴承故障识别模型-CSDN博客 P…...

根据语言变化动态更新图片资源方案

根据语言变化动态更新图片资源方案 一、需求描述二、关于 Locale三、实现方案3.1 方案一&#xff08;不可行&#xff09;3.2 方案二&#xff08;不可行&#xff09;3.3 方案三 一、需求描述 Android 项目中引导页图片包含文字信息&#xff0c;由于应用是适配了三种语言&#x…...

Python世界:数据结构易错点小结

Python世界&#xff1a;数据结构易错点小结 总体list列表tuple元组Stringdict字典mapset 部分笔记汇总&#xff0c;持续刷新中。区别于其他笔记之处在于&#xff0c;主要记录易错点坑点。 总体 数据结构声明辨析 list []tuple () const listditc {} hashset res set(list) 数…...

Linux | Ubuntu零基础安装 nvm 管理nodejs

目录 介绍 项目地址 前置工具 安装 查看环境配置 更新环境变量 查看版本 查看 nodejs包 列表 安装nodejs 查看 nvm 状态 测试 nodejs 介绍 nvm是什么&#xff1f;你可以把它理解成 nodejs的管理软件&#xff0c;方便快速切换nodejs的版本&#xff0c;达到兼容状态 …...

flask后端开发(3):html模板渲染

目录 渲染模板html模板获取路由参数 gitcode地址&#xff1a; https://gitcode.com/qq_43920838/flask_project.git 渲染模板 这样就能够通过html文件来渲染前端&#xff0c;而不是通过return了 html模板获取路由参数...

HAL 库句柄

一、命名方式&#xff1a;句柄是h为首字母&#xff0c;后面接协议名称 比如&#xff1a;huart、hadc、hi2c等 二、句柄类型&#xff1a; 这里拿huart举例&#xff0c;它的类型是UART_HandleTypeDef 进去stm32f1xx_hal_uart.h之后发现句柄的结构定义有部分是灰色的 灰色的当U…...

53.最大子数组和

53.最大子数组和 思路&#xff1a;动态规划 dp[i]表示截止到i的最大连续子数组的和 dp[0]nums[0] dp[i]max(dp[i-1]nums[i],nums[i]) 代码&#xff1a; class Solution { public:int maxSubArray(vector<int>& nums) {vector<int> dp(nums.size());dp[0]…...

计算机网络 (16)数字链路层的几个共同问题

一、封装成帧 封装成帧是数据链路层的一个基本问题。数据链路层把网络层交下来的数据构成帧发送到链路上&#xff0c;以及把接收到的帧中的数据取出并上交给网络层。封装成帧就是在一段数据的前后分别添加首部和尾部&#xff0c;构成了一个帧。接收端在收到物理层上交的比特流后…...

[OpenGL]使用glsl实现smallpt

一、简介 本文介绍了如何使用 OpenGL&#xff0c;使用 glsl 语言在 Fragment shader 中实现 smallpt。程序完成后可以得到以下渲染结果&#xff08;samples per pixel, spp 16&#xff09;。在程序中按下A,W可以左右平移&#xff0c;按下W,S可以前后平移&#xff1a; 二、s…...

数据结构与算法Python版 骑士周游问题与深度优先搜索

文章目录 一、图的应用-骑士周游问题二、图的深度优先搜索 一、图的应用-骑士周游问题 骑士周游问题 在一个88的国际象棋棋盘上&#xff0c;一个棋子“马”&#xff08;骑士&#xff09;&#xff0c;按照“马走日”的规则&#xff0c;从一个格子出发&#xff0c;要走遍所有棋…...

HIVE数据仓库分层

1&#xff1a;为什么要分层 大多数情况下&#xff0c;我们完成的数据体系却是依赖复杂、层级混乱的。在不知不觉的情况下&#xff0c;我们可能会做出一套表依赖结构混乱&#xff0c;甚至出现循环依赖的数据体系。 我们需要一套行之有效的数据组织和管理方法来让我们的数据体系…...

WOFOST作物模型(3):敏感性分析

目录 一、定义参数范围二、采样生成参数样本三、运行不同参数组下的WOFOST四、计算敏感度与可视化1.敏感度2.二阶交互敏感度五、敏感变量对产量的影响结果可视化一、定义参数范围 使用TAGP(Total Above Ground Production),地上总产量 TSUM1,temperature sum from emergence…...

【2024年-6月-14日-开源社区openEuler实践记录】探索 test - tools:高效测试的开源宝库

开篇引言 大家好&#xff0c;我是 fzr123&#xff0c;在软件开发领域深耕多年&#xff0c;一直致力于探索各种提升效率的工具与技术。今天&#xff0c;我将为大家深入介绍一款在测试领域极具价值的开源项目——test - tools&#xff0c;它为开发者们提供了一系列强大的测试功能…...

go-xorm连接

package mainimport ("fmt"_ "github.com/go-sql-driver/mysql""time""xorm.io/xorm" )func MysqlDbContent() {//数据库基本信息var (userName string "root"password string "12345678"ipAddress string &…...

Java字节分割文件流

使用 Java 通过字节分割大文件并将其以文件流的方式读写的示例代码。这个代码展示了如何将一个大文件分割成多个小文件&#xff0c;并以字节流的方式操作文件。 完整代码示例 import java.io.*;public class FileSplitter {public static void main(String[] args) {// 原始文…...

【潜意识Java】深入详细理解分析Java中的toString()方法重写完整笔记总结,超级详细。

目录 一、toString() 方法是啥&#xff1f; &#xff08;一&#xff09;默认的 toString() 方法 &#xff08;二&#xff09;toString() 方法的作用 二、为啥要重写 toString() 方法&#xff1f; &#xff08;一&#xff09;提高代码的可读性 &#xff08;二&#xff09;…...

仙盟系统开发——启动app失败

var 返回 仙盟使者.Cyber_CallApp(VOAPP, 命令, 携带);...