文章目录[隐藏]
1. 简介
本文主要包括ESP32开发板的程序和ESP8266开发板的程序。涉及到的内容有OLED显示、DHT22的数据采集、ADC电压测量、TB6612驱动和PS2接收。
2. 电路连接
控制板ESP32的主要电路连接如下图所示:
遥控器ESP8266的主要电路连接如下图所示:
3. 软件设计
3.1 OLED显示
OLED显示的示例代码如下:
#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ 22, /* data=*/ 21, /* reset=*/ U8X8_PIN_NONE); // All Boards without Reset of the Display
void setup(void) {
u8g2.begin();
}
void loop(void) {
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(0,10,"Hello SSD1306!"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
delay(1000);
}
为了方便显示,定义了一个显示函数:
char str1[22];
char str2[22];
char str3[22];
char str4[22];
char str5[22];
...
void drawoled(char * str1, char* str2, char* str3, char* str4, char* str5)
{
// Need 104 ms to run this function
// Serial.printf("0 millis()=%d \n", millis());
u8g2.setFont(u8g2_font_ncenB08_tr); // font size is 8x6
u8g2.clearBuffer(); // clear the internal memory
u8g2.setCursor(0, 12);
u8g2.print(str1);
u8g2.setCursor(0, 24);
u8g2.print(str2);
u8g2.setCursor(0, 36);
u8g2.print(str3);
u8g2.setCursor(0, 48);
u8g2.print(str4);
u8g2.setCursor(0, 60);
u8g2.print(str5);
u8g2.sendBuffer(); // transfer internal memory to the
// Serial.printf("1 millis()=%d \n", millis());
}
str1等可以通过如下语句进行赋值后操作:
sprintf(str1, "msgid:%d t:%d", msgid, millis());
3.2 DHT22
部分代码:
#include "DHT.h"
...
#define DHTPIN 17 // DHT22
#define DHTTYPE DHT22 // DHT型号
...
// 初始化DHT传感器
DHT dht(DHTPIN, DHTTYPE);
...
void mqttIntervalPost()
{
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
h = dht.readHumidity();
// Read temperature as Celsius (the default)
t = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
f = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t) || isnan(f)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
// Compute heat index in Fahrenheit (the default)
float hif = dht.computeHeatIndex(f, h);
// Compute heat index in Celsius (isFahreheit = false)
float hic = dht.computeHeatIndex(t, h, false);
...
}
3.3 ADC电压测量
在主控板上,电池分压后的测试点接入ESP32的GPIO36。
部分代码如下:
#define ANALOG_PIN_0 36
...
vol_value = analogRead(ANALOG_PIN_0);
vol = vol_value*0.003630;
Serial.printf("ADC on Pin(%d)=%d, vol:%.2f\n",ANALOG_PIN_0,vol_value, vol);
3.4 TB6612驱动
TB6612的PWM输入接ESP32的GPIO16,部分代码如下:
int freq = 2000; // 频率
int channel = 0; // 通道
int resolution = 8; // 分辨率
uint16_t speed = 1;
const int pwmpin = 16;
const int AIN2 = 4;
const int AIN1 = 0;
const int BIN1 = 2;
const int BIN2 = 15;
...
void motorInit()
{
pinMode(AIN2, OUTPUT);
pinMode(AIN1, OUTPUT);
pinMode(BIN1, OUTPUT);
pinMode(BIN2, OUTPUT);
digitalWrite(AIN2, LOW);
digitalWrite(AIN1, LOW);
digitalWrite(BIN1, LOW);
digitalWrite(BIN2, LOW);
ledcSetup(channel, freq, resolution); // 设置通道
ledcAttachPin(pwmpin, channel); // 将通道与对应的引脚连接
ledcWrite(channel, speed*80); // 输出PWM
}
3.5 PS2接收
在遥控器端,ESP8266的SPI端口与PS2接收器相连,需要安装PS2X库才可以进行开发。部分代码如下:
#include <PS2X_lib.h> //for v1.6
...
/******************************************************************
* select modes of PS2 controller:
* - pressures = analog reading of push-butttons
* - rumble = motor rumbling
* uncomment 1 of the lines for each mode selection
******************************************************************/
//These are our button constants
#define CPSB_SELECT 1
#define CPSB_L3 2
#define CPSB_R3 3
#define CPSB_START 4
#define CPSB_PAD_UP 5
#define CPSB_PAD_RIGHT 6
#define CPSB_PAD_DOWN 7
#define CPSB_PAD_LEFT 8
#define CPSB_L2 9
#define CPSB_R2 10
#define CPSB_L1 11
#define CPSB_R1 12
#define CPSB_GREEN 13
#define CPSB_RED 14
#define CPSB_BLUE 15
#define CPSB_PINK 16
#define CPSB_TRIANGLE 13
#define CPSB_CIRCLE 14
#define CPSB_CROSS 15
#define CPSB_SQUARE 16
#define pressures false
#define rumble false
#define PS2_DAT 19 //MISO 19
#define PS2_CMD 23 //MOSI 23
#define PS2_SEL 5 //SS 5
#define PS2_CLK 18 //SLK 18
PS2X ps2x; // create PS2 Controller Class
//right now, the library does NOT support hot pluggable controllers, meaning
//you must always either restart your Arduino after you connect the controller,
//or call config_gamepad(pins) again after connecting the controller.
int error = -1;
byte type = 0;
byte vibrate = 0;
int tryNum = 1;
...
void ps2Init()
{
//added delay to give wireless ps2 module some time to startup, before configuring it
//CHANGES for v1.6 HERE!!! **************PAY ATTENTION*************
while (error != 0) {
delay(1000);// 1 second wait
//setup pins and settings: GamePad(clock, command, attention, data, Pressures?, Rumble?) check for error
error = ps2x.config_gamepad(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT, pressures, rumble);
Serial.print("#try config ");
Serial.println(tryNum);
tryNum ++;
}
Serial.println(ps2x.Analog(1), HEX);
type = ps2x.readType();
switch(type) {
case 0:
Serial.println(" Unknown Controller type found ");
break;
case 1:
Serial.println(" DualShock Controller found ");
break;
case 2:
Serial.println(" GuitarHero Controller found ");
break;
case 3:
Serial.println(" Wireless Sony DualShock Controller found ");
break;
}
}
void ps2Decode()
{
ps2x.read_gamepad(false, vibrate);
if(ps2x.ButtonPressed(PSB_BLUE))
motorMove(2);
if(ps2x.ButtonPressed(PSB_PINK))
motorMove(4);
if(ps2x.ButtonPressed(PSB_RED))
motorMove(6);
if(ps2x.ButtonPressed(PSB_GREEN))
motorMove(8);
if(ps2x.ButtonPressed(PSB_R1))
motorMove(9);
if(ps2x.ButtonPressed(PSB_R2))
motorMove(3);
}
每隔一定时间,需要读取PS2接收器的缓冲器,也即ps2Decode
。
4. 阿里云物联网平台相关
无论是主控板上的ESP32还是遥控板上的ESP8266,都接入了阿里云物联网。ESP32/ESP8266首先需要连接上WIFI,然后登录MQTT,再才能上传或获取相应数据。
下面是部分代码:
#include <WiFi.h>
#include <ArduinoJson.h>//json包
#include <PubSubClient.h>
...//wifi信息
#define WIFI_SSID "id"
#define WIFI_PASSWD "pws"
char* id="id"; //定义两个字符串指针常量
char* psw="pws";
...
//阿里云设备三元组,能够唯一确定设备
#define PRODUCT_KEY "a1***"
#define DEVICE_NAME "CAR2WD-ESP32"
#define DEVICE_SECRET "******"
//地区
#define REGION_ID "cn-shanghai"
/* 线上环境域名和端口号,不需要改 */
#define MQTT_SERVER PRODUCT_KEY ".iot-as-mqtt." REGION_ID ".aliyuncs.com"
#define MQTT_PORT 1883
#define MQTT_USRNAME DEVICE_NAME "&" PRODUCT_KEY
#define CLIENT_ID "CAR2WD-ESP32|securemode=3,signmethod=hmacsha1|"
#define MQTT_PASSWD "******"
#define ALINK_PDATA_FORMAT "{\"id\":%d,\"version\":\"1.0.0\",\"method\":\"user.p_data\",\"params\":%s}"
#define ALINK_TOPIC_PDATA "/" PRODUCT_KEY "/" DEVICE_NAME "/user/p_data"
#define ALINK_POST_FORMAT "{\"id\":%d,\"version\":\"1.0.0\",\"method\":\"thing.event.property.post\",\"params\":%s}"
#define ALINK_TOPIC_POST "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/event/property/post"
static WiFiClient espClient;
PubSubClient client(espClient);
...
//初始化wifi信息
const char* ip;
const char* ss = "0";
void wifiInit(char *ssid, char *passphrase)
{
WiFi.begin(ssid, passphrase);
delay(3000);
// 不论WIFI是否连上WiFi.status()都可能为255(WL_NO_SHIELD)
// 所以需要查看IP值
ip = WiFi.localIP().toString().c_str();
while (WiFi.status()!= WL_CONNECTED) {
WiFi.begin(ssid, passphrase);
delay(3000);
sprintf(str2, "WIFI status: %d %d", WiFi.status(), WL_CONNECTED);
sprintf(str3, "time:%d", millis());
drawoled("Connecting to WIFI...", str2, str3);
Serial.printf("Connecting to WiFi... %d %d \n",WiFi.status(),WL_CONNECTED);
if(ip[0] != ss[0])
break;
}
sprintf(str2, "IP: %s", (char *)(WiFi.localIP().toString().c_str()));
sprintf(str3, "Gateway: %s", (char *)(WiFi.gatewayIP().toString().c_str()));
drawoled("WIFI connected!", str2, str3, "Connecting to MQTT...","");
Serial.println("Connected to AP");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.print("Gateway IP address: ");
Serial.println(WiFi.gatewayIP());
Serial.print("espClient [");
client.setServer(MQTT_SERVER, MQTT_PORT); /* 连接WiFi之后,连接MQTT服务器 */
client.setCallback(callback);
}
void WIFICheckConnect()
{
while (WiFi.status()!= WL_CONNECTED) {
WiFi.begin(WIFI_SSID, WIFI_PASSWD);
delay(3000);
ip = WiFi.localIP().toString().c_str();
sprintf(str2, "WIFI status: %d %d", WiFi.status(), WL_CONNECTED);
sprintf(str3, "time:%d", millis());
drawoled("Connecting to WIFI...", str2, str3);
Serial.printf("Connecting to WiFi... %d %d \n",WiFi.status(),WL_CONNECTED);
if(ip[0] != ss[0])
break;
}
}
void mqttCheckConnect()
{
while (!client.connected())
{
Serial.println("Connecting to MQTT Server ...");
if (client.connect(CLIENT_ID, MQTT_USRNAME, MQTT_PASSWD))
{
Serial.println("MQTT Connected!");
}
else
{
sprintf(str1, "msgid:%d t:%d", msgid, millis());
sprintf(str2, "WIFI status: %d %d", WiFi.status(), WL_CONNECTED);
sprintf(str3, "time:%d", millis());
sprintf(str4, "MQTT Connect err: %d!", client.state());
drawoled(str1,str2,str3,str4);
Serial.print("MQTT Connect err:");
Serial.println(client.state());
delay(5000);
}
}
}
...
void mqttIntervalPost()
{
...
char param[64];
char jsonBuf[128];
boolean d;
// Data to ps2ctrl-esp8266
sprintf(param, "{\"BatteryVoltage\":%.2f}", vol);
sprintf(jsonBuf, ALINK_PDATA_FORMAT, msgid, param);
d = client.publish(ALINK_TOPIC_PDATA, jsonBuf);
Serial.println(jsonBuf);
Serial.println(d ? "publish:成功" : "publish:失败");
// Data to Aliyun IOT
sprintf(param, "{\"BatteryVoltage\":%.2f, \"Humidity\":%.1f, \"Temperature\":%.1f}", vol, h, t);
sprintf(jsonBuf, ALINK_POST_FORMAT, msgid, param);
d = client.publish(ALINK_TOPIC_POST, jsonBuf);
Serial.println(jsonBuf);
Serial.println(d ? "publish:成功" : "publish:失败");
...
}
StaticJsonDocument<200> doc;
void callback(char *topic, byte *payload, unsigned int length)
{
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
payload[length] = '\0';
Serial.println((char *)payload);
DeserializationError error = deserializeJson(doc, (char *)payload);
if (!error) //检查反序列化是否成功
{
// Read JSON
int code = doc["code"];
if(code!=0) // code: =0, empty;
return;
int cmdword = doc["params"]["cmdword"];
if(cmdword!=0) // cmdword: =0, empty;
motorMove(cmdword);
}
}
...
unsigned long lastMs = 0;
void loop(){
if (millis() - lastMs >= ptgap)
{
lastMs = millis();
WIFICheckConnect();
mqttCheckConnect();
/* 上报消息心跳周期 */
mqttIntervalPost();
}
// ps2Decode(); // ESP8266需要定时读取PS2接收器缓冲器
client.loop();
delay(50);
}
如果编译时遇到错误:
Connecting to MQTT Server ...
MQTT Connect err:2
需要修改库文件PubSubClient.h的内容
MQTT_MAX_PACKET_SIZE必须大于1024,MQTT_KEEPALIVE必须大于等于60
PubSubClient.h的位置在Arduino IDE 【文件】-【首选项】-【设置】-【项目文件夹位置】里面(即C:\Users\Administrator\Documents\Arduino\libraries\PubSubClient)。
5. 最后
以上是ESP32的主要代码,ESP8266的类似。
版权声明:本文为CSDN博主「iqiaoqiao」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/iqiaoqiao/article/details/122802852
暂无评论