You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,再对应接线:

  1. 按钮部分
    • 修改代码里的按钮定义:
      #define BTN_DIR PD2
      #define BTN_SPEED PD3
      
    • 接线:方向按钮一端接PD2,另一端接地;速度按钮一端接PD3,另一端接地(代码里开了内部上拉,不需要额外接电阻)。
  2. 电机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的控制引脚。
  3. 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上电稳定后再初始化。


三、分步测试建议(避免越改越乱)

  1. 先单独测LCD:注释掉电机和按钮代码,只保留LCD初始化和固定显示的代码,调节VO电位器直到能清晰显示文字,确认LCD正常工作。
  2. 单独测电机:写一个简单的测试函数,固定给电机一个速度和方向,确认电机能正转、反转、调速,PWM输出正常。
  3. 单独测按钮:在主循环里读按钮状态,用LCD显示按钮是否被按下,确认按键消抖正常。
  4. 最后整合所有功能:把三部分代码整合,测试完整功能。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 11:43:06