fork download
  1. /*
  2.  * File: main.c
  3.  * Author: Lelo
  4.  * Description: Practical 2 - Toggle LED patterns on button release based on ADC value
  5.  */
  6.  
  7. #include <xc.h>
  8.  
  9. #define _XTAL_FREQ 4000000 // 4MHz Oscillator
  10.  
  11. // CONFIG1H
  12. #pragma config FOSC = INTIO7 // Oscillator Selection bits (Internal oscillator block, CLKOUT function on RA6, port function on RA7)
  13. #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
  14. #pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)
  15.  
  16. // CONFIG2L
  17. #pragma config PWRT = OFF // Power-up Timer Enable bit (PWRT disabled)
  18. #pragma config BOREN = SBORDIS // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
  19. #pragma config BORV = 18 // Brown Out Reset Voltage bits (VBOR set to 1.8 V nominal)
  20.  
  21. // CONFIG2H
  22. #pragma config WDTEN = OFF // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
  23. #pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)
  24.  
  25. // CONFIG3H
  26. #pragma config CCP2MX = PORTC // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
  27. #pragma config PBADEN = ON // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
  28. #pragma config LPT1OSC = OFF // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for higher power operation)
  29. #pragma config HFOFST = ON // HFINTOSC Fast Start-up (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
  30. #pragma config MCLRE = ON // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)
  31.  
  32. // CONFIG4L
  33. #pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
  34. #pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
  35. #pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))
  36.  
  37. // CONFIG5L
  38. #pragma config CP0 = OFF // Code Protection Block 0 (Block 0 (000800-001FFFh) not code-protected)
  39. #pragma config CP1 = OFF // Code Protection Block 1 (Block 1 (002000-003FFFh) not code-protected)
  40. #pragma config CP2 = OFF // Code Protection Block 2 (Block 2 (004000-005FFFh) not code-protected)
  41. #pragma config CP3 = OFF // Code Protection Block 3 (Block 3 (006000-007FFFh) not code-protected)
  42.  
  43. // CONFIG5H
  44. #pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
  45. #pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM not code-protected)
  46.  
  47. // CONFIG6L
  48. #pragma config WRT0 = OFF // Write Protection Block 0 (Block 0 (000800-001FFFh) not write-protected)
  49. #pragma config WRT1 = OFF // Write Protection Block 1 (Block 1 (002000-003FFFh) not write-protected)
  50. #pragma config WRT2 = OFF // Write Protection Block 2 (Block 2 (004000-005FFFh) not write-protected)
  51. #pragma config WRT3 = OFF // Write Protection Block 3 (Block 3 (006000-007FFFh) not write-protected)
  52.  
  53. // CONFIG6H
  54. #pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
  55. #pragma config WRTB = OFF // Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected)
  56. #pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM not write-protected)
  57.  
  58. // CONFIG7L
  59. #pragma config EBTR0 = OFF // Table Read Protection Block 0 (Block 0 (000800-001FFFh) not protected from table reads executed in other blocks)
  60. #pragma config EBTR1 = OFF // Table Read Protection Block 1 (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)
  61. #pragma config EBTR2 = OFF // Table Read Protection Block 2 (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)
  62. #pragma config EBTR3 = OFF // Table Read Protection Block 3 (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)
  63.  
  64. // CONFIG7H
  65. #pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot Block (000000-0007FFh) not protected from table reads executed in other blocks)
  66.  
  67.  
  68. // Function Prototypes
  69. void init_ADC();
  70. unsigned int read_ADC();
  71.  
  72. void main(void) {
  73. OSCCON = 0b01100000; // Set internal oscillator to 4 MHz
  74. TRISBbits.TRISB0 = 1; // Set RB0 as input (Button)
  75. TRISD = 0x00; // Set PORTD as output (LEDs)
  76. ANSELH = 0x00; // Disable analog inputs on PORTB
  77. init_ADC(); // Initialize ADC
  78.  
  79. char prevButtonState = 1; // Tracks previous button state
  80. unsigned int adcValue = 0;
  81. char patternState = 0; // Tracks LED pattern state
  82. char adcZone = 0; // Keeps track of current ADC range
  83.  
  84. while (1) {
  85. if (prevButtonState == 0 && PORTBbits.RB0 == 1) { // Button RELEASE detected
  86. __delay_ms(50); // Debounce delay
  87. if (PORTBbits.RB0 == 1) {
  88. adcValue = read_ADC(); // Read ADC value
  89.  
  90. // Determine ADC zone
  91. if (adcValue < 341) { // 0% - 33% (1023 * 0.33 = 341)
  92. if (adcZone != 1) { patternState = 0; }
  93. adcZone = 1;
  94. patternState = !patternState;
  95. LATD = (patternState) ? 0b10101010 : 0b01010101;
  96. }
  97. else if (adcValue < 682) { // 33% - 66% (1023 * 0.66 = 682)
  98. if (adcZone != 2) { patternState = 0; }
  99. adcZone = 2;
  100. patternState = !patternState;
  101. LATD = (patternState) ? 0b11001100 : 0b00110011;
  102. }
  103. else { // 66% - 100%
  104. if (adcZone != 3) { patternState = 0; }
  105. adcZone = 3;
  106. patternState = (patternState + 1) % 3;
  107. if (patternState == 0) LATD = 0b11110000;
  108. else if (patternState == 1) LATD = 0b00001111;
  109. else LATD = 0b10100101;
  110. }
  111. }
  112. }
  113. prevButtonState = PORTBbits.RB0;
  114. }
  115. }
  116.  
  117. void init_ADC() {
  118. TRISA = 0xFF; // Set PORTA as input (for ADC)
  119. ANSEL = 0x01; // Enable AN0 (RA0) as analog input
  120. ADCON0 = 0b00000001; // Select AN0, Enable ADC
  121. ADCON2 = 0b10010101; // Right justify, 8TAD, Fosc/16
  122. }
  123.  
  124. unsigned int read_ADC() {
  125. ADCON0bits.GO = 1; // Start conversion
  126. while (ADCON0bits.GO); // Wait for conversion to complete
  127. return ((ADRESH << 8) + ADRESL); // Return 10-bit ADC value
  128. }
  129.  
  130. /*
  131.  * Answers to Practical Questions:
  132.  *
  133.  * 1. An infinite while loop runs indefinitely until an external condition breaks it.
  134.  * 2. The TRIS register sets the direction of a pin (0 = output, 1 = input).
  135.  * 3. Use LATx registers to set voltage (e.g., LATD = 0b10101010; to set PORTD pattern).
  136.  * 4. A bit-field is a way to access specific bits in a register, e.g., PORTBbits.RB0.
  137.  * 5. The Oscillator must be set to 4 MHz using OSCCON = 0b01100000.
  138.  * 6. When the button is released, ADC is read and the LED pattern toggles accordingly.
  139.  * 7. Detection works by comparing current and previous button states (0->1 transition).
  140.  * 8. A pull-up resistor ensures a default HIGH state when no button is pressed.
  141.  * 9. 33% of 1023 is 341, 66% is 682, and patterns are assigned based on these values.
  142.  * 10. ADC reading is taken by enabling ADCON0bits.GO and waiting for completion.
  143.  * 11. Setup involves configuring ANSEL, TRISA, and ADCON registers.
  144.  * 12. ADC value (0-1023) is converted to voltage using V = (ADC * Vref) / 1023.
  145.  */
  146.  
Success #stdin #stdout 0.03s 26084KB
stdin
Standard input is empty
stdout
/*
 * 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.
 */