模块简述

esp01s是物联网无线模块,板载芯片为esp8266ex,1M SPI外设储存
笔者:其实esp01s给我感觉很不稳定,特别是IO0和IO2引脚,会发生引脚抖动,如后接继电器,则导致继电器工作状态不确定,如错误发生,改用TX、RX(即1、3号引脚)
如不对模块大小有要求,建议选用esp-12f或esp8266NodeMCU,程序代码通用的

模块特点
1.WIFI支持安全机制WPA/WPA2
2.WIFI模式支持 接入点/热点/接入点&热点
3.外设丰富:UART、SDIO、SPI、IIC、GPIO、ADC、PWM、IR遥控

esp01s模块

引脚定义

引脚定义表

程序开发

环境&准备

笔者推荐使用vscode+插件platformIO+arduino库的开发方式,不仅开发简单,拓展性也极强。
下载程序需切换为下载模式,上电后bootloader输出的信息,波特率为76800,为方便起见,在开发时应另购买esp01s烧录器
esp01s烧录器

点灯测试代码

1
2
3
4
5
6
7
8
9
10
11
12
const int LED_PIN = 2;

void setup() {
pinMode(LED_PIN, OUTPUT);
}

void loop() {
digitalWrite(LED_PIN, HIGH);
delay(1000);
digitalWrite(LED_PIN, LOW);
delay(1000);
}

下载后,板载LED间隔一秒闪动

PWM测试

虽笔者在芯片手册中查阅到主控芯片esp8266ex支持四路PWM,但模块esp01s并未将其引出,因此只能使用软件PWM。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "Arduino.h"

const int LedPin = 0; // 设置要控制的 LED 引脚(GPIO0)

void setup()
{
// 初始化 GPIO0 引脚为输出模式
pinMode(LedPin, OUTPUT);
}

void loop()
{
for (int i = 0; i < 1024; i++)
{
analogWrite(LedPin, i);
delay(1);
}
for (int i = 1023; i > 0; i--)
{
analogWrite(LedPin, i);
delay(1);
}
}

物联网服务平台

代码来源于巴法云官方教程,在此放出来仅作存档。
一些事项:

  • 巴法云在TCP创客平台中引入了MQTT的心跳机制,若超过65秒未向服务器发送在线声明作为“心跳”,则认为其离线
  • 有些朋友可能使用AT指令上云而不是烧录固件,具体的指令格式可参考巴法云TCP平台接入协议
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    #include <ESP8266WiFi.h>

    #define ssid "Wifi名字" // WIFI名称,区分大小写,不要写错
    #define passwd "Wifi密码" // WIFI密码
    String UID = "用户私钥"; //用户私钥,可在控制台获取,修改为自己的UID
    String TOPIC = " 主题名字"; //主题名字,可在控制台新建
    const int LED_Pin = 0; //单片机LED引脚值,GPIO0引脚

    int Wifi_connect()
    {
    int count = 0;
    WiFi.begin(ssid, passwd);
    Serial.println("Connecting");
    while (WiFi.status() != WL_CONNECTED)
    {
    delay(500);
    Serial.print(".");
    if (count++ > 10)
    return 0;
    }
    Serial.println();
    Serial.print("Connected, IP address: ");
    Serial.println(WiFi.localIP());
    return 1;
    }

    // tcp客户端相关初始化,默认即可
    WiFiClient TCPclient;
    String TcpClient_Buff = "";
    unsigned int TcpClient_BuffIndex = 0;
    unsigned long TcpClient_preTick = 0;
    unsigned long preHeartTick = 0; //心跳
    unsigned long preTCPStartTick = 0; //连接
    bool preTCPConnected = false;

    //巴法云服务器地址默认即可
    #define TCP_SERVER_ADDR "bemfa.com"
    //服务器端口,tcp创客云端口8344
    #define TCP_SERVER_PORT "8344"

    //最大字节数
    #define MAX_PACKETSIZE 512
    //设置心跳值60s
    #define KEEPALIVEATIME 60 * 1000

    void sendtoTCPServer(String p)
    {

    if (!TCPclient.connected())
    {
    Serial.println("Client is not readly");
    return;
    }
    TCPclient.print(p);
    Serial.println("[Send to TCPServer]:String");
    Serial.println(p);
    preHeartTick = millis(); //心跳计时开始,需要每隔60秒发送一次数据
    }

    void startTCPClient()
    {
    if (TCPclient.connect(TCP_SERVER_ADDR, atoi(TCP_SERVER_PORT)))
    {
    Serial.print("\nConnected to server:");
    Serial.printf("%s:%d\r\n", TCP_SERVER_ADDR, atoi(TCP_SERVER_PORT));

    String tcpTemp = ""; //初始化字符串
    tcpTemp = "cmd=1&uid=" + UID + "&topic=" + TOPIC + "\r\n"; //构建订阅指令
    sendtoTCPServer(tcpTemp); //发送订阅指令
    tcpTemp = ""; //清空

    preTCPConnected = true;
    TCPclient.setNoDelay(true); //禁用nagle算法
    }
    else
    {
    Serial.print("Failed connected to server:");
    Serial.println(TCP_SERVER_ADDR);
    TCPclient.stop();
    preTCPConnected = false;
    }
    preTCPStartTick = millis();
    }

    /*
    *检查数据,发送心跳
    */
    void doTCPClientTick()
    {
    //检查是否断开,断开后重连
    if (WiFi.status() != WL_CONNECTED)
    return;

    if (!TCPclient.connected())
    { //断开重连

    if (preTCPConnected == true)
    {

    preTCPConnected = false;
    preTCPStartTick = millis();
    Serial.println();
    Serial.println("TCP Client disconnected.");
    TCPclient.stop();
    }
    else if (millis() - preTCPStartTick > 1 * 1000) //重新连接
    startTCPClient();
    }
    else
    {
    if (TCPclient.available())
    { //收数据
    char c = TCPclient.read();
    TcpClient_Buff += c;
    TcpClient_BuffIndex++;
    TcpClient_preTick = millis();

    if (TcpClient_BuffIndex >= MAX_PACKETSIZE - 1)
    {
    TcpClient_BuffIndex = MAX_PACKETSIZE - 2;
    TcpClient_preTick = TcpClient_preTick - 200;
    }
    }
    if (millis() - preHeartTick >= KEEPALIVEATIME)
    { //保持心跳
    preHeartTick = millis();
    Serial.println("--Keep alive:");
    sendtoTCPServer("cmd=0&msg=keep\r\n");
    }
    }
    if ((TcpClient_Buff.length() >= 1) && (millis() - TcpClient_preTick >= 200))
    { // data ready
    TCPclient.flush();//清除发送缓冲区
    Serial.print("Rev string: ");
    TcpClient_Buff.trim(); //去掉首位空格
    Serial.println(TcpClient_Buff); //打印接收到的消息
    String getTopic = "";
    String getMsg = "";
    if (TcpClient_Buff.length() > 15)
    { //注意TcpClient_Buff只是个字符串,在上面开头做了初始化 String TcpClient_Buff = "";
    //此时会收到推送的指令,指令大概为 cmd=2&uid=xxx&topic=light002&msg=off
    int topicIndex = TcpClient_Buff.indexOf("&topic=") + 7; // c语言字符串查找,查找&topic=位置,并移动7位,不懂的可百度c语言字符串查找
    int msgIndex = TcpClient_Buff.indexOf("&msg="); // c语言字符串查找,查找&msg=位置
    getTopic = TcpClient_Buff.substring(topicIndex, msgIndex); // c语言字符串截取,截取到topic,不懂的可百度c语言字符串截取
    getMsg = TcpClient_Buff.substring(msgIndex + 5); // c语言字符串截取,截取到消息
    Serial.print("topic:------");
    Serial.println(getTopic); //打印截取到的主题值
    Serial.print("msg:--------");
    Serial.println(getMsg); //打印截取到的消息值
    }
    if (getMsg == "on")
    {
    // digitalWrite(3, LOW);
    // delay(1000);
    digitalWrite(3, HIGH);
    }
    else if (getMsg == "off")
    {
    digitalWrite(2, LOW);
    // delay(1000);
    // digitalWrite(2, HIGH);
    }

    TcpClient_Buff = "";
    TcpClient_BuffIndex = 0;
    }
    }

    void setup()
    {
    Serial.begin(115200);
    Serial.println();
    pinMode(2, OUTPUT);
    digitalWrite(2, HIGH);
    pinMode(3, OUTPUT);
    digitalWrite(3, HIGH);
    Serial.println("Beginning...");

    if (!Wifi_connect())
    {
    Serial.println("Wifi connect error");
    }
    }

    void loop()
    {

    doTCPClientTick();
    }