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

PIC16F1829单片机控制LED异常闪烁问题求助

问题排查与解决方案

核心故障原因

  1. 按钮引脚浮空导致状态不稳定:RA2未启用内部弱上拉,引脚处于浮空状态,随机产生高低电平变化,反复触发LED开关逻辑,导致LED循环闪烁。
  2. 防抖逻辑不严谨:原代码仅检测到状态变化就直接更新稳定状态,未再次确认延时后的引脚状态,无法有效过滤按钮抖动或浮空产生的噪声。

修复步骤

1. 启用按钮引脚内部弱上拉

在main函数的初始化部分添加以下代码,确保RA2引脚在未按下时保持稳定高电平:

OPTION_REGbits.nWPUEN = 0; // 启用全局弱上拉功能
WPUAbits.WPUA2 = 1;        // 为RA2引脚启用弱上拉

2. 修正按钮防抖逻辑

将原防抖代码替换为:

// 修正后的防抖逻辑
if (current_button_state != stable_button_state) {
    __delay_ms(DEBOUNCE_DELAY);
    // 延时后再次读取引脚,确认状态确实变化
    if (BUTTON_PIN == current_button_state) {
        stable_button_state = current_button_state;
    }
}

3. 可选:移除调试代码(避免干扰PWM初始化)

原代码中的调试延时会直接操作LED引脚,虽然不影响最终逻辑,但可以移除以避免混淆:

// 移除以下调试代码
// LATCbits.LATC2 = 1;
// __delay_ms(1000);
// LATCbits.LATC2 = 0;
// __delay_ms(1000);

修改后的完整代码

#include <xc.h>
#include <stdint.h>

#define _XTAL_FREQ 500000  // CPU clock at 500 kHz

// Define button and LED pin
#define BUTTON_PIN PORTAbits.RA2  // Button on RA2
#define LED_PIN LATCbits.LATC2    // DS3 on LATC2

// Look-up table for brightness according to Steven's Power Law (gamma = 2.2)
const uint16_t brightness_table[256] __attribute__((space(prog))) = {
    0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 14, 15, 16, 18,
    19, 21, 22, 24, 25, 27, 29, 30, 32, 34, 35, 37, 39, 41, 43, 44,
    46, 48, 50, 52, 54, 56, 58, 61, 63, 65, 67, 69, 72, 74, 76, 78,
    81, 83, 86, 88, 91, 93, 96, 98, 101, 103, 106, 109, 111, 114, 117, 120,
    122, 125, 128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 161, 164, 168,
    171, 174, 177, 181, 184, 187, 191, 194, 198, 201, 205, 208, 212, 215, 219, 222,
    226, 230, 233, 237, 241, 244, 248, 252, 256, 260, 263, 267, 271, 275, 279, 283,
    287, 291, 295, 299, 303, 307, 312, 316, 320, 324, 328, 333, 337, 341, 345, 350,
    354, 358, 363, 367, 372, 376, 381, 385, 390, 394, 399, 403, 408, 412, 417, 422,
    426, 431, 436, 440, 445, 450, 455, 459, 464, 469, 474, 479, 484, 489, 493, 498,
    503, 508, 513, 518, 523, 528, 533, 538, 543, 548, 554, 559, 564, 569, 574, 579,
    584, 590, 595, 600, 605, 610, 616, 621, 626, 632, 637, 642, 647, 653, 658, 664,
    669, 674, 680, 685, 690, 696, 701, 707, 712, 718, 723, 729, 734, 740, 745, 751,
    756, 762, 767, 773, 778, 784, 790, 795, 801, 806, 812, 818, 823, 829, 834, 840,
    846, 851, 857, 863, 868, 874, 880, 885, 891, 897, 902, 908, 914, 920, 925, 931,
    937, 942, 948, 954, 960, 965, 971, 977, 982, 988, 994, 1000, 1005, 1011, 1017, 1023
};

// Variables for brightness and button status
uint8_t brightness_index = 0;  // Start at 0% brightness
uint8_t led_state = 0;         // 0 = off, 1 = on
uint8_t last_button_state = 1; // Button not pressed
uint8_t stable_button_state = 1;

// Debounce delay
#define DEBOUNCE_DELAY 50  

void update_pwm_duty_cycle(uint16_t duty_cycle);

void setup_pwm(void) {
    PR2 = 255;               // PWM period
    T2CON = 0b00000100;      // Enable Timer2, Prescaler 1:1
    CCP2CON = 0b00001100;    // Enable PWM mode
    CCPR2L = brightness_table[brightness_index] >> 2;
    CCP2CONbits.DC2B = brightness_table[brightness_index] & 0x03;
    TRISCbits.TRISC2 = 0;    // Set LATC2 as output (PWM)
}

void update_pwm_duty_cycle(uint16_t duty_cycle) {
    CCPR2L = (unsigned char)((duty_cycle >> 2) & 0xFF);
    CCP2CONbits.DC2B = duty_cycle & 0x03;
}

void main(void) {
    OSCCON = 0b00111000;  // Internal oscillator at 500 kHz
    TRISC = 0b11111011;   // Only RC2 as output (PWM)
    LATC = 0x00;          // All outputs low
    TRISA = 0xFF;         // Port A as input
    ANSELA &= ~(1 << 2);  // RA2 as digital input (no ADC)
    
    // Enable weak pull-up for RA2 button
    OPTION_REGbits.nWPUEN = 0;
    WPUAbits.WPUA2 = 1;

    setup_pwm();
    update_pwm_duty_cycle(brightness_table[brightness_index]);

    while (1) {
        uint8_t current_button_state = BUTTON_PIN;

        // Debounce logic - corrected
        if (current_button_state != stable_button_state) {
            __delay_ms(DEBOUNCE_DELAY);
            // Re-read pin to confirm state change
            if (BUTTON_PIN == current_button_state) {
                stable_button_state = current_button_state;
            }
        }

        // Button pressed?
        if (last_button_state == 1 && stable_button_state == 0) {
            if (led_state == 0) {
                led_state = 1;
                brightness_index = 255;  // Maximum brightness
            } else {
                led_state = 0;
                brightness_index = 0;    // Off
            }
            update_pwm_duty_cycle(brightness_table[brightness_index]);
            __delay_ms(DEBOUNCE_DELAY);
        }
        last_button_state = stable_button_state;
    }
}

验证说明

  • 启用弱上拉后,RA2引脚在未按下时保持稳定高电平,避免浮空噪声。
  • 修正后的防抖逻辑会在状态变化后再次确认,有效过滤抖动。
  • PWM模块配置本身无问题,修复按钮逻辑后,LED会根据按钮操作正常切换亮灭/亮度,不再出现随机闪烁。

内容的提问来源于stack exchange,提问作者learningtoomuch

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 19:48:13