/******* TenthsFahr.c ********** * * Display the temperature in tenths of a degree Fahrenheit. Resolution of * ten-bit ADC imposes a maximum resolution of 0.2 degree Fahrenheit. * * Calculation: TENTHF = (((2121*ADRES)>>8)>>8) +159 broken out into * individual operations, to optimize the compilation. * * Use Fosc = 4 MHz for Fcpu = Fosc/4 = 1 MHz. * Sleep for 16 ms (nominal), using watchdog timeout for wakeup. * ******* Program hierarchy ***** * * main * Initial * BlinkAlive * Temperature * ASCII4 * Display * ******************************* */ #include // Define PIC18LF4321 registers and bits /******************************* * Configuration selections ******************************* */ #pragma config OSC = INTIO1 // Use internal osc, RA6=Fosc/4, RA7=I/O #pragma config PWRT = ON // Enable power-up delay #pragma config LVP = OFF // Disable low-voltage programming #pragma config WDT = OFF // Disable watchdog timer initially #pragma config WDTPS = 4 // 16 millisecond WDT timeout period, nominal #pragma config MCLRE = ON // Enable master clear pin #pragma config PBADEN = DIG // PORTB<4:0> = digital #pragma config CCP2MX = RB3 // Connect CCP2 internally to RB3 pin #pragma config BOR = SOFT // Brown-out reset controlled by software #pragma config BORV = 3 // Brown-out voltage set for 2.1V, nominal #pragma config LPT1OSC = OFF // Deselect low-power Timer1 oscillator /******************************* * Global variables ******************************* */ unsigned char ALIVECNT; // Scale-of-248 counter for blinking "Alive" LED unsigned char TEMPCNT; // Scale-of-31 counter for half-second samples unsigned char i; // Index into strings unsigned long VALUE; // Thirty-two bit value of temperature for calc. unsigned int DELAY; // Sixteen-bit counter for obtaining a delay signed int BIGNUM; // Sixteen-bit parameter for ASCII conversion unsigned char THOUSANDS,HUNDREDS,TENS,ONES; // ASCII coding of digits char LCDSTRING[] = " "; // Nine-character display string /******************************* * Function prototypes ******************************* */ void Initial(void); void BlinkAlive(void); void Temperature(void); void Display(void); void ASCII4(void); /******************************* * Macros ******************************* */ #define Delay(x) DELAY = x; while(--DELAY){ Nop(); Nop(); } /////// Main program ////////////////////////////////////////////////////////// /******************************* * main ******************************* */ void main() { Initial(); // Initialize everything while (1) { PORTCbits.RC2 ^= 1; // Toggle pin, for measuring loop time BlinkAlive(); // Blink "Alive" LED Temperature(); // Display pot value or "temperature" value Sleep(); // Sleep, letting watchdog timer wake up chip Nop(); } } /******************************* * Initial * * This function performs all initializations of variables and registers. ******************************* */ void Initial() { OSCCON = 0b01100010; // Use Fosc = 4 MHz (Fcpu = 1 MHz) SSPSTAT = 0b00000000; // Set up SPI for output to LCD SSPCON1 = 0b00110000; ADCON1 = 0b00001011; // RA0,RA1,RA2,RA3 pins analog; others digital TRISA = 0b00001111; // Set I/O for PORTA TRISB = 0b01000100; // Set I/O for PORTB TRISC = 0b10000000; // Set I/O for PORTC TRISD = 0b10000000; // Set I/O for PORTD TRISE = 0b00000010; // Set I/O for PORTE PORTA = 0; // Set initial state for all outputs low PORTB = 0; PORTC = 0; PORTD = 0b00100000; // except RD5 that drives LCD interrupt PORTE = 0; SSPBUF = ' '; // Send a blank to initialize state of UART Delay(50000); // Pause for half a second RCONbits.SBOREN = 0; // Now disable brown-out reset ALIVECNT = 247; // Blink immediately TEMPCNT = 30; // Convert temperature immediately WDTCONbits.SWDTEN = 1; // Enable watchdog timer } /******************************* * BlinkAlive * * This function briefly blinks the LED every four seconds. * With a looptime of about 16 ms, count 4x62 = 248 looptimes ******************************* */ void BlinkAlive() { PORTDbits.RD4 = 0; // Turn off LED if (++ALIVECNT == 248) // Increment counter and return if not 248 { ALIVECNT = 0; // Reset ALIVECNT PORTDbits.RD4 = 1; // Turn on LED for 16 ms every 4 secs } } /******************************* * Temperature * * Update temperature display every half second using Figure 9-9 algorithm. ******************************* */ void Temperature() { if (++TEMPCNT == 31) // Increment counter and return if not 31 { TEMPCNT = 0; // Reset TEMPCNT PORTDbits.RD6 = 1; // Power up temperature sensor ADCON1 = 0b00011011; // Use VREF+ ADCON2 = 0b00001001; // Left-justify result Delay(2); // Wait 20 usec ADCON0 = 0x07; // Power up ADC; select temperature; convert while(ADCON0bits.GO_DONE); // Wait for completion of conversion PORTDbits.RD6 = 0; // Power down temperature sensor ADCON0bits.ADON = 0; // Power down ADC VALUE = ADRES; // Copy to 32-bit VALUE to avoid overflow VALUE *= 2121; // These 5 lines add 216 bytes and 111 us VALUE >>= 8; VALUE >>= 8; VALUE += 159; BIGNUM = VALUE; // Copy result to 16-bit BIGNUM ASCII4(); // Break out digits LCDSTRING[2] = THOUSANDS; LCDSTRING[3] = HUNDREDS; LCDSTRING[4] = TENS; LCDSTRING[6] = ONES; LCDSTRING[5] = '.'; LCDSTRING[7] = '?'; // Degree symbol LCDSTRING[8] = 'F'; if (LCDSTRING[2] = '0') // Blank leading zero { LCDSTRING[2] = ' '; } PORTBbits.RB1 = 0; Display(); } } /******************************* * Display() * * This function sends LCDSTRING to the LCD. ******************************* */ void Display() { PORTDbits.RD5 = 0; // Wake up LCD display for (i = 0; i <= 8; i++) { PIR1bits.SSPIF = 0; // Clear SPI flag SSPBUF = LCDSTRING[i]; // Send byte while (!PIR1bits.SSPIF); // Wait for transmission to complete } PORTDbits.RD5 = 1; // Return RB5 high, ready for next string } /******************************* * ASCII4 * * This function converts the unsigned int parameter passed to it * in BIGNUM, that ranges between 0 and 9999, to four ASCII-coded digits * by performing successive subtractions. * Simplified by Chad Kersey. Takes up to 353 cycles. ******************************* */ void ASCII4() { ONES = TENS = HUNDREDS = THOUSANDS ='0'; //Initialize to ASCII zeroes while (BIGNUM >= 1000) { THOUSANDS++; BIGNUM -= 1000; } // Form THOUSANDS while (BIGNUM >= 100) { HUNDREDS++; BIGNUM -= 100; } // Form HUNDREDS while (BIGNUM >= 10) { TENS++; BIGNUM -= 10; } // Form TENS ONES += BIGNUM; // Form ONES }