STM32的HAL库开发系列 - CAN通信实例

本文涉及的产品
数据传输服务 DTS,数据迁移 small 3个月
推荐场景:
MySQL数据库上云
数据传输服务 DTS,数据同步 small 3个月
推荐场景:
数据库上云
数据传输服务 DTS,数据同步 1个月
简介: STM32的HAL库开发系列 - CAN通信实例

CAN通信是一种高效、可靠、灵活的数据传输方式,适用于各种应用场景,在工业自动化、汽车电子、医疗设备等领域有着广泛的应用。

但理解CAN通信的实际应用,也不能全部只看软件方面,还需要对硬件上也有了解。

在硬件上,CAN通信使用两条线路:一条是数据线(CAN_H),另一条是地线(CAN_L)。数据线和地线之间的电压差表示了数据的“1”或“0”。数据传输采用非连续总线唤醒(Non-Continuous Dominant State)的方式,这意味着,当有节点需要发送数据时,它会把总线电压拉高,表示“1”,其他节点就会停止发送,并等待数据传输完成。这种方式能够有效地避免数据冲突,保证了数据的可靠性。

使用CAN通信的设备需要实现CAN控制器,它负责控制总线的电压,并检测和处理总线上的数据。在软件层面,需要使用CAN驱动程序来实现对CAN控制器的控制。

以下这段代码就是实际应用的举例。

/**
  * @brief            HAL库CAN FIFO0接受邮箱中断(Rx0)回调函数
  * @param            hcan : CAN句柄指针
  */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
    static BaseType_t xHigherPriorityTaskWoken = pdFALSE;    // 不请求上下文切换
    CAN_RxHeaderTypeDef RxHeader;                            // CAN通信协议头
    uint8_t rx_data[8] = {0};                                // 暂存CAN接收数据
    motor_measure_t motorDataTmp;                            // 电机数据
    uint8_t i = 0;
    
//    if (hcan == &hcan1)
    if (hcan->Instance == CAN1)
    {
        if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, rx_data) == HAL_OK)    // 接收CAN总线上发送来的数据
        {
            // 对应电机向总线上发送的反馈的标识符和程序电机序号
            switch (RxHeader.StdId) {
                case CAN_2006_M_ID : i = MotorID_ShootM; break;
                case CAN_PITCH_MOTOR_ID : i = MotorID_GimbalPitch; break;
                case CAN_YAW_MOTOR_ID : i = MotorID_GimbalYaw; break;
                #if DEBUGMODE
                default : i = RxHeader.StdId - CAN_3508_M1_ID; break;
                #else
                default : break;
                #endif
            }

            // 电机返回数据协议解析
            get_motor_measure(&motorDataTmp, rx_data);
            #if DEBUGMODE
                get_motor_measure(&motorData[i], rx_data);
            #endif

            // 向消息队列中填充数据
            if (messageQueueCreateFlag) {
                xQueueOverwriteFromISR(messageQueue[i], (void *)&motorDataTmp, &xHigherPriorityTaskWoken);
                portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
            }
        }
    }
}

对于CAN发送,相应的实例如下:

/**
  * @brief          发送C620电调控制电流
  * @param[in]        motorID对应的电机控制电流, 范围 [-16384, 16384],对应电调输出的转矩电流范围 [-20A, 20A]
  * @param[in]      etcID: 控制报文标识符(电调ID)为1-4还是5-8
  */
void CAN_Cmd_C620(CAN_HandleTypeDef *hcan, int16_t motor1, int16_t motor2, int16_t motor3, int16_t motor4, bool_t etcID)
{
    CAN_TxHeaderTypeDef TxHeader;                        // CAN通信协议头
    uint8_t TxData[8] = {0};                            // 发送电机指令缓存
    uint32_t TxMailboxX = CAN_TX_MAILBOX0;                // CAN发送邮箱

    if (etcID == false) {
        TxHeader.StdId = CAN_3508_ALL_ID;                // 标准格式标识符ID
    } else {
        TxHeader.StdId = CAN_3508_ETC_ID;
    }
    TxHeader.ExtId = 0;
    TxHeader.IDE = CAN_ID_STD;                            // 标准帧
    TxHeader.RTR = CAN_RTR_DATA;                        // 传送帧类型为数据帧
    TxHeader.DLC = 0x08;                                // 数据长度码
    TxData[0] = (uint8_t)(motor1 >> 8);
    TxData[1] = (uint8_t)motor1;
    TxData[2] = (uint8_t)(motor2 >> 8);
    TxData[3] = (uint8_t)motor2;
    TxData[4] = (uint8_t)(motor3 >> 8);
    TxData[5] = (uint8_t)motor3;
    TxData[6] = (uint8_t)(motor4 >> 8);
    TxData[7] = (uint8_t)motor4;

    //找到空的发送邮箱
    while (HAL_CAN_GetTxMailboxesFreeLevel(hcan) == 0);    // 如果三个发送邮箱都阻塞了就等待直到其中某个邮箱空闲
    if ((hcan->Instance->TSR & CAN_TSR_TME0) != RESET) {
        // 检查发送邮箱0状态 如果邮箱0空闲就将待发送数据放入FIFO0
        TxMailboxX = CAN_TX_MAILBOX0;
    } else if ((hcan->Instance->TSR & CAN_TSR_TME1) != RESET) {
        TxMailboxX = CAN_TX_MAILBOX1;
    } else if ((hcan->Instance->TSR & CAN_TSR_TME2) != RESET) {
        TxMailboxX = CAN_TX_MAILBOX2;
    }
    // 将数据通过CAN总线发送
    #if DEBUGMODE
        if (HAL_CAN_AddTxMessage(hcan, &TxHeader, TxData, (uint32_t *)TxMailboxX) != HAL_OK) {
            Error_Handler();                            // 如果CAN信息发送失败则进入死循环
        }
    #else
        HAL_CAN_AddTxMessage(hcan, &TxHeader, TxData, (uint32_t *)TxMailboxX);
    #endif
}

另外,CAN通信还具有较高的安全性。例如,它使用了校验和机制来检测数据传输中的错误,并使用了访问控制机制来限制对总线的访问。

在实际应用中,CAN通信还有许多标准,如:

CAN 2.0A: 这是最早的标准,支持11位帧ID和8字节数据。
CAN 2.0B: 与2.0A相比,它增加了29位帧ID和支持高速模式。
CAN FD (Flexible Data-rate) : 这是最新的标准,支持高达64字节的数据帧和更高的通信速率。

同时,由于其在工业、汽车等领域的广泛应用,也有许多标准化组织和协会为其制定了专门的应用标准,如:

J1939: 这是专门为汽车应用设计的标准,它定义了许多特定的应用层协议。
DeviceNet: 这是专门为工业自动化应用设计的标准,它定义了许多特定的应用层协议。

总之,CAN通信是一种高效、可靠、灵活的数据传输方式,适用于各种应用场景,并有许多标准和协议来支持其在不同领域的应用,是一种非常重要的通信技术。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
Sqoop 企业级大数据迁移方案实战
Sqoop是一个用于在Hadoop和关系数据库服务器之间传输数据的工具。它用于从关系数据库(如MySQL,Oracle)导入数据到Hadoop HDFS,并从Hadoop文件系统导出到关系数据库。 本课程主要讲解了Sqoop的设计思想及原理、部署安装及配置、详细具体的使用方法技巧与实操案例、企业级任务管理等。结合日常工作实践,培养解决实际问题的能力。本课程由黑马程序员提供。
目录
相关文章
|
4月前
stm32f407探索者开发板(十七)——串口寄存器库函数配置方法
stm32f407探索者开发板(十七)——串口寄存器库函数配置方法
700 0
|
1月前
【寄存器开发速成】半小时入门STM32寄存器开发(二)
【寄存器开发速成】半小时入门STM32寄存器开发(二)
|
1月前
|
芯片
【寄存器开发速成】半小时入门STM32寄存器开发(一)
【寄存器开发速成】半小时入门STM32寄存器开发(一)
|
5月前
|
IDE 开发工具
使用STM32F103标准库实现自定义键盘
通过本文,我们学习了如何使用STM32F103标准库实现一个简单的自定义键盘。我们首先初始化了GPIO引脚,然后实现了一个扫描函数来检测按键状态。这个项目不仅能够帮助我们理解STM32的GPIO配置和按键扫描原理,还可以作为进一步学习中断处理和低功耗设计的基础。希望本文对你有所帮助,祝你在嵌入式开发的道路上不断进步!
506 4
|
5月前
|
存储 数据采集 数据安全/隐私保护
使用STM32F103读取TF卡并模拟U盘:使用标准库实现
通过以上步骤,你可以实现用STM32F103将TF卡内容变成U盘进行读取。这种功能在数据采集、便携式存储设备等应用中非常有用。如果你有更多的需求,可以进一步扩展此项目,例如添加文件管理功能、加密存储等。希望这篇博客能帮到你,如果有任何问题,欢迎在评论区留言讨论!
230 1
|
4月前
|
监控
stm32f407探索者开发板(十八)——串口通信实验讲解(USART_RX_STA流程图详解)
stm32f407探索者开发板(十八)——串口通信实验讲解(USART_RX_STA流程图详解)
280 0
|
4月前
stm32f407探索者开发板(十六)——串行通信原理讲解-UART
stm32f407探索者开发板(十六)——串行通信原理讲解-UART
264 0
|
4月前
|
传感器 编解码 API
【STM32开发入门】温湿度监测系统实战:SPI LCD显示、HAL库应用、GPIO配置、UART中断接收、ADC采集与串口通信全解析
SPI(Serial Peripheral Interface)是一种同步串行通信接口,常用于微控制器与外围设备间的数据传输。SPI LCD是指使用SPI接口与微控制器通信的液晶显示屏。这类LCD通常具有较少的引脚(通常4个:MISO、MOSI、SCK和SS),因此在引脚资源有限的系统中非常有用。通过SPI协议,微控制器可以向LCD发送命令和数据,控制显示内容和模式。
157 0
|
5月前
使用STM32F103标准库实现定时器控制LED点亮和关闭
通过这篇博客,我们学习了如何使用STM32F103标准库,通过定时器来控制LED的点亮和关闭。我们配置了定时器中断,并在中断处理函数中实现了LED状态的切换。这是一个基础且实用的例子,适合初学者了解STM32定时器和中断的使用。 希望这篇博客对你有所帮助。如果有任何问题或建议,欢迎在评论区留言。
431 2
|
6月前
|
传感器
STM32标准库ADC和DMA知识点总结-1
STM32标准库ADC和DMA知识点总结