【Proteus仿真】【STM32单片机】智能语音家居陪护机器人

文章目录

  • 一、功能简介
  • 二、软件设计
  • 三、实验现象
  • 联系作者


一、功能简介

本项目使用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设计,视频分享,技术交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/105570.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

“深入探讨操作系统和虚拟化技术“

目录 引言1.操作系统1.1.什么是操作系统1.2.常见操作系统1.3.个人版本和服务器版本的区别1.4.Linux的各个版本 2.安装VMWare虚拟机1.VMWare虚拟机介绍2.VMWare虚拟机安装3.VMWare虚拟机配置 3.安装配置Windows Server 2012 R24.完成电脑远程访问电脑5.服务器环境搭建配置jdk配置…

【k8s】kubeadm安装k8s集群

一、环境部署 master192.168.88.10docker、kubeadm、kubelet、kubectl、flannelnode01192.168.88.20docker、kubeadm、kubelet、kubectl、flannelnode02192.168.88.30docker、kubeadm、kubelet、kubectl、flannelhub.lp.com192.168.88.40 docker、docker-compose harbor-offli…

git合并错分支还原技巧

如果合并错了&#xff0c;但是还没有push&#xff0c;还原的简单粗暴的方式就是把合并后的分支删了。 本文主要讲的是git合并错分支并且已经push了的还原方式 比如&#xff1a;开发分支future_1&#xff0c;合并到项目组共同使用的分支develop上了&#xff0c;并且已经push了&…

2023高频前端面试题-http

1. HTTP有哪些⽅法&#xff1f; HTTP 1.0 标准中&#xff0c;定义了3种请求⽅法&#xff1a;GET、POST、HEAD HTTP 1.1 标准中&#xff0c;新增了请求⽅法&#xff1a;PUT、PATCH、DELETE、OPTIONS、TRACE、CONNECT 2. 各个HTTP方法的具体作用是什么&#xff1f; 方法功能G…

Babylonjs学习笔记(五)——创建PBR材质

书接上回&#xff0c;这里讨论PBR材质&#xff01;&#xff01;&#xff01; // 创建天空盒/* */const createSkyBox (scene:Scene):void>{const envTex CubeTexture.CreateFromPrefilteredData(./env/environment.env,scene)scene.environmentTexture envTex;scene.cre…

C++前缀和算法的应用:从栈中取出 K 个硬币的最大面值和 原理源码测试用例

本文涉及的基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 题目 一张桌子上总共有 n 个硬币 栈 。每个栈有 正整数 个带面值的硬币。 每一次操作中&#xff0c;你可以从任意一个栈的 顶部 取出 1 个硬币&#xff0c;从栈中移除…

python excel接口自动化测试框架

前言 前些天写了pytestyamlallure接口自动化测试框架这篇文章。 今天采用Excel继续写一个接口自动化测试框架。 设计流程图 这张图是我的excel接口测试框架的一些设计思路。 首先读取excel文件&#xff0c;得到测试信息&#xff0c;然后通过封装的requests方法&#xff0c…

C++数据结构X篇_21_插入排序(稳定的排序)

文章目录 1. 插入排序原理2. 算法图解3. 核心代码&#xff1a;4. 插入排序整体代码实现 1. 插入排序原理 插入排序是一种最简单直观的排序算法&#xff0c;它的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相…

线程间的调度顺序

目录 ♫join和sleep ♫wait ♫notify和notifyAll 我们知道线程是抢占式执行&#xff0c;随机调度的&#xff0c;而这也是诱发线程安全的根本原因。我们虽然无法指定线程之间的调度顺序&#xff0c;但是可以通过JVM提供的一些API让某个线程阻塞&#xff0c;主动放弃CPU&#xf…

【31】c++设计模式——>模板方法模式

模板方法模式通常由以下几个部分组成&#xff1a; 1.抽象基类&#xff08;Abstract Base Class&#xff09;&#xff1a;抽象基类定义了一个算法的骨架&#xff0c;其中包含了模板方法和一些基本操作方法。模板方法在抽象基类中被声明为虚函数&#xff0c;它定义了算法的流程&…

CentOS - 安装 Elasticsearch

"Elasticsearch"是一个流行的开源搜索和分析引擎&#xff0c;它可以用于实时搜索、日志和事件数据分析等任务。以下是在 CentOS 上安装 Elasticsearch 的基本步骤&#xff1a; 安装 Java&#xff1a; Elasticsearch 是基于 Java 的应用程序&#xff0c;所以首先需要…

openwrt下游设备在校园网(DLUT-LingShui)中使用ipv6网络

背景&#xff1a;校园网最多支持6台设备的无感认证&#xff0c;需要使用路由器(本人使用openwrt系统)为更多的设备提供网络&#xff0c;但校园网分配的ipv6地址子网为/128&#xff0c;不能为路由器下的设备分配全球ipv6地址&#xff0c;因此需要使用nat6转发下游设备的局域网ip…

el-table多选表格 实现默认选中 删除选中列表取消勾选等联动效果

实现效果如下&#xff1a; 代码如下&#xff1a; <template><div><el-tableref"multipleTable":data"tableData"tooltip-effect"dark"style"width: 100%"selection-change"handleSelectionChange"><…

Generative AI 新世界 | Falcon 40B 开源大模型的部署方式分析

在上期文章&#xff0c;我们探讨了如何在自定义数据集上来微调&#xff08;fine-tuned&#xff09;模型。本期文章&#xff0c;我们将重新回到文本生成的大模型部署场景&#xff0c;探讨如何在 Amazon SageMaker 上部署具有 400 亿参数的 Falcon 40B 开源大模型。 亚马逊云科技…

IC-705连接wfview

wfview是一款开源的主要针对ICOM的远程控制软件&#xff0c;可以通过USB或者无线控制电台&#xff0c;貌似还支持X6100。 IC-705支持WLAN功能&#xff0c;连接wfview非常方便。 IC-705的WLAN支持两种模式&#xff0c;一种是Station模式&#xff0c;可用于连接WI-FI路由器&#…

【考研数学】数学“背诵”手册 | 需要记忆且容易遗忘的知识点

文章目录 引言一、高数常见泰勒展开 n n n 阶导数公式多元微分函数连续、可微、连续可偏导之间的关系多元函数极值无条件极值条件极值 三角函数的积分性质华里士公式&#xff08; “点火”公式 &#xff09;特殊性质 原函数与被积函数的奇偶性结论球坐标变换公式 二、写在最后 …

python自动化测试(四):ECShop后台:商品分类添加

前置条件&#xff1a; 本地部署&#xff1a;ECShop的版本是3.0.0、Google版本是 Google Chrome65.0.3325.162 (正式版本) &#xff08;32 位&#xff09; Google驱动的selenium版本是3.11.0 目录 前置代码 一、登录&#xff08;后台登录&#xff09; 二、进入商品分类页…

JavaScript笔记(本文中将JavaScript简写为JS)

JS对大小写敏感 JS代码块的作用域都是全局的 JS的数组只能使用数字作为下标 JS对浮点型数据的精确度很难确定 JS在定义数组元素以及对象&#xff0c;在最后不能添加逗号 JS 中&#xff0c;变量可以在使用后声明&#xff0c;也就是变量可以先使用再声明&#xff0c;但不适用于已…

wkhtmltoimage/wkhtmltopdf 使用实践

1. 介绍 wkhtmltopdf/wkhtmltoimage 用于将简单的html页面转换为pdf或图片&#xff1b; 2.安装 downloads 2.1. mac os 下载64-bit 版本然后按照指示安装, 遇到 untrust developers 时&#xff0c;需要在 Settings -> Privacy 处信任下该安装包。 2.2. debian # 可用…

vscode代码快捷输入

Vscode代码片段快捷输入 常用的代码片段为了避免重复输入,可以使用Vsco的中用户代码片段进行设置,这样就可以实现快捷输入. 操作流程 如下 打开vscode的设置 2. 找到用户代码片段 3. 选择模板 4. 然后写入代码片段即可 上面的代码片段可以设置多个,看自己 重点关注的是 prefi…