主要参考学习资料:
B站@江协科技
STM32入门教程-2023版 细致讲解 中文字幕
开发资料下载链接:https://pan.baidu.com/s/1h_UjuQKDX9IpP-U1Effbsw?pwd=dspb
单片机套装:STM32F103C8T6开发板单片机C6T6核心板 实验板最小系统板套件科协
实验:
- 输入捕获模式测频率
- PWMI模式测频率占空比
新函数:
- 定时器库函数(输入捕获和主从触发模式部分)
目录
- 输入捕获简介
- 频率测量
- 输入捕获通道
- 主从触发模式
- 输入捕获基本结构
- PWMI基本结构
- 函数详解
- TIM_ICInit函数
- TIM_ICInitTypeDef结构体
- TIM_PWMIConfig函数
- TIM_ICStructInit函数
- TIM_SelectInputTrigger函数
- TIM_SelectOutputTrigger函数
- TIM_SelectSlaveMode函数
- TIM_SetICxPrescaler函数
- TIM_GetCapturex函数
- 实验13 输入捕获模式测频率
- 接线图
- PWM驱动
- 输入捕获驱动
- 主程序
- 实验14 PWMI模式测频率占空比
- 输入捕获驱动
- 主程序
输入捕获简介
- IC(Input Capture)输入捕获
- 输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数。
- 每个高级定时器和通用定时器都拥有4个输入捕获通道。
- 可配置为PWMI模式,同时测量频率和占空比。
- 可配合主从触发模式,实现硬件全自动测量。
频率测量
- 测频法:在闸门时间T内,对上升沿计次,得到N,则频率 f x = N / T f_x=N/T fx=N/T,适合测高频信号,数据相对稳定。
- 测周法:两个上升沿内,以标准频率 f C f_C fC计次,得到 N N N,则频率 f x = f c / N f_x=f_c/N fx=fc/N,适合测低频信号,数据跳变快。
- 中界频率:测频法与测周法误差相等(N相等)的频率点 f m = f C / T f_m=\sqrt{f_C/T} fm=fC/T,是选择测频法还是测周法的依据。
定时器外部时钟和对射式红外传感器计次的代码稍加改进,间隔相同时间读取次数并清零即为测频法。本节输入捕获采用测周法。
输入捕获通道
滤波器接收来自引脚的输入TI1并对其进行滤波后输出TI1F, f D T S f_{DTS} fDTS为滤波器采样时钟来源,TIMx_CCMR1寄存器的ICF可以控制滤波器的参数,滤波器以采样频率对输入信号采样,当连续N个值都为高电平,输出才为高电平,当连续N个值都为低电平,输出才为低电平,否则输出保持不变。
滤波后的信号通过边沿检测器捕获上升沿或下降沿,TIMx_CCER寄存器的CC1P可以选择极性,最终得到TI1FP1触发信号,与来自通道2的触发信号一同经过数据选择器,由CC1S进行选择。每个输入捕获通道都有两条独立的滤波器和边沿检测器路线,一路连接当前通道后续电路,另一路连接其他通道后续电路,由此实现一个通道灵活切换两个引脚和两个通道同时捕获一个引脚的功能,其中CH1和CH2交叉,CH3和CH4交叉。
被选择的触发信号继续通过由ICPS控制的分频器,最后CC1E控制输出使能或失能。如果使能,则触发信号可以将CNT的值转运到CCR中。每捕获一次CNT的值,都要将CNT清零以进行下一次捕获,在硬件电路中由TI1FP1到从模式控制器的映射自动完成。
主从触发模式
主从触发模式是主模式、从模式和触发源选择三个功能的简称。主模式将定时器内部信号映射到TRGO引脚,用于触发别的外设。从模式将其他外设或者自身外设的信号映射到TRGI引脚,用于控制自身定时器的运行。触发源选择用于选择从模式的触发信号源,从模式从列表中选择一项执行。输入捕获CNT自动清零即通过TI1FP1信号触发从模式的Reset操作实现(只有通道1和通道2可以,通道3和通道4需在中断函数手动清零)。信号的具体解释参见芯片数据手册。
输入捕获基本结构
使用输入捕获基本结构测量频率,测频法的标准频率即为系统时钟经过预分频后计数器自增的时钟频率。GPIO口输入方波信号,通过滤波器和边沿检测,选择上升沿触发,直连当前通道,分频器不分频。同时触发源选择选择TI1FP1为触发信号,从模式选择复位操作。电路工作时,CCR1的值始终保持为最新一个周期的计数值,即测频法中的N,再计算 f C / N f_C/N fC/N即可得到输入频率。
PWMI基本结构
PWMI模式使用两个通道同时捕获一个引脚,可以同时测量频率和占空比。TI1FP1和输入捕获基本结构中一样,TI1FP2则配置为下降沿触发,通过交叉通道触发通道2的捕获单元。此时CCR2捕获高电平期间的计数值,但不触发清零,CNT继续计数直至上升沿被CCR1捕获到一个周期的计数值,CNT清零。占空比为CCR2/CCR1。
函数详解
TIM_ICInit函数
简介:配置输入捕获单元(单一通道)。
参数一:定时器名称
参数二:指向初始化信息TIM_ICInitTypeDef结构体的指针
TIM_ICInitTypeDef结构体
成员TIM_Channel:输入捕获通道
TIM_Channel_1, ..., TIM_Channel_4
成员TIM_ICFilter:滤波器
成员TIM_ICPolarity:极性
TIM_ICPolarity_Rising, TIM_ICPolarity_Falling, TIM_ICPolarity_BothEdge
成员TIM_ICPrescaler:分频器
TIM_ICPSC_DIV1, TIM_ICPSC_DIV2, TIM_ICPSC_DIV4, TIM_ICPSC_DIV8
成员TIM_ICSelection:数据选择器
TIM_ICSelection_DirectTI(直连通道输入)
TIM_ICSelection_IndirectTI(交叉通道输入)
TIM_ICSelection_TRC(暂时不用)
TIM_PWMIConfig函数
简介:配置输入捕获单元(PWMI模式,限通道1和通道2),函数自动为另一个通道初始化为相反的配置。
参数一:定时器名称
参数二:指向初始化信息TIM_ICInitTypeDef结构体的指针
TIM_ICStructInit函数
简介:给TIM_ICInitTypeDef结构体赋默认值。
参数:指向初始化信息TIM_ICInitTypeDef结构体的指针
TIM_SelectInputTrigger函数
简介:选择输入触发源TRGI。
参数一:定时器名称
参数二:TRGI触发源
TIM_TS_触发源名称
TIM_SelectOutputTrigger函数
简介:选择输出触发源TRGO。
参数一:定时器名称
参数二:TRGO触发源
TIM_TRGOSource_触发源名称
TIM_SelectSlaveMode函数
简介:选择从模式。
参数一:定时器名称
参数二:从模式
TIM_SlaveMode_从模式名称(列表后四个)
TIM_SetICxPrescaler函数
简介:单独配置通道x的分频器(x可选1、2、3、4)。
参数一:定时器名称
参数二:分频器
TIM_GetCapturex函数
简介:读取通道x的CCR(x可选1、2、3、4)。
实验13 输入捕获模式测频率
接线图
在没有信号发生器的情况下,我们使用PA0口输出方波信号,由PA6口测量。
PWM驱动
PWM驱动沿用实验10,新增了调节频率函数。
PWM.h
#ifndef __PWM_H
#define __PWM_Hvoid PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);
void PWM_SetPrescaler(uint16_t Prescaler);#endif
PWM.c
#include "stm32f10x.h" void PWM_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_InternalClockConfig(TIM2);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//固定ARR为100-1,此时PSC调节频率,CCR调节占空比TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = 0;TIM_OC1Init(TIM2, &TIM_OCInitStructure);TIM_Cmd(TIM2, ENABLE);
}//配置CCR改变占空比
void PWM_SetCompare1(uint16_t Compare)
{TIM_SetCompare1(TIM2, Compare);
}//配置PSC改变频率
void PWM_SetPrescaler(uint16_t Prescaler)
{//由于要求不高,PSC使用无预装模式TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate);
}
输入捕获驱动
由于同一通道不能同时输入捕获和输出比较,输入捕获我们使用TIM3。
IC.h
#ifndef __IC_H
#define __IC_Hvoid IC_Init(void);
uint32_t IC_GetFreq(void);#endif
IC.c
#include "stm32f10x.h"void IC_Init(void)
{//配置PA6(TIM3的CH1引脚)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//配置TIM3的时基单元RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);TIM_InternalClockConfig(TIM3);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//ARR设大,防止计数器溢出TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;//标准频率1MHz,根据信号频率分布范围调整TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);//配置输入捕获单元TIM_ICInitTypeDef TIM_ICInitStructure;TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;TIM_ICInitStructure.TIM_ICFilter = 0x0F;TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;TIM_ICInit(TIM3, &TIM_ICInitStructure);//配置TRGI触发源TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);//配置从模式ResetTIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);TIM_Cmd(TIM3, ENABLE);
}//读取并计算频率
uint32_t IC_GetFreq(void)
{//实测CCR总是会少1,此处做补偿return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}
主程序
#include "stm32f10x.h"
#include "Delay.h"
#include "PWM.h"
#include "OLED.h"
#include "IC.h"int main(void)
{OLED_Init();PWM_Init();IC_Init();OLED_ShowString(1, 1, "Freq:00000Hz");//频率Freq = 72M / (PSC + 1) / 100PWM_SetPrescaler(720 - 1);//占空比Duty = CCR / 100PWM_SetCompare1(50);while(1){OLED_ShowNum(1, 6, IC_GetFreq(), 5);}
}
实验14 PWMI模式测频率占空比
接线图、PWM驱动同实验13,输入捕获驱动新增配置PWMI模式和获取占空比函数。
输入捕获驱动
IC.h
#ifndef __IC_H
#define __IC_Hvoid IC_Init(void);
uint32_t IC_GetFreq(void);
uint32_t IC_GetDuty(void);#endif
IC.c
#include "stm32f10x.h"void IC_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);TIM_InternalClockConfig(TIM3);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);TIM_ICInitTypeDef TIM_ICInitStructure;TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;TIM_ICInitStructure.TIM_ICFilter = 0x0F;TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;TIM_ICInit(TIM3, &TIM_ICInitStructure);//配置PWMI模式TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);TIM_Cmd(TIM3, ENABLE);
}uint32_t IC_GetFreq(void)
{return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}//获取并计算占空比,乘一百转换为百分比
uint32_t IC_GetDuty(void)
{return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1);
}
主程序
#include "stm32f10x.h"
#include "Delay.h"
#include "PWM.h"
#include "OLED.h"
#include "IC.h"int main(void)
{OLED_Init();PWM_Init();IC_Init();OLED_ShowString(1, 1, "Freq:00000Hz");OLED_ShowString(2, 1, "Duty:00%");//频率Freq = 72M / (PSC + 1) / 100PWM_SetPrescaler(720 - 1);//占空比Duty = CCR / 100PWM_SetCompare1(50);while(1){OLED_ShowNum(1, 6, IC_GetFreq(), 5);OLED_ShowNum(2, 6, IC_GetDuty(), 2);}
}