硬汉嵌入式论坛

 找回密码
 立即注册
查看: 3430|回复: 1
收起左侧

[客户分享] 讨论输出比较模式容易遇到的问题。

[复制链接]

20

主题

56

回帖

116

积分

初级会员

积分
116
发表于 2017-7-31 22:44:19 | 显示全部楼层 |阅读模式
近期边学边做定时器输出比较模式的试验遇到问题,经过反复测试及对比库函数代码,总算找到了问题所在,特与大家分享。
先看看手册上怎么介绍使用定时器输出比较模式的
微信截图_20170731220606.jpg
微信截图_20170801180132.jpg
按照其步骤,编写实验代码,目的是当计数器值等于CCR1的值(1000)时,停止计数器,此时延时1000uS,代码如下:

int main(void)
{
    RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;    // 开启TIM4时钟
    TIM4->CCMR1 = TIM_CCMR1_OC1M_0;        // 对CH1通道开启输出比较
    TIM4->PSC = 71;                // 对72MHz进行72分频,得到1MHz时钟
    TIM4->ARR = 0xFFFF;            
    TIM4->CCR1 = 1000;            // 设置1000uS延时
    TIM4->CNT = 0;
    TIM4->CR1 |= TIM_CR1_CEN;        // 开启定时器
    while (!(TIM4->SR & TIM_SR_CC1IF));    // 循环等待CNT计数值为1000
    TIM4->CR1 &= ~TIM_CR1_CEN;        // 定时时间到,关闭定时器
    while (1);
}
编译无误后,先进入软件仿真,测试结果为关闭TIM4时的CNT计数值为1000(0x3E8),符合设计要求。
可是,当将执行代码下载到开发板以硬件方式运行时,测试结果为关闭TIM4时的CNT计数值为1050(0x41A),如果改变PSC寄存器的值为719,硬件运行的延时值也不正确。
如果用库函数进行时钟设置,
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Prescaler = 71;//预分频值
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;//在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x01;//重复计数值
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure);//初始化
硬件运行结果是正确的。
对比库函数初始化后的寄存器,感觉其作用与自编的代码

    TIM4->PSC = 71;                // 对72MHz进行72分频,得到1MHz时钟
    TIM4->ARR = 0xFFFF;   
    作用相同,但为何运行效果却不一致呢?
经过参阅和调试库函数代码,发现库函数代码中包含了对寄存器EGR的操作,我们再看看资料有关EGR的介绍
微信截图_20170731222957.jpg

微信截图_20170731223014.jpg

库函数在初始化PSC和ARR之后,执行了一条EGR=0x01的操作。根据资料(上图),位0是UG产生更新事件的,于是也在自己的代码中加入相同的设置指令,硬件运行的结果就正常了。
代码如下:

int main(void)
{
    RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;    // 开启TIM4时钟
    TIM4->CCMR1 = TIM_CCMR1_OC1M_0;        // 对CH1通道开启输出比较
    TIM4->PSC = 71;                // 对72MHz进行72分频,得到1MHz时钟
    TIM4->ARR = 0xFFFF;            
    TIM4->EGR = 0x01;            // 这条语句非常关键,缺了它会遇到不少怪现象,有了这一句,延时就正确了。
    TIM4->CCR1 = 1000;            // 设置1000uS延时
    TIM4->CNT = 0;
    TIM4->CR1 |= TIM_CR1_CEN;        // 开启定时器
    while (!(TIM4->SR & TIM_SR_CC1IF));    // 循环等待CNT计数值为1000
    TIM4->CR1 &= ~TIM_CR1_CEN;        // 定时时间到,关闭定时器
    while (1);
}
由于官方手册在输出比较模式的介绍缺了EGR寄存器配置的介绍,而且对EGR赋值后,EGR依然为零,很容易让新手迷失方向,这个问题也是本人花了比较长的时间才找出原因解决的,希望后来者少走弯路。

评分

参与人数 1 +5 收起 理由
eric2013 + 5

查看全部评分

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106959
QQ
发表于 2017-8-1 01:31:42 | 显示全部楼层
谢谢楼主分享,[s:151]
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-11 13:53 , Processed in 0.161160 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表