———————————————————————————————————————————
版权声明:本文为CSDN博主「qlexcel」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qlexcel/article/details/96972555

———————————————————————————————————————————

一直没搞清楚stm32定时器的TIM_OC1PreloadConfig、TIM_ARRPreloadConfig函数的作用,影子寄存器、预装载寄存器、重载寄存器的概念。今天来研究一下:

关于影子寄存器、预装载寄存器

首先看高级定时器的框图:

图1.高级定时器框图

图1中有阴影的小方框(已用红色框标出),代表该功能对应的寄存器有影子寄存器,也就是:PSC预分频器、自动重装载寄存器、REP寄存器和4个通道的捕获/比较寄存器。

可以看到这几个寄存器都是经常用到的,而且存在定时器工作过程中修改他们的可能性。在定时器工作过程中修改他们的值,就会出现一个问题了:如果上次ARR的值是200,通道1的比较寄存器CCR1值是100,产生占空比为50%的PWM。这个时候我要改变PWM的频率,我把ARR的值改为100,CCR1的值还没来得及更改,那么占空比肯定就会出问题,所以我就需要让他们同步修改。以前ARR=200,CCR1=100,提高频率后ARR=100,CCR1=50,我需要这两个寄存器的值同步修改,最好还是让他们计数完一个周期后再修改,那么进入下一个周期ARR、CCR1同步修改过去,对PWM的占空比就没有一点影响了。

为了达到这个目的,就得先用一个寄存器A把修改的值保存好(ARR_A=100,CCR1_A=50),一旦上一个周期结束,给一个信号,立即就把寄存器A的值赋值过去,立即生效,这样就完成了最理想的在定时器运行中修改寄存器的过程。下面对应到stm32中:

有影子寄存器的寄存器实际上对应了两个寄存器:一个是用户可以写入或读出数据的寄存器,称为preload register(预装载寄存器),另一个是用户看不见的、但在操作中真正起作用的寄存器称为shadow register(影子寄存器)。我们修改的定时器周期、预分频系数、通道的比较值等都是修改的表面那个预装载寄存器,要让这个修改起作用,就还要把预装载寄存器的值赋给影子寄存器才行。

从ARR预装载寄存器传送到影子寄存器,有两种方式,一种是立刻更新,一种是等触发事件之后更新;这两种方式主要取决于寄存器TIMx->CR1中的“APRE”位:

  • APRE=0,当ARR值被修改时,同时马上更新影子寄存器的值;
  • APRE=1,当ARR值被修改时,必须在下一次事件UEV发生后才能更新影子寄存器的值;

TIM_OC1PreloadConfig和TIM_ARRPreloadConfig的作用

这就是TIM_ARRPreloadConfig(TIM1, ENABLE);函数的作用:

#define  TIM_CR1_ARPE     ((uint16_t)0x0080)

void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState)
{
if (NewState != DISABLE)
{
TIMx->CR1 |= TIM_CR1_ARPE;
}
else
{
TIMx->CR1 &= (uint16_t)~((uint16_t)TIM_CR1_ARPE);
}
}

  

4个通道的捕获/比较寄存器也是同样的道理,从CCRx的预装载寄存器传送到影子寄存器由下面的位控制:

TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);函数的作用就是修改这个位:

#define  TIM_CCMR1_OC1PE        ((uint16_t)0x0008)
#define TIM_OCPreload_Enable ((uint16_t)0x0008) void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload)
{
uint16_t tmpccmr1 = 0;
tmpccmr1 = TIMx->CCMR1;
tmpccmr1 &= (uint16_t)~((uint16_t)TIM_CCMR1_OC1PE);
tmpccmr1 |= TIM_OCPreload;
TIMx->CCMR1 = tmpccmr1;
}

再给几个时序图:

 

图2.计数器时序图(当ARPE=0)

1、APRE=0,直接给ARR影子寄存器赋值的情况:

可以看到之前ARR=FF,给ARR赋值为36后,马上就生效了,并在等于36时发生了溢出。

图3.计数器时序图(当ARPE=1)

2、APRE=1,在下一个周期再更新值的情况:

可以看到之前ARR=F5,这个时候修改ARR的值为36,只有表面的重加载寄存器值更改了,真正起作用的影子寄存器并没有更改。等到上一个周期结束,发生更新事件,影子寄存器才更改。

参考博文:https://blog.csdn.net/jpaekeo/article/details/64906477
———————————————————————————————————————————
版权声明:本文为CSDN博主「qlexcel」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qlexcel/article/details/96972555

STM32定时器TIM_OC1PreloadConfig、TIM_ARRPreloadConfig函数详解的更多相关文章

  1. kzalloc 函数详解(转载)

    用kzalloc申请内存的时候, 效果等同于先是用 kmalloc() 申请空间 , 然后用 memset() 来初始化 ,所有申请的元素都被初始化为 0. view plain /** * kzal ...

  2. malloc 与 free函数详解<转载>

    malloc和free函数详解   本文介绍malloc和free函数的内容. 在C中,对内存的管理是相当重要.下面开始介绍这两个函数: 一.malloc()和free()的基本概念以及基本用法: 1 ...

  3. NSSearchPathForDirectoriesInDomains函数详解

    NSSearchPathForDirectoriesInDomains函数详解     #import "NSString+FilePath.h" @implementation ...

  4. JavaScript正则表达式详解(二)JavaScript中正则表达式函数详解

    二.JavaScript中正则表达式函数详解(exec, test, match, replace, search, split) 1.使用正则表达式的方法去匹配查找字符串 1.1. exec方法详解 ...

  5. Linux C popen()函数详解

    表头文件 #include<stdio.h> 定义函数 FILE * popen( const char * command,const char * type); 函数说明 popen( ...

  6. Netsuite Formula > Oracle函数列表速查(PL/SQL单行函数和组函数详解).txt

    PL/SQL单行函数和组函数详解 函数是一种有零个或多个参数并且有一个返回值的程序.在SQL中Oracle内建了一系列函数,这些函数都可被称为SQL或PL/SQL语句,函数主要分为两大类: 单行函数 ...

  7. jQuery.attr() 函数详解

    一,jQuery.attr()  函数详解: http://www.365mini.com/page/jquery-attr.htm 二,jQuery函数attr()和prop()的区别: http: ...

  8. memset函数详解

    语言中memset函数详解(2011-11-16 21:11:02)转载▼标签: 杂谈 分类: 工具相关  功 能: 将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值, 块的大 ...

  9. CreateFile函数详解

    CreateFile函数详解 CreateFile The CreateFile function creates or opens the following objects and returns ...

  10. MYSQL常用内置函数详解说明

    函数中可以将字段名当作变量来用,变量的值就是该列对应的所有值:在整理98在线字典数据时(http://zidian.98zw.com/),有这要一个需求,想从多音字duoyinzi字段值提取第一个拼音 ...

随机推荐

  1. Jmeter之非GUI下执行脚本

    1.进入jmeter 应用所在路径 eg: cd D:\Program Files\apache-jmeter-5.2\bin 2.输入运行命令:jmeter -n -t [jmx脚本路径] -l [ ...

  2. week_Last

    Andrew Ng 机器学习笔记 总结! 注:等下用xmind做一个树状图! 来回忆知识! 所以...树状图待补.... 最后,谢谢吴恩达老师!! 感谢吴恩达老师的无私付出!!

  3. Octave/Matlab初步学习

    Octave/Matlab初步学习 1.基本运算 和其他语言一样,可以通过数学运算符号来实现数学公式的运算.逻辑运算也基本相同 要注意的是,≠这个符号,表达式为 1 ~= 2 而不是用!=来表达 ​ ...

  4. JavaScript:操作符:正负号和自增自减及其隐式转换数据类型

    正负号 正号即加号,负号即减号,运算结果同数学意义一样: 对非数字类型进行正负号运算,会隐式转换为数字,再进行运算: 一些特殊的非数字,转换情况同算术运算符: 自增自减 自增即为++,自减即为--. ...

  5. DP经典例题——LIS&LCS

    DP经典例题--LIS&LCS LCS 最长公共子序列,英文缩写为LCS(Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列 ...

  6. python之路53 ajax补充返回序列化数据,多对多创建三种方式,django内置序列化组件(drf前身),批量操作数据,自定义分页器,form组件

    ajax补充说明 主要是针对回调函数args接收到的响应数据 1.后端request.is_ajax() 用于判断当前请求是否由ajax发出 2.后端返回的三板斧都会被args接收不再影响整个浏览器页 ...

  7. Joplin修改笔记存储位置

    默认存储路径 笔记的默认保存位置可以通过 工具 > 选项 > 通用选项 ,在最上方可以看到路径 使用Windows快捷方式启动 在Joplin的快捷方式上右击,选择属性,然后选择快捷方式选 ...

  8. BUG日记---SSM进行多表查询错误-----页面使用<c:foreach>错误

    javax.servlet.ServletException: javax.servlet.jsp.JspTagException: Don't know how to iterate over su ...

  9. 教你解决虚拟机用不了USB设备的苦恼。

    如果你看见了上图的效果说明我们的苦恼是一样一样的. vm10 vm11 vm player都有这个问题!!!!  对不对?哈哈 . 在虚拟机右击设备点击连接(Connect) 然后听见你的电脑发出了硬 ...

  10. C#依赖注入(直白明了)讲解 一看就会系列

    最基础的:UI-BLL-DAL 这是我们耳熟能详的分层 (补充:)  我们的类正常都不是孤立存在的.很多都是要依赖于其它的类. 比如说我们有一个Work类,Work类在工作的时候需要把信息记录下来. ...