本项目使用Proteus8仿真STM32单片机控制器,使用OLED显示模块、红外传感器、蜂鸣器、DS18B20温度传感器,风扇LED、语音识别模块等。
主要功能:
系统运行后,OLED显示动画效果,一段时间后静止。当到达指定时间时开启闹钟,系统需感应到有人后,此时可通过K4键或语音关闭闹铃。系统感应到有人后,OLED显示测量的人体体温、时间、LED和风扇的开关状态;此时可通过语音开关LED和风扇;可通过按键K3进入闹钟设置界面,通过K3键切换不同时间位置,K1和K2键加减调节,设置后按下K4键保存并退出,返回测温和时钟显示界面。
语音识别指令(十六进制数):
开灯–>0X01
关灯–>0X02
开风扇–>0X11
关风扇–>0X12
关闹铃–>0X22
/*
作者:嗨小易(QQ:3443792007)
*/
//系统数据获取
void sys_data_get(void)
{
static u8 i=0;
static u8 oneflag=1;
while(1)
{
//人体红外检测
if(IRED==0)
{
//温度获取
i++;
if(i%1==0)
{
TIM_Cmd(TIM2,DISABLE); //关闭定时器
sys_ctrl.temp=DS18B20_GetTemperture()*10;
TIM_Cmd(TIM2,ENABLE); //打开定时器
}
sys_ctrl.man=1;
}
else sys_ctrl.man=0;
//界面状态显示
if(sys_ctrl.man==0)
{
sys_ctrl.window=0;
if(oneflag==0)
{
oneflag=1;
sys_open_show();//系统开机界面显示
}
}
else
{
sys_ctrl.window=1;
if(oneflag==1)
{
oneflag=0;
sys_parm_show();//系统数据参数显示界面
}
}
break;
}
}
//系统数据显示
void sys_data_show(void)
{
u8 buf[9];
while(1)
{
//显示数据界面
if(sys_ctrl.window==1)
{
//正常模式下
if(sys_ctrl.mode==0)
{
//温度显示
buf[0]=sys_ctrl.temp/100+0x30;
buf[1]=sys_ctrl.temp%100/10+0x30;
buf[2]='.';
buf[3]=sys_ctrl.temp%100%10+0x30;
buf[4]='C';
buf[5]='\0';
OLED_ShowString(3*16,0,buf,16);
//时间显示
buf[0]=sys_ctrl.hour/10+0x30;
buf[1]=sys_ctrl.hour%10+0x30;
buf[2]=':';
buf[3]=sys_ctrl.min/10+0x30;
buf[4]=sys_ctrl.min%10+0x30;
buf[5]=':';
buf[6]=sys_ctrl.sec/10+0x30;
buf[7]=sys_ctrl.sec%10+0x30;
buf[8]='\0';
OLED_ShowString(3*16,2,buf,16);
//灯状态显示
if(sys_ctrl.led==1)OLED_ShowString(2*16,4,"ON ",16);
else OLED_ShowString(2*16,4,"OFF",16);
//风扇状态显示
if(sys_ctrl.motor==1)OLED_ShowString(6*16+8*1,4,"ON ",16);
else OLED_ShowString(6*16+8*1,4,"OFF",16);
}
//时间设置模式下
else
{
//吃药时间显示
buf[0]=sys_ctrl.stime[0][0]/10+0x30;
buf[1]=sys_ctrl.stime[0][0]%10+0x30;
buf[2]=':';
buf[3]=sys_ctrl.stime[0][1]/10+0x30;
buf[4]=sys_ctrl.stime[0][1]%10+0x30;
buf[5]=':';
buf[6]=sys_ctrl.stime[0][2]/10+0x30;
buf[7]=sys_ctrl.stime[0][2]%10+0x30;
buf[8]='\0';
OLED_ShowString(3*16,0,buf,16);
//运动时间显示
buf[0]=sys_ctrl.stime[1][0]/10+0x30;
buf[1]=sys_ctrl.stime[1][0]%10+0x30;
buf[2]=':';
buf[3]=sys_ctrl.stime[1][1]/10+0x30;
buf[4]=sys_ctrl.stime[1][1]%10+0x30;
buf[5]=':';
buf[6]=sys_ctrl.stime[1][2]/10+0x30;
buf[7]=sys_ctrl.stime[1][2]%10+0x30;
buf[8]='\0';
OLED_ShowString(3*16,3,buf,16);
//休息时间显示
buf[0]=sys_ctrl.stime[2][0]/10+0x30;
buf[1]=sys_ctrl.stime[2][0]%10+0x30;
buf[2]=':';
buf[3]=sys_ctrl.stime[2][1]/10+0x30;
buf[4]=sys_ctrl.stime[2][1]%10+0x30;
buf[5]=':';
buf[6]=sys_ctrl.stime[2][2]/10+0x30;
buf[7]=sys_ctrl.stime[2][2]%10+0x30;
buf[8]='\0';
OLED_ShowString(3*16,6,buf,16);
switch(sys_ctrl.mode)
{
case 1://吃药-时
OLED_ShowString(3*16,0," ",16);
delay_ms(50);
buf[0]=sys_ctrl.stime[0][0]/10+0x30;
buf[1]=sys_ctrl.stime[0][0]%10+0x30;
buf[2]='\0';
OLED_ShowString(3*16,0,buf,16);
break;
case 2://吃药-分
OLED_ShowString(3*16+3*8,0," ",16);
delay_ms(50);
buf[0]=sys_ctrl.stime[0][1]/10+0x30;
buf[1]=sys_ctrl.stime[0][1]%10+0x30;
buf[2]='\0';
OLED_ShowString(3*16+3*8,0,buf,16);
break;
case 3://吃药-秒
OLED_ShowString(3*16+6*8,0," ",16);
delay_ms(50);
buf[0]=sys_ctrl.stime[0][2]/10+0x30;
buf[1]=sys_ctrl.stime[0][2]%10+0x30;
buf[2]='\0';
OLED_ShowString(3*16+6*8,0,buf,16);
break;
case 4://运动-时
OLED_ShowString(3*16,3," ",16);
delay_ms(50);
buf[0]=sys_ctrl.stime[1][0]/10+0x30;
buf[1]=sys_ctrl.stime[1][0]%10+0x30;
buf[2]='\0';
OLED_ShowString(3*16,3,buf,16);
break;
case 5://运动-分
OLED_ShowString(3*16+3*8,3," ",16);
delay_ms(50);
buf[0]=sys_ctrl.stime[1][1]/10+0x30;
buf[1]=sys_ctrl.stime[1][1]%10+0x30;
buf[2]='\0';
OLED_ShowString(3*16+3*8,3,buf,16);
break;
case 6://运动-秒
OLED_ShowString(3*16+6*8,3," ",16);
delay_ms(50);
buf[0]=sys_ctrl.stime[1][2]/10+0x30;
buf[1]=sys_ctrl.stime[1][2]%10+0x30;
buf[2]='\0';
OLED_ShowString(3*16+6*8,3,buf,16);
break;
case 7://休息-时
OLED_ShowString(3*16,6," ",16);
delay_ms(50);
buf[0]=sys_ctrl.stime[2][0]/10+0x30;
buf[1]=sys_ctrl.stime[2][0]%10+0x30;
buf[2]='\0';
OLED_ShowString(3*16,6,buf,16);
break;
case 8://休息-分
OLED_ShowString(3*16+3*8,6," ",16);
delay_ms(50);
buf[0]=sys_ctrl.stime[2][1]/10+0x30;
buf[1]=sys_ctrl.stime[2][1]%10+0x30;
buf[2]='\0';
OLED_ShowString(3*16+3*8,6,buf,16);
break;
case 9://休息-秒
OLED_ShowString(3*16+6*8,6," ",16);
delay_ms(50);
buf[0]=sys_ctrl.stime[2][2]/10+0x30;
buf[1]=sys_ctrl.stime[2][2]%10+0x30;
buf[2]='\0';
OLED_ShowString(3*16+6*8,6,buf,16);
break;
}
}
}
break;
}
}
//系统数据设置
void sys_data_set(void)
{
u8 key=0;
static u8 oneflag=0;
//有人的时候
if(sys_ctrl.window==1)
{
key=KEY_Scan(1);
//语音识别
if(USART1_RX_BUF[0]==LED_ON_CMD)//开灯
{
USART1_RX_BUF[0]=0;
LED=0;
sys_ctrl.led=1;
}
else if(USART1_RX_BUF[0]==LED_OFF_CMD)//关灯
{
USART1_RX_BUF[0]=0;
LED=1;
sys_ctrl.led=0;
}
else if(USART1_RX_BUF[0]==MOTOR_ON_CMD)//开风扇
{
USART1_RX_BUF[0]=0;
MOTOR=0;
sys_ctrl.motor=1;
}
else if(USART1_RX_BUF[0]==MOTOR_OFF_CMD)//关风扇
{
USART1_RX_BUF[0]=0;
MOTOR=1;
sys_ctrl.motor=0;
}
else if(USART1_RX_BUF[0]==ALARM_OFF_CMD)//关闹铃
{
USART1_RX_BUF[0]=0;
sys_ctrl.alarm=0;
OLED_ShowString(0,6," ",16);
}
}
//模式设置
if(key==KEY3_PRESS)
{
sys_ctrl.mode++;
if(sys_ctrl.mode>9)sys_ctrl.mode=1;
if(oneflag==0)//时间设置界面仅显示1次
{
oneflag=1;
sys_time_set_show();//系统时间设置界面显示
}
}
//在设置模式下,加
else if(key==KEY1_PRESS)
{
switch(sys_ctrl.mode)
{
case 1://吃药-时
sys_ctrl.stime[0][0]++;
if(sys_ctrl.stime[0][0]>23)sys_ctrl.stime[0][0]=0;
break;
case 2://吃药-分
sys_ctrl.stime[0][1]++;
if(sys_ctrl.stime[0][1]>59)sys_ctrl.stime[0][1]=0;
break;
case 3://吃药-秒
sys_ctrl.stime[0][2]++;
if(sys_ctrl.stime[0][2]>59)sys_ctrl.stime[0][2]=0;
break;
case 4://运动-时
sys_ctrl.stime[1][0]++;
if(sys_ctrl.stime[1][0]>24)sys_ctrl.stime[1][0]=0;
break;
case 5://运动-分
sys_ctrl.stime[1][1]++;
if(sys_ctrl.stime[1][1]>59)sys_ctrl.stime[1][1]=0;
break;
case 6://运动-秒
sys_ctrl.stime[1][2]++;
if(sys_ctrl.stime[1][2]>59)sys_ctrl.stime[1][2]=0;
break;
case 7://休息-时
sys_ctrl.stime[2][0]++;
if(sys_ctrl.stime[2][0]>24)sys_ctrl.stime[2][0]=0;
break;
case 8://休息-分
sys_ctrl.stime[2][1]++;
if(sys_ctrl.stime[2][1]>59)sys_ctrl.stime[2][1]=0;
break;
case 9://休息-秒
sys_ctrl.stime[2][2]++;
if(sys_ctrl.stime[2][2]>59)sys_ctrl.stime[2][2]=0;
break;
}
}
//在设置模式下,减
else if(key==KEY2_PRESS)
{
switch(sys_ctrl.mode)
{
case 1://吃药-时
sys_ctrl.stime[0][0]--;
if(sys_ctrl.stime[0][0]<0)sys_ctrl.stime[0][0]=23;
break;
case 2://吃药-分
sys_ctrl.stime[0][1]--;
if(sys_ctrl.stime[0][1]<0)sys_ctrl.stime[0][1]=59;
break;
case 3://吃药-秒
sys_ctrl.stime[0][2]--;
if(sys_ctrl.stime[0][2]<0)sys_ctrl.stime[0][2]=59;
break;
case 4://运动-时
sys_ctrl.stime[1][0]--;
if(sys_ctrl.stime[1][0]<0)sys_ctrl.stime[1][0]=23;
break;
case 5://运动-分
sys_ctrl.stime[1][1]--;
if(sys_ctrl.stime[1][1]<0)sys_ctrl.stime[1][1]=59;
break;
case 6://运动-秒
sys_ctrl.stime[1][2]--;
if(sys_ctrl.stime[1][2]<0)sys_ctrl.stime[1][2]=59;
break;
case 7://休息-时
sys_ctrl.stime[2][0]--;
if(sys_ctrl.stime[2][0]<0)sys_ctrl.stime[2][0]=23;
break;
case 8://休息-分
sys_ctrl.stime[2][1]--;
if(sys_ctrl.stime[2][1]<0)sys_ctrl.stime[2][1]=59;
break;
case 9://休息-秒
sys_ctrl.stime[2][2]--;
if(sys_ctrl.stime[2][2]<0)sys_ctrl.stime[2][2]=59;
break;
}
}
//确定
else if(key==KEY4_PRESS)
{
if(oneflag==1)
{
sys_ctrl.mode=0;
oneflag=0;
sys_parm_show();//系统数据参数显示界面
}
//闹铃
if(sys_ctrl.alarm==1)
{
sys_ctrl.alarm=0;
OLED_ShowString(0,6," ",16);
}
}
}
//应用控制系统
void appdemo_show(void)
{
u8 i=10;
KEY_Init();
ctrl_pin_init();
BEEP_Init();
DS18B20_Init();
//等待温度数据稳定
while(i--)
{
sys_ctrl.temp=DS18B20_GetTemperture()*10;
delay_ms(100);
}
OLED_Init();
USART1_Init(9600);
printf("USART1_Init OK\r\n");
TIM2_Init(400-1,70);//定时10ms
sys_parm_init();//系统参数初始化
sys_open_show();//系统初始界面显示
TIM_Cmd(TIM2,ENABLE); //打开定时器
while(1)
{
sys_data_get();//系统数据获取
sys_data_show();//系统数据显示
sys_data_set();//系统数据设置
sys_fun_ctrl();//系统功能控制
}
}
B站演示视频:https://space.bilibili.com/444388619
视频地址:https://space.bilibili.com/444388619/video
专注于51单片机、STM32、国产32、DSP、Proteus、ardunio、ESP32、物联网软件开发,PCB设计,视频分享,技术交流。