【STM32项目开源】基于STM32的智能药盒系统
目录
一、设计背景和意义
1.1设计背景
在全球老龄化进程持续加速与慢性病负担日益加重的双重背景下,智能药盒系统的研发承载着重要的社会价值与技术使命。当前,不合理用药已成为威胁公众健康的隐形杀手——世界卫生组织的调研数据显示,发展中国家约有50%的慢性病患者因用药依从性不足导致病情恶化,由此产生的额外医疗支出占到卫生总费用的15%以上。我国作为世界上老年人口最多的国家,约有1.8亿老年人需要长期服药,但传统药盒的功能局限性使得"漏服、错服、忘服"现象普遍存在,这不仅加剧了医疗资源紧张,更直接影响了患者的生活质量。在这一现实困境下,本课题研发的智能药盒系统通过物联网技术与嵌入式智能的深度融合,构建起从药物存储、用药提醒到健康管理的闭环服务体系,其意义已超越单纯的产品创新,而是对现有慢性病管理模式的重要革新。
1.2设计意义
从更宏观的社会效益来看,智能药盒系统的普及应用将产生显著的溢出效应。对家庭用户而言,精准的用药提醒和药品管理功能可降低30%以上的用药错误率,大幅减轻照护者负担;对医疗机构来说,系统采集的用药依从性数据为疗效评估和处方优化提供了客观依据;对公共卫生体系而言,海量用药行为的数字化沉淀有助于发现区域性疾病管理中的共性问题,为制定精准化健康政策提供数据支撑。特别在应对突发公共卫生事件时,联网药盒系统可快速转变为药品发放与用药监测的重要节点,这种"平战结合"的特性进一步凸显了其社会价值。正如诺贝尔经济学奖获得者阿马蒂亚·森所言:"健康是发展的核心目标,也是实现发展的关键手段",本课题的研究正是在技术赋能健康的理念下,通过智能化的手段让科技创新真正服务于人的健康需求,这既符合"健康中国2030"的战略方向,也体现了工程技术研究的人文关怀。
二、实物效果展示
2.1实物图片

2.2实物演示视频
【开源】基于STM32的智能药盒系统
三、硬件功能简介
3.1项目功能详解
1.传感器检测:检测药盒的温度、湿度、药盒药的重量
2.缺药提醒:药物重量为0会开启蜂鸣器报警
3.时间设置:可以设置时间并显示在屏幕上,实现自动计时
4.定时提醒:可以设置定时吃药的时间提醒吃药,每个时间可以自由设定开关
5.药盒开关:定时吃药时间到后,控制舵机自动模拟开启药盒
6.语音提醒:吃药时间到后,语音模块播报”吃药时间到了,请您及时吃药“
7.App控制:可以显示药盒的温度、湿度数据、药物的余量数据、吃药提醒;手动控制药盒的开关
3.2元器件清单
- 主控STM32F103C8T6
- 0.96OLED显示屏幕
- DHT11温湿度传感器
- HX711称重模块
- 舵机(药盒开关)
- JQ6500语音模块
- JDY31-SPP蓝牙模块
- 蜂鸣器
- 按键
四、主框图与软件流程图
主框图

流程图

五、硬件PCB展示


六、软件程序设计
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "dht11.h"
#include "control.h"
#include "adc.h"
#include "key.h"
#include "timer.h"
#include "oled.h"
#include "ds1302.h"
#include "hx711.h"
#include "pwm.h"
/**** 数据变量 ****/
int temp_door_value = 40; //温度阈值
int hum_door_value = 70; //湿度阈值
int weight_door_value = 0; //重量阈值
uint8_t timeone_flag = 0; //定时吃药提醒一
uint8_t timetwo_flag = 0; //定时吃药提醒二
uint8_t timethree_flag = 0; //定时吃药提醒三
uint8_t box_flag = 0; //药盒开关
/**** 菜单变量 ****/
uint8_t keu_num = 0; //按键赋值
uint8_t page_num = 1; //页面ID
uint8_t option = 0; //阈值选项
/**** 功能函数声明 ****/
void get_all_sensor_data(); //传感器数据采集
void Sensor_Data_Handle(); //不同模式下控制效果
void Key_event_handle(void); //按键功能函数
void OLED_Show_FirstPage(); //第一屏显示内容
void OLED_Show_SecondPage(); //第二屏显示内容
void OLED_Show_ThirdPage(); //第三屏显示内容
int main(void)
{
delay_init(); //系统延时函数初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//改变指定管脚的映射,JTAG-DP 禁用 + SW-DP 使能
OLED_Init(); //屏幕初始化
uart3_init(115200); //串口3初始化,波特率115200
uart1_init(9600); //串口1初始化,波特率9600
uart2_init(9600); //串口2初始化,波特率9600
DHT11_Init(); //DHT11温湿度初始化
KEY_Init(); //按键初始化
TIME_Config(); //定时器初始化
DS1302_Init(&SysDate); //DS1302时钟模块初始化
DS1302_DateSet(&SysDate); //DS1302时钟时间设置
PWM_Init(); //舵机PWM初始化
PWM_SetCompare2(185); //默认药盒关闭的角度
HX711_Init(); //称重模块初始化
reset = HX711_GetData(); //重量归零(去皮)
Control_Init(); //蜂鸣器初始化
while(1)
{
Key_event_handle(); //按键监测
if(Time_Period[1]>1000) //Time_Period[1] 在定时器中累加
{
get_all_sensor_data(); //传感器数据采集
Time_Period[1] = 0;
}
if(page_num == 1){ //屏幕更新
OLED_Show_FirstPage();
}else if(page_num == 2){
OLED_Show_SecondPage();
}else if(page_num == 3){
OLED_Show_ThirdPage();
}
Sensor_Data_Handle(); //数据处理
}
}
void Key_event_handle(void)
{
keu_num = KEY_Scan(1); //按键扫描赋值
switch(keu_num)
{
case 1: //按键1按下
if(page_num==1){
page_num=2;option=0;
OLED_Clear();OLED_Show_SecondPage();
}else if(page_num==2){
page_num = 3;option=0;
OLED_Clear();OLED_Show_ThirdPage();
}else if(page_num==3){
page_num = 1;option=0;
OLED_Clear();OLED_Show_FirstPage();
}
break;
case 2: //按键2按下
if(page_num==2){
option++;
if(option==4)option=0;
OLED_Show_SecondPage();
}else if(page_num==3){
option++;
if(option==10)option=0;
OLED_Show_ThirdPage();
}else if(page_num==1){
box_flag = 1;
PWM_SetCompare2(195);
}
break;
case 3: //按键3按下
if(page_num==2){
if(option==1)temp_door_value++;
else if(option==2)hum_door_value++;
else if(option==3)weight_door_value+=5;
OLED_Show_SecondPage();
}else if(page_num==3){
if(option==1){
Timed_One.hour++;
if(Timed_One.hour>23)Timed_One.hour=0;
}else if(option==2){
Timed_One.min++;
if(Timed_One.min>59)Timed_One.min=0;
}else if(option==3){
timeone_flag = 1;
}else if(option==4){
Timed_Two.hour++;
if(Timed_Two.hour>23)Timed_Two.hour=0;
}else if(option==5){
Timed_Two.min++;
if(Timed_Two.min>59)Timed_Two.min=0;
}else if(option==6){
timetwo_flag = 1;
}else if(option==7){
Timed_Three.hour++;
if(Timed_Three.hour>23)Timed_Three.hour=0;
}else if(option==8){
Timed_Three.min++;
if(Timed_Three.min>59)Timed_Three.min=0;
}else if(option==9){
timethree_flag = 1;
}
OLED_Show_ThirdPage();
}else if(page_num==1){
box_flag = 0;
PWM_SetCompare2(185);
}
break;
case 4: //按键4按下
if(page_num==2){
if(option==1)temp_door_value--;
else if(option==2)hum_door_value--;
else if(option==3)weight_door_value-=5;
OLED_Show_SecondPage();
}else if(page_num==3){
if(option==1){
Timed_One.hour--;
if(Timed_One.hour>23)Timed_One.hour=23;
}else if(option==2){
Timed_One.min--;
if(Timed_One.min>59)Timed_One.min=59;
}else if(option==3){
timeone_flag = 0;
}else if(option==4){
Timed_Two.hour--;
if(Timed_Two.hour>23)Timed_Two.hour=23;
}else if(option==5){
Timed_Two.min--;
if(Timed_Two.min>59)Timed_Two.min=59;
}else if(option==6){
timetwo_flag = 0;
}else if(option==7){
Timed_Three.hour--;
if(Timed_Three.hour>23)Timed_Three.hour=23;
}else if(option==8){
Timed_Three.min--;
if(Timed_Three.min>59)Timed_Three.min=59;
}else if(option==9){
timethree_flag = 0;
}
OLED_Show_ThirdPage();
}
break;
}
}
void get_all_sensor_data()
{
DHT11_Read_Data(&temp,&hum); //获取温湿度数据
DS1302_DateRead(&SysDate); //读时间
value = HX711_GetData(); //获取药物重量
weight=(float)(value-reset)*Weights/(float)(Weights_100-reset);
if(weight<0)weight=-weight;
}
void Sensor_Data_Handle()
{
//温度、湿度大于阈值 或 药物重量小于阈值,打开蜂鸣器报警
if(temp > temp_door_value || hum > hum_door_value|| hum > hum_door_value || (int)weight<weight_door_value){
Beep = 1;
} else if(temp < temp_door_value && hum < hum_door_value) {
Beep = 0;
}
//定时吃药提醒一打开
if(timeone_flag==1){
if(SysDate.hour==Timed_One.hour&&SysDate.min==Timed_One.min&&SysDate.sec==0){
PWM_SetCompare2(195);
U2_SendBuff(sound1_buf,6);
delay_ms(1000);delay_ms(1000);delay_ms(1000);
U2_SendBuff(sound1_buf,6);
delay_ms(1000);delay_ms(1000);delay_ms(1000);
U2_SendBuff(sound1_buf,6);
}
}
//定时吃药提醒二打开
if(timetwo_flag==1){
if(SysDate.hour==Timed_Two.hour&&SysDate.min==Timed_Two.min&&SysDate.sec==0){
PWM_SetCompare2(195); //舵机转动,打开药盒
U2_SendBuff(sound1_buf,6); //发送播放提醒语音指令
delay_ms(1000);delay_ms(1000);delay_ms(1000);
U2_SendBuff(sound1_buf,6);
delay_ms(1000);delay_ms(1000);delay_ms(1000);
U2_SendBuff(sound1_buf,6);
}
}
//定时吃药提醒三打开
if(timethree_flag==1){
if(SysDate.hour==Timed_Three.hour&&SysDate.min==Timed_Three.min&&SysDate.sec==0){
PWM_SetCompare2(195);
U2_SendBuff(sound1_buf,6);
delay_ms(1000);delay_ms(1000);delay_ms(1000);
U2_SendBuff(sound1_buf,6);
delay_ms(1000);delay_ms(1000);delay_ms(1000);
U2_SendBuff(sound1_buf,6);
}
}
}
// 温(0) 湿(1) 度(2) 水(3) 位(4) 重(5) 量(6) 模(7) 式(8) 自(9) 手(10) 动(11) 光(12) 照(13) ℃(14) 阈(15)
// 值(16) 设(17) 置(18) 投(19) 食(20) 中(21) 时(22) 间(23) 一(24) 二(25) 三(26) 开(27) 关(28)
void OLED_Show_FirstPage()
{
// OLED_ShowChinese(16*0,0,7,16,1); // “模”
// OLED_ShowChinese(16*1,0,8,16,1); // “式”
// OLED_ShowChar(16*2,0,':',16,1); // “:”
// if(auto_mode == 1){
// OLED_ShowChinese(16*2+8,0,9,16,1); // “自”
// }else if (auto_mode == 0){
// OLED_ShowChinese(16*2+8,0,10,16,1); // “手”
// }
// OLED_ShowChinese(16*3+8,0,11,16,1); // “动”
OLED_ShowChar(8*8+8,0,SysDate.year/10+'0',8,1);
OLED_ShowChar(8*9+8,0,SysDate.year%10+'0',8,1);
OLED_ShowChar(8*10+6,0,'-',8,1);
OLED_ShowChar(8*11+4,0,SysDate.mon/10+'0',8,1);
OLED_ShowChar(8*12+4,0,SysDate.mon%10+'0',8,1);
OLED_ShowChar(8*13+2,0,'-',8,1);
OLED_ShowChar(8*14,0,SysDate.day/10+'0',8,1);
OLED_ShowChar(8*15,0,SysDate.day%10+'0',8,1);
OLED_ShowChar(8*8+8,8,SysDate.hour/10+'0',8,1);
OLED_ShowChar(8*9+8,8,SysDate.hour%10+'0',8,1);
OLED_ShowChar(8*10+6,8,':',8,1);
OLED_ShowChar(8*11+4,8,SysDate.min/10+'0',8,1);
OLED_ShowChar(8*12+4,8,SysDate.min%10+'0',8,1);
OLED_ShowChar(8*13+2,8,':',8,1);
OLED_ShowChar(8*14,8,SysDate.sec/10+'0',8,1);
OLED_ShowChar(8*15,8,SysDate.sec%10+'0',8,1);
OLED_ShowChar(16*0,0,'T',16,1);
OLED_ShowChar(16*0+8,0,':',16,1); // “:”
OLED_ShowNum(16*1,0,temp,2,16,1); // temp
OLED_ShowChinese(16*2,0,14,16,1);
OLED_ShowChar(16*0,16,'H',16,1);
OLED_ShowChar(16*0+8,16,':',16,1); // “:”
OLED_ShowNum(16*1,16,hum,2,16,1); // temp
OLED_ShowString(16*2,16,"%RH",16,1);
OLED_ShowChinese(16*0,32,5,16,1); //重量
OLED_ShowChinese(16*1,32,6,16,1);
OLED_ShowChar(16*2,32,':',16,1);
OLED_ShowNum(16*2+8,32,weight,4,16,1);
OLED_ShowChar(16*4+8,32,'g',16,1);
OLED_Refresh();
}
void OLED_Show_SecondPage()
{
uint8_t a,b,c,d,e;
if(option==1){a=0;b=1;c=1;d=1;e=1;}
else if(option==2){a=1;b=0;c=1;d=1;e=1;}
else if(option==3){a=1;b=1;c=0;d=1;e=1;}
else if(option==4){a=1;b=1;c=1;d=0;e=1;}
else if(option==5){a=1;b=1;c=1;d=1;e=0;}
else {a=1;b=1;c=1;d=1;e=1;}
OLED_ShowChinese(16*2,0,15,16,0); //阈值设置
OLED_ShowChinese(16*3,0,16,16,0);
OLED_ShowChinese(16*4,0,17,16,0);
OLED_ShowChinese(16*5,0,18,16,0);
OLED_ShowChinese(16*0,16,0,16,1); // “温”
OLED_ShowChinese(16*1,16,2,16,1); // “度”
OLED_ShowChar(16*2,16,':',16,1); // “:”
OLED_ShowNum(16*2+8,16,temp_door_value,3,16,a); // temp_door_value
OLED_ShowChinese(16*0,32,1,16,1); // “湿”
OLED_ShowChinese(16*1,32,2,16,1); // “度”
OLED_ShowChar(16*2,32,':',16,1); // “:”
OLED_ShowNum(16*2+8,32,hum_door_value,3,16,b); // hum_door_value
OLED_ShowChinese(16*0,48,5,16,1); // “重”
OLED_ShowChinese(16*1,48,6,16,1); // “量”
OLED_ShowChar(16*2,48,':',16,1); // “:”
OLED_ShowNum(16*2+8,48,weight_door_value,4,16,c); // smoke_door_value
OLED_Refresh();
}
void OLED_Show_ThirdPage()
{
uint8_t a,b,c,d,e,f,g,h,i;
if(option==1){a=0;b=1;c=1;d=1;e=1;f=1;g=1;h=1;i=1;}
else if(option==2){a=1;b=0;c=1;d=1;e=1;f=1;g=1;h=1;i=1;}
else if(option==3){a=1;b=1;c=0;d=1;e=1;f=1;g=1;h=1;i=1;}
else if(option==4){a=1;b=1;c=1;d=0;e=1;f=1;g=1;h=1;i=1;}
else if(option==5){a=1;b=1;c=1;d=1;e=0;f=1;g=1;h=1;i=1;}
else if(option==6){a=1;b=1;c=1;d=1;e=1;f=0;g=1;h=1;i=1;}
else if(option==7){a=1;b=1;c=1;d=1;e=1;f=1;g=0;h=1;i=1;}
else if(option==8){a=1;b=1;c=1;d=1;e=1;f=1;g=1;h=0;i=1;}
else if(option==9){a=1;b=1;c=1;d=1;e=1;f=1;g=1;h=1;i=0;}
else {a=1;b=1;c=1;d=1;e=1;f=1;g=1;h=1;i=1;}
OLED_ShowChinese(16*2,0,22,16,0); //时间设置
OLED_ShowChinese(16*3,0,23,16,0);
OLED_ShowChinese(16*4,0,17,16,0);
OLED_ShowChinese(16*5,0,18,16,0);
OLED_ShowChinese(16*0,16,24,16,1); //一
OLED_ShowNum(16*2,16,Timed_One.hour,2,16,a);
OLED_ShowChar(16*3,16,':',16,1);
OLED_ShowNum(16*3+8,16,Timed_One.min,2,16,b);
if(timeone_flag==1)OLED_ShowChinese(16*5,16,27,16,c);
else OLED_ShowChinese(16*5,16,28,16,c);
OLED_ShowChinese(16*0,32,25,16,1); //二
OLED_ShowNum(16*2,32,Timed_Two.hour,2,16,d);
OLED_ShowChar(16*3,32,':',16,1);
OLED_ShowNum(16*3+8,32,Timed_Two.min,2,16,e);
if(timetwo_flag==1)OLED_ShowChinese(16*5,32,27,16,f);
else OLED_ShowChinese(16*5,32,28,16,f);
OLED_ShowChinese(16*0,48,26,16,1); //三
OLED_ShowNum(16*2,48,Timed_Three.hour,2,16,g);
OLED_ShowChar(16*3,48,':',16,1);
OLED_ShowNum(16*3+8,48,Timed_Three.min,2,16,h);
if(timethree_flag==1)OLED_ShowChinese(16*5,48,27,16,i);
else OLED_ShowChinese(16*5,48,28,16,i);
OLED_Refresh();
}
七、项目资料包内容

资料获取:查看主页介绍“充哥单片机设计”
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)