目录
一、前言
项目成品图片:
哔哩哔哩视频链接:
STM32智能坐垫|座椅
(资料分享见文末)
二、项目简介
1.功能详解
基于STM32的智能坐垫|座椅
功能如下:
- 使用STM32F103C8T6单片机作为主控单元
- 通过DHT11检测温湿度数据,当温度不在设定的范围内,则控制加热和散热
- 通过按键设置时长、温度上下限值、手动控制加热、散热、模式切换
- 通过HX711检测重量,当重量不为0,则表明有人坐在坐垫上,此时开始计时,当计时时间超过设定的最长时间,则语音提醒“久坐多时,注意起身运动”
- 通过OLED显示测量数据
- 通过蓝牙模块,可将坐下时长、温湿度发送到手机端,手机端也可控制加热、散热、模式切换
2.主要器件
- STM32F103C8T6单片机
- OLED 屏幕
- DHT11温湿度传感器
- HX711称重传感器
- JR6001语音模块
- BT04A蓝牙模块
- 继电器
- 风扇模块
- PTC加热片
三、原理图设计
四、PCB硬件设计
PCB图
五、程序设计
#include "sys.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "math.h"
#include "delay.h"
#include "gpio.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "dht11.h"
#include "timer.h"
#include "hx711.h"
/**********************************
变量定义
**********************************/
uint8_t key_num = 0; //按键扫描标志位
uint8_t flag_display = 0; //显示界面标志位
uint32_t time_num = 0; //10ms计时
uint8_t temp_value = 0; //温度值
uint8_t humi_value = 0; //湿度值
uint32_t temp_max = 35; //温度最大值
uint32_t temp_min = 15; //温度最小值
char display_buf[16]; //显示数组
_Bool flag_mode = 0; //模式标志位
_Bool flag_JR = 0; //加热标志位
_Bool flag_SR = 0; //散热标志位
uint8_t count_hour_old = 1; //计时存储时
int count_minute_old = 0; //计时存储分
int count_second_old = 0; //计时存储秒
uint8_t count_hour = 0; //计时时
int count_minute = 0; //计时分
int count_second = 0; //计时秒
_Bool flag_count_end = 0; //计时结束标志位
extern uint8_t usart1_buf[256]; //串口1接收数组
extern uint8_t flag_timer_begin_1s; //定时器开始标志位
extern uint8_t flag_1s; //一秒钟到达标志位
_Bool flag_weight = 0; //重量标志位
uint32_t weight_maopi = 0; //毛皮重量
uint32_t weight_value = 0; //总重量
/**********************************
函数声明
**********************************/
void Key_function(void); //按键函数
void Monitor_function(void); //监测函数
void Display_function(void); //显示函数
void Manage_function(void); //处理函数
/****
******* 主函数
*****/
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置中断优先分组
Delay_Init(); //延时初始化
Gpio_Init(); //IO初始化
Key_Init(); //按键初始化
Oled_Init(); //OLED初始化
DHT11_Init(); //DHT11初始化
TIM2_Init(999,7199); //定时器初始化
Hx711_Init(); //HX711初始化
Oled_Clear_All(); //清屏
Usart1_Init(9600); //串口1初始化
Usart2_Init(9600); //串口2初始化
UsartPrintf(USART2,"AF:30");
Delay_ms(1000);
UsartPrintf(USART2,"A7:00001");
Delay_ms(1000);
while(1)
{
Key_function(); //按键函数
Monitor_function(); //监测函数
Display_function(); //显示函数
Manage_function(); //处理函数
time_num++; //计时变量+1
Delay_ms(10);
if(time_num %10 == 0)
LED_SYS = ~LED_SYS;
if(time_num >= 5000)
{
time_num = 0;
}
}
}
/****
*******按键函数
*****/
void Key_function(void)
{
key_num = Chiclet_Keyboard_Scan(0); //按键扫描
if(key_num != 0) //有按键按下
{
switch(key_num)
{
case 1: //按键1,切换设置界面
flag_display++;
if(flag_display >= 6)
flag_display = 0;
Oled_Clear_All(); //清屏
break;
case 2: //按键2:设定值加
switch(flag_display)
{
case 0: //界面0:手动控制加热
flag_mode = 1;
JR = !JR;
SR = 0;
break;
case 1: //界面1:温度最大值加
if(temp_max < 99)
temp_max++;
break;
case 2: //界面2:温度最小值加
if(temp_min < temp_max-1)
temp_min++;
break;
case 3: //界面3:设定时间“时”加
if(count_hour_old < 100)
count_hour_old++;
break;
case 4: //界面4:设定时间“分”加
count_minute_old++;
if(count_minute_old >= 60)
count_minute_old = 0;
break;
case 5: //界面5:设定时间“秒”加
count_second_old++;
if(count_second_old >= 60)
count_second_old = 0;
break;
default:
break;
}
break;
case 3: //按键3:设定值减
switch(flag_display)
{
case 0: //界面0:手动控制散热
flag_mode = 1;
JR = 0;
SR = !SR;
break;
case 1: //界面1:温度最大值减
if(temp_max > temp_min+1)
temp_max--;
break;
case 2: //界面2:温度最小值减
temp_min--;
break;
case 3: //界面3:设定时间“时”减
if(count_hour_old > 0)
count_hour_old--;
break;
case 4: //界面4:设定时间“分”减
count_minute_old--;
if(count_minute_old < 0)
count_minute_old = 59;
break;
case 5: //界面5:设定时间“秒”减
count_second_old--;
if(count_second_old < 0)
count_second_old = 59;
break;
default:
break;
}
break;
case 4: //按键4:手动自动模式切换
if(flag_display == 0)
flag_mode = 0;
break;
default:
break;
}
}
}
/****
*******监测函数
*****/
void Monitor_function(void)
{
u32 weight_test = 0;
if(flag_display == 0) //测量界面
{
if(time_num % 3 == 0) //获取数据
{
DHT11_Read_Data(&temp_value,&humi_value);
if(flag_weight == 0)
{
weight_maopi = Hx711_Get_Maopi(); //获取毛皮重量
flag_weight = 1;
}
else
weight_test = Hx711_Get_Weight(weight_maopi); //获取总重量
if(weight_test < 5000)
weight_value = weight_test;
}
if(time_num % 50 == 0) //发送数据
{
UsartPrintf(USART1,"温度:%dC\r\n",temp_value);
UsartPrintf(USART1,"湿度:%d%%\r\n",humi_value);
UsartPrintf(USART1,"时间:%d%d:%d%d:%d%d\r\n",count_hour/10,count_hour%10,count_minute/10,count_minute%10,count_second/10,count_second%10);
}
if(USART1_WaitRecive() == 0) //如果接收到蓝牙数据
{
switch(usart1_buf[0])
{
case('A'): //A:切换自动模式
if(flag_display == 0)
flag_mode = 0;
break;
case('B'): //B:加热
flag_mode = 1;
JR = !JR;
SR = 0;
break;
case('C'): //C:散热
flag_mode = 1;
JR = 0;
SR = !SR;
break;
default:
break;
}
USART1_Clear();
}
}
}
/****
*******显示函数
*****/
void Display_function(void)
{
switch(flag_display) //根据不同的显示模式标志位,显示不同的界面
{
case 0: //界面0:显示模式,温度,湿度,时间
Oled_ShowCHinese(1,0,"模式:");
Oled_ShowCHinese(2,0,"温度:");
sprintf(display_buf,"%dC",temp_value);
Oled_ShowString(2,6,display_buf);
Oled_ShowCHinese(3,0,"湿度:");
sprintf(display_buf,"%d%%",humi_value);
Oled_ShowString(3,6,display_buf);
Oled_ShowCHinese(4,0,"时间:");
sprintf(display_buf,"%d%d:%d%d:%d%d",count_hour/10,count_hour%10,count_minute/10,count_minute%10,count_second/10,count_second%10);
Oled_ShowString(4,6,display_buf);
if(flag_mode == 0)
Oled_ShowCHinese(1,3,"自动");
else
Oled_ShowCHinese(1,3,"手动");
break;
case 1: //界面1:显示设置温度最大值
Oled_ShowCHinese(1,1,"设置温度最大值");
if(time_num % 10== 0)
{
sprintf(display_buf,"%d%d",temp_max/10,temp_max%10);
Oled_ShowString(2,7,display_buf);
}
if(time_num % 20 == 0)
{
Oled_ShowString(2,7," ");
}
break;
case 2: //界面2:显示设置温度最小值
Oled_ShowCHinese(1,1,"设置温度最小值");
if(time_num % 10== 0)
{
sprintf(display_buf,"%d%d",temp_min/10,temp_min%10);
Oled_ShowString(2,7,display_buf);
}
if(time_num % 20 == 0)
{
Oled_ShowString(2,7," ");
}
break;
case 3: //界面3:显示设置时间时
Oled_ShowCHinese(1,1,"设置时间时");
if(time_num % 10== 0)
{
sprintf(display_buf,"%d%d:%d%d:%d%d",count_hour_old/10,count_hour_old%10,count_minute_old/10,count_minute_old%10,count_second_old/10,count_second_old%10);
Oled_ShowString(2,4,display_buf);
}
if(time_num % 20 == 0)
{
Oled_ShowString(2,4," ");
}
break;
case 4: //界面4:显示设置时间分
Oled_ShowCHinese(1,1,"设置时间分");
if(time_num % 10== 0)
{
sprintf(display_buf,"%d%d:%d%d:%d%d",count_hour_old/10,count_hour_old%10,count_minute_old/10,count_minute_old%10,count_second_old/10,count_second_old%10);
Oled_ShowString(2,4,display_buf);
}
if(time_num % 20 == 0)
{
Oled_ShowString(2,7," ");
}
break;
case 5: //界面5:显示设置时间秒
Oled_ShowCHinese(1,1,"设置时间秒");
if(time_num % 10== 0)
{
sprintf(display_buf,"%d%d:%d%d:%d%d",count_hour_old/10,count_hour_old%10,count_minute_old/10,count_minute_old%10,count_second_old/10,count_second_old%10);
Oled_ShowString(2,4,display_buf);
}
if(time_num % 20 == 0)
{
Oled_ShowString(2,10," ");
}
break;
default:
break;
}
}
/****
*******处理函数
*****/
void Manage_function(void)
{
if(flag_display == 0) //测量界面
{
if(flag_mode == 0)
{
if(temp_value > temp_max) //温度高于最大值开启散热
{
SR = 1;
JR = 0;
}
else if(temp_value < temp_min) //温度小于最小值加热
{
SR = 0;
JR = 1;
}
else //温度低于最大值且温度大于最小值,关闭散热和加热
{
SR = 0;
JR = 0;
}
}
if(weight_value > 5 ) //人坐上坐垫开始计时
{
flag_timer_begin_1s = 1;
if(count_hour_old != 0 || count_minute_old != 0 || count_second_old != 0) //设置时间不为零,同时到达设置时间时播报"请劳逸结合,注意起身运动"
{
if(count_hour == count_hour_old && count_minute == count_minute_old && count_second == count_second_old)
{
UsartPrintf(USART2,"A7:00002");
Delay_ms(1500);
}
}
}
else //人离开坐垫
{
flag_timer_begin_1s = 0;
count_hour = 0; //重新赋值计时时间
count_minute = 0;
count_second = 0;
}
}
else //设置界面:关闭加热,散热,定时器
{
flag_timer_begin_1s = 0;
SR = 0;
JR = 0;
}
}
六、实验效果
七、资料内容