编程:
首先,我需要确定在编写这段代码时需要实现的目标:
1、它需要在 ESP32 上运行;
2、使用Wi-Fi同步时间;
3、通过超声波传感器控制步进电机;
4、控制LED灯条的亮度。
转换为代码结构后,它包括以下结构
A.设置网络连接;
B.LED配置;
C.定时器配置;
D.实现多任务处理。
设置网络连接:
查找所有必需的库文件:
#include<Arduino.h>
#include <WiFi.h>
#include "Ultrasonic.h"
#include <String.h>
#include "FastLED.h"
首先介绍Arduino核心库,WiFi库用于网络功能,超声波库用于读取超声波测距传感器,String用于字符串处理,FastLED用于控制LED灯带。
Wi-Fi 设置
const char *ssid = "x.factory"; // Wi-Fi SSID
const char *password = "make0314"; // Wi-Fi 密码
此处设置了用于连接到 Wi-Fi 网络的 SSID 和密码。请注意,这里需要 2.4G 网络。如果没有,则需要提前在网络设置中设置。
此处设置了用于连接到 Wi-Fi 网络的 SSID 和密码。请注意,这里需要 2.4G 网络。如果没有,则需要提前在网络设置中设置。
LED配置
LED灯条配置
#define NUM_LEDS 100
#define LED_DT 9
#define LED_TYPE WS2812
#define COLOR_ORDER GRB
此代码定义了使用的 LED 数量,我在这里设置了 100 盏灯 ,连接到 ESP32 的数据引脚(我定义 GPIO9)、LED 类型和颜色序列。
LED亮度和颜色配置
uint8_t max_bright = 128;
CRGB leds[NUM_LEDS];
CRGB myRGBcolor(50,50,50);
设置 LED 的最大亮度(调试后,这里我设置亮度 128)并定义一个 CRGB 阵列来控制 LED 灯条的每个 LED。还定义了颜色变量 myRGBcolor。
其他硬件配置
Ultrasonic ultrasonic(4);
const int dirPin = 1;
const int stepPin = 2;
...
初始化步进电机的超声波传感器、方向和步进引脚。
定时器配置:
与时间相关的定义和变量
#define NTP1 "ntp1.aliyun.com"
...
String minute;
String second;
String hour;
定义 NTP 服务器地址和用于存储时间的字符串变量。
实现多任务处理:
多任务处理功能
xTaskOne
xTaskTwo
这两个函数是 FreeRTOS 任务,分别用于循环测量距离和控制 LED 灯带的亮度。
Setup 函数:
void setup() {
...
WiFi.begin(ssid, password);
...
configTime(8 * 3600, 0, NTP1, NTP2, NTP3);
...
xTaskCreate(...);
}
在设置功能中,初始化串口,设置步进电机控制引脚,连接Wi-Fi网络,获取网络时间,创建前面描述的任务。
其他功能:
loop 函数:
此功能包括时间同步和根据超声波传感器读数控制步进电机的旋转,以模拟时钟时针、分针和秒针的运动。
onestep用于步进电机的一步操作。 fast用于将步进电机快速旋转一整步。
getCurrentAngle_F和getCurrentAngle_S用于计算步进电机旋转的角度。
setClock 用于读取网络时间和更新时间变量。
经过多次测试和集成,最终的代码如下所示
#include<Arduino.h>
#include <WiFi.h>
#include "Ultrasonic.h"
#include <String.h>
#include "FastLED.h"
//wifi config
const char *ssid = "x.factory"; // WIFI account
const char *password = "make0314"; // WIFI password
#define USE_MULTOCRE 0
#define NUM_LEDS 100 // set the num of led
#define LED_DT 9 // LED pin
#define LED_TYPE WS2812 // LED Light Strip Model
#define COLOR_ORDER GRB
uint8_t max_bright = 128; // LED max bright
CRGB leds[NUM_LEDS];
//CRGB ColorName方法定义颜色
CRGB myRGBcolor(50,50,50); // myRGBcolor(rValue,gValue,bValue)
// rValue: 0 - 255
// gValue: 0 - 255
// bValue: 0 - 255
Ultrasonic ultrasonic(4);
const int dirPin = 1; // dir pin
const int stepPin = 2; // step pin
int num = 0;
const int STEPS_PER_REV = 1;
const float stepAngle = 0.9; // Step angle of stepper motor
const int microstepping = 1; // 1 = full step
long stepCount_S = 0; // num of step fow slow
long stepCount_F = 0; // num of step fow fast
long RangeInCentimeters = 1000;
int remember_min; //rec min
int remember_sec; // rec sec
int remember_hour; // rec hour
// Time info
#define NTP1 "ntp1.aliyun.com"
#define NTP2 "ntp2.aliyun.com"
#define NTP3 "ntp3.aliyun.com"
String minute;
String second;
String hour;
/*
Task one
This function continuously measures the distance using an ultrasonic sensor,
calculates the average of three measurements, and then prints the average distance.
*/
void xTaskOne(void *xTask1){
int rangeMeasurements[3]; // Storage of three measurements
int sum = 0; // For totalizing measured values
while (1) {
for (int i = 0; i < 3; i++) { // Perform three measurements
rangeMeasurements[i] = ultrasonic.MeasureInCentimeters(); // Get the distance in centimeters from the ultrasonic sensor
sum += rangeMeasurements[i]; // Add the current measurement to the sum
delay(250);
}
// Calculation of the average value
int averageRange = sum / 3;
RangeInCentimeters = averageRange;
sum = 0;
delay(500);
}
vTaskDelete(NULL);
}
/*
Task two
This function is responsible for controlling the brightness of an LED strip.
*/
void xTaskTwo(void *xTask2){
while (1) {
// increase brightness
for (double i = 20;i<150;i+=0.5){
FastLED.setBrightness(i);
myRGBcolor.r = 50;
myRGBcolor.b = 50;
myRGBcolor.g = 50;
fill_solid(leds, NUM_LEDS, myRGBcolor);
FastLED.show();
delay(10);
}
// Reduced brightness
for (double i = 150;i>20;i-=0.5){
FastLED.setBrightness(i);
myRGBcolor.r = 50;
myRGBcolor.b = 50;
myRGBcolor.g = 50;
fill_solid(leds, NUM_LEDS, myRGBcolor);
FastLED.show();
delay(10);
}
}
vTaskDelete(NULL);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
delay(500);
// Set the pin modes for the stepper motor control pins
pinMode(stepPin,OUTPUT);
pinMode(dirPin,OUTPUT);
// Set WiFi to station mode and attempt to connect to the specified network
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
// Set WiFi to station mode and attempt to connect to the specified network
LEDS.addLeds<LED_TYPE, LED_DT, COLOR_ORDER>(leds, NUM_LEDS);
// Set the brightness of the LED strip to the maximum value
FastLED.setBrightness(max_bright);
// Wait for the WiFi connection to be established
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected!");
configTime(8 * 3600, 0, NTP1, NTP2, NTP3);
#if !USE_MULTCORE
// Create task one with a specified name, stack size, priority, and no parameters
xTaskCreate(
xTaskOne,/* Task function. */
"TaskOne",/* String with name of task. */
4096,/* Stack size in bytes.*/
NULL,/* parameter passed as input of the task */
1,/* priority of the task.(configMAx PRIORITIES - 1 being the highest, and @ being the lowest.) */
NULL);/* Task handle.*/
// Create task two with a specified name, stack size, priority, and no parameters
xTaskCreate(
xTaskTwo,/* Task function.*/
"TaskTwo",/* String with name of task. */
4096,/* Stack size in bytes.*/
NULL,/* parameter passed as input of the task */
2,/* priority of the task.(configMax PRIORITIES - 1 being the highest, and being the lowest.) */
NULL); /* Task handle.*/
#else
xTaskCreatepinnedToCore(xTaskOne,"TaskOne",4096,NULL,1,NULL,0);
xTaskCreatepinnedToCore(xTaskTwo,"TaskTwo",4896,NULL,2,NULL,1);
#endif
}
void loop() {
int current_angle; // Variable to store the current angle of the actuator in 360 degree
int getCurrentAngle; // Variable to store the total angle of the actuator
if(RangeInCentimeters > 300){
setClock(); // Function to read the current time
int num_hour = hour.toInt(); // Convert the current hour to an integer
if(num_hour>12){
num_hour = num_hour - 12; // Convert to 12-hour format if greater than 12
}
// Check if the current hour is different from the remembered hour
if(num_hour != remember_hour){
remember_hour = num_hour; // Update the remembered hour
int target_angle = num_hour * 30; // Calculate the target angle based on the hour
Serial.print("hour is, ");
Serial.println(num_hour);
getCurrentAngle = getCurrentAngle_S(); // Get the current angle
current_angle = getCurrentAngle % 360; // Update the current angle, wrapping around at 360 degrees
// Determine the direction to rotate and perform the rotation
if(target_angle > current_angle){
for(int i = 0; i < (target_angle - current_angle)/0.9; i++){
onestep();
delay(10);
}
}else{
for(int i = 0; i < (target_angle + 360 - current_angle)/0.9; i++){
onestep();
}
}
// getCurrentAngle = getCurrentAngle_S();
// current_angle = getCurrentAngle % 360;
// Serial.print("current angle is ");
// Serial.println(current_angle);
}
}
else if(RangeInCentimeters < 300 && RangeInCentimeters > 50){ // Minutes logic
remember_hour = 60;
setClock();
int num_min = minute.toInt();
if(num_min != remember_min){
remember_min = num_min;
int target_angle = num_min * 6;
Serial.print("min is, ");
Serial.println(num_min);
getCurrentAngle = getCurrentAngle_S();
current_angle = getCurrentAngle % 360;
if(target_angle > current_angle){
for(int i = 0; i < (target_angle - current_angle)/0.9; i++){
onestep();
delay(10);
}
}else{
for(int i = 0; i < (target_angle + 360 - current_angle)/0.9; i++){
onestep();
}
}
}
} else{ // Seconds logic
remember_min = 70;
remember_hour = 60;
setClock();
int num_sec = second.toInt();
if(num_sec != remember_sec){
remember_sec = num_sec;
int target_angle = num_sec * 6;
Serial.print("sec is, ");
Serial.println(num_sec);
getCurrentAngle = getCurrentAngle_S();
current_angle = getCurrentAngle % 360;
if(target_angle > current_angle){
for(int i = 0; i < (target_angle - current_angle)/0.9; i++){
onestep();
// Serial.print(i);
delay(10);
}
}else{
for(int i = 0; i < (target_angle + 360 - current_angle)/0.9; i++){
onestep();
}
}
getCurrentAngle = getCurrentAngle_S();
current_angle = getCurrentAngle % 360;
Serial.print("current angle is ");
Serial.println(current_angle);
}
}
}
void onestep(){
digitalWrite(dirPin,HIGH);
digitalWrite(stepPin,HIGH);
delayMicroseconds(1000);
digitalWrite(stepPin,LOW);
delayMicroseconds(1000);
stepCount_S++; // update the num of step
// delay(1000);
}
void fast(){
digitalWrite(dirPin,HIGH);
for(int x = 0; x < STEPS_PER_REV ; x++) {
digitalWrite(stepPin,HIGH);
delayMicroseconds(1000);
digitalWrite(stepPin,LOW);
delayMicroseconds(1000);
stepCount_F++;
}
}
float getCurrentAngle_F() {
return stepCount_F * (stepAngle / microstepping);
}
float getCurrentAngle_S() {
return stepCount_S * (stepAngle / microstepping);
}
//time_t now;
void setClock()
{
struct tm timeInfo;
if (!getLocalTime(&timeInfo))
{
Serial.println("Failed to obtain time");
return;
}
//Serial.print(asctime(&timeInfo));
// String date = WDAY_NAMES[timeInfo.tm_wday];
// Serial.println(date.c_str());
// sprintf_P(buff1, PSTR("%04d-%02d-%02d %s"), timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday, WDAY_NAMES[timeInfo.tm_wday].c_str());
// String shuju = String(timeInfo.tm_year + 1900);
// shuju += "-";
// // shuju += timeInfo.tm_mon + 1;
// // shuju += "-";
// shuju += timeInfo.tm_mday;
// shuju += " ";
// shuju += timeInfo.tm_hour;
// shuju += ":";
// shuju += timeInfo.tm_min;
// shuju += ":";
// shuju += timeInfo.tm_sec;
// shuju += " ";
// // shuju += WDAY_NAMES[timeInfo.tm_wday].c_str();
// Serial.println(shuju.c_str());
minute = timeInfo.tm_min;
second = timeInfo.tm_sec;
hour = timeInfo.tm_hour;
}
外观设计:
集成:
以下为组装过程:
https://www.youku.com/video/X...