本帖最后由 LightP 于 2025-1-10 23:14 编辑
原来图片点一下就能加到文章里 ,不搞图床了
就是这个小东西
平常放在公司用的,下班经常忘记关被部门老大吐槽
故决定乘着冬天不用的时候改造下
这个小风扇共有四个挡位(用4个LED表示),两个按键控制
按键比较简单,先放一边
首先要明确的就是怎么知道现在现在在哪个挡位上。接下来把三个引脚接入ESP32(使用arduino框架),编写代码读取对应电压
#define LED_PIN_IN1 25
#define LED_PIN_IN2 27
#define LED_PIN_IN3 32
void setup(){
pinMode(LED_PIN_IN1,INPUT_PULLDOWN);
pinMode(LED_PIN_IN2,INPUT_PULLDOWN);
pinMode(LED_PIN_IN3,INPUT_PULLDOWN);
}
void loop()
{
Serial.print(String(digitalRead(LED_PIN_IN1))+String(digitalRead(LED_PIN_IN2))+String(digitalRead(LED_PIN_IN3)));
Serial.println("");
}
复制代码
通过万用表一顿量,挡位LED控制电路如下
纵向时LED点亮的位置,横向时IO口
发现挡位2和挡位4的电压在esp32的逻辑高低中一致,但是这个小风扇的控制逻辑中的二档必须是由一档切换的,而四档必须是由三档切换的(新概念序列档 )故挡位逻辑如下
void getFanLevel()
{
static uint8_t fanLevelLast = 0;
if(digitalRead(LED_PIN_IN1) == 1 && digitalRead(LED_PIN_IN2) == 1 && digitalRead(LED_PIN_IN3) == 1)
{
fanLevel = 0;
}
else if(digitalRead(LED_PIN_IN1) == 0 && digitalRead(LED_PIN_IN2) == 1 && digitalRead(LED_PIN_IN3) == 0)
{
fanLevel = 1;
}
else if(digitalRead(LED_PIN_IN1) == 0 && digitalRead(LED_PIN_IN2) == 0 && digitalRead(LED_PIN_IN3) == 1 && fanLevelLast == 1)
{
fanLevel = 2;
}
else if(digitalRead(LED_PIN_IN1) == 1 && digitalRead(LED_PIN_IN2) == 0 && digitalRead(LED_PIN_IN3) == 0)
{
fanLevel = 3;
}
else if(digitalRead(LED_PIN_IN1) == 0 && digitalRead(LED_PIN_IN2) == 0 && digitalRead(LED_PIN_IN3) == 1 && fanLevelLast == 3)
{
fanLevel = 4;
}
if(fanLevel != fanLevelLast)
{
fanLevelLast = fanLevel;
}
}
复制代码
至此,风扇挡位读取搞定,接下来搞按键部分,接下来的代码部分比较多,所以我把它上传到github 和gitee :
在此之前由于在arduino框架下调试某一个函数比较困难,而按键必然涉及到某一个函数的有限次可控重复执行,故先给这个程序加入一个串口shell用于调试
我这里用的是letter-shell (在这里对原作者表示感谢),根据手册这个shell的移植也非常简单,只要将对应的文件移入工程,但是由于arduino属于Cpp,所以要把src文件夹中的shell.h换成extensions/cpp_support中的shell_cpp.h。然后再实现两个接口函数就行
这里注意由于,如上文所述arduino属于Cpp项目,而cpp的成员函数没有办法脱离对象运行,所以需要关闭宏定义
#define SHELL_USING_CMD_EXPORT 0
复制代码
接口函数代码如下
static signed short shellWrite(char *data, unsigned short len)
{
Serial.write((uint8_t *)data, len);
return len;
}
static signed short shellRead(char *data, unsigned short len)
{
unsigned short i = 0;
while (Serial.available() && i < len)
{
data[i] = Serial.read();
i++;
}
return i;
}
复制代码
然后在setup函数添加对应的初始化如下
Serial.begin(115200);
debugShell.read = shellRead;
debugShell.write = shellWrite;
shellInit(&debugShell, shellBuffer, 512);
复制代码
到这里我们的程序已经有了风扇挡位检测和shell功能,理论上还是可以继续放在loop函数中运行的,但是考虑到之后还需要继续添加的按键执行,wifi+mqtt,wifi+ota等功能,所以选择在此时加入freertos的相关api至工程(arduino下的esp32项目只需要添加头文件即可)
先包含对应头文件
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
复制代码
创建对应的任务
xTaskCreate(fanLevelJudge, "fanLevelJudge", 4096, NULL, 2, NULL);
xTaskCreate(shellTask, "shellTask", 4096, &debugShell, tskIDLE_PRIORITY, NULL);
复制代码
注意这里letter-shell任务是原生支持在rtos中直接执行,再将letter-shell中的shellTask传入,再将shell控制handle作为形参传入任务
同时根据letter-shell的手册,修改shell_cfg.h,
#define SHELL_TASK_WHILE 0
复制代码
至
#define SHELL_TASK_WHILE 1
复制代码