前言:
本次项目采用的ESP32芯片作为主控,使用MicroPython和thonny来开发的智慧系统。MCU连接阿里云通过阿里云的数据流转功能将连接MCU的DHT11,超声波等传感器所测得的数据通过MQTT协议上传至阿里云平台,而后在云平台上通过数据流转功能将得到的数据通过MQTT协议下发至微信小程序上而后显示,通过小程序可远程开关板载LED灯以及WS2812B炫彩灯。
一、ESP32
上海乐鑫的ESP32微控制器是一款集成有2.4GHz Wi-Fi和蓝牙4.0双模的物联网芯片方案,采用超低功耗的40纳米工艺代工。片上集成有天线开关、射频巴伦、功率放大器、接收低噪声放大器、滤波器、电源管理模块等功能,仅需要20余个外围元件,就可以适配大量的物联网场景。
除此之外,ESP32系列的工作温度范围达在-40°C ~ +125°C 之间,并且内部集成的自校准电路可以实现动态电压调整,以消除外部电路缺陷,适应外部条件的变化。从而在产品量产时,不需要使用到昂贵的专用Wi-Fi测量仪器。
该芯片即可以基于内嵌的Xtensa 32-bit MCU作为独立的片上系统使用,也可以作为其它MCU主控方案的从设备,通过 SPI/SDIO 或者 I2C、UART等串行总线协议提供Wi-Fi与蓝牙通信功能。
二、DHT11温湿度传感器
1、具有抗冲击性及电气性能优良
2、 完全标定
3、 优异的长期稳定性
4、响应迅速、恢复时间快、抗干扰能力强
5、数字输出,单总线通讯
图二、DHT11数字温度传感器
图三、DHT11数字温度传感器原理与
在该项目当中,DHT11的选型为三针默认NC引脚悬空,输出口接ESP32的GPIO16
对于MicroPython来说,使用该模块来检测环境的温湿度相较于c语言来说变得异常简单,因为它自带了DHT11的驱动函数,并且封装好了只需要调用即可。上述代码dht库中就包含了DHT11的测量函数measure(),只需对其引用使用一个变量来存储函数的和返回值便可得到对应的温湿度信息,最后将其封装成一个函数,供其它工程进行调用。
下方链接可供读者快速了解关于MicroPyhton在ESP32上的一下语法应用。
Quick reference for the ESP32 — MicroPython latest documentation (86x.net)
单总线通讯:DHT11通过单总线通讯应用与DHT11与MCU之间的通讯上,通过该方式来向MCU发送测得的温湿度信息。
图三、DHT11单总线传输顺序数据图
图四、DHT11单总线传送数据表
图五、单总线数据计算示例
步骤一:
DHT11上电后(DHT11上电后要等待1S以越过不稳定状态在此期间不能发送任何指令),测 试环境温湿度数据,并记录数据,同时DHT11的DATA数据线由上拉电阻拉高一直保持高电平; 此时DHT11的DATA引脚处于输入状态,时刻检测外部信号。
步骤二:
MCU初始电平状态为高,我们可以选择I/O口默认初始电平为高的I/O口也就是有着上拉电阻的IO口,这样它的起始电位则为高电平,而后MCU的I/O口输出低电平且低电平时间不低于18ms,而后MCU释放总线,总线电平返回为高,MCU的I/O口此时设置为输入模式,等待DHT11反应回复应答信号。
图六、主机发送起始信号
图七、从机响应信号
步骤三:
DHT11的输出引脚DATA检测到外部信号有低电平,等待外部信号低电平结束,延迟后的DHT11输出引脚为输出状态,输出83us的低电平信号作为应答信号,而后再输出87us左右的高电平通知MCU接收接下来的数据
步骤四:
由DHT11的DATA引脚输出40位的数据,MCU根据I/O电平的变化接收40位数据,位数据 “0”的格式为:54微秒的低电平和23-27微秒的高电平,位数据“1”的格式为:54微秒的低 电平加68-74微秒的高电平。
图八、输出数据0传输格式
图九、输出数据1传输格式
结束信号:
最后一bit传输完成之后,从机拉低总线50us,随后总线由上拉电阻将总线拉高进入空闲状态,等待下次的数据传输。
图十:完整通讯规程
对应STM32(C语言)代码块:
void DHT11_OUT() //将引脚设置为输出模式
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
void DHT11_INPUT() //设置为输入模式
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_Instructure;
GPIO_Instructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Instructure.GPIO_Pin=GPIO_Pin_0;
GPIO_Instructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_Instructure);
}
void DHT11_Rest() //复位函数
{
DHT11_OUT();
GPIO_ResetBits(GPIOA,GPIO_Pin_0); //拉低
Delay_ms(20); //至少拉低18ms
GPIO_SetBits(GPIOA,GPIO_Pin_0); //拉高
Delay_us(25); //拉高20-40us
}
void DHT11_ACK()
{
DHT11_INPUT() //引脚设置为输入模式
}
uint16_t DHT11_Check()
{
uint16_t count=0;
DHT11_INPUT();
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1 && count<100) //等待输入电平为0跳出循环
{
Delay_us(1);
count++;
}
if(count>=100)
{
return 1;
}
else
count= 0; //检测到低电平 此时将计数值重新至0,进入下一个高电平检测
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==0 && count<100) //等待输入电平为高跳出循环
{
Delay_us(1);
count++;
}
if(count>=100)
{
return 1;
}
return 0; //检测到高电平 传感器正常开始传送数据
}
uint16_t DHT11_ReadBit()
{
uint16_t count=0;
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1 && count<=100)
{
count++;
Delay_us(1);
}
count=0;
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==0 && count<=100)//读取高电平
{
count++;
Delay_us(1);
}
Delay_us(40);
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1) //说明该为读取的数据为1
return 1;
else
return 0; //不是1说明数据为0
}
uint16_t DHT11_ReadByte()
{
uint16_t date;
for(uint16_t i=0;i<=8;i++)
{
date<<=1;
date|=DHT11_ReadBit(); //数据读取 高位在前,低位在后,读取完向左移1位,将提取的数据为逐步提至最高位
}
return date;
}
void Readdate(uint16_t *temp,uint16_t *hum)
{
uint16_t buf[5];
DHT11_Rest();
if(DHT11_Check()==0)
{
for(uint16_t i=0;i<5;i++)
{
buf[i]=DHT11_ReadByte();
}
if(buf[0]+buf[1]+buf[2]+buf[3]==buf[4])
{
*temp=buf[0];
*hum=buf[2];
}
}
}
三、WS2812B(RGB彩灯)
图11、ws2812b实物图
图12、原理图
数据传送方式为D1,D2.D3,D4代表按顺序排列的WS2812B灯珠。从图中可以看出D1介绍到第一个24bit的数据后将后三个的数据传输给下一个灯珠,下一个灯珠取完自身所要接收的灯珠后将而后的数据往下传递。
数据的发送由高位到低位,每8bit位代表WS2812B灯珠对该颜色的发光强度,所以三原色绿红蓝的十六进制编码分别为:0xff0000,0x00ff00,0x0000ff。
MicroPython代码 ,通过元组来存储不同颜色的色值分量,达到改变颜色交替呈现不同的颜色的效果。
from machine import Pin, PWM
from neopixel import NeoPixel
import utime
# Pin configuration
pin = Pin(15, Pin.OUT)
np = NeoPixel(pin, 4)
ws2812bshow_flag = 0
# Define colors
red = (255, 0, 0)
blue = (0, 0, 255)
green = (0, 255, 0)
white = (255, 255, 255)
orange = (255, 165, 0)
purple = (128, 0, 128)
cyan = (0, 255, 255)
yellow = (255, 255, 0)
pink = (255, 192, 203)
indigo = (75, 0, 130)
light_blue = (173, 216, 230)
dark_green = (0, 100, 0)
light_green = (144, 238, 144)
gold = (255, 215, 0)
salmon = (250, 128, 114)
violet = (238, 130, 238)
turquoise = (64, 224, 208)
beige = (245, 222, 179)
coral = (255, 127, 80)
mint = (189, 252, 201)
chocolate = (210, 105, 30) # Color for breathing effect
# Function to show colors in a forward direction
def show(color, num):
for i in range(num, 4):
np[i] = color
np.write()
utime.sleep(0.05)
# Function to show colors in a reverse direction
def show1(color, num):
for i in range(num, 4)[::-1]:
np[i] = color
np.write()
utime.sleep(0.05)
# Function to display a sequence of colors
def ws2812b_show():
for i in range(1):
show(red, i)
show1(blue, i)
show(green, i)
show1(white, i)
show(red, i)
show1(blue, i)
show(white, i)
show1(chocolate, i)
# Function to display another sequence of colors
def ws28b12b_show2():
for i in range(1):
show1(orange, i)
show(purple, i)
show1(yellow, i)
show(pink, i)
show1(indigo, i)
show(light_blue, i)
show1(dark_green, i)
# Function to display a third sequence of colors
def ws2812b_show3():
for i in range(1):
show1(light_green, i)
show(gold, i)
show1(salmon, i)
show(violet, i)
show1(turquoise, i)
show(beige, i)
show1(coral, i)
show(mint, i)
# Function to create a breathing effect for NeoPixels
def breathing_led(duration=1, steps=50):
for step in range(steps):
# Calculate brightness level (0-255)
brightness = int((step / steps) * 255) # Fade in
for i in range(30): # Set all pixels to the calculated brightness
np[i] = (chocolate[0] * brightness // 255,
chocolate[1] * brightness // 255,
chocolate[2] * brightness // 255)
np.write() # Update the NeoPixel strip
utime.sleep(duration / steps) # Wait time based on duration and steps
for step in range(steps):
# Calculate brightness level (255-0)
brightness = int(((steps - step) /