#include "LPC17xx.h" // PWM variables volatile unsigned long int duty_cycle = 10; // Start at 10% volatile unsigned long int pwm_counter = 0; // Pin definitions #define LED_SHIFT 4 // CNA: P0.4-P0.11 #define LED_MASK (0xFF << LED_SHIFT) // Keypad on CND - ROW-0 #define COL0 (1<<0) // P2.0 #define COL1 (1<<1) // P2.1 #define COL2 (1<<23) // P0.23 #define COL3 (1<<24) // P0.24 #define ROW0 (1<<25) // P0.25 #define COL_MASK_P0 (COL2 | COL3) #define COL_MASK_P2 (COL0 | COL1) #define PWM_PERIOD 100 // 100 steps for percentage static void delay_ms(unsigned int ms) { unsigned int i, j; for(i = 0; i < ms; i++) for(j = 0; j < 10000; j++); } static void set_column(unsigned int col) { LPC_GPIO2->FIOSET = COL_MASK_P2; LPC_GPIO0->FIOSET = COL_MASK_P0; switch(col) { case 0: LPC_GPIO2->FIOCLR = COL0; break; case 1: LPC_GPIO2->FIOCLR = COL1; break; case 2: LPC_GPIO0->FIOCLR = COL2; break; case 3: LPC_GPIO0->FIOCLR = COL3; break; } } static unsigned int is_row0_pressed(void) { return !(LPC_GPIO0->FIOPIN & ROW0); } // HIGH-SPEED PWM Interrupt Handler void PWM1_IRQHandler(void) { if (LPC_PWM1->IR & (1 << 0)) { // Fast software PWM for all 8 LEDs if(pwm_counter < duty_cycle) LPC_GPIO0->FIOSET = LED_MASK; // All LEDs ON else LPC_GPIO0->FIOCLR = LED_MASK; // All LEDs OFF pwm_counter++; if(pwm_counter >= PWM_PERIOD) pwm_counter = 0; LPC_PWM1->IR = (1 << 0); // Clear interrupt flag } } int main(void) { unsigned int col_idx; unsigned int read_key; unsigned int last_key = 0xFF; // === PIN CONFIGURATION === LPC_PINCON->PINSEL0 &= ~(0xFFFF << 8); // P0.4-P0.11 as GPIO LPC_PINCON->PINSEL1 &= ~(0xFFFF << 14); // P0.23-P0.28 as GPIO LPC_PINCON->PINSEL4 &= ~(0xF << 0); // P2.0-P2.1 as GPIO // === GPIO SETUP === LPC_GPIO0->FIODIR |= LED_MASK; // LEDs output LPC_GPIO0->FIODIR |= COL_MASK_P0; // Columns output LPC_GPIO2->FIODIR |= COL_MASK_P2; // Columns output LPC_GPIO0->FIODIR &= ~ROW0; // Row input // Initialize LPC_GPIO0->FIOCLR = LED_MASK; LPC_GPIO2->FIOSET = COL_MASK_P2; LPC_GPIO0->FIOSET = COL_MASK_P0; // === HIGH-SPEED PWM CONFIGURATION === LPC_SC->PCONP |= (1 << 6); // Power on PWM1 LPC_PWM1->TCR = (1 << 1); // Reset LPC_PWM1->CTCR = 0; // Timer mode LPC_PWM1->PR = 9; // Prescaler = 10 // 100MHz / 10 = 10MHz timer clock LPC_PWM1->MR0 = 100; // Match every 100 ticks // Interrupt rate = 10MHz/100 = 100kHz // PWM frequency = 100kHz/100 = 1kHz // NO VISIBLE FLICKER! LPC_PWM1->MCR = (1 << 1) | (1 << 0); // Reset on MR0 + interrupt LPC_PWM1->LER = (1 << 0); // Latch MR0 NVIC_EnableIRQ(PWM1_IRQn); // Enable interrupt NVIC_SetPriority(PWM1_IRQn, 0); // Highest priority LPC_PWM1->TCR = (1 << 0) | (1 << 3); // Start PWM // === MAIN LOOP === while(1) { read_key = 0xFF; // Scan ROW-0 only for(col_idx = 0; col_idx < 4; col_idx++) { set_column(col_idx); delay_ms(5); // Short delay for stable reading if(is_row0_pressed()) { read_key = col_idx; // Key 0, 1, 2, or 3 // Wait for key release while(is_row0_pressed()) { delay_ms(10); } break; } } // Restore columns LPC_GPIO2->FIOSET = COL_MASK_P2; LPC_GPIO0->FIOSET = COL_MASK_P0; // Update brightness immediately on key press if(read_key != 0xFF && read_key != last_key) { last_key = read_key; switch(read_key) { case 0: duty_cycle = 10; break; // 10% case 1: duty_cycle = 25; break; // 25% case 2: duty_cycle = 50; break; // 50% case 3: duty_cycle = 75; break; // 75% } } delay_ms(50); // Main loop delay } }