赞
踩
选编译并下载固件(右箭头)
下载成功后按复位按钮运行程序
用 Arduino IDE 生成一个工程的 bin 文件,然后用 ESPFlashDownloadTool 下载固件。
先点导出 bin 文件
打开 ESPFlashDownloadTool ,选择刚导出的bin文件和bootloader , default文件,填写好地址和参数,点击下载。
Core 文件夹:乐鑫提供的 ESP32 底层内核文件,包括 gpio timer iic spi touch uarts 等外设驱动,还有二次封装好的 TCP UDP Server 等常用 arduino 库文件。
libraries 文件夹:包含各厂家的 arduino 例程,我们的例程文件夹是 ESP-32F
variants 文件夹:各种 esp32 开发板的引脚定义头文件 (如果需要添加的自己开发板,则需 要在该文件夹内加入自己开发板的引脚定义头文件,添加方法可以参考其他开发板的头文 件,依样画葫芦即可)
Tools 文件夹:esp32 sdk 和编译工具链
Boards.txt:定义开发板的各项参数,这些参数将会在 arduino ide 选择开发板型号和参数的 面板中体现出来
steup 函数相当于 main 函数 ,程序从这里开始
void setup() {
// put your setup code here, to run once:
}
Loop 函数相当予 while(1){} 函数,
void loop() {
// put your main code here, to run repeatedly:
}
delay(x); arduino 系统延时函数 延时 x 毫秒
rand() 随机数函数,rand()%2 代表 0-1 这两个数取随机数
void setup() {
// put your setup code here, to run once:
pinMode(32,OUTPUT);
pinMode(33,OUTPUT);
pinMode(27,OUTPUT);//IO27 IO32 IO33 三个引脚设置为输出模式
}
void loop() {
// put your main code here, to run repeatedly:
digitalWrite(32,rand()%2); //三个 LED 随机点亮,组成不同的颜色
digitalWrite(33,rand()%2);
digitalWrite(27,rand()%2);
delay(1000);//延时 1000ms
}
Arduino 串口通讯会用到 Stream 这个类,Stream 类是二进制数据或者字符串数据流传输的基础类,不能被直接调用,但可以被继承。
available()获取数据流中接收到的字节数,返回值是 int 类型。
read()获取数据流中第一个字节数据,获取数据后会清除当前字节数据。返回值是 读取数据字符的第一个字节(8bit)
peek()从数据流中读取当前的一个字节,不会清除数据流中当前字节数据
flush()清除数据流所有未向外发送的数据。返回bool 类型。
find() 从数据流中查找目标字符串,找到目标字符串后返回值 = true,超时则返回值 = false。
findUntil() 从数据流中读取目标字符串或者终止目标字符串,找到目标字符串后返回值 = true,超时则返回值 = false。
Serial 类 用于对串口数据流的读写。
String buf; char temp; void setup() { // put your setup code here, to run once: Serial.begin(115200); Serial.setTimeout(10);//设置串口接收超时时间 10ms (如果不明白可以改成 1000 ,用串 口助手看效果) Serial.println("Goouuu HelloWorld!"); } void loop() { // put your main code here, to run repeatedly: if(Serial.available()!=0)//如果接收缓冲区非空 { buf=Serial.readString();//将收到的数据以字符串形式存到 buf Serial.print(buf);//串口打印 buf } } } }
如图,串口正常打印输入信息。
ESP-32F 开发板上的触摸通道是用了 T0(IO4) 和 T2(IO2)
uint16_t touchRead(uint8_t pin); 获取某个通道采集的数值。
// Just test touch pin - Touch0 is T0 which is on GPIO 2. int T0_Cul=0; int T2_Cul=0; void LED_Init(void)//LED 初始化 { pinMode(33,OUTPUT); pinMode(27,OUTPUT); } void setup() { LED_Init(); Serial.begin(115200); Serial.println("ESP32 Touch Test"); } void Touch_Pad_Check(void) { Serial.print("T0_Value:"); Serial.println(touchRead(T0)); // get value using T0 T0_Cul=touchRead(T0); Serial.print("T2_Value:"); // get value using T2 Serial.println(touchRead(T2)); // T2_Cul=touchRead(T2); if(T0_Cul<=15)//通道采集数值低于 15 被认为按键按下 { digitalWrite(33,0);//点亮 LEDA } else if(T0_Cul>20)//通道采集数值高于 20 被认为按键被释放 { digitalWrite(33,1);//熄灭 LEDA } if(T2_Cul<=15) { digitalWrite(27,0); } else if(T2_Cul>20) { digitalWrite(27,1); } } void loop() { Touch_Pad_Check(); }
当我按住触摸按键 T1 不放时,T0 通 道输出值都是保持在 15 以下,这时候这个通道触发的阀值就很清楚了。此时LED点亮。
if(T0_Cul<=15)//通道采集数值低于 15 被认为按键按下
{
digitalWrite(33,0);//点亮 LEDA
}
hw_timer_t *timer=NULL;//创建一个定时器结构体 volatile SemaphoreHandle_t timerSemaphore;//创建一个定时器信号量 int time_count=0; portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; void IRAM_ATTR Timer_Hander() { portENTER_CRITICAL_ISR(&timerMux);//进入临界段 time_count++; portEXIT_CRITICAL_ISR(&timerMux);//退出临界段 xSemaphoreGiveFromISR(timerSemaphore, NULL);//释放一个二值信号量 timerSemaphore } void setup() { // put your setup code here, to run once: Serial.begin(115200); timerSemaphore=xSemaphoreCreateBinary();//定义信号量 timer = timerBegin(0, 80, true);//初始化定时器 0 80 分频 向上计数 // 配置定时器中断函数 timerAttachInterrupt(timer, &Timer_Hander, true); // Set alarm to call onTimer function every second (value in microseconds). // Repeat the alarm (third parameter) timerAlarmWrite(timer, 5000000, true);//每计数 5000000 次触发定时器中断 自动重载开启 // Start an alarm timerAlarmEnable(timer);//使能定时器函数 } void loop() { // put your main code here, to run repeatedly:收到定时器触发后置位的二值信号量后打印 计数值if (xSemaphoreTake(timerSemaphore,0) == pdTRUE){ portENTER_CRITICAL_ISR(&timerMux); Serial.println(millis());//打印系统已经运行了多少时间 Serial.println(time_count);//计数值 portEXIT_CRITICAL_ISR(&timerMux); } }
串口打印系统程序已经运行的时间和定时器计数的次数。
DHT11 输出两个字节湿度数据,两个字节温度数据 ,一个校验字节,共五个字节。
1.点击下拉箭头 新建标签,输入文件名 xxx.cpp 后确定。
在类实例化对象时自动执行,对类中的数据进行初始化。
构造函数可以从载,可以有多个, 但是只能有一个缺省构造函数。
构造函数必须和类同名 。
在撤销对象占用的内存之前,进行一些操作的函数。
析构函数不能被重载,只能有一个。
析构函数如果我们不写的话,C++ 会帮我们自动的合成一个,C++ 会自动的帮我们写一个析构函数。自动生成的析构函数可以很好的工作,但是一些重要的事迹, 就必须我们自己去写析构函数。
析构函数和构造函数是一对。构造函数用于创建对象,而析构函数是用来撤销对象。一个对象出生的时候,使用构造函数,死掉的时候,使用析构函数。
定义:
类名::方法名
void analogSetSamples(uint8_t samples); 设置分频 1-255
bool adcAttachPin(uint8_t pin); 设置 ADC 采集引脚
uint16_t analogRead(uint8_t pin); 读取 ADC 通道值
bool adcStart(uint8_t pin); 开始 ADC 采集
检测原理
传感器中心有个洞可以让空气自由流过,定向发射LED光,通过检测经过空气中灰尘折射过后的光线来判断灰尘的含量。
#include "Arduino.h" #define dustPin 35 //定义 adc 采集引脚 #define ledPower 21 //定义 led 发射引脚 int value; float dustVal=0; int delayTime=280; int delayTime2=40; float offTime=9680; void setup() { // put your setup code here, to run once: pinMode(ledPower,OUTPUT); adcAttachPin(dustPin); //设置 ADC 采集引脚 adcStart(dustPin); //开始 ADC 采集 Serial.begin(115200); } void loop() { // put your main code here, to run repeatedly: digitalWrite(ledPower,LOW); delayMicroseconds(delayTime); dustVal=analogRead(dustPin); // Serial.write(value>>8); Serial.write(value); delayMicroseconds(delayTime2); digitalWrite(ledPower,HIGH); delayMicroseconds(offTime); delay(1000); if (dustVal>36.455) Serial.println((float(dustVal/4096)-0.0356)*120000*0.035); }
引脚问题,需要拿个中介板焊到一起。
0.96 OLED 和开发板的连线图
VCC ----3.3V
GND----GND
SCL----- GPIO14
SDA---- GPIO15
#include "SSD1306.h" #include "images.h" SSD1306 oled(0x3c,15,14); //实例化 SSD1306 类 void drawCircle(void) { //画圆形 for (int16_t i=0; i<DISPLAY_HEIGHT; i+=2) { oled.drawCircle(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2, i); oled.display(); delay(10); } delay(1000); oled.clear(); //清屏 // This will draw the part of the circel in quadrant 1 // Quadrants are numberd like this: // 0010 | 0001 // ------|----- // 0100 | 1000 // oled.drawCircleQuads(DISPLAY_WIDTH/2,DISPLAY_HEIGHT/2,DISPLAY_HEIGHT/4,0b00000001); oled.display(); delay(200); oled.drawCircleQuads(DISPLAY_WIDTH/2,DISPLAY_HEIGHT/2,DISPLAY_HEIGHT/4,0b00000011); oled.display(); delay(200); oled.drawCircleQuads(DISPLAY_WIDTH/2,DISPLAY_HEIGHT/2,DISPLAY_HEIGHT/4,0b00000111); oled.display(); delay(200); oled.drawCircleQuads(DISPLAY_WIDTH/2,DISPLAY_HEIGHT/2,DISPLAY_HEIGHT/4,0b00001111); oled.display(); } void setup() { // put your setup code here, to run once: oled.init();//初始化 OLED oled.flipScreenVertically();// oled.setContrast(255);//设置对比度 255 drawCircle();//画动态圆形的函数 //oled.drawXbm(0,0, Logo_width,Logo_height, Logo_bits); oled.display();//显示内容 } void loop() { // put your main code here, to run repeatedly: }
错误1
解决:
安装ESP8266 and ESP32 Oled Driver for SSD1306 display
错误2
解决方法:
换一个安装路径。
仍存在此问题,未解决,没有images.h,但是路径中有呀,要再下载一个esp32-expressf-master,我虽然有,但是库中文件不全。
多次下载失败,以上例程未实现,少库,应该是master中文件不全,再下载。
以下例程都是此问题,均未实现。
如果是要打印字符串可以在主函数下添加如下代码
oled.setFont(ArialMT_Plain_16);//设置字体为 16 号
如果想变其他字体可以看下 OLEDDisplayFonts.h 这个文件,选择自己需要的字体。
oled.drawString(1,1,"Goouuu");//打印字符串
如果想打印一张位图 那么可以用这个函数
oled.drawXbm(0,0, Logo_width,Logo_height, Logo_bits);
图片取模过程如下:
1.先用美图秀秀,将图片尺寸强制变成 128x64 并保存为 png 格式。
2.用画图软件打开修改后的 png 图片设置为黑白点确定。
3.打开取模软件,调入黑白图像,点 c51 格式,然后把取到的数据复制到 arduino 里图像的数 组即可。
4.打开取模软件,调入黑白图像,点 c51 格式,然后把取到的数据复制到 arduino 里图像的数 组即可。
之前笔记更简单。
参考之前学习笔记
例程一:画线
#include"lcd.h"
#include"icon.h"
LCD lcd; //实例化这个类
void setup() {
// put your setup code here, to run once:
lcd.LCD_GPIOInit();
lcd.LCD_Init();
lcd.LCD_Clear(BLACK); //清屏幕,并把背景设为黑色
POINT_COLOR=BLUE;//设置画笔颜色蓝色
lcd.LCD_DrawLine(0,127,127,0); // 画两条直线
lcd.LCD_DrawLine(0,0,127,127); //
}
void loop() {
// put your main code here, to run repeatedly:
}
例程二:显示英文和中文字符
#include"lcd.h"
#include"icon.h"
LCD lcd; //实例化这个类
void setup() {
// put your setup code here, to run once:
lcd.LCD_GPIOInit();
lcd.LCD_Init();
lcd.LCD_Clear(BLACK); //清屏幕,并把背景设为黑色
POINT_COLOR=BLUE;//设置画笔颜色蓝色
lcd.Show_Str(40,25,BLUE,BLACK,"Goouuu",16,1);
lcd.Show_Str(32,50,BLUE,BLACK,"果 云 科 技 ",8,1);
}
void loop() {
// put your main code here, to run repeatedly:
}
扬声器就是通常我们说的音箱。可以播放各种声音,例如音乐。
蜂鸣器则是单纯只发出一种声音的报警装置。它会通过声音的长短来报告错误。
#include "Speaker.h"
#include "music_8bit.h"
SPEAKER Speaker;
void setup() {
// put your setup code here, to run once:
Speaker.begin(); //初始化
Speaker.setVolume(10); //设置音量为10
Speaker.playMusic(data, 22500); //播放 pcm 格式数据,并设定采样率
}
void loop() {
// put your main code here, to run repeatedly:
Speaker.update();
}
列出指定目录下的文件
#include "FS.h" #include "SD.h" #include "SPI.h" #include "Speaker.h" SPEAKER Speaker; /*---------------------------------------------------- 列出指定目录下的文件 -----------------------------------------------------*/ void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ Serial.printf("Listing directory: %s\n", dirname); File root = fs.open(dirname); if(!root){ Serial.println("Failed to open directory"); return; } if(!root.isDirectory()){ Serial.println("Not a directory"); return; } File file = root.openNextFile(); while(file){ if(file.isDirectory()){ Serial.print(" DIR : "); Serial.println(file.name()); if(levels){ listDir(fs, file.name(), levels -1); } } else { Serial.print(" FILE: "); Serial.print(file.name()); Serial.print(" SIZE: "); Serial.println(file.size()); } file = root.openNextFile(); } }
创建目录
void createDir(fs::FS &fs, const char * path){
Serial.printf("Creating Dir: %s\n", path);
if(fs.mkdir(path)){
Serial.println("Dir created");
} else {
Serial.println("mkdir failed");
}
}
移除目录
void removeDir(fs::FS &fs, const char * path){
Serial.printf("Removing Dir: %s\n", path);
if(fs.rmdir(path)){
Serial.println("Dir removed");
} else {
Serial.println("rmdir failed");
}
}
读取指定文件的内容
void readFile(fs::FS &fs, const char * path){ uint8_t buf[2]; uint16_t delay_interval = ((uint32_t)1000000/25000); Serial.printf("Reading file: %s\n", path); File file = fs.open(path); if(!file){ Serial.println("Failed to open file for reading"); return; } Serial.print("Read from file: "); while(file.available()){ buf[0]=file.read(); dacWrite(SPEAKER_PIN,buf[0]); delayMicroseconds(delay_interval-20); } file.close(); }
写入指定内容到指定文件
void writeFile(fs::FS &fs, const char * path, const char * message){ Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE); //打开指定的某个文件
if(!file){
Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)){
Serial.println("File written");
} else {
Serial.println("Write failed");
}file.close();
}
写入指定内容到指定文件,如果这个文件不存在,则创建一个新的指定名字的文件,再写入内容。
void appendFile(fs::FS &fs, const char * path, const char * message){ Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file){
Serial.println("Failed to open file for appending");
return;
}
if(file.print(message)){
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}file.close();
}
重命名文件
void renameFile(fs::FS &fs, const char * path1, const char * path2){ Serial.printf("Renaming file %s to %s\n", path1, path2);
if (fs.rename(path1, path2)) {
Serial.println("File renamed");
} else {
Serial.println("Rename failed");
}
}
删除指定文件
void deleteFile(fs::FS &fs, const char * path){
Serial.printf("Deleting file: %s\n", path);
if(fs.remove(path)){
Serial.println("File deleted");
} else {Serial.println("Delete failed");
}
}
读写文件测试
void testFileIO(fs::FS &fs, const char * path){ File file = fs.open(path); static uint8_t buf[512]; size_t len = 0; uint32_t start = millis(); uint32_t end = start; if(file){ len = file.size(); size_t flen = len; start = millis(); while(len){ size_t toRead = len; if(toRead > 512){ toRead = 512; } file.read(buf, toRead); len -= toRead; } end = millis() - start; Serial.printf("%u bytes read for %u ms\n", flen, end); file.close(); } else { Serial.println("Failed to open file for reading"); } file = fs.open(path, FILE_WRITE); if(!file){ Serial.println("Failed to open file for writing"); return; }size_t i; start = millis(); for(i=0; i<2048; i++){ file.write(buf, 512); } end = millis() - start; Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end); file.close(); } void setup(){ Serial.begin(115200); if(!SD.begin()){ //初始化 SD 卡 Serial.println("Card Mount Failed"); return; } uint8_t cardType = SD.cardType(); //读取 SD 卡类型 //判断 SD 卡类型 if(cardType == CARD_NONE){ Serial.println("No SD card attached"); return; } Serial.print("SD Card Type: "); if(cardType == CARD_MMC){ Serial.println("MMC"); } else if(cardType == CARD_SD){ Serial.println("SDSC"); } else if(cardType == CARD_SDHC){ Serial.println("SDHC"); } else { Serial.println("UNKNOWN"); } //读取 SD 卡尺寸 uint64_t cardSize = SD.cardSize() / (1024 * 1024); Serial.printf("SD Card Size: %lluMB\n", cardSize); listDir(SD, "/", 0);//列出目录 createDir(SD, "/mydir");//创建 1 个 mydir 的文件夹目录 listDir(SD, "/", 0);//列出目录 removeDir(SD, "/mydir");//删除 mydir 的文件夹目录 listDir(SD, "/", 2);//列出目录 writeFile(SD, "/hello.txt", "Hello ");//对 hello.txt 这个文件写内容 Hello appendFile(SD, "/hello.txt", "World!\n");//检测 hello.txt 这个是否存在,不存在则创建并写 //入内容,如果存在则直接写入内容 readFile(SD, "/hello.txt");//读取 hello.txt 文件 deleteFile(SD, "/foo.txt");//删除 foo.txt 文件 renameFile(SD, "/hello.txt", "/foo.txt");//把 hello.txt 这个文件重命名为 foo.txt readFile(SD, "/jqm.pcm");//读取 jqm.pcm 这个文件,并播放 } void loop(){ }
ESP32 作为 Station 模式,连接路由器,然后连接我们的公网测试服务器端,惊醒 tcp 通讯。
#include<WiFi.h> #include<WiFiMulti.h> WiFiMulti WiFiMulti; WiFiClient client; #define WIFISSID "yq" #define Password "goouuu8266" uint8_t test[6]={0x12,0x34,0x56,0x78,0x0c,0x0b};//6 个字节的测试数据 const uint16_t port = 8266;//主机端口 const char * host = "39.106.163.29"; // ip or dns 远程主机 ip void Connect_Router(void);//连接到你的路由器 void Connect_Host(void);//连接到远程服务器 void setup() { // put your setup code here, to run once: Serial.begin(115200); Connect_Router();//连接到你的路由器 }void loop() { // put your main code here, to run repeatedly: Connect_Host();//连接到远程服务器 // This will send the request to the server client.write(test,6);//发送 6 个字节数据 client.print("Hello_Goouuu!\r\n");//发送字符串 //read back one line from server String line = client.readStringUntil('\r');读取服务器发来的数据 Serial.println(line);//打印服务器发来的数据 client.stop();//关闭端口 Serial.println("closing connection"); Serial.println("wait 5 sec..."); delay(5000); }void Connect_Router(void) { // We start by connecting to a WiFi network WiFiMulti.addAP(WIFISSID,Password); Serial.println(); Serial.println(); Serial.print("Wait for WiFi... "); while(WiFiMulti.run() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); delay(500); }void Connect_Host(void) { if (!client.connect(host, port)) { Serial.println("connection failed"); Serial.println("wait 5 sec..."); delay(5000); return; } }
#include "WiFi.h" void setup() { Serial.begin(115200); // Set WiFi to station mode and disconnect from an AP if it was previously connected WiFi.mode(WIFI_STA);//设置为 STA 模式 WiFi.disconnect();//断开连接 delay(100); Serial.println("Setup done"); } void loop() { Serial.println("scan start"); // WiFi.scanNetworks will return the number of networks found int n = WiFi.scanNetworks();//获取可以正常连接的热点数量 Serial.println("scan done"); if (n == 0) { Serial.println("no networks found"); } else { Serial.print(n); Serial.println(" networks found"); for (int i = 0; i < n; ++i) { // Print SSID and RSSI for each network found Serial.print(i + 1); Serial.print(": "); Serial.print(WiFi.SSID(i));//打印热点 SSID Serial.print(" ("); Serial.print(WiFi.RSSI(i));//打印热点信号强度 Serial.print(")"); Serial.print(" ("); Serial.print(WiFi.channel(i));//打印热点信道 Serial.print(")"); Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN)?" ":"*"); delay(10); } } Serial.println(""); // Wait a bit before scanning again delay(5000); }
首先 WiFi 模块进入初始化状态,处于一个待收包状态。
手机点下配置键后,将已知 AP 的 SSID 和密码等信息,通过 UDP 广播发送出去。
WiFi 模块收到 UDP 包后解析得到 AP 的 SSID 和密码等信息后,切换到 STA 状态,对目标 AP 发起连接,连上目标 AP 后,配置就结束了。
#include "WiFi.h" void setup() { Serial.begin(115200); //Init WiFi as Station, start SmartConfig WiFi.mode(WIFI_AP_STA); WiFi.beginSmartConfig(); //Wait for SmartConfig packet from mobile Serial.println("Waiting for SmartConfig."); while (!WiFi.smartConfigDone()) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("SmartConfig received."); //Wait for WiFi to connect to AP Serial.println("Waiting for WiFi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("WiFi Connected."); Serial.print("IP Address: "); Serial.println(WiFi.localIP()); } void loop() { // put your main code here, to run repeatedly: }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。