TA的每日心情 | 衰 2018-7-12 13:58 |
---|
签到天数: 10 天 连续签到: 1 天 [LV.3]偶尔看看II
|
本帖最后由 冯俊波 于 2018-3-15 22:13 编辑
乐鑫生产ESP8266 32位RISC处理器,CPU 时钟速度最高可达 160 MHz,支持实时操作系统 (RTOS) 和 Wi-Fi 协议栈,可将高达 80% 的处理能力留给应用编程和开发。
本人自接触机智云以来,使用的最多的模组就是ESP8266,已将ESP8266融入到公司的许多产品之中,现将ESP8266一些使用技巧与大家分享。
一丶开发环境
ESP8266最常用的开发环境有4个(环境下载可以去官网下载,也可以加群438373554下载,几个环境都上传群文件了的)。
1.Ardunio(ESP定制版本)与传统Ardunio一样,支持在线更新和下载库,推荐入门级学习,比如开发wifi探针,室内定位,广告机等可以采用Ardunio开发。
2.lua (运行脚本)和Ardunio开发一样,很好入门,个人觉得用着有一点分散思维。
3.MicroPython(现在比较流行的),不会Python入门难,开发物联网产品方便。
4.Eclipse(ESP8266定制版本)比较综合的版本吧,要用RTOS就得用这个环境来开发,个人觉得也是最好的开发环境,C语言编程,会单片机的入门很快。机智云SOC开发也是使用这个环境进行开发。
二丶硬件的使用技巧
就拿ESP-12F来说,除开flash引脚之后,留给我们使用的就只有11个可用GPIO口(包括串口),一个ADC口(不可作为GPIO口使用),ADC是一个10位精度的AD口,可以测量0-1V的电压,也就是1/1024。如果用来采集大于1V的电压,要进行分压。可以用来做模拟信号类传感器的接口(注意分压0-1V,切记,高了会烧芯片)。接下来硬件设计的时候应该注意一下几个特殊的GPIO口,
上表中可以看出这3个GPIO在上电的时候不同状态下进入的模式不同。比如你想用GPIO15低电平有效来控制一个继电器,那么在上电的瞬间,由于GPIO15必须要保持低电平才能正常进入正常的运行模式,所以上电瞬间继电器也会伴随着启动,这在实际应用中是绝对要避免的,所以GPIO15应该用作高电平有效的控制,其他2端口使用也需要类似的注意,有很多人设计电路之后说下载之后不能用,比如指示灯一直闪烁(也就是GPIO2)。就是因为电路设计上存在缺陷造成的。进入了其他的模式。
在用ESP-12F设计最小的系统板的时候应该注意按照如下电路图进行设计
SW-2.1可以用一个跳冒代替,那样在下载程序和运行的时候的时候只需要拔插跳冒就行了。本人在使用之中经常作为输入的IO有GPIO0 GPIO2 GPIO4 GPIO5,剩下的用于输出或者传感器。在IO足够的情况下尽量不要先考虑使用GPIO16 GPIO0 GPIO15 GPIO2
三丶软件设计基本的入门
1.Ardunio程序设计,此处我写用几个比较典型的例子说明一下
例子1.基本输入输出GPIO0接 按键GPIO2模块上的灯,按键按下灯亮按键送卡灯灭
#define D3 0 //flash按键
#define D4 2 //板载灯
void setup() {
pinMode(D4, OUTPUT);
pinMode(D3, INPUT);
digitalWrite(D4,HIGH);
}
void loop() {
int ss;
ss=digitalRead(D3);
if(ss==1) digitalWrite(D4,HIGH);
else digitalWrite(D4,LOW);
}
例子2.串口测试
void setup()
{
Serial.begin(9600);//设置波特率
Serial.println("GO GO GO Begin");//打印GOGOGOBegin而且换行
}
void loop()
{
Serial.printf("hello");//打印hello不换行
delay(1000);
Serial.println(" ESP8266学习交流");//打印 ESP8266而且换行
delay(1000);
}
例子3.热点广告机实验
#include <ESP8266WiFi.h>
extern "C" {
#include "user_interface.h"
}
void setup() {
delay(500);
//设置为sta模式
wifi_set_opmode(STATION_MODE);
//开启混杂模式
wifi_promiscuous_enable(1);
}
void loop() {
//sendBeacon("test"); //sends beacon frames with the SSID 'test'
//sendRandomBeacon(10); //sends beacon frames with 10 character long random SSID
//sendFuzzedBeacon("FakeBeacon",10); //sends beacon frames with 10 different SSID all starting with 'test' and ending with whitespaces (spaces and/or tabs)
RickRoll();
}
void sendFuzzedBeacon(char* baseSsid, int nr) {
int baseLen = strlen(baseSsid);
int i=0;
for(int j=0; j < 32 - baseLen; j++) { //32 is the maximum length of the SSID
for(int k=0; k < pow(2,j); k++) {
int kk = k;
String ssid = baseSsid;
for(int l=0; l < j; l++) {
if(kk%2 == 1) ssid += " "; //add a space
else ssid += "\t"; //add a tab
kk /= 2;
}
char charBufSsid[33];
ssid.toCharArray(charBufSsid, 33);
sendBeacon(charBufSsid);
if(++i >= nr) return;
}
}
}
void sendRandomBeacon(int len) {
char ssid[len+1];
randomString(len, ssid);
sendBeacon(ssid);
}
void randomString(int len, char* ssid) {
String alfa = "1234567890qwertyuiopasdfghjkklzxcvbnm QWERTYUIOPASDFGHJKLZXCVBNM_";
for(int i = 0; i < len; i++) {
ssid = alfa[random(65)];
}
}
void sendBeacon(char* ssid) {
// Randomize channel //
byte channel = random(1,12);
wifi_set_channel(channel);
uint8_t packet[128] = { 0x80, 0x00, //Frame Control
0x00, 0x00, //Duration
/*4*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //Destination address
/*10*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, //Source address - overwritten later
/*16*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, //BSSID - overwritten to the same as the source address
/*22*/ 0xc0, 0x6c, //Seq-ctl
//Frame body starts here
/*24*/ 0x83, 0x51, 0xf7, 0x8f, 0x0f, 0x00, 0x00, 0x00, //timestamp - the number of microseconds the AP has been active
/*32*/ 0xFF, 0x00, //Beacon interval
/*34*/ 0x01, 0x04, //Capability info
/* SSID */
/*36*/ 0x00
};
int ssidLen = strlen(ssid);
packet[37] = ssidLen;
for(int i = 0; i < ssidLen; i++) {
packet[38+i] = ssid;
}
uint8_t postSSID[13] = {0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, //supported rate
0x03, 0x01, 0x04 /*DSSS (Current Channel)*/ };
for(int i = 0; i < 12; i++) {
packet[38 + ssidLen + i] = postSSID;
}
packet[50 + ssidLen] = channel;
// Randomize SRC MAC
packet[10] = packet[16] = random(256);
packet[11] = packet[17] = random(256);
packet[12] = packet[18] = random(256);
packet[13] = packet[19] = random(256);
packet[14] = packet[20] = random(256);
packet[15] = packet[21] = random(256);
int packetSize = 51 + ssidLen;
wifi_send_pkt_freedom(packet, packetSize, 0);
wifi_send_pkt_freedom(packet, packetSize, 0);
wifi_send_pkt_freedom(packet, packetSize, 0);
delay(1);
}
void RickRoll() {
sendBeacon("电子技术交流");
sendBeacon("1083791810");
sendBeacon("15120205205");
sendBeacon("物联网");
sendBeacon("分享快乐");
sendBeacon("ESP8266");
sendBeacon("机智云");
sendBeacon("让您生活更美好");
}
4.云平台测试
#include <ESP8266WiFi.h>
#include <Ticker.h>
#define D0 16
#define D1 5
#define D2 4
#define D3 0 //flash按键
#define D4 2 //板载灯
#define D5 14
// #define D6 12 //DHT11
#define D7 13
#define D8 15
#define D9 3
#define D10 1
//IO方向设置
#define DHT11_IO_IN() pinMode(12, INPUT)
#define DHT11_IO_OUT() pinMode(12, OUTPUT)
////IO操作函数
#define DHT11_DQ_OUT 12 //数据端口4
#define DHT11_DQ_IN 12 //数据端口4
//*******************
#define u8 unsigned char
Ticker timer;
unsigned long lastTick = 0;
unsigned char SW=15;
uint8_t macAddr[6];
/****************************DHT11部分**********************************/
u8 temperature;
u8 humidity;
u8 t = 0;
//复位DHT11
void DHT11_Rst(void)
{
DHT11_IO_OUT(); //SET OUTPUT
digitalWrite(DHT11_DQ_OUT, LOW); //拉低DQ
delay(20); //拉低至少18ms
digitalWrite(DHT11_DQ_OUT, HIGH); //DQ=1
delayMicroseconds(30); //主机拉高20~40us
}
//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
u8 DHT11_Check(void)
{
u8 retry = 0;
DHT11_IO_IN();//SET INPUT
while (digitalRead(DHT11_DQ_IN) && retry < 100) //DHT11会拉低40~80us
{
retry++;
delayMicroseconds(1);
};
if (retry >= 100)return 1;
else retry = 0;
while (!digitalRead(DHT11_DQ_IN) && retry < 100) //DHT11拉低后会再次拉高40~80us
{
retry++;
delayMicroseconds(1);
};
if (retry >= 100)return 1;
return 0;
}
//从DHT11读取一个位
//返回值:1/0
u8 DHT11_Read_Bit(void)
{
u8 retry = 0;
while (digitalRead(DHT11_DQ_IN) && retry < 100) //等待变为低电平
{
retry++;
delayMicroseconds(1);
}
retry = 0;
while (!digitalRead(DHT11_DQ_IN) && retry < 100) //等待变高电平
{
retry++;
delayMicroseconds(1);
}
delayMicroseconds(40);//等待40us
if (digitalRead(DHT11_DQ_IN))return 1;
else return 0;
}
//从DHT11读取一个字节
//返回值:读到的数据
u8 DHT11_Read_Byte(void)
{
u8 i, dat;
dat = 0;
for (i = 0; i < 8; i++)
{
dat <<= 1;
dat |= DHT11_Read_Bit();
}
return dat;
}
//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
u8 DHT11_Read_Data(u8 *temp, u8 *humi)
{
u8 buf[5];
u8 i;
DHT11_Rst();
if (DHT11_Check() == 0)
{
for (i = 0; i < 5; i++) //读取40位数据
{
buf = DHT11_Read_Byte();
}
if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
{
*humi = buf[0];
*temp = buf[2];
}
} else return 1;
return 0;
}
//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在
u8 DHT11_Init(void)
{
pinMode(4, OUTPUT);
DHT11_Rst();
return DHT11_Check();
}
const char* ssid = "fengshu";//家里面路由器wifi
const char* password = "15120205205";
const char* host = "192.168.1.88"; //服务器地址,此处可更换为云平台,我是局域网测试
const int httpPort = 8810; //服务器端口
char ser[64];
char str[512];
WiFiClient client;// 使用WiFi客户端类创建TCP连接
//反向控制:
unsigned long MS_TIMER = 0;
char flag = false;
void sensor_init()
{
pinMode(D0, OUTPUT);
digitalWrite(D0, HIGH);
pinMode(D1, OUTPUT);
digitalWrite(D1, HIGH);
pinMode(D2, OUTPUT);
digitalWrite(D2, HIGH);
pinMode(D3, OUTPUT);
digitalWrite(D3, HIGH);
pinMode(D4, OUTPUT);
digitalWrite(D4, HIGH);
}
void setup()
{
Serial.begin(115200);
MS_TIMER = millis();
sensor_init();
delay(10);
if (DHT11_Init()) //DHT11初始化
{
delay(200);
}
WiFi.disconnect();/////////////////
// 首先,我们连接到WiFi网络
Serial.println();
Serial.println();
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP());
delay(50);
Serial.println(host);
// 使用WiFi客户端类创建TCP连接
// 使用WiFi客户端类创建TCP连接
if (!client.connect(host, httpPort))
{
// Serial.println(hz[3]);
return;
}
}
int timerun=0;
void loop()
{
if (millis() - lastTick > 10000) //10s读一次
{
lastTick = millis();
//读传感器并发送
DHT11_Read_Data(&temperature, &humidity); //读取温湿度值
WiFi.softAPmacAddress(macAddr);
sprintf(str, "b%02x%02x%02x%02x%02x%02x%01x%d%d\r\n", macAddr[0],macAddr[1],macAddr[2],macAddr[3],macAddr[4],macAddr[5],SW, humidity, temperature);
Serial.printf("MAC:%02x%02x%02x%02x%02x%02x Temp:%d'C,Humi:%d%. \n", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5], temperature, humidity);
client.print(str);
delay(1000);
String recDataStr1 = client.readStringUntil('\n');
if(recDataStr1=="#") timerun=0;
else
{
if(timerun<=6)
{
timerun++;
}
else
{
// WiFi.begin(ssid, password);
client.connect(host, httpPort);
Serial.printf("TCP ERROW");
}
}
}
if (client.available())
{
//读并处理
// R读取服务器的应答的所有行,并把它们打印到串口
String recDataStr = client.readStringUntil('\n');
Serial.println(recDataStr);
if ((recDataStr == "#se")||(recDataStr == "#sc")||(recDataStr == "#sa")||(recDataStr == "#s8")||(recDataStr == "#s6")||(recDataStr == "#s4")||(recDataStr == "#s2")||(recDataStr == "#s0")) //BS ECA86420
{
digitalWrite(D0, LOW);
if((SW&1)==1) SW=SW-1;
else SW=SW;
}
if ((recDataStr == "#sf")||(recDataStr == "#sd")||(recDataStr == "#sb")||(recDataStr == "#s9")||(recDataStr == "#s7")||(recDataStr == "#s5")||(recDataStr == "#s3")||(recDataStr == "#s1"))
{
digitalWrite(D0, HIGH);
if((SW&1)==0) SW=SW+1;
else SW=SW;
}
if ((recDataStr == "#sd")||(recDataStr == "#sc")||(recDataStr == "#s9")||(recDataStr == "#s8")||(recDataStr == "#s5")||(recDataStr == "#s4")||(recDataStr == "#s1")||(recDataStr == "#s0"))
{
digitalWrite(D1, LOW);
if((SW&2)==2) SW=SW-2;
else SW=SW;
}
if ((recDataStr == "#sf")||(recDataStr == "#se")||(recDataStr == "#sb")||(recDataStr == "#sa")||(recDataStr == "#s7")||(recDataStr == "#s6")||(recDataStr == "#s3")||(recDataStr == "#s2"))
{
digitalWrite(D1, HIGH);
if((SW&2)==0) SW=SW+2;
else SW=SW;
}
if ((recDataStr == "#sb")||(recDataStr == "#sa")||(recDataStr == "#s9")||(recDataStr == "#s8")||(recDataStr == "#s3")||(recDataStr == "#s2")||(recDataStr == "#s1")||(recDataStr == "#s0"))
{
digitalWrite(D2, LOW);
if((SW&4)==4) SW=SW-4;
else SW=SW;
}
if ((recDataStr == "#sf")||(recDataStr == "#se")||(recDataStr == "#sd")||(recDataStr == "#sc")||(recDataStr == "#s7")||(recDataStr == "#s6")||(recDataStr == "#s5")||(recDataStr == "#s4"))
{
digitalWrite(D2, HIGH);
if((SW&4)==0) SW=SW+4;
else SW=SW;
}
if ((recDataStr == "#s7")||(recDataStr == "#s6")||(recDataStr == "#s5")||(recDataStr == "#s4")||(recDataStr == "#s3")||(recDataStr == "#s2")||(recDataStr == "#s1")||(recDataStr == "#s0"))
{
digitalWrite(D3, LOW);
if((SW&8)==8) SW=SW-8;
else SW=SW;
}
if ((recDataStr == "#sf")||(recDataStr == "#se")||(recDataStr == "#sd")||(recDataStr == "#sc")||(recDataStr == "#sb")||(recDataStr == "#sa")||(recDataStr == "#s9")||(recDataStr == "#s8"))
{
digitalWrite(D3, HIGH);
if((SW&8)==0) SW=SW+8;
else SW=SW;
}
Serial.println(SW);
// Serial.println(ser);
WiFi.softAPmacAddress(macAddr);
sprintf(str, "b%02x%02x%02x%02x%02x%02x%01x%d%d\r\n", macAddr[0],macAddr[1],macAddr[2],macAddr[3],macAddr[4],macAddr[5],SW, humidity, temperature);
client.print(str);
}
}
可以用串口助手开个端口进行调试,结合VB可以实现自动应答,界面如下
VB代码
Option Explicit
Dim UserCookie() As Long
Private Sub Form_Load()
ReDim UserCookie(0)
wskListen.Bind 8810
wskListen.Listen '监听网络连接
End Sub
Private Sub Form_Unload(Cancel As Integer)
Dim i As Long
On Error Resume Next
Erase UserCookie
For i = wskServer.UBound To 1 Step -1
wskServer(i).Close
Unload wskServer(i)
Next
wskListen.Close
End Sub
Private Sub btnSend_Click()
Dim i As Integer
For i = 1 To wskServer.UBound
If wskServer(i).Tag = UCase(Text2.Text) Then
wskServer(i).SendData Text1.Text
Exit Sub
End If
Next
End Sub
Private Sub btnClose_Click()
Unload Me
End Sub
Private Sub List1_DblClick()
Text2.Text = Mid(List1.Text, 1, 12)
End Sub
Private Sub wskListen_ConnectionRequest(ByVal requestID As Long)
Dim i As Long
For i = 1 To wskServer.UBound
If wskServer(i).State = sckClosed Then
UserCookie(i) = requestID
wskServer(i).Accept requestID
Exit Sub
End If
Next
Load wskServer(i)
wskServer(i).Accept requestID
ReDim Preserve UserCookie(i)
UserCookie(i) = requestID
End Sub
Private Sub wskServer_Close(Index As Integer)
wskServer(Index).Close
wskServer(Index).Tag = ""
'cmbClient.RemoveItem Index
'cmbClient.ListIndex = cmbClient.ListCount - 1
'cmbClient.Tag = cmbClient.Text
'btnSend.Enabled = (cmbClient.ListCount > 0)
End Sub
Private Sub wskServer_DataArrival(Index As Integer, ByVal bytesTotal As Long)
Dim strData As String
wskServer(Index).GetData strData, vbString
If Mid(strData, 1, 1) = "b" Then
wskServer(Index).SendData "b"
wskServer(Index).Tag = UCase(Mid(strData, 2, 12))
strData = Mid(strData, 14)
List1.AddItem wskServer(Index).Tag & ":" & Index & ":" & Mid(strData, 1, 1) & "|" & Mid(strData, 2), 0
End If
End Sub
Private Sub wskServer_SendComplete(Index As Integer)
'MsgBox "给[" & cmbClient.Tag & "]的内容已发送完毕!", vbInformation, "提示"
End Sub
Private Sub cmbClient_Click()
' btnSend.Enabled = (.ListCount > 0)
'End SubcmbClient
End Sub
Private Function FindUser(ByVal lCookie As Long) As String
Dim i As Long
' For i = 0 To cmbClient.ListCount - 1
' If InStr(cmbClient.List(i), "-" & lCookie) > 0 Then Exit For
' Next
' FindUser = cmbClient.List(i)
End Function
温湿度会上传到VB端,发送控制命令过去可以控制端口VB程序在这儿我就不仔细说明了,需要生成的可执行程序可以私聊我发给你
2.lua脚本,此处由于本人用的不多,所以我就写几个基本的
串口打印hello word!
tmr.alarm(0, 1000, tmr.ALARM_AUTO, function()
print("Hello word!\n")
end
)
基本的控制,控制模块板载灯串口打印按键状态
pin = 2
gpio.mode(pin,gpio.OUTPUT)
gpio.write(pin,gpio.HIGH)
gpio.mode(pin,gpio.INPUT)
print(gpio.read(pin))
ESP8266连接到路由器
print(wifi.sta.getip())
wifi.setmode(wifi.STATION)
wifi.sta.config("fengshu","15120205205")
print(wifi.sta.getip())
连接服务器
wifi.setmode(wifi.STATIONAP)
cfg = {}
cfg.ssid = "fengshu"
cfg.pwd = "15120205205"
wifi.ap.config(cfg)
stacfg = {}
stacfg.ssid = "hyx"
stacfg.pwd = "15597700228"
wifi.sta.config(stacfg)
wifi.sta.autoconnect(1)
ClientConnectFlag = 0
TcpClient = nil
tmr.alarm(2, 1000, 1, function() --定时器的妙用,当没连接上就一直打印Error,连接上就OK
if ClientConnectFlag == 0 then
Client = net.createConnection(net.TCP, 0) --创建一个TCP Client
Client:connect(8000, "192.168.0.117") --连接服务器的IP以及端口(下面会介绍怎么看IP)
Clientn("receive", function(sck, data) --Client接收到数据,打印到串口
print(data)
--uart.write(0, data) 两者都可以
end)
Clientn("connection", function(sck, c) --当连接上的时候
ClientConnectFlag = 1 --标志位
TcpClient = sck --记录当前的socket,以供串口向网络发送数据。
print("Link OK")
tmr.stop(2) --连上就停止定时器
--特别注意connection和disconnection的嵌套关系,不然会有意外情况
Clientn("disconnection", function(sck, c) --没有连上
ClientConnectFlag = 0 --清0标志位
TcpClient = nil
tmr.start(2) --重启定时器
end)
end)
if ClientConnectFlag == 0 then
print("Link Error")
end
end
end)
uart.on("data", 0, function(data) --串口要发送数据到网口
if TcpClient~=nil then
TcpClient:send(data)
end
end,0)
printip = 0
wifi.eventmon.register(wifi.eventmon.STA_DISCONNECTED, function(T)
printip = 0
end)
wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, function(T)
if printip==0 then
print("IP: "..T.IP)
end
printip = 1
end)
3. MicroPython MicroPython是一个基于Python 3的、精简和高效的编程语言,其包括Python标准库的一个小子集,并针对微控制器及受限的环境优化以可以运行。python本人今年才开始学的,所以有问题可以一起讨论
Python开发环境可以问我要,此处我不再写环境的搭建
常用命令help()可用于打印信息
编辑器最好使用Notepad++编写。比较方便,下面开始写几个例子
上电自动连接wifi
# main.py
import network
import webrepl
SSID = "fengshu"
PASSWORD = "15120205205"
def do_connect():
import network
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('connecting to network...')
wlan.connect(SSID, PASSWORD)
start = utime.time()
while not wlan.isconnected():
utime.sleep(1)
if utime.time()-start > 5:
print("connect timeout!")
break
if wlan.isconnected():
print('network config:', wlan.ifconfig())
do_connect()
|
|