fork download
  1. #include <xc.h>
  2. #include <stdio.h>
  3.  
  4. // ================= CONFIG =================
  5. // Use these settings in MPLAB/XC8
  6. #pragma config FOSC = HS // HS oscillator
  7. #pragma config WDTE = OFF // Watchdog Timer disabled
  8. #pragma config PWRTE = ON // Power-up Timer enabled
  9. #pragma config BOREN = ON // Brown-out Reset enabled
  10. #pragma config LVP = OFF // Low-Voltage Programming disabled
  11. #pragma config CPD = OFF // Data EEPROM Memory Code Protection off
  12. #pragma config WRT = OFF // Flash Program Memory Write Protection off
  13. #pragma config CP = OFF // Flash Program Memory Code Protection off
  14.  
  15. #define _XTAL_FREQ 20000000 // 20 MHz Crystal (change if different)
  16.  
  17. // ================= LCD CONNECTIONS =================
  18. // LCD on PORTD
  19. #define RS RD0
  20. #define EN RD1
  21. #define D4 RD2
  22. #define D5 RD3
  23. #define D6 RD4
  24. #define D7 RD5
  25.  
  26. // ================= FUNCTION PROTOTYPES =================
  27. void Lcd_Command(char);
  28. void Lcd_Char(char);
  29. void Lcd_Init(void);
  30. void Lcd_String(const char *);
  31. void Lcd_Clear(void);
  32. void Lcd_Set_Cursor(char, char);
  33. unsigned int Read_ADC(unsigned char channel);
  34.  
  35. // ================= GLOBAL VARIABLES =================
  36. volatile unsigned int pulse_count = 0;
  37. unsigned int heart_rate = 0;
  38.  
  39. // ================= MAIN PROGRAM =================
  40. void main(void) {
  41. unsigned int adc_value;
  42. float temperature;
  43. char buffer[16];
  44.  
  45. // ADC setup
  46. ADCON1 = 0x80; // Right justified, Vref=VDD
  47. ADCON0 = 0x41; // ADC enabled, Channel 0 (AN0)
  48.  
  49. // LCD setup
  50. TRISD = 0x00; // LCD port output
  51. Lcd_Init();
  52.  
  53. // RB0 as heart pulse input (external interrupt)
  54. TRISB0 = 1; // RB0 input
  55. INTEDG = 1; // Interrupt on rising edge
  56. INTE = 1; // Enable RB0 external interrupt
  57. GIE = 1; // Enable global interrupts
  58.  
  59. // Timer1 for 1-second period
  60. T1CON = 0x31; // Prescaler 8, Timer1 ON
  61. TMR1H = 0;
  62. TMR1L = 0;
  63.  
  64. while(1) {
  65. // ====== Read Temperature from LM35 ======
  66. adc_value = Read_ADC(0); // Read AN0
  67. temperature = (adc_value * 4.88) / 10.0; // LM35 = 10mV/°C
  68.  
  69. // ====== Heart Rate Calculation every ~1s ======
  70. if (TMR1H > 0x3C) { // Adjust for ~1 second
  71. heart_rate = pulse_count * 60; // convert to bpm
  72. pulse_count = 0;
  73. TMR1H = 0;
  74. TMR1L = 0;
  75. }
  76.  
  77. // ====== Display on LCD ======
  78. Lcd_Clear();
  79.  
  80. sprintf(buffer, "Temp: %.1f C", temperature);
  81. Lcd_Set_Cursor(1, 1);
  82. Lcd_String(buffer);
  83.  
  84. sprintf(buffer, "HR: %u bpm", heart_rate);
  85. Lcd_Set_Cursor(2, 1);
  86. Lcd_String(buffer);
  87.  
  88. __delay_ms(500);
  89. }
  90. }
  91.  
  92. // ================= ADC FUNCTION =================
  93. unsigned int Read_ADC(unsigned char channel) {
  94. if(channel > 7) return 0; // PIC16F877A has 8 ADC channels (AN0–AN7)
  95.  
  96. ADCON0 = (channel << 3) | 0x41; // Select channel, turn on ADC
  97. __delay_ms(2); // Acquisition time
  98. GO_DONE = 1; // Start conversion
  99. while(GO_DONE); // Wait until done
  100. return ((ADRESH << 8) + ADRESL); // Return result
  101. }
  102.  
  103. // ================= LCD FUNCTIONS =================
  104. void Lcd_Command(char cmd) {
  105. RS = 0;
  106. D4 = (cmd >> 4) & 1;
  107. D5 = (cmd >> 5) & 1;
  108. D6 = (cmd >> 6) & 1;
  109. D7 = (cmd >> 7) & 1;
  110. EN = 1; __delay_ms(1); EN = 0;
  111.  
  112. D4 = cmd & 1;
  113. D5 = (cmd >> 1) & 1;
  114. D6 = (cmd >> 2) & 1;
  115. D7 = (cmd >> 3) & 1;
  116. EN = 1; __delay_ms(1); EN = 0;
  117.  
  118. __delay_ms(2);
  119. }
  120.  
  121. void Lcd_Char(char data) {
  122. RS = 1;
  123. D4 = (data >> 4) & 1;
  124. D5 = (data >> 5) & 1;
  125. D6 = (data >> 6) & 1;
  126. D7 = (data >> 7) & 1;
  127. EN = 1; __delay_ms(1); EN = 0;
  128.  
  129. D4 = data & 1;
  130. D5 = (data >> 1) & 1;
  131. D6 = (data >> 2) & 1;
  132. D7 = (data >> 3) & 1;
  133. EN = 1; __delay_ms(1); EN = 0;
  134.  
  135. __delay_ms(2);
  136. }
  137.  
  138. void Lcd_Init() {
  139. Lcd_Command(0x02); // Initialize
  140. Lcd_Command(0x28); // 4-bit mode, 2-line, 5x7
  141. Lcd_Command(0x0C); // Display ON, Cursor OFF
  142. Lcd_Command(0x06); // Auto-increment
  143. Lcd_Command(0x01); // Clear display
  144. }
  145.  
  146. void Lcd_String(const char *str) {
  147. while(*str) Lcd_Char(*str++);
  148. }
  149.  
  150. void Lcd_Clear() {
  151. Lcd_Command(0x01);
  152. }
  153.  
  154. void Lcd_Set_Cursor(char row, char col) {
  155. char pos;
  156. if(row == 1) pos = 0x80 + (col - 1);
  157. else pos = 0xC0 + (col - 1);
  158. Lcd_Command(pos);
  159. }
  160.  
  161. // ================= INTERRUPT SERVICE ROUTINE =================
  162. void __interrupt() ISR(void) {
  163. if (INTF) { // RB0 interrupt flag
  164. pulse_count++;
  165. INTF = 0; // Clear interrupt flag
  166. }
  167. }
  168.  
Success #stdin #stdout 0.03s 25724KB
stdin
Standard input is empty
stdout
#include <xc.h>
#include <stdio.h>

// ================= CONFIG =================
// Use these settings in MPLAB/XC8
#pragma config FOSC = HS        // HS oscillator
#pragma config WDTE = OFF       // Watchdog Timer disabled
#pragma config PWRTE = ON       // Power-up Timer enabled
#pragma config BOREN = ON       // Brown-out Reset enabled
#pragma config LVP = OFF        // Low-Voltage Programming disabled
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection off
#pragma config WRT = OFF        // Flash Program Memory Write Protection off
#pragma config CP = OFF         // Flash Program Memory Code Protection off

#define _XTAL_FREQ 20000000     // 20 MHz Crystal (change if different)

// ================= LCD CONNECTIONS =================
// LCD on PORTD
#define RS RD0
#define EN RD1
#define D4 RD2
#define D5 RD3
#define D6 RD4
#define D7 RD5

// ================= FUNCTION PROTOTYPES =================
void Lcd_Command(char);
void Lcd_Char(char);
void Lcd_Init(void);
void Lcd_String(const char *);
void Lcd_Clear(void);
void Lcd_Set_Cursor(char, char);
unsigned int Read_ADC(unsigned char channel);

// ================= GLOBAL VARIABLES =================
volatile unsigned int pulse_count = 0;
unsigned int heart_rate = 0;

// ================= MAIN PROGRAM =================
void main(void) {
    unsigned int adc_value;
    float temperature;
    char buffer[16];

    // ADC setup
    ADCON1 = 0x80;      // Right justified, Vref=VDD
    ADCON0 = 0x41;      // ADC enabled, Channel 0 (AN0)

    // LCD setup
    TRISD = 0x00;       // LCD port output
    Lcd_Init();

    // RB0 as heart pulse input (external interrupt)
    TRISB0 = 1;         // RB0 input
    INTEDG = 1;         // Interrupt on rising edge
    INTE = 1;           // Enable RB0 external interrupt
    GIE = 1;            // Enable global interrupts

    // Timer1 for 1-second period
    T1CON = 0x31;       // Prescaler 8, Timer1 ON
    TMR1H = 0;
    TMR1L = 0;

    while(1) {
        // ====== Read Temperature from LM35 ======
        adc_value = Read_ADC(0);                    // Read AN0
        temperature = (adc_value * 4.88) / 10.0;    // LM35 = 10mV/°C

        // ====== Heart Rate Calculation every ~1s ======
        if (TMR1H > 0x3C) {   // Adjust for ~1 second
            heart_rate = pulse_count * 60; // convert to bpm
            pulse_count = 0;
            TMR1H = 0;
            TMR1L = 0;
        }

        // ====== Display on LCD ======
        Lcd_Clear();

        sprintf(buffer, "Temp: %.1f C", temperature);
        Lcd_Set_Cursor(1, 1);
        Lcd_String(buffer);

        sprintf(buffer, "HR: %u bpm", heart_rate);
        Lcd_Set_Cursor(2, 1);
        Lcd_String(buffer);

        __delay_ms(500);
    }
}

// ================= ADC FUNCTION =================
unsigned int Read_ADC(unsigned char channel) {
    if(channel > 7) return 0;   // PIC16F877A has 8 ADC channels (AN0–AN7)

    ADCON0 = (channel << 3) | 0x41;  // Select channel, turn on ADC
    __delay_ms(2);                   // Acquisition time
    GO_DONE = 1;                     // Start conversion
    while(GO_DONE);                  // Wait until done
    return ((ADRESH << 8) + ADRESL); // Return result
}

// ================= LCD FUNCTIONS =================
void Lcd_Command(char cmd) {
    RS = 0;
    D4 = (cmd >> 4) & 1;
    D5 = (cmd >> 5) & 1;
    D6 = (cmd >> 6) & 1;
    D7 = (cmd >> 7) & 1;
    EN = 1; __delay_ms(1); EN = 0;

    D4 = cmd & 1;
    D5 = (cmd >> 1) & 1;
    D6 = (cmd >> 2) & 1;
    D7 = (cmd >> 3) & 1;
    EN = 1; __delay_ms(1); EN = 0;

    __delay_ms(2);
}

void Lcd_Char(char data) {
    RS = 1;
    D4 = (data >> 4) & 1;
    D5 = (data >> 5) & 1;
    D6 = (data >> 6) & 1;
    D7 = (data >> 7) & 1;
    EN = 1; __delay_ms(1); EN = 0;

    D4 = data & 1;
    D5 = (data >> 1) & 1;
    D6 = (data >> 2) & 1;
    D7 = (data >> 3) & 1;
    EN = 1; __delay_ms(1); EN = 0;

    __delay_ms(2);
}

void Lcd_Init() {
    Lcd_Command(0x02);   // Initialize
    Lcd_Command(0x28);   // 4-bit mode, 2-line, 5x7
    Lcd_Command(0x0C);   // Display ON, Cursor OFF
    Lcd_Command(0x06);   // Auto-increment
    Lcd_Command(0x01);   // Clear display
}

void Lcd_String(const char *str) {
    while(*str) Lcd_Char(*str++);
}

void Lcd_Clear() {
    Lcd_Command(0x01);
}

void Lcd_Set_Cursor(char row, char col) {
    char pos;
    if(row == 1) pos = 0x80 + (col - 1);
    else pos = 0xC0 + (col - 1);
    Lcd_Command(pos);
}

// ================= INTERRUPT SERVICE ROUTINE =================
void __interrupt() ISR(void) {
    if (INTF) {   // RB0 interrupt flag
        pulse_count++;
        INTF = 0; // Clear interrupt flag
    }
}