最近更新于 2023-08-13 14:29

前言

接续前文:https://blog.iyatt.com/?p=9900

上一次是用的自己的元件和组内花钱买的原件做的,然后我拟定了需要使用的元件清单,由老师再采购,效率是有点低,这一个多月了才开始陆续到,我已经拿到了部分,已经可以动工完成了,剩下没到的元件我自己也有。

主要改动就是把电位器去除掉,不再调速,然后新增一个舵机用于控制左右摆头,然后再加一个遥控组件用于控制左右摆头。
file
被控制端,黑色和红色分别对应负极和正极,这里使用 5V 电压,白线是天线。然后我用万用测试了一下,按右键的时候蓝色线相对黄色线为正 5v,按左键的话正负反向。
file

这次使用的风扇零件是重新采购的,里面没有包含电机驱动模块,结果测试的时候因为电机干扰问题折腾了挺久的。最开始我都没意识到电机运行会产生干扰,先是发现 Arduino 执行逻辑不按照我写的程序走,怀疑了一下是不是我代码的逻辑不对,看了看也没啥问题,然后注意到电机一运行,Arduino 上接的 LCD 亮度降低了,因为电机是通过电磁继电器控制的,电机运行的同时,电磁继电器通电吸合,所以我又怀疑是电磁继电器太耗电,导致电压降低。我把电磁继电器去掉了,再手动接通电机,发现 Arduino 还是出现了降压的情况。这时候我就怀疑电机的电磁干扰了,此时沿用的“折腾一”共地的接线,就是电机和Arduino的供电源是独立的,但是 GND 是相连的,我又去除了共地的连线,结果还是有干扰。然后抱着试探的想法,在电机运行时用万用表测频率,结果测出了 2kHz 的值,这就说明电机运行的时候正负极之间不是直流电了,我没有示波器也看不了波形,电压肯定在波动。在电机运行的同时,我又测了Arduino,发现也有频率,在二三十波动。

然而此时,Arduino 的线路和电机的线路是完全没有相连的部分的,那就判断是电机和Arduino挨得近,电机线路电压波动产生变化磁场,在Arduino这边线路产生了感应电流,导致Arduino的电压波动,以致于影响到Arduino读取电平以及导致电压降低。在这里就卡了一段时间 。
后面想起上次折腾时也没遇到这种问题啊,那我就想那个电机驱动模块是不是能消除电机干扰,因为打算交的是这次的风扇模型,我已经用热熔胶把风扇头固定到舵机了,不好更换了。只得去把上次买的风扇的电机线截断接过来(这段线的插头才可以接驱动板),再测试发现果然不再有干扰了。
再之后我也想起来以前见过有些这种小电机上面会焊一个陶瓷电容,应该就是用来稳压的,减小电压波动。

接线图


补充LCD 的接线 SDA – A4,SCL – A5

file
file

这个是作为最终要交的版本了,用面包板接线测试完就焊接到洞洞板上了,然后用热熔胶固定,从十一点多搞到凌晨五点终于结束

软件环境

Arduino IDE 2.0.4
Arduino 库:

  • LiquidCrystal I2C (by Frank de Brabander) 1.1.2
  • OneWire (by Jim Studt…) 2.3.7
  • Dallas Temperature (by Miles Burton) 3.9.0
  • Servo by Michael Margolis 1.1.8

代码

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Servo.h>

// 温度传感器
OneWire oneWire(10); // 创建单总线引脚
DallasTemperature temperature(&oneWire); // 温度传感器实例

// LCD 实例
LiquidCrystal_I2C lcd(0x27, 16, 2);

// 舵机实例
Servo servo;

void setup()
{
    // LCD 初始化
    lcd.init();
    lcd.backlight();
    lcd.clear();

    // 引脚初始化
    pinMode(A0, INPUT);
    pinMode(A1, INPUT);
    pinMode(8, INPUT_PULLUP);
    pinMode(9, OUTPUT);
    pinMode(11, INPUT_PULLUP);

    // 舵机初始化
    servo.attach(12);

    // 初始化温度传感器
    temperature.begin();
}
void loop()
{
    static int powerStatus = LOW; // 当前开关状态
    static int lastPowerStatus = LOW; // 上一次开关状态
    static char lcdString[17]; // 缓冲 LCD 屏显示内容
    static float temperatureC = 0; // 温度值
    static int angle = 90; // 舵机角度

    // 读取温度
    temperature.requestTemperatures();
    temperatureC = temperature.getTempCByIndex(0);

    // 电源触摸开关
    lastPowerStatus = powerStatus;
    powerStatus = digitalRead(8);

    // 舵机左右摆头
    if (analogRead(A0) > 950 && powerStatus)
    {
        angle -= 30;
        if (angle < 0)
        {
            angle = 0;
        }
    }
    else if (analogRead(A1) > 950 && powerStatus)
    {
        angle += 30;
        if (angle > 180)
        {
            angle = 180;
        }
    }
    servo.write(angle);

    // 开机显示标识信息
    lcd.clear();
    memset(lcdString, 0, sizeof(lcdString));
    lcd.setCursor(0, 0);
    if (powerStatus && !lastPowerStatus)
    {
        sprintf(lcdString, "By IYATT-yx");
        lcd.print(lcdString);
        memset(lcdString, 0, sizeof(lcdString));
        sprintf(lcdString, "blog.iyatt.com");
        lcd.setCursor(0, 1);
        lcd.print(lcdString);
        delay(3000);
    }

    // 显示运行信息
    lcd.clear();
    lcd.setCursor(0, 0);
    memset(lcdString, 0, sizeof(lcdString));
    if (powerStatus)
    {
        sprintf(lcdString, "Angle: %d", angle);
        if (digitalRead(11) == HIGH)
        {
            digitalWrite(9, HIGH);
        }
        else
        {
            digitalWrite(9, LOW);
        }
    }
    else
    {
        sprintf(lcdString, "Power off");
        digitalWrite(9, LOW);
    }
    lcd.print(lcdString);
    lcd.setCursor(0, 1);
    memset(lcdString, 0, sizeof(lcdString));
    sprintf(lcdString, "Temperature: %dC", (int)temperatureC);
    lcd.print(lcdString);
}