/* * File: main.c * Author: Lelo * Description: Practical 2 - Toggle LED patterns on button release based on ADC value */ #include <xc.h> #define _XTAL_FREQ 4000000 // 4MHz Oscillator // CONFIG1H #pragma config FOSC = INTIO7 // Oscillator Selection bits (Internal oscillator block, CLKOUT function on RA6, port function on RA7) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled) #pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled) // CONFIG2L #pragma config PWRT = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config BOREN = SBORDIS // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled)) #pragma config BORV = 18 // Brown Out Reset Voltage bits (VBOR set to 1.8 V nominal) // CONFIG2H #pragma config WDTEN = OFF // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register) #pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768) // CONFIG3H #pragma config CCP2MX = PORTC // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1) #pragma config PBADEN = ON // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset) #pragma config LPT1OSC = OFF // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for higher power operation) #pragma config HFOFST = ON // HFINTOSC Fast Start-up (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.) #pragma config MCLRE = ON // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled) // CONFIG4L #pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset) #pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled) #pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode)) // CONFIG5L #pragma config CP0 = OFF // Code Protection Block 0 (Block 0 (000800-001FFFh) not code-protected) #pragma config CP1 = OFF // Code Protection Block 1 (Block 1 (002000-003FFFh) not code-protected) #pragma config CP2 = OFF // Code Protection Block 2 (Block 2 (004000-005FFFh) not code-protected) #pragma config CP3 = OFF // Code Protection Block 3 (Block 3 (006000-007FFFh) not code-protected) // CONFIG5H #pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected) #pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM not code-protected) // CONFIG6L #pragma config WRT0 = OFF // Write Protection Block 0 (Block 0 (000800-001FFFh) not write-protected) #pragma config WRT1 = OFF // Write Protection Block 1 (Block 1 (002000-003FFFh) not write-protected) #pragma config WRT2 = OFF // Write Protection Block 2 (Block 2 (004000-005FFFh) not write-protected) #pragma config WRT3 = OFF // Write Protection Block 3 (Block 3 (006000-007FFFh) not write-protected) // CONFIG6H #pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected) #pragma config WRTB = OFF // Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected) #pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM not write-protected) // CONFIG7L #pragma config EBTR0 = OFF // Table Read Protection Block 0 (Block 0 (000800-001FFFh) not protected from table reads executed in other blocks) #pragma config EBTR1 = OFF // Table Read Protection Block 1 (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks) #pragma config EBTR2 = OFF // Table Read Protection Block 2 (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks) #pragma config EBTR3 = OFF // Table Read Protection Block 3 (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks) // CONFIG7H #pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot Block (000000-0007FFh) not protected from table reads executed in other blocks) // Function Prototypes void init_ADC(); unsigned int read_ADC(); void main(void) { OSCCON = 0b01100000; // Set internal oscillator to 4 MHz TRISBbits.TRISB0 = 1; // Set RB0 as input (Button) TRISD = 0x00; // Set PORTD as output (LEDs) ANSELH = 0x00; // Disable analog inputs on PORTB init_ADC(); // Initialize ADC char prevButtonState = 1; // Tracks previous button state unsigned int adcValue = 0; char patternState = 0; // Tracks LED pattern state char adcZone = 0; // Keeps track of current ADC range while (1) { if (prevButtonState == 0 && PORTBbits.RB0 == 1) { // Button RELEASE detected __delay_ms(50); // Debounce delay if (PORTBbits.RB0 == 1) { adcValue = read_ADC(); // Read ADC value // Determine ADC zone if (adcValue < 341) { // 0% - 33% (1023 * 0.33 = 341) if (adcZone != 1) { patternState = 0; } adcZone = 1; patternState = !patternState; LATD = (patternState) ? 0b10101010 : 0b01010101; } else if (adcValue < 682) { // 33% - 66% (1023 * 0.66 = 682) if (adcZone != 2) { patternState = 0; } adcZone = 2; patternState = !patternState; LATD = (patternState) ? 0b11001100 : 0b00110011; } else { // 66% - 100% if (adcZone != 3) { patternState = 0; } adcZone = 3; patternState = (patternState + 1) % 3; if (patternState == 0) LATD = 0b11110000; else if (patternState == 1) LATD = 0b00001111; else LATD = 0b10100101; } } } prevButtonState = PORTBbits.RB0; } } void init_ADC() { TRISA = 0xFF; // Set PORTA as input (for ADC) ANSEL = 0x01; // Enable AN0 (RA0) as analog input ADCON0 = 0b00000001; // Select AN0, Enable ADC ADCON2 = 0b10010101; // Right justify, 8TAD, Fosc/16 } unsigned int read_ADC() { ADCON0bits.GO = 1; // Start conversion while (ADCON0bits.GO); // Wait for conversion to complete return ((ADRESH << 8) + ADRESL); // Return 10-bit ADC value } /* * Answers to Practical Questions: * * 1. An infinite while loop runs indefinitely until an external condition breaks it. * 2. The TRIS register sets the direction of a pin (0 = output, 1 = input). * 3. Use LATx registers to set voltage (e.g., LATD = 0b10101010; to set PORTD pattern). * 4. A bit-field is a way to access specific bits in a register, e.g., PORTBbits.RB0. * 5. The Oscillator must be set to 4 MHz using OSCCON = 0b01100000. * 6. When the button is released, ADC is read and the LED pattern toggles accordingly. * 7. Detection works by comparing current and previous button states (0->1 transition). * 8. A pull-up resistor ensures a default HIGH state when no button is pressed. * 9. 33% of 1023 is 341, 66% is 682, and patterns are assigned based on these values. * 10. ADC reading is taken by enabling ADCON0bits.GO and waiting for completion. * 11. Setup involves configuring ANSEL, TRISA, and ADCON registers. * 12. ADC value (0-1023) is converted to voltage using V = (ADC * Vref) / 1023. */
Standard input is empty
/*
* File: main.c
* Author: Lelo
* Description: Practical 2 - Toggle LED patterns on button release based on ADC value
*/
#include <xc.h>
#define _XTAL_FREQ 4000000 // 4MHz Oscillator
// CONFIG1H
#pragma config FOSC = INTIO7 // Oscillator Selection bits (Internal oscillator block, CLKOUT function on RA6, port function on RA7)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)
// CONFIG2L
#pragma config PWRT = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = SBORDIS // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 18 // Brown Out Reset Voltage bits (VBOR set to 1.8 V nominal)
// CONFIG2H
#pragma config WDTEN = OFF // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
#pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)
// CONFIG3H
#pragma config CCP2MX = PORTC // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = ON // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
#pragma config LPT1OSC = OFF // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config HFOFST = ON // HFINTOSC Fast Start-up (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
#pragma config MCLRE = ON // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)
// CONFIG4L
#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))
// CONFIG5L
#pragma config CP0 = OFF // Code Protection Block 0 (Block 0 (000800-001FFFh) not code-protected)
#pragma config CP1 = OFF // Code Protection Block 1 (Block 1 (002000-003FFFh) not code-protected)
#pragma config CP2 = OFF // Code Protection Block 2 (Block 2 (004000-005FFFh) not code-protected)
#pragma config CP3 = OFF // Code Protection Block 3 (Block 3 (006000-007FFFh) not code-protected)
// CONFIG5H
#pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
#pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM not code-protected)
// CONFIG6L
#pragma config WRT0 = OFF // Write Protection Block 0 (Block 0 (000800-001FFFh) not write-protected)
#pragma config WRT1 = OFF // Write Protection Block 1 (Block 1 (002000-003FFFh) not write-protected)
#pragma config WRT2 = OFF // Write Protection Block 2 (Block 2 (004000-005FFFh) not write-protected)
#pragma config WRT3 = OFF // Write Protection Block 3 (Block 3 (006000-007FFFh) not write-protected)
// CONFIG6H
#pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF // Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected)
#pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM not write-protected)
// CONFIG7L
#pragma config EBTR0 = OFF // Table Read Protection Block 0 (Block 0 (000800-001FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF // Table Read Protection Block 1 (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF // Table Read Protection Block 2 (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF // Table Read Protection Block 3 (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)
// CONFIG7H
#pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot Block (000000-0007FFh) not protected from table reads executed in other blocks)
// Function Prototypes
void init_ADC();
unsigned int read_ADC();
void main(void) {
OSCCON = 0b01100000; // Set internal oscillator to 4 MHz
TRISBbits.TRISB0 = 1; // Set RB0 as input (Button)
TRISD = 0x00; // Set PORTD as output (LEDs)
ANSELH = 0x00; // Disable analog inputs on PORTB
init_ADC(); // Initialize ADC
char prevButtonState = 1; // Tracks previous button state
unsigned int adcValue = 0;
char patternState = 0; // Tracks LED pattern state
char adcZone = 0; // Keeps track of current ADC range
while (1) {
if (prevButtonState == 0 && PORTBbits.RB0 == 1) { // Button RELEASE detected
__delay_ms(50); // Debounce delay
if (PORTBbits.RB0 == 1) {
adcValue = read_ADC(); // Read ADC value
// Determine ADC zone
if (adcValue < 341) { // 0% - 33% (1023 * 0.33 = 341)
if (adcZone != 1) { patternState = 0; }
adcZone = 1;
patternState = !patternState;
LATD = (patternState) ? 0b10101010 : 0b01010101;
}
else if (adcValue < 682) { // 33% - 66% (1023 * 0.66 = 682)
if (adcZone != 2) { patternState = 0; }
adcZone = 2;
patternState = !patternState;
LATD = (patternState) ? 0b11001100 : 0b00110011;
}
else { // 66% - 100%
if (adcZone != 3) { patternState = 0; }
adcZone = 3;
patternState = (patternState + 1) % 3;
if (patternState == 0) LATD = 0b11110000;
else if (patternState == 1) LATD = 0b00001111;
else LATD = 0b10100101;
}
}
}
prevButtonState = PORTBbits.RB0;
}
}
void init_ADC() {
TRISA = 0xFF; // Set PORTA as input (for ADC)
ANSEL = 0x01; // Enable AN0 (RA0) as analog input
ADCON0 = 0b00000001; // Select AN0, Enable ADC
ADCON2 = 0b10010101; // Right justify, 8TAD, Fosc/16
}
unsigned int read_ADC() {
ADCON0bits.GO = 1; // Start conversion
while (ADCON0bits.GO); // Wait for conversion to complete
return ((ADRESH << 8) + ADRESL); // Return 10-bit ADC value
}
/*
* Answers to Practical Questions:
*
* 1. An infinite while loop runs indefinitely until an external condition breaks it.
* 2. The TRIS register sets the direction of a pin (0 = output, 1 = input).
* 3. Use LATx registers to set voltage (e.g., LATD = 0b10101010; to set PORTD pattern).
* 4. A bit-field is a way to access specific bits in a register, e.g., PORTBbits.RB0.
* 5. The Oscillator must be set to 4 MHz using OSCCON = 0b01100000.
* 6. When the button is released, ADC is read and the LED pattern toggles accordingly.
* 7. Detection works by comparing current and previous button states (0->1 transition).
* 8. A pull-up resistor ensures a default HIGH state when no button is pressed.
* 9. 33% of 1023 is 341, 66% is 682, and patterns are assigned based on these values.
* 10. ADC reading is taken by enabling ADCON0bits.GO and waiting for completion.
* 11. Setup involves configuring ANSEL, TRISA, and ADCON registers.
* 12. ADC value (0-1023) is converted to voltage using V = (ADC * Vref) / 1023.
*/