输入捕获实验是大家接触定时器后遇到的第一个小困难,它承接定时器更新中断这个知识点和后续PWM的知识点(先了解方波、了解占空比,后续才能更好地理解pwm输出)
也能让大家了解到位操作,如本实验中的STA的8位都有着各自的职能
实验要求:
(1)用TIM4 CH4 (PB9)的输入捕功能测量周期或频率。学习板X9的1号引脚输出幅值3.3v频率1kHz的方波作为输入信号。
(2)设置输入捕获为上升沿检测,记录第一次上升沿发生时TIM4 CNT值;第二次上升沿到来时记录此刻TIM4 CNT值;前后两次TIM4 CNT之差即为方波周期对应的计数值TIM4计数频率已知,可计算出方波周期。
(3)将方波周期显示在4位LED数码管上(单位us)
实验流程图(手写,见谅):
timer.c
main.c
捕获部分
主要代码
main函数
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "timer.h"
#include "74HC595_LED.h"
uint8_t u8DispBuf[5]={0,0x3f,0x06,0x4f,0x66};
extern u8 TIM4CH4_CAPTURE_STA; //输入捕获状态
extern u32 TIM4CH4_CAPTURE_VAL; //输入捕获值
int main(void)
{
TIM_OCInitTypeDef TIM_OCInitStructure;
u16 u16tmp;
uint32_t u32tmp=0;
long long temp=0;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
LED_Init(); //LED端口初始化
TIM4_CH4_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数
Init74HC595();
while(1)
{
if(TIM2CH3_CAPTURE_STA&0X80) //成功捕获到了一次高电平 主函数里面在等,等到捕获到才发串口
{
temp = TIM2CH3_CAPTURE_STA&0X3F; // 0011 1111 即取出溢出的次数
temp *= 0xFFFF; //溢出时间总和
temp += TIM2CH3_CAPTURE_VAL; //得到总的高电平时间
TIM4CH4_CAPTURE_STA = 0; //开启下一次捕获 即当前捕获时间+溢出时间
u8DispBuf[1]= temp / 1000;
u8DispBuf[2]= temp % 1000 / 100;
u8DispBuf[3]= temp % 100 / 10;
u8DispBuf[4]= temp % 10;
}
DispUpdate();
}
}
timer.c
#include "timer.h"
#include "led.h"
//
//捕获状态
//[7]:1-成功捕获到一次高电平;0-尚未成功捕获.
//[6]:1-已捕获到上升沿;0-尚未捕获到上升沿.
//[5:0]:捕获上升沿后溢出的次数(对于32位定时器来说,1us计数器加1,溢出时间:4294秒)
u8 TIM4CH4_CAPTURE_STA=0; //输入捕获状态
u32 TIM4CH4_CAPTURE_VAL; //输入捕获值(TIM2/TIM5是32位)
//
//通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
TIM_ICInitTypeDef TIM4_ICInitStructure;
//定时器2通道3输入捕获配置
//arr:自动重装值
//psc:时钟预分频数
void TIM4_CH4_Cap_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); //TIM4时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PORTB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//PWM 输入捕获都要复用推挽
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //GPIOB9
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PB9 输入 输入捕获当然是输入的
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化PB
GPIO_ResetBits(GPIOB,GPIO_Pin_9);
TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure);
//初始化TIM2输入捕获参数
TIM4_ICInitStructure.TIM_Channel = TIM_Channel_4; //CC1S=01 选择输入端 IC3映射到TI3上
TIM4_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM4_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM4_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM4_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM4, &TIM4_ICInitStructure);
TIM_ITConfig(TIM4,TIM_IT_Update|TIM_IT_CC4,ENABLE);//允许更新中断 ,允许CC3IE捕获中断 更新中断也要打开,因为万一方波太长了没检测到下降就会溢出
TIM4CH4_CAPTURE_STA = 0; //开启一次捕获
TIM_Cmd(TIM4,ENABLE ); //使能定时器5
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
}
//定时器2中断服务程序
void TIM4_IRQHandler(void)
{
if((TIM4CH4_CAPTURE_STA&0X80)==0) //尚未完成一次捕获
{
if(TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) //T4溢出
{
if(TIM4CH4_CAPTURE_STA&0X40) //已捕获到上升沿了
{
if((TIM4CH4_CAPTURE_STA&0X3F)==0X3F) //高电平太长了
{
TIM_Cmd(TIM4,DISABLE); //关闭定时器4//
TIM4CH4_CAPTURE_STA|=0X80; //标记成功捕获一次
TIM4CH4_CAPTURE_VAL=0XFFFF;
}else TIM4CH4_CAPTURE_STA++;
}
}
if(TIM_GetITStatus(TIM4, TIM_IT_CC4) != RESET) //发生捕获3事件
{
if(TIM4CH4_CAPTURE_STA&0X40) //已捕获到上升沿,本次依然是上升沿捕获
{
TIM_Cmd(TIM4,DISABLE); //关闭定时器4//
TIM4CH4_CAPTURE_STA|=0X80; //标记成功捕获到一次高电平脉宽,该标志由main主程序清除
TIM4CH4_CAPTURE_VAL=TIM_GetCapture4(TIM4); //获取当前的捕获值.
TIM_OC4PolarityConfig(TIM4,TIM_ICPolarity_Rising); //CC4P=0 设置为上升沿捕获
}else //第一次捕获到上升沿,立标志、设下降沿捕获
{
TIM4CH4_CAPTURE_STA=0; //清空
TIM4CH4_CAPTURE_VAL=0;
TIM4CH4_CAPTURE_STA|=0X40; //标记捕获到上升沿
TIM_Cmd(TIM4,DISABLE ); //关闭定时器4
TIM_SetCounter(TIM4,0);
TIM_OC4PolarityConfig(TIM4,TIM_ICPolarity_Rising); //CC4P=1 继续上升沿捕获
TIM_Cmd(TIM4,ENABLE ); //使能定时器4
}
}
}
TIM_ClearITPendingBit(TIM4, TIM_IT_CC4|TIM_IT_Update); //清除中断标志位
}
//PSC和ARR的范围为1-65535
/*TIM_IT_Update:更新中断,计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
TIM_IT_CC1~4:都是捕获/比较中断,貌似都是平等的,即输入捕获,输出比较
TIM_IT_Trigger:触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
*/
//● 计数器寄存器(TIMx_CNT)
//● 预分频寄存器(TIMx_PSC)
//● 自动重装载寄存器(TIMx_ARR)
祝大家实验顺利