c-如何写入RP2040上的特定寄存器以消除抖动



我正在使用Arduino IDE和langauge(C(对Raspberry Pi Pico进行编程。我有一个项目,使用16x2液晶显示器和一个按钮来控制它的背光。按钮和其他一切都正常工作,我的问题是,每次我按下开关时,背光都会闪烁,由于弹跳,我建议需要随机按下几次才能保持打开或关闭。我想清除RP2040的ICSR寄存器中的22位,以在从中断返回之前清除中断缓冲区中的任何未决内容。https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_m0plus(第87页,或页面底部的第86页(

到目前为止我的代码:

#include <Adafruit_BMP280.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>
#include "hardware/regs/m0plus.h"
//#include <pico/stdlib.h>
//#include <hardware/pwm.h>
Adafruit_BMP280 bmp; //I2C
hd44780_I2Cexp lcd(0x27, 16, 2);
const uint16_t AirValue = 1023;
const uint16_t WaterValue = 660; //measured fully submerged in water
const uint16_t DarkValue = 0;
const uint16_t LightValue = 1023;
uint16_t soilMoisture;
uint16_t soilMoisturePercent;
uint16_t lightIntensity;
uint16_t lightIntensityPercent;
volatile bool lcdBacklightStatus = false;
byte pressureChar[] = { 0b01000, 0b11110, 0b11100, 0b01000, 0b00011, 0b01111, 0b00000, 0b11110
};
byte moistureChar[] = { 0b00000, 0b00100, 0b01110, 0b11111, 0b11111, 0b11111, 0b01110, 0b00000
};
byte lightIntensityChar[] = { 0b00000, 0b01110, 0b10001, 0b11011, 0b10101, 0b01110, 0b01110, 0b00100
};
byte temperatureChar[] = { 0b01000, 0b10111, 0b10100, 0b11111, 0b11100, 0b11100, 0b11100, 0b01000
};
byte separatorWall[] = { 0b10101, 0b01010, 0b10101, 0b01010, 0b10101, 0b01010, 0b10101, 0b01010
};
byte degreeChar[] = { 0b00111, 0b00101, 0b00111, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000
};
void backlight();
void setup() {
lcd.begin(0x27, 16, 2);
lcd.createChar(0, pressureChar);
lcd.createChar(1, moistureChar);
lcd.createChar(2, lightIntensityChar);
lcd.createChar(3, temperatureChar);
lcd.createChar(4, separatorWall);
lcd.createChar(5, degreeChar);
lcd.home();
pinMode(26, INPUT); //soilMoisture
pinMode(27, INPUT); //lightIntensity
pinMode(17, INPUT); //button
attachInterrupt(digitalPinToInterrupt(17), backlight, RISING);

//Serial.begin(9600);
bmp.begin(0x76);
bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,     /* Operating Mode. */
Adafruit_BMP280::SAMPLING_X2,     /* Temp. oversampling */
Adafruit_BMP280::SAMPLING_X16,    /* Pressure oversampling */
Adafruit_BMP280::FILTER_X16,      /* Filtering. */
Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */
lcd.clear();
lcd.backlight(); //lcd.noBacklight();
lcd.setCursor(1,0);
lcd.print("Plant Station");
lcd.setCursor(6,1);
lcd.print("V0.8");
delay(2000);
lcd.noBacklight();
lcd.clear();
lcd.setCursor(0,0);
lcd.write(byte(3));
lcd.setCursor(10,0);
lcd.write(byte(2));
lcd.setCursor(0,1);
lcd.write(byte(0));
lcd.setCursor(10,1);
lcd.write(byte(1));
lcd.setCursor(7,0);
lcd.write(byte(5));
lcd.setCursor(8,0);
lcd.print("C");
lcd.setCursor(15,0);
lcd.print("%");
lcd.setCursor(6,1);
lcd.print("hPa");
lcd.setCursor(15,1);
lcd.print("%");
}
void loop() {
soilMoisture = analogRead(26);
soilMoisturePercent = map(soilMoisture, AirValue, WaterValue, 0, 100);
lightIntensity = analogRead(27);
lightIntensityPercent = map(lightIntensity, DarkValue, LightValue, 0, 100);
if(soilMoisturePercent >= 100) soilMoisturePercent = 100;
else if(soilMoisturePercent <= 0) soilMoisturePercent = 0; 
if(lightIntensityPercent >= 100) lightIntensityPercent = 100;
else if(lightIntensityPercent <= 0) lightIntensityPercent = 0;
//Serial.print("Moisture: ");
//Serial.println(soilMoisture);
//Serial.print("Percentage: ");
//Serial.println(soilMoisturePercent);
//Serial.print("LightIntensity: ");
//Serial.println(lightIntensity);
//Serial.print(soilMoisture);
//Serial.println(soilMoisturePercent);
//BANNED CURSOR POSITIONS: 0,0  9,0  0,1  9,1  6,0  14,0  7,0  15,0  5,1  15,1
lcd.setCursor(3,0);
lcd.print(bmp.readTemperature(),1);
lcd.setCursor(2,1);
lcd.print(((bmp.readPressure()/100)),0);
if(soilMoisturePercent < 10) {
lcd.setCursor(13,1);
lcd.print(" ");
lcd.print(soilMoisturePercent);
} else if(soilMoisturePercent < 100) {
lcd.setCursor(13,1);
lcd.print(soilMoisturePercent);
} else {
lcd.setCursor(12,1);
lcd.print(soilMoisturePercent);
}
if(lightIntensityPercent < 10) {
lcd.setCursor(13,0);
lcd.print(" ");
lcd.print(lightIntensityPercent);
} else if(lightIntensityPercent < 100) {
lcd.setCursor(13,0);
lcd.print(lightIntensityPercent);
} else {
lcd.setCursor(12,0);
lcd.print(lightIntensityPercent);
}
delay(60000);
}
void backlight() {
//noInterrupts();
detachInterrupt(digitalPinToInterrupt(17));
if(lcdBacklightStatus == true) {
lcd.noBacklight();
} else if(lcdBacklightStatus == false) {
lcd.backlight();
}
delayMicroseconds(500000);
//interrupts();
attachInterrupt(digitalPinToInterrupt(17), backlight, RISING);
lcdBacklightStatus = !lcdBacklightStatus;
//want to clear ICSR register here i guess
}

我可能不够清楚,很抱歉,如果是这样的话,英语不是我的主要语言。

RP2040没有交钥匙去抖动功能,您只需在某个寄存器中写入一位即可启用该功能。

您必须执行多个数字读数,并使用millis()等计时功能来检测何时按下或释放按钮足够长的时间。您可以使用Pololu的Pushbutton库来实现这一点,或者只需阅读其代码作为参考,这样您就可以了解如何实现自己的去抖动。

您还可以考虑使用PIO状态机读取按钮,并将按下/释放事件发送到主CPU。

@stark成为了我的英雄,我删除了整个中断部分和主循环结束时60秒长的延迟。然后添加了以下代码,现在当按下按钮1秒时,液晶背光切换,传感器仍然只每60秒检查一次。仍然不知道如何处理寄存器以取消跳动,所以帖子仍然开放。

for(int i = 0; i < 600; i++) {
if(digitalRead(17) == 1) trueCount++;
if(trueCount == 10) {
lcdBacklightStatus = !lcdBacklightStatus;
trueCount = 0;
}
if(lcdBacklightStatus == false) {
lcd.noBacklight();
} else if(lcdBacklightStatus == true) {
lcd.backlight();
}
delay(100);
}

编辑:

我根据状态机的概念重写了我的整个代码。现在它可以完美地工作,但我仍然想知道如何在RP2040芯片上处理中断,所以非常感谢你的好答案!

代码:

#include <Adafruit_BMP280.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>
Adafruit_BMP280 bmp;
hd44780_I2Cexp lcd(0x27, 16, 2);
const uint8_t moistureSensorPin = 26;
const uint8_t lightSensorPin = 27;
const uint8_t buttonPin = 17;
const uint16_t moistureSensorInterval = 60000;
const uint16_t lightSensorInterval = 60000;
const uint16_t temperatureSensorInterval = 60000;
const uint16_t pressureSensorInterval = 60000;
const uint16_t buttonInterval = 500;
const uint16_t lcdUpdateInterval = 60000;
const uint32_t backlightDuration = 300000;
const uint16_t AirValue = 1023;
const uint16_t WaterValue = 660;
const uint16_t DarkValue = 0;
const uint16_t LightValue = 1023;

uint16_t soilMoisture;
uint16_t soilMoisturePercent;
uint16_t lightIntensity;
uint16_t lightIntensityPercent;
float temperature;
uint32_t pressure;
byte soilMoist = LOW;
byte soilHalfMoist = LOW;
byte soilDry = LOW;
byte buttonState = LOW;
byte lcdBacklightStatus = LOW;
byte buttonPreviouslyPressed = LOW;

uint32_t currentMillis = 0;
uint32_t previousMoistureSensorMillis = 60000;
uint32_t previousLightSensorMillis = 60000;
uint32_t previousTemperatureMillis = 60000;
uint32_t previousPressureMillis = 60000;
uint32_t previousButtonMillis = 0;
uint32_t previousLCDMillis = 0;
byte pressureChar[] = { 0b01000, 0b11110, 0b11100, 0b01000, 0b00011, 0b01111, 0b00000, 0b11110
};
byte moistureChar[] = { 0b00000, 0b00100, 0b01110, 0b11111, 0b11111, 0b11111, 0b01110, 0b00000
};
byte halfMoistureChar[] = { 0b00000, 0b00100, 0b01010, 0b10001, 0b11111, 0b11111, 0b01110, 0b00000
};
byte emptyMoistureChar[] = { 0b00000, 0b00100, 0b01010, 0b10001, 0b10001, 0b10001, 0b01110, 0b00000
};
byte lightIntensityChar[] = { 0b00000, 0b01110, 0b10001, 0b11011, 0b10101, 0b01110, 0b01110, 0b00100
};
byte temperatureChar[] = { 0b01000, 0b10111, 0b10100, 0b11111, 0b11100, 0b11100, 0b11100, 0b01000
};
byte separatorWall[] = { 0b10101, 0b01010, 0b10101, 0b01010, 0b10101, 0b01010, 0b10101, 0b01010
};
byte degreeChar[] = { 0b00111, 0b00101, 0b00111, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000
};
byte painChar[] = { 0b00000, 0b00000, 0b11011, 0b11011, 0b00000, 0b01110, 0b10001, 0b00000
};
void setup() {
pinMode(moistureSensorPin, INPUT);
pinMode(lightSensorPin, INPUT);
pinMode(buttonPin, INPUT);

bmp.begin(0x76);
bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,     /* Operating Mode. */
Adafruit_BMP280::SAMPLING_X2,     /* Temp. oversampling */
Adafruit_BMP280::SAMPLING_X16,    /* Pressure oversampling */
Adafruit_BMP280::FILTER_X16,      /* Filtering. */
Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */


lcd.begin(0x27, 16, 2);
lcd.createChar(0, pressureChar);
lcd.createChar(1, painChar);
lcd.createChar(2, lightIntensityChar);
lcd.createChar(3, temperatureChar);
lcd.createChar(4, moistureChar);
lcd.createChar(5, halfMoistureChar);
lcd.createChar(6, emptyMoistureChar);
lcd.createChar(7, degreeChar);
lcd.home();
lcd.clear();
lcd.backlight(); //lcd.noBacklight();
lcd.setCursor(1,0);
lcd.print("Plant Station");
lcd.setCursor(6,1);
lcd.print("V1.0");
delay(2000);
lcd.noBacklight();
lcd.clear();
lcd.setCursor(0,0);
lcd.write(byte(3));
lcd.setCursor(10,0);
lcd.write(byte(2));
lcd.setCursor(0,1);
lcd.write(byte(0));
lcd.setCursor(10,1);
lcd.write(byte(4));
lcd.setCursor(7,0);
lcd.write(byte(7));
lcd.setCursor(8,0);
lcd.print("C");
lcd.setCursor(15,0);
lcd.print("%");
lcd.setCursor(6,1);
lcd.print("hPa");
lcd.setCursor(15,1);
lcd.print("%");
}
void loop() {
currentMillis = millis();
readMoistureSensor();
readLightSensor();
readTemperature();
readPressure();
readButtonState();
updateBacklight();
updateLCD();
}
void readMoistureSensor() {
if(currentMillis - previousMoistureSensorMillis >= moistureSensorInterval) {
soilMoisture = analogRead(26);
soilMoisturePercent = map(soilMoisture, AirValue, WaterValue, 0, 100);
if(soilMoisturePercent >= 100) soilMoisturePercent = 100;
else if(soilMoisturePercent <= 0) soilMoisturePercent = 0;
previousMoistureSensorMillis += moistureSensorInterval;
}
}
void readLightSensor() {
if(currentMillis - previousLightSensorMillis >= lightSensorInterval) {
lightIntensity = analogRead(27);
lightIntensityPercent = map(lightIntensity, DarkValue, LightValue, 0, 100);
if(lightIntensityPercent >= 100) lightIntensityPercent = 100;
else if(lightIntensityPercent <= 0) lightIntensityPercent = 0;
previousLightSensorMillis += lightSensorInterval;
}
}
void readTemperature() {
if(currentMillis - previousTemperatureMillis >= temperatureSensorInterval) {
temperature = bmp.readTemperature();
previousTemperatureMillis += temperatureSensorInterval;
}
}
void readPressure() {
if(currentMillis - previousPressureMillis >= pressureSensorInterval) {
pressure = (bmp.readPressure()/100);
previousPressureMillis += pressureSensorInterval;
}
}
void readButtonState() {
if(currentMillis - previousButtonMillis >= buttonInterval)  {
buttonState = digitalRead(buttonPin);

if(buttonState == HIGH) {
lcdBacklightStatus = !lcdBacklightStatus;
}
previousButtonMillis += buttonInterval;
}
}
void updateBacklight() {
if(lcdBacklightStatus == HIGH) {
lcd.backlight();
} else {
lcd.noBacklight();
}
}
void updateLCD() {
if(currentMillis - previousLCDMillis >= lcdUpdateInterval) {
if(soilMoisturePercent >= 50) {
lcd.setCursor(10,1);
lcd.write(byte(4));
} else if(soilMoisturePercent >= 25) {
lcd.setCursor(10,1);
lcd.write(byte(5));
} else {
lcd.setCursor(10,1);
lcd.write(byte(6));
}
if(pressure > 1007) {
lcd.setCursor(0,1);
lcd.write(byte(0));
} else {
lcd.setCursor(0,1);
lcd.write(byte(1));
}
lcd.setCursor(3,0);
lcd.print(temperature,1);
lcd.setCursor(2,1);
lcd.print(pressure);
if(soilMoisturePercent < 10) {
lcd.setCursor(13,1);
lcd.print(" ");
lcd.print(soilMoisturePercent);
} else if(soilMoisturePercent < 100) {
lcd.setCursor(13,1);
lcd.print(soilMoisturePercent);
} else {
lcd.setCursor(12,1);
lcd.print(soilMoisturePercent);
}
if(lightIntensityPercent < 10) {
lcd.setCursor(13,0);
lcd.print(" ");
lcd.print(lightIntensityPercent);
} else if(lightIntensityPercent < 100) {
lcd.setCursor(13,0);
lcd.print(lightIntensityPercent);
} else {
lcd.setCursor(12,0);
lcd.print(lightIntensityPercent);
}
previousLCDMillis += lcdUpdateInterval;
}
}

示例代码中的LCD初始化存在一些问题。begin((的API是

begin(cols, rows, [dotsize]);

其中dotsize是可选的,但用于在5x8或5x10字体大小之间进行选择。你很幸运,使用什么工作:

lcd.begin(0x27, 16, 2);

这将列设置为39,行设置为16(这不是正确的几何图形(考虑到库代码的工作方式,使用2表示点大小(这不是一个有效的参数(最终会尝试将字体大小设置为5x10。但由于该字体大小仅适用于单行显示,因此默认为5x8字体。

此外,您确实应该考虑使用自动配置构造函数,这样就不需要指定i2c地址。有关详细信息,请参阅随附的文档。比如API文档和wiki,以获取更多关于hd44780_I2Cexp i/o类的文档。

https://github.com/duinoWitchery/hd44780/wiki

https://github.com/duinoWitchery/hd44780/wiki/ioClass:-hd44780_I2Cexp

相关内容

  • 没有找到相关文章

最新更新