diff --git a/ES/Lab/Lab11/PWM_Keyboard.c b/ES/Lab/Lab11/PWM_Keyboard.c index e335ee8..ab9d4f2 100644 --- a/ES/Lab/Lab11/PWM_Keyboard.c +++ b/ES/Lab/Lab11/PWM_Keyboard.c @@ -4,32 +4,31 @@ unsigned long int duty_cycle = 0; unsigned long int pwm_counter = 0; -// Pin definitions based on connectors -#define LED_SHIFT 4 // CNA: P0.4-P0.11 (8 LEDs) +// Pin definitions +#define LED_SHIFT 4 // CNA: P0.4-P0.11 #define LED_MASK (0xFF << LED_SHIFT) -// Keypad on CND - Only ROW-0 +// 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 (ROW-0 only) +#define ROW0 (1<<25) // P0.25 #define COL_MASK_P0 (COL2 | COL3) #define COL_MASK_P2 (COL0 | COL1) +#define PWM_PERIOD 100 // Smaller for faster PWM + static void short_delay(volatile unsigned int d) { while(d--) __NOP(); } -// Set a specific column low, others high static void set_column(unsigned int col) { - // Set all columns high first LPC_GPIO2->FIOSET = COL_MASK_P2; LPC_GPIO0->FIOSET = COL_MASK_P0; - // Pull specific column low switch(col) { case 0: LPC_GPIO2->FIOCLR = COL0; break; case 1: LPC_GPIO2->FIOCLR = COL1; break; @@ -38,25 +37,25 @@ static void set_column(unsigned int col) } } -// Check if ROW-0 is pressed static unsigned int is_row0_pressed(void) { return !(LPC_GPIO0->FIOPIN & ROW0); } -// PWM Interrupt Handler +// PWM Interrupt Handler - Software PWM void PWM1_IRQHandler(void) { if (LPC_PWM1->IR & (1 << 0)) { - // Software PWM for LEDs (CNA: P0.4-P0.11) - pwm_counter++; - if(pwm_counter >= 3000) pwm_counter = 0; - + // Software PWM for all 8 LEDs if(pwm_counter < duty_cycle) - LPC_GPIO0->FIOSET = LED_MASK; // LEDs ON + LPC_GPIO0->FIOSET = LED_MASK; // All LEDs ON else - LPC_GPIO0->FIOCLR = LED_MASK; // LEDs OFF + 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 } @@ -69,90 +68,93 @@ int main(void) unsigned int stable = 0; unsigned int last_key = 0xFF; + // === SYSTEM CLOCK SETUP (Optional but recommended) === + SystemInit(); // Use default clock setup + // === PIN CONFIGURATION === - LPC_PINCON->PINSEL0 = 0x00000000; // All GPIO - LPC_PINCON->PINSEL1 = 0x00000000; - LPC_PINCON->PINSEL3 = (2 << 14); // PWM1.4 on P1.23 (optional) - LPC_PINCON->PINSEL4 = 0x00000000; + LPC_PINCON->PINSEL0 &= ~(0xFFFF << 8); // Clear P0.4-P0.11 (GPIO) + LPC_PINCON->PINSEL1 &= ~(0xFFFF << 14); // Clear P0.23-P0.28 + LPC_PINCON->PINSEL3 &= ~(0x3 << 14); // Clear P1.23 + LPC_PINCON->PINSEL4 &= ~(0xF << 0); // Clear P2.0-P2.1 // === GPIO DIRECTION SETUP === - // CNA: LEDs (P0.4-P0.11) - LPC_GPIO0->FIODIR |= LED_MASK; - - // CND: Keypad - Columns output, Row-0 input - LPC_GPIO0->FIODIR |= COL_MASK_P0; // Columns (output) - LPC_GPIO2->FIODIR |= COL_MASK_P2; // Columns (output) + LPC_GPIO0->FIODIR |= LED_MASK; // P0.4-P0.11: LEDs (output) + LPC_GPIO0->FIODIR |= COL_MASK_P0; // Keypad columns (output) + LPC_GPIO2->FIODIR |= COL_MASK_P2; // Keypad columns (output) LPC_GPIO0->FIODIR &= ~ROW0; // Row-0 (input) - // === INITIALIZE GPIO STATES === - LPC_GPIO0->FIOCLR = LED_MASK; // LEDs off - LPC_GPIO2->FIOSET = COL_MASK_P2; // Columns high (idle) - LPC_GPIO0->FIOSET = COL_MASK_P0; // Columns high (idle) + // === INITIALIZE GPIO === + LPC_GPIO0->FIOCLR = LED_MASK; // All LEDs off initially + LPC_GPIO2->FIOSET = COL_MASK_P2; // Columns high + LPC_GPIO0->FIOSET = COL_MASK_P0; // Columns high // === PWM CONFIGURATION === + LPC_SC->PCONP |= (1 << 6); // Power on PWM1 + LPC_PWM1->TCR = (1 << 1); // Reset PWM LPC_PWM1->CTCR = 0; // Timer mode - LPC_PWM1->PR = 0; // No prescaler + LPC_PWM1->PR = 99; // Prescaler: divide by 100 + // Creates ~10kHz interrupt rate - LPC_PWM1->MR0 = 3000; // PWM period = 3000 - LPC_PWM1->MR4 = duty_cycle; // Initial duty cycle = 0 + LPC_PWM1->MR0 = PWM_PERIOD; // PWM period = 100 + LPC_PWM1->MR4 = 0; // Duty cycle = 0 - LPC_PWM1->MCR = (1 << 1) | (1 << 0); // Reset and interrupt on MR0 - LPC_PWM1->PCR = (1 << 12); // Enable PWM4 output - LPC_PWM1->LER = (1 << 0) | (1 << 4); // Latch MR0 and MR4 + LPC_PWM1->MCR = (1 << 1) | (1 << 0); // Reset on MR0, interrupt enabled + LPC_PWM1->LER = (1 << 0); // Latch MR0 NVIC_EnableIRQ(PWM1_IRQn); // Enable PWM interrupt + NVIC_SetPriority(PWM1_IRQn, 0); // Highest priority - LPC_PWM1->TCR = (1 << 0) | (1 << 3); // Enable counter and PWM + LPC_PWM1->TCR = (1 << 0) | (1 << 3); // Enable PWM and counter + + // Initial duty cycle: 10% + duty_cycle = 10; // === MAIN LOOP === while(1) { unsigned int read_key = 0xFF; - // Scan ROW-0 only (columns 0-3 = keys 0, 1, 2, 3) + // Scan ROW-0 (keys 0, 1, 2, 3) for(col_idx = 0; col_idx < 4; col_idx++) { set_column(col_idx); - short_delay(200); + short_delay(500); if(is_row0_pressed()) { - read_key = col_idx; // Key 0, 1, 2, or 3 + read_key = col_idx; break; } } - // Restore all columns high + // Restore columns LPC_GPIO2->FIOSET = COL_MASK_P2; LPC_GPIO0->FIOSET = COL_MASK_P0; - // Debounce logic + // Debounce if(read_key == candidate_key) { - if(stable < 3) stable++; + if(stable < 5) stable++; } else { candidate_key = read_key; stable = 1; } - // Update intensity when key is stable and changed - if(stable >= 3) { + // Update intensity when stable + if(stable >= 5) { if(candidate_key != last_key && candidate_key != 0xFF) { last_key = candidate_key; - // Set duty cycle based on key pressed + // Set duty cycle (out of 100) switch(candidate_key) { - case 0: duty_cycle = 300; break; // 10% of 3000 - case 1: duty_cycle = 750; break; // 25% of 3000 - case 2: duty_cycle = 1500; break; // 50% of 3000 - case 3: duty_cycle = 2250; break; // 75% of 3000 + 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% } - - LPC_PWM1->MR4 = duty_cycle; - LPC_PWM1->LER = (1 << 4); } - stable = 3; + stable = 5; } - short_delay(2000); + short_delay(5000); } }