AVR单片机电机控制项目:LCD显示异常、功能失效排查及接线检查请求
AVR单片机电机控制项目:LCD显示异常、功能失效排查及接线检查请求
我来帮你一步步拆解这个项目的问题,从最致命的冲突到细节错误逐一梳理,先解决核心问题:
一、先揪出最致命的接线&引脚冲突问题
你的代码里犯了一个新手常踩的大坑:LCD数据引脚和按钮引脚完全复用,这直接导致LCD显示乱码/不显示、按钮完全失效:
- 你定义
LCD_D5 = PD5,同时又把BTN_DIR = PD5 LCD_D6 = PD6,同时BTN_SPEED = PD6
同一个引脚既要输出LCD的显示数据,又要读按钮的输入信号,两个功能互相干扰,根本不可能正常工作!
另外电机调速的PWM引脚也有代码错误:
- 你定义
MOTOR_EN = PC6(PORTC的第6脚),但代码里Motor_Init()却写了DDRB |= (1<<MOTOR_EN);——把PORTC的引脚当成了PORTB的引脚配置,这会导致PWM信号根本没输出到正确的引脚上,电机根本没法调速。
修正后的引脚分配&接线建议
先把按钮换到和LCD不冲突的空闲引脚,比如PD2、PD3,再对应接线:
- 按钮部分
- 修改代码里的按钮定义:
#define BTN_DIR PD2 #define BTN_SPEED PD3 - 接线:方向按钮一端接PD2,另一端接地;速度按钮一端接PD3,另一端接地(代码里开了内部上拉,不需要额外接电阻)。
- 修改代码里的按钮定义:
- 电机PWM部分
AVR的PWM输出引脚是固定的,不能随便定义,比如ATmega328P的Timer1的OC1B引脚是PB2,适合用来做电机PWM输出,所以调整电机引脚定义:#define MOTOR_IN1 PC0 #define MOTOR_IN2 PC1 #define MOTOR_EN PB2 // 对应Timer1的OC1B PWM输出脚- 接线:电机IN1接PC0,IN2接PC1,EN接PB2,对应L293D的控制引脚。
- LCD部分
保留原有的LCD引脚定义,但必须接对比度调节电位器:- LCD的VO引脚接电位器中间脚,电位器两端接5V和GND,调节电位器直到LCD能清晰显示文字(这是很多新手忽略的点,没接电位器LCD会完全看不到内容)。
- LCD的RW引脚直接接地(因为代码只做写操作,不需要读)。
二、代码核心错误修复
除了引脚冲突,还有这些关键问题要改:
1. 修正电机PWM的定时器配置
因为把MOTOR_EN改成了PB2(Timer1的OC1B),所以要把PWM配置改成Timer1的8位快速PWM模式:
void Motor_Init() { DDRC |= (1<<MOTOR_IN1)|(1<<MOTOR_IN2); DDRB |= (1<<MOTOR_EN); // Timer1 8位快速PWM配置,支持0-255的调速范围 TCCR1A = (1<<COM1B1)|(1<<WGM10); TCCR1B = (1<<WGM12)|(1<<CS10); } void Set_Motor(uint8_t speed, uint8_t dir) { OCR1B = speed; // 对应Timer1的PWM占空比寄存器 if(dir) { PORTC |= (1<<MOTOR_IN1); PORTC &= ~(1<<MOTOR_IN2); } else { PORTC &= ~(1<<MOTOR_IN1); PORTC |= (1<<MOTOR_IN2); } }
2. 修正速度显示逻辑
你原来的代码是直接显示speed的数值(0-255),但你需要的是显示速度百分比(0-100%),所以要把0-255的PWM值转换成百分比:
// 替换主循环里的速度显示代码 uint8_t speed_percent = (speed * 100) / 255; // 把PWM值转成百分比 LCD_Command(0xC0); // 跳转到第二行 // 先写空格覆盖之前的残留内容,避免显示乱码 LCD_String(" "); LCD_Command(0xC0); LCD_String(direction ? "FWD " : "REV "); LCD_Char('S'); LCD_Char(':'); LCD_Char((speed_percent / 100) + '0'); // 百分位(只有0或1) LCD_Char(((speed_percent % 100) / 10) + '0'); // 十位 LCD_Char((speed_percent % 10) + '0'); // 个位 LCD_String("% ");
3. 优化LCD初始化的稳定性
有些LCD需要更长的上电延迟,把LCD_Init()里的_delay_ms(20);改成_delay_ms(50);,确保LCD上电稳定后再初始化。
三、分步测试建议(避免越改越乱)
- 先单独测LCD:注释掉电机和按钮代码,只保留LCD初始化和固定显示的代码,调节VO电位器直到能清晰显示文字,确认LCD正常工作。
- 单独测电机:写一个简单的测试函数,固定给电机一个速度和方向,确认电机能正转、反转、调速,PWM输出正常。
- 单独测按钮:在主循环里读按钮状态,用LCD显示按钮是否被按下,确认按键消抖正常。
- 最后整合所有功能:把三部分代码整合,测试完整功能。
内容来源于stack exchange
相关产品推荐
相关产品推荐

