医疗器械类网站icp备案前置审批,优点有什么,电商网站开发人员,用织梦做的网站怎么管理系统一、高级定时器简介
高级定时器的简介在前面一章已经介绍过#xff0c;可以点击下面链接了解#xff0c;在这里进行一些补充。
[STM32 - 野火] - - - 固件库学习笔记 - - -十二.基本定时器
1.1 功能简介 1、高级定时器可以向上/向下/两边计数#xff0c;还独有一个重复计…一、高级定时器简介
高级定时器的简介在前面一章已经介绍过可以点击下面链接了解在这里进行一些补充。
[STM32 - 野火] - - - 固件库学习笔记 - - -十二.基本定时器
1.1 功能简介 1、高级定时器可以向上/向下/两边计数还独有一个重复计数器RCR。 两边计数例如计数器从0累加计数到ARR的值再从ARR的值递减至0再累加到ARR循环这个过程。 2、有4个GPIO其中通道1~3还有互补输出GPIO。 3、时钟来自PCLK2为72M可实现65536分频。 基本定时器、通用定时器的时钟来自PCK1。
1.2 GPIO说明 可在芯片对应的参考数据手册-引脚说明章节进行查询 二、高级定时器功能框图 2.1 时钟源 高级定时器有4个时钟源可选 1、内部时钟CK_INT 2、外部时钟模式1外部输入引脚TIx 3、外部时钟模式2外部触发输入ETR 4、内部触发输入ITRx
2.1.1 内部时钟CK_INT 内部时钟源来自RCC的TIMx_CLK。 内部时钟源TIMx_CLK的时钟为72M。 一般情况下都是使用内部时钟。 2.1.2 外部时钟模式1 1、时钟信号输入引脚当使用外部时钟模式 1 的时候时钟信号来自于定时器的输入通道总共有 4 个分别为TIMx_CH1/2/3/4。 根据TIM_CCMRx寄存器的位 CCxS[1:0] 配置具体使用哪一路信号。 2、滤波器可以使用滤波器对信号进行重新采样以达到降频或去除高频干扰的目的。 由TIMx_CCMRx寄存器的位 ICxF[3:0]配置。 3、边沿检测器决定是上升沿有效还是下降沿有效。 由 TIMx_CCER寄存器的位 CCxP 和 CCxNP 配置。 4、触发选择可以选择是滤波后的定时器输入1TI1FP1当触发源还是滤波后的定时器输入2TI2FP2当触发源。 由 TIMxSMCR寄存器的位 TS[2:0] 配置。 5、从模式选择选定了触发源信号后把信号连接到 TRGI 引脚让触发信号成为外部时钟模式 1 的输入最终成为CK_PSC。 由 TIMx_SMCR寄存器 的位 SMS[2:0]配置。 总结一下外部时钟模式1中时钟信号-CK_PSC的过程 选择时钟信号输入引脚TIMx_CH1/2/3/4 通过滤波器将高频信号降为低频信号也可以不滤波 经过边沿检测器选择上升有效还是下降有效最终产生两路触发信号TI1FP1、TI2FP2 通过寄存器TIMx_SMCR的TS[2:0]选择哪一路连接到TRGI成为触发信号由TIMx_SMCR的SMS[2:0]位来选择外部时钟模式1 连接到CK_PSC最终驱动预分频器经过分频后成为计数器的时钟。
2.1.3 外部时钟模式2 1、时钟信号输入引脚当使用外部时钟模式 2 的时候时钟信号来自于定时器的特定输入通道 TIMx_ETR只有 1 个。 2、外部触发极性来自 ETR 引脚输入的信号可以选择为上升沿或者下降沿有效。 由 TIMx_SMCR寄存器的位 ETP 配置。 3、外部触发预分频器由于 ETRP 的信号的频率不能超过 TIMx_CLK72M的 1/4当触发信号的频率很高的情况下就必须使用分频器来降频。 ETRP经过外部触发预分频器处理后的信号。 由 TIMx_SMCR寄存器 的位 ETPS[1:0] 配置。 4、滤波器可以使用滤波器对信号进行重新采样通过另外一个时钟很大的信号对ETRP进行采样以达到降频或去除高频干扰的目的。 fDTS时钟频率由TIMx_CR1寄存器的CKD[1:0]控制与fCK_INT相关。 由 TIMx_SMCR寄存器 的位 ETF[3:0] 配置。 5、从模式选择经过滤波器后的时钟ETRF连接到 ETRF 引脚让ETRF信号成为外部时钟模式 2 的输入最终成为CK_PSC。 由TIMx_SMCR寄存器 的位 ECE 配置。 总结一下外部时钟模式2中时钟信号-CK_PSC的过程 通过ETR引脚输入时钟信号 选择为上升沿有效还是下降沿有效 通过分频器分频经过分频器后的信号为ETRP 通过滤波器对信号进行重新采样经过滤波器后的信号为ETRF 将ETRF信号连接到ETRF引脚由 TIMx_SMCR寄存器 的位 ETF[3:0] 来选择外部时钟模式2 连接到CK_PSC最终驱动预分频器经过分频后成为计数器的时钟。
2.1.4 内部触发输入
内部触发输入是使用一个定时器作为另一个定时器的预分频器。
硬件上高级控制定时器和通用定时器在内部连接在一起可以实现定时器同步或级联。 高级定时器的时钟可以给通用定时器提供时钟。 2.2 控制器 控制器用于控制定时器的复位、使能、计数、出发DAC等功能。 主要使用CR1、CR2、SMCR、CCER这几个寄存器。
2.3 时基 1/、CK_PSC 分频后得 CK_CNT计数器时钟 驱动计数器计数计数最大值存储在ARR自动重装载寄存器中 2.1、如果没有使用重复计数器计数器计数到ARR的值时会产生一个更新中断计数值会被清零 2.2、如果使用重复计数器计数器计数到ARR的值时计数器清零重复计数器值1当重复计数器的值计数到REP寄存器存放的值时再产生中断。
2.4 输入捕获ICInput Compare 原理当通道输入引脚出现指定电平跳变时当前CNT的值将被锁存到CCR寄存器中把前后两次捕获到的CCR寄存器中的值相减就可以算出脉宽或者频率。 作用用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数。 边沿信号输入引脚一旦有边沿例如有一个上升沿输入滤波器和边沿检测器就会检测到这个上升沿让输入捕获电路产生动作检测电平跳变执行动作控制后续电路让当前CNT的值锁存到CCR寄存器中。 2.4.1 输入通道
需要被测量的信号从定时器的外部引脚 TIMx_CH1/2/3/4 进入通常叫TI1/2/3/4。
2.4.2 输入滤波和边沿检测 输入滤波器当输入的信号存在高频干扰的时候我们需要对输入信号进行滤波即进行重新采样。 采样的频率必须大于等于两倍的输入信号。 边沿检测器设置信号在捕获的时候是什么边沿有效可以是上升沿下降沿或者是双边沿。
2.4.3 捕获通道
捕获通道就是图中的 IC1/2/3/4每个捕获通道都有相对应的捕获寄存器 CCR1/2/3/4当发生捕获的时候计数器CNT的值就会被锁存到捕获寄存器中。 输入通道与捕获通道的区别 输入通道用来输入信号 捕获通道用来捕获输入信号的通道 一个输入通道的信号可以同时输入给两个捕获通道。 比如输入通道TI1的信号经过滤波器、边沿检测器后的TI1FP1和TI1FP2可以同时进入到捕获通道IC1与IC2。
2.4.4 预分频器
ICx 的输出信号会经过一个预分频器用于决定发生多少个事件时进行一次捕获。
2.4.5 捕获寄存器
经过预分频器的信号 ICxPS 是最终被捕获的信号当发生捕获时第一次计数器 CNT 的值会被锁存到捕获寄存器 CCR 中还会产生 CCxI 中断相应的中断位 CCxIF在 SR 寄存器中会被置位通过软件或者读取 CCR 中的值可以将 CCxIF 清 0。
注意如果发生第二次捕获即CCR寄存器中已捕获计数器值且CCxIF标志位已置1那么捕获溢出标志位CCxOF会被置位且CCxOF只能通过软件清零。换句话说当CCxOF被置位时说明有没被读取的捕获值。
2.4.6 PWMI模式 介绍PWMIPulse Width Modulation Input Mode模式也就是PWM的输入模式是专门为测量PWM频率和占空比设计的通过硬件自动捕获信号的上升沿和下降沿极大简化了测量逻辑。 原理利用定时器的两个输入通道只能为通道1和通道2对同一个引脚减小捕获可以测量频率与占空比。 频率测量通过捕获两个上升沿之间的时间差计算信号周期。 占空比测量通过捕获上升沿到下降沿的时间差高电平时间结合周期计算占空比。
为什么使用PWMI模式的时候只能使用通道TIMx_CH1、TIMx_CH2 触发信号连接到控制器里只能是TI1FP1或TI2FP2这两个触发信号只能由TIMx_CH1、TIMx_CH2产生因此只能是TIMx_CH1、TIMx_CH2。 TIMx_CH1与TIMx_CH2交叉的作用与目的 一个通道灵活切换两个引脚 两个通道同时捕获一个引脚。
2.5 输出比较OCOutput Compare 原理通过比较CNT与CCR寄存器值的关系来对输出电平进行置1、置0或翻转的操作。 作用用于输出一定频率和占空比的PWM波形。 2.5.1 输出比较寄存器 当计数器 CNT 的值跟比较寄存器 CCR 的值相等的时候输出参考信号 OCxREF 的信号的极性就会发送改变并且会产生比较中断 CCxI相应的标志位 CCxIFSR 寄存器中会置位。
OCxREF 再经过一系列的控制之后就成为真正的输出信号 OCx/OCxN。
2.5.2 死区发生器 这是一个半桥驱动电路。 在这个半桥驱动电路中Q1管导通Q2管截止。现在要让Q1管截止Q2管导通。如果在Q1管关闭之后立马打开Q2管由于MOS管的存在会在一段时间内相当于Q1管和Q2管都导通了造成短路。
而死区生成电路能避免上述情况的发生在上管关闭的时候延迟一小段时间再导通下管下管关闭的时候延迟一小段时间再导通上管。 2.5.3 输出控制 在输出比较的输出控制中参考信号 OCxREF 在经过死区发生器之后会产生两路带死区的互补信号 OCx_DT 和 OCxN_DT这两路带死区的互补信号就进入输出控制电路。 通道 1~3 才有互补信号通道 4 没有其余跟通道 1~3 一样。 输出模式控制器的输入是CNT与CCR的大小关系输出是REF的高低电平。
进入输出控制电路的信号会被分成两路一路是原始信号OCx一路是被反向的信号OCxN再根据寄存器配置选择是否由OCx/OCxN引脚输出到外部引脚CHx/CHxN。
如果加入了断路刹车功能则断路和死区寄存器 BDTR 的 MOE、 OSSI 和 OSSR 这三个位会共同影响输出的信号。 通用定时器的输出比较通道与高级定时器的相比少了死区发生器部分。 2.5.4 输出引脚
输出比较的输出信号最终是通过定时器的外部 IO 来输出的分别为 CH1/2/3/4其中前面三个通道还有互补的输出通道 CH1/2/3N。
2.5.5 输出比较模式
模式描述冻结CNTCCR时REF保持为原状态匹配时置有效电平CNTCCR时REF置有效电平匹配时置无效电平CNTCCR时REF置无效电平匹配时电平翻转CNTCCR时REF电平翻转强制为无效电平CNT与CCR无效REF强制为无效电平强制为有效电平CNT与CCR无效REF强制为有效电平PWM模式1向上计数CNTCCR时REF置有效电平CNT≥CCR时REF置无效电平向下计数CNTCCR时REF置无效电平CNT≤CCR时REF置有效电平PWM模式2向上计数CNTCCR时REF置无效电平CNT≥CCR时REF置有效电平向下计数CNTCCR时REF置有效电平CNT≤CCR时REF置无效电平 冻结模式保持REF不变维持上一个状态。 例如你正在输出PWM波想暂停一会输出可以切换为冻结模式输出暂停高低电平维持在暂停时的状。 匹配时置有效电平/匹配时置无效电平有效电平可以理解为高电平无效电平是低电平与关断、刹车这些功能配合表述的。 匹配时置有效电平/匹配时置无效电平是一次性的不适合输出连续变化的波形。 匹配时电平翻转可以输出占空比为50%的PWM波形。 强制为无效电平/有效电平你想暂停输出波形并且在暂停期间保持高电平或低电平可以使用这个模式。 PWM模式1/PWM模式2可用于输出频率和占空比都可调的PWM波形。 PWM模式2实际上就是PWM模式1输出的取反。 REF输出之后还有一个极性配置使用PWM模式1的正极性与PWM模式2的反极性最终的输出是一样的。
2.6 断路刹车功能
断路功能就是电机控制的刹车功能使能断路功能时根据相关控制位状态修改输出信号电平。 在任何情况下 OCx 和 OCxN 输出都不能同时为有效电平这关系到电机控制常用的 H 桥电路结构原因。 断路源可以是时钟故障事件由内部复位时钟控制器中的时钟安全系统 (CSS) 生成也可以是外部断路输入 IO两者是或运算关系。 这个异或门是为三相无刷电机服务的无刷电机有3个霍尔传感器检测转子的位置根据转子的位置进行换相。 当三个输入引脚的任何一个有电平翻转时输出引脚就产生一次电平翻转。 经过异或门的输出信号通过数据选择器再进入输入捕获通道1。 数据选择器如果选择上面输入捕获通道1的输入就是3个引脚的异或值 数据选择器如果选择下面那么异或门就没有用4个通道各用各的引脚。
2.7 输入捕获与输出比较
对于同一个定时器输入捕获和输出比较只能使用其中一个不能同时使用输入捕获与输出比较共用CCR寄存器通道引脚也共用。 输出比较引脚是输出端口根据CNT和CCR的大小关系来执行输出动作。 输入捕获引脚是输入端口接收到输入信号执行CCR锁存到CCR动作。
三、PWM
3.1 PWM简介
PWM脉冲宽度调制。 作用在具有惯性的系统中可以通过对一系列脉冲的宽度进行调制来等效地获取所需要的模拟参量常应用于电机控速等领域。 PWM的频率越快它等效的模拟信号就越平稳同时性能开销就越大。 参数 频率Freq 1/Ts PWM的频率越快它等效的模拟信号就越平稳同时性能开销就越大。 占空比Duty TON/TS 占空比决定了PWM等效出来的模拟电压大小占空比越大等效的模拟电压越趋近于高电平占空比越小等效的模拟电压越趋近于低电平是线性的关系。 分辨率占空比变化步距 比如占空比只能是1%、2%这样以1%的步距跳变那么它的分辨率就是1%。
3.2 PWM波形的产生
以通用定时器来说明一下PWM波形是如何产生的。 图自江协科技。 配置完时基单元后CNT开始不断自增运行。
CCR捕获/比较寄存器中的值是我们自己设置的不断比较CCR的值与CNT的值通过输出模式控制器输出REF信号。 上图中黄线表示ARR红线表示CCR蓝线表示CNT 下图为产生的PWM波形。 当CNTCCR时REF置有效电平GPIO输出高电平 当CNT≥CCR时REF置五效电平GPIO输出低电平 当CNT溢出清零后又输出高电平
3.3 PWM波形参数计算 PWM频率Freq CK_PSC/(PSC1)/(ARR1) PWM占空比Duty CCR/(ARR1) PWM分辨率Reso 1/(ARR1)
四、实验 4.1 PWM互补输出实验
4.1.1 硬件设计
使用高级定时器 TIM1 的通道2及其互补通道作为本实验的波形输出通道对应选择 PC7 和 PB0 引脚。 PB0引脚接到绿灯上方便查看实验现象。 为增加断路功能需要用到 TIM8_BKIN 引脚这里选择 PA6引脚。程序我们设置该引脚为高电平有效当 BKIN 引脚被置低电平的时候两路互补的 PWM 输出就被停止就好像是刹车一样。
4.1.2 软件设计
编程要点 1、定时器用到的 GPIO 初始化 2、定时器时基结构体 TIM_TimeBaseInitTypeDef 初始化 3、定时器输出比较结构体 TIM_OCInitTypeDef 初始化 4、定时器刹车和死区结构体 TIM_BDTRInitTypeDef 初始化 // AdvancedTimer.c文件
#include AdvancedTimer.hstatic void ADVANCED_TIM_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;// 输出比较通道 GPIO 初始化RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin ADVANCE_TIM_CH1_PIN;GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(ADVANCE_TIM_CH1_PORT, GPIO_InitStructure);// 输出比较通道互补通道 GPIO 初始化RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1N_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin ADVANCE_TIM_CH1N_PIN;GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(ADVANCE_TIM_CH1N_PORT, GPIO_InitStructure);// 输出比较通道刹车通道 GPIO 初始化RCC_APB2PeriphClockCmd(ADVANCE_TIM_BKIN_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin ADVANCE_TIM_BKIN_PIN;//GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(ADVANCE_TIM_BKIN_PORT, GPIO_InitStructure);// BKIN引脚默认先输出低电平GPIO_ResetBits(ADVANCE_TIM_BKIN_PORT,ADVANCE_TIM_BKIN_PIN);
}static void ADVANCED_TIM_Mode_Config(void)
{// 开启定时器时钟,即内部时钟CK_INT72MADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK,ENABLE);/*--------------------时基结构体初始化-------------------------*/TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;// 自动重装载寄存器的值累计TIM_Period1个频率后产生一个更新或者中断TIM_TimeBaseStructure.TIM_PeriodADVANCE_TIM_PERIOD; // 驱动CNT计数器的时钟 Fck_int/(psc1)TIM_TimeBaseStructure.TIM_Prescaler ADVANCE_TIM_PSC; // 时钟分频因子 配置死区时间时需要用到TIM_TimeBaseStructure.TIM_ClockDivisionTIM_CKD_DIV1; // 计数器计数模式设置为向上计数TIM_TimeBaseStructure.TIM_CounterModeTIM_CounterMode_Up; // 重复计数器的值没用到不用管TIM_TimeBaseStructure.TIM_RepetitionCounter0; // 初始化定时器TIM_TimeBaseInit(ADVANCE_TIM, TIM_TimeBaseStructure);/*--------------------输出比较结构体初始化-------------------*/ TIM_OCInitTypeDef TIM_OCInitStructure;// 配置为PWM模式1TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1;// 输出使能TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable;// 互补输出使能TIM_OCInitStructure.TIM_OutputNState TIM_OutputNState_Enable; // 设置占空比大小TIM_OCInitStructure.TIM_Pulse ADVANCE_TIM_PULSE;// 输出通道电平极性配置配置为高电平有效TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High;// 互补输出通道电平极性配置TIM_OCInitStructure.TIM_OCNPolarity TIM_OCNPolarity_High;// 输出通道空闲电平极性配置TIM_OCInitStructure.TIM_OCIdleState TIM_OCIdleState_Set;// 互补输出通道空闲电平极性配置TIM_OCInitStructure.TIM_OCNIdleState TIM_OCNIdleState_Reset;TIM_OC2Init(ADVANCE_TIM, TIM_OCInitStructure);TIM_OC2PreloadConfig(ADVANCE_TIM, TIM_OCPreload_Enable); // 使能 OC1 预装载功能/*-------------------刹车和死区结构体初始化-------------------*/// 有关刹车和死区结构体的成员具体可参考BDTR寄存器的描述TIM_BDTRInitTypeDef TIM_BDTRInitStructure;TIM_BDTRInitStructure.TIM_OSSRState TIM_OSSRState_Enable;TIM_BDTRInitStructure.TIM_OSSIState TIM_OSSIState_Enable;TIM_BDTRInitStructure.TIM_LOCKLevel TIM_LOCKLevel_1;// 输出比较信号死区时间配置具体如何计算可参考 BDTR:UTG[7:0]的描述// 这里配置的死区时间为152nsTIM_BDTRInitStructure.TIM_DeadTime 11;TIM_BDTRInitStructure.TIM_Break TIM_Break_Enable;// 当BKIN引脚检测到高电平的时候输出比较信号被禁止就好像是刹车一样TIM_BDTRInitStructure.TIM_BreakPolarity TIM_BreakPolarity_High;TIM_BDTRInitStructure.TIM_AutomaticOutput TIM_AutomaticOutput_Enable;TIM_BDTRConfig(ADVANCE_TIM, TIM_BDTRInitStructure);// 使能计数器TIM_Cmd(ADVANCE_TIM, ENABLE); // 主输出使能当使用的是通用定时器时这句不需要TIM_CtrlPWMOutputs(ADVANCE_TIM, ENABLE);
}void ADVANCED_TIMER_Init(void)
{ADVANCED_TIM_GPIO_Config();ADVANCED_TIM_Mode_Config();
}TIM_OCInitStructure.TIM_OCIdleState TIM_OCIdleState_Set; TIM_OCInitStructure.TIM_OCNIdleState TIM_OCNIdleState_Reset; 当使用短断路刹车功能时两路PWM信号会被强制禁止静止之后输出上面两个参数设定的状态Set为高电平Reset为低电平。 如果不用断路刹车功能可以不配置这两个参数。 死区时间计算参数设置为11二进制0000 1011。 // AdvancedTimer.h文件
#ifndef __ADVANCEDTIMER_H
#define __ADVANCEDTIMER_H#include stm32f10x.h/************高级定时器TIM参数定义只限TIM1和TIM8************/
// 当使用不同的定时器的时候对应的GPIO是不一样的这点要注意
// 这里我们使用高级控制定时器TIM8#define ADVANCE_TIM TIM8
#define ADVANCE_TIM_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADVANCE_TIM_CLK RCC_APB2Periph_TIM8
// PWM 信号的频率 F TIM_CLK/{(ARR1)*(PSC1)}
#define ADVANCE_TIM_PERIOD (8-1) // ARR的值
#define ADVANCE_TIM_PSC (9-1) // 分频因子
#define ADVANCE_TIM_PULSE 4 // 占空比 ADVANCE_TIM_PULSE/(ADVANCE_TIM_PERIOD1)#define ADVANCE_TIM_IRQ TIM1_UP_IRQn
#define ADVANCE_TIM_IRQHandler TIM1_UP_IRQHandler// TIM1 输出比较通道
#define ADVANCE_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOC
#define ADVANCE_TIM_CH1_PORT GPIOC
#define ADVANCE_TIM_CH1_PIN GPIO_Pin_7// TIM1 输出比较通道的互补通道
#define ADVANCE_TIM_CH1N_GPIO_CLK RCC_APB2Periph_GPIOB
#define ADVANCE_TIM_CH1N_PORT GPIOB
#define ADVANCE_TIM_CH1N_PIN GPIO_Pin_0// TIM1 输出比较通道的刹车通道
#define ADVANCE_TIM_BKIN_GPIO_CLK RCC_APB2Periph_GPIOA
#define ADVANCE_TIM_BKIN_PORT GPIOB
#define ADVANCE_TIM_BKIN_PIN GPIO_Pin_6/**************************函数声明********************************/void ADVANCED_TIMER_Init(void);#endif /* __ADVANCEDTIMER_H */#include stm32f10x.h
#include bsp_led.h
#include bsp_rccclkconfig.h
#include bsp_systick.h
#include AdvancedTimer.hint main(void)
{LED_G_GPIO_Config();LED_B_GPIO_Config();LED_R_GPIO_Config();ADVANCED_TIMER_Init();GPIO_SetBits(LED_PROT, GPIO_Pin_All);while(1){}}PWM信号一般的频率为10~25K。
4.2 脉宽测量输入捕获实验
4.2.1 原理 在上升沿捕获进入中断服务函数中将CNT清零并将捕获边沿改为下降沿 在下降沿捕获读取CCR寄存器中的值并将捕获边沿改为上升沿
4.2.2 难点 1、在中断服务函数中需要不断修改捕获的边沿上升沿处理完改为下降沿下降沿处理完改为上升沿。 2、在中断服务函数中记录产生了多少次更新自动。定时器16位只能记录65535个数如果记一个数的时间是1us的话只能计65.536ms
4.2.3 硬件设计 在开发板中 PA0 接的是一个按键默认接 GND当按键按下的时候 IO 口会被拉高这个时候我们可以利用定时器的输入捕获功能来测量按键按下的这段高电平的时间。 根据上面表33-1可知PA0对应的是定时器5的通道1。
4.2.4 软件设计
编程要点 1、定时器用到的 GPIO 初始化 2、定时器时基结构体 TIM_TimeBaseInitTypeDef 初始化 3、定时器输入捕获结构体 TIM_ICInitTypeDef 初始化 4、编写中断服务函数读取捕获值计算出脉宽的时间
// GeneralTimer.c文件
#include GeneralTimer.h// 定时器输入捕获用户自定义变量结构体定义
TIM_ICUserValueTypeDef TIM_ICUserValueStructure {0,0,0,0};// 中断优先级配置
static void GENERAL_TIM_NVIC_Config(void)
{NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为0NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 设置中断来源NVIC_InitStructure.NVIC_IRQChannel GENERAL_TIM_IRQ ; // 设置主优先级为 0NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0; // 设置抢占优先级为3NVIC_InitStructure.NVIC_IRQChannelSubPriority 3; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE;NVIC_Init(NVIC_InitStructure);
}static void GENERAL_TIM_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;// 输入捕获通道 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin GENERAL_TIM_CH1_PIN;GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING;GPIO_Init(GENERAL_TIM_CH1_PORT, GPIO_InitStructure);
}static void GENERAL_TIM_Mode_Config(void)
{// 开启定时器时钟,即内部时钟CK_INT72MGENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);/*--------------------时基结构体初始化-------------------------*/ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;// 自动重装载寄存器的值累计TIM_Period1个频率后产生一个更新或者中断TIM_TimeBaseStructure.TIM_PeriodGENERAL_TIM_PERIOD; // 驱动CNT计数器的时钟 Fck_int/(psc1)TIM_TimeBaseStructure.TIM_Prescaler GENERAL_TIM_PSC; // 时钟分频因子 配置死区时间时需要用到TIM_TimeBaseStructure.TIM_ClockDivisionTIM_CKD_DIV1; // 计数器计数模式设置为向上计数TIM_TimeBaseStructure.TIM_CounterModeTIM_CounterMode_Up; // 重复计数器的值没用到不用管TIM_TimeBaseStructure.TIM_RepetitionCounter0; // 初始化定时器TIM_TimeBaseInit(GENERAL_TIM, TIM_TimeBaseStructure);/*--------------------输入捕获结构体初始化-------------------*/ TIM_ICInitTypeDef TIM_ICInitStructure;// 配置输入捕获的通道需要根据具体的GPIO来配置TIM_ICInitStructure.TIM_Channel GENERAL_TIM_CHANNEL_x;// 输入捕获信号的极性配置TIM_ICInitStructure.TIM_ICPolarity GENERAL_TIM_STRAT_ICPolarity;// 输入通道和捕获通道的映射关系有直连和非直连两种TIM_ICInitStructure.TIM_ICSelection TIM_ICSelection_DirectTI;// 输入的需要被捕获的信号的分频系数TIM_ICInitStructure.TIM_ICPrescaler TIM_ICPSC_DIV1;// 输入的需要被捕获的信号的滤波系数TIM_ICInitStructure.TIM_ICFilter 0;// 定时器输入捕获初始化TIM_ICInit(GENERAL_TIM, TIM_ICInitStructure);// 清除更新和捕获中断标志位TIM_ClearFlag(GENERAL_TIM, TIM_FLAG_Update|GENERAL_TIM_IT_CCx); // 开启更新和捕获中断 TIM_ITConfig (GENERAL_TIM, TIM_IT_Update | GENERAL_TIM_IT_CCx, ENABLE );// 使能计数器TIM_Cmd(GENERAL_TIM, ENABLE);
}void GENERAL_TIMER_Init(void)
{GENERAL_TIM_GPIO_Config();GENERAL_TIM_Mode_Config();GENERAL_TIM_NVIC_Config();
}// GeneralTimer.h文件
#ifndef __GENERALTIMER_H
#define __GENERALTIMER_H#include stm32f10x.h/************通用定时器TIM参数定义只限TIM2、3、4、5************/
// 当使用不同的定时器的时候对应的GPIO是不一样的这点要注意
// 我们这里默认使用TIM5#define GENERAL_TIM TIM5
#define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
#define GENERAL_TIM_CLK RCC_APB1Periph_TIM5
#define GENERAL_TIM_PERIOD 0XFFFF
#define GENERAL_TIM_PSC (72-1)// TIM 输入捕获通道GPIO相关宏定义
#define GENERAL_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA
#define GENERAL_TIM_CH1_PORT GPIOA
#define GENERAL_TIM_CH1_PIN GPIO_Pin_0
#define GENERAL_TIM_CHANNEL_x TIM_Channel_1// 中断相关宏定义
#define GENERAL_TIM_IT_CCx TIM_IT_CC1
#define GENERAL_TIM_IRQ TIM5_IRQn
#define GENERAL_TIM_INT_FUN TIM5_IRQHandler// 获取捕获寄存器值函数宏定义
#define GENERAL_TIM_GetCapturex_FUN TIM_GetCapture1
// 捕获信号极性函数宏定义
#define GENERAL_TIM_OCxPolarityConfig_FUN TIM_OC1PolarityConfig// 测量的起始边沿
#define GENERAL_TIM_STRAT_ICPolarity TIM_ICPolarity_Rising
// 测量的结束边沿
#define GENERAL_TIM_END_ICPolarity TIM_ICPolarity_Falling// 定时器输入捕获用户自定义变量结构体声明
typedef struct
{ uint8_t Capture_FinishFlag; // 捕获结束标志位uint8_t Capture_StartFlag; // 捕获开始标志位uint16_t Capture_CcrValue; // 捕获寄存器的值uint16_t Capture_Period; // 自动重装载寄存器更新标志
}TIM_ICUserValueTypeDef;extern TIM_ICUserValueTypeDef TIM_ICUserValueStructure;/**************************函数声明********************************/void GENERAL_TIMER_Init(void);#endif /* __GENERALTIMER_H */// stm32f10x_it.c文件
#include GeneralTimer.hvoid GENERAL_TIM_INT_FUN(void)
{// 当要被捕获的信号的周期大于定时器的最长定时时定时器就会溢出产生更新中断// 这个时候我们需要把这个最长的定时周期加到捕获信号的时间里面去if ( TIM_GetITStatus ( GENERAL_TIM, TIM_IT_Update) ! RESET ) { TIM_ICUserValueStructure.Capture_Period ; TIM_ClearITPendingBit ( GENERAL_TIM, TIM_FLAG_Update ); }// 上升沿捕获中断if ( TIM_GetITStatus (GENERAL_TIM, GENERAL_TIM_IT_CCx ) ! RESET){// 第一次捕获if ( TIM_ICUserValueStructure.Capture_StartFlag 0 ){// 计数器清0TIM_SetCounter ( GENERAL_TIM, 0 );// 自动重装载寄存器更新标志清0TIM_ICUserValueStructure.Capture_Period 0;// 存捕获比较寄存器的值的变量的值清0 TIM_ICUserValueStructure.Capture_CcrValue 0;// 当第一次捕获到上升沿之后就把捕获边沿配置为下降沿GENERAL_TIM_OCxPolarityConfig_FUN(GENERAL_TIM, TIM_ICPolarity_Falling);// 开始捕获标准置1 TIM_ICUserValueStructure.Capture_StartFlag 1; }// 下降沿捕获中断else // 第二次捕获{// 获取捕获比较寄存器的值这个值就是捕获到的高电平的时间的值TIM_ICUserValueStructure.Capture_CcrValue GENERAL_TIM_GetCapturex_FUN (GENERAL_TIM);// 当第二次捕获到下降沿之后就把捕获边沿配置为上升沿好开启新的一轮捕获GENERAL_TIM_OCxPolarityConfig_FUN(GENERAL_TIM, TIM_ICPolarity_Rising);// 开始捕获标志清0 TIM_ICUserValueStructure.Capture_StartFlag 0;// 捕获完成标志置1 TIM_ICUserValueStructure.Capture_FinishFlag 1; }TIM_ClearITPendingBit (GENERAL_TIM,GENERAL_TIM_IT_CCx); }
}定时器所有中断的中断源都是TIMx_IRQn在中断服务函数中来判断相应标志位决定是哪种中断。 // main.c文件
#include stm32f10x.h
#include bsp_rccclkconfig.h
#include bsp_systick.h
#include usart.h
#include GeneralTimer.huint32_t time 0;int main(void)
{// TIM 计数器的驱动时钟uint32_t TIM_PscCLK 72000000 / (GENERAL_TIM_PSC1);GENERAL_TIMER_Init();USART_Config();while(1){if(TIM_ICUserValueStructure.Capture_FinishFlag 1){// 计算高电平时间的计数器值time TIM_ICUserValueStructure.Capture_Period * (GENERAL_TIM_PERIOD 1) (TIM_ICUserValueStructure.Capture_CcrValue 1);printf(\r\n 高电平脉宽时间 %d.%d \r\n, time/TIM_PscCLK, time%TIM_PscCLK);TIM_ICUserValueStructure.Capture_FinishFlag 0;}}}TIM_ICUserValueStructure.Capture_Period * (GENERAL_TIM_PERIOD 1)计算的是高电平脉宽跨越的完整定时器周期的总时间。 TIM_ICUserValueStructure.Capture_Period表示高电平脉宽跨越了多少个完整的定时器周期。 GENERAL_TIM_PERIOD 1表示一个完整的定时器周期的计数值。因为定时器是从0计数到GENERAL_TIM_PERIOD所以一个完整的周期是GENERAL_TIM_PERIOD 1。 TIM_ICUserValueStructure.Capture_CcrValue 1表示在最后一个定时器周期内高电平脉宽的具体计数值因为定时器是从0开始计数的所以实际的计数值需要加1。 time/TIM_PscCLK time是以定时器的时钟周期为单位的计数值 TIM_PscCLK是定时器的时钟频率定时器的时钟周期单位是秒为1 / TIM_PscCLK 高电平脉宽的实际时间单位是秒为time * (1 / TIM_PscCLK)即 time / TIM_PscCLK。 4.3 PWM输入捕获实验
4.3.1 硬件设计 使用通用定时器TIM3的通道1PA6引脚输出PWM信号 使用高级定时器TIM1的通道1PA8引脚捕获PWM信号 通过杜邦线连接PA6引脚与PA8引脚。
4.3.2 软件设计
编程要点 1、通用定时器产生 PWM 配置 2、高级定时器 PWM 输入配置 3、编写中断服务程序计算测量的频率和占空比并打印出来比较 通用定时器产生PWM信号 // GeneralTimer.c文件
#include GeneralTimer.hstatic void GENERAL_TIM_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;// 输出比较通道1 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin GENERAL_TIM_CH1_PIN;GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GENERAL_TIM_CH1_PORT, GPIO_InitStructure);
}static void GENERAL_TIM_Mode_Config(void)
{// 开启定时器时钟,即内部时钟CK_INT72MGENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);/*--------------------时基结构体初始化-------------------------*/TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;// 自动重装载寄存器的值累计TIM_Period1个频率后产生一个更新或者中断TIM_TimeBaseStructure.TIM_PeriodGENERAL_TIM_PERIOD; // 驱动CNT计数器的时钟 Fck_int/(psc1)TIM_TimeBaseStructure.TIM_Prescaler GENERAL_TIM_PSC; // 时钟分频因子 配置死区时间时需要用到TIM_TimeBaseStructure.TIM_ClockDivisionTIM_CKD_DIV1; // 计数器计数模式设置为向上计数TIM_TimeBaseStructure.TIM_CounterModeTIM_CounterMode_Up; // 重复计数器的值没用到不用管TIM_TimeBaseStructure.TIM_RepetitionCounter0; // 初始化定时器TIM_TimeBaseInit(GENERAL_TIM, TIM_TimeBaseStructure);/*--------------------输出比较结构体初始化-------------------*/ TIM_OCInitTypeDef TIM_OCInitStructure;// 配置为PWM模式1TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1;// 输出使能TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable;// 设置占空比大小TIM_OCInitStructure.TIM_Pulse GENERAL_TIM_PULSE;// 输出通道电平极性配置配置为高电平有效TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High;TIM_OC1Init(GENERAL_TIM, TIM_OCInitStructure);TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable); // 使能 OC1 预装载功能// 使能计数器TIM_Cmd(GENERAL_TIM, ENABLE);
}void GENERAL_TIMER_Init(void)
{GENERAL_TIM_GPIO_Config();GENERAL_TIM_Mode_Config();
}
// GeneralTimer.h文件
#ifndef __GENERALTIMER_H
#define __GENERALTIMER_H#include stm32f10x.h/************通定时器TIM参数定义************/
// 当使用不同的定时器的时候对应的GPIO是不一样的这点要注意
// 这里我们使用通用控制定时器TIM3#define GENERAL_TIM TIM3
#define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
#define GENERAL_TIM_CLK RCC_APB1Periph_TIM3
// PWM 信号的频率 F TIM_CLK/{(ARR1)*(PSC1)}
#define GENERAL_TIM_PERIOD (10-1) // ARR的值
#define GENERAL_TIM_PSC (72-1) // 分频因子
#define GENERAL_TIM_PULSE 9 // 占空比 ADVANCE_TIM_PULSE/(ADVANCE_TIM_PERIOD1)#define GENERAL_TIM_IRQ TIM3_UP_IRQn
#define GENERAL_TIM_IRQHandler TIM3_UP_IRQHandler// TIM3 输出比较通道1
#define GENERAL_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA
#define GENERAL_TIM_CH1_PORT GPIOA
#define GENERAL_TIM_CH1_PIN GPIO_Pin_6/**************************函数声明********************************/void GENERAL_TIMER_Init(void);#endif /* __GENERALTIMER_H */捕获PWM信号 // AdvancedTimer.c文件
#include AdvancedTimer.h /*** brief 高级控制定时器 TIMx,x[1,8]中断优先级配置* param 无* retval 无*/
static void ADVANCE_TIM_NVIC_Config(void)
{NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为0NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 设置中断来源NVIC_InitStructure.NVIC_IRQChannel ADVANCE_TIM_IRQ; // 设置抢占优先级NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0; // 设置子优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority 3; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE;NVIC_Init(NVIC_InitStructure);
}
/*** brief 高级定时器PWM输入用到的GPIO初始化* param 无* retval 无*/
static void ADVANCE_TIM_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin ADVANCE_TIM_CH1_PIN;GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(ADVANCE_TIM_CH1_PORT, GPIO_InitStructure);
}/*** brief 高级定时器PWM输入初始化和用到的GPIO初始化* param 无* retval 无*/
static void ADVANCE_TIM_Mode_Config(void)
{// 开启定时器时钟,即内部时钟CK_INT72MADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK,ENABLE);/*--------------------时基结构体初始化-------------------------*/TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;// 自动重装载寄存器的值累计TIM_Period1个频率后产生一个更新或者中断TIM_TimeBaseStructure.TIM_PeriodADVANCE_TIM_PERIOD; // 驱动CNT计数器的时钟 Fck_int/(psc1)TIM_TimeBaseStructure.TIM_Prescaler ADVANCE_TIM_PSC; // 时钟分频因子 配置死区时间时需要用到TIM_TimeBaseStructure.TIM_ClockDivisionTIM_CKD_DIV1; // 计数器计数模式设置为向上计数TIM_TimeBaseStructure.TIM_CounterModeTIM_CounterMode_Up; // 重复计数器的值没用到不用管TIM_TimeBaseStructure.TIM_RepetitionCounter0; // 初始化定时器TIM_TimeBaseInit(ADVANCE_TIM, TIM_TimeBaseStructure);/*--------------------输入捕获结构体初始化-------------------*/ // 使用PWM输入模式时需要占用两个捕获寄存器一个测周期另外一个测占空比TIM_ICInitTypeDef TIM_ICInitStructure;// 捕获通道IC1配置// 选择捕获通道TIM_ICInitStructure.TIM_Channel ADVANCE_TIM_IC1PWM_CHANNEL;// 设置捕获的边沿TIM_ICInitStructure.TIM_ICPolarity TIM_ICPolarity_Rising;// 设置捕获通道的信号来自于哪个输入通道有直连和非直连两种TIM_ICInitStructure.TIM_ICSelection TIM_ICSelection_DirectTI;// 1分频即捕获信号的每个有效边沿都捕获TIM_ICInitStructure.TIM_ICPrescaler TIM_ICPSC_DIV1;// 不滤波TIM_ICInitStructure.TIM_ICFilter 0x0;// 初始化PWM输入模式TIM_PWMIConfig(ADVANCE_TIM, TIM_ICInitStructure);// 当工作做PWM输入模式时,只需要设置触发信号的那一路即可用于测量周期// 另外一路用于测量占空比会由硬件自带设置不需要再配置// 捕获通道IC2配置
// TIM_ICInitStructure.TIM_Channel ADVANCE_TIM_IC1PWM_CHANNEL;
// TIM_ICInitStructure.TIM_ICPolarity TIM_ICPolarity_Falling;
// TIM_ICInitStructure.TIM_ICSelection TIM_ICSelection_IndirectTI;
// TIM_ICInitStructure.TIM_ICPrescaler TIM_ICPSC_DIV1;
// TIM_ICInitStructure.TIM_ICFilter 0x0;
// TIM_PWMIConfig(ADVANCE_TIM, TIM_ICInitStructure);// 选择输入捕获的触发信号TIM_SelectInputTrigger(ADVANCE_TIM, TIM_TS_TI1FP1); // 选择从模式: 复位模式// PWM输入模式时,从模式必须工作在复位模式当捕获开始时,计数器CNT会被复位TIM_SelectSlaveMode(ADVANCE_TIM, TIM_SlaveMode_Reset);TIM_SelectMasterSlaveMode(ADVANCE_TIM,TIM_MasterSlaveMode_Enable); // 使能捕获中断,这个中断针对的是主捕获通道测量周期那个TIM_ITConfig(ADVANCE_TIM, TIM_IT_CC1, ENABLE); // 清除中断标志位TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);// 使能高级控制定时器计数器开始计数TIM_Cmd(ADVANCE_TIM, ENABLE);
}
/*** brief 高级定时器PWM输入初始化和用到的GPIO初始化* param 无* retval 无*/
void ADVANCE_TIM_Init(void)
{ADVANCE_TIM_GPIO_Config();ADVANCE_TIM_NVIC_Config();ADVANCE_TIM_Mode_Config();
}这里设置的捕获信号频率为1KHz那么它能捕获到的信号频率要≥1KHz这里产生的PWM信号频率为100KHz 因此如果捕获信号的分频系数与ARR寄存器的值设定不合理的话会导致捕获不成功。 选择使用TI1FP1直连到捕获/比较寄存器1当作触发信号 TI1FP1到捕获/比较寄存器1来捕获周期TI1FP2到捕获/比较寄存器2来捕获占空比硬件自动配置 选择使用TI1FP2非直连到捕获/比较寄存器2当作触发信号 TI1FP2到捕获/比较寄存器2来捕获周期TI1FP1到捕获/比较寄存器1来捕获占空比硬件自动配置 // AdvancedTimer.h文件
#ifndef __ADVANCEDTIMER_H
#define __ADVANCEDTIMER_H#include stm32f10x.h/************高级定时器TIM参数定义只限TIM1和TIM8************/
// 当使用不同的定时器的时候对应的GPIO是不一样的这点要注意
// 这里我们使用高级控制定时器TIM1#define ADVANCE_TIM TIM1
#define ADVANCE_TIM_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADVANCE_TIM_CLK RCC_APB2Periph_TIM1// 输入捕获能捕获到的最小的频率为 72M/{ (ARR1)*(PSC1) }
#define ADVANCE_TIM_PERIOD (1000-1)
#define ADVANCE_TIM_PSC (72-1)// 中断相关宏定义
#define ADVANCE_TIM_IRQ TIM1_CC_IRQn
#define ADVANCE_TIM_IRQHandler TIM1_CC_IRQHandler// TIM1 输入捕获通道1
#define ADVANCE_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA
#define ADVANCE_TIM_CH1_PORT GPIOA
#define ADVANCE_TIM_CH1_PIN GPIO_Pin_8#define ADVANCE_TIM_IC1PWM_CHANNEL TIM_Channel_1
#define ADVANCE_TIM_IC2PWM_CHANNEL TIM_Channel_2/**************************函数声明********************************/void ADVANCE_TIM_Init(void);#endif /* __ADVANCEDTIMER_H */
// stm32f10x_it.c文件
#include AdvancedTimer.h
#include usart.h__IO uint16_t IC2Value 0;
__IO uint16_t IC1Value 0;
__IO float DutyCycle 0;
__IO float Frequency 0;
/** 如果是第一个上升沿中断计数器会被复位锁存到CCR1寄存器的值是0CCR2寄存器的值也是0* 无法计算频率和占空比。当第二次上升沿到来的时候CCR1和CCR2捕获到的才是有效的值。其中* CCR1对应的是周期CCR2对应的是占空比。*/
void ADVANCE_TIM_IRQHandler(void)
{/* 清除中断标志位 */TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);/* 获取输入捕获值 */IC1Value TIM_GetCapture1(ADVANCE_TIM);IC2Value TIM_GetCapture2(ADVANCE_TIM);// 注意捕获寄存器CCR1和CCR2的值在计算占空比和频率的时候必须加1if (IC1Value ! 0){/* 占空比计算 */DutyCycle (float)((IC2Value1) * 100) / (IC1Value1);/* 频率计算 */Frequency (72000000/(ADVANCE_TIM_PSC1))/(float)(IC1Value1);printf(占空比 %0.2f%% 频率 %0.2fHz\r\n, DutyCycle, Frequency);}else{DutyCycle 0;Frequency 0;}
}// main.c文件
#include stm32f10x.h
#include usart.h
#include GeneralTimer.h
#include AdvancedTimer.hint main(void)
{USART_Config();GENERAL_TIMER_Init();ADVANCE_TIM_Init();while(1){}}遇到的问题原本的思路是将捕获到的值放到 while(1)中 进行打印但是发现将PA6连接到PA8后串口就不打印数据了而断开后就能打印数据。 原因当PA6连接到PA8后程序会一直跑到定时器1捕获中断服务函数中处理数据。 解决把要打印的数据放到定时器1捕获中断服务函数中。 不建议在中断中添加打印信息如果打印数据多的话会影响系统的速度。