基于stm32单片机老人居家监护报警系统毕业设计

基于stm32单片机老人居家监护报警系统毕业设计

1、采用stm32单片机+LCD1602显示屏+独立按键+MQ4传感器(电位器模拟)+MQ2传感器(电位器模拟)+蜂鸣器+电机,制作一个基于stm32单片机老人居家监护报警系统Proteus仿真;

2、通过MQ2传感器(电位器调节)检测烟雾浓度,并且显示到LCD1602显示屏上面;

3、通过MQ4传感器(电位器调节)检测天然气浓度,并且显示到LCD1602显示屏上面;

4、通过按键设置MQ2和MQ4浓度的阈值,显示到LCD1602屏幕上面;

5、当MQ2检测浓度或者MQ4检测浓度大于设置的阈值,蜂鸣器进行报警提醒,自动打开通风排气电机;

基于您提供的毕业设计要求,以下是一个简化的基于STM32单片机的老人居家监护报警系统的设计和实现方案。由于Proteus(可能是Proteus Design Suite的误写,通常是Proteus或Proteus 8 Professional)主要用于电路图绘制和仿真,我们将主要关注于系统设计和仿真设置。

1. 系统设计

1.1 硬件设计
  • STM32单片机:作为控制核心,负责读取传感器数据、处理按键输入、控制显示屏和电机等外设。
  • LCD1602显示屏:用于显示烟雾和天然气浓度以及阈值设置。
  • 独立按键:用于设置MQ2和MQ4的浓度阈值。
  • MQ2传感器(电位器模拟):模拟烟雾浓度检测,通过电位器调节模拟值。
  • MQ4传感器(电位器模拟):模拟天然气浓度检测,同样通过电位器调节模拟值。
  • 蜂鸣器:当检测到浓度超过阈值时,发出报警声。
  • 电机:当检测到浓度超过阈值时,自动打开通风排气。
1.2 软件设计
  • 初始化:配置STM32的GPIO、USART(如果需要)、定时器、中断等。
  • 传感器读取:通过ADC(模拟数字转换器)读取MQ2和MQ4传感器(电位器模拟)的模拟值,并转换为浓度值。
  • LCD显示:将检测到的烟雾和天然气浓度值,以及设置的阈值显示在LCD1602上。
  • 按键处理:读取按键输入,并根据按键设置MQ2和MQ4的浓度阈值。
  • 报警和电机控制:当检测到的浓度超过阈值时,启动蜂鸣器报警,并控制电机打开通风排气。

2. Proteus仿真设置

2.1 电路图绘制
  • 在Proteus中绘制电路图,包括STM32单片机、LCD1602、按键、电位器(模拟MQ2和MQ4传感器)、蜂鸣器和电机等元件。
  • 连接STM32的GPIO口到LCD1602、按键、电位器和电机的控制引脚。
2.2 仿真设置
  • 配置STM32的GPIO口为适当的模式(输入/输出、上拉/下拉等)。
  • 配置ADC以读取电位器的模拟值。
  • 配置LCD1602的接口(通常为并行接口)。
  • 设置按键的输入模式。
  • 配置蜂鸣器和电机的控制引脚为输出模式。

3. 代码编写

使用STM32的HAL库或标准外设库编写代码,实现以下功能:

  • 初始化系统。
  • 读取MQ2和MQ4传感器的模拟值,并转换为浓度值。
  • 显示浓度值和阈值到LCD1602。
  • 处理按键输入,设置阈值。
  • 检测浓度是否超过阈值,并执行报警和电机控制。

4. 注意事项

  • 由于MQ2和MQ4传感器在Proteus中无法直接模拟,我们使用电位器来模拟传感器的输出。
  • 在实际系统中,您可能需要添加额外的电路来驱动电机和蜂鸣器,以及处理传感器的真实输出。
  • 考虑到老人使用的便捷性,界面和按键设计应尽可能简单直观。
  • 报警系统应确保在紧急情况下能够可靠工作,因此应进行充分的测试和验证。

为了提供一个基于STM32单片机的老人居家监护报警系统的简化代码示例,我们需要考虑系统的几个关键部分:传感器读取(虽然在这里用电位器模拟)、LCD显示、按键输入处理、报警逻辑以及电机控制。以下是一个简化的伪代码/代码框架,用于指导您如何开始编写实际的代码。

请注意,这里假设您已经为STM32配置了必要的HAL库,并且了解如何使用STM32CubeMX或STM32CubeIDE进行初始化设置。

伪代码/代码框架

void System_Init(void) {  
    // 初始化HAL库  
    HAL_Init();  
  
    // 配置系统时钟  
    SystemClock_Config();  
  
    // 初始化GPIO、ADC(用于读取电位器值)、LCD1602、按键等  
    MX_GPIO_Init();  
    MX_ADC_Init(); // 初始化ADC以读取电位器值  
    LCD1602_Init();  
    Keypad_Init();  
  
    // 初始化蜂鸣器和电机控制GPIO  
    Buzzer_Init();  
    Motor_Init();  
  
    // 其他初始化...  
}  
  
// 系统主函数  
int main(void) {  
    System_Init();  
  
    // 主循环  
    while (1) {  
        // 读取传感器值(这里用电位器模拟)  
        float smokeLevel = Read_Potentiometer_Value_As_SmokeLevel(ADC1_CHANNEL_SMOKE); // 假设ADC1_CHANNEL_SMOKE是模拟烟雾的电位器通道  
        float gasLevel = Read_Potentiometer_Value_As_GasLevel(ADC1_CHANNEL_GAS); // 假设ADC1_CHANNEL_GAS是模拟天然气的电位器通道  
  
        // 显示浓度值  
        Display_Concentration(LCD1602, smokeLevel, gasLevel);  
  
        // 处理按键输入  
        if (Key_Pressed(KEY_SET_SMOKE_THRESHOLD)) {  
            // 设置烟雾浓度阈值...  
        }  
        if (Key_Pressed(KEY_SET_GAS_THRESHOLD)) {  
            // 设置天然气浓度阈值...  
        }  
  
        // 检查是否超过阈值并触发报警  
        if (smokeLevel > smokeThreshold || gasLevel > gasThreshold) {  
            Trigger_Alarm(Buzzer);  
            Start_Motor();  
        } else {  
            Stop_Alarm(Buzzer);  
            if (Motor_IsRunning()) {  
                Stop_Motor(); // 延时一段时间后停止电机,以防误报  
            }  
        }  
  
        // 延时或其他任务...  
        HAL_Delay(100); // 假设的延时,用于降低主循环的频率  
    }  
}
  1. 读取电位器值并转换为浓度
    float Read_Potentiometer_Value_As_SmokeLevel(uint32_t adcChannel) {  
        // 读取ADC值并转换为烟雾浓度(这里需要您定义转换逻辑)  
        // 假设ADC值范围为0-1023,对应浓度0-1000 ppm  
        uint32_t adcValue = HAL_ADC_GetValue(&hadc); // hadc是ADC句柄,需要您在初始化中配置  
        float smokeLevel = (float)adcValue * 1000.0f / 1023.0f;  
        return smokeLevel;  
    }  
      
    // 同理,对于天然气浓度  
    float Read_Potentiometer_Value_As_GasLevel(uint32_t adcChannel) {  
        // ...  
    }

  2. LCD显示、按键处理、报警和电机控制
  3. 这只是一个简化的框架,用于指导您开始编写代码。在实际应用中,您可能需要添加错误处理、更复杂的用户界面、网络通信(以便远程监控)等功能。
  4. 请确保在编写代码时参考您所使用的STM32单片机的具体数据手册和参考手册,以及LCD、按键、ADC、蜂鸣器和电机等外设的文档。
  5. 如果您不熟悉STM32的HAL库或标准外设库,建议您先学习这些库的基本用法和API。
  6. 这些函数的具体实现将取决于您使用的LCD模块、按键模块、蜂鸣器和电机的具体型号和接口。通常,您需要编写初始化函数来配置GPIO,然后编写读写函数来与这些外设进行通信。

  7. 为了更具体地展示基于STM32单片机的老人居家监护报警系统的模块化代码,我们可以将每个功能拆分成单独的函数或模块。下面是一个更详细的代码示例,其中包含了一些简化的函数定义,以指导您如何编写和组织代码。

    1. 初始化函数

    #include "stm32f1xx_hal.h" // 根据您的STM32型号选择正确的头文件  
    #include "lcd1602.h"       // 假设您有一个LCD1602的驱动头文件  
    #include "keypad.h"        // 假设您有一个按键处理的头文件  
    #include "buzzer.h"        // 假设您有一个蜂鸣器控制的头文件  
    #include "motor.h"         // 假设您有一个电机控制的头文件  
      
    // 初始化函数  
    void System_Init(void) {  
        HAL_Init();  
        SystemClock_Config();  
        MX_GPIO_Init();  
        MX_ADC_Init();  
        LCD1602_Init();  
        Keypad_Init();  
        Buzzer_Init();  
        Motor_Init();  
      
        // 初始化阈值等变量  
        float smokeThreshold = 500.0f; // 假设的烟雾浓度阈值  
        float gasThreshold = 100.0f;   // 假设的天然气浓度阈值  
        // ... 其他初始化代码 ...  
    }  
      
    int main(void) {  
        System_Init();  
        while (1) {  
            // 主循环代码  
        }  
    }

    2. ADC读取和转换函数

    #include "stm32f1xx_hal.h"  
      
    // 假设hadc是ADC句柄,已经在MX_ADC_Init()中初始化  
    extern ADC_HandleTypeDef hadc;  
      
    // 读取ADC值并转换为烟雾浓度  
    float Read_ADC_As_SmokeLevel(uint32_t adcChannel) {  
        HAL_ADC_Start(&hadc); // 开始ADC转换  
        HAL_ADC_PollForConversion(&hadc, 10); // 等待转换完成(可选的,取决于配置)  
        uint32_t adcValue = HAL_ADC_GetValue(&hadc); // 读取ADC值  
        // 转换逻辑(这里简化处理)  
        float smokeLevel = (float)adcValue * 1000.0f / 1023.0f; // 假设ADC满量程为1023,对应浓度0-1000 ppm  
        return smokeLevel;  
    }  
      
    // 同理,对于天然气浓度  
    float Read_ADC_As_GasLevel(uint32_t adcChannel) {  
        // ...  
    }

    3. LCD显示函数

    lcd1602.clcd1602.h文件中实现。

    // lcd1602.h  
    void LCD1602_WriteString(const char* str);  
    void LCD1602_WriteFloat(float value, uint8_t decimalPlaces); // 假设的函数,用于显示浮点数  
    // ... 其他LCD函数声明 ...  
      
    // lcd1602.c  
    // ... 函数的具体实现 ...

    4. 按键处理函数

    keypad.ckeypad.h文件中实现。

    // keypad.h  
    typedef enum {  
        KEY_NONE,  
        KEY_SET_SMOKE_THRESHOLD,  
        KEY_SET_GAS_THRESHOLD,  
        // ... 其他按键 ...  
    } Keypad_Key;  
      
    Keypad_Key Keypad_GetKey(void);  
    // ... 其他按键函数声明 ...  
      
    // keypad.c  
    // ... 函数的具体实现 ...

    5. 报警和电机控制函数

    buzzer.cbuzzer.hmotor.cmotor.h文件中实现。

    // buzzer.h  
    void Buzzer_Start(void);  
    void Buzzer_Stop(void);  
    // ... 其他蜂鸣器函数声明 ...  
      
    // buzzer.c  
    // ... 函数的具体实现 ...  
      
    // motor.h  
    void Motor_Start(void);  
    void Motor_Stop(void);  
    // ... 其他电机函数声明 ...  
      
    // motor.c  
    // ... 函数的具体实现 ...

    6. 主循环中的逻辑

    #include "stm32f1xx_hal.h"  
    #include "lcd1602.h"  
    #include "keypad.h"  
    #include "buzzer.h"  
    #include "motor.h"  
      
    // 阈值变量(全局或静态,根据需要在初始化时设置)  
    static float smokeThreshold = 500.0f; // 烟雾浓度阈值  
    static float gasThreshold = 100.0f;   // 天然气浓度阈值  
      
    int main(void) {  
        System_Init();  
      
        while (1) {  
            // 读取传感器值  
            float smokeLevel = Read_ADC_As_SmokeLevel(ADC1_CHANNEL_SMOKE);  
            float gasLevel = Read_ADC_As_GasLevel(ADC1_CHANNEL_GAS);  
      
            // 显示浓度值  
            char smokeBuffer[16]; // 假设LCD显示字符串的最大长度  
            char gasBuffer[16];  
            sprintf(smokeBuffer, "Smoke: %.1f ppm", smokeLevel);  
            sprintf(gasBuffer, "Gas: %.1f ppm", gasLevel);  
            LCD1602_Clear(); // 清除LCD显示  
            LCD1602_WriteString(smokeBuffer);  
            LCD1602_SetCursor(0, 1); // 设置LCD光标到第二行  
            LCD1602_WriteString(gasBuffer);  
      
            // 处理按键输入  
            Keypad_Key key = Keypad_GetKey();  
            switch (key) {  
                case KEY_SET_SMOKE_THRESHOLD:  
                    // 实现设置烟雾浓度阈值的逻辑(可能需要一个循环来接收输入)  
                    // ...  
                    break;  
                case KEY_SET_GAS_THRESHOLD:  
                    // 实现设置天然气浓度阈值的逻辑  
                    // ...  
                    break;  
                // ... 处理其他按键 ...  
                default:  
                    break;  
            }  
      
            // 检查是否超过阈值并触发报警  
            if (smokeLevel > smokeThreshold || gasLevel > gasThreshold) {  
                Buzzer_Start(); // 触发报警  
                Motor_Start(); // 启动电机(可能是门窗打开或其他动作)  
            } else {  
                Buzzer_Stop(); // 停止报警  
                // 如果电机在运行,可以延时一段时间后停止  
                if (Motor_IsRunning()) {  
                    HAL_Delay(5000); // 假设5秒后停止电机  
                    Motor_Stop();  
                }  
            }  
      
            // 延时或其他任务...  
            HAL_Delay(100); // 100ms的延时  
        }  
    }
    程序部分展示,有中文注释,新手容易看懂
    void IO_out( void )
    {
      GPIO_InitTypeDef GPIO_InitStructure;
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC ,ENABLE);
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
      //按键
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0| GPIO_Pin_1| GPIO_Pin_2| GPIO_Pin_3;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;  
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;;
      GPIO_Init(GPIOC, &GPIO_InitStructure);  
    
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
      GPIO_Init(GPIOA, &GPIO_InitStructure);  
    
    }
    
    void anjiansaomiao(void)
    {
      static char k1,k2,k3,k4;
      static char K1Flag=0,K2Flag=0,K3Flag=0,K4Flag=0;  
      //按键扫描,获取按键状态
      k1 = GPIO_ReadInputDataBit(GPIOC , GPIO_Pin_0);
      k2 = GPIO_ReadInputDataBit(GPIOC , GPIO_Pin_1);
      k3 = GPIO_ReadInputDataBit(GPIOC , GPIO_Pin_2);
      k4 = GPIO_ReadInputDataBit(GPIOC , GPIO_Pin_3);
    
    
      //表明按下 
      if(k1 == 0)
      {
        K1Flag = 1;
      }
      else
      {
        //释放后进行响应
        if(K1Flag )
        {
          K1Flag = 0;
        MQ2++;
        if(MQ2>100) MQ2=100;    
        }
      }
        
      //表明按下 
      if(k2 == 0)
      {
        K2Flag = 1;
          
      }
      else
      {
        //释放后进行响应
        if(K2Flag )
        {
          K2Flag = 0;
        MQ2--;
        if(MQ2<1) MQ2=1;
        }
      }  
      
      //表明按下  
      if(k3 == 0)
      {
        K3Flag = 1;
      }
      else
      {
        //释放后进行响应
        if(K3Flag )
        {
          K3Flag = 0;
        MQ4++;
        if(MQ4>100) MQ4=100;
        }
      }
        //表明按下  
      if(k4 == 0)
      {
        K4Flag = 1;
      }
      else
      {
        //释放后进行响应
        if(K4Flag )
        {
          K4Flag = 0;
        MQ4--;
        if(MQ4<1) MQ4=1;
        }
      }  
    }
    int main(void)
    {
      int ADC_num1,ADC_num2;
      int temp1,temp2;
      GPIO_Configuration();//初始化
      ADC1_GPIO_Config();
      ADC_Config();     
      Init1602(); 
      IO_out();
      WrByte1602(0,1,'M'); //字符显示
      WrByte1602(0,2,'Q'); 
      WrByte1602(0,3,'2'); 
      WrByte1602(0,4,'='); 
      
      WrByte1602(1,1,'M'); 
      WrByte1602(1,2,'Q'); 
      WrByte1602(1,3,'4'); 
      WrByte1602(1,4,'='); 
    
      WrByte1602(0,9,'S'); 
      WrByte1602(0,10,'E'); 
      WrByte1602(0,11,'T'); 
      WrByte1602(0,12,'='); 
    
      WrByte1602(1,9,'S'); 
      WrByte1602(1,10,'E'); 
      WrByte1602(1,11,'T'); 
      WrByte1602(1,12,'=');   
      delay_ms(500);
      while(1)
      {
    
        ADC_num1=Get_ADC(ADC_Channel_0);//读取MQ2浓度
        temp1=ADC_num1*100/4096;    
        delay_ms(100);      
        ADC_num2=Get_ADC(ADC_Channel_1);//读取MQ4浓度
        temp2=ADC_num2*100/4096;     
      WrByte1602(0,5,AsciiCode[temp1%1000/100]);//显示MQ2浓度
      WrByte1602(0,6,AsciiCode[temp1%100/10]);
      WrByte1602(0,7,AsciiCode[temp1%10]); 
      WrByte1602(1,5,AsciiCode[temp2%1000/100]);  //显示MQ4浓度
      WrByte1602(1,6,AsciiCode[temp2%100/10]);
      WrByte1602(1,7,AsciiCode[temp2%10]);

  • 24
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

科创工作室li

你的鼓励将是大学生的创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值