arduino编程代码结构
void setup() {
// 这里开始写初始化代码,只会执行一次
}
void loop() {
//这里写运行代码,重复执行
}
//可以看成如下代码
void main(){
watchdogEnable();//启动看门狗
setup();//初始化函数
while(1){
loop();//业务代码函数
}
}
1.在ESP8266 Arduino编程中,默认会开启看门狗功能,也就是对应伪代码的watchdogEnable(),所以我们一般需要关掉这个功能。
2.setup()方法:初始化函数,只会运行一次,所以一般情况下,我们都会在这里配置好初始化参数,比如IO口模式、串口波特率设置等
3.loop()方法:不断重复执行,这里编写我们的业务代码,同时要注意执行喂狗操作。
arduino的延时
时间控制,基本上可以说存在于每一个项目代码中。目前在Arduino中跟时间控制有关的方法包括以下几个:
delay(ms)
暂停一个给定的毫秒数的时间间隔。
delayMicroseconds(us)
暂停一个给定的微秒数的时间间隔。
millis()
返回重启(reset)后所经过的毫秒数。
micros()
返回重启(reset)后所经过的微秒数
提示:通常,我们控制LED灯闪烁都会加上一个delay延时来达到切换亮灭时间长度。但是delay有个缺点就是:在给定的时间间隔内是不能做其他操作,这样对于一些需要响应按键操作的场景就不适用了。那么有没有什么办法既能延时又能不影响其他操作呢?当然,这就是millis()的妙用,通过获取两个时间点的毫秒数,然后计算它们的差值,差值时间间隔内是可以执行其他操作的。
管脚映射图:
NodeMcu上的CLK、SD0、CMD、SD1、SD2引脚,是用于连接外接flash芯片,不应该用于连接其他模块,悬空即可,以防程序崩溃。
下面是管脚介绍
NodeMCU的引脚名称 | ESP8266内部GPIO引脚号 | 可复用功能 | 备注 |
---|---|---|---|
D0 | GPIO16 | 无 | 可用,只能用作GPIO读/写,不支持特殊功能 |
D1 | GPIO5 | I2C总线的SCL | 可用 |
D2 | GPIO4 | I2C总线的SDA | 可用 |
D3 | GPIO0 | 无 | 不可用,烧录固件或者运行模式控制端口 |
D4 | GPIO2 | Serial1的TX | Serial1没有RX |
D5 | GPIO14 | SPI总线的SCLK | 可用 |
D6 | GPIO12 | SPI总线的MISO | 可用 |
D7 | GPIO13 | SPI总线的MOSI、Serial的RX | 可用 |
D8 | GPIO15 | SPI总线的CS、Serial的TX | 可用 |
D9 | GPIO3 | Serial的RX | 可用 |
D10 | GPIO1 | Serial的TX | 可用 |
SD2 | GPIO9 | 无 | 尽量不用 |
SD3 | GPIO10 | 无 | 尽量不用 |
从上面表格可以看出,我们大约11个GPIO引脚可用。而11个中的2个引脚通常被保留用于RX和TX,以便进行串口通信。因此最后,只剩下8个通用I / O引脚,即D0到D8(除开D3特殊用途)。
Arduino中的引脚号直接与ESP8266 GPIO的引脚号对应通信。pinMode/digitalRead/digitalWrite函数不变,所以要读取GPIO2,可调用digitalRead(2)。除了D0可以设置为INPUT(输入)、OUTPUT(输出)或者INPUT_PULLDOWN(输入,默认下拉,也就是低电平),剩余的数字IO引脚可以设置为INPUT(输入)、OUTPUT(输出)或者INPUT_PULLUP(输入,默认上拉,也就是高电平)。
先来一个简单的IO口操作:
(在面包板上看了一下效果,可以使用)
void setup() {
pinMode(D1, OUTPUT); // 初始化D1引脚为输出引脚
}
void loop() {
digitalWrite(D1, LOW); // 亮灯
delay(1000); // 延时1s
digitalWrite(D1, HIGH);// 灭灯
delay(1000); // 延时1s
}
中断功能
该功能用于在将指定引脚设置为响应中断。
1.函数: attachInterrupt(pin, function, mode);
参数:
pin:要设置中断编号,注意,这里不是引脚编号。
function:中断发生时运行的函数, 这个函数不带任何参数,不返回任何内容。
Interrupt type/mode:它定义中断被触发的条件方式。
CHANGE:改变沿,引脚电平从低变为高或者从高变为低时触发中断。
RISING:上升沿,引脚电平从低变为高时触发中断。
FALLING:下降沿,引脚电平从高变为低时触发中断。
返回值: 无;
该功能用于禁用指定GPIO引脚上的中断。
2.函数: detachInterrupt(pin)
参数:
pin:要禁用的中断的GPIO引脚。
返回值: 无;
3.digitalPinToInterrupt()
该功能用于获取指定GPIO引脚的中断号。
函数: digitalPinToInterrupt(pin)
参数:
pin:要获取中断号的GPIO引脚。
返回值: 中断号;
这里实现一个例子:
将NodeMcu的D2引脚设置为上升沿中断。在D2上外接一个按键,按键通过电阻下拉到地。当发生中断的时候,我们在串口监视器上打印“Hello ESP8266”。
这个也比较简单
void setup() {
Serial.begin(115200);//设置串口波特率
attachInterrupt(digitalPinToInterrupt(D2), InterruptFunc, RISING);//设置中断号、响应函数、触发方式
}
void loop() {
}
/**
* 中断响应函数
*/
void InterruptFunc(){
Serial.println("Hello ESP8266");
}
模拟输入(ADC)
学过模拟电路或者数字电路的人都会听过ADC,它又叫做模数转换器,用于将模拟信号转换成可视化的数字形式。ESP8266具有内置的10位ADC,只有一个ADC通道,即只有一个ADC输入引脚可读取来自外部器件的模拟电压。
ESP8266上的ADC通道和芯片供电电压复用,也就是说我们可以将其设置为测量系统电压或者外部电压。
analogRead(A0),用于读取施加在模块的ADC引脚上的外部电压;
输入电压范围:0 - 1.0V之间;由于ADC具有10位分辨率,因此会给出0-1023的值范围;
注意:为了支持外部电压范围(0-3.3v),NodeMcu做了一个电阻分压器,而且他不需要换比例,里面会自己算好然后输出。
比如下面我们测量外部电压:
void setup() {
Serial.begin(115200);//配置波特率
}
void loop() {
Serial.print("ADC Value: ");
Serial.println(analogRead(A0));//输出0-1023 对应 外部输入电压 0-1.0v
//延时1s
delay(1000);
}
我们还可以测量系统的电压:
相关方法
ESP.getVcc(),读取NodeMCU模块的VCC电压,单位是mV;
注意点
ADC引脚必须保持悬空;在读取VCC电源电压之前,应更改ADC模式以读取系统电压。
要ADC_MODE(mode)在#include行后面改变ADC模式。
模式是ADC_TOUT(对于外部电压),ADC_VCC(对于系统电压)。默认情况下,它读取外部电压。
具体代码如下:
extern "C" ADC_MODE(ADC_VCC);//设置ADC模式为读取系统电压
//意思是声明一个非C++函数
//这里注意加上extern "C" ,不然会报错。
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.print("ESP8266当前系统电压(mV): ");
Serial.println(ESP.getVcc());
delay(1000);
}
还可以模拟输出(pwm)
mode mcu的pwm引脚:
D1,D2,D3,D4,D5,D6,D7,D8,RX,TX都可以作为pwm引脚
注意:基本上数字IO都可以作为PWM复用引脚,除了D0。不过需要注意的是,D3尽量不用,它内部连接ESP8266 GPIO0。
与pwm有关的系统函数:
1.analogWrite()
该功能用于在指定的引脚上启用软件PWM。
函数: analogWrite(pin,val)
参数:
pin:要启用软件PWM的GPIO引脚。
val:数值,一般在0到PWMRANGE范围,默认PWMRANGE是1023。
返回值: 无;
注意点:
analogWrite(pin, 0)用于禁用指定引脚上的PWM。
2.analogWriteRange()
该功能用于改变PWMRANGE数值。
函数: analogWriteRange(new_range)
参数:
new_range:新的PWMRANGE数值。
返回值: 无;
注意点:
可以理解为PWM精度范围。同样的PWM频率下,默认占空数值0-123。如果你改变PWMRANGE为2047,那么占空数值就变成0-2047。精度高了一倍。
3.analogWriteFreq()
该功能用于改变PWM频率。
函数: analogWriteFreq(new_frequency)
参数:
new_frequency:新PWM频率,默认是1kHZ。
返回值: 无;
LED呼吸灯例子:
#define PIN_LED D6
void setup() {
// 这里开始写初始化代码,只会执行一次
pinMode(PIN_LED,OUTPUT);
analogWrite(PIN_LED,0);
}
void loop() {
//这里写运行代码,重复执行
for(int val=0;val<1024;val++){
//占空比不断增大 亮度渐亮
analogWrite(PIN_LED,val);
delay(2);
}
for(int val=1023;val>=0;val--){
//占空比不断变小 亮度渐暗
analogWrite(PIN_LED,val);
delay(2);
}
}
串口通信(Serial)
ESP8266的串口通信与传统的Arduino设备完全一样。除了硬件FIFO(128字节用于TX和RX)之外,硬件串口还有额外的256字节的TX和RX缓存。发送和接收全都由中断驱动。当FIFO/缓存满时,write函数会阻塞工程代码的执行,等待空闲空间。当FIFO/缓存空时,read函数也会阻塞工程代码的执行,等待串口数据进来。
NodeMcu上有两组串口,Serial和Serial1。
Serial使用UART0,默认对应引脚是GPIO1(TX)和GPIO3(RX)。在Serial.begin执行之后,调用Serial.swap()可以将Serial重新映射到GPIO15(TX)和GPIO13(RX)。再次调用Serial.swap()将Serial重新映射回GPIO1和GPIO3。不过,一般情况下,默认就好。
串口映射例子:
void setup() {
// 这里开始写初始化代码,只会执行一次
Serial.begin(115200);
Serial.println("GPIO1(TX),GPIO3(RX)");
//调用映射方法
Serial.swap();
Serial.println("GPIO15(TX),GPIO13(RX)");
//重新映射回来
Serial.swap();
Serial.println("GPIO1(TX),GPIO3(RX)");
}
void loop() {
//这里写运行代码,重复执行
}
//Serial1使用UART1,默认对应引脚是GPIO2(TX)。
//Serial1不能用于接收数据,因为它的RX引脚被用于flash芯片连接。
//要使用Serial1,请调用Serial.begin(baudrate)。代码如下:
void setup() {
// 这里开始写初始化代码,只会执行一次
Serial.begin(115200);
Serial.println("Hello Serial");
Serial1.begin(115200);
Serial1.println("Hello Serial1");
}
void loop() {
//这里写运行代码,重复执行
}
默认情况下,当调用Serial.begin后,将禁用WiFi库的诊断输出。要想再次启动调试输出,请调用Serial.setDebugOutput(true)。要将调试输出映射到Serial1时,需要调用Serial1.setDebugOutput(true)。
调用Serial.setRxBufferSize(size_t size)允许定义接收缓冲区的大小,默认值是256(缓冲区也是使用内存,意味着不能一味地去增大这个值)。
Serial和Serial1对象都支持5,6,7,8个数据位,奇数(O)、偶数(E)和无(N)奇偶校验,以及1或者2个停止位。要设置所需的模式,请调用Serial.begin(baudrate, SERIAL_8N1), Serial.begin(baudrate, SERIAL_6E2)等。
Serial和Serial1都实现了一种新方法用来获取当前的波特率设置。要获取当前的波特率,请调用Serial.baudRate(),Serial1.baudRate()。代码如下:
void setup() {
// 这里开始写初始化代码,只会执行一次
// 设置当前波特率为57600
Serial.begin(57600);
// 获取当前波特率
int br = Serial.baudRate();
// 将打印 "Serial is 57600 bps"
Serial.printf("Serial is %d bps", br);
}
void loop() {
//这里写运行代码,重复执行
}
一般来说,串口通信用在两个方面:
1.与外围串口设备传输数据,比如蓝牙模块、Arduino等等;
2.开发过程中用来调试代码,通过串口输出Debug信息了解程序运行信息。例程如下:
#include <ESP8266WiFi.h>
#define AP_SSID "xxxxx" //这里改成你的wifi名字
#define AP_PSW "xxxxx"//这里改成你的wifi密码
//以下三个定义为调试定义
#define DebugBegin(baud_rate) Serial.begin(baud_rate)
#define DebugPrintln(message) Serial.println(message)
#define DebugPrint(message) Serial.print(message)
void setup(){
//设置串口波特率,以便打印信息
DebugBegin(115200);
//延时2s 为了演示效果
delay(2000);
DebugPrintln("Setup start");
//启动STA模式,并连接到wifi网络
WiFi.begin(AP_SSID, AP_PSW);
DebugPrint(String("Connecting to ")+AP_SSID);
//判断网络状态是否连接上,没连接上就延时500ms,并且打出一个点,模拟连接过程
//笔者扩展:加入网络一直都连不上 是否可以做个判断,由你们自己实现
while (WiFi.status() != WL_CONNECTED){
delay(500);
DebugPrint(".");
}
DebugPrintln("");
DebugPrint("Connected, IP address: ");
//输出station IP地址,这里的IP地址由DHCP分配
DebugPrintln(WiFi.localIP());
DebugPrintln("Setup End");
}
void loop() {
}
这里感谢一下博哥写的博客,本笔记都是参考他的。