#include #include #include #include /* Set up the configuration bits */ #pragma config OSC = HS #pragma config PWRT = OFF #pragma config BOR = OFF #pragma config WDT = OFF #pragma config LVP = OFF #define BAUD 9600 #define FOSC 20000000L #define MIPS 5 #define LOW_PULSE_PERIOD (500L) // in ms #define HIGH_PULSE_PERIOD (100L) // in ms #define LOW_PULSE_COUNT (0xFFFF - (LOW_PULSE_PERIOD*MIPS*1000L)/256L) #define HIGH_PULSE_COUNT (0xFFFF - (HIGH_PULSE_PERIOD*MIPS*1000L)/256L) #define ERROR 1 #define DEVICE_ADDRESS 0b10010000 // Address(7:1) static unsigned int T0_pulse_count; static signed char current_temp; static signed char assigned_temp; static char state = 'O'; // off; + -> heat; - -> cold void interrupt_handler (void); #pragma code high_vector=0x08 void high_priority_interrupt (void) { _asm GOTO interrupt_handler _endasm } #pragma code void usart_setup(void) { // Set the port direction. TRISCbits.TRISC6 = 0; TRISCbits.TRISC7 = 1; // High baud rate select (TXSTA) TXSTAbits.BRGH = 1; // compute the divider for speed (see page 161) SPBRG = ((int)(FOSC/(16UL * BAUD) -1)); // Asynchronous mode (TXSTA) TXSTAbits.SYNC = 0; // 8 bits reception (RCSTA) RCSTAbits.RX9 = 0; // enable the receiver (RCSTA) RCSTAbits.CREN = 1; // 8 bits transmission (TXTSA) TXSTAbits.TX9 = 0; // enable transmission (TXTSA) TXSTAbits.TXEN = 1; // enable the Serial Port (RCSTA) RCSTAbits.SPEN = 1; } void io_port_setup(void) { // RE2 for input and RE1 for output; TRISE = 0b00000100; // RE1 (LED) is on; PORTE = 0b00000010; // RA0 for input; TRISA = 0b00000001; // Select AN0 as Anolog and AN6/7 (RE1/2) as digital // We are using the internal reference (VDD) // PCFG3:0 = 0010 ADCON1 = 0b00001001; // Result is left aligned in ADRESH ADCON1bits.ADFM = 0; // Conversion clock set to Fosc/32 (ADCS2:0 = 010) // Fosc = 20Mhz ADCON1bits.ADCS2 = 0; ADCON0bits.ADCS1 = 1; ADCON0bits.ADCS0 = 0; // We are sampling AN0: CHS2:0 = 000 // ADCON0 = ((ADCON0 & 0b11100011) | 0b00000000); ADCON0bits.CHS2 = 0; ADCON0bits.CHS1 = 0; ADCON0bits.CHS0 = 0; // Powering the module ADCON0bits.ADON = 1; // Clears A2D interrupt flag PIR1bits.ADIF = 0; // Allows A2D to trigger an interrupt PIE1bits.ADIE = 1; // acquisition delay? // Starting the fist conversion ADCON0bits.GO = 1; } void update_T0_value(unsigned int value) { TMR0H = value >> 8; TMR0L = value & 0xFF; } void timer0_setup(void) { T0_pulse_count = LOW_PULSE_COUNT; // Select low to high transition T0CONbits.T0CS = 0; // Select the pre-scaler T0CONbits.PSA = 0; // Set the pre-scaler value (T0PS2:0 = 111 -> 256) T0CON = ((T0CON & 0b11111000) | 0b00000111); // Set TO to be a 16bits timer T0CONbits.T08BIT = 0; // Load the timer value update_T0_value(T0_pulse_count); // Clear Timer0 interrupt flag INTCONbits.TMR0IF = 0; // Set Timer0 to trigger interrupt INTCONbits.TMR0IE = 1; // Start Timer0 T0CONbits.TMR0ON = 1; } void I2C_setup() { // Disable the SSP module for settings SSPCON1bits.SSPEN = 0; // Set the SSP as a I2C master SSPM3:0 -> 1000 SSPCON1 = (SSPCON1 & 0b11110000)|(0b00001000); // Set the Baud generator (20MHz/100KHz)/4 - 1 = 49; SSPADD = 49; // Standard speed mode (no Slew control) SSPSTATbits.SMP = 1; // set SCK (RC3) and SDI (RC4) as input TRISCbits.TRISC3 = 1; TRISCbits.TRISC4 = 1; SSPCON1bits.WCOL = 0; // Enable the SSP module SSPCON1bits.SSPEN = 1; // Set the slave configuration // start event (S) SSPCON2bits.SEN = 1; while (SSPCON2bits.SEN == 1); // Address on the bus; SSPBUF = DEVICE_ADDRESS; while (SSPSTATbits.R_W == 1); // Command word on the bus; SSPBUF = 0; while (SSPSTATbits.R_W == 1); // Stop event (P) SSPCON2bits.PEN = 1; while (SSPCON2bits.PEN == 1); } signed char I2C_temp_read() { unsigned char result = 0; // start event (S) SSPCON2bits.SEN = 1; while (SSPCON2bits.SEN == 1); // Address on the bus (READ flag set); SSPBUF = DEVICE_ADDRESS | 0b00000001; while (SSPSTATbits.R_W == 1); // Prepare to received from the bus SSPCON2bits.RCEN = 1; // Wait until the received is done... while (SSPCON2bits.RCEN == 1); result = SSPBUF; // NACK to the slave SSPCON2bits.ACKDT = 1; SSPCON2bits.ACKEN = 1; while (SSPCON2bits.ACKEN == 1); // Stop event (P) SSPCON2bits.PEN = 1; while (SSPCON2bits.PEN == 1); return(result); } #pragma interrupt interrupt_handler void interrupt_handler(void) { if (PIR1bits.ADIF == 1) { // New A2D result! assigned_temp = 20 - ((ADRESH - 128)/8); switch (state) { case 'O': if (current_temp > (assigned_temp + ERROR)) { state = '-'; // Switch on the AC } if (current_temp < (assigned_temp - ERROR)) { state = '+'; // Switch on the Heat } break; case '+': if (current_temp >= assigned_temp) { state = 'O'; } break; case '-': if (current_temp <= assigned_temp) { state = 'O'; } break; default: break; } printf("Assigned: %d; Current: %d", assigned_temp, current_temp); switch (state) { case 'O': printf(" OFF \r"); break; case '+': printf(" HEAT ON\r"); break; case '-': printf(" AC ON \r"); break; default: break; } // Clear the interrupt flag PIR1bits.ADIF = 0; } if (INTCONbits.TMR0IF == 1) { // Timer expired // Load the new value update_T0_value(T0_pulse_count); current_temp = I2C_temp_read(); // Clear the interrupt flag INTCONbits.TMR0IF = 0; // Start a new conversion ADCON0bits.GO = 1; } } void main( void) { char input; // setup the ports io_port_setup(); // setup the USART usart_setup(); // setup timer_0; timer0_setup(); I2C_setup(); printf("\n\r"); printf("\n\r"); // Not Interupt Priority RCONbits.IPEN = 0; // Allows for Peripheral interrupts INTCONbits.PEIE = 1; // Interrupts are on INTCONbits.GIE = 1; // Loop forever while (1); }