bxCAN总线Loopback功能实现(STM32F4xx)

news2024/9/29 19:31:00

目录

概述

1 认识bxCAN Loopback

1.1 环回模式

1.2 环回模式特点

2 使用STM32CubeMX 生成工程

2.1 参数配置

2.2 生成工程代码

2.4 了解can.c

3 认识Hal库中的bxCAN

3.1 认识3个重要数据结构

3.2 函数组

3.2.1 初始化函数组

3.2.2 控制函数组

3.2.3 中断管理函数组

3.2.4 中断回调函数组

4 实现bxCAN Loopback功能

4.1 初始化筛选器结构

4.2 发送数据函数

4.3 中断回调函数

4.5 完整代码

5 测试

5.1 编写测试代码

5.2 测试


源代码下载地址: stm32-bxCAN-Loopback测试程序,使用MCU:STM32F407IGX资源-CSDN文库

概述

本文主要介绍STM32F4XX的外设bxCAN的一个重要测试功能: Loopback。包括其实现原理,寄存器配置,代码实现,且还介绍了实现该功能的一些函数接口。并编写测试程序验证其功能。

1 认识bxCAN Loopback

1.1 环回模式

配置环回模式方法可以通过将 CAN_BTR 寄存器的 LBKM 位置 1,将 bxCAN 置于环回模式。

CAN 位时序寄存器 (CAN_BTR)

1.2 环回模式特点

1)在环回模式下,bxCAN 将其自身发送的消息作为接收的消息来处理并存储(如果这些消息通过了验收筛选)在接收邮箱中。

2)该模式为自检功能提供。为了不受外部事件的影响, CAN 内核在环回模式下将忽略确认错误(在数据/远程帧的确认时隙不对显性位采样)。

3)在此模式下, bxCAN 将执行从发送输出到接收输入的内部反馈。 bxCAN 将忽略 CANRX 输入引脚的实际值。从 CANTX 引脚可以监视发送的消息

2 使用STM32CubeMX 生成工程

2.1 参数配置

1) 配置RCC,使能外部晶振

2) GPIO Setting

本测试使用CAN1,与之相关的IO为PH13和PI9

3)CAN Parameter Settings

4) NVIC Setting

2.2 生成工程代码

在Project Manger选项卡中作如下配置,点击GENERATE CODE 生成工程代码。

打开工程文件如下:

2.4 了解can.c

使用STM32CubeMX 生成的工程文件,已经将需要的外设已经做了配置。本文重点介绍和CAN相关的接口,打开can.c可以看到:

在MX_CAN1_Init()中,主要实现can相关参数的配置

在HAL_CAN_MspInit()中配置IO,使其复用到CAN功能。

3 认识Hal库中的bxCAN

3.1 认识3个重要数据结构

1) CAN筛选器结构体

typedef struct {
    uint16_t CAN_FilterIdHigh;            /*CAN_FxR1寄存器的高16位 */
    uint16_t CAN_FilterIdLow;             /*CAN_FxR1寄存器的低16位*/
    uint16_t CAN_FilterMaskIdHigh;        /*CAN_FxR2寄存器的高16位*/
    uint16_t CAN_FilterMaskIdLow;         /*CAN_FxR2寄存器的低16位 */
    uint16_t CAN_FilterFIFOAssignment;     /*设置经过筛选后数据存储到哪个接收FIFO */

    uint8_t CAN_FilterNumber;              /*筛选器编号,范围0-27*/
    uint8_t CAN_FilterMode;                /*筛选器模式 */
    uint8_t CAN_FilterScale;               /*设置筛选器的尺度 */
    FunctionalState CAN_FilterActivation;  /*是否使能本筛选器*/
} CAN_FilterInitTypeDef;

2) 发送/接收结构体

/**
* 发送结构体
*/
typedef struct {
    uint32_t StdId;  /*存储报文的标准标识符11位,0-0x7FF. */
    uint32_t ExtId;  /*存储报文的扩展标识符29位,0-0x1FFFFFFF. */
    uint8_t IDE;     /*存储IDE扩展标志 */
    uint8_t RTR;     /*存储RTR远程帧标志*/
    uint8_t DLC;     /*存储报文数据段的长度,0-8 */
    uint8_t Data[8]; /*存储报文数据段的内容 */
} CanTxMsg;

/**
* 接收结构体
*/
typedef struct {
    uint32_t StdId;  /*存储了报文的标准标识符11位,0-0x7FF. */
    uint32_t ExtId;  /*存储了报文的扩展标识符29位,0-0x1FFFFFFF. */
    uint8_t IDE;     /*存储了IDE扩展标志 */
    uint8_t RTR;     /*存储了RTR远程帧标志*/
    uint8_t DLC;     /*存储了报文数据段的长度,0-8 */
    uint8_t Data[8]; /*存储了报文数据段的内容 */
    uint8_t FMI;     /*存储了 本报文是由经过筛选器存储进FIFO的,0-0xFF */
} CanRxMsg;

3.2 函数组

3.2.1 初始化函数组

使用STM32CubeMX 生成工程中,这部分接口STM32CubeMX已经将其在合适的位置,无需程序员在重新调用。

3.2.2 控制函数组

3.2.3 中断管理函数组

3.2.4 中断回调函数组

4 实现bxCAN Loopback功能

创建stm32f4_drv_can.c 文件,编写代码

4.1 初始化筛选器结构

static void CAN_Drv_fitter( CAN_HandleTypeDef *hcan )
{
    CAN_FilterTypeDef filterStru;
    
    filterStru.FilterActivation  = ENABLE;
    filterStru.FilterBank = 0;
    filterStru.FilterFIFOAssignment = CAN_FILTER_FIFO0;   //帅选后的数据存储在FIFO0
    
    filterStru.FilterIdHigh = 0;
    filterStru.FilterIdLow = 0;
    
    filterStru.FilterMaskIdHigh = 0;
    filterStru.FilterMaskIdLow = 0;
    
    filterStru.FilterMode = CAN_FILTERMODE_IDMASK;   //配置过滤模式:IDMASK
    filterStru.FilterScale = CAN_FILTERSCALE_32BIT;  //设置筛选器的尺度: 32 bit
    
    filterStru.SlaveStartFilterBank = 0;
    
    HAL_CAN_ConfigFilter( hcan, &filterStru);
}

4.2 发送数据函数

void CAN_Drv_sendMessage( CAN_HandleTypeDef *hcan, 
                          uint8 *databuff, uint8 datalen, 
                          uint32 stdId , uint32 extId, uint32 ide)
{
    uint32 txMailbox;
    CAN_TxHeaderTypeDef txHdrStru;  
    
    
    txHdrStru.DLC = datalen;  /*发送的数据长度*/
    
    txHdrStru.ExtId = extId;  /*报文的扩展标识符 ID */
    txHdrStru.StdId = stdId;  /*报文的标准标识符 ID */
    
     /*
        ide = CAN_ID_STD  标准帧
        ide = CAN_ID_EXT  扩展帧
      */
    txHdrStru.IDE = ide;  
    txHdrStru.RTR = CAN_RTR_DATA;  /*RTR远程帧标志 */
    
    txHdrStru.TransmitGlobalTime = DISABLE;
    
    HAL_CAN_AddTxMessage( hcan, &txHdrStru, databuff, &txMailbox);
}

4.3 中断回调函数

CAN0的中断函数void CAN1_RX0_IRQHandler(void)会自动调用该函数。主要实现数据接收和解析

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
    uint8_t recv_data[8];
    CAN_RxHeaderTypeDef header;

    // 从FIFO读取数据
    HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &header, recv_data);
    if(header.IDE == CAN_ID_STD)
    {
        printf("StdId ID: 0x%x\n",header.StdId);
    }
    else
    {
        printf("ExtId ID:%d\n",header.ExtId);
    }
    
    printf("CAN IDE:0x%x\n",header.IDE);
    printf("CAN RTR:0x%x\n",header.RTR);
    printf("CAN DLC:0x%x\n",header.DLC);
    printf("RECV DATA:");
    
    printf("%s \n",recv_data);
    printf("\n");
}

4.5 完整代码

/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * File Name          : stm32f4_drv_can.c
 * Description        : Code for board can driver
 ******************************************************************************
 * @attention
 *
 * Copyright (c) mingfei.tang
 * All rights reserved.
 *
 ******************************************************************************
 */
/* USER CODE END Header */
#include "can.h"
#include "stm32f4_drv_can.h"

static void CAN_Drv_fitter( CAN_HandleTypeDef *hcan );

void CAN_Drv_Init( CAN_HandleTypeDef *hcan )
{
    CAN_Drv_fitter( hcan );    //初始化过滤器
    HAL_CAN_Start( hcan );     //启动CAN
    HAL_CAN_ActivateNotification(hcan,CAN_IT_RX_FIFO0_MSG_PENDING);  //接收触发方式 
}

void CAN_Drv_sendMessage( CAN_HandleTypeDef *hcan, 
                          uint8 *databuff, uint8 datalen, 
                          uint32 stdId , uint32 extId, uint32 ide)
{
    uint32 txMailbox;
    CAN_TxHeaderTypeDef txHdrStru;
    
    txHdrStru.DLC = datalen;
    
    txHdrStru.ExtId = extId;
    txHdrStru.StdId = stdId;
    
    txHdrStru.IDE = ide;
    txHdrStru.RTR = CAN_RTR_DATA;
    
    txHdrStru.TransmitGlobalTime = DISABLE;
    
    HAL_CAN_AddTxMessage( hcan, &txHdrStru, databuff, &txMailbox);
}


static void CAN_Drv_fitter( CAN_HandleTypeDef *hcan )
{
    CAN_FilterTypeDef filterStru;
    
    filterStru.FilterActivation  = ENABLE;
    filterStru.FilterBank = 0;
    filterStru.FilterFIFOAssignment = CAN_FILTER_FIFO0;
    
    filterStru.FilterIdHigh = 0;
    filterStru.FilterIdLow = 0;
    
    filterStru.FilterMaskIdHigh = 0;
    filterStru.FilterMaskIdLow = 0;
    
    filterStru.FilterMode = CAN_FILTERMODE_IDMASK;
    filterStru.FilterScale = CAN_FILTERSCALE_32BIT;
    
    filterStru.SlaveStartFilterBank = 0;
    
    HAL_CAN_ConfigFilter( hcan, &filterStru);
}

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
    uint8_t recv_data[8];
    CAN_RxHeaderTypeDef header;

    HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &header, recv_data);
    if(header.IDE == CAN_ID_STD)
    {
        printf("StdId ID: 0x%x \n",header.StdId);
    }
    else
    {
        printf("ExtId ID:0x%x \n",header.ExtId);
    }
    
    printf("CAN IDE:0x%x\n",header.IDE);
    printf("CAN RTR:0x%x\n",header.RTR);
    printf("CAN DLC:0x%x\n",header.DLC);
    printf("RECV DATA:");
    
    printf("%s \n",recv_data);
    printf("\n");
}


/* End of this file */

5 测试

5.1 编写测试代码

在main.c文件中实现如下函数:

1) 发送接口

void test_can1_send( void )
{
    static uint8 i = 0;
    uint32 stdId , extId, ide;
    uint8 sendBuff[8] ="can-1:";

    sendBuff[6] = 0X30 + i; 
    sendBuff[7] = 0X30 + i +1; 
    stdId = 0x321;
    extId = 2;
    ide = CAN_ID_STD;
    CAN_Drv_sendMessage( &hcan1, sendBuff, sizeof(sendBuff), stdId, extId, ide);
    i++;
}

2)执行函数中,主要做键盘扫描,当按键按下时,发送一次数据

void tick_action( void )
{
   static bool flag_1s = 0;
   static unsigned int tick_cnt = 0;
   static unsigned int beforTick = 0;
   unsigned int currentTick;
   unsigned char val;
    
   currentTick = HAL_GetTick();
   if(beforTick != currentTick )
   {
       beforTick = currentTick;
       tick_cnt++;
       
       // 1s action
       if( (tick_cnt % 1000) == 0) 
       {
          flag_1s = true;;
       }
       
       //1ms action
       bsp_KeyMonitor();
   }
   
    if( flag_1s )
    {
        flag_1s = false;
        HAL_GPIO_TogglePin(SYS_RUN_LED_GPIO_Port, SYS_RUN_LED_Pin);
    }
    
    // send CAN packet 
    val = bsp_KeyGetValue( KEY_1 );
    if( val  )
    {
        test_can1_send();
    }
}

3) main()函数中初始化CAN配置,在while(1)下执行tick_action()

5.2 测试

编译代码,将代码下载到板卡中测试。每按下一次按键,发送数据的值都会加1,接收中断函数也能正确的接受到数据。

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

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

相关文章

【风格迁移】pix2pixHD:高分辨率图像生成

pix2pixHD:高分辨率图像生成 提出背景问题1: 如何提高生成图像的照片级真实感和分辨率?问题2: 如何利用实例级别的对象语义信息进一步提高图像质量?问题3: 如何实现图像合成的多模态性,允许交互式对象编辑? pix2pixHD …

【STK】手把手教你利用STK进行仿真-STK软件基础01 STK的对象组织模式

STK系统采用面向对象和分级组织结构的管理模式对仿真对象进行管理,这种组织二行管理模式非常符合人类的认知习惯,易于理解。STK最基本的对象为场景(Scenario),在场景中可以面向对象和分级组织模式对各场景中的仿真对象…

[c++] c++ 中的顺序(构造,析构,初始化列表,继承)

对象构造的时候,对象成员变量的初始化顺序是什么样的 ? 派生类构造的时候,先构造基类还是先构造派生类 ? 构造函数中的初始化列表,初始化的顺序是列表的顺序吗 ? 析构的时候,析构的顺序是什么…

华为数通方向HCIP-DataCom H12-821题库(多选题:41-60)

第41题 BGP OPEN消息中携带如下哪些信息? A、路由属性 B、BGP Router ID C、Hold time D、本地自治系统(AS)号 【参考答案】BCD 【答案解析】 B. BGP Router ID:OPEN消息中包含发送方BGP路由器的Router ID,用于唯一标识BGP路由器。C.Hold time:OPEN消息中包含发送方BGP路由…

区块链媒体发布推广10个热门案例解析-华媒舍

区块链技术的发展已经引起了媒体的广泛关注,越来越多的区块链媒体纷纷发布推广相关的热门案例。本文将介绍10个成功的区块链媒体推广案例,并分享它们的成功秘诀,帮助读者更好地了解区块链媒体推广的方法与技巧。 随着区块链技术的成熟和应用场…

vue2本地开发环境正常,生产环境下this.$router.push({ name: ‘login‘ })不跳转

如果在Vue.js 2中在本地开发环境下正常运行,但在生产环境下使用​​this.$router.push({ name: login })​​不起作用,可能有几个原因需要检查和解决: 路由配置问题: 确保你的路由配置正确,特别是确保在生产环境中,路由的配置和本地开发环境一致。检查是否正确设置了name…

课程表系列(BFS)

广度优先搜索 文章目录 广度优先搜索207. 课程表210. 课程表 II思路 630. 课程表 III1462. 课程表 IV547. 省份数量 207. 课程表 207. 课程表 你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程…

多元函数积分思路合集

[曲线积分笔记]第一类曲线积分 [微积分笔记]第二类曲线/面积分总结 积分方法意义/提示平面第二型曲线积分化为定积分 ∮ L → ∫ a b \oint_L \to \int_a^b ∮L​→∫ab​平面第二型曲线积分格林公式 ∮ L → ∬ D \oint_L \to \iint_D ∮L​→∬D​化为对平面区域的二重积分空…

百度搜索引擎SEO优化方法

随着互联网的不断发展,搜索引擎已经成为人们获取信息、产品和服务的主要途径之一。而在中国,百度作为最大的搜索引擎,其影响力不可忽视。了解并掌握百度SEO关键词优化方法,对于提升网站在搜索引擎中的排名至关重要。 关键词选择&a…

chatgpt-3的文章生成器有哪些?可以批量生成文章的生成器

GPT-3(Generative Pre-trained Transformer 3)作为人工智能领域的一项重大突破,开启了新一代的文本生成技术。同时市面上也涌现出了一些GPT-3文章生成器,为用户提供了快速、高效地生成各种类型文章的工具。本文将介绍一些中国的GP…

JS:原型与原型链(附带图解与代码)

一、原型 写在前面: 任何对象都有原型。 函数也是对象,所以函数也有原型。 1.什么是原型 在 JavaScript 中,对象有一个特殊的隐藏属性 [[Prototype]],它要么为 null,要么就是对另一个对象的引用,该对象…

MATLAB基于隐马尔可夫模型-高斯混合模型-期望最大化的MR图像分割

隐马尔可夫模型是一种统计模型,它描述了马尔可夫过程,隐马尔可夫过程中包含隐变量,语音识别和词性自动标注等一些领域常常使用隐马尔可夫模型方法来处理。马尔可夫过程是一类随机过程,马尔可夫链是它的原始模型,马尔可…

《OpenScene: 3D Scene Understanding with Open Vocabularies》阅读笔记1

传统的3D场景理解方法依赖于带标签的3D数据集,用于训练一个模型以进行单一任务的监督学习。我们提出了OpenScene,一种替代方法,其中模型在CLIP特征空间中预测与文本和图像像素共同嵌入的3D场景点的密集特征。这种零样本方法实现了与任务无关的训练和开放词汇查询。例如,为了…

03-JNI 类型和数据结构

上一篇: 02-设计概述 本章讨论 JNI 如何将 Java 类型映射为本地 C 类型。 3.1 原始类型 下表描述了 Java 原始类型及其与机器相关的本地等价类型。 为方便起见,定义如下: #define JNI_FALSE 0 #define JNI_TRUE 1 jsize 整数类型用于描述…

《Spring Security 简易速速上手小册》第8章 常见问题与解决方案(2024 最新版)

文章目录 8.1 异常处理和日志记录8.1.1 基础知识详解8.1.2 重点案例:统一异常处理案例 Demo拓展 8.1.3 拓展案例 1:日志记录策略案例 Demo拓展 8.1.4 拓展案例 2:日志聚合案例 Demo拓展 8.2 多租户安全性问题8.2.1 基础知识详解8.2.2 重点案例…

Redis之十:Spring Data Redis --- CrudRepository方式

SpringData Redis CrudRepository方式 Spring Data Redis 的 CrudRepository 是 Spring Data 框架中用于提供基础 CRUD(创建、读取、更新和删除)操作的一个接口。在与 Redis 集成时,尽管 Redis 是一个键值存储系统,并没有像关系型…

STM32使用FlyMcu串口下载程序与STLink Utility下载程序

文章目录 前言软件链接一、FlyMcu串口下载程序原理优化手动修改跳线帽选项字节其他功能 二、STLink Utility下载程序下载程序选项字节固件更新 前言 本文主要讲解使用FlyMcu配合USART串口为STM32下载程序、使用STLink Utility配合STLink为STM32下载程序,以及这两个…

javascript中对包含关系判断介绍

本文将为您详细讲解 JavaScript 中对包含关系的判断,包括数组、字符串等,并提供相应的代码例子。 1. 数组包含关系判断 在 JavaScript 中,数组包含关系判断通常使用 Array.prototype.includes() 方法。这个方法返回一个布尔值,表示…

C语言第三十四弹---动态内存管理(下)

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】 动态内存管理 1、动态内存经典笔试题分析 1.1、题目1 1.2、题目2 1.3、题目3 1.4、题目4 2、柔性数组 2.1、柔性数组的特点 2.2、柔性数组的使用 2.3、…

7、Bluecms代码审计

一、sql注入 环境 流程:将bluecms文件夹放到WWW中,访问文件中的install(安装文件),安装后可以删掉成功后直接访问bluecms目录即可后台访问报错解决。在php.ini配置文件里找到。关闭后记得重启phpstudy display_errors off建议删除安装文件或者将文件名更改1、sql…