摘要:目前,物联网技术已广泛应用到农业领域中,比如利用物联网技术来监测某种农作物的生长环境。对于杏鲍菇而言,它在不同生长阶段对环境温湿度、光照强度以及土壤湿度等因素有着严格的要求。然而,传统的栽培技术并不能精准调控杏鲍菇生长环境中各个参数,传统方式栽培的杏鲍菇产量和质量也不稳定。因此,本文针对菇农在栽培杏鲍菇的过程中,对栽培环境的调控不精准、不及时等问题,设计了一套智能化的杏鲍菇生长环境监测与控制系统来解决这些问题。该系统以STM32F103单片机作为主控制器,用DHT11、BH1750和土壤温湿度传感器分别采集杏鲍菇生长环境的温湿度、光照强度和土壤湿度。同时,采用ESP8266 Wi-Fi模块将这些传感器采集到的信息通过MQTT协议上传到OneNET进行显示,供用户查看。OneNET根据设定的参数阈值来对STM32下发控制指令,STM32接收并执行控制指令,控制水泵、遮阳板和热风机的执行状态,使其各项参数值处于适宜杏鲍菇生长和发育的范围内。实验结果表明,该系统可以有效地监测和控制杏鲍菇的生长环境,提高生产效率和质量。
关键词:杏鲍菇;环境监测与控制;STM32;OneNET
一、系统总体设计
本设计是一个基于STM32的杏鲍菇生长环境监测与控制系统,以STM32作为主控板,结合DHT11、BH1750和土壤湿度传感器采集杏鲍菇的生长环境数据,将采集的数据显示在OLED屏上。采用ESP8266模块将传感器获取的数据信息传输到云端,供用户查看。云端接收数据,并判断是否达到参数阈值,给STM32单片机发送控制指令,STM32接收并执行控制指令,根据控制指令改变水泵、遮阳板、热风机的状态。

二、硬件设计
1、主控制器
STM32微控制器是整个系统的核心,负责接收传感器的数据,执行控制算法,并与外部设备进行通信。STM32最小系统主要由单片机、晶振电路、复位电路、程序下载电路、启动模式配置电路和稳压模块组成。单片机是主要的中央处理器,外部晶振电路用于提供系统时钟,电源电路包括5V和3.3V两种稳压芯片,为单片机外围器件提供所需要的电压,复位电路可通过复位按键来确保系统的可靠启动,程序下载电路包括SWD调试接口和UART串口调试接口,用于芯片的调试和程序下载;启动模式配置是通过设置BOOT引脚的电平来选择模式的。STM32F103C8T6最小系统板电路原理图如图所示。

2、ESP-01S

3、DHT11

4、BH1750

5、土壤湿度监测模块

6、蜂鸣器报警模块

7、OLED显示屏

三、软件设计
1、系统程序流程图

2、主函数代码
`#include <string.h>
include "stm32f10x.h"
include "Common.h"
include "onenet.h"
include "MqttKit.h"
include "esp8266.h"
include "usart.h"
include "Buzzer.h"
include "DHT11.h"
include "Soil_humi.h"
include "BH1750.h"
include "SG90.h"
include "Machine.h"
include "Delay.h"
include "OLED.h"
unsigned short timeCount = 0;//控制数据上云的时间
//B6 绿 温度低于阈值 灯亮 接热风机则吹热风升温
//B7 红 土壤湿度低于阈值 灯亮 接抽水机则抽水
//
uint8_t air_humi, air_humi_th;
float soil_humi;
float soil_humi_th;
uint8_t light, light_th;
int8 temp;
int8 temp_th;
uint8_t buzzer = 0;
uint8_t wind = 0;
uint8_t water = 0;
uint8_t sg90 = 0;
int main(void)
{
//数据指针
unsigned char *dataPtr = NULL;
//阈值初始值
//温度小于阈值热风机工作 生长发育阶段为例子
temp_th = 25;
//空气湿度小于阈值蜂鸣器工作
air_humi_th = 35;
//光照强度大于阈值遮阳板遮阳
light_th = 150;
//土壤湿度小于阈值抽水机工作
soil_humi_th = 0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断控制器分组设置
//串口1,打印WiFi配网信息
Usart1_Init(115200);
//串口2,驱动WiFi模块
Usart2_Init(115200);
ESP8266_Init(); //初始化ESP8266
while(OneNet_DevLink()); //接入OneNET
Delay_ms(500);
OneNET_Subscribe();
Delay_ms(500);
//土壤湿度模块初始化
Soil_humi_Init();
//初始化OLED屏幕模块
OLED_Init();
//初始化空气温湿度模块
DHT11_Init();
//初始化光照强度模块
BH1750_Init();
//初始化遮阳板模块;
SG90_Init();
//清屏
OLED_Clear();
//数据显示的基本信息
OLED_ShowString(1, 1, "ahumi:");
OLED_ShowString(2, 1, "temp :");
OLED_ShowString(3, 1, "light:");
OLED_ShowString(3, 11, "Lx");
OLED_ShowString(1, 11, "%");
OLED_ShowString(2, 11, "Centig");
OLED_ShowString(4, 1, "shumi:");
OLED_ShowString(4, 11, "%");
// UsartPrintf(USART2, " Hardware init OK\r\n");
// UsartPrintf(USART_DEBUG, " Hardware init OK\r\n");
//在最后初始化
//避免蜂鸣器系统初始化中出现噪音
buzzer_Init();
//避免热风机抽水机系统初始化中进入工作模式
Machine_Init();
while (1)
{
//显示和上传数据
DHT11_ReadData(&temp, &air_humi);
OLED_ShowNum(1, 7, air_humi, 2);
OLED_ShowNum(2, 7, temp, 2);
light = Light_Intensity();
OLED_ShowNum(3, 7, light, 3);
soil_humi = 100 - (float)Soil_humi_GetValue() * 100 / 4095;
OLED_ShowNum(4, 7, soil_humi, 2);
//空气湿度和警报
if(air_humi < air_humi_th)
{
buzzer = 1;
buzzerRing();
}
else if(air_humi >= air_humi_th)
{
buzzer = 0;
not_buzzerRing();
}
//空气湿度和警报
//土壤湿度和灌溉
if(soil_humi < soil_humi_th)
{
water = 1;
Machine_Water_ON();
}
else if(soil_humi >= soil_humi_th)
{
water = 0;
Machine_Water_OFF();
}
//土壤湿度和灌溉
//光照强度和遮阳
if(light > light_th)
{
sg90 = 1;
SG90_open();
}
else if(light <= light_th)
{
sg90 = 0;
SG90_close();
}
//光照强度和遮阳
//温度和热风
if(temp < temp_th)
{
wind = 1;
Machine_Wind_ON();
}
else if(temp >= temp_th)
{
wind = 0;
Machine_Wind_OFF();
}
//温度和热风
//空气湿度和警报
if(air_humi > air_humi_th)
{
buzzer = 0;
buzzerRing();
//OLED_ShowString(3, 14, "bu");
}
else if(air_humi <= air_humi_th)
{
buzzer = 1;
not_buzzerRing();
//OLED_ShowString(3, 14, " ");
}
//空气湿度和警报
//配合Delay_ms(10),控制数据上传的时间,大概为3秒钟
if(++timeCount >= 150)
{
UsartPrintf(USART_DEBUG, "OneNet_SendData\r\n");
//在这上传数据
OneNet_SendData();
timeCount = 0;
ESP8266_Clear();
UsartPrintf(USART_DEBUG, "温度%d\r\n", temp);
UsartPrintf(USART_DEBUG, "温度阈值%d\r\n", temp_th);
UsartPrintf(USART_DEBUG, "空气湿度%d\r\n", air_humi);
UsartPrintf(USART_DEBUG, "空气湿度阈值%d\r\n", air_humi_th);
UsartPrintf(USART_DEBUG, "土壤湿度%d\r\n", soil_humi);
UsartPrintf(USART_DEBUG, "土壤湿度阈值%d\r\n", soil_humi_th);
UsartPrintf(USART_DEBUG, "光照强度%d\r\n", (int)light);
UsartPrintf(USART_DEBUG, "光照强度阈值%d\r\n", light_th);
}
dataPtr = ESP8266_GetIPD(1);
if(dataPtr != NULL)
OneNet_RevPro(dataPtr);
Delay_ms(10);
}
}
3、OLED.c#include "stm32f10x.h"
include "DHT11.h"
include "OLED_Font.h"
/引脚配置/
define OLED_W_SCL(x) GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(x))
define OLED_W_SDA(x) GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)(x))
/引脚初始化/
void OLED_I2C_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_Init(GPIOB, &GPIO_InitStructure);
OLED_W_SCL(1);
OLED_W_SDA(1);
}
/**
- @brief I2C开始
- @param 无
- @retval 无
*/
void OLED_I2C_Start(void)
{
OLED_W_SDA(1);
OLED_W_SCL(1);
OLED_W_SDA(0);
OLED_W_SCL(0);
}
/**
- @brief I2C停止
- @param 无
- @retval 无
*/
void OLED_I2C_Stop(void)
{
OLED_W_SDA(0);
OLED_W_SCL(1);
OLED_W_SDA(1);
}
/**
- @brief I2C发送一个字节
- @param Byte 要发送的一个字节
- @retval 无
*/
void OLED_I2C_SendByte(uint8_t Byte)
{
uint8_t i;
for (i = 0; i < 8; i++)
{
OLED_W_SDA(Byte & (0x80 >> i));
OLED_W_SCL(1);
OLED_W_SCL(0);
}
OLED_W_SCL(1); //额外的一个时钟,不处理应答信号
OLED_W_SCL(0);
}
/**
- @brief OLED写命令
- @param Command 要写入的命令
- @retval 无
*/
void OLED_WriteCommand(uint8_t Command)
{
OLED_I2C_Start();
OLED_I2C_SendByte(0x78); //从机地址
OLED_I2C_SendByte(0x00); //写命令
OLED_I2C_SendByte(Command);
OLED_I2C_Stop();
}
/**
- @brief OLED写数据
- @param Data 要写入的数据
- @retval 无
*/
void OLED_WriteData(uint8_t Data)
{
OLED_I2C_Start();
OLED_I2C_SendByte(0x78); //从机地址
OLED_I2C_SendByte(0x40); //写数据
OLED_I2C_SendByte(Data);
OLED_I2C_Stop();
}
/**
- @brief OLED设置光标位置
- @param Y 以左上角为原点,向下方向的坐标,范围:0~7
- @param X 以左上角为原点,向右方向的坐标,范围:0~127
- @retval 无
*/
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
OLED_WriteCommand(0xB0 | Y); //设置Y位置
OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4)); //设置X位置高4位
OLED_WriteCommand(0x00 | (X & 0x0F)); //设置X位置低4位
}
/**
- @brief OLED清屏
- @param 无
- @retval 无
*/
void OLED_Clear(void)
{
uint8_t i, j;
for (j = 0; j < 8; j++)
{
OLED_SetCursor(j, 0);
for(i = 0; i < 128; i++)
{
OLED_WriteData(0x00);
}
}
}
/**
- @brief OLED显示一个字符
- @param Line 行位置,范围:1~4
- @param Column 列位置,范围:1~16
- @param Char 要显示的一个字符,范围:ASCII可见字符
- @retval 无
*/
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{
uint8_t i;
OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8); //设置光标位置在上半部分
for (i = 0; i < 8; i++)
{
OLED_WriteData(OLED_F8x16[Char - ' '][i]); //显示上半部分内容
}
OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8); //设置光标位置在下半部分
for (i = 0; i < 8; i++)
{
OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]); //显示下半部分内容
}
}
/**
- @brief OLED显示字符串
- @param Line 起始行位置,范围:1~4
- @param Column 起始列位置,范围:1~16
- @param String 要显示的字符串,范围:ASCII可见字符
- @retval 无
*/
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i++)
{
OLED_ShowChar(Line, Column + i, String[i]);
}
}
/**
- @brief OLED次方函数
- @retval 返回值等于X的Y次方
*/
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1;
while (Y--)
{
Result *= X;
}
return Result;
}
/**
- @brief OLED显示数字(十进制,正数)
- @param Line 起始行位置,范围:1~4
- @param Column 起始列位置,范围:1~16
- @param Number 要显示的数字,范围:0~4294967295
- @param Length 要显示数字的长度,范围:1~10
- @retval 无
*/
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
}
}
/**
- @brief OLED显示数字(十进制,带符号数)
- @param Line 起始行位置,范围:1~4
- @param Column 起始列位置,范围:1~16
- @param Number 要显示的数字,范围:-2147483648~2147483647
- @param Length 要显示数字的长度,范围:1~10
- @retval 无
*/
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
uint8_t i;
uint32_t Number1;
if (Number >= 0)
{
OLED_ShowChar(Line, Column, '+');
Number1 = Number;
}
else
{
OLED_ShowChar(Line, Column, '-');
Number1 = -Number;
}
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
}
}
/**
- @brief OLED显示数字(十六进制,正数)
- @param Line 起始行位置,范围:1~4
- @param Column 起始列位置,范围:1~16
- @param Number 要显示的数字,范围:0~0xFFFFFFFF
- @param Length 要显示数字的长度,范围:1~8
- @retval 无
*/
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i, SingleNumber;
for (i = 0; i < Length; i++)
{
SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
if (SingleNumber < 10)
{
OLED_ShowChar(Line, Column + i, SingleNumber + '0');
}
else
{
OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
}
}
}
/**
- @brief OLED显示数字(二进制,正数)
- @param Line 起始行位置,范围:1~4
- @param Column 起始列位置,范围:1~16
- @param Number 要显示的数字,范围:0~1111 1111 1111 1111
- @param Length 要显示数字的长度,范围:1~16
- @retval 无
*/
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
}
}
/**
-
@brief OLED初始化
-
@param 无
-
@retval 无
*/
void OLED_Init(void)
{
uint32_t i, j;for (i = 0; i < 1000; i++) //上电延时
{
for (j = 0; j < 1000; j++);
}OLED_I2C_Init(); //端口初始化
OLED_WriteCommand(0xAE); //关闭显示
OLED_WriteCommand(0xD5); //设置显示时钟分频比/振荡器频率
OLED_WriteCommand(0x80);OLED_WriteCommand(0xA8); //设置多路复用率
OLED_WriteCommand(0x3F);OLED_WriteCommand(0xD3); //设置显示偏移
OLED_WriteCommand(0x00);OLED_WriteCommand(0x40); //设置显示开始行
OLED_WriteCommand(0xA1); //设置左右方向,0xA1正常 0xA0左右反置
OLED_WriteCommand(0xC8); //设置上下方向,0xC8正常 0xC0上下反置
OLED_WriteCommand(0xDA); //设置COM引脚硬件配置
OLED_WriteCommand(0x12);OLED_WriteCommand(0x81); //设置对比度控制
OLED_WriteCommand(0xCF);OLED_WriteCommand(0xD9); //设置预充电周期
OLED_WriteCommand(0xF1);OLED_WriteCommand(0xDB); //设置VCOMH取消选择级别
OLED_WriteCommand(0x30);OLED_WriteCommand(0xA4); //设置整个显示打开/关闭
OLED_WriteCommand(0xA6); //设置正常/倒转显示
OLED_WriteCommand(0x8D); //设置充电泵
OLED_WriteCommand(0x14);OLED_WriteCommand(0xAF); //开启显示
OLED_Clear(); //OLED清屏
}
4、OLED.h#ifndef __OLED_H
define __OLED_H
void OLED_Init(void);
void OLED_Clear(void);
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char);
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String);
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length);
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
endif
5、OLED_Font.h#ifndef __OLED_FONT_H
define __OLED_FONT_H
/OLED字模库,宽8像素,高16像素/
const uint8_t OLED_F8x16[][16]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,
0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,
0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,
0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,
0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,
0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,
0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,
0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,
0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,
0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,
0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,
0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,
0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,
0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,
0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,
0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,
0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,
0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,
0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,
0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,
0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,
0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,
0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,
0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,
0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,
0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,
0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,
0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,
0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,
0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,
0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,
0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,
0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,
0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,
0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,
0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,
0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,
0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,
0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,
0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,
0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,
0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,
0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,
0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,
0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,
0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,
0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,
0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,
0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,
0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,
0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,
0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,
0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,
0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,
0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,
0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,
0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,
0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
};
endif
6、buzzer.c#include "stm32f10x.h" // Device header
void buzzer_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void buzzerRing()
{
//鸣响
GPIO_SetBits(GPIOB, GPIO_Pin_12);
}
void not_buzzerRing()
{
//不响
GPIO_ResetBits(GPIOB, GPIO_Pin_12);
}
7、buzzer.h#include "stm32f10x.h"
ifndef _BUZZER
define _BUZZER
extern uint8_t buzzer;
void buzzer_Init(void);
void buzzerRing(void);
void not_buzzerRing(void);
endif
8、DHT11.c#include "stm32f10x.h" // Device header
include "Delay.h"
include "DHT11.h"
define DHT11_GPIO GPIOB
define DHT11_PIN GPIO_Pin_14
void DHT11_Init()
{
Delay_ms(1000);
OLED_ShowString(3, 1, "temp:");
OLED_ShowString(2, 1, " air_humi:");
}
//初始化为输出
void DHT11_GPIO_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //开启挂载GPIO的总线APB2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出,输入也是有效
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//初始化为输入
void DHT11_GPIO_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入,不可以输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
uint8_t DHT11_ReadByte(void)
{
uint8_t temp;
uint8_t ReadDat=0;
uint8_t retry = 0;
uint8_t i;
//二进数除以十即为数据
for(i=0;i<8;i++)
{
//消耗准备信号低电平50us
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==0&&retry<100)
{
Delay_us(1);
retry++;
}
retry=0;
//虽然0信号持续时间为28us,retry循环非常巧妙,
//避免问题,相当于如果一直是0的话可以避免延时带来的多出时间
Delay_us(30);//如果是0,那temp=0起作用,非0,仍然在高电平时间内
//因为如果数据是0的话持续时间短,故先预置0,简化代码。
temp=0;//数字信号0,temp=0
//数字0信号高电平持续28us,数字1信号高电平70us,延时30us以确认数字0或1
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==1)
{
temp=1;
}
//数字1信号高电平剩余40us
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==1&&retry<100)
{
Delay_us(1);
retry++;
}
retry=0;
//<<=左移赋值符号,|=先或再赋值,得到1位数据,即8bit
ReadDat<<=1;
ReadDat|=temp;
}
return ReadDat;
}
void DHT11_ReadData(int8 *temp, uint8_t *air_humi)
{
uint8_t i,data[5];
uint8_t retry=0;
//stm32 PB14设置为输出,发送开始信号低电平18ms,高电平40us
DHT11_GPIO_OUT();
GPIO_ResetBits(GPIOB,GPIO_Pin_14);//拉低引脚输出电平
Delay_ms(18);//保证dht11能收到起始信号
GPIO_SetBits(GPIOB,GPIO_Pin_14);//拉高引脚输出电平
Delay_us(40);//延时40us,等待dht11响应信号
//stm32 PB14设置为输入,检查并接收响应信号低电平80us,高电平80us
DHT11_GPIO_IN();//可以不切换,直接输出高电平,输入也是开启的
Delay_us(20);
//延时20us,dht11响应低电平80us,还剩60us,检查是否是低电平以确定是否有响应信号
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==0)
{ //第一个循环消耗响应低电平60us
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==0&&retry<100)//接收响应信号低电平剩余60us
{
Delay_us(1);
retry++;
}
retry=0;//超过100us自动向下运行,以免卡死
//消耗dht11拉高80us
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==1&&retry<100)//接收响应信号高电平80us
{
Delay_us(1);
retry++;
}
retry=0;
//接收8字节数据,每传送1bit之前先进行拉低50us
//接收了5位数据,40bit
for(i=0;i<5;i++)
{
data[i]=DHT11_ReadByte();
}
Delay_us(50);//DHT11拉低总线50us作为一字节结束信号,或者使用以下语句
if ((data[0] + data[1] + data[2] + data[3]) == data[4])
{
*air_humi = data[0];
*temp = data[2];
}
}
}
9、DHT11.h#ifndef __DHT11_H
define __DHT11_H
include "stm32f10x.h" // Device header
include "Common.h"
include "OLED.h"
extern uint8_t air_humi, air_humi_th;
extern int8 temp, temp_th;
void DHT11_Init(void);
void DHT11_GPIO_OUT(void);
void DHT11_GPIO_IN(void);
void DHT11_ReadData(int8 *temp, uint8_t *air_humi);
uint8_t DHT11_ReadByte(void);
endif
10、Usart.c/**
************************************************************
************************************************************
************************************************************
* 文件名: usart.c
*
* 作者: 张继瑞
*
* 日期: 2016-11-23
*
* 版本: V1.0
*
* 说明: 单片机串口外设初始化,格式化打印
*
* 修改记录:
************************************************************
************************************************************
************************************************************
**/
//硬件驱动
include "usart.h"
include "delay.h"
//C库
include <stdarg.h>
include <string.h>
include <stdio.h>
/*
- 函数名称: Usart1_Init
- 函数功能: 串口1初始化
- 入口参数: baud:设定的波特率
- 返回参数: 无
- 说明: TX-PA9 RX-PA10
*/
void Usart1_Init(unsigned int baud)
{
GPIO_InitTypeDef gpio_initstruct;
USART_InitTypeDef usart_initstruct;
NVIC_InitTypeDef nvic_initstruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//PA9 TXD
gpio_initstruct.GPIO_Mode = GPIO_Mode_AF_PP;
gpio_initstruct.GPIO_Pin = GPIO_Pin_9;
gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio_initstruct);
//PA10 RXD
gpio_initstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio_initstruct.GPIO_Pin = GPIO_Pin_10;
gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio_initstruct);
usart_initstruct.USART_BaudRate = baud;
usart_initstruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控
usart_initstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //接收和发送
usart_initstruct.USART_Parity = USART_Parity_No; //无校验
usart_initstruct.USART_StopBits = USART_StopBits_1; //1位停止位
usart_initstruct.USART_WordLength = USART_WordLength_8b; //8位数据位
USART_Init(USART1, &usart_initstruct);
USART_Cmd(USART1, ENABLE); //使能串口
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //使能接收中断
nvic_initstruct.NVIC_IRQChannel = USART1_IRQn;
nvic_initstruct.NVIC_IRQChannelCmd = ENABLE;
nvic_initstruct.NVIC_IRQChannelPreemptionPriority = 0;
nvic_initstruct.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&nvic_initstruct);
}
/*
- 函数名称: Usart2_Init
- 函数功能: 串口2初始化
- 入口参数: baud:设定的波特率
- 返回参数: 无
- 说明: TX-PA2 RX-PA3
*/
void Usart2_Init(unsigned int baud)
{
GPIO_InitTypeDef gpio_initstruct;
USART_InitTypeDef usart_initstruct;
NVIC_InitTypeDef nvic_initstruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
//PA2 TXD
gpio_initstruct.GPIO_Mode = GPIO_Mode_AF_PP;
gpio_initstruct.GPIO_Pin = GPIO_Pin_2;
gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio_initstruct);
//PA3 RXD
gpio_initstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio_initstruct.GPIO_Pin = GPIO_Pin_3;
gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio_initstruct);
usart_initstruct.USART_BaudRate = baud;
usart_initstruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控
usart_initstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //接收和发送
usart_initstruct.USART_Parity = USART_Parity_No; //无校验
usart_initstruct.USART_StopBits = USART_StopBits_1; //1位停止位
usart_initstruct.USART_WordLength = USART_WordLength_8b; //8位数据位
USART_Init(USART2, &usart_initstruct);
USART_Cmd(USART2, ENABLE); //使能串口
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); //使能接收中断
nvic_initstruct.NVIC_IRQChannel = USART2_IRQn;
nvic_initstruct.NVIC_IRQChannelCmd = ENABLE;
nvic_initstruct.NVIC_IRQChannelPreemptionPriority = 0;
nvic_initstruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&nvic_initstruct);
}
/*
- 函数名称: Usart_SendString
- 函数功能: 串口数据发送
- 入口参数: USARTx:串口组
-
str:要发送的数据 -
len:数据长度 - 返回参数: 无
- 说明:
*/
void Usart_SendString(USART_TypeDef *USARTx, unsigned char *str, unsigned short len)
{
unsigned short count = 0;
for(; count < len; count++)
{
USART_SendData(USARTx, *str++); //发送数据
while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET); //等待发送完成
}
}
/*
- 函数名称: UsartPrintf
- 函数功能: 格式化打印
- 入口参数: USARTx:串口组
-
fmt:不定长参 - 返回参数: 无
- 说明:
*/
void UsartPrintf(USART_TypeDef *USARTx, char *fmt,...)
{
unsigned char UsartPrintfBuf[296];
va_list ap;
unsigned char *pStr = UsartPrintfBuf;
va_start(ap, fmt);
vsnprintf((char *)UsartPrintfBuf, sizeof(UsartPrintfBuf), fmt, ap); //格式化
va_end(ap);
while(*pStr != 0)
{
USART_SendData(USARTx, *pStr++);
while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
}
}
/*
- 函数名称: USART1_IRQHandler
- 函数功能: 串口1收发中断
- 入口参数: 无
- 返回参数: 无
- 说明:
*/
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
{
USART_ClearFlag(USART1, USART_FLAG_RXNE);
}
}
11、Usart.h#ifndef USART_H
define USART_H
include "stm32f10x.h"
define USART_DEBUG USART1 //调试打印所使用的串口组
void Usart1_Init(unsigned int baud);
void Usart2_Init(unsigned int baud);
void Usart_SendString(USART_TypeDef *USARTx, unsigned char *str, unsigned short len);
void UsartPrintf(USART_TypeDef *USARTx, char *fmt,...);
endif
12、BH1750.c#include "BH1750.h"
/****************************************************************************
** 函数名称:I2C_Configuration()
** 函数功能:显示用到的引脚初始化与 IIC初始化
** 参数说明:
**
** 返回值:无
** IIC_InitTypeDef 说明:
I2C_ClockSpeed; //设置SCL时钟频率,此值最高 400 000
I2C_Mode; //指定工作模式,可选IIC模式及SMBUS模式
I2C_DutyCycle; //时钟占空比,可选low/high = 2:0或16:9
I2C_OwnAddress1; //自身的IIC设备地址
I2C_Ack; //使能或者关闭响应,一般是使能
I2C_AcknowledgedAddress;//指定地址长度,可为7或1
// STM32F103C8T6芯片的硬件:
// IIC_1: PB10 -- SCL; PB11 -- SDA //
// IIC_1(重映射):PB8 -- SCL; PB9 -- SDA
// IIC_2:IIC_1: PB10 -- SCL; PB11 -- SDA
*****************************************************************************/
void I2C_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //I2C必须开漏输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_InitTypeDef I2C_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
I2C_DeInit(I2C2); //使用I2C2
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //选择IIC模式
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //占空比 1/2
I2C_InitStructure.I2C_OwnAddress1 = 0x33; //主机的I2C地址
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //应答信号使能
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //IIC 7 位寻址
I2C_InitStructure.I2C_ClockSpeed = 100000; //设置最大400K
I2C_Cmd(I2C2, ENABLE); //使能IIC2
I2C_Init(I2C2, &I2C_InitStructure); //初始化 IIC_2 相关
}
/****************************************************************************
** 函数名称:BH1750_WriteByte()
** 函数功能:BH1750 写数据
** 参数说明:
** uint8_t addr: 寄存器地址
**
** 返回值:无
** IIC函数说明:
** I2C_GetFlagStatus(IIC_x, IIC_Flag_x)-- 检查标志位是否置 1
**
*****************************************************************************/
void BH1750_WriteByte(uint8_t addr)
{
/* 先判断总线是否忙 */
while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY));
/* 发送Start信号,切换到主模式(M/SL 位置 1) */
I2C_GenerateSTART(I2C2, ENABLE);
/* 等待EV5事件,IIC开始信号已经发出 */
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
/* 发送器件地址,发送方向: I2C_Direction_Transmitter */
I2C_Send7bitAddress(I2C2, (BH1750_Addr_GND_REG<<1|0), I2C_Direction_Transmitter);
/* 等待EV6事件:表示地址已经发送 */
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/* 需要操作的寄存器地址 */
I2C_SendData(I2C2, addr);
/* 等待EV8事件:数据寄存器DR为空,地址数据已经发送 */
while (!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
/* 产生应答信号 */
I2C_AcknowledgeConfig(I2C2, ENABLE);
I2C_GenerateSTOP(I2C2, ENABLE);//产生停止信号,关闭I2C2总线
}
/****************************************************************************
** 函数名称:BH1750_Read_Data()
** 函数功能:BH1750 读取数据
** 参数说明:
** uint8_t addr :寄存器地址
**
** 返回值:RX_Data
** IIC函数说明:
** I2C_GetFlagStatus(IIC_x, IIC_Flag_x)-- 检查标志位是否置 1
**
*****************************************************************************/
uint16_t BH1750_Read_Data(void)
{
uint16_t RX_Data; //读取到的数据
while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY)); /* 先判断总线是否忙 */
I2C_GenerateSTART(I2C2, ENABLE); /* 发送Start信号,切换到主模式 */
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)); /* 等待EV5事件,IIC开始信号已经发出 */
/* 发送读地址指令,发送方向: I2C_Direction_Receiver */
I2C_Send7bitAddress(I2C2, BH1750_Addr_GND_REG<<1|1, I2C_Direction_Receiver);
/* 等待EV6事件:地址已发送 (接收类型) */
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
I2C_AcknowledgeConfig(I2C2, ENABLE); /* 产生应答信号 */
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED)); /* 等待EV7事件 */
RX_Data = I2C_ReceiveData(I2C2); /* 读取高8位数据 */
I2C_AcknowledgeConfig(I2C2, ENABLE); /* 产生应答信号 */
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED)); /* 等待EV7事件 */
/* 与高8位合成16位完整数据 */
RX_Data = (RX_Data<<8) + I2C_ReceiveData(I2C2); /* 读取低8位 */
I2C_AcknowledgeConfig(I2C2, DISABLE); /* 产生非应答信号 */
I2C_GenerateSTOP(I2C2, ENABLE); /** 发送停止信号 **/
return RX_Data;
}
/** BH1750上电 **/
void BH1750_Power_ON(void)
{
BH1750_WriteByte(BH1750_Power_ON_REG);
}
/** BH1750断电 **/
void BH1750_Power_OFF(void)
{
BH1750_WriteByte(BH1750_Power_OFF_REG);
}
/** BH1750数据寄存器复位 **/
void BH1750_RESET(void)
{
BH1750_WriteByte(BH1750_MODULE_RESET_REG);
}
/** BH1750初始化 **/
void BH1750_Init(void)
{
I2C_Configuration();
BH1750_Power_ON();
BH1750_RESET();
BH1750_WriteByte(BH1750_CONTINUE_H_MODE2);
}
/** 获取光照强度 /
/ 分辨率 光照强度(单位lx)=(High Byte + Low Byte)/ 1.2 **/
float Light_Intensity(void)
{
return (float)(BH1750_Read_Data() / 1.2f );
}
/*************************************END**************************************************/
13、bh1750.h#ifndef __BH1750_H
define __BH1750_H
include "stm32f10x.h"
include "Delay.h"
extern uint8_t light, light_th;
/* 器件地址(7位-用左移1位-最后1位为读写位--1为读-0为写) */
define BH1750_Addr_GND_REG 0X23 //ADDR引脚接低电平
define BH1750_Addr_VCC_REG 0X5C //ADDR引脚接高电平
/****** 指令集宏定义*****/
define BH1750_Power_OFF_REG 0x00 //断电
define BH1750_Power_ON_REG 0x01 //通电,等待测量命令
define BH1750_MODULE_RESET_REG 0x07 //重置数据寄存器,关机模式下,不能接受重置命令
/*************************************************
不同模式下分辨率不同(也即精度不同)
高分辨率模式2:分辨率是0.5lx
高分辨率模式:分辨率1lx
低分辨率模式:分辨率4lx
不同模式只是精度不一样,对于计算没有区别
*************************************************/
/ 工作模式指令集 **/
define BH1750_CONTINUE_H_MODE 0x10 //连续H分辨率模式
define BH1750_CONTINUE_H_MODE2 0x11 //连续H分辨率模式2
define BH1750_CONTINUE_L_MODE 0x13 //连续L分辨率模式
define BH1750_ONE_TIME_H_MODE 0x20 //一次H分辨率模式
define BH1750_ONE_TIME_H_MODE2 0x21 //一次H分辨率模式2
define BH1750_ONE_TIME_L_MODE 0x23 //一次性L分辨率模式
/** 函数声明区 **/
void I2C_Configuration (void);
void BH1750_WriteByte (uint8_t addr);
uint16_t BH1750_Read_Data (void);
void BH1750_Power_ON (void);
void BH1750_Power_OFF (void);
void BH1750_RESET (void);
void BH1750_Init (void);
float Light_Intensity (void);
endif
14、sg90.c#include "stm32f10x.h" // Device header
void SG90_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_Cmd(TIM2, ENABLE);
}
void SG90_SetCompare2(uint16_t Compare)
{
TIM_SetCompare2(TIM2, Compare);
}
void SG90_open()
{
float Angle = 0;
SG90_SetCompare2(Angle / 180 * 2000 + 500);
}
void SG90_close()
{
float Angle = 180;
SG90_SetCompare2(Angle / 180 * 2000 + 500);
}
15、sg90.h#ifndef __SG90_H
define __SG90_H
void SG90_Init(void);
void SG90_open(void);
void SG90_close(void);
void SG90_SetCompare2(uint16_t Compare);
endif
16、soil.c#include "stm32f10x.h"
include "Soil_humi.h"
void Soil_humi_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);
}
uint16_t Soil_humi_GetValue(void)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
return ADC_GetConversionValue(ADC1);
}
17、soil.h#ifndef __Soil_humi_H
define __Soil_humi_H
extern float soil_humi, soil_humi_th;
void Soil_humi_Init(void);
uint16_t Soil_humi_GetValue(void);
endif
18、machine.c#include "stm32f10x.h" // Device header
void Machine_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB, GPIO_Pin_6 | GPIO_Pin_7);
}
void Machine_Wind_ON(void)
{
GPIO_SetBits(GPIOB, GPIO_Pin_6);
}
void Machine_Wind_OFF(void)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_6);
}
void Machine_Water_ON(void)
{
GPIO_SetBits(GPIOB, GPIO_Pin_7);
}
void Machine_Water_OFF(void)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_7);
}
19、machine.h#ifndef __Machine_H
define __Machine_H
extern uint8_t wind;
extern uint8_t water;
void Machine_Init(void);
void Machine_Wind_ON(void);
void Machine_Wind_OFF(void);
void Machine_Water_ON(void);
void Machine_Water_OFF(void);
endif
20、common.h#ifndef COMMON_H
define COMMON_H
/---------------------------------------------------------------------------/
/* Type Definition Macros /
/---------------------------------------------------------------------------*/
typedef _Bool uint1;
typedef unsigned char uint8;
typedef char int8;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned int uint32;
typedef int int32;
typedef unsigned int size_t;
endif /* COMMON_H */
21、esp8266.c
//单片机头文件
include "stm32f10x.h"
//网络设备驱动
include "esp8266.h"
//硬件驱动
include "delay.h"
include "usart.h"
//C库
include <string.h>
include <stdio.h>
define ESP8266_WIFI_INFO "AT+CWJAP="zzx","12345678"\r\n"
//#define ESP8266_ONENET_INFO "AT+CIPSTART="TCP","mqtts.heclouds.com",1883\r\n"
define ESP8266_ONENET_INFO "AT+CIPSTART="TCP","mqtts.heclouds.com",1883\r\n"
unsigned char esp8266_buf[512];
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0;
//==========================================================
// 函数名称: ESP8266_Clear
//
// 函数功能: 清空缓存
//
// 入口参数: 无
//
// 返回参数: 无
//
// 说明:
//==========================================================
void ESP8266_Clear(void)
{
memset(esp8266_buf, 0, sizeof(esp8266_buf));
esp8266_cnt = 0;
}
//==========================================================
// 函数名称: ESP8266_WaitRecive
//
// 函数功能: 等待接收完成
//
// 入口参数: 无
//
// 返回参数: REV_OK-接收完成 REV_WAIT-接收超时未完成
//
// 说明: 循环调用检测是否接收完成
//==========================================================
_Bool ESP8266_WaitRecive(void)
{
if(esp8266_cnt == 0) //如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数
return REV_WAIT;
if(esp8266_cnt == esp8266_cntPre) //如果上一次的值和这次相同,则说明接收完毕
{
esp8266_cnt = 0; //清0接收计数
return REV_OK; //返回接收完成标志
}
esp8266_cntPre = esp8266_cnt; //置为相同
return REV_WAIT; //返回接收未完成标志
}
//==========================================================
// 函数名称: ESP8266_SendCmd
//
// 函数功能: 发送命令
//
// 入口参数: cmd:命令
// res:需要检查的返回指令
//
// 返回参数: 0-成功 1-失败
//
// 说明:
//==========================================================
_Bool ESP8266_SendCmd(char *cmd, char *res)
{
unsigned char timeOut = 200;
Usart_SendString(USART2, (unsigned char *)cmd, strlen((const char *)cmd));
while(timeOut--)
{
if(ESP8266_WaitRecive() == REV_OK) //如果收到数据
{
if(strstr((const char *)esp8266_buf, res) != NULL) //如果检索到关键词
{
ESP8266_Clear(); //清空缓存
return 0;
}
}
Delay_ms(10);
}
return 1;
}
//==========================================================
// 函数名称: ESP8266_SendData
//
// 函数功能: 发送数据
//
// 入口参数: data:数据
// len:长度
//
// 返回参数: 无
//
// 说明:
//==========================================================
void ESP8266_SendData(unsigned char *data, unsigned short len)
{
char cmdBuf[32];
ESP8266_Clear(); //清空接收缓存
sprintf(cmdBuf, "AT+CIPSEND=%d\r\n", len); //发送命令
if(!ESP8266_SendCmd(cmdBuf, ">")) //收到‘>’时可以发送数据
{
Usart_SendString(USART2, data, len); //发送设备连接请求数据
}
}
//==========================================================
// 函数名称: ESP8266_GetIPD
//
// 函数功能: 获取平台返回的数据
//
// 入口参数: 等待的时间(乘以10ms)
//
// 返回参数: 平台返回的原始数据
//
// 说明: 不同网络设备返回的格式不同,需要去调试
// 如ESP8266的返回格式为 "+IPD,x:yyy" x代表数据长度,yyy是数据内容
//==========================================================
unsigned char *ESP8266_GetIPD(unsigned short timeOut)
{
char *ptrIPD = NULL;
do
{
if(ESP8266_WaitRecive() == REV_OK) //如果接收完成
{
ptrIPD = strstr((char *)esp8266_buf, "IPD,"); //搜索“IPD”头
if(ptrIPD == NULL) //如果没找到,可能是IPD头的延迟,还是需要等待一会,但不会超过设定的时间
{
// UsartPrintf(USART_DEBUG, "\"IPD\" not found\r\n");
}
else
{
ptrIPD = strchr(ptrIPD, ':'); //找到':'
if(ptrIPD != NULL)
{
ptrIPD++;
return (unsigned char *)(ptrIPD);
}
else
return NULL;
}
}
Delay_ms(5); //延时等待
} while(timeOut--);
return NULL; //超时还未找到,返回空指针
}
//==========================================================
// 函数名称: ESP8266_Init
//
// 函数功能: 初始化ESP8266
//
// 入口参数: 无
//
// 返回参数: 无
//
// 说明:
//==========================================================
void ESP8266_Init(void)
{
GPIO_InitTypeDef GPIO_Initure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//ESP8266复位引脚
GPIO_Initure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Initure.GPIO_Pin = GPIO_Pin_14; //GPIOC14-复位
GPIO_Initure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_Initure);
GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_RESET);
Delay_ms(250);
GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_SET);
Delay_ms(500);
ESP8266_Clear();
// UsartPrintf(USART_DEBUG, "1. AT\r\n");
while(ESP8266_SendCmd("AT\r\n", "OK"))
Delay_ms(500);
// UsartPrintf(USART_DEBUG, "2. CWMODE\r\n");
while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))
Delay_ms(500);
// UsartPrintf(USART_DEBUG, "3. AT+CWDHCP\r\n");
while(ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK"))
Delay_ms(500);
// UsartPrintf(USART_DEBUG, "4. CWJAP\r\n");
while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))
Delay_ms(500);
// UsartPrintf(USART_DEBUG, "5. CIPSTART\r\n");
while(ESP8266_SendCmd(ESP8266_ONENET_INFO, "CONNECT"))
Delay_ms(500);
// UsartPrintf(USART_DEBUG, "6. ESP8266 Init OK\r\n");
}
//void ESP8266_Init(void)
//{
//
// GPIO_InitTypeDef GPIO_Initure;
//
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// //ESP8266复位引脚
// GPIO_Initure.GPIO_Mode = GPIO_Mode_Out_PP;
// GPIO_Initure.GPIO_Pin = GPIO_Pin_14; //GPIOC14-复位
// GPIO_Initure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_Init(GPIOC, &GPIO_Initure);
//
// GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_RESET);
// Delay_ms(250);
// GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_SET);
// Delay_ms(500);
//
// ESP8266_Clear();
//
// UsartPrintf(USART_DEBUG, "1. AT\r\n");
// while(ESP8266_SendCmd("AT\r\n", "OK"))
// Delay_ms(500);
//
// UsartPrintf(USART_DEBUG, "2. CWMODE\r\n");
// while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))
// Delay_ms(500);
//
// UsartPrintf(USART_DEBUG, "3. AT+CWDHCP\r\n");
// while(ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK"))
// Delay_ms(500);
//
// UsartPrintf(USART_DEBUG, "4. CWJAP\r\n");
// while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))
// Delay_ms(500);
//
// UsartPrintf(USART_DEBUG, "5. CIPSTART\r\n");
// while(ESP8266_SendCmd(ESP8266_ONENET_INFO, "CONNECT"))
// Delay_ms(500);
//
// UsartPrintf(USART_DEBUG, "6. ESP8266 Init OK\r\n");
//}
//==========================================================
// 函数名称: USART2_IRQHandler
//
// 函数功能: 串口2收发中断
//
// 入口参数: 无
//
// 返回参数: 无
//
// 说明:
//==========================================================
void USART2_IRQHandler(void)
{
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收中断
{
if(esp8266_cnt >= sizeof(esp8266_buf)) esp8266_cnt = 0; //防止串口被刷爆
esp8266_buf[esp8266_cnt++] = USART2->DR;
USART_ClearFlag(USART2, USART_FLAG_RXNE);
//当GET KEY的数据流时,服务器会下发这样的数据, ..,"value":"0"}],"id":"KEY"}
// if(esp8266_buf[esp8266_cnt-3]'"'&&esp8266_buf[esp8266_cnt-2]'0'&&esp8266_buf[esp8266_cnt-1]'"')
// {
//// LED = 1; //关灯
// UsartPrintf(USART_DEBUG, "value:0\r\n");
// }
// else if(esp8266_buf[esp8266_cnt-3]'"'&&esp8266_buf[esp8266_cnt-2]'1'&&esp8266_buf[esp8266_cnt-1]'"')
// {
//// LED = 0; //开灯
// UsartPrintf(USART_DEBUG, "value:1\r\n");
// }
//将接收到的数据,通过串口1返发给PC
// USART_SendData(USART1, USART2->DR);
// while( USART_GetFlagStatus(USART1, USART_FLAG_TXE)==RESET); //等待发送完成
// USART_ClearFlag(USART1,USART_FLAG_TXE); //清空标志位
}
}
22、esp8266.h#ifndef ESP8266_H
define ESP8266_H
define REV_OK 0 //接收完成标志
define REV_WAIT 1 //接收未完成标志
void ESP8266_Init(void);
void ESP8266_Clear(void);
_Bool ESP8266_SendCmd(char *cmd, char *res);
void ESP8266_SendData(unsigned char *data, unsigned short len);
unsigned char *ESP8266_GetIPD(unsigned short timeOut);
endif
23、onnet.c
include <string.h>
include <stdio.h>
include "cJSON.h"
include "Common.h"
include "base64.h"
include "hmac_sha1.h"
include "stm32f10x.h"
include "Soil_humi.h"
include "esp8266.h"
include "onenet.h"
include "mqttkit.h"
include "usart.h"
include "Delay.h"
include "Buzzer.h"
include "BH1750.h"
include "DHT11.h"
//设备ID
define PROID "Cq1TeX8Z9V"
//设备密钥
define ACCESS_KEY "900TZfFRpc2zqVU1le81b3fbTR3Zo7tVU0f3R/cHkz8="
//设备名称
define DEVICE_NAME "ZZX_dev"
extern unsigned short timeCount;
extern float soil_humi, soil_humi_th;
extern uint8_t air_humi, buzzer, air_humi_th;
extern int8 temp, temp_th;
extern uint8_t wind;
extern uint8_t water;
extern uint8_t sg90;
char devid[16];
char key[48];
extern unsigned char esp8266_buf[512];
/*
- 函数名称: OTA_UrlEncode
- 函数功能: sign需要进行URL编码
- 入口参数: sign:加密结果
- 返回参数: 0-成功 其他-失败
- 说明: + %2B
-
空格 %20 -
/ %2F -
? %3F -
% %25 -
# %23 -
& %26 -
= %3D
*/
static unsigned char OTA_UrlEncode(char *sign)
{
char sign_t[40];
unsigned char i = 0, j = 0;
unsigned char sign_len = strlen(sign);
if(sign == (void *)0 || sign_len < 28)
return 1;
for(; i < sign_len; i++)
{
sign_t[i] = sign[i];
sign[i] = 0;
}
sign_t[i] = 0;
for(i = 0, j = 0; i < sign_len; i++)
{
switch(sign_t[i])
{
case '+':
strcat(sign + j, "%2B");j += 3;
break;
case ' ':
strcat(sign + j, "%20");j += 3;
break;
case '/':
strcat(sign + j, "%2F");j += 3;
break;
case '?':
strcat(sign + j, "%3F");j += 3;
break;
case '%':
strcat(sign + j, "%25");j += 3;
break;
case '#':
strcat(sign + j, "%23");j += 3;
break;
case '&':
strcat(sign + j, "%26");j += 3;
break;
case '=':
strcat(sign + j, "%3D");j += 3;
break;
default:
sign[j] = sign_t[i];j++;
break;
}
}
sign[j] = 0;
return 0;
}
/*
- 函数名称: OTA_Authorization
- 函数功能: 计算Authorization
- 入口参数: ver:参数组版本号,日期格式,目前仅支持格式"2018-10-31"
-
res:产品id -
et:过期时间,UTC秒值 -
access_key:访问密钥 -
dev_name:设备名 -
authorization_buf:缓存token的指针 -
authorization_buf_len:缓存区长度(字节) - 返回参数: 0-成功 其他-失败
- 说明: 当前仅支持sha1
*/
define METHOD "sha1"
static unsigned char OneNET_Authorization(char *ver, char *res, unsigned int et, char *access_key, char *dev_name,
char *authorization_buf, unsigned short authorization_buf_len, _Bool flag)
{
size_t olen = 0;
char sign_buf[64]; //保存签名的Base64编码结果 和 URL编码结果
char hmac_sha1_buf[64]; //保存签名
char access_key_base64[64]; //保存access_key的Base64编码结合
char string_for_signature[72]; //保存string_for_signature,这个是加密的key
//----------------------------------------------------参数合法性--------------------------------------------------------------------
if(ver == (void *)0 || res == (void *)0 || et < 1564562581 || access_key == (void *)0
|| authorization_buf == (void *)0 || authorization_buf_len < 120)
return 1;
//----------------------------------------------------将access_key进行Base64解码----------------------------------------------------
memset(access_key_base64, 0, sizeof(access_key_base64));
BASE64_Decode((unsigned char *)access_key_base64, sizeof(access_key_base64), &olen, (unsigned char *)access_key, strlen(access_key));
//UsartPrintf(USART_DEBUG, "access_key_base64: %s\r\n", access_key_base64);
//----------------------------------------------------计算string_for_signature-----------------------------------------------------
memset(string_for_signature, 0, sizeof(string_for_signature));
if(flag)
snprintf(string_for_signature, sizeof(string_for_signature), "%d\n%s\nproducts/%s\n%s", et, METHOD, res, ver);
else
snprintf(string_for_signature, sizeof(string_for_signature), "%d\n%s\nproducts/%s/devices/%s\n%s", et, METHOD, res, dev_name, ver);
//UsartPrintf(USART_DEBUG, "string_for_signature: %s\r\n", string_for_signature);
//----------------------------------------------------加密-------------------------------------------------------------------------
memset(hmac_sha1_buf, 0, sizeof(hmac_sha1_buf));
hmac_sha1((unsigned char *)access_key_base64, strlen(access_key_base64),
(unsigned char *)string_for_signature, strlen(string_for_signature),
(unsigned char *)hmac_sha1_buf);
//UsartPrintf(USART_DEBUG, "hmac_sha1_buf: %s\r\n", hmac_sha1_buf);
//----------------------------------------------------将加密结果进行Base64编码------------------------------------------------------
olen = 0;
memset(sign_buf, 0, sizeof(sign_buf));
BASE64_Encode((unsigned char *)sign_buf, sizeof(sign_buf), &olen, (unsigned char *)hmac_sha1_buf, strlen(hmac_sha1_buf));
//----------------------------------------------------将Base64编码结果进行URL编码---------------------------------------------------
OTA_UrlEncode(sign_buf);
//UsartPrintf(USART_DEBUG, "sign_buf: %s\r\n", sign_buf);
//----------------------------------------------------计算Token--------------------------------------------------------------------
if(flag)
snprintf(authorization_buf, authorization_buf_len, "version=%s&res=products%%2F%s&et=%d&method=%s&sign=%s", ver, res, et, METHOD, sign_buf);
else
snprintf(authorization_buf, authorization_buf_len, "version=%s&res=products%%2F%s%%2Fdevices%%2F%s&et=%d&method=%s&sign=%s", ver, res, dev_name, et, METHOD, sign_buf);
//UsartPrintf(USART_DEBUG, "Token: %s\r\n", authorization_buf);
return 0;
}
//==========================================================
// 函数名称: OneNET_RegisterDevice
//
// 函数功能: 在产品中注册一个设备
//
// 入口参数: access_key:访问密钥
// pro_id:产品ID
// serial:唯一设备号
// devid:保存返回的devid
// key:保存返回的key
//
// 返回参数: 0-成功 1-失败
//
// 说明:
//==========================================================
_Bool OneNET_RegisterDevice(void)
{
_Bool result = 1;
unsigned short send_len = 11 + strlen(DEVICE_NAME);
char *send_ptr = NULL, *data_ptr = NULL;
char authorization_buf[144]; //加密的key
send_ptr = malloc(send_len + 240);
if(send_ptr == NULL)
return result;
while(ESP8266_SendCmd("AT+CIPSTART=\"TCP\",\"183.230.40.33\",80\r\n", "CONNECT"))
Delay_ms(500);
OneNET_Authorization("2018-10-31", PROID, 1956499200, ACCESS_KEY, NULL,
authorization_buf, sizeof(authorization_buf), 1);
snprintf(send_ptr, 240 + send_len, "POST /mqtt/v1/devices/reg HTTP/1.1\r\n"
"Authorization:%s\r\n"
"Host:ota.heclouds.com\r\n"
"Content-Type:application/json\r\n"
"Content-Length:%d\r\n\r\n"
"{\"name\":\"%s\"}",
authorization_buf, 11 + strlen(DEVICE_NAME), DEVICE_NAME);
ESP8266_SendData((unsigned char *)send_ptr, strlen(send_ptr));
/*
{
"request_id" : "f55a5a37-36e4-43a6-905c-cc8f958437b0",
"code" : "onenet_common_success",
"code_no" : "000000",
"message" : null,
"data" : {
"device_id" : "589804481",
"name" : "mcu_id_43057127",
"pid" : 282932,
"key" : "indu/peTFlsgQGL060Gp7GhJOn9DnuRecadrybv9/XY="
}
}
*/
data_ptr = (char *)ESP8266_GetIPD(250); //等待平台响应
if(data_ptr)
{
data_ptr = strstr(data_ptr, "device_id");
}
if(data_ptr)
{
char name[16];
int pid = 0;
if(sscanf(data_ptr, "device_id\" : \"%[^\"]\",\r\n\"name\" : \"%[^\"]\",\r\n\r\n\"pid\" : %d,\r\n\"key\" : \"%[^\"]\"", devid, name, &pid, key) == 4)
{
UsartPrintf(USART_DEBUG, "create device: %s, %s, %d, %s\r\n", devid, name, pid, key);
result = 0;
}
}
free(send_ptr);
ESP8266_SendCmd("AT+CIPCLOSE\r\n", "OK");
return result;
}
//==========================================================
// 函数名称: OneNet_DevLink
//
// 函数功能: 与onenet创建连接
//
// 入口参数: 无
//
// 返回参数: 1-成功 0-失败
//
// 说明: 与onenet平台建立连接
//==========================================================
_Bool OneNet_DevLink(void)
{
MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0}; //协议包
unsigned char *dataPtr;
char authorization_buf[160];
_Bool status = 1;
OneNET_Authorization("2018-10-31", PROID, 1956499200, ACCESS_KEY, DEVICE_NAME,
authorization_buf, sizeof(authorization_buf), 0);
UsartPrintf(USART_DEBUG, "OneNET_DevLink\r\n"
"NAME: %s, PROID: %s, KEY:%s\r\n"
, DEVICE_NAME, PROID, authorization_buf);
if(MQTT_PacketConnect(PROID, authorization_buf, DEVICE_NAME, 512, 1, MQTT_QOS_LEVEL0, NULL, NULL, 0, &mqttPacket) == 0)
{
ESP8266_SendData(mqttPacket._data, mqttPacket._len); //上传平台
dataPtr = ESP8266_GetIPD(250); //等待平台响应
if(dataPtr != NULL)
{
if(MQTT_UnPacketRecv(dataPtr) == MQTT_PKT_CONNACK)
{
switch(MQTT_UnPacketConnectAck(dataPtr))
{
case 0:UsartPrintf(USART_DEBUG, "Tips: 连接成功\r\n");status = 0;break;
case 1:UsartPrintf(USART_DEBUG, "WARN: 连接失败:协议错误\r\n");break;
case 2:UsartPrintf(USART_DEBUG, "WARN: 连接失败:非法的clientid\r\n");break;
case 3:UsartPrintf(USART_DEBUG, "WARN: 连接失败:服务器失败\r\n");break;
case 4:UsartPrintf(USART_DEBUG, "WARN: 连接失败:用户名或密码错误\r\n");break;
case 5:UsartPrintf(USART_DEBUG, "WARN: 连接失败:非法链接(比如token非法)\r\n");break;
default:UsartPrintf(USART_DEBUG, "ERR: 连接失败:未知错误\r\n");break;
}
}
}
MQTT_DeleteBuffer(&mqttPacket); //删包
}
else
UsartPrintf(USART_DEBUG, "WARN: MQTT_PacketConnect Failed\r\n");
return status;
}
//unsigned char OneNet_FillBuf(char *buf)
//{
//
// char text[64];
//
// memset(text, 0, sizeof(text));
//
// strcpy(buf, "{"id":"111","params":{");
//
// memset(text, 0, sizeof(text));
// sprintf(text, ""buzzer":[{"value":%d}],", buzzer);
// strcat(buf, text);
//
// memset(text, 0, sizeof(text));
// sprintf(text, ""soil_humi":[{"value":%d}],", soil_humi);
// strcat(buf, text);
//
// memset(text, 0, sizeof(text));
// sprintf(text, ""ired":[{"value":%d}]", ired);
// strcat(buf, text);
//
// memset(text, 0, sizeof(text));
// sprintf(text, ""air_humi":[{"value":%d}]", air_humi);
// strcat(buf, text);
//
// memset(text, 0, sizeof(text));
// sprintf(text, ""temp":[{"value":%d}],", temp);
// strcat(buf, text);
//
// strcat(buf, "}}");
//
// return strlen(buf);
//}
unsigned int OneNet_FillBuf(char *buf)
{
char text[64];
memset(text, 0, sizeof(text));
strcpy(buf, "{\"id\":\"111\",\"params\":{");
memset(text, 0, sizeof(text));
sprintf(text, "\"buzzer\":{\"value\":%s},", buzzer ? "true" : "false");
strcat(buf, text);
memset(text, 0, sizeof(text));
sprintf(text, "\"water\":{\"value\":%s},", water ? "true" : "false");
strcat(buf, text);
memset(text, 0, sizeof(text));
sprintf(text, "\"wind\":{\"value\":%s},", wind ? "true" : "false");
strcat(buf, text);
memset(text, 0, sizeof(text));
sprintf(text, "\"sg90\":{\"value\":%s},", sg90 ? "true" : "false");
strcat(buf, text);
memset(text, 0, sizeof(text));
sprintf(text, "\"soil_humi\":{\"value\":%d},", (int)soil_humi);
strcat(buf, text);
memset(text, 0, sizeof(text));
sprintf(text, "\"soil_humi_th\":{\"value\":%d},", (int)soil_humi_th);
strcat(buf, text);
memset(text, 0, sizeof(text));
sprintf(text, "\"light\":{\"value\":%d},", (int)light);
strcat(buf, text);
memset(text, 0, sizeof(text));
sprintf(text, "\"light_th\":{\"value\":%d},", (int)light_th);
strcat(buf, text);
memset(text, 0, sizeof(text));
sprintf(text, "\"air_humi\":{\"value\":%d},", (int)air_humi);
strcat(buf, text);
memset(text, 0, sizeof(text));
sprintf(text, "\"air_humi_th\":{\"value\":%d},", (int)air_humi_th);
strcat(buf, text);
memset(text, 0, sizeof(text));
sprintf(text, "\"temp_th\":{\"value\":%d},", (int)temp_th);
strcat(buf, text);
memset(text, 0, sizeof(text));
sprintf(text, "\"temp\":{\"value\":%d}", (int)temp);
strcat(buf, text);
strcat(buf, "}}");
return strlen(buf);
}
//==========================================================
// 函数名称: OneNet_SendData
//
// 函数功能: 上传数据到平台
//
// 入口参数: type:发送数据的格式
//
// 返回参数: 无
//
// 说明:
//==========================================================
void OneNet_SendData(void)
{
MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0}; //协议包
char buf[1536];
short body_len = 0, i = 0;
UsartPrintf(USART_DEBUG, "Tips: OneNet_SendData-MQTT\r\n");
memset(buf, 0, sizeof(buf));
body_len = OneNet_FillBuf(buf); //获取当前需要发送的数据流的总长度
if(body_len)
{
if(MQTT_PacketSaveData(PROID, DEVICE_NAME, body_len, NULL, &mqttPacket) == 0) //封包
{
for(; i < body_len; i++)
mqttPacket._data[mqttPacket._len++] = buf[i];
ESP8266_SendData(mqttPacket._data, mqttPacket._len); //上传数据到平台
UsartPrintf(USART_DEBUG, "Send %d Bytes\r\n", mqttPacket._len);
MQTT_DeleteBuffer(&mqttPacket); //删包
}
else
UsartPrintf(USART_DEBUG, "WARN: EDP_NewBuffer Failed\r\n");
}
}
//==========================================================
// 函数名称: OneNET_Publish
//
// 函数功能: 发布消息
//
// 入口参数: topic:发布的主题
// msg:消息内容
//
// 返回参数: 无
//
// 说明:
//==========================================================
void OneNET_Publish(const char *topic, const char *msg)
{
MQTT_PACKET_STRUCTURE mqtt_packet = {NULL, 0, 0, 0}; //协议包
UsartPrintf(USART_DEBUG, "Publish Topic: %s, Msg: %s\r\n", topic, msg);
if(MQTT_PacketPublish(MQTT_PUBLISH_ID, topic, msg, strlen(msg), MQTT_QOS_LEVEL0, 0, 1, &mqtt_packet) == 0)
{
ESP8266_SendData(mqtt_packet._data, mqtt_packet._len); //向平台发送订阅请求
MQTT_DeleteBuffer(&mqtt_packet); //删包
}
}
//==========================================================
// 函数名称: OneNET_Subscribe
//
// 函数功能: 订阅
//
// 入口参数: 无
//
// 返回参数: 无
//
// 说明:
//==========================================================
void OneNET_Subscribe(void)
{
MQTT_PACKET_STRUCTURE mqtt_packet = {NULL, 0, 0, 0}; //协议包
char topic_buf[56];
const char *topic = topic_buf;
snprintf(topic_buf, sizeof(topic_buf), "$sys/%s/%s/thing/property/set", PROID, DEVICE_NAME);
UsartPrintf(USART_DEBUG, "Subscribe Topic: %s\r\n", topic_buf);
if(MQTT_PacketSubscribe(MQTT_SUBSCRIBE_ID, MQTT_QOS_LEVEL0, &topic, 1, &mqtt_packet) == 0)
{
ESP8266_SendData(mqtt_packet._data, mqtt_packet._len); //向平台发送订阅请求
MQTT_DeleteBuffer(&mqtt_packet); //删包
}
}
//==========================================================
// 函数名称: OneNet_RevPro
//
// 函数功能: 平台返回数据检测
//
// 入口参数: dataPtr:平台返回的数据
//
// 返回参数: 无
//
// 说明:
//==========================================================
void OneNet_RevPro(unsigned char *cmd)
{
//my 111
cJSON * my_pares, * my_params, * buzzer_value, * sg90_value, * wind_value, * water_value, * temp_th_value, * air_humi_th_value, * soil_humi_th_value, * light_th_value;
//my 111
char *req_payload = NULL;
char *cmdid_topic = NULL;
unsigned short topic_len = 0;
unsigned short req_len = 0;
unsigned char qos = 0;
static unsigned short pkt_id = 0;
unsigned char type = 0;
short result = 0;
// char *dataPtr = NULL;
// char numBuf[10];
// int num = 0;
type = MQTT_UnPacketRecv(cmd);
switch(type)
{
case MQTT_PKT_PUBLISH: //接收的Publish消息
result = MQTT_UnPacketPublish(cmd, &cmdid_topic, &topic_len, &req_payload, &req_len, &qos, &pkt_id);
if(result == 0)
{
//char *data_ptr = NULL;
UsartPrintf(USART_DEBUG, "topic: %s, topic_len: %d, payload: %s, payload_len: %d\r\n",
cmdid_topic, topic_len, req_payload, req_len);
//my buzzer
my_pares = cJSON_Parse(req_payload);
my_params = cJSON_GetObjectItem(my_pares, "params");
buzzer_value = cJSON_GetObjectItem(my_params, "buzzer");
if(buzzer_value != NULL)
{
if(buzzer_value -> type == cJSON_True)
{
buzzer = 1;
OLED_ShowString(3, 14, "bu");
}else if(buzzer_value -> type == cJSON_False)
{
buzzer = 0;
OLED_ShowString(3, 14, " ");
}
timeCount = 149;
}
//my buzzer
//my water
water_value = cJSON_GetObjectItem(my_params, "water");
if(water_value != NULL)
{
if(water_value -> type == cJSON_True)
{
water = 1;
}else if(water_value -> type == cJSON_False)
{
water = 0;
}
timeCount = 149;
}
//my water
//my wind
wind_value = cJSON_GetObjectItem(my_params, "wind");
if(wind_value != NULL)
{
if(wind_value -> type == cJSON_True)
{
wind = 1;
}else if(water_value -> type == cJSON_False)
{
wind = 0;
}
timeCount = 149;
}
//my wind
//my sg90
sg90_value = cJSON_GetObjectItem(my_params, "sg90");
if(sg90_value != NULL)
{
if(sg90_value -> type == cJSON_True)
{
sg90 = 1;
}else if(sg90_value -> type == cJSON_False)
{
sg90 = 0;
}
timeCount = 149;
}
//my sg90
//my temp_th
temp_th_value = cJSON_GetObjectItem(my_params, "temp_th");
if(temp_th_value != NULL)
{
temp_th = temp_th_value ->valueint;
temp_th = temp_th_value ->valueint;
timeCount = 149;
}
//my temp_th
//my air_humi_th
air_humi_th_value = cJSON_GetObjectItem(my_params, "air_humi_th");
if(air_humi_th_value != NULL)
{
air_humi_th = air_humi_th_value ->valueint;
//OLED_ShowNum(3, 14, air_humi_th_value ->valueint, 2);
air_humi_th = air_humi_th_value ->valueint;
timeCount = 149;
}
//my air_humi_th
//my soil_humi_th
soil_humi_th_value = cJSON_GetObjectItem(my_params, "soil_humi_th");
if(soil_humi_th_value != NULL)
{
soil_humi_th = soil_humi_th_value ->valueint;
if(soil_humi_th < 0)
{
soil_humi_th = 0;
}
timeCount = 149;
}
//my soil_humi_th
//my light_th
light_th_value = cJSON_GetObjectItem(my_params, "light_th");
if(light_th_value != NULL)
{
light_th = light_th_value ->valueint;
//OLED_ShowNum(3, 14, light_th_value ->valueint, 3);
light_th = light_th_value ->valueint;
timeCount = 149;
}
//my light_th
cJSON_Delete(my_pares);
// data_ptr = strstr(cmdid_topic, "request/"); //查找cmdid
// if(data_ptr)
// {
// char topic_buf[80], cmdid[40];
//
// data_ptr = strchr(data_ptr, '/');
// data_ptr++;
//
// memcpy(cmdid, data_ptr, 36); //复制cmdid
// cmdid[36] = 0;
//
// snprintf(topic_buf, sizeof(topic_buf), "$sys/%s/%s/cmd/response/%s",
// PROID, DEVICE_NAME, cmdid);
// OneNET_Publish(topic_buf, "ojbk"); //回复命令
// }
}
case MQTT_PKT_PUBACK: //发送Publish消息,平台回复的Ack
if(MQTT_UnPacketPublishAck(cmd) == 0)
UsartPrintf(USART_DEBUG, "Tips: MQTT Publish Send OK\r\n");
break;
case MQTT_PKT_SUBACK: //发送Subscribe消息的Ack
if(MQTT_UnPacketSubscribe(cmd) == 0)
UsartPrintf(USART_DEBUG, "Tips: MQTT Subscribe OK\r\n");
else
UsartPrintf(USART_DEBUG, "Tips: MQTT Subscribe Err\r\n");
break;
default:
result = -1;
break;
}
ESP8266_Clear(); //清空缓存
if(result == -1)
return;
// dataPtr = strchr(req_payload, '😂; //搜索':'
// if(dataPtr != NULL && result != -1) //如果找到了
// {
// dataPtr++;
//
// while(*dataPtr >= '0' && *dataPtr <= '9') //判断是否是下发的命令控制数据
// {
// numBuf[num++] = *dataPtr++;
// }
// numBuf[num] = 0;
//
// num = atoi((const char *)numBuf); //转为数值形式
// }
if(type == MQTT_PKT_CMD || type == MQTT_PKT_PUBLISH)
{
MQTT_FreeBuffer(cmdid_topic);
MQTT_FreeBuffer(req_payload);
}
}
24、onenet.h#ifndef ONENET_H
define ONENET_H
extern uint8_t ired_change;
_Bool OneNET_RegisterDevice(void);
_Bool OneNet_DevLink(void);
void OneNet_SendData(void);
void OneNET_Subscribe(void);
void OneNet_RevPro(unsigned char *cmd);
endif
`
浙公网安备 33010602011771号