目录
前言
设计的内容
(1)显示
(2)定时时间与用药量的设定
(3)实时时间调节
(4)报警功能
时钟模块
蓝牙模块
系统软件设计
系统主程序
按键函数
中断服务函数
作品展示
测试药定时提醒功能
完整代码
近年来,疫情反复,这让一些家庭使得自己的家里的老人造成了没有人照看的状态,那这就会出现一个问题,那就是我国现在的医疗物资非常的紧张,因为收到了疫情的影响,相关的专业的人员都已经开始向智慧云药能方面开始发展了,同时现在也是大数据的社会在这样的时代的背景下,那些对自身健康问题越来越重视的人,就能够从网络上获取到很多有关于医疗的信息,所以为了迎合拿下记忆力下降而遇到事情就容易忘记的健忘人员,对于他们的需求,就由此提出了一种可以给基于嵌入式单片机的智能药盒的设计方案。
首先介绍一下本设计的使用的LCD160液晶显示屏幕的显示的原理,以及实时时钟模块运行的原理和声控光控报警系统模块的原理。
系统的硬件部分由以下几个模块组成:STC90C51单片机、4×2键盘模块、LCD1602液晶显示屏幕模块、声光报警模块、HC-05蓝牙模块。其中LCD1602液晶显示屏幕模块可以实现实时日期、时间显示功能,键盘模块可以实现对时间、药物用量的设置,声光报警模块可以实现定时时间的提醒,HC-05模块建立单片机与手机之间的链接。
其中系统实现的基本功能具体如下:
采用LCD1602液晶屏幕显示实时日期时间、用药种类及用量等。
系统将在LCD屏幕上显示并实现三种药物用量以及时间的定时设置,分别通过键盘模块中的七个按键完成。
其中七个按键的功能具体为:一个设置键,记为k1,负责进入设置状态;一个功能键记为k2,负责进入三种药品的用药量设置状态;两个调节键,分别记为k7、k8。其中k7的作用为药量增加1,k8的作用为药量减少1。三次定时对应的三个定时按键k4、k5、k6,按下即可停止蜂鸣器鸣警报。
实时时间通过三个按键进行调节,一个为设置键,记为k1,负责进入时间设置状态;另外两个个为调节键,记为k2、k3。其中k2的作用为增加时间,k3为减少时间。
系统内部程序存储器中,自动将系统时钟模块运行的实时时间与定时时间进行对比判断,在两者一致的情况下,蜂鸣器警报响起,且根据需要的服用药物种类,同时对应的LED发光二极管将持续闪烁。
本设计以STC90C516RD+单片机作为核心主控芯片,在本文中主要介绍系统复位电路以及内部振荡电路的原理。其中LCD1602屏幕显示模块则负责时间、日期、药物种类、用药量等设置[4],将简单介绍其原理组成、指令时序。由LED发光二极管与蜂鸣器电路组成的声光报警系统中,以蜂鸣器警报为主,LED则起到辅助报警功能。系统的基本原理为:各模块驱动程序运行后,系统主程序调用单片机和按键扫描子程序,将扫描结果发送给系统数据更新程序,反馈给LCD1602液晶屏幕显示模块,从而实现按键的输入信息显示功能。在声光报警电路中,程序将调用单片机细分读取数据并输入报警时间。
时间设置用三个按键完成,一个功能按键k1,两个调节按键k2、k3,在屏幕时间显示界面,按下功能按键后即可进入时间设置状态,两个调节按键k2、k3分别为时间增加1、减少1,最后按下功能按键直至退出设置状态,时钟开始工作。
药品用量设置用四个按键完成,两个功能按键,两个调节按键。其中一个功能键作用为屏幕由时间显示转换到药量显示,另一个即进入、退出设置状态。两个调节按键分别为药量增加1、减少1。
声光报警系统中,停止蜂鸣器警报与LED发光二极管的闪烁需要使用到三个按键,分别对应三种药物,按下即可停止;如果没有按下相应按键,则将在一分钟后,程序判定实时时钟超过固定时钟,即实时时间超过定时时间,判断结果为时间不相等,系统自动退出报警程序。
除了复位电路模块,在此次的单片机的应用系统中,按键键盘模块部分也是不可或缺的。键盘是计算机全部操作中使用的输入设备之一,通过用手指按压键盘按钮——通常按钮上附有对应文字标签,向计算机发送文字信号等。
键盘的开关主要有膜合开关、机械开关、电容无接点方式,其中,膜合开关和机械开关是完全数字的开关,只有触点关闭或触点打开两种状态。
本系统键盘电路共由8个按键按钮组成,并根据4×2的格式进行布局焊接。
按下键帽时,内置的电路成为闭路,电流流动,作为电信号被编码器读取并作为数字信号输入到单片机系统中。
本次系统所采用的是电磁式蜂鸣器,是利用电磁线圈对蜂鸣片的作用而发声,相对于压电式蜂鸣器,其运作时所需要的电压较低。
发光二极管是二极管的一种,与荧光灯、白炽灯泡等许多其他光源不同,LED会产生偏向特定波长的光。因此,有时由于不包含亮度所需要的波长的光,所以不能得到充分的效果。但LED结构简单,可以大量生产,从而价格相对白炽灯、荧光灯较为低廉,在当今市场上被广泛应用[5]。虽然LED对高温缺乏耐受性,其半导体的材质有可能因电路产生问题而发生故障,但其由于不使用灯丝,重量轻且耐冲击性强,由此可知寿命比白炽灯长。并且与需要稳定器的荧光灯相比,LED的电路比较简单。
发光二极管与其他一般二极管一样具有极性,在阳极上加正电压用于阴极,即电源正极与发光二极管的正极相连,阴极同理,此时将该电路中的电压称为“正向下降电压”。与一般将硅用作主原料的二极管相比,发光二极管的正向下降电压高。
单片机中,具有处理时间和一定周期等形式的时间相关功能的是定时/计时器。本次设计采用的是DS1302时钟芯片作为系统的定时/计时器,通过传送多个字节的时钟信号或RAM数据,对年月日期及时分秒进行计时。
时钟信号是指在电子基板和半导体芯片等内部,为了使多个电子电路发送接收信号的定时一致,有规则地被刻上的电信号。通过这样的信号使各电路的动作同步的方式称为时钟同步设计。信号的形式有几种,但最简单的时钟信号每隔一定的时间切换高电压和低电压,将电压从上升到下一个上升的时间(或从下降到下一个下降的时间)称为“时钟周期”,每单位时间的周期数 “时钟频率”。时钟频率越高,越能高速处理和收发数据。
时钟信号是由内置水晶和陶瓷振子的时钟振荡电路发出的,通过专用的信号线提供给各电路。虽然基板上的芯片或电路根据单个时钟进行操作,但是也可以仅在诸如CPU之类的特定芯片内以来自外部的信号的数倍的时钟信号高速工作。
无线通信主要是利用电波进行的电子通信,而使用电缆等作为传输线的通信称为有线通信。蓝牙是无线通信技术之一。使用超短波2.4GHz带宽,无线连接近距离的数字设备[7]。
蓝牙是一种只有小基础和电池的小型轻量装置,与Wi-Fi等无线LAN相比,价格与功耗较低,并且对于开发者来说具有较为容易理解的数据模型,在此基础上可以自由扩展功能,应用于各种服务。
当本系统主程序运行在不同阶段时,在系统逐步完成各个功能模块的初始化之后,将进入程序的循环状态,即此时系统正在运行扫描程序。之后根据所需,按下键盘模块上的按钮,向系统输入信息,于是系统内置的程序存储库中将信息命令判断并执行,这些操作完成之后LCD1602液晶显示屏将实时显示输入信息,同理可实现定时提醒、设定三种药物的剂量。
系统中的八个按键分别具有不同的职能,以下主要介绍设置键k1、功能键兼调节键k2、k3、调节键k7、k8:
(1)设置键,当屏幕显示实时时间时,按下即进入设置状态,同理可退出设置状态。
(2)在屏幕时间设置状态下,k2作为调节键,起到时间增加1的作用;相反,未进入时间设置状态时,k2作为功能键,按下即进入药量显示状态,此时可对三种药物的用量进行设置。同理,k3作为调节键时起到时间减少1的作用,作为功能键时可切换时间的显示。
(3)调节键k7为药量增加1,则k8为药量减少1。
在正常程序运行中,中断处理作为CPU的硬件功能实现,强制中断正常程序的执行。例如,从LED发光二极管闪烁这样简单的处理到在多任务操作系统中,有时必须停止程序的长时间运行。而在本系统时钟模块中,这种情况出现时将利用定时器中的中断子函数进行处理。
电路焊接完成得到单片机成品之后,经过对软件程序的设置并烧入,硬件成品上的键盘模块便可实现按键输入功能,对LCD1602屏幕上的时间进行设置与时间的定时,以及对屏幕时间显示内容进行切换显示为三种药品的用量界面,进行用量设置。完成以上步骤之后退出设置状态,系统便会按照设定的数值进行工作,然后在运行时判断是否启动报警程序。
LCD1602液晶屏幕时间显示界面如图25所示,在当前显示界面图中,第一行为日期,其中THU为英文Thursday的缩写,表示2022年4月13日为星期四;第二行为实时时间显示,采用24小时制,其显示分别为小时、分钟、秒.
时间显示 药量显示
蓝牙连接后的效果图
单片机实物上的键盘模块按钮按从左至右,先第一行后第二行的顺序命名为k1、k2、k3、k4、k5、k6、k7、k8。
如图28所示,按下k1或手机屏幕显示上的“按键①”,进入设置状态,,在此将单片机实时显示时间设定为16:59:54(24小时制)
LCD屏实时时间显示再次按下如上相同位置的按键,直至进入定时时间设置状态,“SET TIME1”即第一次定时时间,在此将其设定为17:00。
最后按下如上相同位置按键,直至退出时间设置状态,此时按下k2或“按键②”后LCD1602屏幕显示DRU1、DRU2、DRU3即三种药物的用量。而后用同上的按键进入设置状态。手机软件显示界面中, “药量加”即k7、“药量减”即k8。默认状态下三种药物用量均为零,需手动设置。到达定时时间时,用量不为一的情况下,声光报警系统发出提醒警报。如图30所示,将药物一用量设定为3,药物二用量为2,药物三用量为1。最后退出设置状态。
定时时间到,根据设定,如图31所示单片机上三盏LED灯闪烁同时伴随蜂鸣器警报响起。同理,若设定需服用药物种类用量仅为两种或一种,则LED闪烁对应两盏灯或一盏灯。
按下k2切换LCD屏幕显示药物种类及用量;或如图33所示,按下手机显示屏幕上名为“按键②”的按钮也能达到此目的。
手机“蓝牙串口”软件切换显示药量
#include "common.h"
#include "DS1302.h"
#include "lcd1602.h"
#include "uart.h"
#define UART_RX_BUF RX1_Buffer
sbit LED1 = P3^2;
sbit LED2 = P3^3;
sbit LED3 = P3^4;
sbit BEEP = P2^0;
uchar sec, min, hour, day, month, week, year;
sbit p_r=0;
bit displayMode=0;
uchar setn=0;
unsigned char bobao = 0;
unsigned char Dosage1=0;
unsigned char Dosage2=0;
unsigned char Dosage3=0;
uchar tx1_shi = 8,tx1_fen = 0;
uchar tx2_shi = 12,tx2_fen = 0;
uchar tx3_shi = 19,tx3_fen = 0;
uchar REMINDFLAG = 0x00;
void Timer0Init(void)
{
TMOD |= 0x01;
TL0 = 0x00;
TH0 = 0x4C;
ET0 = 1;
TR0 = 1;
EA = 1;
};
void write_week(uchar week)
{
lcd_write_com(0x80+12);
switch(week)
{
case 1:lcd_write_data('M');lcd_write_data('O');lcd_write_data('N');break;
case 2:lcd_write_data('T');lcd_write_data('U');lcd_write_data('E');break;
case 3:lcd_write_data('W');lcd_write_data('E');lcd_write_data('D');break;
case 4:lcd_write_data('T');lcd_write_data('H');lcd_write_data('U');break;
case 5:lcd_write_data('F');lcd_write_data('R');lcd_write_data('I');break;
case 6:lcd_write_data('S'); lcd_write_data('T');lcd_write_data('A');break;
case 7:lcd_write_data('S');lcd_write_data('U');lcd_write_data('N');break;}
lcd_write_data(' ');
}
void displayTime()
{
lcd_write_com(0x80);
lcd_write_data(' ');
lcd_write_data('2');
lcd_write_data('0');
lcd_write_data(year/10+0x30);
lcd_write_data(year%10+0x30);
lcd_write_data('-');
lcd_write_data(month/10+0x30);
lcd_write_data(month%10+0x30);
lcd_write_data('-');
lcd_write_data(day/10+0x30);
lcd_write_data(day%10+0x30);
lcd_write_data(' ');
write_week(week);
lcd_write_com(0x80+0x40+4);
lcd_write_data(hour/10+0x30);
lcd_write_data(hour%10+0x30);
lcd_write_data(':');
lcd_write_data(min/10+0x30);
lcd_write_data(min%10+0x30);
lcd_write_data(':');
lcd_write_data(sec/10+0x30);
lcd_write_data(sec%10+0x30);
}
void Run_DS1302(void)
{
v_W1302(0x8f, 0);
sec = bcdtodec(uc_R1302(0x81));
v_W1302(0x8f, 0);
min = bcdtodec(uc_R1302(0x83));
v_W1302(0x8f, 0);
hour = bcdtodec(uc_R1302(0x85));
v_W1302(0x8f, 0);
day = bcdtodec(uc_R1302(0x87));
v_W1302(0x8f, 0);
month = bcdtodec(uc_R1302(0x89));
v_W1302(0x8f, 0);
week = bcdtodec(uc_R1302(0x8b));
v_W1302(0x8f, 0);
year = bcdtodec(uc_R1302(0x8d));
if(!displayMode)
displayTime();
}
void displayDosage()
{
if(Dosage1==0)
{lcd_write_char(1,1,'-');
lcd_write_char(2,1,'-');}
else{
lcd_write_char(1,1,Dosage1/10+'0');
lcd_write_char(2,1,Dosage1%10+'0');
}
if(Dosage2==0)
{
lcd_write_char(7,1,'-');
lcd_write_char(8,1,'-');}
else{
lcd_write_char(7,1,Dosage2/10+'0');
lcd_write_char(8,1,Dosage2%10+'0');}
if(Dosage3==0)
{
lcd_write_char(13,1,'-');
lcd_write_char(14,1,'-');
}
else
{
lcd_write_char(13,1,Dosage3/10+'0');
lcd_write_char(14,1,Dosage3%10+'0');
}
}
//灯状态
void LedState()
{
if(REMINDFLAG&0x01)
LED1=0;
else
LED1=1;
if(REMINDFLAG&0x02)
LED2=0;
else
LED2=1;
if(REMINDFLAG&0x04)
LED3=0;
else LED3=1;
}
//按键扫描
void keyscan()
{
uint nian_temp;
if(P1==0xFE || strstr(UART_RX_BUF,"k1")!=NULL)
{
delay_ms(30);
if(P1==0xFE || strstr(UART_RX_BUF,"k1")!=NULL)
{
memset(UART_RX_BUF, 0, COM_RX1_Lenth);
RX1_RxCounter = 0;
bobao = 0;
setn++;
if(!displayMode
{
if(setn > 13){setn = 0;
lcd_write_com(0x0c);
lcd_clear();}
if(setn == 1)
{
bobao = 0;
displayTime();
lcd_write_com(0x80+4);
lcd_write_com(0x0f);}
if(setn == 2)
{
lcd_write_com(0x80+7);
lcd_write_com(0x0f);
}
if(setn == 3)
{
lcd_write_com(0x80+10);
lcd_write_com(0x0f);
}
if(setn == 4)
{
lcd_write_com(0x80+14);
lcd_write_com(0x0f);
}
if(setn == 5)
{
lcd_write_com(0x80+0x40+5);
lcd_write_com(0x0f);
}
if(setn == 6)
{
lcd_write_com(0x80+0x40+8);
lcd_write_com(0x0f);
}
if(setn == 7)
{
lcd_write_com(0x80+0x40+11);
lcd_write_com(0x0f);
}
if(setn == 8)
{
lcd_write_str(0,0," SET TIME 1 ");
lcd_write_str(0,1," 00:00 ");
lcd_write_com(0x80+0x40+6);
lcd_write_data(tx1_shi/10 + 0x30);
lcd_write_data(tx1_shi%10 + 0x30);
lcd_write_data(':');
lcd_write_data(tx1_fen/10 + 0x30);
lcd_write_data(tx1_fen%10 + 0x30);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0F);
}
if(setn == 9)
{
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
if(setn == 10)
{
lcd_write_str(0,0," SET TIME 2 ");
lcd_write_str(0,1," 00:00 ");
lcd_write_com(0x80+0x40+6);
lcd_write_data(tx2_shi/10 + 0x30);
lcd_write_data(tx2_shi%10 + 0x30);
lcd_write_data(':');
lcd_write_data(tx2_fen/10 + 0x30);
lcd_write_data(tx2_fen%10 + 0x30);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0F);
}
if(setn == 11)
{
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
if(setn == 12)
{
lcd_write_str(0,0," SET TIME 3 ");
lcd_write_str(0,1," 00:00 ");
lcd_write_com(0x80+0x40+6);
lcd_write_data(tx3_shi/10 + 0x30);
lcd_write_data(tx3_shi%10 + 0x30);
lcd_write_data(':');
lcd_write_data(tx3_fen/10 + 0x30);
lcd_write_data(tx3_fen%10 + 0x30);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0F);
}
if(setn == 13)
{
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
}
else{if(setn > 3)
{
setn = 0;
lcd_write_com(0x0c);
}
if(setn == 1) {lcd_write_com(0x80+0x40+2); lcd_write_com(0x0f); }
if(setn == 2) {lcd_write_com(0x80+0x40+8); lcd_write_com(0x0f);}
if(setn == 3) {lcd_write_com(0x80+0x40+14);lcd_write_com(0x0f);}}while(P1==0xFE);}
}
if(P1==0xFD || strstr(UART_RX_BUF,"k2")!=NULL){delay_ms(20);
if(P1==0xFD || strstr(UART_RX_BUF,"k2")!=NULL){ memset(UART_RX_BUF, 0, COM_RX1_Lenth);
RX1_RxCounter = 0;
if(setn == 0)
{
displayMode=1;
lcd_clear();
if(displayMode)
{
lcd_write_str(0,0,"DRU1| DRU2 |DRU3");
lcd_write_str(0,1," | | ");
displayDosage();
}
}
if(!displayMode){
if(setn == 1){
year++;if(year == 100)year = 0;
Write_DS1302Init(year,month,day,week,hour,min,sec);
nian_temp=2000+year;
if((nian_temp%400==0)||((nian_temp%100!=0)&&(nian_temp%4==0)))p_r=1;
elsep_r=0;
displayTime();
lcd_write_com(0x80+4);
lcd_write_com(0x0f);
}
else if(setn == 2)
{
month++;
if(month==13) month=1;
if((month==4)||(month==6)||(month==9)||(month==11))
{
if(day>30)day=1;
}
else{if(month==2) {if(p_r==1) {if(day>29) day=1; }else{if(day>28) day=1; }}}
Write_DS1302Init(year,month,day,week,hour,min,sec); displayTime();
lcd_write_com(0x80+7); lcd_write_com(0x0f);} else if(setn == 3)
{ day++;if((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12)) {if(day==32) day=1;}
else{if(month==2){if(p_r==1){if(day==30) day=1;}else{if(day==29)day=1;}}
else{if(day==31)day=1; }}Write_DS1302Init(year,month,day,week,hour,min,sec);displayTime();lcd_write_com(0x80+10);