如何修改AVR C代码实现RPI-1031倾斜传感器控制LED功能?
问题修复:AVR读取RPI-1031倾斜传感器仅上方LED常亮
问题背景
使用Atmel Studio编写AVR C代码,通过PORTD引脚2和3读取RPI-1031四向倾斜传感器的上/下/左/右信号,控制PORTB连接的4个对应方向LED点亮。但代码运行后仅上方LED常亮,尝试过宏定义引脚和直接读取引脚均无效。
原代码
#include <avr/io.h> #include <util/delay.h> #ifndef F_CPU #define F_CPU 16000000UL #endif //// define input sensor on PORT D // //#define tilt_S1 (PIND&(1<<2)) //#define tilt_S2 (PIND&(1<<3)) // ////define output LEDs on PORT B // //#define LED_U (PINB&(1<<0)) //#define LED_D (PINB&(1<<1)) //#define LED_L (PINB&(1<<2)) //#define LED_R (PINB&(1<<3)) int main(void) { DDRD =0x00; //port d as input DDRB =0xFF; //port b as out while (1) { //int pos = GetTiltPos(); //get current sensor position if ( ( (PIND & (1<<2))==0 ) && ((PIND & (1<<3))==0 ) ) //Up (North) [S1=0, S2=0] { PORTB |= 1<<PINB0; //up turn on TOP led only PORTB &= ~(1<<PINB1); //down PORTB &= ~(1<<PINB2); //left PORTB &= ~(1<<PINB3); //right } else if (((PIND & (1<<2))==1 ) && ((PIND & (1<<3))==0 )) //Left (West) { PORTB &= ~(1<<PINB0); //up PORTB &= ~(1<<PINB1); //down PORTB |= 1<<PINB2; //left turn on LEFT led only PORTB &= ~(1<<PINB3); //right } else if (((PIND & (1<<2))==0) && ((PIND & (1<<3))==1)) //Right (East) { PORTB &= (~(1<<PINB0)); //up PORTB &= (~(1<<PINB1)); //down PORTB &= (~(1<<PINB2)); //left PORTB |= (1<<PINB3); //right turn on RIGHT led only } else if ( ((PIND & (1<<2))==1 ) && ((PIND & (1<<3))==1 ) ) //Down (South) { PORTB &= ~(1<<PINB0); //up PORTB |= 1<<PINB1; //down turn on BOTTOM led only PORTB &= ~(1<<PINB2); //left PORTB &= ~(1<<PINB3); //right } } } //int GetTiltPos() //function to determine position of sensor //{ //int S1 = 1<<PIND2; //int S2 = 1<<PIND3; //int R = ((S1<<1)| S2) ; //return R; //}
问题诊断
- 输入引脚浮空:DDRD设为0x00后,PORTD2/3为浮空输入,无外部上拉/下拉时电平不稳定,导致传感器信号无法被正确读取,代码始终进入第一个
if分支(上方LED常亮)。 - PORTB初始状态未清零:上电后PORTB寄存器可能残留默认电平,导致LED异常点亮。
- 缺少防抖处理:倾斜传感器触发时可能存在机械抖动,导致电平频繁变化,影响逻辑判断。
修改方案
1. 配置输入引脚上拉电阻
RPI-1031是开关型倾斜传感器,触发时对应引脚接地,因此需要给PORTD2/3配置内部上拉电阻,确保空闲时为高电平,触发时为低电平。
2. 初始化PORTB为全灭状态
上电时先将PORTB置0,避免残留电平导致LED异常。
3. 添加防抖延迟
在循环中加入短延迟,过滤传感器的机械抖动。
4. 简化代码逻辑(可选)
用位操作直接设置PORTB值,减少冗余代码。
修改后的代码
#include <avr/io.h> #include <util/delay.h> #ifndef F_CPU #define F_CPU 16000000UL #endif // 传感器引脚定义 #define S1_PIN (1 << PD2) #define S2_PIN (1 << PD3) // LED引脚定义 #define LED_U_PIN (1 << PB0) #define LED_D_PIN (1 << PB1) #define LED_L_PIN (1 << PB2) #define LED_R_PIN (1 << PB3) int main(void) { DDRD = 0x00; // PORTD设为输入 PORTD |= S1_PIN | S2_PIN; // 开启PORTD2/3内部上拉电阻 DDRB = 0xFF; // PORTB设为输出 PORTB = 0x00; // 初始化PORTB为全灭 while (1) { uint8_t s1_state = !(PIND & S1_PIN); // 取反:触发时为1 uint8_t s2_state = !(PIND & S2_PIN); // 根据传感器状态设置LED if (!s1_state && !s2_state) { PORTB = LED_U_PIN; // 仅上方LED亮 } else if (s1_state && !s2_state) { PORTB = LED_L_PIN; // 仅左方LED亮 } else if (!s1_state && s2_state) { PORTB = LED_R_PIN; // 仅右方LED亮 } else if (s1_state && s2_state) { PORTB = LED_D_PIN; // 仅下方LED亮 } _delay_ms(50); // 防抖延迟,过滤机械抖动 } }
额外调试建议
- 用万用表测量PORTD2/3的电平,确认传感器倾斜时电平是否在高/低之间切换。
- 单独测试PORTB引脚:直接设置
PORTB = LED_L_PIN等,确认LED硬件连接正常。 - 若传感器触发逻辑相反(触发时为高电平),则去掉代码中的
!取反操作。
内容的提问来源于stack exchange,提问作者Mariam Ghanem
相关产品推荐
相关产品推荐

