赞
踩
药品计数我们使用这种计数器模块,原理类似投币机。后续我们通过编程外部中断来实现精准计数。
选择PA12作为信号输入脚,配置成外部中断模式。
按键的话我们使用4个,依次配置成GPIO输入模式,由于设计时候将按键接地所以当按键按下时候检测为低电平,默认我们将其上拉。配置如下图
依次完成KEY1、2、3、4的设置。
按键操作时候存在物理抖动,需要抖动消除。此次没采用延时函数,采用定时器计时方式过度按键抖动。定时器配置如下。
定时器设置为72000000/71/10000=100hz,等于10ms。
完成上诉配置后生成工程代码。
按键的程序设计如下所示,我们将按键检测丢入定时器回调函数,每10ms检测一次,然后通过状态机结构体进行长按和短按检测,后续进行一个时钟或者定时闹钟设置时候希望通过长按方式实现。
KEY.C
- #include "interrupt.h"
- #include "usart.h"
- #include "stdio.h"
- extern uint8_t clock_state;
- struct keys key[4]={0,0,0};
- uint8_t txbuf[20];
- extern uint8_t shi_clock,fen_clock,miao_clock;
- extern uint8_t set_num;
- extern bool clock_flag;
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
- {
- if(htim->Instance==TIM3)
- {
- DS1302_ReadTime();
- if(clock_state==1)
- {
- HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
- HAL_GPIO_TogglePin(BEEP_GPIO_Port,BEEP_Pin);
- }
- if(clock_flag==1)
- {
- sprintf((char *)txbuf,"%u:%u:%u:%u",shi_clock,fen_clock,miao_clock,set_num);
- HAL_UART_Transmit(&huart3,txbuf,sizeof(txbuf),0xffff);
- }
- else if(clock_flag==0)
- {
- HAL_UART_Transmit(&huart3,(uint8_t *)"NONE",4,0xffff);
- }
- }
- else if(htim->Instance==TIM4)
- {
- key[0].key_sta=HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin);
- key[1].key_sta=HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin);
- key[2].key_sta=HAL_GPIO_ReadPin(KEY3_GPIO_Port,KEY3_Pin);
- key[3].key_sta=HAL_GPIO_ReadPin(KEY4_GPIO_Port,KEY4_Pin);
- for(int i=0;i<4;i++)
- {
- switch(key[i].judge_sta)
- {
- case 0:
- {
- if(key[i].key_sta==0)
- {
- key[i].judge_sta=1;
- key[i].key_time=0;
- }
- }
- break;
- case 1:
- {
- if(key[i].key_sta==0)
- {
- key[i].judge_sta=2;
-
- }
- else key[i].judge_sta=0;
- }
- break;
- case 2:
- {
- if(key[i].key_sta==1)
- {
- key[i].judge_sta=0;
- if(key[i].key_time<70) key[i].single_flag=1;
- }
- else
- {
- key[i].key_time++;
- if(key[i].key_time>70) key[i].long_flag=1;
- }
- }
- break;
- }
- }
- }
- }
-
KEY.h文件
- #ifndef __INTERRUPT_H__
- #define __INTERRUPT_H__
-
- #include "main.h"
- #include "ds1302.h"
- #include "stdbool.h"
-
- struct keys
- {
- unsigned char judge_sta;
- bool key_sta;
- bool single_flag;
- unsigned int key_time;
- bool long_flag;
- };
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
-
- #endif
在主函数开头中开启定时器HAL_TIM_Base_Start_IT(&htim4);
外部中断的判断通过外部中断回调函数。
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
- {
- last_state=1;
- }
通过设置一个标志位让检测到外部中断就让标志位置1。
下面就展示下OLED菜单和按键联合使用。我们定义菜单变量uint8_t menu;
在主界面显示一个DS1302实时实现,如果开启了闹钟就是更新显示一个闹钟定时时间,也就是吃药时间和一个吃药数量。此时在主界面下按下按键1则menu=2进入下一个菜单页清空OLED显示新的内容。
- if(menu==1)
- {
- OLED_ShowChinese(0, 0,"当前");
- OLED_ShowChinese(0, 16,"时间");
- OLED_Printf(32, 0, OLED_8X16," 20%02d-%02d-%02d ",nian,yue,ri);
- OLED_Printf(42, 16, OLED_8X16," %02d-%02d-%02d ",shi,fen,miao);
- if(clock_flag==0)
- {
- OLED_ShowChinese(0, 40,"当前未设吃药时间");
- }
- if(clock_flag==1)
- {
- OLED_ShowChinese(0,32,"吃药时间");
- OLED_Printf(0,48, OLED_8X16," %02d-%02d-%02d ",shi_clock,fen_clock,miao_clock);
- OLED_ShowChinese(80,32,"数量");
- OLED_Printf(80,48, OLED_8X16," %02d ",set_num);
- }
- if(key[0].single_flag==1)
- {
- OLED_Clear();
- show_flag=1;
- menu=2;
- key[0].single_flag=0;
- }
- }
在菜单2底下会显示4行模式选择,分别为存药模式、取药模式、定时吃药模式、修改系统时钟时间。通过OLED反色显示实现在视觉上的一个换行,按下按键2往上走一行,按下按键3往下走一行。按下按键 1是表示确认键,依次跳转到对应的菜单功能页,按下按键4则表示返回上一个菜单也就是主界面。
- else if(menu==2)
- {
- if(show_flag==1)
- {
- OLED_ShowChinese(0, 0,"一、存药模式");
- OLED_ShowChinese(0, 16,"二、取药模式");
- OLED_ShowChinese(0, 32,"三、定时吃药模式");
- OLED_ShowChinese(0, 48,"四、修改系统时间");
- OLED_ReverseArea(0, 16*i, 128, 16);
- show_flag=0;
- }
- if(key[1].single_flag==1)
- {
- OLED_ReverseArea(0, 16*i, 128, 16);
- i--;
- show_flag=1;
- key[1].single_flag=0;
- if(i==255)i=3;
- }else if(key[2].single_flag==1)
- {
- OLED_ReverseArea(0, 16*i, 128, 16);
- i++;
- show_flag=1;
- key[2].single_flag=0;
- if(i>3)i=0;
- }
- else if(key[3].single_flag==1)
- {
- OLED_Clear();
- menu=1;
- key[3].single_flag=0;
- }
- else if(key[0].single_flag==1)
- {
- switch(i)
- {
- case 0:
- OLED_Clear();
- menu=3;
- break;
- case 1:
- OLED_Clear();
- menu=4;
- break;
- case 2:
- OLED_Clear();
- menu=5;
- break;
- case 3:
- OLED_Clear();
- menu=6;
- once_time=1;
- break;
- default:
- break;
- }
- key[0].single_flag=0;
- }
- }
下面代码中的菜单3、4、5、6分别为上面菜单中的4个功能页,我们在菜单3下,通过外部中断标志位形式记录存入药盒的药品数量,可以通过按键2和3进行数量微调防止传感器错误判断导致计数不准确,通过按键4返回上一界面。在菜单4底下,可以设置一个取药的数量,通过按键1确认取出对应数量药品。在菜单5下通过短按按键1来进行定时时间的时分秒设置以及吃药数量设置,通过长按按键1 完成设置,按键2和3依次对应加和减,按键4返回。菜单6下类似与菜单5就是对系统时间的一个设置,不单独赘述了。
- else if(menu==3)
- {
- OLED_ShowChinese(30,10,"存药模式");
- OLED_ShowChinese(10, 32,"剩余药量:");
- OLED_Printf(90,32, OLED_8X16, "%02d", temp);
- if(last_state==1)
- {
- last_state=0;
- last_count++;
- temp=last_count/2;
- }
- if(key[1].single_flag==1)
- {
- temp--;
- if(temp==255)temp=0;
- key[1].single_flag=0;
- }
- else if(key[2].single_flag==1)
- {
- temp++;
- key[2].single_flag=0;
- }
- else if(key[3].single_flag==1)
- {
- OLED_Clear();
- show_flag=1;
- menu=2;
- key[3].single_flag=0;
- }
- }
- else if(menu==4)
- {
- OLED_ShowChinese(30,0,"取药模式");
- OLED_ShowChinese(10, 26,"总剩余量:");
- OLED_Printf(90,26, OLED_8X16, "%02d", temp);
- OLED_ShowChinese(0, 42,"输入取出个数:");
- OLED_Printf(112,42, OLED_8X16, "%d", eat_num);
- if(key[3].single_flag==1)
- {
- OLED_Clear();
- show_flag=1;
- menu=2;
- key[3].single_flag=0;
- }else if(key[1].single_flag==1)
- {
- eat_num--;
- if(eat_num==255)eat_num=0;
- key[1].single_flag=0;
- }else if(key[2].single_flag==1)
- {
- eat_num++;
- if(eat_num>=temp)eat_num=temp;
- key[2].single_flag=0;
- }else if(key[0].single_flag==1)
- {
- temp=temp-eat_num;
- last_count=last_count-eat_num*2;
- eat_num=0;
- OLED_Clear();
- OLED_ShowChinese(30, 20,"取药成功");
- OLED_Update();
- HAL_Delay(500);
- OLED_Clear();
- key[0].single_flag=0;
- }
- }
- else if(menu==5)
- {
- OLED_ShowChinese(30,0,"定时吃药");
- OLED_Printf(30,16, OLED_8X16, "%02d--%02d--%02d", shi_clock,fen_clock,miao_clock);
- OLED_ShowChinese(20,32,"设置吃药数量");
- OLED_Printf(55,48, OLED_8X16, "%02d", set_num);
- if(j<=2)OLED_ReverseArea(30+j*32, 16, 16, 16);
- else if(j>2)OLED_ReverseArea(55+(j-3)*32, 48, 16, 16);
- if(once_time==1)
- {
- shi_clock=shi;
- fen_clock=fen+1;
- miao_clock=miao;
- once_time=0;
- }
- if(key[0].single_flag==1)
- {
- j++;
- if(j==4)j=0;
- key[0].single_flag=0;
- }
- else if(key[1].single_flag==1)
- {
- if(j==0)
- {
- shi_clock--;
- if(shi_clock==255)shi_clock=24;
- }
- else if(j==1)
- {
- fen_clock--;
- if(fen_clock==255)fen_clock=59;
- }
- else if(j==2)
- {
- miao_clock--;
- if(miao_clock==255)miao_clock=59;
- }
- else if(j==3)
- {
- set_num--;
- if(set_num==255)set_num=0;
- }
- key[1].single_flag=0;
- }
- else if(key[2].single_flag==1)
- {
- if(j==0)
- {
- shi_clock++;
- if(shi_clock==25)shi_clock=0;
- }
- else if(j==1)
- {
- fen_clock++;
- if(fen_clock==60)fen_clock=0;
- }
- else if(j==2)
- {
- miao_clock++;
- if(miao_clock==60)miao_clock=0;
- }
- else if(j==3)set_num++;
- key[2].single_flag=0;
- }
- else if(key[3].single_flag==1)
- {
- OLED_Clear();
- j=0;
- show_flag=1;
- menu=2;
- key[3].single_flag=0;
- }
- else if(key[0].long_flag==1)
- {
- clock_flag=!clock_flag;
- OLED_Clear();
- if(clock_flag==1)OLED_ShowChinese(30, 20,"开启定时");
- else if(clock_flag==0)OLED_ShowChinese(30, 20,"关闭定时");
- OLED_Update();
- HAL_Delay(500);
- OLED_Clear();
- key[0].long_flag=0;
- }
- }
- else if(menu==6)
- {
- if(once_time==1)
- {
- shi1=shi;
- fen1=fen;
- miao1=miao;
- nian1=nian;
- yue1=yue;
- ri1=ri;
- once_time=0;
- }
- OLED_ShowChinese(20,0,"修改系统时间");
- OLED_Printf(30,20, OLED_8X16, "%02d--%02d--%02d", nian1,yue1,ri1);
- OLED_Printf(30,36, OLED_8X16, "%02d--%02d--%02d", shi1,fen1,miao1);
- if(j<=2)OLED_ReverseArea(30+j*32, 20, 16, 16);
- else if(j>2)OLED_ReverseArea(30+(j-3)*32, 36, 16, 16);
- if(key[0].single_flag==1)
- {
- j++;
- if(j==6)j=0;
- key[0].single_flag=0;
- }
- else if(key[1].single_flag==1)
- {
- if(j==0)
- {
- nian1--;
- if(nian1==255)nian=99;
- }
- else if(j==1)
- {
- yue1--;
- if(yue1==0)yue1=12;
- }
- else if(j==2)
- {
- ri1--;
- if(ri1==0)ri1=31;
- }
- else if(j==3)
- {
- shi1--;
- if(shi1==255)shi1=24;
- }
- else if(j==4)
- {
- fen1--;
- if(fen1==255)fen1=59;
- }
- else if(j==5)
- {
- miao1--;
- if(miao1==255)miao1=59;
- }
- key[1].single_flag=0;
- }
- else if(key[2].single_flag==1)
- {
- if(j==0)nian1++;
- else if(j==1)
- {
- yue1++;
- if(yue1==13)yue1=1;
- }
- else if(j==2)
- {
- ri1++;
- if(ri1==32)ri1=1;
- }
- else if(j==3)
- {
- shi1++;
- if(shi1==25)shi1=0;
- }
- else if(j==4)
- {
- fen1++;
- if(fen1==60)fen1=0;
- }
- else if(j==5)
- {
- miao1++;
- if(miao1==60)miao1=0;
- }
- key[2].single_flag=0;
- }
- else if(key[3].single_flag==1)
- {
- OLED_Clear();
- show_flag=1;
- j=0;
- menu=2;
- key[3].single_flag=0;
- }
- else if(key[0].long_flag==1)
- {
- DS1302_SetTime();
- OLED_Clear();
- OLED_ShowChinese(30,20,"修改成功");
- OLED_Update();
- HAL_Delay(500);
- OLED_Clear();
- j=0;
- key[0].long_flag=0;
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。