江科大TIM定时器hal库实现

定时器相关hal库函数

hal库的定时器函数相比于标准库,多了很多的中断回调函数,同时对于定时器的初始化也改成使用句柄一次性顺带连带DMA等功能一起初始化了

typedef struct
{uint32_t Prescaler;         /*定时器的预分频值*/uint32_t CounterMode;       /*计数方向,向上计数,向下计数或双边计数*/uint32_t Period;            /*自动重装载值*/uint32_t ClockDivision;     /*定时器时钟分频*/uint32_t RepetitionCounter;  /*高级定时器特有的重装载次数*/uint32_t AutoReloadPreload;  /*自动重装值的更新方式,使能的话,就会使用影子寄存器来等待这次的定时器周期过了才会更新自动重装值到ARR寄存器,失能的话就是直接更新到ARR*/
} TIM_Base_InitTypeDef;

时基单元的初始化和标准库的也是几乎一样的,多了一个自动重装值的更新方式。

#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
typedef struct __TIM_HandleTypeDef
#else
typedef struct
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
{TIM_TypeDef                        *Instance;         /*TIMX的地址,选择我们要的定时器*/TIM_Base_InitTypeDef               Init;              /*定时器初始化结构体*/HAL_TIM_ActiveChannel              Channel;           /*定时器通道使能*/DMA_HandleTypeDef                  *hdma[7];          /*DMA结构体初始化*/HAL_LockTypeDef                    Lock;              /*定时器配置锁定*/__IO HAL_TIM_StateTypeDef          State;             /*定时器状态标志*/__IO HAL_TIM_ChannelStateTypeDef   ChannelState[4];   /*定时器四个通道状态*/__IO HAL_TIM_ChannelStateTypeDef   ChannelNState[4];  /*高级定时器的四个互补通道状态*/__IO HAL_TIM_DMABurstStateTypeDef  DMABurstState;     /*定时器DMA突发传输状态*/
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)void (* Base_MspInitCallback)(struct __TIM_HandleTypeDef *htim);              /*!< TIM Base Msp Init Callback                              */void (* Base_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim);            /*!< TIM Base Msp DeInit Callback                            */void (* IC_MspInitCallback)(struct __TIM_HandleTypeDef *htim);                /*!< TIM IC Msp Init Callback                                */void (* IC_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim);              /*!< TIM IC Msp DeInit Callback                              */void (* OC_MspInitCallback)(struct __TIM_HandleTypeDef *htim);                /*!< TIM OC Msp Init Callback                                */void (* OC_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim);              /*!< TIM OC Msp DeInit Callback                              */void (* PWM_MspInitCallback)(struct __TIM_HandleTypeDef *htim);               /*!< TIM PWM Msp Init Callback                               */void (* PWM_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim);             /*!< TIM PWM Msp DeInit Callback                             */void (* OnePulse_MspInitCallback)(struct __TIM_HandleTypeDef *htim);          /*!< TIM One Pulse Msp Init Callback                         */void (* OnePulse_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim);        /*!< TIM One Pulse Msp DeInit Callback                       */void (* Encoder_MspInitCallback)(struct __TIM_HandleTypeDef *htim);           /*!< TIM Encoder Msp Init Callback                           */void (* Encoder_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim);         /*!< TIM Encoder Msp DeInit Callback                         */void (* HallSensor_MspInitCallback)(struct __TIM_HandleTypeDef *htim);        /*!< TIM Hall Sensor Msp Init Callback                       */void (* HallSensor_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim);      /*!< TIM Hall Sensor Msp DeInit Callback                     */void (* PeriodElapsedCallback)(struct __TIM_HandleTypeDef *htim);             /*!< TIM Period Elapsed Callback                             */void (* PeriodElapsedHalfCpltCallback)(struct __TIM_HandleTypeDef *htim);     /*!< TIM Period Elapsed half complete Callback               */void (* TriggerCallback)(struct __TIM_HandleTypeDef *htim);                   /*!< TIM Trigger Callback                                    */void (* TriggerHalfCpltCallback)(struct __TIM_HandleTypeDef *htim);           /*!< TIM Trigger half complete Callback                      */void (* IC_CaptureCallback)(struct __TIM_HandleTypeDef *htim);                /*!< TIM Input Capture Callback                              */void (* IC_CaptureHalfCpltCallback)(struct __TIM_HandleTypeDef *htim);        /*!< TIM Input Capture half complete Callback                */void (* OC_DelayElapsedCallback)(struct __TIM_HandleTypeDef *htim);           /*!< TIM Output Compare Delay Elapsed Callback               */void (* PWM_PulseFinishedCallback)(struct __TIM_HandleTypeDef *htim);         /*!< TIM PWM Pulse Finished Callback                         */void (* PWM_PulseFinishedHalfCpltCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM PWM Pulse Finished half complete Callback           */void (* ErrorCallback)(struct __TIM_HandleTypeDef *htim);                     /*!< TIM Error Callback                                      */void (* CommutationCallback)(struct __TIM_HandleTypeDef *htim);               /*!< TIM Commutation Callback                                */void (* CommutationHalfCpltCallback)(struct __TIM_HandleTypeDef *htim);       /*!< TIM Commutation half complete Callback                  */void (* BreakCallback)(struct __TIM_HandleTypeDef *htim);                     /*!< TIM Break Callback                                      */
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
} TIM_HandleTypeDef;

 上面是关于定时器的相关配置和能与定时器联系起来的DMA的相关配置以及所有的中断回调函数的注册。

我们使用CubeMX初始化就行了,在Cubemx生成的代码里面,我们还能看见定时器时钟选择,主从模式的失能等操作。

所有的句柄成员都会在对应的.c文件下有着对应的定义,还有Is_xxx这类型的宏定义,来辅助系统对外设初始化的检测,所有的句柄初始化成功,就返回HAL_OK,错误就返回HAL_ERROR并提供给我们一个错误回调函数,我们就能在这里面知道对应的外设初始化失败,需要我们去调试程序。

定时器的中断使能和中断优先级设置cubemx都放在了mspInit初始化回调函数里面,但是我们还需要在主函数前面开启对应的TIMX中断,才能正常使用。

定时器中断

设置定时时间,也就是计数值,然后计数值CNT到达ARR后,清空CNT并且触发一次定时器溢出中断,通过设置的预分频值和自动重装值,控制我们需要的时间。

中断服务函数都在it.c文件里面找,void TIM2_UP_IRQHandler(void);TIM2更新中断触发的时候,就会进入这个中断服务函数,在里面调用总的定时器中断服务函数HAL_TIM_IRQHandler。在里面先对定时器TIMX进行判别,再清除对应的中断请求位,然后进入对应的中断回调函数。

在对中断进行编写的时候,容易遇到芯片的复位键无法使用了,这个时候基本就是遇到

中断处理异常:中断服务函数编写错误,如未正确清除中断标志位,导致中断一直触发,干扰正常复位流程。这个问题了,我们需要对我们的程序进行检查和修改。

还有对于我们的用户自定义函数也得进行检查,比如说我们移植的OLED函数,就算我们没有使用OELD_Init,但是我们依旧可以使用OLED里面的显示函数,还不会报错,因为没有初始化,导致OLED的I2C协议没有正常运行,使得程序卡死在了我们OLED显示函数那边,导致程序运行有误。

我们使用CubeMx来初始化定时器TIM2,ClockSource选择 Internal Clock

设置预分频值为7200-1和自动重装值10000-1,这样我们得到的计数时间就是

72000000/7200/10000 = 1s;

一秒产生溢出溢出更新中断。

在NVIC界面勾选TIM2的中断允许

其他的配置和前面的一样就行了。

记得开启中断

这里我们得注意了,定时器的中断,需要我们在主函数前面通过

HAL_TIM_Base_Start_IT(&htim2);

来开启对应的TIMX中断,没开启时中断是没响应的。

我们用到的是定时器TIM2的溢出中断,在HAL_TIM_IRQHandler里面找

里面有各种中断的标志位判别,以及他们的中断回调函数。

在里面我们找到TIM_FALG_UPDATE对应的中断回调函数,就是HAL_TIM_PeriodElapsedCallback()

中断回调函数都是weak修饰的,弱定义函数,我们直接对其进行内容修改即可。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim == &htim2){Num++;  // 每秒递增1}
}

我们是TIM2的更新中断,所以在这个函数里面我们得对定时器先进行判别,再对数据进行操作

这样就能成功实现定时器的溢出中断计时功能了,OLEDInit别忘记了,也会导致芯片的下载出错的,但不会锁死芯片。

定时器输出比较 

TIM的OC功能,我们常见的就是PWM的输出,

通过计数值CNT和CCR的比较,控制GPIO口的电平在一定时间内高电平的占比,这就是PWM输出的思路,这里实现PWM的呼吸灯功能

使用Cubemx来初始化TIM2作为PWM的输出定时器,使用通道1的PWM模式(pwm模式就是oc的一种功能,只不过运用的比较广泛,单独作为一个功能拎出来了),预分频值和自动重装载值设置为719和99,自动重装载值就是一个PWM的周期。

下面的Pulse就是我们要控制的CCR了,控制CCR就能控制PWM的占空比,如果我们一直循环控制CCR从0~100,再从100~0,就能实现我们的呼吸灯功能了。

别忘记  HAL_TIM_PWM_Start_IT(&htim2,TIM_CHANNEL_1);//开启定时器TIM2的通道1中断

不开启的话,是使用不了的,这个函数的功能就是启动定时器的 PWM 输出并启用中断。

也可以使用 HAL_TIM_PWM_Start,不开启中断,开启PWM输出,这两个的区别就是是否启用中断,但必须有一个使用,来开启PWM输出。

HAL_TIM_PWM_Start_IT(&htim2,TIM_CHANNEL_1);//开启定时器TIM2的通道1中断while (1){for(i=0;i<100;i++){__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,i);//设置CCR值HAL_Delay(10);}for(i=100;i>0;i--){__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,i);//设置CCR值HAL_Delay(10);}}

和江科大一样的芯片连线就行,使用的是TIM2的通道1,按照硬件电路上看,就是PA0作为PWM的输出端口。

PWM驱动舵机和直流电机就按照上面的代码照壶画瓢就行了。

定时器输入捕获

这里需要我们上面的PWM生成的代码,IC输入捕获来测量PWM的频率,

IC输入捕获通过捕获输入TIM通道的信号上升沿下降沿,双边沿,来触发中断,在中断里面把CNT的值获取得到对应的时间,这个时间就是我们输入信号的周期,频率就是周期的倒数,得到频率。

CNT是按照时基单元的设置一直自增的。

按照江科大的设置来,定时器2通道1作为PWM的输出PA0

定时器3通道1 PA6作为输入引脚。

预分频值和自动重装值是决定频率的值,我们会在主函数里面进行修改,来控制频率可调,这边给一个72,得到的频率就是100000Hz的频率,自动重装载值我们给最大值,这样我们能测量的时间就更大,如果CNT溢出了还没有接收到信号,我们就定义一个Count值在溢出中断的时候自增,得到更大的计数值。

捕获极性这些就用默认设置的即可。

最后设置TIM3的从触发模式,TI1FP1:表示将 TI1 引脚的信号连接到通道 1的输入捕获模块,作为捕获源,在这里就是把TIM2的通道1的引脚信号作为TIM3的通道1的输入捕获。

TIm2通道1信号到达上升沿后,TIM3收到信号,会自动存储CNT的值到CCR里面,并重置CNT计数值,我们读取CCR保存的部分即可。

这边调用上面的PWM部分的时候不要弄错预分频值和自动重装值,PWM的为719和99

控制为1000HZ的频率,我们可以在主函数前面通过hal库的宏定义来修改这两个参数来获得不同的PWM频率,在TIM3处IC捕获,然后显示到我们的OLED上。

但是注意,在设置自动重装值值的时候,自动重装值不能小于我们的占空比CCR的值,或者说我们修改自动重装值ARR的时候,顺带修改CCR的值,不然会造成错误。

  /* USER CODE BEGIN 2 */HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);//开启TIM2的通道1PWM输出功能HAL_TIM_IC_Start(&htim3,TIM_CHANNEL_1);//开启TIM3的通道1IC输入功能/* USER CODE END 2 */OLED_ShowString(1, 1, "Freq:00000Hz");		//1行1列显示字符串Freq:00000Hz/* Infinite loop */__HAL_TIM_SET_PRESCALER(&htim2,359);//修改TIM2频率__HAL_TIM_SET_AUTORELOAD(&htim2,99);//设置自动重装值__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,50);//修改TIM2通道1的PWM占空比,TIM2的CCR值/* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */
//      OLED_ShowString(2,1,"ADDR");
//      OLED_ShowString(3,1,"CCR");
//      OLED_ShowNum(2,6,__HAL_TIM_GET_AUTORELOAD(&htim2),4);
//      OLED_ShowNum(3,6,__HAL_TIM_GetCompare(&htim2,TIM_CHANNEL_1),4);OLED_ShowNum(1, 6, IC_GetFreq(), 5);	//不断刷新显示输入捕获测得的频率/* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}uint32_t IC_GetFreq(void){return 1000000/(__HAL_TIM_GET_COMPARE(&htim3,TIM_CHANNEL_1)+1);
}

TIM注意事项

 TIM的注意点还是挺多的,首先就是使用CubeMx初始化完成TIm后,我们要使用他的相关功能,就得在主函数前面进行对应的定时器使能,使用普通的计数计时功能,就只需要时基使能,需要中断功能的加入,就得中断使能,运用输出功能就得OC使能,或者对应的功能使能如PWM使能,IC输入就得IC使能,普通的Start和startIT的区别就是普通的STart只开启功能,而startIT不仅会开启功能,还会开启对应的相关中断。

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

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

相关文章

CentOS 10:启动telnet服务

参考&#xff0c; 鳥哥私房菜 - 第七章、網路安全與主機基本防護&#xff1a;限制埠口, 網路升級與 SELinux 7.3.3 埠口与服务的启动/关闭及开机时状态设定 我们知道系统的 Telnet 服务通常是以 super daemon 来控管的&#xff0c;请您启动您系统的 telnet 试看看。 1 要启动 …

Taro 安全区域

目录 一、问题描述 二、问题解决 1、顶部刘海区 2、底部小黑条 一、问题描述 安全区域主要是为了避免刘海屏或底部栏遮挡&#xff0c;而造成的不良显示效果。 本次将针对以下两点进行考量&#xff1a; 1、顶部刘海屏区 2、苹果X底部小黑条 二、问题解决 通过Taro.getS…

【Java微服务组件】分布式协调P1-数据共享中心简单设计与实现

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 欢迎评论交流&#xff0c;感谢您的阅读&#x1f604;。 目录 引言设计一个共享数据中心选择数据模型键值对设计 数据可靠性设计持久化快照 &#xff08…

在SpringBoot项目中,使用单元测试@Test

1.引入依赖 <!--单元测试Test的依赖--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>3.2.1</version> </dependency> 2.在src/test/java目录…

在Java中,将Object对象转换为具体实体类对象

在Java中&#xff0c;将Object对象转换为具体实体类对象可以通过以下几种方法实现&#xff1a; 1‌.使用instanceof关键字进行类型检查和转换‌&#xff1a; 首先&#xff0c;使用instanceof关键字检查Object对象是否为目标实体类的类型。 如果是&#xff0c;则进行强制类型…

JAVA学习-练习试用Java实现“音频文件的读取与写入 :使用Java音频库处理音频数据”

问题&#xff1a; java语言编辑&#xff0c;实现音频文件的读取与写入 &#xff1a;使用Java音频库处理音频数据。 解答思路&#xff1a; 在Java中处理音频文件通常需要使用第三方库&#xff0c;例如javax.sound.sampled包&#xff0c;它提供了处理音频文件的基本功能。以下是一…

Flink架构概览,Flink DataStream API 的使用,FlinkCDC的使用

一、Flink与其他组件的协同 Flink 是一个分布式、高性能、始终可用、准确一次&#xff08;Exactly-Once&#xff09;语义的流处理引擎&#xff0c;广泛应用于大数据实时处理场景中。它与 Hadoop 生态系统中的组件可以深度集成&#xff0c;形成完整的大数据处理链路。下面我们从…

linux 查看java的安装路径

一、验证Java安装状态 java -version正常安装会显示版本信息&#xff1a; openjdk version "1.8.0_65" OpenJDK Runtime Environment (build 1.8.0_65-b17) OpenJDK 64-Bit Server VM (build 25.65-b01, mixed mode)二、检查环境变量配置 若已配置JAVA_HOME&#…

2025-5-21 个人笔记篇matlab小笔记和clang基础使用(简单记录)

个人笔记篇 再不记录就找不到了&#xff0c;之前学的一点基础&#xff0c;看看就行,请不要提问,因为很久了>_<(至少我看来是这样的) matlab小笔记 % 开绘制(新建) figure % 设置绘制标题 title(标题); % 设置绘制的X轴Lable xlabel(x); % 设置绘制的y轴Lable ylabel(cos…

前端JavaScript-嵌套事件

点击 如果在多层嵌套中&#xff0c;对每层都设置事件监视器&#xff0c;试试看 <!DOCTYPE html> <html lang"cn"> <body><div id"container"><button>点我&#xff01;</button></div><pre id"output…

网感驱动下开源AI大模型AI智能名片S2B2C商城小程序源码的实践路径研究

摘要&#xff1a;在数字化浪潮中&#xff0c;网感已成为内容创作者与商业运营者必备的核心能力。本文以开源AI大模型、AI智能名片及S2B2C商城小程序源码为技术载体&#xff0c;通过解析网感培养与用户需求洞察的内在关联&#xff0c;提出"数据驱动-场景适配-价值重构"…

AG-UI:重构AI代理与前端交互的下一代协议标准

目录 技术演进背景与核心价值协议架构与技术原理深度解析核心功能与标准化事件体系典型应用场景与实战案例开发者生态与集成指南行业影响与未来展望1. 技术演进背景与核心价值 1.1 AI交互的三大痛点 当前AI应用生态面临三大核心挑战: 交互碎片化:LangGraph、CrewAI等框架各…

游戏引擎学习第301天:使用精灵边界进行排序

回顾并为今天的内容做准备 昨天&#xff0c;我们解决了一些关于排序的问题&#xff0c;这对我们清理长期存在的Z轴排序问题很有帮助。这个问题我们一直想在开始常规游戏代码之前解决。虽然不确定是否完全解决了问题&#xff0c;但我们提出了一个看起来合理的排序标准。 有两点…

Ajax快速入门教程

输入java时&#xff0c;页面并没有刷新但是下面自动联想出了跟java有关的东西&#xff0c;像这种就叫异步交互 它不会妨碍你的输入&#xff0c;同时还能够同步进行对于java相关联想词的推送 发送异步请求需要借助工具axios 引入axios&#xff0c;可以直接在scripts中引入 get和…

Anti Spy安卓版:智能防护,守护手机安全

Anti Spy安卓版是一款专为安卓设备设计的智能防护应用&#xff0c;旨在帮助用户实时防护手机安全&#xff0c;抵御间谍软件、恶意软件和其他潜在威胁。它基于人工智能和启发式搜索方法的引擎&#xff0c;能够检测并阻止已知和未知的间谍软件、后门程序、账单欺诈、短信欺诈、电…

超低延迟音视频直播技术的未来发展与创新

引言 音视频直播技术正在深刻改变着我们的生活和工作方式&#xff0c;尤其是在教育、医疗、安防、娱乐等行业。无论是全球性的体育赛事、远程医疗、在线教育&#xff0c;还是智慧安防、智能家居等应用场景&#xff0c;都离不开音视频技术的支持。为了应对越来越高的需求&#x…

系统架构设计(十二):统一过程模型(RUP)

简介 RUP 是由 IBM Rational 公司提出的一种 面向对象的软件工程过程模型&#xff0c;以 UML 为建模语言&#xff0c;是一种 以用例为驱动、以架构为中心、迭代式、增量开发的过程模型。 三大特征 特征说明以用例为驱动&#xff08;Use Case Driven&#xff09;需求分析和测…

海康相机连接测试-极简版

文章目录 1、下载客户端 1、下载客户端 海康机器人官网下载软件 软件下载地址 先下载客户端测试连接 按照你的相机的类型选择客户端 安装完毕后&#xff0c;确保USB线插的是3.0的端口 软件会自动识别相机型号 在上方有播放按钮&#xff0c;可以采集图像信息显示

Linux 磁盘扩容实战案例:从问题发现到完美解决

Linux 磁盘扩容实战案例&#xff1a;从问题发现到完美解决 案例背景 某企业服务器根目录 (/) 空间不足&#xff0c;运维人员通过 df -h 发现 /dev/vda1 分区已 100% 占满&#xff08;99G 已用&#xff09;。检查发现物理磁盘 /dev/vda 已扩展至 200G&#xff0c;但分区和文件…

深入解析FramePack:高效视频帧打包技术原理与实践

摘要 本文深入探讨FramePack技术在视频处理领域的核心原理&#xff0c;解析其在不同场景下的应用优势&#xff0c;并通过OpenCV代码示例演示具体实现方法&#xff0c;为开发者提供可落地的技术解决方案。 目录 1. FramePack技术背景 2. 核心工作原理剖析 3. 典型应用场景 …