最近搞了个Arduino研究研究,当积木搭到同时上了旋转编码器和EEPROM(FT24C256兼容AT24C256)时,踩到了一个小坑,在编码器开关触发时进行EEPROM写入操作时会出现卡死情况,特此记录下解决过程:
#include <Wire.h>
#include "PinChangeInterrupt.h"
#define CLK 2
#define DT 3
#define SW 4
#define ADDRESS_AT24C256 0x50
static word data_addr = 0x0F00;
static uint8_t anim_delay = 40;
void setup() {
Serial.begin(9600);
delay(2000);
Serial.println(F("Starting!"));
Wire.begin();
pinMode(CLK, INPUT);
pinMode(DT, INPUT);
pinMode(SW, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(CLK), encoder_value, CHANGE);
attachPCINT(digitalPinToPCINT(SW), button_press, CHANGE);
Wire.beginTransmission(ADDRESS_AT24C256);
Wire.write(highByte(data_addr));
Wire.write(lowByte(data_addr));
Wire.endTransmission();
Wire.requestFrom(ADDRESS_AT24C256, sizeof(anim_delay));
if(Wire.available() >= sizeof(anim_delay))
{
anim_delay = Wire.read();
Serial.print(F("anim_delay loaded from eeprom: "));
Serial.println(anim_delay, DEC);
}
}
bool anim = true;
void loop() {
if (!anim)
return;
delay(anim_delay);
}
unsigned long debounce_delay = 0;
void button_press() {
int btn_val = digitalRead(SW);
if (LOW == btn_val) {
if (millis() - debounce_delay > 200) {
anim = !anim;
Serial.print(F("Animation switched to: "));
Serial.println(anim, DEC);
save_delay = !anim;
Wire.beginTransmission(ADDRESS_AT24C256);
Wire.write(highByte(data_addr));
Wire.write(lowByte(data_addr));
Wire.write(byte(anim_delay));
Wire.endTransmission();
delay(6);
Serial.println(F("anim_delay saved!"));
}
debounce_delay = millis();
}
}
static unsigned char encode_cnt;
void encoder_value() {
bool clk_value = digitalRead(CLK);
bool dt_value = digitalRead(DT);
static u8 check_cnt = 0;
static bool last_clk;
static u32 timee = 0;
if (last_clk != clk_value && millis() - timee > 5) {
last_clk = clk_value;
if (++check_cnt == 1) {
check_cnt = 0;
encode_cnt = (clk_value != dt_value ? 1 : -1);
if (encode_cnt == 1) {
// Serial.println(F(" r++"));
anim_delay += 5;
} else {
// Serial.println(F(" r--"));
anim_delay -= 5;
}
if (anim_delay < 5) anim_delay = 5;
Serial.print(F("anim_delay: "));
Serial.println(anim_delay, DEC);
}
timee = millis();
}
}
代码基本都是抄来的,用了“PinChangeInterrupt”这个库,顺时针、逆时针旋转编码器时以5为步进加减anim_delay变量的值,在开关按下时将当前值写入EEPROM,所以顺利成章的认为在button_press中用I2C通信写入EEPROM就ok了,结果跑起来一按编码器就卡死,Arduino IDE中的串口监视器看到的”Animation switched to:”这行日志也没打全,开始还以为是代码写的有问题,可是setup时的读EEPROM值却没有出现卡死的情况,顺利读出了“0”,最后盲猜了下是不能在中断处理里写写存储代码,于是将代码逻辑改成了下面这版:
#include <Wire.h>
#include "PinChangeInterrupt.h"
#define CLK 2
#define DT 3
#define SW 4
#define ADDRESS_AT24C256 0x50
static word data_addr = 0x0F00;
static uint8_t anim_delay = 40;
void setup() {
Serial.begin(9600);
delay(2000);
Serial.println(F("Starting!"));
Wire.begin();
pinMode(CLK, INPUT);
pinMode(DT, INPUT);
pinMode(SW, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(CLK), encoder_value, CHANGE);
attachPCINT(digitalPinToPCINT(SW), button_press, CHANGE);
Wire.beginTransmission(ADDRESS_AT24C256);
Wire.write(highByte(data_addr));
Wire.write(lowByte(data_addr));
Wire.endTransmission();
Wire.requestFrom(ADDRESS_AT24C256, sizeof(anim_delay));
if(Wire.available() >= sizeof(anim_delay))
{
anim_delay = Wire.read();
Serial.print(F("anim_delay loaded from eeprom: "));
Serial.println(anim_delay, DEC);
}
}
bool anim = true;
bool save_delay = false;
void loop() {
if (save_delay) {
Wire.beginTransmission(ADDRESS_AT24C256);
Wire.write(highByte(data_addr));
Wire.write(lowByte(data_addr));
Wire.write(byte(anim_delay));
Wire.endTransmission();
save_delay = false;
delay(6);
Serial.println(F("anim_delay saved!"));
}
if (!anim)
return;
delay(anim_delay);
}
unsigned long debounce_delay = 0;
void button_press() {
int btn_val = digitalRead(SW);
if (LOW == btn_val) {
if (millis() - debounce_delay > 200) {
anim = !anim;
Serial.print(F("Animation switched to: "));
Serial.println(anim, DEC);
save_delay = !anim;
}
debounce_delay = millis();
}
}
static unsigned char encode_cnt;
void encoder_value() {
bool clk_value = digitalRead(CLK);
bool dt_value = digitalRead(DT);
static u8 check_cnt = 0;
static bool last_clk;
static u32 timee = 0;
if (last_clk != clk_value && millis() - timee > 5) {
last_clk = clk_value;
if (++check_cnt == 1) {
check_cnt = 0;
encode_cnt = (clk_value != dt_value ? 1 : -1);
if (encode_cnt == 1) {
// Serial.println(F(" r++"));
anim_delay += 5;
} else {
// Serial.println(F(" r--"));
anim_delay -= 5;
}
if (anim_delay < 5) anim_delay = 5;
Serial.print(F("anim_delay: "));
Serial.println(anim_delay, DEC);
}
timee = millis();
}
}
按键按下时只进行标记,在loop中处理写存储操作,上电一试,果然ok了。
博主友情提示:
如您在评论中需要提及如QQ号、电子邮件地址或其他隐私敏感信息,欢迎使用>>博主专用加密工具v3<<处理后发布,原文只有博主可以看到。