1.项目简介

硬件平台:基于某STM32F103开发板。

软件平台:KEIL5 MDK V5.38,基于LCD屏幕库函数例程库为模板,添加了外部中断,定时器中断相关代码,稍加修改而成。

功能简介:有三个功能按键,启动,暂停,归零;一块LCD屏幕上显示数据数据,理论精度0.01秒

2.硬件简介

按键模块硬件接线图如图所示。

硬件接线图

需要注意的是三个按键中,KEY0,KEY1一端接的是GND。我们在初始化时应设置上拉输入,即没有按下按下按键,IO口读取电压为高,当按键按下,IO口读取的电压会变低,可正确完成按键按下判断;WK_UP按键同理,应设置下拉输入。

3.软件简介

3.1软件总体代码

#include "delay.h"
#include "usart.h"
#include "timer.h"
#include "exti.h"
#include "lcd.h"
#include "led.h"
#include "sys.h"
#include "key.h"volatile u8 m=0; //分钟
volatile u8 s=0; //秒位
volatile u8 ms=0;//毫秒位,1个ms代表10毫秒,如果显示毫秒,屏幕刷不过来int main(void)
{ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2   LED_Init();          //LED初始化delay_init();   //延时函数初始化uart_init(115200);//LCD与主控通过串口通信进行初始化,不可省略LCD_Init();       //LCD初始化EXTIX_Init();   //外部中断初始化POINT_COLOR=RED;  //设置颜色LCD_ShowString(65,25,12*9,24,24,"stopwatch");//显示标题LCD_ShowChar(60+3*12,80,'m',24,0);//字体大小设置为12像素宽,24像素长LCD_ShowChar(60+6*12,80,'s',24,0);TIM3_Int_Init(100,7199);//时钟周期72M/(7199+1)=10k,10Khz的计数频率,计数到计数到100,为10ms  while(1) {      LCD_ShowxNum(60+0*12,80,m,2,24,0);//显示LCD_ShowxNum(60+4*12,80,s,2,24,0);LCD_ShowxNum(60+7*12,80,ms,2,24,0);} return 0;
}

初始化以及main函数代码

下面我们按照顺序依次讲解。

3.2按键外部中断

//外部中断初始化函数
void EXTIX_Init(void)
{EXTI_InitTypeDef EXTI_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟KEY_Init();//初始化按键对应io模式//GPIOC.5 中断线以及中断初始化配置GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);EXTI_InitStructure.EXTI_Line=EXTI_Line5;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);        //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器//GPIOA.15   中断线以及中断初始化配置GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15);EXTI_InitStructure.EXTI_Line=EXTI_Line15;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);       //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器//GPIOA.0    中断线以及中断初始化配置GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);EXTI_InitStructure.EXTI_Line=EXTI_Line0;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);        //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;          //使能按键所在的外部中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;    //抢占优先级2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;                 //子优先级1NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                             //使能外部中断通道NVIC_Init(&NVIC_InitStructure);     //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;          //使能按键所在的外部中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;    //抢占优先级2, NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;                 //子优先级1NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                             //使能外部中断通道NVIC_Init(&NVIC_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;         //使能按键所在的外部中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;    //抢占优先级2, NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;                 //子优先级1NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                             //使能外部中断通道NVIC_Init(&NVIC_InitStructure);
}

我们设置的是按键触发是外部中断,所以先进行按键的初始化,在初始化时注意按键的硬件连接,如果按键另一端连接的3.3V,那就设置为下拉输入,按键连接的GND那就设置上拉输入。

对于外部中断,STM32的中断主控制支持19个外部中断请求:

线0~15:对应外部IO口的输入中断。

线16:连接到PVD输出。

线17:连接到RTC闹钟事件。

线18:连接到USB唤醒事件。

每个外部中断线可以独立的配置触发方式(上升沿,下降沿或者双边沿触发),触发/屏蔽,专用的状态位。

我们使用的是第一类中断。STM32的IO每组最多只有16个(如PA0~PA15),所以根据IO口序号选择对应的外部中断线即可。例如:我们的按键的硬件IO口别是分PA0,PA15,PC5,我就需要配置为

PA0 -EXTI_Line0PA15-EXTI_Line15PC5 -EXTI_Line5
(根据IO口序号选择即可)

(如果选择PA0与PB0来触发外部中断,将无法正常工作,因为他们共用一条中断线)

再配置触发方式(上升沿,下降沿,双边沿)

选择对应的中断向量,对应的选择如下图所示

同样根据IO口序号选择即可,如果是0~4号口,选择EXTI0~4即可,如果是5~9号口,那么只能选择EXTI9_5这个中断向量,10~15号口同理只能选择EXTI15_10。

(这就意味着如果同时选择PC9,PB7作为外部中断触发,那么他们将无法同时正常工作,因为他们位于同样的中断向量EXTI9_5)

//io口对应外部中断关系如下
io口  外部中断线  中断向量        中断服务函数
PA0 -EXTI_Line0 -EXTI0_IRQn    -EXTI0_IRQHandler PA15-EXTI_Line15-EXTI15_10_IRQn-EXTI15_10_IRQHandlerPC5 -EXTI_Line5 -EXTI9_5_IRQn  -EXTI9_5_IRQHandler

选好了中断向量,就在对应的中断服务函数中去按照要求编写代码即可。

外部中断服务函数代码如下。

volatile u8 suspend_flag=0;//暂停标
volatile u8 start_flag=0;  //开始标
volatile u8 zero_flag=0;   //清零void EXTI0_IRQHandler(void)//开始
{if(WK_UP==1){    //delay_ms(10);    //消抖,会提高按键识别率,但是会影响秒表精度,自行选择start_flag=1;//开始zero_flag=0; suspend_flag=0;    LED0=!LED0;LED1=!LED1;    }EXTI_ClearITPendingBit(EXTI_Line0);  //清除EXTI0线路挂起位
}void EXTI15_10_IRQHandler(void)//暂停
{        if(KEY1==0)  {//delay_ms(10);  //消抖,会提高按键识别率,但是会影响秒表精度,自行选择if(start_flag==1&&suspend_flag==0)//正常运行情况下,才暂停{suspend_flag=1;}LED0=!LED0;LED1=!LED1;}EXTI_ClearITPendingBit(EXTI_Line15);//清除LINE15线路挂起位
}void EXTI9_5_IRQHandler(void)//清零
{           //delay_ms(10);  //消抖,会提高按键识别率,但是会影响秒表精度,自行选择   if(KEY0==0)  {if(suspend_flag==1)//只暂停状态下清零{zero_flag=1;     //清零}LED0=!LED0;LED1=!LED1;}EXTI_ClearITPendingBit(EXTI_Line5);    //清除LINE5上的中断标志位
}

在进入中断后可以选择打开10ms消抖,减少误判率,但是本设计是秒表,为了提高计时精准性,选择将它关闭,所以实际测试时,会有误判现象发生,如误判较多,开启10ms消抖即可,但会降低计时精度。

进入到每个按键的中断服务函数后,可以根据情况,选择将标志置位或者清除,在定时器中断函数中读取相关标志位并做出相应操作。

3.3定时器中断

定时器初始化代码如下

 TIM3_Int_Init(100,7199);//时钟周期72M/(7199+1)=10k,10Khz的计数频率,计数到计数到100,为10ms  
void TIM3_Int_Init(u16 arr,u16 psc)
{TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位//使能或者失能指定的TIM中断//TIM3//使能TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设
}

定时器中断中需注意分频系数与装载值,这两个参数决定了计数频率,具体公式在注释中有写。

将定时器中断初始化好,就可在定时器中断服务函数中编写代码了。

(注意:一般情况下,定时器初始化都在最后配置,因为一旦配置完成,定时器自动执行中断,可能会影响其他外设的初始化,造成初始化失败)

定时器中断服务函数如下

extern volatile u8 start_flag;  //开始标
extern volatile u8 suspend_flag;//暂停标
extern volatile u8 zero_flag;   //清零标extern volatile u8 m; //分钟
extern volatile u8 s; //秒位
extern volatile u8 ms;//毫秒位void TIM3_IRQHandler(void)   //TIM3中断
{if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 {if(zero_flag==1)//数值清零{s=0;//清零m=0;ms=0;    zero_flag=0;//清零后把自己置零,保证清一次,不然数值永远是0}if(start_flag==1)//只要在开始模式下{if(suspend_flag==1){;//暂停按下,数值不再自加}     else//正常计时{ms++;  //毫秒位if(ms>=100){s++;//进位操作ms=0;}if(s>=60){m++;//进位操作s=0;}}}TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源 LED1=!LED1;}
}

根据在定时器中断设置的几个标志位,来决定时间是自增,还是空跑。

3.4main函数

while(1) {        LCD_ShowxNum(60+0*12,80,m,2,24,0);//显示LCD_ShowxNum(60+4*12,80,s,2,24,0);LCD_ShowxNum(60+7*12,80,ms,2,24,0);} 

在main函数中只有显示这一功能,注意显示区域,不要重叠即可。

4.总结

设计了一个简易秒表,通过按键外部中断来控制开始,暂停,清零等功能,计时功能通过10ms的定时器中断,60一进位,完成时分秒的显示,在main函数调用屏幕显示函数将将关数据显示出来。

计时精度其实不高,估计STM32的72M的晶振产生的10ms中断未必是真的10ms,或者屏幕显示占用了一定的时间,这些误差随着时间是积累,误差会越来越大,实测每一分钟大概会慢0.5秒左右,所以仅供学习参考,不建议实际使用。

开源代码如下:基于STM32的秒表项目: 基于STM32的秒表项目,有三个按键,启动,暂停,归零,时间数据在LCD屏幕上显示,显示到0.01秒https://gitee.com/xu-shuhao/stopwatch.git

欢迎支持,有问题欢迎交流讨论。

qq:2296449414

基于STM32外部中断系统的秒表的设计相关推荐

  1. 单片机毕业设计 基于stm32的病房呼叫系统

    文章目录 1 简介 2 绪论 2.1 课题背景 3 系统设计 3.1 系统架构 3.2 主程序设计 3.3 语音模块程序设计 3.4 显示模块程序设计 3.5 键盘模块程序设计 3.6 无线传输模块程 ...

  2. STM32外部中断与各通道对应关系

    EXTI0_IRQn的值,其实就是EXTI0中断向量在中断向量表中的位置(STM32技术参考手册中断向量表position栏中的数值) 一:外部中断使用配置过程: (1)配置时钟信号 (2)引脚属性 ...

  3. STM32外部中断总结

    STM32外部中断总结 STM32的外部中断是我们在学习stm32的一个必要模块,外部中断的用途可以增加人机交互的体验,也可以增加程序的执行效率.下面将以一个小实验来记录外部中断的使用需要注意的事项 ...

  4. 基于STM32的最小系统电路设计(手把手零基础教学)

    文章目录 前言 一.复位电路 二.晶振电路 三.电源转换电路 四.SWD下载电路 五.LED测试电路 六.芯片外扩引脚 七.STM32微控制电路 总结 前言    在上篇介绍完<STM32的核心 ...

  5. STM32——外部中断

    目录 外部中断简述 什么是外部中断 传统单片机与新型单片机外部中断区别 STM32外部中断请求 STM32中断线与IO口的对应 STM32 中断服务函数 外部中断与中断服务函数的对应 中断服务函数列表 ...

  6. 基于STM32视频监控系统

    目录 一.项目需求 二.原理图 三.上位机界面 四.实物 五.程序 六.说明文档 七.资料清单 资料下载地址:基于STM32视频监控系统 一.项目需求 上位机能够实时显示摄像头的画面,并且可以控制摄像 ...

  7. STM32外部中断与(NVIC)中断优先级管理

    文章目录 1.中断介绍 1.中断的概念 2.中断的产生 3.中断处理的流程 2.STM32内嵌向量中断控制器NVIC 1.NVIC控制器的寄存器 2.STM32中断配置 3.STM32外部中断EXIT ...

  8. STM32外部中断与看门狗

    STM32外部中断与看门狗 前面说过中断的概念了,但是没有细究,中断除了内部中断(比如运行错误),还能受到外部中断 文章目录 STM32外部中断与看门狗 一 外部中断描述 1.1 外部中断描述 1.2 ...

  9. STM32外部中断干扰解决方案

    STM32 外部中断很容易受干扰误触发,无论上拉下拉设置都没有效果,最后采用软件判断解决该问题. 进入外部中断程序需同时判断引脚电平是否和上升触发和下降触发一致,这个判断很重要. void EXTI3 ...

最新文章

  1. JS设计模式—节流模式的实际应用
  2. matlab平面绘图命令
  3. HTML5怎样创建画布?
  4. boost::mp11::mp_partial_sum相关用法的测试程序
  5. 《构建实时机器学习系统》一1.8 实时机器学习模型的生存期
  6. 【牛客 - 157F】三轮(dp,分治fft)
  7. 特别推荐:系统性能提升优先法宝 | 缓存应用实践
  8. zabbix企业应用:通过SNMP和iDRAC监控DELL服务器硬件
  9. 全球唯一标识符 System.Guid.NewGuid().ToString()
  10. 有向图生成树个数(bzoj 4894: 天赋)
  11. Win8:Setting
  12. 用户输出表单处理php
  13. vmlinuz文件解压方法
  14. html 字体图标大小,CSS ICONFONT 基线和大小问题
  15. java多线程编程实例
  16. Android 通过应用设置系统日期和时间的方法
  17. 电子计算机与其它计算机工具的本质区别是,电子计算机与其他计算工具的本质区别是...
  18. 山西农业大学计算机科学与技术分数线,山西农业大学计算机科学与技术专业2016年在湖北理科高考录取最低分数线...
  19. android程序怎样远程控制手机,如何用手机远程控制手机(安卓),看这就够了,怎样使用手机远程控制它人手机...
  20. win10主题更换_【小A问答】遇到超好看的Win10主题壁纸如何提取?

热门文章

  1. python删除空文件夹脚本
  2. linux 远程桌面
  3. Python numpy输出省略号
  4. 计算机网络实验三:TCP Tahoe与Reno运行机制对比分析
  5. 天天正能量:没有到不了的明天
  6. 允许计算机关闭此设备 蓝牙,大师为你解决win7系统配置蓝牙时“允许Bluetooth设备连接到此计算机”选项灰色的修复步骤...
  7. 锤子的“中年危机” | 一点财经
  8. 苹果电脑双系统怎么切换 苹果电脑双系统的切换方法
  9. 数据结构课程设计——停车场管理系统
  10. 【精讲】PCIe Quality of Service(QoS)机制