最近搞了个Arduino研究研究,当积木搭到同时上了旋转编码器和EEPROM(FT24C256兼容AT24C256)时,踩到了一个小坑,在编码器开关触发时进行EEPROM写入操作时会出现卡死情况,特此记录下解决过程:
![](https://blog.k-res.net/wp-content/uploads/2022/11/image-1024x576.png)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | #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”,最后盲猜了下是不能在中断处理里写写存储代码,于是将代码逻辑改成了下面这版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | #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<<处理后发布,原文只有博主可以看到。
加载更多