去看小组作业页面。
我开始这次作业,是想改进农场的灌溉自动化。我们已经有了一台 ESP8266 在控制一个水泵和 4 个继电器,并监测水泵的电流消耗。问题是 ESP8266 和它的程序反应不灵敏,这让设置时间很费时。这是由于 ADC 引脚数量有限。农场上的一位志愿者 Shakeel 向我解释过,ESP8266 用它唯一的 ADC 引脚来监测 WiFi 连接,所以他写了一个程序,减少电流表采样的次数,好把这个引脚和 WiFi 共用。好吧,这确实能用,但让 WiFi 连接变得不稳定,所以我的挑战将是试着弄懂 ESP32,以便移植他的程序,同时完成这次作业。试试看!
另外我想指出的是,我会更专注于代码,因为我已经在其他周演示过电路板制作过程。还有,我完成作业方式的一个重大变化是:我会边学边做边记录,所以这次作业会更像一份日志,而不是教程。
我最初的目标是更好地理解 ESP32;然后,作为第二个目标,让它取代现在的灌溉控制;第三个目标是把这些知识应用到我孵化器的最终项目。

我先看了 techtutorialsx.com 这个网站。
正如页面上解释的,打开继电器的代码和我见过的其他 Arduino 代码很相似,那就来看看。
我会用 int pumprelayPin1 = 22; 把变量 pumprelayPin1 定义为引脚 22,它会把这个值存成整数。
pinMode(pumprelayPin1, OUTPUT); 把 pumprelayPin1 的引脚模式设为输出引脚,意思是它会主动输出,而不是像输入那样被动地监测信号。
digitalWrite(pumprelayPin1, LOW); 会用 LOW 把引脚设为关闭状态。
delay(4000); 会让程序等待 4 秒,也就是 4000 毫秒。
到目前为止我的代码是这样的:
int pumprelayPin1 = 22;
void setup() {
pinMode(pumprelayPin1, OUTPUT);
digitalWrite(pumprelayPin1, LOW);
}
void loop() {
digitalWrite(pumprelayPin1, HIGH);
delay(4000);
digitalWrite(pumprelayPin1, LOW);
delay(4000);
}
到目前为止,这段代码会启动,然后每隔 4 秒把继电器打开和关闭一次。
现在,第二部分,我想从实时时钟获取时间,以便在特定时间启动水泵。所以首先需要包含 RTC 时钟库。我用的是 DS1302 RTC 时钟芯片,所以这个库配上这段代码 #include <virtuabotixRTC.h> 应该就行了,根据库的文档在这里。
其次,我们需要用这段代码声明 RTC 时钟的引脚 virtuabotixRTC myRTC(5, 18, 19); 和 RtcDS1302<ThreeWire> Rtc(myWire);。这意味着当 ESP32 与实时时钟芯片通信时,它会用引脚 5 作为 CLK、18 作为 DAT、19 作为 RST。
警告: RtcDS1302<ThreeWire> Rtc(myWire); 来自另一个库(Makuna 的 Rtc 库,RtcDS1302.h),而 myWire 从未定义,所以这一行照原样是编译不过的。用这里使用的 virtuabotixRTC 库,virtuabotixRTC myRTC(5, 18, 19); 就够了。
现在,为了显示实时时钟的时间,我把它写在 void setup() {} 区域或 void loop() {} 区域里。前者只打印一次;后者会在我让它运行期间一直打印。当然,我们需要加上至少一分钟的延时,用 delay(60000);。变量的单位是毫秒,所以 1000 表示 1 秒,60000 表示 60 秒。
Serial.begin(115200);
myRTC.updateTime();
Serial.println();
如果这个 RTC 以前从未使用过,你可以运行一次下面的代码来设置时间:myRTC.setDS1302Time(00, 28, 16, 7, 23, 5, 2020);,前几个数字依次是秒、分、时(24 小时制)、星期几、月中的某天、月、年。(后来更正:星期几从 1 = 星期日开始计数,所以 2020 年 5 月 23 日星期六是 7,2020 年 5 月 24 日星期日是 1;原来的代码两个都写成了 6。)
到目前为止代码是这样的:
#include <virtuabotixRTC.h>
virtuabotixRTC myRTC(5, 18, 19);// (CLK,DAT,RST)
int pumprelayPin1 = 22;
void setup() {
Serial.begin(115200);
pinMode(pumprelayPin1, OUTPUT);
}
void loop() {
myRTC.updateTime();
Serial.print(myRTC.hours);
Serial.print(":");
Serial.print(myRTC.minutes);
delay(58000);
digitalWrite(pumprelayPin1, HIGH);
delay(1000);
digitalWrite(pumprelayPin1, LOW);
delay(1000);
}
到目前为止还没有逻辑测试:代码每分钟显示一次时间,并打开和关闭继电器。所以,为了加上逻辑测试,我们需要 if 语句。它会检查某个条件是否为真,然后执行程序里接下来的内容。
摘自 Arduino 参考文档:
if (condition) {
//statement(s)
}
所以,为了检查时间并打开我的继电器,我会试着这样写:if ((myRTC.hours) == 15 && (myRTC.minutes) == 0) {digitalWrite(pumprelayPin1, HIGH);}
要关闭它,代码会是这样:if ((myRTC.hours) >= 15 && (myRTC.minutes) >= 1) {digitalWrite(pumprelayPin1, LOW);}
我的代码现在是这样:
//libraries
#include <virtuabotixRTC.h>
//Settings
virtuabotixRTC myRTC(5, 18, 19);// (CLK,DAT,RST)
int pumprelayPin1 = 22;
//run once
void setup() {
Serial.begin(115200);
myRTC.setDS1302Time(50, 15, 16, 1, 24, 5, 2020); // sets seconds, minutes, hours (24h mode), day of the week, day, month, year) comment after first compile
pinMode(pumprelayPin1, OUTPUT);
}
//run in loop
void loop() {
myRTC.updateTime();//updates time
Serial.print("Current Time: ");
Serial.print(myRTC.hours);
Serial.print(":");
Serial.print(myRTC.minutes);
Serial.print(":");
Serial.print(myRTC.seconds);
Serial.println();
delay (1000);
//condition (logic test)
if ((myRTC.minutes) == 16) digitalWrite(pumprelayPin1, HIGH);
if ((myRTC.minutes) >= 17) digitalWrite(pumprelayPin1, LOW);
}
这是它在 ESP32 开发板上的运行情况:
这块板我至少需要 4 个数字引脚,如果以后想测量水泵的电流,还需要一个模拟引脚。所以我认为 ATtiny44 就足够合适了。ESP32 我会留到网络周再用 ;-)。另外,我的 ESP32 SMD 元件还没到;我觉得是因为 COVID-19 导致供应链中断。所以我才用手头已有的 ESP32 开发板做实验。

有了这个,我会修改我在输入设备周做的 tiny45 板,再加一个排针,方便编程和串口监视,并把所有引脚都引出来,让这块板尽可能模块化。
我不会详细讲 Eagle 设计或铣削,因为我在输入设备周已经做过了。我只讲我可能没用过的命令,比如 replace,然后放几张主图和测试。
那就从重新设计开始吧!
这些是板的原理图和布局:
电路板布局
接下来,我运行 ULP pcb-gcode,就像输入设备里解释的那样。
G 代码隔离走线可视化
接下来,我用 Autoleveller 这个程序,也是在输入设备里解释过的,然后得到一份根据空白电路板的不平整做了调整的 G 代码。
Autoleveller 输出
铣削电路板
铣好的电路板
铣好的电路板
焊上元件后的 ATtiny44 板是这样的。
焊好元件的板
现在电路板做好了,我改代码让它在 ATtiny44 上运行。一个值得注意的地方是,ATtiny44 需要软件串口库,我用这段代码引入它 #include <SoftwareSerial.h>。还有两件事让串口工作:库需要知道 RX 和 TX 是哪些引脚,SoftwareSerial Monitor(1, 0);;在 void setup() {} 里,我用 Monitor.begin(115200); 代替通常的 Serial.begin(115200); 来做串口监视器的初始化;最后,在 void loop() {} 里,每次我想让串口打印东西,都得用 Monitor.print(); 代替通常的 Serial.print();。
最后我的测试代码是这样的:
//libraries
#include <virtuabotixRTC.h>
#include <SoftwareSerial.h>
//Settings
virtuabotixRTC myRTC(3, 8, 7);// (CLK,DAT,RST)
int pumprelayPin1 = 2;
SoftwareSerial Monitor(1, 0);
//run once
void setup() {
Monitor.begin(115200);
myRTC.setDS1302Time(50, 15, 16, 1, 24, 5, 2020); // sets seconds, minutes, hours (24h mode), day of the week, day, month, year) comment after first compile
pinMode(pumprelayPin1, OUTPUT);
}
//run in loop
void loop() {
myRTC.updateTime();//updates time
Monitor.print("Current Time: ");
Monitor.print(myRTC.hours);
Monitor.print(":");
Monitor.print(myRTC.minutes);
Monitor.print(":");
Monitor.print(myRTC.seconds);
Monitor.println();
delay (1000);
//condition (logic test)
if ((myRTC.minutes) == 16) digitalWrite(pumprelayPin1, HIGH);
if ((myRTC.minutes) >= 17) digitalWrite(pumprelayPin1, LOW);
}
警告: 在跑内部 8 MHz 振荡器的 ATtiny44 上,115200 波特的 SoftwareSerial 不可靠(时序误差会让字符乱掉)。用 Monitor.begin(9600); 并把串口监视器设为 9600,这才是安全的速度。
现在来编程吧!想看不用 Arduino IDE 的另一种方法,请看嵌入式编程。
USBasp
用 USBasp 配合 Arduino 给 ATtiny44 板编程。
FabISP
用我做的 FabTinyISP 或 USBtinyISP 配合 Arduino 给 ATtiny44 板编程也没问题。唯一不方便的是得给目标板供电。
先打开 Arduino IDE,然后在 Tools 里选择板子,我这里是 ATtiny24/44/84。接下来在 Processor 里,我选择 ATtiny44。

接下来,选择时钟。因为我没有用外部晶振,所以我选了“Internal 8MHz”。

接下来,到 Programmer:“USBasp”,或者 FabISP 用“USBtiny”。

下面的视频里,我展示用 FabISP 编程的过程。
想看全分辨率的视频,请看 YouTube
这个视频里,我展示用 USBasp 编程的过程。
想看全分辨率的视频,请看 YouTube
我可以展示 ATtiny44 控制一个继电器,在程序设定的特定时间打开一台压缩机。
想看全分辨率的视频,请看 YouTube
主图
板子的主图
以后要看看 millis 的用法。