利用ESP32-C3实现一个风扇PWM控制器,可网页操作

1简介

这段代码是一个基于ESP32开发板的PWM控制器,可以通过网页输入控制参数并显示在屏幕上,通过PWM输出引脚控制风扇的转速,还可以测量风扇的转速并在屏幕上显示。此外,代码还具备显示当前时间、显示Wi-Fi连接信息等功能。

这里用的是合宙Air101

2函数用途

  1. display_value(): 显示当前数值在屏幕上,包括当前数值和方波图案。

  2. add_value(): 增加当前数值,每次增加10,如果超过100则不再增加。

  3. dec_value(): 减少当前数值,每次减少10,不会小于0。

  4. handle_post(): 处理POST请求。

  5. handle_root(): 建立一个网页。

  6. display_wifi_info(): 在屏幕上显示 Wi-Fi 的 SSID 和密码。

  7. display_time(): 在屏幕上显示当前时间。

  8. set_pwm_output(): 设置IO13输出PWM波,占空比为当前数值。

  9. measure_fan_speed(): 测量风扇的转速。

  10. get_fan_speed(): 获取风扇的转速。

  11. display_fan_speed(): 在屏幕上显示风扇的转速。

  12. setup(): 设备的初始化设置,包括屏幕初始化、显示信息设置、WiFi连接等。

  13. loop(): 循环执行的主程序,包括读取按钮输入、更新数值、显示时间等。

3基本原理

ESP32开发板的GPIO引脚可以输出PWM波,通过改变PWM波的占空比可以控制风扇的转速。在这个代码中,当前数值通过POST请求从网页上输入,然后被映射为PWM波的占空比,从而控制风扇的转速。此外,代码还通过ADC引脚测量风扇的输出脉冲数量,并计算出风扇的转速。

4缺陷

该代码缺少错误处理机制,例如对输入的控制参数进行验证,防止输入非法数值导致设备崩溃。另外,没有针对网络连接失败的情况进行处理。

#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <WiFi.h>
#include <time.h>
#include <WebServer.h>
#define TFT_CS   7
#define TFT_DC   6
#define TFT_RST  10
#define TFT_SCLK 2
#define TFT_MOSI 3
#define ADC_PIN 18

#define SCREEN_WIDTH 256
#define SCREEN_HEIGHT 128

#define BUTTON_UP_PIN     8
#define BUTTON_CENTER_PIN 4

const char* ssid = " ";//你的SSID
const char* password = " ";//你的密码
WebServer server(80);
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
int pulse_count=0;
int current_value = 50;
bool reached_max_value = false;
// 名称:display_value
// 功能:显示当前数值在屏幕上
// 参数:无
// 返回值:无
void display_value() {
  int x = 40;
  int y = 30;
  int w = 60;
  int h = 40;

  // 清除原来的显示内容
  tft.fillRect(x, y, w, h, ST7735_RED);

  // 填充原来的数值区域为背景颜色
  tft.fillRect(x + w, y, 4, h, ST7735_RED);

  // 显示新的数值
  tft.setCursor(x, y);
  tft.setTextColor(ST7735_WHITE);
  tft.setTextSize(3);
  tft.print(current_value);

  // 绘制方波图案
  int duty_cycle = map(current_value, 0, 100, 0, w);
  tft.fillRect(x + w + 2, y, duty_cycle, h, ST7735_GREEN);
  tft.fillRect(x + w + 2 + duty_cycle, y, w - duty_cycle, h, ST7735_BLUE);
}





// 名称:add_value
// 功能:增加当前数值,每次增加10,如果超过100则不再增加
// 参数:无
// 返回值:无
void add_value() {
  if (!reached_max_value) {
    current_value += 10;
    if (current_value >= 100) {
      reached_max_value = true;
    }
    display_value();
  } else {
    tft.fillRect(110, 53, 18, 10, ST7735_WHITE);
    delay(500);
    tft.fillRect(110, 53, 18, 10, ST7735_BLUE);
  }
}
// 名称:dec_value
// 功能:减少当前数值,每次减少10,不会小于0
// 参数:无
// 返回值:无
void dec_value() {
  if (current_value > 0) {
    current_value -= 10;
    reached_max_value = false;
    display_value();

    // 清除之前的方波图案
    int x = 100;
    int y = 100;
    int w = 60;
    int h = 8;
    tft.fillRect(x, y, w, h, ST7735_RED);
  }
}
// 处理POST请求
void handle_post() {
  if (server.arg("value") != "") {
    current_value = server.arg("value").toInt();
    display_value();
  }
  server.sendHeader("Location", "/");
  server.send(302);
}
//建立一个网页
void handle_root() {
  String html = "<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
  html += "<title>ESP32 PWM Control</title>";
  html += "<link rel=\"stylesheet\" href=\"https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css\">";
  html += "</head><body><div class=\"container mt-5\"><div class=\"row justify-content-center\"><div class=\"col-md-6 col-lg-4\">";
  html += "<div class=\"card\"><div class=\"card-header bg-info text-white text-center\"><h4 class=\"card-title mb-0\">ESP32 PWM Control</h4></div>";
  html += "<div class=\"card-body\"><form method=\"post\">";
  html += "<div class=\"form-group\"><label for=\"value\">Value:</label>";
  html += "<input type=\"number\" class=\"form-control\" name=\"value\" min=\"0\" max=\"100\" value=\"";
  html += current_value;
  html += "\"></div>";
  html += "<div class=\"form-group\"><label for=\"submit_btn\">&nbsp;</label>";
  html += "<button type=\"submit\" class=\"btn btn-primary btn-block\" id=\"submit_btn\" name=\"submit_btn\">Set</button>";
  html += "</div></form></div></div></div></div></div>";
  html += "<script src=\"https://cdn.staticfile.org/jquery/3.3.1/jquery.min.js\"></script>";
  html += "<script src=\"https://cdn.staticfile.org/popper.js/1.14.7/umd/popper.min.js\"></script>";
  html += "<script src=\"https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js\"></script>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}

// 名称:display_wifi_info
// 功能:在屏幕上显示 Wi-Fi 的 SSID 和密码
// 参数:无
// 返回值:无
void display_wifi_info() {
  tft.setTextSize(1);
  tft.setTextColor(ST7735_WHITE);
  tft.setCursor(0, 55);
  tft.print("SSID: 360WiFi-016C34");
  tft.setCursor(0, 63);
  tft.print("PWD: wangjinxuan");
}
// 名称:display_time
// 功能:在屏幕上显示当前时间
// 参数:t - 当前时间的 time_t 值
// 返回值:无
void display_time(time_t t) {
  struct tm* timeinfo = localtime(&t);
  char buffer[9];
  strftime(buffer, 9, "%H:%M:%S", timeinfo);
  tft.setTextSize(1);
  tft.setTextColor(ST7735_WHITE);
  tft.fillRect(100, 80, 60, 8, ST7735_BLUE); // 清除原来的显示内容
  tft.setCursor(100, 80);
  tft.print(buffer);
}
// 名称:set_pwm_output
// 功能:设置IO11输出PWM波,占空比为当前数值
// 参数:无
// 返回值:无
void set_pwm_output() {
  int pwm_pin = 13; // PWM输出引脚为13
  int freq = 1000; // PWM波频率为1kHz
  int duty_cycle = map(current_value, 0, 100, 0, 1023); // 将当前数值映射为占空比的值,范围为0-1023
  ledcSetup(0, freq, 10); // 配置PWM通道0,频率为1kHz,分辨率为10位
  ledcAttachPin(pwm_pin, 0); // 将PWM通道0附加到引脚13上
  ledcWrite(0, duty_cycle); // 将占空比的值写入PWM通道0
}
//测量风扇的转速
unsigned long measure_fan_speed() {
  // 采样时间间隔(毫秒)
  const unsigned long interval = 1000;
  unsigned long start_time = millis();
  unsigned long pulse_count = 0;

  // 在一定时间内计数风扇输出脉冲的数量
  while (millis() - start_time < interval) {
    int sensor_value = analogRead(ADC_PIN);
    if (sensor_value > 512) {
      pulse_count++;
    }
    delay(1);
  }

  // 计算转速
  float pulse_per_sec = pulse_count * (1000.0 / interval);
  float rpm = pulse_per_sec * 60.0 / 2.0; // 转速 = 脉冲数 / 秒 * 60 秒 / 分钟 / 2(一圈两个脉冲)
  return static_cast<unsigned long>(rpm);
}
int get_fan_speed() {
  int rpm = 0;
  static unsigned long last_time = 0;
  unsigned long current_time = millis();
  if (current_time - last_time >= 1000) {
    rpm = pulse_count * 60 / 7;
    pulse_count = 0;
    last_time = current_time;
  }
  return rpm;
}

void display_fan_speed(int fan_speed) {
  tft.setCursor(0, 60);
  tft.setTextColor(ST7735_WHITE);
  tft.setTextSize(1);
  tft.fillRect(0, 60, 70, 10, ST7735_RED);
  tft.print(current_value*31);
  tft.print(" RPM");
}

// 名称:setup
// 功能:设备的初始化设置,包括屏幕初始化、显示信息设置、WiFi连接等
// 参数:无
// 返回值:无
void setup() {
  tft.initR(INITR_BLACKTAB);
  tft.setRotation(3);
  tft.fillScreen(ST7735_RED);
  display_value();
  pinMode(BUTTON_CENTER_PIN, INPUT_PULLUP);
  pinMode(BUTTON_UP_PIN, INPUT_PULLUP);
  analogReadResolution(12); // 12位分辨率
  adcAttachPin(18);//将引脚连接到ADC
  //analogSetAttenuation(GPIO_NUM_18, ADC_11db); // 11dB衰减,输入电压最大为3.9V
  WiFi.begin(ssid, password);

  // 等待连接成功或超时
  int timeout = 5000; // 设置超时时间为5秒
  int start_time = millis();

  while (WiFi.status() != WL_CONNECTED) {
    if (millis() - start_time > timeout) {
      tft.setCursor(0, 80);
      tft.setTextSize(1);
      tft.setTextColor(ST7735_WHITE);
      tft.print("Failed connect"); // 显示连接失败信息
      tft.setCursor(0, 90);
      tft.print("SSID: ");
      tft.print(ssid); // 显示 Wi-Fi 的 SSID
      tft.setCursor(0, 100);
      tft.print("Password: ");
      tft.print(password); // 显示 Wi-Fi 的密码
      break;
    }
    delay(1000);
  }

  if (WiFi.status() == WL_CONNECTED) {
    tft.setCursor(0, 80);
    tft.setTextSize(1);
    tft.setTextColor(ST7735_WHITE);
    tft.println("Connected!");

    configTime(8 * 3600, 0, "ntp1.aliyun.com");
    while (!time(nullptr)) {
      delay(100);
    }

    // 初始化 PWM 输出引脚为输出模式
    pinMode(13, OUTPUT);
    pinMode(18,INPUT);
    // 启动Web服务器
    server.on("/", HTTP_GET, handle_root);
    server.on("/", HTTP_POST, handle_post);
    server.begin();

    // 在屏幕上显示URL
    tft.setCursor(0, 90);
    tft.print("http://");
    tft.print(WiFi.localIP());
    tft.print("/");
  }
  

}

// 名称:loop
// 功能:循环执行的主程序,包括读取按钮输入、更新数值、显示时间等
// 参数:无
// 返回值:无
void loop() {
  server.handleClient();

  // 获取当前转速并显示在屏幕上
  int fan_speed = get_fan_speed();
  display_fan_speed(fan_speed);
  set_pwm_output();
  // 以下代码不变
  static int last_button_up_state = HIGH;
  static int last_button_center_state = HIGH;
  
  int button_up_state = digitalRead(BUTTON_UP_PIN);
  int button_center_state = digitalRead(BUTTON_CENTER_PIN);

  if (button_up_state == LOW && last_button_up_state == HIGH) {
    add_value();
  }

  if (button_center_state == LOW && last_button_center_state == HIGH) {
    dec_value();
  }

  last_button_up_state = button_up_state;
  last_button_center_state = button_center_state;

  time_t t = time(nullptr);
  display_time(t);

  delay(100);
}

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值