#include typedef unsigned char uint8_t; /* * Breathing LED via bit-bang PWM on PORTA(0) and PORTB(0). * * The PWM period is 256 counts of the inner counter 'pwm'. * Each duty level is held for HOLD_PERIODS full PWM periods before * stepping, giving a smooth fade up then down (heartbeat pattern). * * At 50 MHz with SDCC's output (~10 instructions/iteration) the inner * loop runs at roughly 5 MHz, so one 256-count PWM period ≈ 51 µs * → ~20 kHz PWM. With HOLD_PERIODS = 32 each brightness step lasts * ~1.6 ms and the full 0→255→0 sweep takes ~820 ms — a natural breath. * Tweak HOLD_PERIODS to taste. */ #define HOLD_PERIODS 32 void main(void) { uint8_t duty = 0; /* current duty cycle, 0..255 */ uint8_t dir = 1; /* 1 = ramping up, 0 = ramping down */ uint8_t pwm = 0; /* free-running counter within one period */ uint8_t periods = 0; /* how many full periods at this duty level */ while (1) { /* PWM compare: LED on when we're inside the duty window */ if (pwm < duty) { PORTA = 0x01; PORTB = 0x01; } else { PORTA = 0x00; PORTB = 0x00; } pwm++; /* wraps 255→0, completing one 256-count PWM period */ if (pwm == 0) { periods++; if (periods == HOLD_PERIODS) { periods = 0; if (dir) { duty++; if (duty == 255) dir = 0; /* peak: start ramping down */ } else { duty--; if (duty == 0) dir = 1; /* floor: start ramping up */ } } } } }