每个列类都是通过指定屏幕大小(小 - sm、中 - md 或大 - lg)和列宽(值介于 1 到 12 之间的值,或者对于流体列可以省略它),用破折号分隔(例如,.col-sm-6 表示小屏幕上的 6 宽列)。使用这些,您可以通过使用多个类更改列的宽度来为不同的屏幕尺寸应用不同的布局。
【小屏幕】
【中、大屏幕】
mini.css 提供了卡片 (.card),这是帮助你组织 Web 应用内容的常规用途容器。卡片应与网格系统结合使用,这意味着它们需要放置在网格的行内才能正常工作。使用卡片创建的布局是响应式的,会根据屏幕上的可用大小重新对齐。
表单、标签和常见的 HTML5 输入元素已使用干净、现代的规则进行样式设置,从而提高了 Web 应用程序表单的可访问性和可用性。
更多特性请访问:https://minicss.us/
3.丰富的API:提供了丰富的 DOM 操作、事件处理、动画效果等功能。
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Zepto.js 示例</title>
<script src="https://cdn.jsdelivr.net/npm/zepto@1.2.0/dist/zepto.min.js"></script>
</head>
<body>
<button id="myButton">点击我</button>
<script>
$(document).ready(function() {
$('#myButton').on('click', function() {
alert('按钮被点击了!');
});
});
</script>
</body>
</html>
更多特性请访问:https://zeptojs.com/
本实例是一个配置WiFi的例子
初始化程序先检查preferences里有无wifi配置,若没有,则开启AP热点,启动配置服务,等待配置,用手机连接热点并访问配置,设置ssid和密码,若成功连接则保存信息到preferences内。
/***************************************************
** ESP32 开启热点配置WIFI信息
*
** author: 老张
** homesite: www.xpstem.com
****************************************************/
#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#include <Preferences.h>
//************** 常数数据 开始 **********************
// AP模式下信息
const IPAddress wifi_ap_ip(192,168,5,1);
const IPAddress wifi_ap_gateway(192,168,6,0);
const IPAddress wifi_ap_subnet(255,255,255,0);
String wifi_ap_ssid = "ssid-";
const char *wifi_ap_password = "abcd1234";
// mini.css v3.0.1(替代bootstrap) https://minicss.us/
const char *minicss = "代码过多,此处省略...";
// Zepto v1.2.0(替代jQuery)https://zeptojs.com/
const char *zeptojs = "代码过多,此处省略...";
//*************** 常数数据 结束 **********************
//************* 配置变量 开始 ************************
// WiFi Credentials
String ssid; // wifi账号
String password; // wifi秘密
//************* 配置变量 结束 *********************
//************* 运行时变量 开始 ********************
WebServer webServer(80);
Preferences prefs;
String chipId;
//************* 运行时变量 结束 *********************
const char *configHtml = "<html>\
<head>\
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>\
<meta name='viewport' content='width=device-width, initial-scale=1'>\
<link rel='stylesheet' href='/mini.css'>\
<script src='/zepto.js'></script>\
<script src='/layer.js'></script>\
<title>xxx配置</title>\
</head>\
<body>\
<h2>xxx配置</h2>\
<p></p>\
<form action='' method='post'>\
<fieldset>\
<legend>WiFi配置</legend>\
<div class='row responsive-label'>\
<div class='col-sm-12 col-md-3'><label for='ssid'>WiFi名称:</label></div>\
<div class='col-sm-12 col-md'><input type='text' style='width:90%' name='ssid'></div>\
</div>\
<div class='row responsive-label'>\
<div class='col-sm-12 col-md-3'><label for='password'>WiFi密码:</label></div>\
<div class='col-sm-12 col-md'><input type='text' style='width:90%' name='password'></div>\
</div>\
</fieldset>\
<p> </p>\
<input type='button' id='submit' class='primary' value=' 提交 '>\
</form>\
<script type='text/javascript'>\
$(document).ready(function() { \
$('#submit').on('click', function() { \
$.ajax({ \
url: 'config', \
type: 'post', \
data: $('#form').serialize(), \
success: function(resp) { \
alert(resp.msg); \
},\
error: function(xhr, status, error) { \
console.error('Error', error); \
} \
});\
});\
}); \
</script>\
</body>\
</html>";
/***********************************************************
*** 检查是否保存了配置
**********************************************************/
boolean comm_haveConfig() {
prefs.begin("config", true);
bool exist = prefs.isKey("ssid");
prefs.end();
return exist;
}
/***********************************************************
*** 保存配置
**********************************************************/
void conf_saveConfig() {
prefs.begin("config", false);
prefs.clear();
prefs.putString("ssid", ssid);
prefs.putString("password", password);
prefs.end();
Serial.println("配置已保存。");
}
/***********************************************************
*** 配置页提交处理
*** 1.连接WiFI
*** 2.硬件信息设定
**********************************************************/
void conf_handleConfig() {
if (webServer.method() != HTTP_POST) {
conf_handleNotFound();
return;
}
String staSsid = webServer.arg("ssid");
String staPassword = webServer.arg("password");
if (staSsid=="" || staPassword=="") {
// 未连接上。
webServer.send(200, "application/json", "{\"code\":-1,\"msg\":\"内容不能为空!\"}");
return;
}
// if ok
Serial.printf("connect wifi %s testing.", ssid.c_str());
WiFi.begin(staSsid, staPassword);
int n = 0;
// 最多等待60s
while (++n < 600) {
delay(100);
if (n % 30 == 0) { Serial.print("."); }
if (WiFi.status() == WL_CONNECTED) {
break; //已连接,中止等待
}
}
Serial.println("");
if (WiFi.status() != WL_CONNECTED) {
// 未连接上。
webServer.send(200, "application/json", "{\"code\":-2,\"msg\":\"无法连接WiFi,请检查配置!\"}");
return;
}
ssid = staSsid;
password = staPassword;
conf_saveConfig();
// 配置成功
webServer.send(200, "application/json", "{\"code\":0,\"msg\":\"产品配置成功,设备重启中...\"}");
delay(3000);
Serial.println("restarting...");
ESP.restart();
}
/***********************************************************
*** 404处理
**********************************************************/
void conf_handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += webServer.uri();
message += "\nMethod: ";
message += (webServer.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += webServer.args();
message += "\n";
for (uint8_t i = 0; i < webServer.args(); i++) {
message += " " + webServer.argName(i) + ": " + webServer.arg(i) + "\n";
}
webServer.send(404, "text/plain", message);
}
/********************************************************
*** 启动配置服务
********************************************************/
void conf_startConfigServer() {
wifi_ap_ssid = "ssid-" + chipId.substring(0, 3);
WiFi.softAPConfig(wifi_ap_ip, wifi_ap_gateway, wifi_ap_subnet);
if (!WiFi.softAP(wifi_ap_ssid.c_str(), wifi_ap_password)) {
Serial.println("Soft AP creation failed.");
while(1);
}
Serial.printf("Wifi AP %s on 192.168.6.1\n", wifi_ap_ssid.c_str());
webServer.on("/", [](){ webServer.send(200, "text/html", configHtml); });
webServer.on("/mini.css", [](){ webServer.send(200, "text/css", minicss); });
webServer.on("/zepto.js", [](){ webServer.send(200, "text/javascript", zeptojs); });
webServer.on("/config", conf_handleConfig);
webServer.onNotFound(conf_handleNotFound);
webServer.begin();
Serial.println("HTTP server started");
}
/***********************************************************
*** 获取芯片ID
**********************************************************/
String comm_getChipId() {
uint64_t number = ESP.getEfuseMac();
unsigned long long1 = (unsigned long)((number & 0xFFFF0000) >> 16);
unsigned long long2 = (unsigned long)((number & 0x0000FFFF));
return String(long1, HEX) + String(long2, HEX);
}
/***********************************************************
*** 读取配置
**********************************************************/
void main_loadConfig() {
prefs.begin("config", true);
ssid = prefs.getString("ssid");
password = prefs.getString("password");
prefs.end();
}
/***********************************************************
*** 连接到WiFi
**********************************************************/
void main_connectToWiFi() {
WiFi.begin(ssid, password);
Serial.print("正在连接 WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print(".");
}
Serial.print("\n连接到 WiFi, localIP: ");
Serial.println(WiFi.localIP());
}
/***********************************************************
*** 初始化设置
**********************************************************/
void setup() {
Serial.begin(115200);
Serial.println();
chipId = comm_getChipId();
Serial.printf("ChipId:%s\n", chipId);
if (!comm_haveConfig()) {
Serial.println("未发现配置,启动配置程序。");
WiFi.mode(WIFI_AP);
conf_startConfigServer();
Serial.println("等待配置...");
return;
}
Serial.println("发现配置,启动主程序。");
main_loadConfig();
main_connectToWiFi();
}
/***********************************************************
*** 主循环
**********************************************************/
void loop() {
if (!comm_haveConfig()) {
webServer.handleClient();
delay(10);
return;
}
Serial.println("主代码开始执行...");
// your main code.
delay(1000); //1s
}
代码中minicss和zeptojs字符数组内容请替换成对应文件内容。
运行效果
四位数码管是一种常见的LED显示器件,主要用于显示数字信息。
本文介绍如何使用Arduino-ESP32库中的API函数获取ESP32的芯片、RAM信息等,并提供了一个示例程序代码。
ESP32系列(包括ESP32-S3)搭载Xtensa双核处理器,默认情况下Arduino框架仅使用单核运行用户代码,通过多核编程,可以充分利用硬件资源来提升系统响应和性能。
ESP32 芯片有34个物理GPIO管脚。每个GPIO管脚都可用作一个通用IO,或连接一个内部的外设信号。IO_MUX ¹、RTC IO MUX 和GPIO交换矩阵用于将信号从外设传输至GPIO管脚。
ESP32Encoder库是一个利用ESP32脉冲计数器硬件外设实现高效旋转编码器读取的软件库。
本文对比了几款适合物联网开发的盒子硬件参数,供大家参考。
乐动掌控采用掌控板作为主控,塑胶一体式外壳,侧面和底面开具多个乐高扩展孔位,兼容乐高积木,可完成多种创意应用。
在MicroPython的ESP32库中,NVS类用于管理非易失性存储,支持 32 位有符号整数和 二进制blob。
Arduino-ESP32项目提供的Preferences库是一个专为ESP32设计的非易失性存储解决方案,它替代了传统的Arduino EEPROM库,提供了更强大、更可靠的数据存储功能。
本方案是一个基于ESP32-CAM + 物联网的图像采集方案。
ESP32-CAM与MicroPython结合可实现摄像头图像采集、视频流传输等功能,不过Micropython官方没有支持ESP32-CAM的固件,需要烧录第三方的专有固件。