1 簡(jiǎn)介
Hi,大家好,這里是丹成學(xué)長(zhǎng),今天向大家介紹一個(gè)學(xué)長(zhǎng)做的單片機(jī)項(xiàng)目
基于STM32的智能藥箱系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)
大家可用于 課程設(shè)計(jì) 或 畢業(yè)設(shè)計(jì)
單片機(jī)-嵌入式畢設(shè)選題大全及項(xiàng)目分享:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-791412.html
https://blog.csdn.net/m0_71572576/article/details/125409052文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-791412.html
2 緒論
2.1 課題背景
照顧老人, 特別是提醒老人準(zhǔn)時(shí)吃藥已經(jīng)成為了一個(gè)社會(huì)關(guān)心的問(wèn)題。長(zhǎng)期記錄吃藥種類(lèi)、 吃藥時(shí)間能為分析老人的病理提供有力的依據(jù)。
基于目 前市場(chǎng)需求, 學(xué)長(zhǎng)設(shè)計(jì)了一款基于 STM32F103 并結(jié)合網(wǎng)絡(luò)來(lái)提醒老人按時(shí)吃藥的系統(tǒng)。
整個(gè)智能藥箱系統(tǒng)分為智能藥箱端與遠(yuǎn)程服務(wù)器端兩個(gè)部分, 智能藥箱端用于提醒, 服務(wù)器端用于記錄監(jiān)督
2.2 實(shí)現(xiàn)功能
整個(gè)系統(tǒng)經(jīng)過(guò)多次測(cè)試和應(yīng)用, 各功能模塊都可以正常運(yùn)行, 符合設(shè)計(jì)要求。 具有的功
能包括: 從服務(wù)器端的數(shù)據(jù)庫(kù)中實(shí)時(shí)獲取藥物信息, 鬧鐘信息等并存儲(chǔ)。 播放音頻文件提醒老人用藥, 在液晶屏上提示吃藥信息, 老人可以根據(jù)顯示信息正確用藥。 智能藥箱端能記錄藥箱中每種藥的數(shù)目, 并進(jìn)行藥量檢測(cè), 在藥量不足時(shí)發(fā)出提醒, 提示用戶(hù)配藥。 另外還可以對(duì)老人取藥動(dòng)作進(jìn)行記錄, 將取藥狀態(tài)通過(guò)互聯(lián)網(wǎng)傳輸給服務(wù)器監(jiān)控端, 為以后看病做依據(jù)。 另外, 智能藥箱端通過(guò)程序界面方便的配置智能藥箱內(nèi)部的網(wǎng)絡(luò)信息,包括服務(wù)器地址、端口、 網(wǎng)關(guān)等。
它的主要功能分為下面幾個(gè)部分:
-
- 提醒功能
-
- 取藥監(jiān)督
-
- 記錄吃藥時(shí)間
-
- 對(duì)老人是否吃藥及時(shí)做出反應(yīng)
-
- 顯示吃藥信息
服務(wù)器中記錄下的取藥時(shí)間可以作為以后看病的有力依據(jù), 使醫(yī)生能夠準(zhǔn)確對(duì)老人的病情做出判斷, 減少一定的醫(yī)學(xué)失誤。
盡管智能藥箱的發(fā)展并沒(méi)有早期預(yù)期的那么快。 但是, 它的應(yīng)用價(jià)值極高, 針對(duì)性也很
強(qiáng), 可以有效的管理老年人用藥, 減少兒女對(duì)父母吃藥問(wèn)題上的擔(dān)心。 所以, 隨著科技的發(fā)展, 智能藥箱的普及將指日可待。
3 系統(tǒng)設(shè)計(jì)
3.1 系統(tǒng)架構(gòu)
設(shè)計(jì)上必須從上圖架構(gòu)出發(fā), 從上圖可以得出智能藥箱系統(tǒng)的總體功能:
- a) 鬧鐘提醒吃藥
- b) 液晶顯示吃藥信息
- c) 實(shí)時(shí)采集取藥狀態(tài)
- d) 存儲(chǔ)從服務(wù)器端獲取的信息
- e) 配置界面配置藥箱端的網(wǎng)絡(luò)參數(shù)
- f) 實(shí)時(shí)檢測(cè)藥數(shù)量, 不足提醒用戶(hù)
- g) 增加服務(wù)器端, 記錄藥物信息, 鬧鐘, 取狀態(tài)藥等信息
3.2 硬件設(shè)計(jì)
3.2.1 wifi電路設(shè)計(jì)
3.2.2 其他電路設(shè)計(jì)
略,內(nèi)容相對(duì)冗余,也不是本文介紹的重點(diǎn),需要詳細(xì)設(shè)計(jì)方案,可以在文章末尾聯(lián)系學(xué)長(zhǎng)。
3.3 軟件設(shè)計(jì)
3.3.1 軟件工作流程
程序包括模塊的驅(qū)動(dòng)與功能操作, 驅(qū)動(dòng)主要是硬件的驅(qū)動(dòng), 每個(gè)模塊只有在硬件驅(qū)動(dòng)成功后, 才能執(zhí)行其余功能。
3.3.2 鬧鈴提醒程序設(shè)計(jì)
下圖是鬧鈴提醒的程序流程圖, STM32 從 TF 卡中讀取 512 字節(jié)數(shù)據(jù), 按順序傳輸給VS1003 進(jìn)行音頻轉(zhuǎn)換和播放。 然后, 依次讀取下一個(gè)扇區(qū)的 512 個(gè)字節(jié)進(jìn)行播放。 如果播放過(guò)程中檢測(cè)到藥箱打開(kāi), 則停止鬧鈴并退出。
3.3.3 液晶顯示程序設(shè)計(jì)
下圖是鬧鈴提醒的程序流程圖, STM32 從 TF 卡中讀取 512 字節(jié)數(shù)據(jù), 按順序傳輸給VS1003 進(jìn)行音頻轉(zhuǎn)換和播放。 然后, 依次讀取下一個(gè)扇區(qū)的 512 個(gè)字節(jié)進(jìn)行播放。 如果播放過(guò)程中檢測(cè)到藥箱打開(kāi), 則停止鬧鈴并退出。
3.3.4 信息存儲(chǔ)程序設(shè)計(jì)
存儲(chǔ)信息的過(guò)程如下:
當(dāng)智能藥箱接收網(wǎng)絡(luò)參數(shù), 藥物信息時(shí), 首先對(duì)數(shù)據(jù)按協(xié)議正確處理, 然后向 24C08 發(fā)送存儲(chǔ)地址, 如果地址上已經(jīng)有數(shù)據(jù), 則讀取。 然后將地址上的數(shù)據(jù)清空, 將剛才接收并處理的信息與從存儲(chǔ)芯片讀取的數(shù)據(jù)進(jìn)行統(tǒng)一處理, 保留不變的, 修改已改變的數(shù)據(jù), 再存入地址中。 如果需要讀取存儲(chǔ)芯片上的數(shù)據(jù), 則向 24C08 發(fā)送地址讀取數(shù)據(jù)即可, 程序流程圖如下圖所示。
3.3.5 報(bào)警電路程序設(shè)計(jì)
智能藥箱與服務(wù)器之間每半小時(shí)需要藥數(shù)目的校正, 以便兩者之間可以同步。 當(dāng)藥箱內(nèi)部藥量不足時(shí), 就會(huì)觸發(fā)蜂鳴器以示提醒。 蜂鳴器采用是有源蜂鳴器, 接通電流就會(huì)發(fā)聲,整個(gè)報(bào)警的程序流程圖如下圖所示。
3.4 部分實(shí)現(xiàn)代碼
#include <Arduino.h>
#include "MAX30105.h"
#include "heartRate.h"
#include "motor.h"
#define DEBUG
#define OUT_POSITION 1
#define TAKE_POSITION 2
#define OPEN_POSITION 5
bool isTaskTake = false;
int boxdisplacement = 0;
int pillsParameters[2] = {3, 1};
enum BOXNAME { BOX1 = 1, BOX2, BOX3, BOX4, BOX5, BOX6 };
TaskHandle_t taskGreenLEDHandler;
void rotateToOpen(int boxName);
void rotateToClose(int boxName);
void rotateToTake(int boxName);
void rotateToOut(int boxName);
void takePills(int boxName, int pillsNumber);
void taskTakePills(void *pvParameters);
void takePillsTest();
void setup() {
Serial.begin(115200);
delay(1000);
motor_init();
// xTaskCreate(taskPrint, "taskPrint", 1000, NULL, 1, NULL);
}
void loop() {
if (Serial.available()) {
char message = ' ';
message = Serial.read();
if (message == 't') {
if (!isTaskTake) {
isTaskTake = true;
Serial.println("*************\n*開(kāi)始取藥過(guò)程*\n*************");
// xTaskCreate(taskTakePills, "taskTakePills", 20000,
// pillsParameters, 1, NULL);
takePills(3, 1);
} else {
Serial.println("已經(jīng)有一個(gè)取藥任務(wù)了");
}
}
if (message == 'i') { //開(kāi)蓋
if (!isTaskTake) {
isTaskTake = true;
taskOpenBox(NULL);
isTaskTake = false;
} else {
Serial.println("已經(jīng)有一個(gè)取藥任務(wù)了");
}
}
if (message == 'j') { //關(guān)蓋
if (!isTaskTake) {
isTaskTake = true;
taskCloseBox(NULL);
digitalWrite(PIN_ENABLE, HIGH);
isTaskTake = false;
} else {
Serial.println("已經(jīng)有一個(gè)取藥任務(wù)了");
}
}
if (message == 'm') { //關(guān)蓋
if (!isTaskTake) {
isTaskTake = true;
digitalWrite(PIN_ENABLE, LOW);
takePillsTest();
digitalWrite(PIN_ENABLE, HIGH);
isTaskTake = false;
} else {
Serial.println("已經(jīng)有一個(gè)取藥任務(wù)了");
}
}
if (message == 'g') { //左旋
if (!isTaskTake) {
isTaskTake = true;
digitalWrite(PIN_ENABLE, LOW);
taskRotate(LEFT);
boxdisplacement--;
digitalWrite(PIN_ENABLE, HIGH);
isTaskTake = false;
} else {
Serial.println("已經(jīng)有一個(gè)取藥任務(wù)了");
}
}
if (message == 'h') { //右旋
if (!isTaskTake) {
isTaskTake = true;
digitalWrite(PIN_ENABLE, LOW);
taskRotate(RIGHT);
boxdisplacement++;
digitalWrite(PIN_ENABLE, HIGH);
isTaskTake = false;
} else {
Serial.println("已經(jīng)有一個(gè)取藥任務(wù)了");
}
}
if (message == 'k') {
if (!isTaskTake) {
isTaskTake = true;
Serial.println("開(kāi)始推出藥盒");
digitalWrite(PIN_ENABLE, LOW);
taskPushBoxOut(NULL);
delay(1000);
Serial.println("開(kāi)始推入藥盒");
taskPullBoxIn(NULL);
digitalWrite(PIN_ENABLE, HIGH);
isTaskTake = false;
} else {
Serial.println("已經(jīng)有一個(gè)取藥任務(wù)了");
}
}
if (message == '3') {
taskPillsOut(NULL);
}
if (message == 'a') { //開(kāi)氣泵
openPump();
}
if (message == 'b') { //關(guān)氣泵
closePump();
}
}
}
void rotateToOpen(int boxName) {
int currentPosition = boxName + boxdisplacement;
int targetRotation = OPEN_POSITION - currentPosition;
if (targetRotation >= 0) {
#ifdef DEBUG
Serial.println("rorate right " + String(targetRotation) +
" step to open.");
Serial.println("向右旋轉(zhuǎn) " + String(targetRotation) + " 步以開(kāi)蓋.");
#endif
for (int i = 0; i < targetRotation; i++) {
taskRotate(RIGHT);
boxdisplacement++;
}
} else {
#ifdef DEBUG
Serial.println("rorate left " + String(-targetRotation) +
" step to open.");
Serial.println("向左旋轉(zhuǎn) " + String(-targetRotation) + " 步以開(kāi)蓋.");
#endif
for (int i = 0; i < -targetRotation; i++) {
taskRotate(LEFT);
boxdisplacement--;
}
}
}
void rotateToClose(int boxName) {
int currentPosition = boxName + boxdisplacement;
int targetRotation = OPEN_POSITION - currentPosition;
if (targetRotation >= 0) {
#ifdef DEBUG
Serial.println("rorate right " + String(targetRotation) +
" step to close.");
Serial.println("向右旋轉(zhuǎn) " + String(targetRotation) + " 步以關(guān)蓋.");
#endif
for (int i = 0; i < targetRotation; i++) {
taskRotate(RIGHT);
boxdisplacement++;
}
} else {
#ifdef DEBUG
Serial.println("rorate right " + String(-targetRotation) +
" step to close.");
Serial.println("向左旋轉(zhuǎn) " + String(-targetRotation) + " 步以關(guān)蓋.");
#endif
for (int i = 0; i < -targetRotation; i++) {
taskRotate(LEFT);
boxdisplacement--;
}
}
}
void rotateToTake(int boxName) {
int currentPosition = boxName + boxdisplacement;
int targetRotation = TAKE_POSITION - currentPosition;
if (targetRotation >= 0) {
#ifdef DEBUG
Serial.println("rorate right " + String(targetRotation) +
" step to take pills.");
Serial.println("向右旋轉(zhuǎn) " + String(targetRotation) + " 步以取藥.");
#endif
for (int i = 0; i < targetRotation; i++) {
taskRotate(RIGHT);
boxdisplacement++;
}
} else {
#ifdef DEBUG
Serial.println("rorate right " + String(-targetRotation) +
" step to take pills.");
Serial.println("向左旋轉(zhuǎn) " + String(-targetRotation) + " 步以取藥.");
#endif
for (int i = 0; i < -targetRotation; i++) {
taskRotate(LEFT);
boxdisplacement--;
}
}
}
void rotateToOut(int boxName) {
int currentPosition = boxName + boxdisplacement;
int targetRotation = OUT_POSITION - currentPosition;
if (targetRotation >= 0) {
#ifdef DEBUG
Serial.println("rorate right " + String(targetRotation) +
" step to add pills.");
Serial.println("向右旋轉(zhuǎn) " + String(targetRotation) + " 步以換(加)藥.");
#endif
for (int i = 0; i < targetRotation; i++) {
taskRotate(RIGHT);
boxdisplacement++;
}
} else {
#ifdef DEBUG
Serial.println("rorate right " + String(-targetRotation) +
" step to add pills.");
Serial.println("向左旋轉(zhuǎn) " + String(-targetRotation) +
" 步以換(加)藥.");
#endif
for (int i = 0; i < -targetRotation; i++) {
taskRotate(LEFT);
boxdisplacement--;
}
}
}
void takePills(int boxName, int pillsNumber) {
digitalWrite(PIN_ENABLE, LOW);
// taskPillsUp(NULL);
rotateToOpen(boxName);
taskOpenBox(NULL);
rotateToTake(boxName);
// stepper2.runToNewPosition(5000);
midToLeft();
openPump();
// stepper2.runToNewPosition(6400);
delay(1000);
digitalWrite(PIN_STEPPER2_DIR, LOW);
for (int j = 0; j <= 5; j++) {
for (int i = 0; i < 500; i++) {
digitalWrite(PIN_STEPPER2_STEP, HIGH);
delayMicroseconds(400);
digitalWrite(PIN_STEPPER2_STEP, LOW);
delayMicroseconds(400);
}
delay(500);
digitalWrite(PIN_STEPPER2_DIR, HIGH);
for (int k = 0; k < 500; k++) {
digitalWrite(PIN_STEPPER2_STEP, HIGH);
delayMicroseconds(400);
digitalWrite(PIN_STEPPER2_STEP, LOW);
delayMicroseconds(400);
}
digitalWrite(PIN_STEPPER2_DIR, LOW);
}
// stepper2.setMaxSpeed(2500);
// stepper2.setAcceleration(1500);
// stepper2.runToNewPosition(-20000);
leftToMid();
taskMidToRight(NULL);
closePump();
openAir();
delay(3000);
closeAir();
delay(2000);
taskPillsOut(NULL);
taskRightToMid(NULL);
// xTaskCreate(taskRightToMid, "taskRightToMid", 1000, NULL, 1, NULL);
isTaskTake = false;
digitalWrite(PIN_ENABLE, HIGH);
}
void taskTakePills(void *pvParameters) {
int boxName = ((int *)pvParameters)[0];
int pillsNumber = ((int *)pvParameters)[1];
#ifdef DEBUG
Serial.println("boxName: " + String(boxName));
Serial.println("pillsNumber: " + String(pillsNumber));
#endif
takePills(boxName, pillsNumber);
vTaskDelete(NULL);
}
void takePillsTest() {
midToLeft();
openPump();
// stepper2.runToNewPosition(6400);
delay(1000);
digitalWrite(PIN_STEPPER2_DIR, LOW);
for (int j = 0; j <= 5; j++) {
for (int i = 0; i < 500; i++) {
digitalWrite(PIN_STEPPER2_STEP, HIGH);
delayMicroseconds(400);
digitalWrite(PIN_STEPPER2_STEP, LOW);
delayMicroseconds(400);
}
delay(500);
digitalWrite(PIN_STEPPER2_DIR, HIGH);
for (int k = 0; k < 500; k++) {
digitalWrite(PIN_STEPPER2_STEP, HIGH);
delayMicroseconds(400);
digitalWrite(PIN_STEPPER2_STEP, LOW);
delayMicroseconds(400);
}
digitalWrite(PIN_STEPPER2_DIR, LOW);
}
// stepper2.setMaxSpeed(2500);
// stepper2.setAcceleration(1500);
// stepper2.runToNewPosition(-20000);
leftToMid();
taskMidToRight(NULL);
closePump();
openAir();
delay(3000);
closeAir();
taskRightToMid(NULL);
}
作品展示:
單片機(jī)-嵌入式畢設(shè)選題大全及項(xiàng)目分享:
https://blog.csdn.net/m0_71572576/article/details/125409052
4 最后
到了這里,關(guān)于【畢業(yè)設(shè)計(jì)】基于STM32的智能藥箱系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn) - 物聯(lián)網(wǎng) 單片機(jī)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!