在传统药盒的基础上,本文根据老年人在服药过程中经常出现漏服和忘服的问题,提出以ATMEGA328系列微控制器芯片为核心设计一个智能药盒。智能药盒主要由OLED显示屏、时钟模块、MP3播放器组成,同时采用ESP8266作为网络控制核心,该系统可以实现吃药时间提醒功能以及药物存储功能。以传统药盒相比,本系统提供了药物存储功能,DHT11温湿度模块进行药物存储环境的温湿度检测,并通过阿里云物联网平台在线控制。 本系统经过测试,可以在设定好的时间内,通过语音播报和灯光常亮进行吃药时间提醒。温湿度模块实时监测药物存储的温湿度上传阿里云平台,在线控制风扇的开关,调节温湿度,保证药品存储在适宜的环境下。为智能医疗产品设计的发展提供了新的参考和借鉴。
一、功能:
一天三次吃药的时间(早上、中午和晚上)到了之后会有语音提示,并且会有相对应的LED灯被点亮,可以通过按钮设置(早上、中午和晚上)吃药的时间。
二、材料清单:
Arduino UNO 一块,扩展板一块、5号电池盒四节一个、LED灯三个,按钮四个,OLED显示屏一块,DS3231时钟模块一个,MINIMP3模块转换板、MINIMP3、TF卡、若干杜邦线。
三、硬件连接:
****Arduino ******** UNO ****** ** <------> ******** 黄色按钮
GND <------> G
5V <------> V
4 <------> D
Arduino ******** UNO ****** **** ****** <------> ******** 红色按钮
GND <------> G
5V <------> V
5 <------> D
****Arduino ******** UNO **** <------> ******** 绿色按钮
GND <------> G
5V <------> V
6 <------> D
Arduino ******** UNO <------> ******** 白色按钮
GND <------> G
5V <------> V
7 <------> D
Arduino ******** UNO <------> ******** DS1307时钟模块
GND <------> G
5V <------> V
10 <------> SDA
11 <------> SCL
****Arduino ******** UNO ****** ** <------> ******** 黄色LED灯
GND <------> G
5V <------> V
A3 <------> D
****Arduino ******** UNO **** ****<------> ****** **** **** **红色LED灯
GND <------> G
5V <------> V
A2 <------> D
Arduino ******** UNO ****<------> ****** **** **绿色LED灯
GND <------> G
5V <------> V
A1 <------> D
****Arduino ******** UNO ****** ** ****<------> ****** **** **OLED显示屏
GND <------> G
5V <------> V
SDA <------> SDA
SCL <------> SCL
****Arduino ******** UNO ****** **** ******<------> ****MINI MP3模块
GND <------> G
5V <------> V
9 <------> TX
8 <------> RX
****Arduino ******** UNO ****** **** **** ******<------> ****** **** **5号电池盒(4节)
VIN <------> 正极(红色线)
GND <------> 负极(黑色线)
四、软件系统详细设计
4.1 Arduino与Esp8266环境搭建
(1)登录Arduino官网,下载软件。
(2)打开文件à首选项,再将该连接复制到à“附加开发板管理器网址”。
网址为:https://arduino.esp8266.com/stable/package_esp8266_index.json
添加附加开发板管理器网址如图所示:
- 重启Arduino软件,依次点击:工具-开发板-开发板管理器,然后搜索ESP8266并下载。如图17所示为搜索结果:
(4)下载完成后,依次点击工具à开发板,可以观察到ESP8266相关的开发板,如下图所示,至此Arduino 和 ESP8266 开发环境就搭建好了。
4.2 字模提取软件
对于智能药盒设计对显示汉字的需求,选择PCtoLCD2002字体取模软件。软件的配置界面如下图所示。
其中,阴码和阳码是指:字模点阵中有笔迹像素位的状态是“1”还是“0”,即对应的薄膜晶体管是“亮”还是“灭”。
自定义格式中只有两种格式“C51”和“A51”,在这里要选择常用的“C51”格式。取模方式选择逐行式,一行一行的以最低位开始,向最高位进行扫描。进行相应的设定后,在输入框输入想要显示的汉字点击生成字模即可。比如我们输入汉字“智能药盒”,如下图所示。
4.3 阿里云平台开发
4.3.1 药物存储环境
药物的处方成分比较复杂,应按照其特性,剂型选择合适的储存条件。如果是常温贮存的,温度一般保持在1030℃左右即可,如果是需要阴凉贮存的,一般温度控制在1020℃左右为宜,若温度过高,中成药的某些成分可能会氧化、分解加速、变量变质,例如含芳香挥发性成分的药物可因加速挥发而损失,含脂肪油成分的药物易“泛油”或酸败,胶囊剂易黏软变型,片剂易裂片变色等等;但是温度也不宜过低,温度过低容易导致糖浆剂、露剂、含乙醇制剂等产生沉淀、结晶,甚至变性失效。一般中成药的储存相对湿度以35%~75%为宜。如果环境湿度过高,例如梅雨季节,容易导致中成药发生潮解、变形、生虫甚至霉变,如果环境湿度过低,则可能会导致中成药风化或干燥等等。对此,进行药盒内部温湿度的检测上传阿里云平台进行实时监控,保证药物的存储环境达标。同时接入一个风扇,通过开关对温湿度进行调节。
4.3.2 开发流程图设计
药物存储也是整个药盒系统设计过程中最重要的环节,流程图如下图20所示。
首先,登录阿里云官网进行实名注册登录,点击控制台搜索物联网平台开通公共实例。选择产品,进行产品创建,所属类品选择温湿度采集,连网方式选择WIFI,创建产品成功后进行创建设备,自定义功能,进行温湿度以及风扇开关的属性设置,温湿度为单精度浮点型,开关为布尔型。设置完相应功能后进行发布上线,属性设置如下图所示。
下一步是DHT11温湿度传感器接入ESP8266,连接阿里云物联网平台,从设备信息查看三元组信息并且更改代码的三元组以及WIFI信息,更改信息如下图所示。
最后上传代码连接到WIFI就可以激活设备,此时就能在阿里云平台观察到设备在线,就表示已经连接到阿里云平台。此时就可以查看实时的温湿度信息,进行药物存储环境的监控。外接的继电器用于控制风扇,用于调节温湿度情况,显示结果如下图所示:
4.4 语音提醒设计
在智能药盒系统设计中,选择MP3 PLAY模块作为语音提醒模块。在文本转语音平台可以自定义文本,设置相应的语言、身份、情况等的设置,更加注重情感化的设计。MP3模块是使用串口通信,本系统采用的是虚拟串口。主要实现代码如下:
#include "SoftwareSerial.h"//软串口库
#include "DFRobotDFPlayerMini.h"
SoftwareSerial mySerial(8, 9);
DFRobotDFPlayerMini myPlayer;
void setup()
{
mySoftwareSerial.begin(9600);
myPlayer.begin(mySoftwareSerial);
myPlayer.volume(100); //音量设定为100
myPlayer.playFolder(1, 1); //播放TF卡中 01文件夹下001.mp3 文件
}
void loop(){}
工作流程图如下图所示。
本系统采用微软Al语音,输入你需要转换的文本即可得到你想要的语音内容。
在合成相应的语言和可以选择完整播放,和试听选择,设置合理之后点击下载,生成的语言要放在01开头的文件夹,同时文件夹里的早中晚提醒语音文件名必须设定为001.mp3、002.mp3和003.mp3.mp3。myPlayer.playFolder(1,2)表示播放的是01文件夹的001播放源。
五、系统功能测试
5.1 Arduino程序上传
Arduino程序上传调试我们采用的是Arduino IDE,打开软件新建项目文件,在工具栏中选择我们所需要的开发板型号,开发板型号选择Arduino/Genuino Uno,进行程序编写,对我们本系统所需要的库文件逐一进行添加。然后在IDE软件中进行程序的编译,编译成功后选择对应端口点击程序上传,一段时间后就可以看见下方显示上传成功,至此,Arduino调试成功。上传成功界面如下图26所示。
5.2ESP8266程序上传
ESP8266端的程序上传同样采用的是Arduino IDE,打开软件新建项目文件,在工具栏中选择我们所需要的开发板型号,开发板型号选择ESP8266 NoedMcu 1.0,进行程序的编写,编写完成后选择对应端口进行程序下载。在IDE软件中显示上传成功后表示程序已上传,打开串口监视器,显示相应的温湿度信息。温湿度显示信息如下图27所示。
根据上图的串口显示结果,可以看到看到连接成功,显示数字1。同时可以观察到实时的温度和湿度,当连接不成功的时候则显示-1。
5.3闹钟时间测试
本系统满足人们对日常药盒的基本需求,分别可以设置早中晚三个服药时间, 早上时间设置定义一个zss变量,用if语句进行实现,当按键按下时早上时间加一,考虑时间是24小时制,预先设置一个阈值,当大于24时重头开始计数,中午和晚上设置时间同早上一致,if (digitalRead(5) == HIGH) {
delay(300); //早上小时的时间设置
zss = zss + 1;当按下D5按键时,小时时间加一
if (zss >= 24) {
zss = 0;
}
EEPROM.put(1, zss);//将早上小时的时间设置写入EEPROM地址1
}
if (digitalRead(6) == HIGH) {
delay(300); //早上分钟的时间设置
zsf = zsf + 1;当按下按键D6时,分钟时间加一
if (zsf >= 60) {
zsf = 0;}
EEPROM.put(11, zsf); //将早上分钟的设置写入EEPROM地址1}
if (digitalRead(7) == HIGH) {
delay(300); //如果7号按钮被按下则退出程序返回界面
A = 0; break;}当按下按键D7时,退出,测试结果如图28所示。
在闹钟设定显示界面图中,第一行显示的是当前的年月日,第二行显示的是当前的时间,包括时、分和秒,在第三行中显示的是用户设定好的早上吃药的闹钟、中午吃药时间的闹钟以及晚上吃药的时间。一共显示5个数据,时间显示区采用24小时制。
5.4声光测试结果
本系统设置多种提醒方式,声音提醒和LED灯常亮。获取时间代码如下:
if (Rtc.GetDateTime().Hour() == zss && (Rtc.GetDateTime().Minute()
== zsf && Rtc.GetDateTime().Second() == 0))
{
pinMode(A3,OUTPUT);
digitalWrite(A3,HIGH);
myPlayer.playFolder(1,1);
}
声光提醒图如图29所示。
在声光提醒显示界面中,设定好早上吃药时间的闹钟是22:12,if (Rtc.GetDateTime().Hour() == zss && (Rtc.GetDateTime().Minute() == zsf是获取时间,当到达闹钟设定的22:12的时候, pinMode(A3, OUTPUT);digitalWrite(A3,HIGH);可以看到早上药物所存储的格子绿灯亮起,同时 myPlayer.playFolder(1, 1),语音进行播报。
5.5温湿度监控
本系统连接阿里云上传温湿度信息,实时监测,在存储环境不佳时通过开关打开和关闭风扇,调节存储药物所需环境。
void loop(){
AliyunIoTSDK::loop();
AliyunIoTSDK::send("temperature",t);
AliyunIoTSDK::send("Humidity",h);
AliyunIoTSDK::send("LEDPIN", digitalRead(LED_BUILTIN));
h = dht.readHumidity();
t = dht.readTemperature();
Serial.print("Temperature:");
Serial.println(t); delay(1000);
Serial.print("Humidity:");
Serial.print(h);
Serial.println("%");
delay(1000);}温湿度实时监测数据图如下图30所示。
AliyunIoTSDK::send("temperature",t);AliyunIoTSDK::send("Humidity",h);表示把温度和湿度信息发送到IOT云平台。通过温湿度监控页面可以实时看到通过串口打印Serial.print("Temperature:");Serial.print("Humidity:")的实时温度为18.7℃,湿度为42.0%。在温湿度不在预期范围内,可以在云端进行风扇开关的调节。在ESP8266上外接一个继电器用于风扇的开关,风扇接在继电器上。当给继电器一个高电平时,打开了继电器的开关,风扇就会进行转动。在温湿度达到预期的药物存储环境时,相反的给继电器一个低电平,从而使风扇关闭,停止工作。
- 程序设计
一天三次吃药的时间(早上、中午和晚上)到了之后会有语音提示,并且会有相对应的LED灯被点亮。
#include <U8g2lib.h> //显示屏和时钟模块的库文件
void page1() {
u8g2.setFont(u8g2_font_timR10_tf); //显示年,月,日,时,分,秒,早上、中午和晚上时间
u8g2.setFontPosTop();
u8g2.setCursor(35,0);
u8g2.print(String(Rtc.GetDateTime().Year()) + String(String("-") + String(String(Rtc.GetDateTime().Month()) + String(String("-") + String(Rtc.GetDateTime().Day())))));
u8g2.setFont(u8g2_font_timR18_tf);
u8g2.setFontPosTop();
u8g2.setCursor(30,15);
u8g2.print(Rtc.GetDateTime().Hour());
u8g2.setCursor(60,15);
u8g2.print(":");
u8g2.setCursor(70,15);
u8g2.print(Rtc.GetDateTime().Minute());
u8g2.setFont(u8g2_font_timR10_tf);
u8g2.setFontPosTop();
u8g2.setCursor(95,25);
u8g2.print(Rtc.GetDateTime().Second());
u8g2.drawXBMP(0, 50, 48, 16, bitmap1);
u8g2.drawXBMP(43, 50, 48, 16, bitmap2);
u8g2.drawXBMP(87, 50, 48, 16, bitmap3);
u8g2.drawXBMP(33, 35, 60, 16, bitmap4);
u8g2.setFont(u8g2_font_timR08_tf);
u8g2.setFontPosTop();
u8g2.setCursor(20,50);
u8g2.print(String(zss) + String(String(":") + String(zsf)));
u8g2.setCursor(63,50);
u8g2.print(String(zws) + String(String(":") + String(zwf)));
u8g2.setCursor(106,50);
u8g2.print(String(wss) + String(String(":") + String(wsf)));
}
void my_1() {
u8g2.setFont(u8g2_font_timR10_tf);
u8g2.setFontPosTop();
u8g2.drawXBMP(0, 50, 48, 16, bitmap1);
u8g2.setFont(u8g2_font_timR08_tf);
u8g2.setFontPosTop();
u8g2.setCursor(20,50);
u8g2.print(String(zss) + String(String(":") + String(zsf)));
}
void my_2() {
u8g2.setFont(u8g2_font_timR10_tf);
u8g2.setFontPosTop();
u8g2.drawXBMP(43, 50, 48, 16, bitmap2);
u8g2.setFont(u8g2_font_timR08_tf);
u8g2.setFontPosTop();
u8g2.setCursor(63,50);
u8g2.print(String(zws) + String(String(":") + String(zwf)));
}
void my_3() {
u8g2.setFont(u8g2_font_timR10_tf);
u8g2.setFontPosTop();
u8g2.drawXBMP(87, 50, 48, 16, bitmap3);
u8g2.setFont(u8g2_font_timR08_tf);
u8g2.setFontPosTop();
u8g2.setCursor(106,50);
u8g2.print(String(wss) + String(String(":") + String(wsf)));
}
void setup(){
u8g2.setI2CAddress(0x3C*2);
u8g2.begin();
Rtc.Begin();
Rtc.SetIsRunning(true);
mySerial.begin(9600);
myPlayer.begin(mySerial);
//Rtc.SetDateTime(RtcDateTime(__DATE__, __TIME__));
myPlayer.setTimeOut(500);
myPlayer.volume(100);
myPlayer.EQ(DFPLAYER_EQ_NORMAL);
myPlayer.outputDevice(DFPLAYER_DEVICE_SD);
pinMode(A1, OUTPUT); //定义A1,A2和A3为输出管脚
digitalWrite(A1,LOW);
pinMode(A2, OUTPUT);
digitalWrite(A2,LOW);
pinMode(A3, OUTPUT);
digitalWrite(A3,LOW);
u8g2.enableUTF8Print();
pinMode(4, INPUT); //定义4,5,6,和7为输入管脚
pinMode(5, INPUT);
pinMode(6, INPUT);
pinMode(7, INPUT);
}
void loop(){
EEPROM.get(1, zss); //读取EEPROM地址1的变量值
EEPROM.get(11, zsf); //读取EEPROM地址11的变量值
EEPROM.get(21, zws); //读取EEPROM地址21的变量值
EEPROM.get(31, zwf); //读取EEPROM地址31的变量值
EEPROM.get(41, wss); //读取EEPROM地址41的变量值
EEPROM.get(51, wsf); //读取EEPROM地址51的变量值
u8g2.firstPage();
do
{
page1();
}while(u8g2.nextPage()); //如果到达早上设置时间则对应的LED灯点亮,语音播放
if (Rtc.GetDateTime().Hour() == zss && (Rtc.GetDateTime().Minute() == zsf && Rtc.GetDateTime().Second() == 0)) {
pinMode(A3, OUTPUT);
digitalWrite(A3,HIGH);
pinMode(A1, OUTPUT);
digitalWrite(A1,LOW);
pinMode(A2, OUTPUT);
digitalWrite(A2,LOW);
myPlayer.playFolder(1, 1);
}
if (Rtc.GetDateTime().Hour() == zws && (Rtc.GetDateTime().Minute() == zwf && Rtc.GetDateTime().Second() == 0)) {
pinMode(A2, OUTPUT); //如果到达中午设置时间则对应的LED灯点亮,语音播放
digitalWrite(A2,HIGH);
pinMode(A1, OUTPUT);
digitalWrite(A1,LOW);
pinMode(A3, OUTPUT);
digitalWrite(A3,LOW);
myPlayer.playFolder(1, 2);
}
if (Rtc.GetDateTime().Hour() == wss && (Rtc.GetDateTime().Minute() == wsf && Rtc.GetDateTime().Second() == 0)) {
pinMode(A1, OUTPUT); //如果到达晚上设置时间则对应的LED灯点亮,语音播放主人,晚上吃药的时间到了
digitalWrite(A1,HIGH);
pinMode(A2, OUTPUT);
digitalWrite(A2,LOW);
pinMode(A3, OUTPUT);
digitalWrite(A3,LOW);
myPlayer.playFolder(1, 3);
}
if (digitalRead(4) == HIGH) {
delay(300); //如果4号按钮被按下,那么进行闹钟时间的设置
u8g2.firstPage();
do
{
my_1();
}while(u8g2.nextPage());
delay(1000); A = A + 10;
while (A == 10) {
u8g2.firstPage();
do
{
my_1();
}while(u8g2.nextPage());
if (digitalRead(5) == HIGH) {
delay(300); //早上小时的时间设置
zss = zss + 1;
if (zss >= 24) {
zss = 0;
}
EEPROM.put(1, zss);//将早上小时的时间设置写入EEPROM地址1
}
if (digitalRead(6) == HIGH) {
delay(300); //早上分钟的时间设置
zsf = zsf + 1;
if (zsf >= 60) {
zsf = 0;
}
EEPROM.put(11, zsf); //将早上分钟的时间设置写入EEPROM地址11
}
if (digitalRead(7) == HIGH) {
delay(300); //如果7号按钮被按下则退出程序返回界面
A = 0; break;
}
if (digitalRead(4) == HIGH) { //如果4号按钮被按下切换到中午时间的设置
delay(300);
A = A + 10; break;
}
}
u8g2.firstPage();
do
{
my_2();
}while(u8g2.nextPage());
delay(1000);
while (A == 20) {
u8g2.firstPage();
do
{
my_2();
}while(u8g2.nextPage());
if (digitalRead(5) == HIGH) {
delay(300); //中午小时的时间设置
zws = zws + 1;
if (zws >= 24) {
zws = 0;
}
EEPROM.put(21, zws);//将中午小时的时间设置写入EEPROM地址21
}
if (digitalRead(6) == HIGH) {
delay(300);
zwf = zwf + 1; //中午分钟的时间设置
if (zwf >= 60) {
zwf = 0;
}
EEPROM.put(31, zwf);//将中午分钟的时间设置写入EEPROM地址31
}
if (digitalRead(7) == HIGH) {
delay(300); //如果7号按钮被按下则退出程序返回界面
A = 0; break;
}
if (digitalRead(4) == HIGH) {
A = A + 10; //如果4号按钮被按下切换到晚上时间的设置
delay(300); break;
}
}
u8g2.firstPage();
do
{
my_3();
}while(u8g2.nextPage());
delay(1000);
while (A == 30) {
u8g2.firstPage();
do
{
my_3();
}while(u8g2.nextPage());
if (digitalRead(5) == HIGH) {
delay(300);
wss = wss + 1; //晚上小时的时间设置
if (wss >= 24) {
wss = 0;
}
EEPROM.put(41, wss);//将晚上小时的时间设置写入EEPROM地址41
}
if (digitalRead(6) == HIGH) {
delay(300);
wsf = wsf + 1; //晚上分钟的时间设置
if (wsf >= 60) {
wsf = 0;
}
EEPROM.put(51, wsf);//将晚上分钟的时间设置写入EEPROM地址51
}
if (digitalRead(7) == HIGH) {
delay(300); //如果7号按钮被按下则退出程序返回界面
A = 0; break;
}
if (digitalRead(4) == HIGH) { //如果4号按钮被按下则退出程序返回界面
delay(300);
A = 0; break;
} } }
if (digitalRead(7) == HIGH) { //如果7号管脚被按下则3盏灯全部熄灭
pinMode(A1, OUTPUT);
digitalWrite(A1,LOW);
pinMode(A2, OUTPUT);
digitalWrite(A2,LOW);
pinMode(A3, OUTPUT);
digitalWrite(A3,LOW);
} }
版权归原作者 icy、泡芙 所有, 如有侵权,请联系我们删除。