本人使用的是正点原子的ministm32
整体思路
本次实验用到的寄存器仍然是之前学过的那几个,但是在用法上却更深入一些,本次实验的难点个人认为有两个,一是理解按键捕获的原理,二是理解按键捕获的实现方法。
按键捕获的原理:
定时器向上计数,定时器被设置为上升沿捕捉,当按键被按下时,捕捉到上升沿,于是记录此时的计数值为t1,然后立刻设为下降沿捕获,并且将计数值清0,再次向上计数,直到t2发生下降沿捕获时,记录此时的计数值为CCRx2。通过这个数据我们可以计算出按键按下的时间,即高电平持续时间。但是注意,我们的定时器是有时间限制的,一旦超过定时器的最大时间就会清0重新计时(溢出),所以我们计算高电平持续时间的时候应该这样计算:
溢出次数N*一次计时最大值ARR+CCRx2
按键捕获的实现方法这个等代码列出来之后再解释把
主要代码部分
main函数
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "timer.h"
#include "into.h"
extern u8 TIM2CH1_CAPTURE_STA;//输入捕获状态
extern u16 TIM2CH1_CAPTURE_VAL;//输入捕获值
int main(){
u32 temp=0;
Stm32_Clock_Init(9);
uart_init(72,9600);
delay_init(72);
LED_Init();
TIM1_PWM_Init(899,0);//10Khz的计数频率。计数5K次为500ms
TIM2_Cap_Init(0XFFFF,72-1);//以1Mhz计算
while(1){
delay_ms(10);
LED0_PWM_VAL++;//呼吸灯
if(LED0_PWM_VAL==300)
LED0_PWM_VAL=0;
if(TIM2CH1_CAPTURE_STA&0X80)//成功补获一次
{
temp = TIM2CH1_CAPTURE_STA&0X3F;//溢出了多少次
temp*=65536;//溢出次数乘以每次溢出的时间等于溢出时间总和
temp+=TIM2CH1_CAPTURE_VAL;//得到高电平总时间
printf("HIGH:%d us\r\n",temp); //打印总高电平时间
TIM2CH1_CAPTURE_STA=0; //开启下一次捕获
}
}
}
into.c
#include "into.h"
#include "led.h"
void TIM2_Cap_Init(u16 arr,u16 psc){
RCC->APB1ENR|=1<<0; //TIM2时钟使能
RCC->APB2ENR|=1<<2;//使能A时钟
GPIOA->CRL&= 0XFFFFFFF0;
GPIOA->CRL |=0X00000008;//输入
GPIOA->ODR |=0<<0;//下拉
TIM2->ARR=arr;
TIM2->PSC=psc;
TIM2->CCMR1|=1<<0;//选择输入IC1映射带TI1上
TIM2->CCMR1|=1<<4;//IC1F是0001模式,2个事件后有效
TIM2->CCMR1|=0<<10;//配置输入分频为不分频
TIM2->CCER |= 1<<0;//允许捕获计数器
TIM2->CCER|=0<<1;//上升沿触发
TIM2->DIER|=1<<1;//允许捕获中断
TIM2->DIER|=1<<0;//允许更新中断
TIM2->CR1 |=0x01;//使能定时器2
MY_NVIC_Init(2,0,TIM2_IRQn,2);//抢占2,子优先级0,组2
//捕获状态
//定时器2中断服务
}
u8 TIM2CH1_CAPTURE_STA=0;//输入捕获状态
u16 TIM2CH1_CAPTURE_VAL;//输入捕获值
void TIM2_IRQHandler(void){
u16 tsr;
tsr = TIM2->SR;//寄存器状态
if((TIM2CH1_CAPTURE_STA&0X80)==0)
{//还未捕获成功
if(tsr&0X01)
{//是否有更新事件产生
if(TIM2CH1_CAPTURE_STA & 0X40)
{//已经捕获到高电平
if((TIM2CH1_CAPTURE_STA & 0X3F)==0X3F)
{
TIM2CH1_CAPTURE_STA|=0x80;//标记成功捕获了一次
TIM2CH1_CAPTURE_VAL=0XFFFF;//捕获值为
}
else
{
TIM2CH1_CAPTURE_STA++;
}
}
}
if(tsr&0x02){ //捕获1发生捕获事件
if(TIM2CH1_CAPTURE_STA&0X40)//捕获到一个下降沿
{
TIM2CH1_CAPTURE_STA|=0X80;
TIM2CH1_CAPTURE_VAL=TIM2->CCR1;//获得当前的捕获值
TIM2->CCER &=~(1<<1);//变为检测上升沿
}
else
{ //还未开始,第一次捕捉上升沿
TIM2CH1_CAPTURE_VAL=0;
TIM2CH1_CAPTURE_STA=0X40;//标记捕捉到了上升延
TIM2->CNT=0;//计数器清空
TIM2->CCER|=1<<1;//设为下降沿捕获
}
}
}
TIM2->SR=0;//清除中断标志位
}
into.h
#ifndef _INTO_H
#define _INTO_H
#include "sys.h"
void TIM2_Cap_Init(u16 arr,u16 psc);
#endif
其他timer函数的内容可以移步上篇csdn,主要说明一下into.c的代码逻辑 前面的配置先不多说了,重点是TIM2_IRQHandler,TIM2的中断函数
我们定义了一个八位的变量TIM2CH1_CAPTURE_STA
bit5~0:捕获高电平后定时器溢出的次数
bit6:捕获到高电平的标志
bit 7:捕获完成的标志
TIM2CH1_CAPTURE_VAL
记录捕获到下降沿时TIM2_CNT的值
首先我们设置为上升沿捕获,当上升中断捕获到来时,如果TIM2CH1_CAPTURE_STA的第六位还不是1,那我们先消除一切配置,将TIM2CH1_CAPTURE_STA,TIM2CH1_CAPTURE_VAL和TIM2->CNT清0,然后再手动把TIM2CH1_CAPTURE_STA的第六位置1,意为捕捉到了高电平,然后再设置位下降沿捕获,如果高电平持续时间过长,那就会发生溢出,在TIM2CH1_CAPTURE_STA中对溢出进行记数,当最大溢出次数来临(0~5位都满了),就强制捕获完成,把TIM2CH1_CAPTURE_STA第七位置为1,标记成功捕获了一次高电平,读取定时器的捕获值到TIM2CH1_CAPTURE_VAL中,最后再设置为上升沿捕获,回到初始状态。