大家好,我是Zhou
这次Funpack3-5活动给大家带来的是,基于Arduino UNO R4 WiFi的远程灯光控制和联网时钟设计。
Arduino UNO R4 WiFi 将瑞萨电子的 RA4M1 微处理器与乐鑫的 ESP32-S3 相结合,为创客打造了一款一体化工具,具有增强的处理能力和多样化的全新外设。凭借其内置的 Wi-Fi® 和蓝牙®功能,UNO R4 WiFi 使制造商能够探索无限的创意可能性。此外,这款多功能板拥有方便的板载 12x8 LED 矩阵和 Qwiic 连接器,为各个级别的创客提供了无与伦比的灵活性和可能性。
电路板上的 MCU 是高性能的 Renesas RA4M1(Arm® Cortex®-M4),具有 48 MHz 时钟速度、32 kB SRAM 和 256 kB 闪存。 UNO R4 WiFi 还配备了用于连接 Wi-Fi®/Bluetooth® 的 ESP32-S3,也可通过特定的接头对其进行单独编程。
本次活动我选择完成的是任务一,同时自由发挥完成了可视化联网时钟的设计
所连接的WiFi应为2.4G频段
任务1:点灯!通过网络连接到智能云端,尝试将设备模拟成可以控制的灯,远程端发送指令,将灯光开启关闭,或调整灯光的亮度,0到90%时,矩阵亮起逐渐变大的范围,90%以上时,灯板显示出太阳的图标
想要实现这个设计,我们需要将任务进行拆分:
- 智能云端
- 矩阵显示
矩阵显示又可以细化为:
- 点亮不同数量LED
- 太阳图案显示
我们需要声明以下头文件:
#include "WiFiS3.h"
#include "arduino_secrets.h"
#include "array.h"
#include "Arduino_LED_Matrix.h"
其中 "WiFiS3.h" 和 "Arduino_LED_Matrix.h" 是官方库的头文件
"array.h"是我定义的一个头文件,用于存储LED数组,如显示太阳图标:
uint8_t frame1[8][12]={
{0,0,1,0,0,1,1,0,0,1,0,0},
{1,0,0,1,0,0,0,0,1,0,0,1},
{0,0,0,0,0,1,1,0,0,0,0,0},
{0,0,1,0,1,0,0,1,0,1,0,0},
{0,0,1,0,1,0,0,1,0,1,0,0},
{0,0,0,0,0,1,1,0,0,0,0,0},
{1,0,0,1,0,0,0,0,1,0,0,1},
{0,0,1,0,0,1,1,0,0,1,0,0},
};
"arduino_secrets.h"是官方例程中用到的一个统一SSID和密码的头文件,方便用户测试不同例程,免去了删除例程头文件声明和添加SSID、密码的步骤。因为程序参考例程设计,这里我进行了保留:
//arduino_secrets.h header file
#define SECRET_SSID "yournetwork"
#define SECRET_PASS "yourpassword"
接下来声明一个 ArduinoLEDMatrix 类:
ArduinoLEDMatrix matrix;
存储 arduino_secrets.h 中的SSID和密码,声明网络密钥索引号(仅WEP需要),声明两个标志位用于存储矩阵数组的行列信息:
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;
int keyIndex = 0; // 网络密钥索引号(仅WEP需要)
int num1;
int num2;
声明单颗LED引脚、WiFi模块的状态,同时在端口80上创建一个服务器:
int led = LED_BUILTIN; // 连接LED的引脚
int status = WL_IDLE_STATUS;
WiFiServer server(80); // 在端口80上创建一个服务器
处理客户端发送的HTTP请求,并根据请求内容生成相应的HTML响应
实现在网页创建一个调节亮度的滑块:
if (c == '\n') {
if (currentLine.length() == 0) {
// 发送响应:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println();
client.print("<p style=\"font-size:5vw;\">Num Choose</p>");
client.print("<input type='range' min='0' max='100' value='50' class='slider' id='myRange' 'updateSliderValue()'>");
client.print("");
client.print("<br><br>Current Value: <span id='demo'></span>");
client.print("");
client.println();
// 退出while循环:
break;
} else { // 如果收到换行符,则清除currentLine:
currentLine = "";
}
再是根据不同情况判断LED矩阵应该如何显示:
if (currentLine.endsWith("GET /B?val=100")) {
digitalWrite(led, HIGH); // GET /B?val=100打开LED
matrix.renderBitmap(frame1, 8, 12);
} else if (currentLine.endsWith("GET /B?val=0")) {
digitalWrite(led, LOW); // GET /B?val=0关闭LED
matrix.renderBitmap(frame0, 8, 12);
} else if (currentLine.startsWith("GET /B?val=")) {
int val = currentLine.substring(11).toInt(); // 提取val后面的值
analogWrite(led, map(val, 0, 100, 0, 255)); // 将值映射到PWM范围并设置LED亮度
if(val >= 90){matrix.renderBitmap(frame1, 8, 12);}
else {
for(int m = 0; m < 8; m++){
for(int n = 0; n < 12; n++){
frame2[m][n] = 0;
}
}
num1 = val / 12;
num2 = val % 12;
for(int m = 0; m <= num1; m++){
for(int n = 0; n <= 11; n++){
if(m == num1 & n == num2) {break;}
frame2[m][n] = 1;
}
}
matrix.renderBitmap(frame2, 8, 12);
}
以上即是主要代码段的讲解,使用时先连接开发板创建的热点,浏览器访问192.48.56.2,即可通过滑块控制LED矩阵了:
实际效果如下:
自由发挥:通过LED矩阵显示从NTP服务器获取到的时间信息,包括年、月、日、时、分、秒,同时约每12分钟会自动校时一次
想要实现这个设计,我们需要将任务进行拆分:
- NTP校时
- 矩阵显示
参考NTP例程,我们需要声明以下头文件:
// Include the RTC library
#include "RTC.h"
//Include the NTP library
#include <NTPClient.h>
#if defined(ARDUINO_PORTENTA_C33)
#include <WiFiC3.h>
#elif defined(ARDUINO_UNOWIFIR4)
#include <WiFiS3.h>
#endif
#include <WiFiUdp.h>
矩阵显示使用了官方提供的滚动显示例程,声明以下头文件:
// To use ArduinoGraphics APIs, please include BEFORE Arduino_LED_Matrix
#include "ArduinoGraphics.h"
#include "Arduino_LED_Matrix.h"
添加自己WiFi的SSID和密码:
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = ""; // your network SSID (name)
char pass[] = ""; // your network password (use for WPA, or use as key for WEP)
setup()函数中我们需要进行以下操作:
初始化串口通信,波特率为9600:
Serial.begin(9600);
while (!Serial);
连接到WiFi和RTC模块。调用自定义函数连接到WiFi网络,初始化RTC模块初始化NTP客户端,更新NTP客户端的时间:
connectToWiFi();
RTC.begin();
Serial.println("\nStarting connection to server...");
timeClient.begin();
timeClient.update();
获取并设置时间。
因为我们使用北京时间,所以定义时区偏移量为8。打印调整后的Unix时间戳到串口、将Unix时间转换为RTC时间对象并设置:
auto timeZoneOffsetHours = 8;
auto unixTime = timeClient.getEpochTime() + (timeZoneOffsetHours * 3600);
Serial.print("Unix time = ");
Serial.println(unixTime);
RTCTime timeToSet = RTCTime(unixTime);
RTC.setTime(timeToSet);
从读取RTC并串口打印时间:
RTCTime currentTime;
RTC.getTime(currentTime);
Serial.println("The RTC was just set to: " + String(currentTime));
初始化LED矩阵显示屏,设置绘图颜色为白色、文本字体、起始位置,并显示文本:
matrix.begin();
matrix.beginDraw();
matrix.stroke(0xFFFFFFFF);
// add some static text
// will only show "UNO" (not enough space on the display)
const char text[] = "UNO r4";
matrix.textFont(Font_4x6);
matrix.beginText(0, 1, 0xFFFFFF);
matrix.println(text);
matrix.endText();
matrix.endDraw();
}
loop()函数中我们需要进行以下操作:
同上获取当前时间并设置RTC模块,计数到一定值时才校准时间:
RTC.getTime(currentTime);
if (i == 100)
{
RTCTime timeToSet = RTCTime(unixTime);
RTC.setTime(timeToSet);
// Retrieve the date and time from the RTC and print them
Serial.println("The RTC was just set to: " + String(currentTime));
i = 0;
}
开始绘制操作并设置文本滚动速度:
matrix.beginDraw();
matrix.stroke(0xFFFFFFFF);
matrix.textScrollSpeed(40);
添加并显示滚动文本:
const char* text = (" " + String(currentTime) + " ").c_str();
matrix.textFont(Font_5x7);
matrix.beginText(0, 1, 0xFFFFFF);
matrix.println(text);
matrix.endText(SCROLL_LEFT);
结束绘制操作并增加计数器:
matrix.endDraw();
i++;
delay(2000);
以上即是主要代码段的讲解,实际效果如下:
感谢阅读
(~ ̄▽ ̄)~
对本活动的心得体会
任务难度适中,板卡资源丰富,活动体验良好
(但还是建议返现金捏
2024/12/28