STM32智能独居老人看护系统

目录

一、前言

二、项目简介

1.功能详解

2.主要器件

三、原理图设计

四、PCB硬件设计

[PCB图 ​编辑​编辑](#PCB图 编辑编辑)

五、程序设计

六、实验效果

七、包含内容

项目分享


一、前言

项目成品图片:

哔哩哔哩视频链接:

https://www.bilibili.com/video/BV1XYXfBJEgo/?spm_id_from=333.1387.homepage.video_card.click&vd_source=199aed5297a00e80e1faf7e270afe8d7

(资料分享见文末)

二、项目简介

1.功能详解

基于STM32的智能智能独居老人看护系统

功能如下:

  1. 环境采集:DS18B20温度传感器检测环境温度、MAX30102心率血氧传感器采集老人心率血氧、超声波传感器检测与前方障碍物距离、六轴陀螺仪检测老人是否发生跌倒、空气质量传感器检测环境空气质量情况
  2. 显示功能:环境数据显示在OLED屏幕上
  3. 模式切换:通过按键可以切换手动模式和自动模式
  4. 自动模式:如果温度超过阈值、心率大于阈值、血氧小于阈值、超声波距离小于阈值、发生跌倒、空气质量超过阈值时蜂鸣器报警
  5. 手动模式:可以通过按键控制报警开关与LED灯开关
  6. 阈值调节:可通过按键进入阈值设置界面,可调节温度、心率、血氧、空气质量、距离阈值
  7. 机智云APP:WIFI接入机智云平台,通过手机APP可查看信息数据和控制指令下发

2.主要器件

  • STM32F103C8T6最小系统板
  • OLED显示屏(4针IIC协议)
  • 18B20温度传感器
  • MQ-135空气质量传感器
  • HC-SR04超声波传感器
  • ESP8266-01S(WIFI模块)
  • MAX30102心率血氧传感器
  • MPU6050陀螺仪传感器
  • 蜂鸣器
  • LED灯

三、原理图设计

四、PCB硬件设计

PCB图

五、程序设计

cpp 复制代码
#include "stm32f10x.h"
#include "led.h"
#include "beep.h"
#include "usart.h"
#include "delay.h"
#include "oled.h"
#include "key.h"
#include "Modules.h"
#include "TIM2.h"
#include "adcx.h"
#include "flash.h"
#include "usart2.h"
#include "usart3.h"
#include "max30102_read.h"
#include "myiic.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ds18b20.h"
#include "string.h" 	
#include "ultrasonic.h"
#include "timer.h"
#include "TIM3.h" 
#include "MPU6050.h" 
#include "gizwits_product.h"         
#include "gizwits_protocol.h"   
/****************异方辰电子工作室******************
	                 STM32
											
 * 项目			:	STM32独居老人看护系统                 
 * 版本			:   V2.0
 * 日期			:   2025.11.07
 * MCU			:	STM32F103C8T6
 * 接口			:	见代码		
 * IP账号		:	异方辰电子/辰哥单片机设计(同BILIBILI|抖音|快手|小红书|CSDN|公众号|视频号等)
 * 作者			:	辰哥 
 * 工作室		:   异方辰电子工作室
 * 授权IP	 	:	辰哥单片机设计、异方辰电子、YFC电子、异方辰系列 
 * 官方网站	    :	www.yfcdz.cn	

**********************BEGIN***********************/

// 按键功能宏定义
#define KEY_Long1	11   // 按键1长按
#define KEY_1	1        // 按键1短按
#define KEY_2	2        // 按键2
#define KEY_3	3        // 按键3
#define KEY_4	4        // 按键4

#define FLASH_START_ADDR	0x0801f000	

#define AUTO_MODE     1   // 自动模式
#define MANUAL_MODE   2   // 手动模式
#define SETTINGS_MODE 3   // 设置模式
uint8_t ID;								//定义用于存放ID号的变量
int16_t AX, AY, AZ, GX, GY, GZ;			//定义用于存放各个数据的变量
int16_t SUM,SUM_OLD = 0,sum,test=0,count = 0;


extern  SensorModules sensorData;								
extern  SensorThresholdValue Sensorthreshold;		
extern  DriveModules driveData;			

// 系统核心全局变量
uint8_t mode = 1;	// 系统模式控制:1=自动模式,2=手动模式,3=设置模式
u8 dakai;// 串口3数据传递临时变量
u8 Flag_dakai;// 串口3接收完成标志位
uint8_t is_secondary_menu = 0;  // 二级菜单状态标识:0=一级菜单,1=二级菜单(预留RTC时间设置等扩展功能)
uint8_t secondary_pos = 1;      // 二级菜单光标位置:1-3对应时/分/秒(预留扩展)
uint8_t secondary_type = 0;   // 二级菜单类型:0=RTC时间,1=定时开启,2=定时关闭



// 外部变量声明:从其他.c文件导入的全局变量
extern unsigned char p[16];// 温度数据字符串缓存(DS18B20采集后格式化存储到该数组)
short temperature = 0; 	// 温度原始数据存储变量

// 系统静态变量用于记录模式内状态
//static uint8_t count_a = 1;  //自动模式按键数
 uint8_t count_m = 1;  // 手动模式按键计数:记录当前选中的控制项(1=灯光,2=蜂鸣器)
 uint8_t count_s = 1;	 // 设置模式按键计数:记录当前选中的阈值项(1=温度,2=心率,3=光照,4=距离)
 uint8_t last_mode = 0;      // 记录上一次的模式(注释,主函数内重新定义静态变量)
uint8_t last_count_s = 0;   // 记录设置模式内上一次的页面(注释,未使用)
uint8_t auto_page = 1; 

int main(void)
{ 
    SystemInit();    
    delay_init(72);  
    ADCX_Init();     
    LED_Init();      
    BEEP_Init();     
    BEEP_OFF;        
	  Ultrasonic_Init(); 
    USART1_Config();     
    USART2_Config();   
    USART3_Config();     
    Key_Init();          
    Init_MAX30102();     
    OLED_Init();         
    DS18B20_Init();      
    OLED_Clear();        
	//  MyI2C_Init(); 
	  MPU6050_Init();	
    srand((unsigned int)delay_get_tick());  
    TIM2_Init(72-1,1000-1); 
		TIM3_Int_Init(1000-1,72-1);
    delay_ms(100); 
    FLASH_ReadThreshold();
   
    static uint8_t last_mode = 0;  // 记录上一次的系统模式(用于模式切换时清屏)
    static uint32_t last_sensor_time = 0; // 传感器扫描时间戳(控制采集频率)
    static uint32_t last_display_time = 0; // 显示刷新时间戳(控制屏幕刷新频率)
    
    // 阈值合法性检查:若Flash中阈值超出合理范围,恢复默认值
    if (Sensorthreshold.tempValue > 40    || 
			  Sensorthreshold.hrAvgValue >120   || 
        Sensorthreshold.sopAvgValue > 100 || 
		    Sensorthreshold.distanceValue > 50||
		    Sensorthreshold.mq135Value>200)
    {
        // 写入默认阈值:温度30℃,心率80次/分,光照100Lux,距离10CM
        FLASH_W(FLASH_START_ADDR, 30, 95, 96, 10,20);
        FLASH_ReadThreshold(); // 重新读取默认阈值
    }
    

    userInit();       // 机智云用户初始化(数据点初始化等)
    gizwitsInit();    // 机智云协议初始化(WiFi配网、数据通信初始化)
	  gizwitsSetMode(WIFI_AIRLINK_MODE); //默认一键配网
	  delay_ms(200);
	
    printf("Start \n"); 
    gizwitsHandle((dataPoint_t *)&currentDataPoint);
    ScanGizwitsMode();

   delay_ms(200);


    
    while (1) 
    {	
			
         gizwitsHandle((dataPoint_t *)&currentDataPoint);
        // ==================== 获取当前系统时间 ====================
        uint32_t current_time = delay_get_tick(); // 使用系统滴答计数获取当前时间(毫秒级)
        
        // ==================== 优化传感器扫描频率 ====================
        if(current_time - last_sensor_time > 100) // 每100ms扫描一次传感器
        {
            SensorScan(); 	//获取传感器数据(温度、心率、光照、距离、碰撞)
            last_sensor_time = current_time; // 更新传感器扫描时间戳
        }
        
        // ==================== 立即处理按键 ====================
        uint8_t current_key_num = KeyNum; // 保存当前按键值(避免被其他逻辑修改)
        
        // 模式切换按键立即处理(短按KEY1/长按KEY1)
        if(current_key_num != 0)
        {
            switch(mode)
            {
                case AUTO_MODE:
                    if(current_key_num == KEY_1) // 短按KEY1:自动模式→手动模式
                    {
                        mode = MANUAL_MODE;
                        count_m = 1; // 手动模式默认选中灯光控制项
                        // 切换到手动模式时关闭灯和蜂鸣器
                        driveData.LED_Flag = 0;
                        driveData.BEEP_Flag = 0;
                        KeyNum = 0; // 立即清除按键标志,避免重复触发
                    }
                    else if(current_key_num == KEY_Long1) // 长按KEY1:自动模式→设置模式
                    {
                        mode = SETTINGS_MODE;
                        count_s = 1; // 设置模式默认选中温度阈值项
                        KeyNum = 0; // 立即清除按键标志
                    }
                    break;
                    
                case MANUAL_MODE:
                    if(current_key_num == KEY_1) // 短按KEY1:手动模式→自动模式
                    {
                        mode = AUTO_MODE;
                        KeyNum = 0; // 立即清除按键标志
                    }
                    break;
                    
                case SETTINGS_MODE:
                    // 设置模式内部按键在各自模式中处理
                    break;
            }
        }
        
        // ==================== 模式切换优化 ====================
        if(last_mode != mode) // 检测到系统模式变化
        {
            OLED_Clear(); // 清屏,避免不同模式页面重叠
            last_mode = mode; // 更新上一次模式
            
            // 立即绘制新模式的固定标题内容
            switch(mode)
            {
                case AUTO_MODE:
									  auto_page = 1;
                    OLED_autoPage1(); // 自动模式:绘制传感器标题页面
								    SensorDataDisplay1();	
                    break;
                case MANUAL_MODE:
                    OLED_manualPage1(); // 手动模式:绘制控制项标题页面
                    break;
                case SETTINGS_MODE:
                    OLED_settingsPage1(); // 设置模式:绘制阈值标题页面
								    SettingsThresholdDisplay1(); 
                    break;
            }
            OLED_Refresh(); // 立即刷新显示,使新模式页面生效
        }
        
        // ==================== 模式处理 ====================
        switch(mode)
        {
            // -------------------- 自动模式 --------------------
            case AUTO_MODE:
						{
							 uint8_t curr_auto_page = SetAuto();
							if(curr_auto_page == 1)
                {
                SensorDataDisplay1();	
									
                // 仅时间变化时刷新
                 OLED_Refresh();
								}
								 else
                {
                    SensorDataDisplay2();	
                }
                AutoControl();
                Control_Manager();
                break;
						}  
                
            // -------------------- 手动模式 --------------------
            case MANUAL_MODE:
            {
                // 手动模式静态状态变量(保持模式内状态)
                static uint8_t manual_page_initialized = 0; // 页面初始化标志
                static uint8_t last_manual_count = 0; // 上一次选中的控制项序号
                static uint8_t last_LED_Flag = 0; // 上一次LED状态
                static uint8_t last_BEEP_Flag = 0; // 上一次蜂鸣器状态
                static uint8_t force_refresh = 0;  // 强制刷新标志(模式切换时使用)
                
                // 模式切换时重新初始化状态
                if(last_mode != mode)
                {
                    manual_page_initialized = 0;
                    last_manual_count = 0;
                    last_LED_Flag = driveData.LED_Flag;
                    last_BEEP_Flag = driveData.BEEP_Flag;
                    force_refresh = 1;  // 设置强制刷新标志
                    
                    // 确保光标指向灯光控制项
                    count_m = 1;
                    // 确保设备状态为关闭
                    driveData.LED_Flag = 0;
                    driveData.BEEP_Flag = 0;
                }
                
                uint8_t current_manual_count = SetManual(); // 获取当前选中的控制项序号
                
                // 检查设备状态是否改变(LED/蜂鸣器),若改变则需要刷新显示
                uint8_t need_refresh = 0;
                if(driveData.LED_Flag != last_LED_Flag || driveData.BEEP_Flag != last_BEEP_Flag)
                {
                    need_refresh = 1;
                    last_LED_Flag = driveData.LED_Flag;
                    last_BEEP_Flag = driveData.BEEP_Flag;
                }
                
                // 页面未初始化/光标位置改变/设备状态改变/强制刷新→重新绘制页面
                if(!manual_page_initialized || current_manual_count != last_manual_count || need_refresh || force_refresh)
                {
                    OLED_manualPage1();          // 绘制控制项固定标题
                    OLED_manualOption(current_manual_count); // 显示当前光标位置
                    ManualSettingsDisplay1();    // 显示设备当前状态(开/关)
                    manual_page_initialized = 1;
                    last_manual_count = current_manual_count;
                    force_refresh = 0;  // 清除强制刷新标志
                    OLED_Refresh(); // 强制刷新显示
                }
                
                // 立即处理手动模式按键(控制设备开关)
                if(current_key_num != 0)
                {
                    ManualControl(current_manual_count); // 执行当前控制项的按键操作
                    OLED_manualPage1();          // 重新绘制固定标题
                    OLED_manualOption(current_manual_count); // 显示光标
                    ManualSettingsDisplay1();    // 刷新设备状态
                    OLED_Refresh(); // 按键操作后立即刷新显示
                    KeyNum = 0; // 立即清除按键标志
                }
                
                Control_Manager(); // 执行硬件开关控制(LED、蜂鸣器)
                break;
            }
                
            // -------------------- 设置模式 --------------------
            case SETTINGS_MODE:
            {
                // 优化设置模式响应速度:静态初始化标志
                static uint8_t is_threshold_page_inited = 0;
                uint8_t curr_count_s = SetSelection(); // 获取当前选中的阈值项序号
                
                // 立即处理设置模式内的按键
                if(current_key_num != 0)
                {
                    if (is_secondary_menu == 1) // 二级菜单(预留,当前未实现)
                    {
                        // 二级菜单按键立即处理
                        if (current_key_num == KEY_2 || current_key_num == KEY_3 || current_key_num == KEY_4)
                        {
                            // 这里根据你的二级菜单逻辑处理(如时间设置)
                            // 处理完后立即刷新
                            OLED_Refresh();
                            KeyNum = 0;
                        }
                        else if (current_key_num == KEY_1) // 按键1→返回一级菜单
                        {
                            is_secondary_menu = 0;
                            secondary_pos = 1;
                            OLED_Clear();
                            OLED_settingsPage1();
                            SettingsThresholdDisplay1();
                            OLED_settingsOption(curr_count_s);
                            OLED_Refresh();
                            KeyNum = 0;
                        }
                    }
                   else 
        {
            if (current_key_num == KEY_3 || current_key_num == KEY_4)
            {
                ThresholdSettings(curr_count_s); 
                // 核心修复:根据当前页选择对应的显示刷新函数
                if(curr_count_s >=1 && curr_count_s <=4)
                {
                    SettingsThresholdDisplay1(); // 第一页刷新
                }
                else if(curr_count_s ==5)
                {
                    SettingsThresholdDisplay2(); // 第二页刷新(不再调用第一页)
                }
                OLED_Refresh();
                KeyNum = 0;
            }
                        else if (current_key_num == KEY_1) // 按键1→返回自动模式
                        {
                            mode = AUTO_MODE;
                            is_threshold_page_inited = 0;
                            // 保存调整后的阈值到Flash
                           		FLASH_W(FLASH_START_ADDR, Sensorthreshold.tempValue, 
		                                                    Sensorthreshold.hrAvgValue,
                                                        Sensorthreshold.sopAvgValue,
															                          Sensorthreshold.distanceValue,
															                          Sensorthreshold.mq135Value);
                            KeyNum = 0;
                        }
                    }
                }
                
                // 正常显示逻辑
                if (is_secondary_menu == 1)
                {
                    // 二级菜单显示(预留,当前未实现)
                }
                else
                {
                    // 一级菜单显示(阈值调整页面)
                    if (curr_count_s >= 1 && curr_count_s <= 4) // 光标在有效阈值项范围内
                    {
                        if (is_threshold_page_inited == 0) // 页面未初始化→绘制标题
                        {
                            OLED_settingsPage1();
                            is_threshold_page_inited = 1;
													 SettingsThresholdDisplay1();
                        }
												   OLED_settingsOption(curr_count_s); // 显示第一页光标
                    }
										 else if (curr_count_s ==5 )
               {
								  if (is_threshold_page_inited == 0)
            {
								   OLED_settingsPage2();
                SettingsThresholdDisplay2(); // 显示第二页阈值
                is_threshold_page_inited = 1;
						}
						OLED_settingsOption(curr_count_s);
               }
                 
                   
                }
                break;
            }
        }
        
        // ==================== 限制显示刷新频率 ====================
        if(current_time - last_display_time > 25) // 每25ms刷新一次显示
        {
            // 所有模式都需要刷新显示
            OLED_Refresh();
            last_display_time = current_time; // 更新显示刷新时间戳
        }
					userHandle();
   }
}

六、实验效果

七、包含内容

项目分享

相关推荐
feifeigo1232 小时前
基于Cortex-M3和步进电机的数字钟控制及其语音播报系统设计
单片机·嵌入式硬件
我不是程序猿儿3 小时前
【嵌入式】USBCDC学习目标--STM32 板载 USB 做 CDC 虚拟串口(Virtual COM Port)
stm32·单片机·嵌入式硬件·学习
学嵌入式的小杨同学3 小时前
STM32 进阶封神之路(三十四):TFT LCD 深度全解 —— 显示原理、ILI9341 控制器、8080 并行接口与底层驱动体系
vscode·stm32·单片机·嵌入式硬件·mcu·智能硬件·嵌入式实时数据库
三佛科技-187366133973 小时前
遥控台灯方案开发案例,主控芯片8位MCU
单片机·嵌入式硬件
激昂网络3 小时前
用CT001解读Type-C线材设计:为什么只有一个CC灯亮?
c语言·开发语言·嵌入式硬件
逐步前行4 小时前
HAL_NVIC
stm32·单片机·嵌入式硬件
养一回月亮!4 小时前
STM32F407VET6驱动1.8寸TFT LCD移植LVGL,实现矩阵按键控制UI
stm32·单片机·lvgl
恒森宇电子有限公司4 小时前
芯晞微CSM4056H 单节锂离子电池充电器芯片 封装ESOP-8
单片机·嵌入式硬件
果果燕4 小时前
ARM嵌入式学习(五)---IMX6ULL外部中断
单片机·嵌入式硬件