Bootstrap

基于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和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板子后有空会实现给大家,觉得有帮助的可以点点关注!

;