PIC16F877A+L293D直流电机控制器代码编译上传故障求助
PIC16F877A直流电机控制器代码问题修复方案
代码中的核心问题及修复:
配置位缺失/错误
PIC16F877A必须通过配置位指定振荡器类型、看门狗、MCLR功能等参数,缺失配置或参数错误会直接导致编译失败或程序无法正常运行。- 修复:添加配置位定义(根据硬件调整,示例为HS振荡器、关闭看门狗):
// 可放在代码开头或config.h中 __CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & BOREN_ON & LVP_OFF & CPD_OFF & WRT_OFF & DEBUG_OFF);
- 修复:添加配置位定义(根据硬件调整,示例为HS振荡器、关闭看门狗):
IO端口操作不规范
单独操作TRISD0、TRISD1的写法不兼容部分PIC编译器,需通过TRISD寄存器整体配置端口方向。- 修复:替换原IO配置代码:
// 原代码:TRISD0 = 0; TRISD1 = 0; TRISD &= ~0x03; // 将RD0、RD1设置为输出
- 修复:替换原IO配置代码:
PWM占空比位操作错误
设置CCP1X位时,直接使用DC & 2会将位值设为2(二进制10),但CCP1X是单个位寄存器,只能取0或1,导致占空比计算错误。- 修复:修正
PWM1_Set_Duty函数中的位操作:void PWM1_Set_Duty(uint16_t DC) { if(DC < 1024) { CCP1Y = DC & 1; // 取DC的第0位 CCP1X = (DC >> 1) & 1; // 取DC的第1位 CCPR1L = DC >> 2; // 取DC的高8位 } }
- 修复:修正
CCP模块配置不完整
仅设置CCP1M3和CCP1M2无法完全启用PWM模式,需将CCP1M1和CCP1M0设为0。- 修复:用
CCP1CON寄存器一次性配置:// 原代码:CCP1M3 = 1; CCP1M2 = 1; CCP1CON = 0x0C; // CCP1M3=1, CCP1M2=1, 其余位0,启用PWM模式
- 修复:用
按钮消抖与电平稳定性问题
原代码仅通过延迟等待按钮释放,未做消抖检测,且未启用RB端口内部上拉,导致按钮易受干扰、误触发。- 修复:启用RB内部上拉,并添加按钮释放检测:
修改按钮检测逻辑(以Rev按钮为例):// 在main函数开头添加 OPTION_REG &= ~0x80; // 清除RBPU位,启用RB端口内部上拉
其余按钮检测同理修改,避免一次按下多次触发。if(Rev) { __delay_ms(20); // 消抖延迟 while(Rev); // 等待按钮释放 RD0 = ~RD0; RD1 = ~RD1; }
- 修复:启用RB内部上拉,并添加按钮释放检测:
冗余代码问题
main函数为void类型,末尾的return;语句无意义,可删除。
修复后的完整代码:
#include <xc.h> #include <stdint.h> // 配置位定义(根据硬件调整) __CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & BOREN_ON & LVP_OFF & CPD_OFF & WRT_OFF & DEBUG_OFF); #define _XTAL_FREQ 4000000 // 引脚定义 #define Rev RB0 // 反转按钮 #define LV0 RB1 // 0%速度按钮 #define LV1 RB2 // 50%速度按钮 #define LV2 RB3 // 75%速度按钮 #define LV3 RB4 // 100%速度按钮 // 函数声明 void PWM1_Set_Duty(uint16_t); void main(void) { // IO端口配置 TRISB = 0x1F; // RB0-RB4设为输入 TRISD &= ~0x03; // RD0、RD1设为输出 OPTION_REG &= ~0x80; // 启用RB端口内部上拉 // 初始方向:顺时针 RD0 = 0; RD1 = 1; // CCP1 PWM配置 CCP1CON = 0x0C; // 启用PWM模式 TRISC2 = 0; // CCP1输出引脚(RC2)设为输出 // Timer2配置(PWM频率2kHz) PR2 = 124; // 周期寄存器设置 T2CKPS0 = 1; T2CKPS1 = 0; // Timer2预分频1:4 TMR2 = 0; // 初始化Timer2计数器 TMR2ON = 1; // 启动Timer2 // 主循环 while(1) { // 反转方向 if(Rev) { __delay_ms(20); while(Rev); RD0 = ~RD0; RD1 = ~RD1; } // 0%占空比 if(LV0) { __delay_ms(20); while(LV0); PWM1_Set_Duty(0); } // 50%占空比 if(LV1) { __delay_ms(20); while(LV1); PWM1_Set_Duty(250); } // 75%占空比 if(LV2) { __delay_ms(20); while(LV2); PWM1_Set_Duty(375); } // 100%占空比 if(LV3) { __delay_ms(20); while(LV3); PWM1_Set_Duty(500); } __delay_ms(10); } } // PWM占空比设置函数 void PWM1_Set_Duty(uint16_t DC) { if(DC < 1024) { CCP1Y = DC & 1; CCP1X = (DC >> 1) & 1; CCPR1L = DC >> 2; } }
内容的提问来源于stack exchange,提问作者Abdou
相关产品推荐
相关产品推荐

