官方Arduino例程学习
在DFrobot的官方网站上,提供了很多Arduino的演示例程,可以帮助我们快速使用这块开发板来时实现各种应用。本文对官方的例程进行演示。
1.1 PWM例程演示
查看板卡的IO引脚分布可以看出,开发板上的LED引脚和LCD的背光控制引脚是连接在一起的。硬件连接如图所示。
参考官方的指南,在Ardinuo中编写以下代码,即可通过PWM波的方式实现呼吸灯的效果,由于LED与LCD的背光控制引脚是连接在一起的,所以LCD屏幕的亮度也会随着变化。
const int ledPin = 21;
const int freq = 10000;
const int ledChannel = 0;
const int resolution = 8;
void setup(){
ledcSetup(ledChannel, freq, resolution);
ledcAttachPin(ledPin, ledChannel);
}
void loop(){
for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++){
ledcWrite(ledChannel, dutyCycle);
delay(15);
}
for(int dutyCycle = 255; dutyCycle >= 0; dutyCycle--){
ledcWrite(ledChannel, dutyCycle);
delay(15);
}
}
1.2 GDI屏幕驱动例程
屏幕上提供了GDI的屏幕驱动接口,可以通过18pin-FPC线连接屏幕,更加方便地使用屏幕,这里使用同为DFrobot出品地2.8" 320x240 TFT电阻触摸显示屏来演示开发板驱动屏幕程序。
首先需要安装DFRobot_GDL库文件,将下载好的屏幕驱动库放置到Arduino IDE的库文件目录中,\Arduino15\libraries\DFRobot_GDL。
参考官方提供例程,代码与相关的注释如下
#include "DFRobot_GDL.h"
#define TFT_DC 3
#define TFT_CS 18
#define TFT_RST 38
DFRobot_ILI9341_240x320_HW_SPI screen(TFT_DC,TFT_CS,TFT_RST);
void setup() {
Serial.begin(115200);
screen.begin();
}
void loop(){
testLine();
testFastLines(COLOR_RGB565_PURPLE,COLOR_RGB565_YELLOW);
testRects(COLOR_RGB565_BLACK,COLOR_RGB565_WHITE);
testRoundRects();
testCircles(24,COLOR_RGB565_BLUE);
testTriangles(COLOR_RGB565_YELLOW);
testPrint();
}
void testLine(){
uint16_t color = 0x00FF;
screen.fillScreen(COLOR_RGB565_BLACK);
for (int16_t x=0; x < screen.width(); x+=6) {
screen.drawLine(screen.width()/2, screen.height()/2, x, 0, color+=0x0700);
}
for (int16_t y=0; y < screen.height(); y+=6) {
screen.drawLine(screen.width()/2, screen.height()/2, screen.width(), y, color+=0x0700);
}
for (int16_t x = screen.width(); x >= 0; x-=6) {
screen.drawLine(screen.width()/2, screen.height()/2, x,screen.height(), color+=0x0700);
}
for (int16_t y = screen.height(); y >= 0; y-=6) {
screen.drawLine(screen.width()/2, screen.height()/2, 0, y, color+=0x0700);
}
}
void testFastLines(uint16_t color1, uint16_t color2) {
for (int16_t y=0; y < screen.height(); y+=4) {
screen.drawFastHLine(0, y, screen.width(),color2);
delay(10);
}
for(int16_t x=0; x < screen.width(); x+=3) {
screen.drawFastVLine(x, 0, screen.height(), color1);
delay(10);
}
}
void testRects(uint16_t color1, uint16_t color2) {
screen.fillScreen(COLOR_RGB565_BLACK);
int16_t x=screen.width()-12;
for (; x > 100; x-=screen.width()/40) {
screen.drawRect(screen.width()/2 -x/2, screen.height()/2 -x/2 , x, x, color2+=0x0F00);
delay(100);
}
screen.fillRect(screen.width()/2 -x/2, screen.height()/2 -x/2 , x, x, color2);
delay(100);
for(; x > 6; x-=screen.width()/40){
screen.drawRect(screen.width()/2 -x/2, screen.height()/2 -x/2 , x, x, color1);
delay(100);
}
}
void testRoundRects() {
screen.fillScreen(COLOR_RGB565_BLACK);
int color = 0xF00F;
int i;
int x = 0;
int y = 0;
int w = screen.width()-3;
int h = screen.height()-3;
for(i = 0 ; i <= 10; i+=2) {
screen.drawRoundRect(x, y, w, h, 20, color);
x+=5;
y+=5;
w-=10;
h-=10;
color+=0x0100;
delay(50);
}
for(i = 0 ; i <= 10; i+=2) {
screen.fillRoundRect(x, y, w, h, 10, color);
x+=5;
y+=5;
w-=10;
h-=10;
color+=0x0500;
delay(50);
}
}
void testCircles(uint8_t radius, uint16_t color) {
screen.fillScreen(COLOR_RGB565_BLACK);
for (int16_t x=radius; x <=screen.width()-radius; x+=radius*2) {
for (int16_t y=radius; y <=screen.height()-radius; y+=radius*2) {
screen.drawCircle(x, y, radius, color);
if(x == y ||x == -y ||x == y + 2*radius)
screen.fillCircle(x, y, radius, color);
color += 800;
delay(100);
}
}
}
void testTriangles(uint16_t color){
screen.fillScreen(COLOR_RGB565_BLACK);
for (int16_t i=0; i <=screen.width(); i+=24)
screen.drawTriangle(i,0,0,screen.height()-i,screen.width()-i,screen.height(), color);
for (int16_t i=0; i <screen.width(); i+=24)
screen.drawTriangle(screen.width(),i*4/3,0,screen.height()-i*4/3,i,0, color);
for (int16_t i=0; i <screen.width(); i+=24)
screen.drawTriangle(screen.width(),i*4/3,i,0,screen.width()-i,screen.height(), color);
color = COLOR_RGB565_RED;
for (int16_t i=0; i <=screen.width(); i+=24)
screen.fillTriangle(i,0,0,screen.height()-i,screen.width()-i,screen.height(), color+=100);
for (int16_t i=0; i <screen.width(); i+=24)
screen.fillTriangle(screen.width(),i*4/3,0,screen.height()-i*4/3,i,0, color+=100);
for (int16_t i=0; i <screen.width(); i+=24)
screen.fillTriangle(screen.width(),i*4/3,i,0,screen.width()-i,screen.height(), color+=100);
}
void testPrint() {
int16_t color = 0x00FF;
screen.setTextWrap(false);
screen.fillScreen(COLOR_RGB565_BLACK);
screen.setCursor(0, 50);
screen.setTextColor(color+=0x3000);
screen.setTextSize(0);
screen.println("Hello World!");
screen.setTextColor(color+=0x3000);
screen.setTextSize(1);
screen.println("Hello World!");
screen.setTextColor(color+=0x3000);
screen.setTextSize(2);
screen.println("Hello World!");
screen.setTextColor(color+=0x3000);
screen.setTextSize(3);
screen.println("Hello World!");
screen.setTextColor(color+=0x3000);
screen.setTextSize(4);
screen.println("Hello!");
screen.setTextSize(5);
screen.print("Hello!");
delay(2000);
screen.setCursor(0, 0);
screen.fillScreen(COLOR_RGB565_BLACK);
screen.setTextSize(2);
screen.setTextColor(color+=0x3000);
screen.print("a = ");
screen.setTextColor(color+=0x3000);
int a = 1234;
screen.println(a, 1);
screen.setTextColor(color+=0x3000);
screen.print(8675309, HEX);
screen.println("this is HEX!");
screen.println("");
screen.setTextColor(color+=0x0F00);
screen.println("running for: ");
screen.setTextColor(color+=0x0F00);
screen.print(millis());
screen.setTextColor(color+=0x0F00);
screen.println("/1000 seconds.");
char text[] = "Hi DFRobot!";
screen.setTextColor(color+=0x0F00);
screen.setTextWrap(true);
screen.setTextSize(3);
screen.println(text);
screen.println(text);
delay(2000);
}
运行额效果如文末视频所示。
1.3 Wifi获取网络时间
由于ESP32-S3自带了Wifi功能,这样我们就可以使用其Wifi功能连接互联网,从而实现查询网络时间的功能。在官方提供例程的基础上,修改ntp服务器为能够访问的阿里云网络时间服务器。演示代码如下。
#include <WiFi.h>
const char *ssid = "HOST_BWG";
const char *password = "Xdy_China_Mobile";
const char *ntpServer = "ntp.aliyun.com";
const long gmtOffset_sec = 8 * 3600;
const int daylightOffset_sec = 0;
void printLocalTime()
{
struct tm timeinfo;
if (!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
return;
}
Serial.println(&timeinfo, "%F %T %A");
}
void setup()
{
Serial.begin(115200);
Serial.println();
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected!");
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
printLocalTime();
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
Serial.println("WiFi disconnected!");
}
void loop()
{
delay(1000);
printLocalTime();
}
演示效果如图所示。
1.4 摄像头使用
开发板上的摄像头的供电由AXP313电源控制芯片控制,所以在使用前需要安装AXP313的驱动库,与屏幕驱动库的安装方法一致,将驱动库文件放置到Arduino的安装路径下的库文件夹下\Arduino15\libraries\DFRobot_AXP313A。
在arduino IDE中选择File->Examples->ESP32->Camera->CameraWebServer示例.
根据自己的Wifi配置信息修改工程中相应的Wifi账号密码,主程序的相关源码如下所示:
#include "esp_camera.h"
#include <WiFi.h>
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 45
#define SIOD_GPIO_NUM 1
#define SIOC_GPIO_NUM 2
#define Y9_GPIO_NUM 48
#define Y8_GPIO_NUM 46
#define Y7_GPIO_NUM 8
#define Y6_GPIO_NUM 7
#define Y5_GPIO_NUM 4
#define Y4_GPIO_NUM 41
#define Y3_GPIO_NUM 40
#define Y2_GPIO_NUM 39
#define VSYNC_GPIO_NUM 6
#define HREF_GPIO_NUM 42
#define PCLK_GPIO_NUM 5
#include "DFRobot_AXP313A.h"
DFRobot_AXP313A axp;
const char* ssid = "自己的Wifi账号";
const char* password = "自己的Wifi密码";
void startCameraServer();
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
while(axp.begin() != 0){
Serial.println("init error");
delay(1000);
}
axp.enableCameraPower(axp.eOV2640);
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.frame_size = FRAMESIZE_UXGA;
config.pixel_format = PIXFORMAT_JPEG;
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 12;
config.fb_count = 1;
if(config.pixel_format == PIXFORMAT_JPEG){
if(psramFound()){
config.jpeg_quality = 10;
config.fb_count = 2;
config.grab_mode = CAMERA_GRAB_LATEST;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.fb_location = CAMERA_FB_IN_DRAM;
}
} else {
config.frame_size = FRAMESIZE_240X240;
#if CONFIG_IDF_TARGET_ESP32S3
config.fb_count = 2;
#endif
}
#if defined(CAMERA_MODEL_ESP_EYE)
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
#endif
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
sensor_t * s = esp_camera_sensor_get();
if (s->id.PID == OV3660_PID) {
s->set_vflip(s, 1);
s->set_brightness(s, 1);
s->set_saturation(s, -2);
}
if(config.pixel_format == PIXFORMAT_JPEG){
s->set_framesize(s, FRAMESIZE_QVGA);
}
#if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM)
s->set_vflip(s, 1);
s->set_hmirror(s, 1);
#endif
#if defined(CAMERA_MODEL_ESP32S3_EYE)
s->set_vflip(s, 1);
#endif
WiFi.begin(ssid, password);
WiFi.setSleep(false);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
startCameraServer();
Serial.print("Camera Ready! Use 'http://");
Serial.print(WiFi.localIP());
Serial.println("' to connect");
}
void loop() {
delay(10000);
}
下载程序到开发板上,在浏览器中输入http://192.168.0.102进行连接,从而可以调整摄像头的参数、人脸检测和入侵检测。
打开Face Detection可以进行人脸探测,效果如下:
打开Face Recognition可以进行人脸设备,在没有注册人脸时,如显示入侵报警,点击Enroll录入人脸后,就可以对人脸进行识别,同时在网页上显示ID,效果如下。
1.5 总结
通过官方提供的示例程序,可以快速地验证开发板上地相关功能,对不同应用的工作原理能够有整体的认识,在此基础上,可以通过对源码的修改来实现不同的功能。