定时器计数说白了就是把内部时钟信号(fmaster)变成外部时钟信号(TIx、ETR),计数需要有时钟/触发控制器和时基单元,定时器1拥有这两个,定时器2和3虽然没有,但可以在捕获模式下进入捕获中断里计数。
使用外部信号计数有两种方式,见下图:
一种输入方式是使用定时器1通道输入,第二种使用定时器1触发输入,各输入口见下图,其中PC1到PC4为定时器1输入通道,PB3为定时器1触发输入口:
如何使用这两种方式来计数外部信号呢,看手册说明:
第一种方式:外部时钟源模式1(使用定时器通道):
第二种方式:外部时钟源模式2(使用触发方式):
这里使用定时器4作为定时1s电平翻转输出到PE4作为计数器外部计数信号,输入到PC2口的TIM1通道2。
下面分别使用这两个模式来对外部信号计数:
外部时钟源模式1:
void Tim1_Count_mode1_Init(void){//tim1计数模式1初始化
PC_DDR_DDR2 =0;//输入
//PD_CR1_C14 =0;//浮空输入
PC_CR1_C12 =1;//上拉输入
PC_CR2_C22 =0;//禁止外部中断功能
TIM1_CCMR2_CC2S=0x01;//CC2通道被配置为输入, IC2映射在TI2FP2上;
TIM1_CCMR2_OC2M=0x00;//无滤波器,以fMASTER采样
TIM1_CCER1_CC2P=0;//捕获发生在TI2F的上升沿
TIM1_CCMR2_OC2PE=0x00;//无预分频器,捕获输入口上检测到的每一个边沿都触发一次捕获
TIM1_SMCR_SMS=0x07;//配置计数器使用外部时钟源模式1
TIM1_SMCR_TS=0x06;//选定TI2作为输入源
TIM1_IER_TIE=1;//触发中断使能
TIM1_CR1_CEN=1;//使能计数器
Send_String("tim1计数初始化完成rn");
}
#pragma vector=TIM1_OVR_TIF_vector//计数上升沿触发中断
__interrupt void Tim2_Count_mode1_IRQHandler(void){
if(TIM1_SR1_TIF){
TIM1_SR1_TIF=0;
Send_String("外部时钟源模式1计数上升沿触发中断:");
Send_O(TIM1_CNTRH);//发计数器高8位
Send_O(TIM1_CNTRL);//发计数器低8位
Send_String("rn");
}
}
TIM4部分省略。
串口调试输出:
外部时钟源模式2:
使用PB3作为外部触发需要修改选项字节,如下图:
这里需要注意的是,外部时钟模式2没有触发中断,外部时钟模式1有,见下图:
所以为了观察定时器1计数器的计数值,在TIM4定时器1s中断中输出定时器1计数器的计数值,代码如下(注意,这里预分频器默认使用官方文档分频系数2):
void Tim1_Count_mode2_Init(void){//tim1计数模式2初始化
PB_DDR_DDR3 =0;//输入
PD_CR1_C14 =0;//浮空输入
//PB_CR1_C13 =1;//上拉输入
PB_CR2_C23 =0;//禁止外部中断功能
TIM1_ETR_ETF=0x00;//无滤波器,以fMASTER采样
TIM1_ETR_ETPS=0x01;//EPRP的频率/2,触发两次计数一次
TIM1_ETR_ETP=0;//ETR不反相,即高电平或上升沿有效
TIM1_ETR_ECE=1;//使能外部时钟模式2,计数器的时钟为ETRF的有效沿
// TIM1_IER_TIE=1;//触发中断使能
TIM1_CR1_CEN=1;//使能计数器
Send_String("tim1模式2计数初始化完成rn");
}
这里列出定时器4中断部分代码:
unsigned int i=0;
#pragma vector=TIM4_OVR_UIF_vector//TIM4更新中断
__interrupt void TIM4_OVR_UIF_IRQHandler(void){
if(TIM4_SR_UIF) {
i++;
TIM4_SR_UIF=0;//清除更新中断标志
if(i>=4000){
i=0;
Send_String("1S中断一次:");
Send_O(TIM1_CNTRH);//发计数器高8位
Send_O(TIM1_CNTRL);//发计数器低8位
Send_String("rn");
PE_ODR_ODR5=!PE_ODR_ODR5;
}
}
}
串口调试输出:
这里可以看到串口输出的“000000”只有三次,其他的都是四次,这是为什么呢?
我猜可能的原因在于stm8s复位时引脚默认是输出高电平的,这样提前了一个高电平,在定时器中断三次加提前的那一次,使计数器计数了,后面的数据都是保持4次不变,第一次的数据不影响我们分析:
可以看到,在2分频下,定时器每1s输出一次计数器数据,刚好在4s改变一次数据,验证了每两个ETR上升沿才计数一次。
使用按键触发计数。如下图所示,按键使用硬件防抖,每按一下按键,向串口输出计数值。
void Tim1_Count_mode2_Init(void){//tim1计数模式2初始化
PB_DDR_DDR3 =0;//输入
//PB_CR1_C14 =0;//浮空输入
PB_CR1_C13 =1;//上拉输入
EXTI_CR1_PBIS=0x02;//仅下降沿触发
PB_CR2_C23 =1;//使能外部中断功能
TIM1_ETR_ETF=0x00;//无滤波器,以fMASTER采样
TIM1_ETR_ETPS=0x00;//无分频
TIM1_ETR_ETP=1;//ETR反相,即低电平或下降沿有效
TIM1_ETR_ECE=1;//使能外部时钟模式2,计数器的时钟为ETRF的有效沿
// TIM1_IER_TIE=1;//触发中断使能
TIM1_CR1_CEN=1;//使能计数器
Send_String("tim1模式2计数初始化完成rn");
}
#pragma vector=EXTI1_vector//端口B外部中断
__interrupt void EXTI1_IRQHandler(void){
if(PB_IDR_IDR3==0){
Send_String("PB3下降沿触发:");
Send_O(TIM1_CNTRH);//发计数器高8位
Send_O(TIM1_CNTRL);//发计数器低8位
Send_String("rn");
EXTI_CR1_PBIS=0x01;//仅上升沿触发
}
if(PB_IDR_IDR3){
Send_String("上升沿沿触发rn");
EXTI_CR1_PBIS=0x02;//仅下降沿触发
}
}
使用PB3外部中断,在中断里面输出计数值。这里需要注意的是,一旦满足外部中断的中断条件后,就会进入中断,但这个中断是一直锁存着,如果按键还是一直按下的,就会一直触发中断,具体看官方手册。所以我这里为了防止中断程序在执行完后在按键还未释放时又进入中断,先是使用了下降沿触发中断,输出计数值,修改中断触发方式为上升沿中断,在按键释放时候发生上升沿,将触发方式又改为下降沿中断,这些就可以解决了按键为放开是又进入中断服务程序。
串口输出:
END!
上一篇:STM8外部中断
下一篇:STVD TIM4 8位中断定时器
推荐阅读最新更新时间:2024-11-12 23:31