stm32_HAL_CAN(特点:广播试,检测线路是否空,id有优先级)

UART

I2C

SPI

介绍

CAN(Controller Area Network)接口是一种常用于嵌入式系统中的通信接口,尤其在汽车和工业领域。它由Robert Bosch GmbH在1986年开发,旨在提供一种可靠、高效、灵活的车载通信网络。CAN总线的主要

特点包括:

  1. 多主通信:CAN总线上的所有节点都可以主动发送数据,没有固定的主节点。
  2. 消息优先级:通过消息的标识符(ID)来设定优先级,ID越低,优先级越高。
  3. 非破坏性仲裁:当多个节点同时尝试发送数据时,CAN总线使用非破坏性仲裁机制来确定哪个消息可以继续传输。
  4. 自动错误处理:CAN总线具有错误检测和容错机制,包括位错误检测、帧检验、循环冗余检验(CRC)和自动重传。
  5. 高噪声免疫性:由于其差分信号的特点,CAN总线对电磁干扰有较高的抵抗能力。
  6. 数据传输速率:CAN总线支持从1 kbps到1 Mbps不等的数据传输速率。
  7. 通信距离:在不使用中继器的情况下,CAN总线可以支持最长40米(在1 Mbps速率下)的通信距离。
  8. 低成本:与其他通信协议相比,CAN总线接口的硬件实现成本较低。

补充

两根通信线(CAN_H、CAN_L),线路少,无需共地

差分信号通信,抗干扰能力强

高速CAN(ISO11898):125k~1Mbps, <40m

低速CAN(ISO11519):10k~125kbps, <1km

异步,无需时钟线,通信速率由设备各自约定

半双工,可挂载多设备,多设备同时发送数据时通过仲裁判断先后顺序

11位/29位报文ID,用于区分消息功能,同时决定优先级

可配置1~8字节的有效载荷

可实现广播式和请求式两种传输方式

应答、CRC校验、位填充、位同步、错误处理等特性

CAN接口通常由CAN控制器和CAN收发器组成。

CAN控制器负责处理数据帧的封装、解析和错误处理等逻辑,而CAN收发器则负责将控制器发出的信号转换为适合在物理总线上传输的差分信号,或者将物理总线上的差分信号转换为控制器能够处理的信号。

硬件电路

CAN电平标准

CAN总线采用差分信号,即两线电压差(VCAN_H-VCAN_L)传输数据位

高速CAN规定:   

         电压差为0V时表示逻辑1(隐性电平)     

        电压差为2V时表示逻辑0(显性电平)

低速CAN规定:   

         电压差为-1.5V时表示逻辑1(隐性电平)   

         电压差为3V时表示逻辑0(显性电平)

帧类型

        

  1. 数据帧(Data Frame):

    • 标准数据帧:使用11位标识符,用于传输数据。
    • 扩展数据帧:使用29位标识符,提供更多的标识符可能性,也用于传输数据。
  2. 遥控帧(Remote Transmission Request, RTR):

    • 标准遥控帧:使用11位标识符,请求发送具有特定标识符的数据帧。
    • 扩展遥控帧:使用29位标识符,请求发送具有特定标识符的数据帧。
  3. 错误帧(Error Frame):

    • 由任何检测到错误的节点发送,用于指示总线上发生了错误。
  4. 过载帧(Overload Frame):

    • 用于在需要更多时间来处理接收到的数据帧时,延长下一个数据帧的发送。
  5. 帧间隔(Interframe Space):

    • 在数据帧和遥控帧之间的最小时间间隔,确保总线上的节点有足够的时间来处理接收到的帧。

数据帧

遥控帧

遥控帧无数据段,RTR为隐性电平1,其他部分与数据帧相同

错误帧

总线上所有设备都会监督总线的数据,一旦发现“位错误”或“填充错误”或“CRC错误”或“格式错误”或“应答错误” ,这些设备便会发出错误帧来破坏数据,同时终止当前的发送设备

过载帧

当接收方收到大量数据而无法处理时,其可以发出过载帧,延缓发送方的数据发送,以平衡总线负载,避免数据丢失

帧间隔

将数据帧和远程帧与前面的帧分离开



注意

位填充

数据传输时两个设备做了什么

在CAN(Controller Area Network)总线中,当两个节点(例如,节点A和节点B)进行通信时,它们各自扮演不同的角色:一个是发送节点,另一个是接收节点。以下是两个节点在数据帧传输过程中各自所做的具体工作:

发送节点(节点A):

  1. 构造数据帧

    • 节点A将需要发送的数据组织成数据帧格式,包括帧起始(SOF)、仲裁域(标识符和RTR位)、控制域(DLC)、数据域(实际数据)、CRC域(CRC序列)和帧结束(EOF)。
  2. 发送数据帧

    • 节点A将数据帧发送到CAN总线上。它首先监测总线是否空闲,然后在总线空闲时开始发送数据帧。
  3. 仲裁

    • 如果多个节点同时尝试发送数据,节点A会参与仲裁过程。如果节点A的标识符具有最高的优先级(最低的数值),它将赢得仲裁并继续发送数据帧。
  4. 等待确认

    • 在发送完数据帧的ACK槽期间,节点A监听总线,以确定是否有接收节点发送了确认响应(ACK)。
  5. 处理错误

    • 如果在传输过程中检测到错误(例如,在ACK槽中没有收到确认),节点A会根据错误类型和错误计数器采取相应的错误处理措施,可能会重传数据帧。

接收节点(节点B):

  1. 监听总线

    • 节点B持续监听总线上的信号,等待数据帧的到来。
  2. 识别标识符

    • 当节点B检测到帧起始(SOF)时,它会开始解析仲裁域,识别标识符,以确定是否应该接收这个数据帧。
  3. 接收数据帧

    • 如果数据帧的标识符与节点B的接收过滤器匹配,节点B将继续接收数据帧的剩余部分,包括控制域、数据域、CRC域等。
  4. 验证数据帧

    • 节点B计算数据帧的CRC,并将其与接收到的CRC序列进行比较,以验证数据在传输过程中没有发生错误。
  5. 发送确认

    • 如果数据帧验证无误,节点B在ACK槽期间向总线发送一个显性位(逻辑“0”),以向发送节点(节点A)确认数据帧已被正确接收。
  6. 处理数据

    • 一旦数据帧被正确接收和确认,节点B可以将数据传递给应用程序进行处理。

各个版本协议

CAN(Controller Area Network)是一种广泛使用的、基于消息的通信协议,主要用于汽车和其他嵌入式系统中。随着技术的发展,CAN协议也经历了多次更新和扩展,主要包括CAN 2.0A、CAN 2.0B和CAN FD三个标准。

  1. CAN 2.0A

    • CAN 2.0A是CAN协议的一个版本,也被称为标准帧格式。
    • 它支持11位标识符,这意味着可以有最多2048个不同的消息标识符。
    • CAN 2.0A通常用于较为简单的网络,其中节点数量和消息优先级不是特别高。
  2. CAN 2.0B

    • CAN 2.0B是CAN协议的另一个版本,也被称为扩展帧格式。
    • 它支持29位标识符,这意味着可以有最多约536870912个不同的消息标识符。
    • CAN 2.0B通过增加额外的标识符位数,提供了更高的消息标识符数量,从而能够支持更复杂的网络和更多的节点。
  3. CAN FD(Flexible Data-Rate)

    • CAN FD是CAN协议的一个扩展,旨在提高数据传输速率和数据长度。
    • 它支持两种不同的数据传输速率:在仲裁阶段使用传统的CAN速率,而在数据阶段可以使用高达8Mbps的速率。
    • CAN FD还支持更长的数据字段,可以达到64字节,而传统的CAN协议最多只能支持8字节。
    • CAN FD向后兼容CAN 2.0A和CAN 2.0B,但在使用更高速率和更长数据长度时需要网络中的所有节点都支持CAN FD。

最大时钟速度

CAN标准理论上的最大速度:

  1. CAN 2.0A/CAN 2.0B

    • CAN 2.0A和CAN 2.0B是CAN协议的基础版本,它们在物理层和数据链路层上有所不同,但理论上支持的最大通信速度相同。
    • 传统上,CAN 2.0A/B的通信速度通常限制在1 Mbps(兆比特每秒)以内,这是大多数CAN控制器和收发器的标准速度。
    • 然而,一些高性能的CAN控制器和收发器可能支持更高的速度,例如2 Mbps或更高,但这通常需要优化的硬件设计和严格的位定时参数配置。
  2. CAN FD(Flexible Data-Rate)

    • CAN FD是CAN协议的一个扩展,旨在提高数据传输速率和数据长度。
    • 在仲裁阶段,CAN FD仍然支持与传统CAN相同的标准速度,通常也是1 Mbps。
    • 在数据阶段,CAN FD可以支持更高的速度,理论上可以达到5 Mbps甚至8 Mbps,但实际应用中的速度取决于具体的硬件支持和网络配置。

stm32CudeMX配置CAN

  1. Bit Timings Parameters(位定时参数)

    • Prescaler (for Time Quantum)(时间量子预分频器): 用于确定CAN模块的时间量子(Time Quantum)的长度,通过这个预分频器可以设置CAN时钟的频率。
    • Time Quantum(时间量子): 是CAN总线上的基本时间单位,用于定义位时间。
    • Time Quanta in Bit Segment 1(位段1中的时间量子): 定义一个CAN位中的第一个时间段(例如,同步段、传播时间段)的长度。
    • Time Quanta in Bit Segment 2(位段2中的时间量子): 定义一个CAN位中的第二个时间段(例如,相位缓冲段1)的长度。
    • Time for one Bit(一个位的时间): 定义一个完整的CAN位的时间长度。
    • Baud Rate(波特率): 定义CAN通信的速率,即每秒钟传输的位数。
    • ReSynchronization Jump Width(重新同步跳变宽度): 定义在CAN位时间内,重新同步跳变的最大宽度。
  2. Basic Parameters(基本参数)

    • Time Triggered Communication Mode(时间触发通信模式): 如果启用,CAN模块将工作在时间触发通信模式,这种模式下所有的通信都是基于时间的,可以提高通信的确定性和可靠性。
    • Automatic Bus-Off Management(自动总线关闭管理): 如果启用,当CAN节点检测到错误过多时,会自动进入总线关闭状态,并在一定条件满足后自动尝试重新连接到总线。
    • Automatic Wake-Up Mode(自动唤醒模式): 如果启用,当CAN模块检测到总线活动时,会自动唤醒微控制器。
    • Automatic Retransmission(自动重传模式): 如果启用,当CAN消息发送失败时,模块会自动重传消息。
    • Receive Fifo Locked Mode(接收FIFO锁定模式): 如果启用,当FIFO溢出时,锁定的消息不会被覆盖,而是保持不变。
    • Transmit Fifo Priority(发送FIFO优先级): 定义发送FIFO中消息的发送顺序,可以设置为优先级或FIFO模式。
  3. Advanced Parameters(高级参数)

    • Test Mode(测试模式): 允许用户将CAN模块设置为不同的测试模式,用于诊断和测试目的。

模式(Normal :正常  Loop back :回环   Silent :静默   Loop back combined with Silent :回环静默)

正常模式:CAN外设正常地向CAN总线发送数据并从CAN总线上接收数据。
回环模式:CAN外设正常向CAN总线发送数据,同时接收自己发送的数据,但不从CAN总线上接收数据。在学习CAN外设的时候非常有用,特别是在没有专门的USB转CAN模块也没有两块开发板的时候。
静默模式:CAN外设不向CAN总线发送数据,仅从CAN总线上接收数据,但不会应答。一般用于检测CAN总线的流量。
静默回环模式:CAN外设不会往CAN总线收发数据,仅给自己发送。一般用于自检。
 

函数解释


//启动CAN模块,使其进入正常工作模式。
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);
//将CAN模块从睡眠模式唤醒。
HAL_StatusTypeDef HAL_CAN_WakeUp(CAN_HandleTypeDef *hcan);
//检查CAN模块是否处于活动睡眠模式。
uint32_t HAL_CAN_IsSleepActive(const CAN_HandleTypeDef *hcan);
//向CAN模块的发送邮箱添加一条消息。
HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, const CAN_TxHeaderTypeDef *pHeader,const uint8_t aData[], uint32_t *pTxMailbox);
//取消正在发送的消息。
HAL_StatusTypeDef HAL_CAN_AbortTxRequest(CAN_HandleTypeDef *hcan, uint32_t TxMailboxes);
//获取空闲的发送邮箱数量。
uint32_t HAL_CAN_GetTxMailboxesFreeLevel(const CAN_HandleTypeDef *hcan);
//检查是否有消息正在发送邮箱中等待发送。
uint32_t HAL_CAN_IsTxMessagePending(const CAN_HandleTypeDef *hcan, uint32_t TxMailboxes);
//获取发送消息的时间戳。
uint32_t HAL_CAN_GetTxTimestamp(const CAN_HandleTypeDef *hcan, uint32_t TxMailbox);
//从接收FIFO中读取一条消息。
HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, uint32_t RxFifo,CAN_RxHeaderTypeDef *pHeader, uint8_t aData[]);
//获取接收FIFO中的消息数量
uint32_t HAL_CAN_GetRxFifoFillLevel(const CAN_HandleTypeDef *hcan, uint32_t RxFifo);
每个函数的解释:*HAL_StatusTypeDef HAL_CAN_Start(CAN_HandleTypeDef hcan);
启动CAN模块,使其进入正常工作模式。
参数 hcan 是指向CAN_HandleTypeDef结构的指针,该结构包含CAN模块的配置和状态信息。
*HAL_StatusTypeDef HAL_CAN_Stop(CAN_HandleTypeDef hcan);
停止CAN模块,使其不再接收或发送数据。
参数 hcan 是指向CAN_HandleTypeDef结构的指针。
*HAL_StatusTypeDef HAL_CAN_RequestSleep(CAN_HandleTypeDef hcan);
请求CAN模块进入睡眠模式,以降低功耗。
参数 hcan 是指向CAN_HandleTypeDef结构的指针。
*HAL_StatusTypeDef HAL_CAN_WakeUp(CAN_HandleTypeDef hcan);
将CAN模块从睡眠模式唤醒。
参数 hcan 是指向CAN_HandleTypeDef结构的指针。
*uint32_t HAL_CAN_IsSleepActive(const CAN_HandleTypeDef hcan);
检查CAN模块是否处于活动睡眠模式。
参数 hcan 是指向CAN_HandleTypeDef结构的指针。
返回值:如果CAN模块处于睡眠模式,则返回非零值,否则返回0。
**HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, const CAN_TxHeaderTypeDef pHeader, const uint8_t aData[], uint32_t pTxMailbox);
向CAN模块的发送邮箱添加一条消息。
参数 hcan 是指向CAN_HandleTypeDef结构的指针。
参数 pHeader 是指向CAN_TxHeaderTypeDef结构的指针,该结构包含要发送消息的头部信息。
参数 aData 是指向要发送的数据的指针。
参数 pTxMailbox 是指向用于存储发送邮箱编号的变量的指针。
返回值:操作状态(HAL_OK, HAL_ERROR等)。
*HAL_StatusTypeDef HAL_CAN_AbortTxRequest(CAN_HandleTypeDef hcan, uint32_t TxMailboxes);
取消正在发送的消息。
参数 hcan 是指向CAN_HandleTypeDef结构的指针。
参数 TxMailboxes 是要取消的消息所在的发送邮箱的位掩码。
返回值:操作状态(HAL_OK, HAL_ERROR等)。
*uint32_t HAL_CAN_GetTxMailboxesFreeLevel(const CAN_HandleTypeDef hcan);
获取空闲的发送邮箱数量。
参数 hcan 是指向CAN_HandleTypeDef结构的指针。
返回值:空闲发送邮箱的数量。
*uint32_t HAL_CAN_IsTxMessagePending(const CAN_HandleTypeDef hcan, uint32_t TxMailboxes);
检查是否有消息正在发送邮箱中等待发送。
参数 hcan 是指向CAN_HandleTypeDef结构的指针。
参数 TxMailboxes 是要检查的发送邮箱的位掩码。
返回值:如果有消息正在等待发送,则返回非零值,否则返回0。
*uint32_t HAL_CAN_GetTxTimestamp(const CAN_HandleTypeDef hcan, uint32_t TxMailbox);
获取发送消息的时间戳。
参数 hcan 是指向CAN_HandleTypeDef结构的指针。
参数 TxMailbox 是要获取时间戳的发送邮箱的编号。
返回值:发送消息的时间戳。
**HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef hcan, uint32_t RxFifo, CAN_RxHeaderTypeDef pHeader, uint8_t aData[]);
从接收FIFO中读取一条消息。
参数 hcan 是指向CAN_HandleTypeDef结构的指针。
参数 RxFifo 是要读取的接收FIFO的编号。
参数 pHeader 是指向CAN_RxHeaderTypeDef结构的指针,该结构用于存储接收消息的头部信息。
参数 aData 是用于存储接收数据的数组。
返回值:操作状态(HAL_OK, HAL_ERROR等)。
*uint32_t HAL_CAN_GetRxFifoFillLevel(const CAN_HandleTypeDef hcan, uint32_t RxFifo);
获取接收FIFO中的消息数量。
参数 hcan 是指向CAN_HandleTypeDef结构的指针。
参数 RxFifo 是要检查的接收FIFO的编号。
返回值:接收FIFO中的消息数量。

基本步骤:

初始化CAN接口

  1. 配置CAN模式和波特率

    • 使用HAL_CAN_Init()函数来初始化CAN接口。
    • 通过CAN_HandleTypeDef结构体配置CAN的工作模式,如正常模式、测试模式等,并设置适当的波特率。
  2. 配置过滤器

    • 设置CAN过滤器以过滤不必要的报文。这可以通过HAL_CAN_ConfigFilter()函数来完成。

发送数据

  1. 创建CAN报文

    • 使用CAN_TxHeaderTypeDef结构体定义要发送的报文的头部信息,包括标识符、数据长度、帧类型等。
  2. 填充数据

    • 准备要发送的数据,通常存储在一个数组中。
  3. 发送报文

    • 调用HAL_CAN_AddTxMessage()函数,将报文添加到发送队列中。
    • 如果发送成功,该函数会返回HAL_OK

接收数据

  1. 接收中断

    • 使能CAN中断,并配置中断处理函数。在中断处理函数中,调用HAL_CAN_IRQHandler()
  2. 读取数据

    • 在中断处理函数或主循环中,使用HAL_CAN_GetRxMessage()函数来读取接收到的报文。
    • 读取到的数据存储在事先定义的数组中。
  3. 处理数据

    • 根据应用程序的需求处理接收到的数据。

RxFifo 参数通常是一个枚举值

区别

  • CAN_RX_FIFO0:通常用于存储高优先级的消息。这意味着如果CAN消息在硬件筛选过程中被认为具有较高的优先级,它们将被放入FIFO 0。
  • CAN_RX_FIFO1:用于存储低优先级的消息。那些在筛选过程中被认为优先级较低的消息将被放入FIFO 1。

筛选器(不设置不可接收数据)

(filters)是用于过滤接收到的消息的重要功能。CAN控制器通常包含多个筛选器,允许您根据特定的标准(如标识符)来选择性地接收消息。这有助于减少CPU的处理负担,因为只有符合特定条件的消息才会触发中断或被传送到应用程序。

STM32微控制器的CAN模块通常具有多个筛选器,每个筛选器都可以独立配置。筛选器可以根据以下标准来过滤消息:

  1. 标识符(ID):筛选器可以基于标准标识符(11位)或扩展标识符(29位)来过滤消息。

  2. 远程传输请求(RTR):筛选器可以区分数据帧和远程帧。

  3. IDE位:筛选器可以根据标识符类型(标准或扩展)来过滤消息。

在STM32的HAL库中,您可以使用以下函数来配置CAN筛选器:

  • HAL_CAN_ConfigFilter():用于配置一个或多个筛选器。

  • HAL_CAN_ActivateNotification():用于启用与筛选器相关的中断。

CAN_HandleTypeDef hcan;
CAN_FilterTypeDef sFilterConfig;// 初始化CAN
hcan.Instance = CAN1;
hcan.Init.Mode = CAN_MODE_NORMAL;
// ... 其他初始化设置// 初始化CAN并启用中断
if (HAL_CAN_Init(&hcan) != HAL_OK)
{// 初始化失败的处理
}// 配置筛选器
sFilterConfig.FilterBank = 0; // 使用筛选器组0
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 筛选器模式为掩码模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 使用32位筛选器
sFilterConfig.FilterIdHigh = 0x0000; // 筛选器ID高16位
sFilterConfig.FilterIdLow = 0x0000; // 筛选器ID低16位
sFilterConfig.FilterMaskIdHigh = 0x0000; // 掩码ID高16位
sFilterConfig.FilterMaskIdLow = 0x0000; // 掩码ID低16位
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // 将筛选器关联到FIFO0
sFilterConfig.FilterActivation = ENABLE; // 启用筛选器// 设置筛选器
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
{// 筛选器配置失败的处理
}

{

  • FilterIdHigh :CAN_FiR1寄存器的高16位,用于填写筛选码。具体的格式要根据16位、32位;掩码模式、列表模式来确定。
    • 取值: 0x0 ~ 0xFFFF
  • FilterIdLow :CAN_FiR1寄存器的低16位
  • FilterMaskIdHigh :CAN_FiR2寄存器的高16位
  • FilterMaskIdLow :CAN_FiR2寄存器的低16位
  • FilterFIFOAssignment :通过筛选器的报文存在FIFO0还是FIFO1中
    • 取值:CAN_FILTER_FIFO0 或 CAN_FILTER_FIFO1
  • FilterBank :本次配置的筛选器号
    • 取值:对于单CAN为 0 ~ 13;对于双CAN为 0 ~ 27
  • FilterMode :筛选模式,掩码模式或列表模式。
    • 取值:CAN_FILTERMODE_IDMASK 或 CAN_FILTERMODE_IDMASK
  • FilterScale :筛选码大小,16位或32位。
    • 取值:CAN_FILTERSCALE_16BIT 或 CAN_FILTERSCALE_32BIT
  • FilterActivation :使能或失能此筛选器。
    • 取值:CAN_FILTER_DISABLE 或 CAN_FILTER_ENABLE
  • SlaveStartFilterBank :为从CAN(CAN2)分配的筛选器个数。如果只使用单个CAN,可忽略此成员
    • 取值:        0 ~ 27


                        
原文链接:https://blog.csdn.net/jdhfusk/article/details/121748853

}

实现收发数据

思路

定义一个按键,串口,can

按键点击开始发发完再接收,将数据通过串口发给电脑

1定义函数

/***       CAN 发送一组数据*  	数据  长度*/
uint8_t can_send_msg(  uint8_t *data, uint8_t len )
{//发的结构体CAN_TxHeaderTypeDef can_tx;can_tx.DLC=len;         // 数据长度代码can_tx.ExtId=0x00;// 扩展标识符can_tx.IDE=CAN_ID_EXT;// 标识符类型为扩展帧                            //标识符的长度can_tx.RTR=CAN_RTR_DATA;// 远程传输请求为数据帧can_tx.StdId=0x12;// 标准标识符                                           //can的ID//can_tx.TransmitGlobalTime=ENABLE;// 使用全局时间    ENABLE开启   DISABLE关闭   时间戳uint32_t as=CAN_TX_MAILBOX0;if(HAL_CAN_AddTxMessage(&hcan,&can_tx,data,&as)==HAL_OK){int as1=HAL_CAN_GetTxMailboxesFreeLevel(&hcan);char aa[28];sprintf(aa,"数据发送成功,邮箱个数为:%d\n",as1);HAL_UART_Transmit(&huart1,(uint8_t*)aa,27,50);}while (HAL_CAN_GetTxMailboxesFreeLevel(&hcan) != 3); /* 等待发送完成,所有邮箱为空 */return 0;
}/***        CAN 接收数据查询//    数据*/
void can_receive_msg(  uint8_t *data )
{//接收的结构体// 声明一个变量来存储接收到的消息的头部信息CAN_RxHeaderTypeDef can_rx;//can_rx.DLC			// 数据长度//can_rx.ExtId				//扩展标识符//can_rx.FilterMatchIndex// 过滤器匹配索引//can_rx.IDE			// 标识符类型为扩展帧//can_rx.RTR			// 远程传输请求为数据帧//can_rx.StdId;			// 标准标识符//can_rx.Timestamp	;	// 时间戳if(HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &can_rx, data)== HAL_OK){char aa[28]={"接收成功\n"};HAL_UART_Transmit(&huart1,(uint8_t*)aa,9,50);}else{char aa[28]={"接收失败\n"};HAL_UART_Transmit(&huart1,(uint8_t*)aa,9,50);}
}

2初始化过滤器

  CAN_FilterTypeDef sFilterConfig;//配置CAN过滤器sFilterConfig.FilterBank = 0;                             /* 过滤器0 */sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;sFilterConfig.FilterIdHigh = 0x0000;                      /* 32位ID */sFilterConfig.FilterIdLow = 0x0000;sFilterConfig.FilterMaskIdHigh = 0x0000;                  /* 32位MASK */sFilterConfig.FilterMaskIdLow = 0x0000;sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;    /* 过滤器0关联到FIFO0 */sFilterConfig.FilterActivation = CAN_FILTER_ENABLE;       /* 激活滤波器0 */sFilterConfig.SlaveStartFilterBank = 14;// 过滤器配置 if ( HAL_CAN_ConfigFilter( &hcan, &sFilterConfig ) != HAL_OK ){return 2;}// 启动CAN外围设备 if ( HAL_CAN_Start( &hcan ) != HAL_OK ){return 3;}

3检测按键收发

 if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)== GPIO_PIN_SET){HAL_Delay(20);if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==HAL_OK){char a[]={"按键按下了\n"};HAL_UART_Transmit(&huart1,(uint8_t*)a,11,50);uint8_t tx_data[8] = {"ABCDEFGH"}; // 消息数据uint8_t rx_data[8]; // 接收数据缓冲区can_send_msg(  tx_data, 8 );if(HAL_CAN_GetRxFifoFillLevel(&hcan ,CAN_RX_FIFO0)){can_receive_msg(  rx_data );}else{char aa[28]={"无数据\n"};HAL_UART_Transmit(&huart1,(uint8_t*)aa,9,50);}HAL_Delay(500);HAL_UART_Transmit(&huart1,rx_data,8,500);}}

全部在主文件中

main.c

/* USER CODE BEGIN Header */
/********************************************************************************* @file           : main.c* @brief          : Main program body******************************************************************************* @attention** Copyright (c) 2024 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "can.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/***       CAN 发送一组数据*  	数据  长度*/
uint8_t can_send_msg(  uint8_t *data, uint8_t len )
{//发的结构体CAN_TxHeaderTypeDef can_tx;can_tx.DLC=len;         // 数据长度代码can_tx.ExtId=0x00;// 扩展标识符can_tx.IDE=CAN_ID_EXT;// 标识符类型为扩展帧                            //标识符的长度can_tx.RTR=CAN_RTR_DATA;// 远程传输请求为数据帧can_tx.StdId=0x12;// 标准标识符                                           //can的ID//can_tx.TransmitGlobalTime=ENABLE;// 使用全局时间    ENABLE开启   DISABLE关闭   时间戳uint32_t as=CAN_TX_MAILBOX0;if(HAL_CAN_AddTxMessage(&hcan,&can_tx,data,&as)==HAL_OK){int as1=HAL_CAN_GetTxMailboxesFreeLevel(&hcan);char aa[28];sprintf(aa,"数据发送成功,邮箱个数为:%d\n",as1);HAL_UART_Transmit(&huart1,(uint8_t*)aa,27,50);}while (HAL_CAN_GetTxMailboxesFreeLevel(&hcan) != 3); /* 等待发送完成,所有邮箱为空 */return 0;
}/***        CAN 接收数据查询//    数据*/
void can_receive_msg(  uint8_t *data )
{//接收的结构体// 声明一个变量来存储接收到的消息的头部信息CAN_RxHeaderTypeDef can_rx;//can_rx.DLC			// 数据长度//can_rx.ExtId				//扩展标识符//can_rx.FilterMatchIndex// 过滤器匹配索引//can_rx.IDE			// 标识符类型为扩展帧//can_rx.RTR			// 远程传输请求为数据帧//can_rx.StdId;			// 标准标识符//can_rx.Timestamp	;	// 时间戳if(HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &can_rx, data)== HAL_OK){char aa[28]={"接收成功\n"};HAL_UART_Transmit(&huart1,(uint8_t*)aa,9,50);}else{char aa[28]={"接收失败\n"};HAL_UART_Transmit(&huart1,(uint8_t*)aa,9,50);}
}
/* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_CAN_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */CAN_FilterTypeDef sFilterConfig;//配置CAN过滤器sFilterConfig.FilterBank = 0;                             /* 过滤器0 */sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;sFilterConfig.FilterIdHigh = 0x0000;                      /* 32位ID */sFilterConfig.FilterIdLow = 0x0000;sFilterConfig.FilterMaskIdHigh = 0x0000;                  /* 32位MASK */sFilterConfig.FilterMaskIdLow = 0x0000;sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;    /* 过滤器0关联到FIFO0 */sFilterConfig.FilterActivation = CAN_FILTER_ENABLE;       /* 激活滤波器0 */sFilterConfig.SlaveStartFilterBank = 14;// 过滤器配置 if ( HAL_CAN_ConfigFilter( &hcan, &sFilterConfig ) != HAL_OK ){return 2;}// 启动CAN外围设备 if ( HAL_CAN_Start( &hcan ) != HAL_OK ){return 3;}/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)== GPIO_PIN_SET){HAL_Delay(20);if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==HAL_OK){char a[]={"按键按下了\n"};HAL_UART_Transmit(&huart1,(uint8_t*)a,11,50);uint8_t tx_data[8] = {"ABCDEFGH"}; // 消息数据uint8_t rx_data[8]; // 接收数据缓冲区can_send_msg(  tx_data, 8 );if(HAL_CAN_GetRxFifoFillLevel(&hcan ,CAN_RX_FIFO0)){can_receive_msg(  rx_data );}else{char aa[28]={"无数据\n"};HAL_UART_Transmit(&huart1,(uint8_t*)aa,9,50);}HAL_Delay(500);HAL_UART_Transmit(&huart1,rx_data,8,500);}}/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK){Error_Handler();}
}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @brief  This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#ifdef  USE_FULL_ASSERT
/*** @brief  Reports the name of the source file and the source line number*         where the assert_param error has occurred.* @param  file: pointer to the source file name* @param  line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

个人主页有项目文件资料免费自行下载

还会总一篇STM32CudeMX的全过程

此篇重点介绍概念

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/26722.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

eNSP学习——配置高级的访问控制列表

目录 主要命令 原理概述 实验目的 实验内容 实验拓扑 实验编址 实验步骤 1、基本配置 2、搭建OSPF网络 3、配置Telnet 4、配置高级ACL控制访问 需要eNSP各种配置命令的点击链接自取&#xff1a;华为&#xff45;NSP各种设备配置命令大全PDF版_ensp配置命令大全资源-…

数据结构01 栈及其相关问题讲解

栈是一种线性数据结构&#xff0c;栈的特征是数据的插入和删除只能通过一端来实现&#xff0c;这一端称为“栈顶”&#xff0c;相应的另一端称为“栈底”。 栈及其特点 用一个简单的例子来说&#xff0c;栈就像一个放乒乓球的圆筒&#xff0c;底部是封住的&#xff0c;如果你想…

【简单介绍下Sass,什么是Sass?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

Linux:多线程的操作

多线程操作 进程与线程线程的创建 create_pthread创建线程池给线程传入对象的指针 线程等待 pthread_join退出线程 pthread_exit线程等待参数 retval 与 线程退出参数 retval 线程中断 pthread_cancel获取线程编号 pthread_self线程分离 pthread_detach 进程与线程 进程是资源…

史上最全,呕心沥血总结oracle推进SCN方法(八)

作者介绍&#xff1a;老苏&#xff0c;10余年DBA工作运维经验&#xff0c;擅长Oracle、MySQL、PG数据库运维&#xff08;如安装迁移&#xff0c;性能优化、故障应急处理等&#xff09; 公众号&#xff1a;老苏畅谈运维 欢迎关注本人公众号&#xff0c;更多精彩与您分享。前面介…

17-C语言中的变量生命周期——自动存储期、青苔存储期、自定义存储期

17-C语言中的变量生命周期——自动存储期、青苔存储期、自定义存储期 文章目录 17-C语言中的变量生命周期——自动存储期、青苔存储期、自定义存储期一、自动存储期示例 二、静态存储期2.1 示例 三、自定义存储期3.1 如何申请内存3.2 如何释放内存3.3 如何清空内存3.4 示例 概念…

MQTT通讯协议接入

1.MQTT协议概述 MQTT是一种基于发布/订阅模式的轻量级消息传输协议&#xff0c;常用于低带宽、不可靠网络环境下传输消息&#xff0c;适用于物联网设备之间的通信。 1.1 MQTT协议的组件 客户端&#xff08;Client&#xff09;&#xff1a;连接到MQTT代理服务器的设备&#xff…

计算机组成原理(六)

0x12345678和12345678H都是指同一个十六进制,也就是12345678&#xff0c;不过是不同的编程语言的写法而已 具体来说&#xff0c;如果有 n 根地址线&#xff0c;计算机可以寻址的内存空间大小是 2^n 字节。 24根地址线&#xff1a; 如果一个系统有24根地址线&#xff0c;意味着它…

汇编程序设计之 位操作指令、顺序程序设计

文章目录 位操作类指令逻辑运算指令NOTORANDXORTEST 移位指令逻辑移位算数移位循环移位指令 处理机控制类指令顺序结构程序设计概念例子 位操作类指令 逻辑运算指令 NOT OR 对于每一个位&#xff0c;有1即为1 AND 同时为1才是1 XOR 不相同才为1 TEST 和and 一样的功能&…

RK3568技术笔记六 新建 Ubuntu Linux 虚拟机

VMware 安装完成后&#xff0c;启动 VMware 软件。启动后在 VMware 主界面点击“创建新的虚拟机”。如下图所示&#xff1a; 开始对新建的虚拟机进行设置。选择“自定义”&#xff0c;然后点击“下一步”。如下图所示&#xff1a; 使用默认配置&#xff0c;单击“下一步”。如下…

PyTorch -- 最常见激活函数的选择

首先&#xff0c;简单复习下什么是梯度&#xff1a;梯度是偏微分的集合 举例说明&#xff1a;对于 z y 2 − x 2 : ∇ z ( ∂ z ∂ x , ∂ z ∂ y ) &#xff08; 2 x , 2 y &#xff09; z y^2-x^2: \nabla z (\frac{\partial z}{\partial x}, \frac{\partial z}{\partia…

夏日炎炎 水域守护:北斗守护安全防线——为生命撑起智能保护伞

随着夏季的来临&#xff0c;炎热的天气让许多人纷纷寻求水的清凉。清凉的河流与广阔的海域成为了不少人消暑降温的向往之地。然而&#xff0c;私自下河、下海的行为却暗藏着巨大的安全隐患&#xff0c;每年夏季溺水事故频发&#xff0c;给无数家庭带来不可挽回的悲痛。为有效遏…

规模弹性: 管理谷歌的TPUv4机器学习超级计算机

摘要 TPUv4&#xff08;张量处理单元&#xff09;是谷歌用于机器学习训练的第三代加速器&#xff0c;采用定制的三维环形互连&#xff0c;部署为 4096 节点的超级计算机。在本文中&#xff0c;我们将介绍设计和运行软件基础设施的经验&#xff0c;这些软件基础设施使 TPUv4 超…

Git进阶使用(图文详解)

文章目录 Git概述Git基础指令Git进阶使用一、Git分支1.主干分支2.其他分支2.1创建分支2.2查看分支1. 查看本地分支2. 查看远程分支3. 查看本地和远程分支4. 显示分支的详细信息5. 查看已合并和未合并的分支 2.3切换分支1. 切换到已有的本地分支2. 创建并切换到新分支3. 切换到远…

【SkiaSharp绘图03】SKPaint详解(一)BlendMode混合模式、ColorFilter颜色滤镜

文章目录 SKPaintSKPaint属性BlendMode获取或设置混合模式SKBlendMode 枚举成员效果预览 Color/ColorF获取或设置前景色ColorFilter 颜色滤镜CreateBlendMode 混合模式CreateColorMatrix 颜色转换CreateCompose 组合滤镜CreateHighContrast 高对比度滤镜CreateLighting 照明滤镜…

flask实战之模板实现公共导航

基础实现 目标 在Flask中&#xff0c;使用模板继承和块&#xff08;blocks&#xff09;可以方便地提取公共导航菜单&#xff0c;使得您可以在多个页面上重用相同的导航结构。以下是一个基本示例&#xff0c;展示如何创建一个包含公共导航菜单的模板&#xff1a; 创建基础模板…

译译交友项目介绍

一、 项目背景 随着社会的进步&#xff0c;英语作为一种国际语言&#xff0c;很多人都在学习英语&#xff0c;然而现在很多人都会因为学习英语而烦恼&#xff0c;有时还会因为是一个人学习而感到枯燥。面对情绪的低落&#xff0c;往往会使学习更困难。因此&#xff0c;我打造了…

MySQL系列-语法说明以及基本操作(二)

1、MySQL数据表的约束 1.1、MySQL主键 “主键&#xff08;PRIMARY KEY&#xff09;”的完整称呼是“主键约束”。 MySQL 主键约束是一个列或者列的组合&#xff0c;其值能唯一地标识表中的每一行。这样的一列或多列称为表的主键&#xff0c;通过它可以强制表的实体完整性。 …

微信小程序开发教程

尚硅谷微信小程序开发教程&#xff0c;2024最新版微信小程序项目实战&#xff01; 一、小程序基础 1. 初始小程序 微信小程序是一种运行在微信内部的 轻量级 应用程序。 使用小程序时 不需要下载&#xff0c;用户 扫一扫 或 搜一下 即可打开应用&#xff0c;它也体现了 “用…

【ARM Cache 及 MMU 系列文章 6.4 -- ARMv8/v9 如何读取 Cache Tag 及分析其数据?】

请阅读【ARM Cache 及 MMU/MPU 系列文章专栏导读】 及【嵌入式开发学习必备专栏】 文章目录 Cache Tag 数据读取测试代码Cache Tag 数据读取 在处理器中,缓存是一种快速存储资源,用于减少访问主内存时的延迟。缓存通过存储主内存中经常访问的数据来实现这一点。为了有效地管…