当前位置: 首页
AI教程
STM32F105 CAN总线双机通信代码实现

STM32F105 CAN总线双机通信代码实现

热心网友 时间:2026-06-09
转载

基于STM32F105系列,采用标准外设库和CAN1实现双机通信,涵盖GPIO配置、中断设置、工作模式与波特率配置、过滤器设置,以及发送函数与接收中断服务函数。通过ID分配和过滤器配置实现双机配对,主函数中循环发送数据。

对于从事嵌入式开发的朋友来说,CAN总线通信的需求十分常见。本文以STM32F105系列微控制器为例,基于标准外设库,使用CAN1外设,提供一套完整的双机通信代码实现方案。整个流程涵盖初始化、数据发送、接收以及双机配对的关键配置,下面我们逐步展开。

基于STM32F105系列使用CAN总线实现双机通信代码

1. CAN总线初始化

初始化是CAN通信的基础环节,涉及GPIO配置、中断设置、工作模式与波特率设定以及过滤器配置,每一步都不可或缺。请看具体代码实现:

#include "stm32f10x.h"
#include "stm32f10x_can.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "misc.h"

// CAN初始化结构体
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CanTxMsg TxMessage;
CanRxMsg RxMessage;

void CAN_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    // 使能GPIO和CAN时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

    // 配置CAN引脚: PA11->RX, PA12->TX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;   // TX
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  // 推挽复用输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;   // RX
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  // 上拉输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void CAN_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

    // 配置CAN接收中断
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

void CAN_Mode_Config(void)
{
    CAN_DeInit(CAN1);
    CAN_StructInit(&CAN_InitStructure);

    // CAN工作模式配置
    CAN_InitStructure.CAN_TTCM = DISABLE;  // 禁止时间触发通信模式
    CAN_InitStructure.CAN_ABOM = DISABLE;  // 禁止自动离线管理
    CAN_InitStructure.CAN_AWUM = DISABLE;  // 禁止自动唤醒模式
    CAN_InitStructure.CAN_NART = DISABLE;  // 禁止自动重传
    CAN_InitStructure.CAN_RFLM = DISABLE;  // 禁止FIFO锁定
    CAN_InitStructure.CAN_TXFP = DISABLE;  // 禁止发送FIFO优先级

    // 配置波特率
    // CAN波特率 = APB1时钟 / ((CAN_BS1 + CAN_BS2 + 1) * CAN_Prescaler)
    // 假设APB1时钟为36MHz,波特率设为500kbps
    CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq;   // 时间段1
    CAN_InitStructure.CAN_BS2 = CAN_BS2_4tq;   // 时间段2
    CAN_InitStructure.CAN_Prescaler = 6;         // 分频系数
    // 总时间片 = 1 + 9 + 4 = 14
    // 波特率 = 36MHz / (14 * 6) = 428.57kHz (接近500k)

    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;  // 正常工作模式
    CAN_Init(CAN1, &CAN_InitStructure);

    // 配置CAN过滤器
    CAN_FilterInitStructure.CAN_FilterNumber = 0;     // 使用过滤器0
    CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;  // 掩码模式
    CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; // 32位模式
    CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;  // 要过滤的ID高位
    CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;   // 要过滤的ID低位
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;  // 掩码高位
    CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;   // 掩码低位
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;  // 关联到FIFO0
    CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;  // 启用过滤器
    CAN_FilterInit(&CAN_FilterInitStructure);

    // 使能CAN接收中断
    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
}

2. CAN数据发送函数

发送部分的逻辑非常清晰:先构建发送帧结构体,填充ID、数据长度及具体内容,然后调用发送接口并等待传输完成。注意增加超时处理,避免程序陷入死等状态。

uint8_t CAN_Send_Msg(uint8_t* msg, uint8_t len, uint32_t id)
{
    uint8_t i = 0;
    uint8_t transmit_mailbox = 0;

    TxMessage.StdId = id;          // 标准ID
    TxMessage.ExtId = 0x00;        // 扩展ID
    TxMessage.IDE = CAN_Id_Standard;  // 标准帧
    TxMessage.RTR = CAN_RTR_Data;     // 数据帧
    TxMessage.DLC = len;              // 数据长度(最大8字节)

    // 填充数据
    for(i = 0; i < len; i++)
    {
        TxMessage.Data[i] = msg[i];
    }

    // 发送数据
    transmit_mailbox = CAN_Transmit(CAN1, &TxMessage);

    // 等待发送完成
    i = 0;
    while((CAN_TransmitStatus(CAN1, transmit_mailbox) != CANTXOK) && (i < 0xFF))
    {
        i++;
    }
    if(i >= 0xFF)
    {
        return 1;  // 发送失败
    }
    return 0;  // 发送成功
}

3. CAN数据接收中断服务函数

接收采用中断方式,效率更高。进入中断后先检查标志位,再读取FIFO中的数据存入缓冲区,记得清除中断标志。缓冲区内容可后续处理,例如转发至串口或触发其他控制逻辑。

void USB_LP_CAN1_RX0_IRQHandler(void)
{
    static uint8_t receive_buffer[8];

    if(CAN_GetITStatus(CAN1, CAN_IT_FMP0) != RESET)
    {
        // 读取接收到的数据
        CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);

        // 清除中断标志
        CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0);

        // 处理接收到的数据
        if(RxMessage.IDE == CAN_Id_Standard)
        {
            uint8_t i;
            // 复制接收到的数据
            for(i = 0; i < RxMessage.DLC; i++)
            {
                receive_buffer[i] = RxMessage.Data[i];
            }
            // 在这里处理接收到的数据
            // 例如:将数据发送到串口或进行其他处理
            // Process_Received_Data(receive_buffer, RxMessage.DLC, RxMessage.StdId);
        }
    }
}

4. 主函数示例

主函数中演示了周期性发送的典型用法:先初始化系统时钟和CAN外设,然后在主循环中每隔1秒发送一帧数据。实际项目可根据需求调整发送频率或添加条件触发机制。

int main(void)
{
    uint8_t send_data[8] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
    uint32_t message_id = 0x123;  // CAN消息ID

    // 初始化系统时钟
    SystemInit();

    // 配置GPIO
    CAN_GPIO_Config();

    // 配置NVIC中断
    CAN_NVIC_Config();

    // 配置CAN模式
    CAN_Mode_Config();

    // 主循环
    while(1)
    {
        // 每隔1秒发送一次数据
        Delay(1000);  // 自定义延时函数

        // 发送CAN消息
        CAN_Send_Msg(send_data, 8, message_id);

        // 可以在这里添加其他处理逻辑
    }
}

5. 双机通信配置说明

要使两个设备正常通信,ID分配和过滤器设置是关键。以设备A作为发送方、设备B作为接收方为例:

设备A配置(发送设备):

// 设置设备A的ID为0x100
uint32_t device_a_id = 0x100;

设备B配置(接收设备):

// 配置过滤器只接收来自设备A的消息
CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0100 << 5;  // ID高16位
CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;         // ID低16位
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;    // 掩码高位
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;     // 掩码低位

6. 完整的工程配置步骤

硬件连接:

  • CAN_H 连接 CAN_H
  • CAN_L 连接 CAN_L
  • 两个设备的GND相连
  • 在总线的两端接120Ω终端电阻

软件配置:

// 波特率计算
// 假设系统时钟为72MHz,APB1时钟为36MHz
// 500kbps配置:BS1=9, BS2=4, Prescaler=6
// 1Mbps配置:BS1=9, BS2=4, Prescaler=3

编译和下载:

  • 使用Keil MDK或STM32CubeIDE
  • 确保包含正确的头文件
  • 配置正确的系统时钟

注意事项

  • 终端电阻:必须在CAN总线的两端各接一个120Ω的终端电阻
  • 波特率:两个设备的波特率必须相同
  • 中断优先级:根据实际应用需求合理配置中断优先级
  • 错误处理:在实际应用中应添加错误检测和重发机制
  • ID冲突:确保每个设备的CAN ID唯一,避免冲突
来源:https://developer.aliyun.com/article/1740288

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
LangChain高效部署实战:NVIDIA CUDA环境配置与模型选择指南

LangChain高效部署实战:NVIDIA CUDA环境配置与模型选择指南

围绕LangChain本地部署与NVIDIACUDA环境配置,梳理硬件确认、驱动安装、Python环境、深度学习框架验证、模型选择和常见故障处理,帮助开发者搭建稳定高效的AI应用运行环境。

时间:2026-07-19 06:10
免费方案FastGPT安装教程:数据目录迁移全流程与常见问题汇总

免费方案FastGPT安装教程:数据目录迁移全流程与常见问题汇总

FastGPT免费自部署适合个人测试和小团队试用,迁移数据目录前需确认组件路径、完整备份、停服复制、校验权限,并准备回滚方案,避免因卷挂载错误导致知识库、账号或配置丢失。

时间:2026-07-19 06:09
Dify注册登录与账号配置教程(国内可用,附下载地址与环境要求)

Dify注册登录与账号配置教程(国内可用,附下载地址与环境要求)

Dify可通过云端或本地部署使用,注册登录前需确认浏览器、服务器、Docker与模型接口条件,并完成账号、团队、密钥、知识库权限等配置,注意数据安全与版本兼容。

时间:2026-07-19 06:09
Open WebUI安装配置全攻略及多用户权限设置

Open WebUI安装配置全攻略及多用户权限设置

OpenWebUI适合为本地大模型提供类聊天产品界面,可对接Ollama与兼容接口。部署重点在运行环境、模型连接、账号注册、角色分配、模型可见范围和外部访问安全控制。

时间:2026-07-19 06:08
LocalAI安装环境配置与中文汉化教程 快速上手检查清单

LocalAI安装环境配置与中文汉化教程 快速上手检查清单

LocalAI适合在本机或内网部署类OpenAI接口服务,安装前需确认系统、Docker、模型格式与硬件资源。配置重点包括模型目录、服务端口、中文提示词、接口测试和权限控制。

时间:2026-07-19 06:08
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 热门数据榜