Posts Issued on August 8, 2026

posted by sakurai on August 8, 2026 #1102

Geminiに設計してもらったプログラムをClaudeに修正してもらったものを以下に示します。

/* ============================================================
 *  NY_night  --  PIC12F1501 LED driver
 *  rev.3 : SMD / PCBA board (AO3400A output stage) + sleep
 *
 *  RA2 = PWM1 -> R2 -> T2 gate -> L_N   (Left channel)
 *  RA4 = PWM3 -> R1 -> T1 gate -> R_N   (Right channel)
 *  RA5 = mode button (SW1, to GND, internal pull-up)
 *  RA3 = unused input, brought out to JP1 pin 1 (MCLR/VPP)
 *
 *  Modes: 1 alternating fade -> 2 steady -> 3 blink -> SLEEP -> 1 ...
 *  In sleep the core is stopped; a button press wakes it via IOC.
 * ============================================================ */

#pragma config FOSC     = INTOSC   /* internal oscillator                 */
#pragma config WDTE     = OFF      /* watchdog off                        */
#pragma config PWRTE    = ON       /* power-up timer on                   */
#pragma config MCLRE    = OFF      /* pin 4 is RA3, not MCLR              */
#pragma config CP       = OFF      /* code protect off                    */
#pragma config BOREN    = NSLEEP   /* BOR active when running, off asleep */
#pragma config CLKOUTEN = OFF      /* no clock output                     */
#pragma config BORV     = LO       /* low BOR threshold (battery)         */
#pragma config LPBOR    = OFF      /* low-power BOR off                   */
#pragma config LVP      = OFF      /* HV programming via JP1              */

#include 
#include 

#define _XTAL_FREQ 4000000

/* ---- timing, all expressed in 10 ms ticks ---- */
#define TICK_MS         10
#define FADE_TICKS       4     /*  40 ms per fade step   */
#define BLINK_TICKS     30     /* 300 ms per blink phase */
#define DEBOUNCE_TICKS   3     /*  30 ms settle time     */

#define FADE_STEP        5
#define DUTY_MAX       250
#define DUTY_MIN         5

#define PWM_L  PWM1DCH         /* RA2, pin 5 */
#define PWM_R  PWM3DCH         /* RA4, pin 3 */

#define SW_PRESSED  (RA5 == 0)

/* ------------------------------------------------------------
 *  Output stage on / off
 *  With the PWM modules disabled the pins revert to port
 *  control; LATA = 0 holds both gates low, and R3/R4 back
 *  that up so the MOSFETs cannot float on.
 * ---------------------------------------------------------- */
static void outputs_off(void)
{
    PWM_L   = 0;
    PWM_R   = 0;
    PWM1CON = 0x00;
    PWM3CON = 0x00;
    T2CONbits.TMR2ON = 0;
    LATA    = 0x00;
}

static void outputs_on(void)
{
    LATA    = 0x00;
    PWM_L   = 0;
    PWM_R   = 0;
    PR2     = 255;
    T2CONbits.TMR2ON = 1;
    PWM1CON = 0xC0;
    PWM3CON = 0xC0;
}

/* ------------------------------------------------------------
 *  Sleep until the button is pressed.
 *  GIE stays 0, so the core resumes at the instruction after
 *  SLEEP() instead of vectoring to an ISR -- no ISR needed.
 * ---------------------------------------------------------- */
static void sleep_until_button(void)
{
    outputs_off();

    IOCAF = 0x00;                  /* clear any stale edge flag  */
    IOCANbits.IOCAN5 = 1;          /* wake on RA5 falling edge   */
    INTCONbits.IOCIE = 1;
    INTCONbits.GIE   = 0;

    SLEEP();
    NOP();

    IOCANbits.IOCAN5 = 0;
    INTCONbits.IOCIE = 0;
    IOCAF = 0x00;

    outputs_on();
}

int main(void)
{
    /* ---------------- initialisation ---------------- */
    OSCCON = 0x6A;             /* 4 MHz internal                        */
    ANSELA = 0x00;             /* all pins digital                      */
    LATA   = 0x00;             /* outputs low before they are enabled   */
    TRISA  = 0b00101000;       /* RA5 = button in, RA3 = input only     */
    WPUA   = 0b00101000;       /* pull up RA5 AND RA3                   */
    OPTION_REGbits.nWPUEN = 0; /* enable weak pull-ups globally         */

    T2CON = 0x04;              /* Timer2 on, prescale 1:1               */
    outputs_on();              /* PWM period 3.9 kHz, both channels 0   */

    /* ---------------- state ---------------- */
    uint8_t mode     = 1;      /* 0:sleep  1:fade  2:steady  3:blink */
    uint8_t duty     = 0;
    int8_t  step     = FADE_STEP;

    uint8_t fade_t   = 0;
    uint8_t blink_t  = 0;
    uint8_t blink_on = 1;

    uint8_t sw_raw   = 0;      /* 1 = pressed */
    uint8_t sw_prev  = 0;
    uint8_t sw_state = 0;      /* debounced   */
    uint8_t dbnc     = DEBOUNCE_TICKS;

    while (1) {
        /* -------- button: non-blocking, acts on release -------- */
        sw_raw = SW_PRESSED ? 1 : 0;

        if (sw_raw != sw_prev) {
            dbnc = 0;                       /* level changed, restart timer */
        } else if (dbnc < DEBOUNCE_TICKS) {
            if (++dbnc == DEBOUNCE_TICKS) { /* level has settled            */
                if (sw_state == 1 && sw_raw == 0) {
                    mode = (uint8_t)((mode + 1) & 0x03);
                    duty     = 0;
                    step     = FADE_STEP;
                    fade_t   = 0;
                    blink_t  = 0;
                    blink_on = 1;
                }
                sw_state = sw_raw;
            }
        }
        sw_prev = sw_raw;

        /* -------- mode output -------- */
        switch (mode) {

        case 0:                             /* off -> sleep */
            sleep_until_button();

            /* Woken by a press. Go straight to mode 1 so that even a
             * very short tap responds, then swallow this press so the
             * release does not advance the mode a second time.        */
            mode = 1;
            while (SW_PRESSED) {
                __delay_ms(TICK_MS);
            }
            __delay_ms(30);                 /* release bounce */

            sw_raw = sw_prev = sw_state = 0;
            dbnc     = DEBOUNCE_TICKS;
            duty     = 0;
            step     = FADE_STEP;
            fade_t   = 0;
            blink_t  = 0;
            blink_on = 1;
            break;

        case 1:                             /* alternating fade */
            if (++fade_t >= FADE_TICKS) {
                fade_t = 0;
                if (step > 0) {
                    if (duty < DUTY_MAX) duty = (uint8_t)(duty + FADE_STEP);
                    else                 step = -FADE_STEP;
                } else {
                    if (duty > DUTY_MIN) duty = (uint8_t)(duty - FADE_STEP);
                    else                 step = FADE_STEP;
                }
            }
            PWM_L = duty;
            PWM_R = (uint8_t)(255 - duty);
            break;

        case 2:                             /* steady on */
            PWM_L = 255;
            PWM_R = 255;
            break;

        case 3:                             /* simultaneous blink */
            if (++blink_t >= BLINK_TICKS) {
                blink_t  = 0;
                blink_on ^= 1;
            }
            PWM_L = blink_on ? 255 : 0;
            PWM_R = blink_on ? 255 : 0;
            break;
        }

        __delay_ms(TICK_MS);
    }
}

左矢前のブログ 次のブログ右矢