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

目录

前言:

项目效果演示:

一、简介

二、硬件需求准备

三、硬件框图

四、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和passwordHAL_Delay(5000);printf("AT+MQTTCLIENTID=0,\"%s\"\r\n",CLIENTID);	//设置CLIENTIDHAL_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.mzph.cn/bicheng/69299.shtml

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

相关文章

游戏与硬件深度协同,打造更精细的体验优化

高画质的游戏往往带来手机的发热和卡顿从而影响游戏体验。开发者希望能够获取到手机运行的实时状态&#xff0c;从而能够进行主动的负载调节&#xff0c;将手机发热时游戏体验影响降到最低&#xff1b;同时手机也可以通过游戏传入的关键场景如"正在下载资源"“团战中…

14-7C++STL的stack容器

&#xff08;一&#xff09;stack容器的入栈与出栈 &#xff08;1&#xff09;stack容器的简介 stack堆栈容器&#xff0c;“先进后出”的容器&#xff0c;且stack没有迭代器 &#xff08;2&#xff09;stack对象的默认构造 stack采用模板类实现&#xff0c;stack对象的默认…

Python从0到100(八十五):神经网络-使用迁移学习完成猫狗分类

前言: 零基础学Python:Python从0到100最新最全教程。 想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Python爬虫、Web开发、 计算机视觉、机器学习、神经网络以及人工智能…

C动态库的生成与在Python和QT中的调用方法

目录 一、动态库生成 1&#xff09;C语言生成动态库 2&#xff09;c类生成动态库 二、动态库调用 1&#xff09;Python调用DLL 2&#xff09;QT调用DLL 三、存在的一些问题 1&#xff09;python调用封装了类的DLL可能调用不成功 2&#xff09;DLL格式不匹配的问题 四、…

flutter_学习记录_00_环境搭建

1.参考文档 Mac端Flutter的环境配置看这一篇就够了 flutter的中文官方文档 2. 本人环境搭建的背景 本人的电脑的是Mac的&#xff0c;iOS开发&#xff0c;所以iOS开发环境本身是可用的&#xff1b;外加Mac电脑本身就会配置Java的环境。所以&#xff0c;后面剩下的就是&#x…

arcgis短整型变为长整型的处理方式

1.用QGIS的重构字段工具进行修改&#xff0c;亲测比arcgis的更改字段工具有用 2.更换低版本的arcgis10.2.2&#xff0c;亲测10.5和10.6都有这个毛病&#xff0c;虽然官方文档里面说的是10.6.1及以上 Arcgis10.2.2百度链接&#xff1a;https://pan.baidu.com/s/1HYTwgnBJsBug…

H2 Database安装部署

H2 Database H2 Database官网 H2 中文文档 安装部署H2 java版本要高于java 11 ## 下载java21 wget https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.tar.gz[rootlocalhost ~]# tar xf jdk-21_linux-x64_bin.tar.gz -C /usr/local/ [rootlocalhost ~]# vi…

回首2024,展望2025

2024年&#xff0c;是个充满挑战与惊喜的年份。在这366个日夜里&#xff0c;我站在编程与博客的交汇点&#xff0c;穿越了无数的风景与挑战&#xff0c;也迎来了自我成长的丰收时刻。作为开发者的第十年&#xff0c;我依然步伐坚定&#xff0c;心中始终带着对知识的渴望与对自我…

工具的应用——安装copilot

一、介绍Copilot copilot是一个AI辅助编程的助手&#xff0c;作为需要拥抱AI的程序员可以从此尝试进入&#xff0c;至于好与不好&#xff0c;应当是小马过河&#xff0c;各有各的心得。这里不做评述。重点在安装copilot的过程中遇到了一些问题&#xff0c;然后把它总结下&…

w181乐享田园系统的设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

python实战(十五)——中文手写体数字图像CNN分类

一、任务背景 本次python实战&#xff0c;我们使用来自Kaggle的数据集《Chinese MNIST》进行CNN分类建模&#xff0c;不同于经典的MNIST数据集&#xff0c;我们这次使用的数据集是汉字手写体数字。除了常规的汉字“零”到“九”之外还多了“十”、“百”、“千”、“万”、“亿…

【深入理解FFMPEG】命令行阅读笔记

这里写自定义目录标题 第三章 FFmpeg工具使用基础3.1 ffmpeg常用命令3.1.13.1.3 转码流程 3.2 ffprobe 常用命令3.2.1 ffprobe常用参数3.2.2 ffprobe 使用示例 3.3 ffplay常用命令3.3.1 ffplay常用参数3.3.2 ffplay高级参数3.3.4 ffplay快捷键 第4章 封装与解封装4.1 视频文件转…

ORACLE-主备备-Failover

背景 随着业务的不断增涨,至使现有的单节点DG环境的连接已经无法满足当前业务需求,并且随着业务的重要性,同时也要求数据库的高可用性,减少数据库故障对业务的影响。于是规划迁移方案。 迁移方案如下: 因PRIMARY库本地磁盘空间已达到80%决定弃用,搭建高可用2个节点的RAC做…

OpenEuler学习笔记(十):用OpenEuler搭建web服务器

以下是在OpenEuler系统上搭建Web服务器的详细步骤&#xff0c;这里以常见的Nginx为例。 1. 系统更新 在进行任何操作之前&#xff0c;最好先更新系统的软件包&#xff0c;确保系统是最新的状态。 sudo dnf update -y2. 安装Nginx 可以使用OpenEuler的软件包管理器dnf来安装…

【C语言系列】深入理解指针(4)

深入理解指针&#xff08;4&#xff09; 一、回调函数是什么&#xff1f;二、qsort使用举例2.1使用qsort函数排序整型数据2.2使用qsort排序结构数据 三、qsort函数的模拟实现四、总结 一、回调函数是什么&#xff1f; 回调函数就是一个通过函数指针调用的函数。 如果你把函数的…

vim的多文件操作

[rootxxx ~]# vim aa.txt bb.txt cc.txt #多文件操作 next #下一个文件 prev #上一个文件 first #第一个文件 last #最后一个文件 快捷键: ctrlshift^ #当前和上个之间切换 说明&#xff1a;快捷键ctrlshift^&#xff0c…

解决CentOS9系统下Zabbix 7.2图形中文字符乱码问题

操作系统&#xff1a;CentOS 9 Zabbix版本&#xff1a;Zabbix7.2 问题描述&#xff1a;主机图形中文字符乱码 解决方案&#xff1a; # 安装字体配置和中文语言包 sudo yum install -y fontconfig langpacks-zh_CN.noarch # 检查是否已有中文字体&#xff1a; fc-list :lan…

[SUCTF 2018]MultiSQL1

进去题目页面如下 发现可能注入点只有登录和注册,那么我们先注册一个用户&#xff0c;发现跳转到了/user/user.php&#xff0c; 查看用户信息,发现有传参/user/user.php?id1 用?id1 and 11,和?id1 and 12,判断为数字型注入 原本以为是简单的数字型注入&#xff0c;看到大…

计算机视觉-卷积

卷积-图像去噪 一、图像 二进制 灰度 彩色 1.1二进制图像 0 1 一个点可以用一个bit&#xff08;0/1&#xff09;来表示 1.2灰度图像 0-255 一个点可以用一个byte来表示 1.3彩色图像 RGB 表达一个彩色图像先说它的分辨率p/w&#xff08;宽&#xff09;和q/h&#xff08;高…

mybatis(78/134)

前天学了很多&#xff0c;关于java的反射机制&#xff0c;其实跳过了new对象&#xff0c;然后底层生成了字节码&#xff0c;创建了对应的编码。手搓了一遍源码&#xff0c;还是比较复杂的。 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE …