《STM32 HAL库》CAN通信系列函数详尽解析——HAL_CAN_Init()

2024-06-22 11:36

本文主要是介绍《STM32 HAL库》CAN通信系列函数详尽解析——HAL_CAN_Init(),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

食用指南:本文主要内容为梳理CAN初始化函数主要运行逻辑及重点功能实现代码的详尽解析。函数源码在文末,建议在阅读源码之后观看。
CAN相关寄存器图:

主要逻辑分析:

下面分点梳理函数的主要逻辑(注意逻辑序号,后文依次为点进行分析):

  1. 首先,函数会检查传入的参数hcan是否为NULL,如果是NULL,则返回错误代码HAL_ERROR

  2. 接下来,函数会使用assert_param宏对传入的hcan结构体的各个参数进行检查,确保它们的取值范围符合要求。

  3. 如果宏USE_HAL_CAN_REGISTER_CALLBACKS的值为1并且hcan的状态为HAL_CAN_STATE_RESET,则表示使用了回调函数,并且需要将回调函数重置为默认的“legacy”函数。如果hcan->MspInitCallback为空,则将其设置为默认的初始化函数HAL_CAN_MspInit。然后调用hcanMspInitCallback函数,用于初始化底层硬件。

  4. 如果USE_HAL_CAN_REGISTER_CALLBACKS的值不为1或者hcan的状态不为HAL_CAN_STATE_RESET,则直接调用HAL_CAN_MspInit函数初始化底层硬件。

  5. 在初始化之前,首先需要将CAN控制器从睡眠模式唤醒。通过清除CAN_MCR_SLEEP位实现。

  1. 接着,获取当前的系统滴答计数器值tickstart,用于超时判断。

  2. 检查CAN控制器是否成功离开了睡眠模式。通过检查CAN_MSR_SLAK位,如果该位为0,则表示成功离开了睡眠模式。如果超时时间超过了预设的超时值CAN_TIMEOUT_VALUE,则更新错误代码并返回错误。

  3. 发送初始化请求,通过设置CAN_MCR_INRQ位实现。

  4. 获取当前的系统滴答计数器值tickstart,用于超时判断。

  5. 等待CAN控制器接受初始化请求。通过检查CAN_MSR_INAK位,如果该位为1,则表示CAN控制器已经接受了初始化请求。如果超时时间超过了预设的超时值CAN_TIMEOUT_VALUE,则更新错误代码并返回错误。

  6. 根据初始化参数设置CAN控制器的各种工作模式和配置,包括时间触发通信模式、自动总线断开管理、自动唤醒模式、自动重传、接收FIFO锁定模式和传输FIFO优先级等。

  1. 设置位时序寄存器BTR,将各个参数值写入寄存器中。

  2. 初始化错误代码和CAN状态。

  3. 返回函数执行状态HAL_OK

重点部分分析

逻辑 3

#if USE_HAL_CAN_REGISTER_CALLBACKS == 1if (hcan->State == HAL_CAN_STATE_RESET){/* Reset callbacks to legacy functions */hcan->RxFifo0MsgPendingCallback  =  HAL_CAN_RxFifo0MsgPendingCallback;  /* Legacy weak RxFifo0MsgPendingCallback */hcan->RxFifo0FullCallback        =  HAL_CAN_RxFifo0FullCallback;        /* Legacy weak RxFifo0FullCallback */hcan->RxFifo1MsgPendingCallback  =  HAL_CAN_RxFifo1MsgPendingCallback;  /* Legacy weak RxFifo1MsgPendingCallback */hcan->RxFifo1FullCallback        =  HAL_CAN_RxFifo1FullCallback;        /* Legacy weak RxFifo1FullCallback */hcan->TxMailbox0CompleteCallback =  HAL_CAN_TxMailbox0CompleteCallback; /* Legacy weak TxMailbox0CompleteCallback */hcan->TxMailbox1CompleteCallback =  HAL_CAN_TxMailbox1CompleteCallback; /* Legacy weak TxMailbox1CompleteCallback */hcan->TxMailbox2CompleteCallback =  HAL_CAN_TxMailbox2CompleteCallback; /* Legacy weak TxMailbox2CompleteCallback */hcan->TxMailbox0AbortCallback    =  HAL_CAN_TxMailbox0AbortCallback;    /* Legacy weak TxMailbox0AbortCallback */hcan->TxMailbox1AbortCallback    =  HAL_CAN_TxMailbox1AbortCallback;    /* Legacy weak TxMailbox1AbortCallback */hcan->TxMailbox2AbortCallback    =  HAL_CAN_TxMailbox2AbortCallback;    /* Legacy weak TxMailbox2AbortCallback */hcan->SleepCallback              =  HAL_CAN_SleepCallback;              /* Legacy weak SleepCallback */hcan->WakeUpFromRxMsgCallback    =  HAL_CAN_WakeUpFromRxMsgCallback;    /* Legacy weak WakeUpFromRxMsgCallback */hcan->ErrorCallback              =  HAL_CAN_ErrorCallback;              /* Legacy weak ErrorCallback */if (hcan->MspInitCallback == NULL){hcan->MspInitCallback = HAL_CAN_MspInit; /* Legacy weak MspInit */}/* Init the low level hardware: CLOCK, NVIC */hcan->MspInitCallback(hcan);}

让我们一句一句地详细分析这段代码:

#if USE_HAL_CAN_REGISTER_CALLBACKS == 1

这是一个条件编译的预处理指令,它检查宏定义USE_HAL_CAN_REGISTER_CALLBACKS是否等于1。如果等于1,则表示要使用回调函数注册功能。

if (hcan->State == HAL_CAN_STATE_RESET)
{

这是一个条件语句,它检查CAN的状态hcan->State是否等于HAL_CAN_STATE_RESET。只有当CAN处于复位状态时,才会执行接下来的代码块。

/* Reset callbacks to legacy functions */
hcan->RxFifo0MsgPendingCallback  =  HAL_CAN_RxFifo0MsgPendingCallback;  /* Legacy weak RxFifo0MsgPendingCallback */
……

这一系列的语句将CAN处理器结构体hcan中的回调函数成员设置为默认的回调函数。这些默认的回调函数被称为”Legacy weak”,表示它们是在历史版本中使用的弱定义回调函数。以第一句为例,作用是将HAL_CAN_RxFifo0MsgPendingCallback的回调函数的地址赋值给hcan->RxFifo0MsgPendingCallback,即将CAN模块的RxFIFO0消息待处理回调函数指针指向一个特定的函数。在CAN模块中,当RxFIFO0内有消息待处理时,可以通过注册一个回调函数来通知应用程序进行相应的处理。

点击《STM32 HAL库》CAN通信系列函数详尽解析——HAL_CAN_Init()——古月居可查看全文

这篇关于《STM32 HAL库》CAN通信系列函数详尽解析——HAL_CAN_Init()的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1084179

相关文章

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中

Python使用getopt处理命令行参数示例解析(最佳实践)

《Python使用getopt处理命令行参数示例解析(最佳实践)》getopt模块是Python标准库中一个简单但强大的命令行参数处理工具,它特别适合那些需要快速实现基本命令行参数解析的场景,或者需要... 目录为什么需要处理命令行参数?getopt模块基础实际应用示例与其他参数处理方式的比较常见问http

Python利用ElementTree实现快速解析XML文件

《Python利用ElementTree实现快速解析XML文件》ElementTree是Python标准库的一部分,而且是Python标准库中用于解析和操作XML数据的模块,下面小编就来和大家详细讲讲... 目录一、XML文件解析到底有多重要二、ElementTree快速入门1. 加载XML的两种方式2.

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

java解析jwt中的payload的用法

《java解析jwt中的payload的用法》:本文主要介绍java解析jwt中的payload的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java解析jwt中的payload1. 使用 jjwt 库步骤 1:添加依赖步骤 2:解析 JWT2. 使用 N

一文带你搞懂Python中__init__.py到底是什么

《一文带你搞懂Python中__init__.py到底是什么》朋友们,今天我们来聊聊Python里一个低调却至关重要的文件——__init__.py,有些人可能听说过它是“包的标志”,也有人觉得它“没... 目录先搞懂 python 模块(module)Python 包(package)是啥?那么 __in

Python中__init__方法使用的深度解析

《Python中__init__方法使用的深度解析》在Python的面向对象编程(OOP)体系中,__init__方法如同建造房屋时的奠基仪式——它定义了对象诞生时的初始状态,下面我们就来深入了解下_... 目录一、__init__的基因图谱二、初始化过程的魔法时刻继承链中的初始化顺序self参数的奥秘默认

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析