当前位置:   article > 正文

基于STM32的智能药盒(2)--按键部分以及药品数量计数_基于stm32的多功能智能药盒自动出药

基于stm32的多功能智能药盒自动出药

 药品计数我们使用这种计数器模块,原理类似投币机。后续我们通过编程外部中断来实现精准计数。

选择PA12作为信号输入脚,配置成外部中断模式。

按键的话我们使用4个,依次配置成GPIO输入模式,由于设计时候将按键接地所以当按键按下时候检测为低电平,默认我们将其上拉。配置如下图

依次完成KEY1、2、3、4的设置。

按键操作时候存在物理抖动,需要抖动消除。此次没采用延时函数,采用定时器计时方式过度按键抖动。定时器配置如下。

定时器设置为72000000/71/10000=100hz,等于10ms。

完成上诉配置后生成工程代码。

按键的程序设计如下所示,我们将按键检测丢入定时器回调函数,每10ms检测一次,然后通过状态机结构体进行长按和短按检测,后续进行一个时钟或者定时闹钟设置时候希望通过长按方式实现。

KEY.C

  1. #include "interrupt.h"
  2. #include "usart.h"
  3. #include "stdio.h"
  4. extern uint8_t clock_state;
  5. struct keys key[4]={0,0,0};
  6. uint8_t txbuf[20];
  7. extern uint8_t shi_clock,fen_clock,miao_clock;
  8. extern uint8_t set_num;
  9. extern bool clock_flag;
  10. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  11. {
  12. if(htim->Instance==TIM3)
  13. {
  14. DS1302_ReadTime();
  15. if(clock_state==1)
  16. {
  17. HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
  18. HAL_GPIO_TogglePin(BEEP_GPIO_Port,BEEP_Pin);
  19. }
  20. if(clock_flag==1)
  21. {
  22. sprintf((char *)txbuf,"%u:%u:%u:%u",shi_clock,fen_clock,miao_clock,set_num);
  23. HAL_UART_Transmit(&huart3,txbuf,sizeof(txbuf),0xffff);
  24. }
  25. else if(clock_flag==0)
  26. {
  27. HAL_UART_Transmit(&huart3,(uint8_t *)"NONE",4,0xffff);
  28. }
  29. }
  30. else if(htim->Instance==TIM4)
  31. {
  32. key[0].key_sta=HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin);
  33. key[1].key_sta=HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin);
  34. key[2].key_sta=HAL_GPIO_ReadPin(KEY3_GPIO_Port,KEY3_Pin);
  35. key[3].key_sta=HAL_GPIO_ReadPin(KEY4_GPIO_Port,KEY4_Pin);
  36. for(int i=0;i<4;i++)
  37. {
  38. switch(key[i].judge_sta)
  39. {
  40. case 0:
  41. {
  42. if(key[i].key_sta==0)
  43. {
  44. key[i].judge_sta=1;
  45. key[i].key_time=0;
  46. }
  47. }
  48. break;
  49. case 1:
  50. {
  51. if(key[i].key_sta==0)
  52. {
  53. key[i].judge_sta=2;
  54. }
  55. else key[i].judge_sta=0;
  56. }
  57. break;
  58. case 2:
  59. {
  60. if(key[i].key_sta==1)
  61. {
  62. key[i].judge_sta=0;
  63. if(key[i].key_time<70) key[i].single_flag=1;
  64. }
  65. else
  66. {
  67. key[i].key_time++;
  68. if(key[i].key_time>70) key[i].long_flag=1;
  69. }
  70. }
  71. break;
  72. }
  73. }
  74. }
  75. }

KEY.h文件 

  1. #ifndef __INTERRUPT_H__
  2. #define __INTERRUPT_H__
  3. #include "main.h"
  4. #include "ds1302.h"
  5. #include "stdbool.h"
  6. struct keys
  7. {
  8. unsigned char judge_sta;
  9. bool key_sta;
  10. bool single_flag;
  11. unsigned int key_time;
  12. bool long_flag;
  13. };
  14. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
  15. #endif

在主函数开头中开启定时器HAL_TIM_Base_Start_IT(&htim4);

外部中断的判断通过外部中断回调函数。

  1. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
  2. {
  3. last_state=1;
  4. }

通过设置一个标志位让检测到外部中断就让标志位置1。

下面就展示下OLED菜单和按键联合使用。我们定义菜单变量uint8_t menu;

在主界面显示一个DS1302实时实现,如果开启了闹钟就是更新显示一个闹钟定时时间,也就是吃药时间和一个吃药数量。此时在主界面下按下按键1则menu=2进入下一个菜单页清空OLED显示新的内容。

  1. if(menu==1)
  2. {
  3. OLED_ShowChinese(0, 0,"当前");
  4. OLED_ShowChinese(0, 16,"时间");
  5. OLED_Printf(32, 0, OLED_8X16," 20%02d-%02d-%02d ",nian,yue,ri);
  6. OLED_Printf(42, 16, OLED_8X16," %02d-%02d-%02d ",shi,fen,miao);
  7. if(clock_flag==0)
  8. {
  9. OLED_ShowChinese(0, 40,"当前未设吃药时间");
  10. }
  11. if(clock_flag==1)
  12. {
  13. OLED_ShowChinese(0,32,"吃药时间");
  14. OLED_Printf(0,48, OLED_8X16," %02d-%02d-%02d ",shi_clock,fen_clock,miao_clock);
  15. OLED_ShowChinese(80,32,"数量");
  16. OLED_Printf(80,48, OLED_8X16," %02d ",set_num);
  17. }
  18. if(key[0].single_flag==1)
  19. {
  20. OLED_Clear();
  21. show_flag=1;
  22. menu=2;
  23. key[0].single_flag=0;
  24. }
  25. }

在菜单2底下会显示4行模式选择,分别为存药模式、取药模式、定时吃药模式、修改系统时钟时间。通过OLED反色显示实现在视觉上的一个换行,按下按键2往上走一行,按下按键3往下走一行。按下按键 1是表示确认键,依次跳转到对应的菜单功能页,按下按键4则表示返回上一个菜单也就是主界面。

  1. else if(menu==2)
  2. {
  3. if(show_flag==1)
  4. {
  5. OLED_ShowChinese(0, 0,"一、存药模式");
  6. OLED_ShowChinese(0, 16,"二、取药模式");
  7. OLED_ShowChinese(0, 32,"三、定时吃药模式");
  8. OLED_ShowChinese(0, 48,"四、修改系统时间");
  9. OLED_ReverseArea(0, 16*i, 128, 16);
  10. show_flag=0;
  11. }
  12. if(key[1].single_flag==1)
  13. {
  14. OLED_ReverseArea(0, 16*i, 128, 16);
  15. i--;
  16. show_flag=1;
  17. key[1].single_flag=0;
  18. if(i==255)i=3;
  19. }else if(key[2].single_flag==1)
  20. {
  21. OLED_ReverseArea(0, 16*i, 128, 16);
  22. i++;
  23. show_flag=1;
  24. key[2].single_flag=0;
  25. if(i>3)i=0;
  26. }
  27. else if(key[3].single_flag==1)
  28. {
  29. OLED_Clear();
  30. menu=1;
  31. key[3].single_flag=0;
  32. }
  33. else if(key[0].single_flag==1)
  34. {
  35. switch(i)
  36. {
  37. case 0:
  38. OLED_Clear();
  39. menu=3;
  40. break;
  41. case 1:
  42. OLED_Clear();
  43. menu=4;
  44. break;
  45. case 2:
  46. OLED_Clear();
  47. menu=5;
  48. break;
  49. case 3:
  50. OLED_Clear();
  51. menu=6;
  52. once_time=1;
  53. break;
  54. default:
  55. break;
  56. }
  57. key[0].single_flag=0;
  58. }
  59. }

下面代码中的菜单3、4、5、6分别为上面菜单中的4个功能页,我们在菜单3下,通过外部中断标志位形式记录存入药盒的药品数量,可以通过按键2和3进行数量微调防止传感器错误判断导致计数不准确,通过按键4返回上一界面。在菜单4底下,可以设置一个取药的数量,通过按键1确认取出对应数量药品。在菜单5下通过短按按键1来进行定时时间的时分秒设置以及吃药数量设置,通过长按按键1 完成设置,按键2和3依次对应加和减,按键4返回。菜单6下类似与菜单5就是对系统时间的一个设置,不单独赘述了。

  1. else if(menu==3)
  2. {
  3. OLED_ShowChinese(30,10,"存药模式");
  4. OLED_ShowChinese(10, 32,"剩余药量:");
  5. OLED_Printf(90,32, OLED_8X16, "%02d", temp);
  6. if(last_state==1)
  7. {
  8. last_state=0;
  9. last_count++;
  10. temp=last_count/2;
  11. }
  12. if(key[1].single_flag==1)
  13. {
  14. temp--;
  15. if(temp==255)temp=0;
  16. key[1].single_flag=0;
  17. }
  18. else if(key[2].single_flag==1)
  19. {
  20. temp++;
  21. key[2].single_flag=0;
  22. }
  23. else if(key[3].single_flag==1)
  24. {
  25. OLED_Clear();
  26. show_flag=1;
  27. menu=2;
  28. key[3].single_flag=0;
  29. }
  30. }
  31. else if(menu==4)
  32. {
  33. OLED_ShowChinese(30,0,"取药模式");
  34. OLED_ShowChinese(10, 26,"总剩余量:");
  35. OLED_Printf(90,26, OLED_8X16, "%02d", temp);
  36. OLED_ShowChinese(0, 42,"输入取出个数:");
  37. OLED_Printf(112,42, OLED_8X16, "%d", eat_num);
  38. if(key[3].single_flag==1)
  39. {
  40. OLED_Clear();
  41. show_flag=1;
  42. menu=2;
  43. key[3].single_flag=0;
  44. }else if(key[1].single_flag==1)
  45. {
  46. eat_num--;
  47. if(eat_num==255)eat_num=0;
  48. key[1].single_flag=0;
  49. }else if(key[2].single_flag==1)
  50. {
  51. eat_num++;
  52. if(eat_num>=temp)eat_num=temp;
  53. key[2].single_flag=0;
  54. }else if(key[0].single_flag==1)
  55. {
  56. temp=temp-eat_num;
  57. last_count=last_count-eat_num*2;
  58. eat_num=0;
  59. OLED_Clear();
  60. OLED_ShowChinese(30, 20,"取药成功");
  61. OLED_Update();
  62. HAL_Delay(500);
  63. OLED_Clear();
  64. key[0].single_flag=0;
  65. }
  66. }
  67. else if(menu==5)
  68. {
  69. OLED_ShowChinese(30,0,"定时吃药");
  70. OLED_Printf(30,16, OLED_8X16, "%02d--%02d--%02d", shi_clock,fen_clock,miao_clock);
  71. OLED_ShowChinese(20,32,"设置吃药数量");
  72. OLED_Printf(55,48, OLED_8X16, "%02d", set_num);
  73. if(j<=2)OLED_ReverseArea(30+j*32, 16, 16, 16);
  74. else if(j>2)OLED_ReverseArea(55+(j-3)*32, 48, 16, 16);
  75. if(once_time==1)
  76. {
  77. shi_clock=shi;
  78. fen_clock=fen+1;
  79. miao_clock=miao;
  80. once_time=0;
  81. }
  82. if(key[0].single_flag==1)
  83. {
  84. j++;
  85. if(j==4)j=0;
  86. key[0].single_flag=0;
  87. }
  88. else if(key[1].single_flag==1)
  89. {
  90. if(j==0)
  91. {
  92. shi_clock--;
  93. if(shi_clock==255)shi_clock=24;
  94. }
  95. else if(j==1)
  96. {
  97. fen_clock--;
  98. if(fen_clock==255)fen_clock=59;
  99. }
  100. else if(j==2)
  101. {
  102. miao_clock--;
  103. if(miao_clock==255)miao_clock=59;
  104. }
  105. else if(j==3)
  106. {
  107. set_num--;
  108. if(set_num==255)set_num=0;
  109. }
  110. key[1].single_flag=0;
  111. }
  112. else if(key[2].single_flag==1)
  113. {
  114. if(j==0)
  115. {
  116. shi_clock++;
  117. if(shi_clock==25)shi_clock=0;
  118. }
  119. else if(j==1)
  120. {
  121. fen_clock++;
  122. if(fen_clock==60)fen_clock=0;
  123. }
  124. else if(j==2)
  125. {
  126. miao_clock++;
  127. if(miao_clock==60)miao_clock=0;
  128. }
  129. else if(j==3)set_num++;
  130. key[2].single_flag=0;
  131. }
  132. else if(key[3].single_flag==1)
  133. {
  134. OLED_Clear();
  135. j=0;
  136. show_flag=1;
  137. menu=2;
  138. key[3].single_flag=0;
  139. }
  140. else if(key[0].long_flag==1)
  141. {
  142. clock_flag=!clock_flag;
  143. OLED_Clear();
  144. if(clock_flag==1)OLED_ShowChinese(30, 20,"开启定时");
  145. else if(clock_flag==0)OLED_ShowChinese(30, 20,"关闭定时");
  146. OLED_Update();
  147. HAL_Delay(500);
  148. OLED_Clear();
  149. key[0].long_flag=0;
  150. }
  151. }
  152. else if(menu==6)
  153. {
  154. if(once_time==1)
  155. {
  156. shi1=shi;
  157. fen1=fen;
  158. miao1=miao;
  159. nian1=nian;
  160. yue1=yue;
  161. ri1=ri;
  162. once_time=0;
  163. }
  164. OLED_ShowChinese(20,0,"修改系统时间");
  165. OLED_Printf(30,20, OLED_8X16, "%02d--%02d--%02d", nian1,yue1,ri1);
  166. OLED_Printf(30,36, OLED_8X16, "%02d--%02d--%02d", shi1,fen1,miao1);
  167. if(j<=2)OLED_ReverseArea(30+j*32, 20, 16, 16);
  168. else if(j>2)OLED_ReverseArea(30+(j-3)*32, 36, 16, 16);
  169. if(key[0].single_flag==1)
  170. {
  171. j++;
  172. if(j==6)j=0;
  173. key[0].single_flag=0;
  174. }
  175. else if(key[1].single_flag==1)
  176. {
  177. if(j==0)
  178. {
  179. nian1--;
  180. if(nian1==255)nian=99;
  181. }
  182. else if(j==1)
  183. {
  184. yue1--;
  185. if(yue1==0)yue1=12;
  186. }
  187. else if(j==2)
  188. {
  189. ri1--;
  190. if(ri1==0)ri1=31;
  191. }
  192. else if(j==3)
  193. {
  194. shi1--;
  195. if(shi1==255)shi1=24;
  196. }
  197. else if(j==4)
  198. {
  199. fen1--;
  200. if(fen1==255)fen1=59;
  201. }
  202. else if(j==5)
  203. {
  204. miao1--;
  205. if(miao1==255)miao1=59;
  206. }
  207. key[1].single_flag=0;
  208. }
  209. else if(key[2].single_flag==1)
  210. {
  211. if(j==0)nian1++;
  212. else if(j==1)
  213. {
  214. yue1++;
  215. if(yue1==13)yue1=1;
  216. }
  217. else if(j==2)
  218. {
  219. ri1++;
  220. if(ri1==32)ri1=1;
  221. }
  222. else if(j==3)
  223. {
  224. shi1++;
  225. if(shi1==25)shi1=0;
  226. }
  227. else if(j==4)
  228. {
  229. fen1++;
  230. if(fen1==60)fen1=0;
  231. }
  232. else if(j==5)
  233. {
  234. miao1++;
  235. if(miao1==60)miao1=0;
  236. }
  237. key[2].single_flag=0;
  238. }
  239. else if(key[3].single_flag==1)
  240. {
  241. OLED_Clear();
  242. show_flag=1;
  243. j=0;
  244. menu=2;
  245. key[3].single_flag=0;
  246. }
  247. else if(key[0].long_flag==1)
  248. {
  249. DS1302_SetTime();
  250. OLED_Clear();
  251. OLED_ShowChinese(30,20,"修改成功");
  252. OLED_Update();
  253. HAL_Delay(500);
  254. OLED_Clear();
  255. j=0;
  256. key[0].long_flag=0;
  257. }
  258. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/462366
推荐阅读
相关标签
  

闽ICP备14008679号