时基单元预分频器自动重装载寄存器计数器简单来说预分频器是将输入时钟进行分频然后输出的频率作为计数器的频率0是1分频1是2分频。所以计数器的频率输入时钟频率/预分频1。自动重装载寄存器就是存放一个值当计数器计到这个值的时候就产生定时器中断或事件计数值清零/返回重装值/0-重装值-0-重装值向上计数/向下技术/中央计数。定时器时基单元的运行流程大概就是这样。两个要计算的1、计数器的频率输入时钟频率/预分频12、计数器溢出频率1/定时时间输入频率/预分频1/自动重装载值1还有预分频寄存器和自动重装载寄存器的影子寄存器机制主要是用于预分频值和自动重装载值与更新事件同步防止运行期间突然修改造成的错误。就是在一个技术周期内这两个值被修改先放到影子寄存器下一个周期才生效。arr影子寄存器可选psc必有影子寄存器时钟源选择主要使用内部时钟通用定时器一般是在APB1总线上但是APB1总线规定不超过36Mhz,所以这里定时器会有个倍频将36倍频到72Mhz其实是二倍频根据实际频率来下定论。还可以使用外部时钟源与其他定时器连接做一个级联还有定时器的通道应该是用于编码器接口输出比较根据CNT和CCR的大小关系来输出高低电平PWM输出模式PWM频率计数器溢出频率输入时钟/预分频1/自动重装载1占空比ccr/自动重装载1PWM分辨率1/自动重装载1输入捕获接收到通道输入信号将CNT所存到CCR。主要用于测量通道信号的频率/周期还可以测双通道上下降沿测脉宽。这里我选择一个比较好理解的两个信号的上升沿一个信号周期内获取CCR的差值德塔CNT计数器每1都需要一个计数器周期计数器频率的倒数所以信号的周期CCR的差值*计数器周期最后可以转换为信号频率计数器频率/CCR差值PWM输入模式主要用于测输入信号的占空比也能算周期在普通输入捕获的情况下加了从模式清除CNT就不用CCR算差值了流程上升沿把CNT存CCR2下降沿把CNT存CCR1。因为有从模式清零这里的CCR就是CNT的数量占空比高电平周期/信号周期CCR1*计数器周期/CCR2*计数器周期CCR1/CCR2周期CCR2*计数器周期编码器接口主要是接收来自编码器的两相信号根据规则来使CNT或者CNT--正转/反转。还可以测频率另开一个定时器测单位时间内CNT的变化。以下是对三种模式的一个应用题目目STM32F103 定时器综合寄存器实战题同时包含基础定时、输出比较 PWM、输入捕获、编码器接口要求纯寄存器开发不调用标准库函数芯片STM32F103C8T6系统时钟 72MHz 引脚分配方便你接线TIM2 通用定时器CH1 (PA0)输出比较产生 1kHz PWM占空比 50%CH2 (PA1)输入捕获上升沿捕获测量外部方波周期TIM3 通用定时器CH1 (PA6)、CH2 (PA7)编码器模式接口正交编码器4 倍频计数任务清单4 个部分全部写寄存器代码时钟配置开启 TIM2、TIM3、GPIOA 时钟Flash 等待周期、时钟树你自己写72MTIM2 CH1输出比较 PWMOC 模式1kHz预分频 ARR 自己算TIM2 CH2输入捕获捕获上升沿用 CCR 存捕获值用全局变量记录方波周期单位usTIM3 CH1CH2编码器接口模式TI1TI24 倍频CNT 随着编码器正转增加、反转减少写一个读取编码器计数值的函数NVIC开启 TIM2 捕获更新中断捕获到信号后置标志主循环读取计算周期主循环不断读取编码器数值判断捕获标志算出输入方波频率你可以用 OLED 打印PWM 占空比、捕获到的频率、编码器计数值代码#include stm32f10x.h // Device header #include Delay.h #include OLED.h volatile static int freq 0; volatile static int outside_pwm 0; int freq_get(){ return 1000000UL/TIM2-CCR2; } void set_pwm(int pwm){ TIM2-CCR1 pwm; } uint16_t get_pwm(){ //返回占空比百分比 return (TIM2-CCR1 * 100) / (TIM2-ARR 1); } int16_t Encoder_get(){ int16_t temp TIM3-CNT; TIM3-CNT 0; return temp; } uint16_t outside_pwm_get(){ //返回占空比百分比 return (TIM4-CCR2 * 100) / TIM4-CCR1; } void timer2_init(){ //开启定时器时钟TIM2,TIM3 RCC-APB1ENR | (1ul 0) | (1ul 1); //TIM2的时基单元,1ms更新事件 //向上计数 TIM2-CR1 ~(1ul 4); //时钟分频因子不分频 TIM2-CR1 ~((1ul 8) | (1ul 9)); //开启ARR的影子寄存器 TIM2-CR1 | (1ul 7); //1kHzPWM //预分频系数 TIM2-PSC 72 - 1; //自动重装载 TIM2-ARR 1000 - 1; //输出比较初始化CH1 //CC1通道被配置为输出 TIM2-CCMR1 ~((1ul 0) | (1ul 1)); //输出比较模式PWM模式1 TIM2-CCMR1 ~(1ul 4); TIM2-CCMR1 | (1ul 5) | (1ul 6); //关闭预装载,让修改的CCR值立刻生效 TIM2-CCMR1 ~(1ul 3); //OC1高电平有效 TIM2-CCER ~(1ul 1); // OC1信号输出到对应的输出引脚 TIM2-CCER | (1ul 0); //初始化CCR1 TIM2-CCR1 500; //输入捕获,CH2 //输入捕获模式,CC2通道配置为输入IC2映射在TI2上 TIM2-CCMR1 ~(1ul 9); TIM2-CCMR1 | (1ul 8); //输入捕获滤波器防噪声干扰(1111采样频率fSAMPLINGfDTS/32N8) TIM2-CCMR1 | (0x0F 12); //无预分频 TIM2-CCMR1 ~((1ul 10) | (1ul 11)); //不反相捕获上升沿捕获使能 TIM2-CCER ~(1ul 5); TIM2-CCER | (1ul 4); //从模式触发源 TIM2-SMCR ~(1ul 4); TIM2-SMCR | (1ul 5) | (1ul 6); //从模式选择复位 TIM2-SMCR ~((1ul 1) | (1ul 0)); TIM2-SMCR | (1ul 2); //使能捕获中断 TIM2-DIER | (1ul 2); //使能TIM2 TIM2-CR1 | (1ul 0); } void gpio_init(){ //打开GPIOA,GPIOB的时钟 RCC-APB2ENR | (1ul 2) | (1ul 3); //PA0复用推挽输出复用以后定时器的PWM信号才能从PA0输出1011 GPIOA-CRL ~(0x0F (4 * 0)); GPIOA-CRL | (0x0B (4 * 0)); //PA1浮空输入 GPIOA-CRL ~(0x0F (4 * 1)); GPIOA-CRL | (1ul 6); //PA6浮空输入 GPIOA-CRL ~(0x0F (4 * 6)); GPIOA-CRL | (0x04 (4 * 6)); //PA7浮空输入 GPIOA-CRL ~(0x0F (4 * 7)); GPIOA-CRL | (0x04 (4 * 7)); //PB6浮空输入TIM4 GPIOB-CRL ~(0x0F (4 * 6)); GPIOB-CRL | (0x04 (4 * 6)); } void nvic_init(){ //优先级组2位抢占优先级2位子优先级 SCB-AIRCR | (0x5FA 16) | (1ul 10) | (1ul 8); SCB-AIRCR ~(1ul 9); //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /*设置优先级,抢占优先级1子优先级1这里是我本人知道优先级组22的情况如果是其他优先级组的话参考官方写法。 如果是31的话NVIC-IP[6] ((1 1) | 1) 4;抢占只左移一位4个位置占三个就有0~7可选子优先级只有1位只有0~1可选 */ //TIM2 NVIC-IP[28] ((1 2) | 1) 4; //开启TIM2_IRQn中断注意查看中断号数组下标为中断号/32后面为中断号对32取余以此类推 NVIC-ISER[0] | (1ul 28); //TIM4 NVIC-IP[30] ((1 2) | 1) 4; NVIC-ISER[0] | (1ul 30); } void timer3_init(){ //编码器接口 //开启TIM3时钟 RCC-APB1ENR | (1ul 1); //时基单元配置 //向上计数 TIM3-CR1 ~(1ul 4); //时钟分频因子不分频 TIM3-CR1 ~((1ul 8) | (1ul 9)); //开启ARR影子寄存器 TIM3-CR1 | (1ul 7); //预分频系数 TIM3-PSC 1 - 1; //自动重装载值 TIM3-ARR 65536 - 1; //输入捕获配置PA6:CH1,PA7:CH2 /*CH1:CC1通道被配置为输入IC1映射在TI1上,无预分频器捕获输入口上检测到的每一个边沿都触发一次捕获,1111采样频率fSAMPLINGfDTS/32N8 */ /*CH2:CC2通道被配置为输入IC2映射在TI2上,无预分频器捕获输入口上检测到的每一个边沿都触发一次捕获,1111采样频率fSAMPLINGfDTS/32N8*/ //1刚好16位一口气配完 TIM3-CCMR1 ~(0xFFFF); TIM3-CCMR1 | (0xF1F1); //不反相捕获上升沿捕获使能 //CC2 TIM3-CCER ~(1ul 5); TIM3-CCER | (1ul 4); //CC1 TIM3-CCER ~(1ul 1); TIM3-CCER | (1ul 0); //从模式选择编码器模式3:A,B相的边沿都能触发计数最常用 TIM3-SMCR ~(0x0F (4 * 0)); TIM3-SMCR | (0x03 (4 * 0)); //使能TIM3(本质计数器) TIM3-CR1 | (1ul 0); } void timer4_init(){ //主要用来配一下PWMIPWM输入模式测外部PWM值 //开启TIM4时钟 RCC-APB1ENR | (1ul 2); //配置时基单元 //向上计数时钟分频因子(不分频)ARR影子寄存器 TIM4-CR1 ~((1ul 4) | (1ul 8) | (1ul 9)); TIM4-CR1 | (1ul 7); TIM4-PSC 72 - 1; TIM4-ARR 65536 - 1; //我想这也算是输入捕获的范畴 //双通道这里CH1和CH2都要映射到TI1 TIM4-CCMR1 ~(0xFFFF); TIM4-CCMR1 | (0xF2F1); //CH1上升沿捕获 TIM4-CCER ~(0x0F (4 * 0)); TIM4-CCER | (0x01 (4 * 0)); //CH2下降沿捕获 TIM4-CCER ~(0x0F (4 * 1)); TIM4-CCER | (0x03 (4 * 1)); //从模式 //从模式选择复位 TIM4-SMCR ~(0x0F (4 * 0)); TIM4-SMCR | (0x04 (4 * 0)); //触发源滤波后的定时器输入1(TI1FP1),上升沿触发清零CNT TIM4-SMCR ~(1ul 5); TIM4-SMCR | (1ul 4) | (1ul 6); //使能捕获中断,上升沿是PWM周期的结束所以是CH1 TIM4-DIER | (1ul 1); //开启定时器 TIM4-CR1 | (1ul 0); } void TIM2_IRQHandler(){ //CH2,CCR2,捕获/比较2 中断标记 if(TIM2-SR (1ul 2)){ freq freq_get(); //手动清除中断标记 TIM2-SR ~(1ul 2); } } void TIM4_IRQHandler(){ if(TIM4-SR (1ul 1)){ outside_pwm outside_pwm_get(); TIM4-SR ~(1ul 1); } } int main(void) { gpio_init(); nvic_init(); timer2_init(); timer3_init(); timer4_init(); while (1) { } }一开始写感觉挺坐牢的我是看着标准库案例跳转到定义来找库函数来配这样效率比较低所以我总结了一下关于定时器的一个配置大致流程1、先开时钟毋庸置疑2、配置时基单元你想要什么计数频率溢出频率自己配记得向上计数时钟因子ARR影子寄存器这些主要是CR和时基单元寄存器3、时基单元配好了就可以进行输出比较/输入捕获/编码器的配置了。输出比较主要是CCMR配置和CCER使能输入捕获和编码器主要是配置输入捕获上升沿捕获CCER选择通道滤波CCMR等等。差别在于从模式选择的模式SMCR。reset还是编码器模式。还有普通输入捕获需要选择从模式触发源编码器模式已经选好。我还自己加了PWMI模式主要是CCR1和CCR2都映射到TI1上一个上升沿一个下降沿一般都是先配置CCMR再使能CCER然后别忘了产生捕获/比较事件EGR。需要用到中断记得使能捕获中断DIER最后就是CR使能定时器定时器本质计数器。注意输出要用复用推挽输出主要流程就是这样吧还是挺难的。
企业数字化 ERP 产品动态
相关推荐
Google Picasa 精神续作:Rust 重写的离线本地相册工具 目录
一、写在前面:Picasa 停更之后,本地相册还缺一款"顺手"的工具
二、技术选型:为什么用 Rust 从零重写
三、整体架构:后台 worker SQLite 的"轻前端、重后台"设计
四、照片索引与文件系统监控&#x… · 2026/11/5 3:54:29
上期聊了“带人”,这期聊聊更上游的事:你定的目标,为什么总落 柯建峰老师系列课③|《目标管理与绩效管理》工作坊:从战略解码到绩效闭环,带走一套能用的目标落地工具前两期,我们拆了柯建峰老师的两门课:一门解决“横向协作”的部门墙,一门解决“纵向带人”的教练式辅导… · 2026/11/5 3:54:29
锐捷设备通过FTP下载到电脑本地 一 组网说明锐捷SW——PC(安装FTP软件)。SW与PC二层或者三层互联,网络可达即可二 FTP服务器和SW客户端配置2.1 FTP服务器配置2.2 SW设备FTP命令JR#copy flash:config.text ftp://admin:admin123172.16.160.235/test-config.text三 测试结果1.… · 2026/11/5 3:54:29
零基础3个月速成网络安全工程师实战指南 1. 项目概述作为一名在网络安全领域摸爬滚打多年的从业者,我经常被问到同一个问题:"零基础如何快速入门网络安全?"今天我就把自己当年用3个月时间从完全不懂到能够独立完成基础渗透测试的学习路径完整分享出来。这份清单之所以被称… · 2026/11/5 4:40:54
AI驱动的数据采集:Bright Data MCP与Trae实践指南 1. 项目概述:AI时代的数据采集新范式最近半年我一直在探索如何将AI能力融入传统数据采集工作流。作为一名长期从事网络数据采集的开发者,我深刻感受到大模型技术对爬虫领域的颠覆性影响。过去我们需要花费大量时间处理反爬机制、解析网页结构、维护代理I… · 2026/11/5 4:40:54
Java C++算法题解leetcode801使序列递增的最小交换次数 前言
LeetCode 801 的题意是:给定两个长度相同的整数数组 nums1 和 nums2,每次操作可以交换某个下标 i 上的两个元素,问最少交换多少次,能使两个数组都严格递增。题目保证答案存在。
这道题最容易掉进的坑是贪心:看到某… · 2026/11/5 4:40:54
基于ECharts的实时天气可视化开发实践 1. 项目背景与核心价值去年夏天帮朋友改造民宿时,发现他们前台用的天气显示还是老式LED屏,不仅信息单一,遇到极端天气也缺乏预警提示。于是用周末时间做了这个网页版天气可视化工具,现在已经成为他们日常运营的标配。相比传统方案… · 2026/11/5 4:40:54
MySQL 把 GROUP_CONCAT 结果当 IN 条件失效的原因与改写 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 4:40:54
TED精读如何训练高阶英语思维与认知能力 1. 项目概述:这不是一节普通英语课,而是一次认知升级的实操训练“跟TED演讲学英文:How AI can save our humanity by Kai-Fu Lee”——这个标题乍看是语言学习类内容,但真正懂行的人一眼就能看出,它根本不是在教“how … · 2026/11/5 4:39:54
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
多智能体协作系统架构设计与实践优化 1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39
大模型系统性入门实战指南:从原理到部署微调的全链路路线 提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39
鸿蒙文件系统沙箱机制解析与开发实践 1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38