我正在构建一个测量组件电压的程序。当电位低于1V时,振动电机将接通。
但我的问题是,如果电压低于1V持续10秒或更长时间,我希望Arduino打开电机。例如,如果电压水平低于1 V持续8秒,然后再次变为5 V以上,则电机不应启动。此外,电机应在振动3秒后关闭。我能满足第一个条件。但我不能关掉马达。
到目前为止,我的代码如下:
int Pin = 2;
const float baselineVoltage = 200.0;
int belowBaselineVoltage = false;
unsigned long turnOnAt = 10000;
const unsigned long turnOnDelay = 10 * 1000;
void setup() {
Serial.begin(9600);
pinMode(Pin, OUTPUT);
}
void loop() {
int sensorValue = analogRead(A0);
float voltage = sensorValue * (5.0 / 1023.0);
float voltage2 = voltage*(1023.0 / 5.0);
Serial.println(voltage2);
delay(1000);
if (voltage2 < baselineVoltage) {
if (belowBaselineVoltage == true) {
if (millis() >= turnOnAt) {
digitalWrite(2, HIGH);
} else {
} else {
belowBaselineVoltage = true;
turnOnAt = millis() + turnOnDelay;
}
} else {
belowBaselineVoltage = false;
}
}
发布于 2021-02-07 01:28:43
状态机在嵌入式系统中非常流行。它使代码以可预测的方式运行,当您没有调试器来单步执行代码时,这是非常有价值的。
让我们定义一下你的状态。
我们有一个要跟踪的数据项,一个状态何时发生变化的时间戳。
// **********************************
// shaker motor related definitions
enum class shaker_state : char
{
motor_off,
time_low_voltage,
motor_on,
};
struct shaker_data_t
{
shaker_state state;
unsigned int timestamp;
// you could add here a small buffer to hold a few previous values
// of ADC readings to do a bit of filtering... The median of 5 filter
// should work very well here. It is not absolutely needed for now,
// but you should consider having some kind of filter. The motor may
// introduce noise in the readings. We'll just keep the last reading for
// now.
unsigned int adc_value;
};
// constants are declared constexpr to save memory space.
constexpr unsigned int SHAKER_TIMEOUT_LOW_VOLTAGE = 8000; // in milliseconds
constexpr unsigned int SHAKER_TIMEOUT_MOTOR_ON = 3000; // .idem.
// Again to save memory, and allow for DAC related constants
// to be computed at compile-time.
constexpr inline float adc_value_to_volts(unsigned int value)
{
return value * (5.f / 1024.f);
}
constexpr inline unsigned int volts_to_adc_value(float tension)
{
return unsigned int(tension * (1024.f / 5.f));
}
constexpr unsigned int SHAKER_ADC_THRESHOLD = volts_to_adc_value(1.f);
constexpr int SHAKER_MOTOR = 2;
constexpr int SHAKER_ADC = A0;
// **********************************
// global data
shaker_data_t shaker;
// **********************************
static void shaker_control()
{
// always read adc.
shaker.adc_value = analogRead(SHAKER_ADC);
switch (shaker.state)
{
default: // in case of catastrophic error, turn motor OFF.
case shaker_state::motor_off:
digitalWrite(SHAKER_MOTOR, LOW);
if (shaker.adc_value < SHAKER_ADC_THRESHOLD)
{
shaker.state = shaker_state::time_low_voltage;
shaker.timestamp = (unsigned int)millis();
}
break;
case shaker_state::time_low_voltage:
digitalWrite(SHAKER_MOTOR, LOW);
if (shaker.adc_value >= SHAKER_ADC_THRESHOLD)
{
shaker.state = shaker_state::motor_off;
}
else if ((unsigned int)millis() - shaker.timestamp >= SHAKER_TIMEOUT_LOW_VOLTAGE)
{
digitalWrite(SHAKER_MOTOR, HIGH);
shaker.state = shaker_state::motor_on;
shaker.timestamp = (unsigned int)millis();
}
break;
case shaker_state::motor_on:
digitalWrite(SHAKER_MOTOR, HIGH);
if ((unsigned int)millis() - shaker.timestamp >= SHAKER_TIMEOUT_MOTOR_ON)
{
digitalWrite(SHAKER_MOTOR, LOW);
shaker.state = shaker_state::motor_off;
shaker.timestamp = (unsigned int)millis();
}
break;
}
}
// **********************************
void setup()
{
Serial.begin(9600);
digitalWrite(SHAKER_MOTOR, LOW);
pinMode(SHAKER_MOTOR, OUTPUT);
shaker.state = shaker_state::motor_off;
shaker.timestamp = (unsigned int)millis();
}
// **********************************
void loop()
{
// get temp and control moror.
shaker_control();
// shaker_control is very fast and never blocks, so you have plenty
// of extra time to blink LEDs, read switches, etc...
}
编辑
这里是一个简单的中值为5的滤波器,您可以添加它来滤除ADC读数中不需要的噪声。
class median_of_5_filter
{
public:
void push(unsigned int value)
{
buffer_[next_] = value;
if (++next_ >= 5)
next_ = 0;
compute();
}
unsigned int get() const
{
return filtered_;
}
private:
void compute()
{
// bubble sort, but only the first 3 elements
unsigned int buf_copy[5] = { buffer_[0], buffer_[1], buffer_[2],
buffer_[3], buffer_[4] };
for (unsigned char i = 0; i < 3; ++i)
{
auto min_index = i;
auto min_value = buf_copy[i];
for (unsigned char j = i + 1; j < 5; ++j)
{
if (buf_copy[j] < min_value)
{
min_value = buf_copy[j];
min_index = j;
}
}
if (i != min_index)
swap(buf_copy[i], buf_copy[min_index]);
}
filtered_ = buf_copy[2];
}
static void swap(unsigned int& a, unsigned int& b)
{
auto t = a;
a = b;
b = t;
}
private:
unsigned int filtered_ = 0;
unsigned char next_ = 0;
unsigned int buffer_[5] = {};
};
要使用以下命令:
struct shaker_data_t
{
// ...
median_of_5_filter adc_value;
};
// when reading ADC...
shaker.adc_value.push(analogRead(SHAKER_ADC));
// to get filtered adc reading
if (shaker.adc_value.get() < SHAKER_ADC_THRESHOLD)
https://stackoverflow.com/questions/66078146
复制相似问题