需求分析与代码实现
为了实现一个,可通过按钮调节基准时间,并通过按钮进行启动的简易电子表,我们需要如下准备
三个变量
在学习了stm32外部中断与定时器相关知识后,想到可以利用定时器触发中断的特性,得到某一特定每隔固定时间执行的函数,在这个函数中引入变量递增便可以得到随时间变化固定递增的变量,利用此变量结合oled显示屏,便可在屏幕上输出显示每隔固定时间递增的变量值,如此可实现计时功能——若选定递增变量递增时间为1秒,便得到了随时间1秒变化一次的变量。
经由统计利用该变量变化次数,我们可以得到1分钟(变量变化60次),1小时(变量变化3600次)对应时间。通过主函数中if语句判别,对变量值进行监控,于是可得到三个特定时间递增变量“时”“分”“秒”,将其显示在oled屏上,便得到对应时钟分钟秒钟
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "timer.h"
#include "controlh.h"
#include "controlm.h"
#include "open.h"
extern int o;
int s=0;
int m=0;
int h=0;
int main(){
/*timer2_init();
timer3_init();*/
OLED_Init();
controlh_init();
controlm_init();
open_init();
while(1){
if(s>59){
s=0;
m=m+1;
if(m>59){
m=0;
h=h+1;
if(h>23){h=0;}
}
}
if(h>23){h=0;}
if(m>59){m=0;}
OLED_ShowNum(2,7,s,2);
OLED_ShowChar(2,3,':');
OLED_ShowNum(2,4,m,2);
OLED_ShowChar(2,6,':');
OLED_ShowNum(2,1,h,2);
}
}
三个按钮
为了调节基准时间,我们至少需要能对时钟分钟初始值进行调控的部件,设想情形为通过按钮,按动一次初始值加一,为实现该功能,考虑借助EXTI外部中断,通过按钮对引脚电平进行调节,触发中断,执行中断函数,在中断函数中使得对应变量加一
#include "stm32f10x.h" // Device header
#include "Delay.h"
extern int m;
void controlm_init(void){
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitTypeDef GPIO_INSTRUCTURE;
GPIO_INSTRUCTURE.GPIO_Mode=GPIO_Mode_IPU;
GPIO_INSTRUCTURE.GPIO_Pin=GPIO_Pin_7;
GPIO_INSTRUCTURE.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_INSTRUCTURE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource7);
EXTI_InitTypeDef EXTI_INSTRUCTURE;
EXTI_INSTRUCTURE.EXTI_Line=EXTI_Line7;
EXTI_INSTRUCTURE.EXTI_LineCmd=ENABLE;
EXTI_INSTRUCTURE.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_INSTRUCTURE.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_Init(&EXTI_INSTRUCTURE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitTypeDef NVIC_INITSTRUCTURE;
NVIC_INITSTRUCTURE.NVIC_IRQChannel=EXTI9_5_IRQn;
NVIC_INITSTRUCTURE.NVIC_IRQChannelCmd=ENABLE;
NVIC_INITSTRUCTURE.NVIC_IRQChannelPreemptionPriority=1;
NVIC_INITSTRUCTURE.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&NVIC_INITSTRUCTURE);
}
void EXTI9_5_IRQHandler(void){
if(EXTI_GetITStatus(EXTI_Line7)==SET){
m++;
EXTI_ClearITPendingBit(EXTI_Line7);
Delay_ms(200);
}}
为了对基准时间启动,我们需要额外引脚来实现按钮控制的外部中断,中断函数中执行定时器启动,进而实现时钟启动
#include "stm32f10x.h" // Device header
extern int s;
void timer_init(void){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef tim_initstructure;
tim_initstructure.TIM_ClockDivision=TIM_CKD_DIV1;//
tim_initstructure.TIM_CounterMode=TIM_CounterMode_Up;//
tim_initstructure.TIM_Period=7200-1;//
tim_initstructure.TIM_Prescaler=10000-1;//
tim_initstructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2,&tim_initstructure);//
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//
NVIC_InitTypeDef nvic_initstructure;
nvic_initstructure.NVIC_IRQChannel=TIM2_IRQn;//
nvic_initstructure.NVIC_IRQChannelCmd=ENABLE;
nvic_initstructure.NVIC_IRQChannelPreemptionPriority=2;
nvic_initstructure.NVIC_IRQChannelSubPriority=1;//
NVIC_Init(&nvic_initstructure);
TIM_Cmd(TIM2,ENABLE);
}
void TIM2_IRQHandler(void){
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){
s++;
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
运行时具体问题
在实际操作时,按动按钮接地控制引脚电平降低,并不如理想情形按动一次oled屏幕上数字加一,反而会出现数字加二,加三情形,猜想为按钮接地存在抖动,并不理想,而且面包板地线未必始终低电平,存在浮空电压抖动。
解决方法:在中断函数内部加入延时函数,对按下操作进行延时,以确保消除抖动
运行情形:
三个EXTI外部中断一个定时器实现的,可设置基准时间电子表
其他方法
在本博客中,为得到分钟时钟相应变量变化,采用了if条件语句嵌套的方式,还可以采用三个独立定时器对秒分时分别定义——其中分与时限于16位寄存器大小以及stm32自带时钟源72MHZ频率限制,无法采用通用定时器定义,需要级联定时器来分频