基于STM32微控制器的CAN总线消息发送调度系统

13 篇文章 0 订阅


前言

CAN(Controller Area Network)总线是一种用于车辆内部通信的强大协议,适用于实时应用。在汽车电子系统中,消息的及时发送和调度至关重要。本文介绍了一种基于STM32微控制器的CAN总线消息发送调度系统,通过消息池和定时发送机制,确保CAN消息按时且有序地发送。


一、使用步骤

1.定义CAN消息数组

首先,定义一个包含多个CAN消息的数组,每个消息包括消息ID、数据、数据长度、发送间隔和下一次发送时间。

#include "can_signal_pool.h"

// 定义CAN消息数组
CAN_Message can_messages[] = {
    {0X200, {0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00}, 8, 200, 0},
    {0X201, {0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00}, 8, 180, 0}, 
    {0X202, {0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00}, 8, 500, 0},
};

2.定义时间和最小公倍数计算函数

为了确保消息按设定的时间间隔发送,我们需要计算当前时间以及所有消息间隔的最小公倍数

// 当前时间,单位:毫秒
uint32_t current_time = 0;

// 当前消息数组中所有间隔的最小公倍数
uint32_t lcm_interval = 1;

// 计算两个数的最大公约数
uint32_t gcd(uint32_t a, uint32_t b) {
    while (b != 0) {
        uint32_t temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

// 计算两个数的最小公倍数
uint32_t lcm(uint32_t a, uint32_t b) {
    return (a * b) / gcd(a, b);
}

3.检查并发送CAN消息函数

该函数用于判断是否到达发送CAN消息的时间间隔,并发送需要发送的消息。同时还会检查是否到达所有消息间隔的整数倍,以完成一轮循环发送。

/**
 * @brief  判断是否到达发送CAN消息的时间间隔以及完成一轮循环发送的函数
 * @note   该函数用于检查是否到达发送CAN消息的时间间隔,并发送需要发送的消息。
 *         同时,该函数还会检查是否到达所有消息间隔的整数倍,以完成一轮循环发送。
 * @retval None
 */
void CheckCANMessages(CAN_Message* can_messages, u8 len) {
    static u8 heartbeat1;
    // 初始化lcm_interval为所有间隔的最小公倍数
    for (int i = 0; i < len; i++) {
        lcm_interval = lcm(lcm_interval, can_messages[i].interval);
    }
    // 判断是否到达发送CAN消息的时间间隔
    for (int i = 0; i < len; i++) {
        if (T1.CAN_send_Ms > can_messages[i].next_send_time) {
            // 发送当前消息
            CAN2_Send_Msg_WithPool(can_messages[i].id, can_messages[i].data, can_messages[i].length);
            // 更新下一条消息的发送时间
            can_messages[i].next_send_time = T1.CAN_send_Ms + can_messages[i].interval;
        }
    }

    // 检查是否到达所有消息间隔的整数倍
    if (T1.CAN_send_Ms % lcm_interval == 0) {
        T1.CAN_send_Ms = 0; 
        for (int i = 0; i < len; i++) {
            can_messages[i].next_send_time = 0;
        }
    }
}

4.CAN消息池与发送调度

为了避免消息发送过程中出现阻塞,我们使用消息池存储待发送的CAN消息,并按顺序从消息池中发送消息。

// CAN消息池
CAN_Msg Msg_Pool[100];
u8 Msg_Index, Msg_Count;

/**
* @brief  将CAN消息存入消息池中
* @param  canid: CAN消息的ID
* @param  msg: 指向CAN消息数据的指针
* @param  len: CAN消息数据的长度
* @retval None
*/
void CAN_Send_Msg_WithPool(u32 canid, u8* msg, u8 len) {
    // 如果消息池未满
    if (Msg_Count <= 100) {
        u8 index = (Msg_Index + Msg_Count) % 100; // 计算下一个可用位置的索引
        memcpy(Msg_Pool[index].buf, msg, 8); // 复制消息数据到消息池中
        Msg_Pool[index].ID = canid; // 设置消息ID
        Msg_Pool[index].Length = len; // 设置消息长度
        Msg_Count++; // 增加消息计数
    }
}

/**
* @brief  从消息池中按顺序发送CAN消息
* @param  None
* @retval None
*/
void CAN_Send_Msg_Schedule() {
    // 如果消息池中有消息
    if (Msg_Count > 0) {
        Can_Send_Msg(Msg_Pool[Msg_Index].ID, Msg_Pool[Msg_Index].buf, Msg_Pool[Msg_Index].length); // 发送消息
        Msg_Index++; // 移动索引到下一条消息
        Msg_Count--; // 减少消息计数
        if (Msg_Index == 100) {
            Msg_Index = 0; // 如果索引达到消息池末尾,则重置为起始位置
        }
    }
}

总结

通过本文介绍的代码实现,我们成功地在STM32微控制器上构建了一个高效的CAN总线消息发送调度系统。该系统不仅能够按设定的时间间隔发送CAN消息,还能通过消息池机制避免发送过程中的阻塞。在实际应用中,可以根据具体需求对发送间隔和消息池进行调整,以满足更多的功能需求。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值