基于STM32的阿里云智能农业大棚

news2025/1/29 13:57:49

目录

前言:

项目效果演示:

一、简介

二、硬件需求准备

三、硬件框图

四、CubeMX配置

4.1、按键、蜂鸣器GPIO口配置

4.2、ADC输入配置

4.3、IIC——驱动OLED

4.4、DHT11温湿度读取

4.5、PWM配置——光照灯、水泵、风扇

4.6、串口——esp8266模块

4.7、定时器配置——按键消抖所需

五、部分代码实现思路

5.1、菜单实现思路

5.2、OLED驱动

5.3、按键消抖

5.4、DHT11温湿度驱动

5.5、光照强度、土壤湿度ADC转换

5.6、esp8266连接阿里云

六、功能拓展


前言:

注意事项:本项目使用的是u8g2库进行显示驱动OLED,需要学会移植或者直接使用我的模板,具体可以看我的这个博文:手把手移植基于STM移植U8g2图形库教程——0.96寸OLED(附送整理资料)

买来的esp8266模可能不支持连接阿里云,需要烧写MQTT固件,具体操作可以看看我的这个博文:手把手连接阿里云教程

里面都会有所需的固件和工具和教程!

项目效果演示:

智能农业大棚

一、简介

这可以作为一个简单的课设或者用来水毕设的一个小项目,总体来说挺简单的,我做完后就打算开源出来大家一起学习一下,具体功能如下:

1、按键:

      按键一:切换菜单

      按键二:切换选项

      按键三:+-或调节风扇 | 水泵 | 灯光

      按键四:确认 | 连接阿里云平台

2、液晶屏幕显示:

     菜单1:主界面显示空气温湿度,土壤湿度,光照强度,检测是否超过或低于临界值

     菜单2:临界值调节

     菜单3:风扇手动开关

     菜单4:灯光手动开关

     菜单5:水泵手动开关

     菜单6:阿里云连接菜单界面

3、土壤湿度、空气温湿度、光照强度高于或低于临界值,蜂鸣器就会响

4、土壤湿度过低自动打开水泵

5、光照强度过低自动打开照明灯

6、空气温度过高会自动打开风扇

7、连接阿里云平台,可以在电脑上面查看各个数据

二、硬件需求准备

1、STM32F103最小核心开发板

2、0.96寸OLED屏幕

3、按键X4

4、TB6612FNG点击驱动模块

5、水泵

6、电机(带小风扇)

7、DHT11温湿度模块

8、esp8266模块

9、蜂鸣器

10、土壤湿度传感器

11、光照强度传感器

12、照明灯模块

三、硬件框图

四、CubeMX配置

这里只演示配置使用的外设配置过程!

4.1、按键、蜂鸣器GPIO口配置

按键配置为上拉模式、蜂鸣器低电平输出有效

  4.2、ADC输入配置

ADC为读取土壤湿度和光照强度的ADC数值,这里开启两个ADC分别读取

ADC1——读取土壤湿度:

ADC2——读取光照强度:

4.3、IIC——驱动OLED

4.4、DHT11温湿度读取

这个使用过程中会对弈随意变动上下拉模式,所以这里就不配置了,使用的GPIO口为PB8

4.5、PWM配置——光照灯、水泵、风扇

4.6、串口——esp8266模块

开启中断:

4.7、定时器配置——按键消抖所需

开启中断:

最后生成工程即可。

五、部分代码实现思路

5.1、菜单实现思路

最常用的就是菜单索引法还有链表法,我这里菜单结构非常简单,所以我就使用索引法了,这里简单说一下,就是每一个菜单都对应一个结构体((这个项目没有二级界面,所以用不到进入索引和返回索引)):

typedef struct
{
	int current_index;//当前索引
	int last_index;   //下一索引
	int enter_index;  //进入索引
	int back_index;   //返回索引
	void(*current)(u8g2_t u8g2);
	
}Menu;

结构体成员包括以上的几个。

这个小项目有5个菜单页面:所以定义5个结构体(这个项目没有二级界面,所以用不到进入索引和返回索引):

Menu Menu_Table[30] = 
{
// 当 下 进 返
	{0, 1, 0, 0,(*Home_Menu)}, //主页显示界面
	{1, 2, 0, 0,(*Set_Menu)},  //设置临界值界面
	{2, 3, 0, 0,(*Fan_Menu)},  //风扇控制界面
	{3, 4, 0, 0,(*Light_Menu)},//灯光控制界面
	{4, 5, 0, 0,(*Water_Menu)},//水泵控制界面
	{5, 0, 0, 0,(*Wifi_Menu)},//连接阿里云控制界面
	
};

然后定义一个当前显示菜单的索引值和当前菜单显示绘制函数:

int Current_Menu_index = 0;//当前菜单索引
void(*Current)(u8g2_t u8g2);//当前菜单索引执行绘制函数

然后初始化好按键,按下后执行跳转:

切换下一菜单使用例子(如果是其他的可以八next换成其他的结构体成员):

Current_Menu_index = Menu_Table[Current_Menu_index].last_index;//变换索引值

Current = Menu_Table[Current_Menu_index].current;//函数复制
(*Current)(u8g2);//执行绘制函数

在举一个例子帮助大家理解一下,比如,我们当前程序处在索引号为2(临界值界面),就会执行Set_Menu函数。此时,如果按下next按键,程序当前索引号就会变为3,并且执行索引号为3时候的Fan_Menu函数。以此类推!

5.2、OLED驱动

这里我是使用开源的u8g2库进行开发,这个库显示效果很好,而且也很好移植!具体可以参考我的这个博文:移植u8g2库,移植成功后使用也可以看看我的另外要给博文:u8g2库函数使用

5.3、按键消抖

我这里使用的是中断消抖:

unsigned char Key_PIN_Read()
{
  unsigned char Temp=0;
	
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET)   Temp = 1;
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_13) == GPIO_PIN_RESET)   Temp = 2;
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14) == GPIO_PIN_RESET)   Temp = 3;
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_15) == GPIO_PIN_RESET)   Temp = 4;

	
	return Temp;


} 


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)              //中断回调函数
{
	Key_Slow++;
	if(Key_Slow == 10)  Key_Slow = 0;//按键消抖
}


void Key_Pro()
{
	
	if(Key_Slow) return;//按键减速
	Key_Slow=1;
	
	Key_Val=Key_PIN_Read();
	Key_Down=Key_Val & (Key_Val ^ Key_Old);//捕捉下降沿
	Key_Up = ~Key_Val & (Key_Old ^ Key_Val);//捕捉按键上降沿
	Key_Old=Key_Val;
	
	
	switch(Key_Up)
    {

       case 1:

       break;

       case 2:

       break;

       case 3:

       break;

       case 4:

       break;

    }


}

5.4、DHT11温湿度驱动

手动配置GPIO模式:

#define DHT_HIGHT HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET)
#define DHT_LOW HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET)
#define DHT_VALUE HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8)


uint8_t datas[5];//空气温湿度数据

void delay_us(uint16_t cnt)
{
	uint8_t i;
	while(cnt)
	{
		for (i = 0; i < 10; i++)
		{
			
		}	
		cnt--;
	}
}

void DHT_GPIO_Init(uint32_t Mode)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	__HAL_RCC_GPIOB_CLK_ENABLE();
	
	GPIO_InitStruct.Pin = GPIO_PIN_8;
	GPIO_InitStruct.Mode = Mode;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void DHT11_Start(void)
{
	DHT_GPIO_Init(GPIO_MODE_OUTPUT_PP);
	DHT_HIGHT;
	DHT_LOW;
	HAL_Delay(30);
	DHT_HIGHT;
	
	DHT_GPIO_Init(GPIO_MODE_INPUT);
	while(DHT_VALUE);
	while(!DHT_VALUE);
	while(DHT_VALUE);
}


void Read_Data_From_DHT()
{
	int i;//轮
	int j;//每一轮读多少次
	char tmp;
	char flag;
	DHT11_Start();
	DHT_GPIO_Init(GPIO_MODE_INPUT);
	for(i= 0;i < 5;i++)
	{
		for(j=0;j<8;j++)
		{
			while(!DHT_VALUE);//等待卡g点
			delay_us(40);
			if(DHT_VALUE == 1)
			{
				flag = 1;
				while(DHT_VALUE);
			}
			else
			{
				flag = 0;
			}
			tmp = tmp << 1;
			tmp |= flag;
		}
		datas[i] = tmp;
	}
}

数据显示以及文字显示:

void Printf_DHT11(u8g2_t u8g2,u8g2_uint_t x, u8g2_uint_t y, const uint8_t *font)
{
	char var_buf[100];
	char var_buf1[100];
	
	Read_Data_From_DHT();//读取温湿度数据
	
	u8g2_DrawXBMP(&u8g2, x, y, 16, 16, kong);
	u8g2_DrawXBMP(&u8g2, x+16, y, 16, 16, qi);
	u8g2_DrawXBMP(&u8g2, x+32, y, 16, 16, wen);
	u8g2_DrawXBMP(&u8g2, x+48, y, 16, 16, du);
	u8g2_DrawXBMP(&u8g2, x, y+16, 16, 16, kong);
	u8g2_DrawXBMP(&u8g2, x+16, y+16, 16, 16, qi);
	u8g2_DrawXBMP(&u8g2, x+32, y+16, 16, 16, wen);
	u8g2_DrawXBMP(&u8g2, x+48, y+16, 16, 16, du);
	
	sprintf(var_buf , ": %d.%d C",datas[2],datas[3]);
	sprintf(var_buf1, ": %d.%d",datas[0],datas[1]);
	u8g2_SetFont(&u8g2, font);
	u8g2_DrawStr(&u8g2, x+64, y+16, var_buf);
  u8g2_DrawStr(&u8g2, x+64, y+32, var_buf1);
}

5.5、光照强度、土壤湿度ADC转换

int Printf_Soil(u8g2_t u8g2,u8g2_uint_t x, u8g2_uint_t y, const uint8_t *font)
{
	char var[100];
	int value;
	
	
	HAL_ADC_Start(&hadc1); //启动ADC单次转换
	HAL_ADC_PollForConversion(&hadc1, 50); //等待ADC转换完成
	value = HAL_ADC_GetValue(&hadc1); //读取ADC转换数据
	value = 100 - value * 100 / 4096;
//	Soil  = value;
	
	u8g2_DrawXBMP(&u8g2, x, y, 16, 16, tu);
	u8g2_DrawXBMP(&u8g2, x+16, y, 16, 16, rang);
	u8g2_DrawXBMP(&u8g2, x+32, y, 16, 16, shi);
	u8g2_DrawXBMP(&u8g2, x+48, y, 16, 16, du);
	
	sprintf(var , ": %d %%", value);
	u8g2_SetFont(&u8g2, font);
	u8g2_DrawStr(&u8g2, x+64, y+16, var);
	
	return value;
	
}



int Printf_Light(u8g2_t u8g2,u8g2_uint_t x, u8g2_uint_t y, const uint8_t *font)
{
	char var[100];
	int value;
	
	
	HAL_ADC_Start(&hadc2); //启动ADC单次转换
	HAL_ADC_PollForConversion(&hadc2, 50); //等待ADC转换完成
	value = HAL_ADC_GetValue(&hadc2); //读取ADC转换数据
	value = 100 - value * 100 / 4096;
//	Light = value;
	
	u8g2_DrawXBMP(&u8g2, x, y, 16, 16, guang);
	u8g2_DrawXBMP(&u8g2, x+16, y, 16, 16, zhao);
	u8g2_DrawXBMP(&u8g2, x+32, y, 16, 16, qiang);
	u8g2_DrawXBMP(&u8g2, x+48, y, 16, 16, du);
	
	sprintf(var , ": %d %%", value);
	u8g2_SetFont(&u8g2, font);
	u8g2_DrawStr(&u8g2, x+64, y+16, var);
	
	return value;
	
}

5.6、esp8266连接阿里云

这里我为了保险起见就是用了很多的延迟时间(连接时间过长),你们可以自己调节时间!

#define USERNAME   "test&k28qfTAtkBg" //用户名
//                 "test&k28qfTAtkBg"
#define PASSWORD   "d7c3b27a5d8ca954487de1e1946a4a08439a2c2508242268e9d90ce178178f39" //密码
//                 "d7c3b27a5d8ca954487de1e1946a4a08439a2c2508242268e9d90ce178178f39"
#define CLIENTID   "k28qfTAtkBg.test|securemode=2\\,signmethod=hmacsha256\\,timestamp=1736673123047|" //设备名称
//                 "k28qfTAtkBg.test|securemode=2\\,signmethod=hmacsha256\\,timestamp=1736673123047|"
#define PRODUCTID  "k28qfTAtkBg" //产品ID
//                 "k28qfTAtkBg"
#define DOMAINNAME "iot-06z00fj5kcoes6j.mqtt.iothub.aliyuncs.com" //域名
//                 "iot-06z00fj5kcoes6j.mqtt.iothub.aliyuncs.com"
#define DEVICENAME "test"


//WiFi连接函数
void Wifi_Connect()
{
	printf("AT\r\n");//避免报错
	HAL_Delay(500);
	
	printf("AT+RESTORE\r\n");//恢复出厂
	HAL_Delay(5000);

	
//	printf("AT+RST\r\n");//复位
//	HAL_Delay(5000);
	printf("ATE0\r\n");//关闭回显
	HAL_Delay(5000);
	printf("AT+CWMODE=3\r\n");//设置双模式
	HAL_Delay(5000);
	printf("AT+CWJAP=\"USER_E191B0\",\"98599714\"\r\n");//设置WIFI密码和账号
	HAL_Delay(5000);
	printf("AT+MQTTUSERCFG=0,1,\"NULL\",\"%s\",\"%s\",0,0,\"\"\r\n",USERNAME,PASSWORD);//设置MQTT的username和password
	HAL_Delay(5000);
	printf("AT+MQTTCLIENTID=0,\"%s\"\r\n",CLIENTID);	//设置CLIENTID
	HAL_Delay(5000);
	printf("AT+MQTTCONN=0,\"%s\",1883,1\r\n",DOMAINNAME);//设置域名
	HAL_Delay(5000);
	printf("AT+MQTTSUB=0,\"/%s/%s/user/get\",1\r\n",PRODUCTID,DEVICENAME);//订阅

}

六、功能拓展

后续拓展:

1、电脑阿里云平台控制单片机

2、添加语音模块

。。。。。。。。。。。。其他

后续打了PCB板子后有空会实现给大家,觉得有帮助的可以点点关注!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WGCLOUD使用介绍 - 如何监控ActiveMQ和RabbitMQ

根据WGCLOUD官网的信息&#xff0c;目前没有针对ActiveMQ和RabbitMQ这两个组件专门做适配 不过可以使用WGCLOUD已经具备的通用监测模块&#xff1a;进程监测、端口监测或者日志监测、接口监测 来对这两个组件进行监控

Win11画图工具没了怎么重新安装

有些朋友想要简单地把图片另存为其他格式&#xff0c;或是进行一些编辑&#xff0c;但是发现自己的Win11系统里面没有画图工具&#xff0c;这可能是因为用户安装的是精简版的Win11系统&#xff0c;解决方法自然是重新安装一下画图工具&#xff0c;具体应该怎么做呢&#xff1f;…

“AI质量评估系统:智能守护,让品质无忧

嘿&#xff0c;各位小伙伴们&#xff01;今天咱们来聊聊一个在现代社会中越来越重要的角色——AI质量评估系统。你知道吗&#xff1f;在这个快速发展的时代&#xff0c;产品质量已经成为企业生存和发展的关键。而AI质量评估系统&#xff0c;就像是我们的智能守护神&#xff0c;…

Ubuntu 顶部状态栏 配置,gnu扩展程序

顶部状态栏 默认没有配置、隐藏的地方 安装使用Hide Top Bar 或Just Perfection等进行配置 1 安装 sudo apt install gnome-shell-extension-manager2 打开 安装的“扩展管理器” 3. 对顶部状态栏进行配置 使用Hide Top Bar 智能隐藏&#xff0c;或者使用Just Perfection 直…

FPGA 使用 CLOCK_LOW_FANOUT 约束

使用 CLOCK_LOW_FANOUT 约束 您可以使用 CLOCK_LOW_FANOUT 约束在单个时钟区域中包含时钟缓存负载。在由全局时钟缓存直接驱动的时钟网段 上对 CLOCK_LOW_FANOUT 进行设置&#xff0c;而且全局时钟缓存扇出必须低于 2000 个负载。 注释&#xff1a; 当与其他时钟约束配合…

RabbitMQ模块新增消息转换器

文章目录 1.目录结构2.代码1.pom.xml 排除logging2.RabbitMQConfig.java3.RabbitMQAutoConfiguration.java 1.目录结构 2.代码 1.pom.xml 排除logging <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/PO…

机器学习:支持向量机

支持向量机&#xff08;Support Vector Machine&#xff09;是一种二类分类模型&#xff0c;其基本模型定义为特征空间上的间隔最大的广义线性分类器&#xff0c;其学习策略便是间隔最大化&#xff0c;最终可转化为一个凸二次规划问题的求解。 假设两类数据可以被 H x : w T x…

Spring Boot(6)解决ruoyi框架连续快速发送post请求时,弹出“数据正在处理,请勿重复提交”提醒的问题

一、整个前言 在基于 Ruoyi 框架进行系统开发的过程中&#xff0c;我们常常会遇到各种有趣且具有挑战性的问题。今天&#xff0c;我们就来深入探讨一个在实际开发中较为常见的问题&#xff1a;当连续快速发送 Post 请求时&#xff0c;前端会弹出 “数据正在处理&#xff0c;请…

2023年版本IDEA复制项目并修改端口号和运行内存

2023年版本IDEA复制项目并修改端口号和运行内存 1 在idea中打开server面板&#xff0c;在server面板中选择需要复制的项目右键&#xff0c;点击弹出来的”复制配置…&#xff08;Edit Configuration…&#xff09;“。如果idea上没有server面板或者有server面板但没有springbo…

微信小程序怎么制作自己的小程序?手把手带你入门(适合新手小白观看)

对于初学者来说&#xff0c;制作一款微信小程序总感觉高大上&#xff0c;又害怕学不会。不过&#xff0c;今天我就用最简单、最有耐心的方式&#xff0c;一步一步给大家讲清楚!让你知道微信小程序的制作&#xff0c;居然可以这么轻松(希望你别吓跑啊!)。文中还加了实战经验&…

EventBus事件总线的使用以及优缺点

EventBus EventBus &#xff08;事件总线&#xff09;是一种组件通信方法&#xff0c;基于发布/订阅模式&#xff0c;能够实现业务代码解耦&#xff0c;提高开发效率 发布/订阅模式 发布/订阅模式是一种设计模式&#xff0c;当一个对象的状态发生变化时&#xff0c;所有依赖…

vim如何设置自动缩进

:set autoindent 设置自动缩进 :set noautoindent 取消自动缩进 &#xff08;vim如何使设置自动缩进永久生效&#xff1a;vim如何使相关设置永久生效-CSDN博客&#xff09;

LongLoRA:高效扩展大语言模型上下文长度的微调方法

论文地址&#xff1a;https://arxiv.org/abs/2309.12307 github地址&#xff1a;https://github.com/dvlab-research/LongLoRA 1. 背景与挑战 大语言模型&#xff08;LLMs&#xff09;通常在预定义的上下文长度下进行训练&#xff0c;例如 LLaMA 的 2048 个 token 和 Llama2 的…

NoSQL使用详解

文章目录 NoSQL使用详解一、引言二、NoSQL数据库的基本概念三、NoSQL数据库的分类及使用场景1. 键值存储数据库示例代码&#xff08;Redis&#xff09;&#xff1a; 2. 文档存储数据库示例代码&#xff08;MongoDB&#xff09;&#xff1a; 3. 列存储数据库4. 图数据库 四、使用…

《FreqMamba: 从频率角度审视图像去雨问题》学习笔记

paper&#xff1a;FreqMamba: Viewing Mamba from a Frequency Perspective for Image Deraining GitHub&#xff1a;GitHub - aSleepyTree/FreqMamba 目录 摘要 1、介绍 2、相关工作 2.1 图像去雨 2.2 频率分析 2.3 状态空间模型 3、方法 3.1 动机 3.2 预备知识 3…

试用ChatGPT开发一个大语言模型聊天App

参考官方文档&#xff0c;安装android studio https://developer.android.com/studio/install?hlzh-cn 参考这个添加permission权限&#xff1a; https://blog.csdn.net/qingye_love/article/details/14452863 参考下面链接完成Android Studio 给项目添加 gradle 依赖 ht…

第30周:文献阅读

目录 摘要 Abstract 文献阅读 问题引入 方法论 堆叠集成模型 深度学习模型 创新点 堆叠模型 敏感性和不确定性分析 优化模型 实验研究 数据集 水质指数WQI的计算 模型的构建与训练 模型性能评估 敏感性和不确定性分析 结论 摘要 本文聚焦于利用深度学习算…

The just sharing principle: advice for advice givers

原文 A while ago I wrote about how Only you know what’s best for your application. That’s because only you fully understand the context within which you are making technical decisions. Any advice need to filtered through that context in order to determi…

【PVE】PVE部署磁盘阵列

什么是磁盘阵列&#xff1f; 磁盘阵列是一种存储技术&#xff0c;通过将多个物理磁盘组合成一个逻辑存储单元&#xff0c;提供数据冗余和/或性能提升。它的核心目的是提高数据的可靠性、可用性和访问速度。磁盘阵列可以由专用硬件或软件实现。 PVE部署磁盘阵列并加入虚拟机 …

FlinkSql使用中rank/dense_rank函数报错空指针

问题描述 在flink1.16(甚至以前的版本)中&#xff0c;使用rank()或者dense_rank()进行排序时&#xff0c;某些场景会导致报错空指针NPE(NullPointerError) 报错内容如下 该报错没有行号/错误位置&#xff0c;无法排查 现状 目前已经确认为bug&#xff0c;根据github上的PR日…