/******* Measure.c ************* * * A number between 0 and 9999 is converted to ASCII-coded digits two ways: * ASCII4 forms each digit by successive subtractions (up to 353 cycles). * ASCII4D forms each digit via two divisions (up to 1498 cycles). * Then a number between 0 and 255 is converted to ASCII-coded digits two ways: * ASCII forms each digit by successive subtractions (up to 98 cycles). * ASCIID forms each digit via two divisions (up to 357 cycles). * For each one, the result is displayed on the LCD. * The execution time (cycles)is displayed on the PC * Execution stops with a sleep command. * * Start and Stop functions are added to measure the execution time of the * code between them. The Send function sends the time to the PC monitor. * * Use Fosc = 4 MHz for Fcpu = Fosc/4 = 1 MHz. * ******* Program hierarchy ***** * * main * Initial * InitTX * Start * Stop * Send * TXascii * ASCII4 * ASCII4D * ASCII * ASCIID * 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 int DELAY; // Sixteen-bit counter for obtaining a delay unsigned char NUMBER; // Eight-bit number to be converted unsigned int BIGNUM; // Sixteen-bit number to be converted unsigned char THOUSANDS,HUNDREDS,TENS,ONES; // ASCII coding of digits unsigned char i; // Index into strings unsigned int CYCLES; // Result of Timer0 counting cycles char LCDSTRING[] = " "; // Nine-character display string /******************************* * Function prototypes ******************************* */ void Initial(void); void InitTX(void); void Start(void); void Stop(void); void Send(void); void ASCII4(void); void ASCII4D(void); void ASCII(void); void ASCIID(void); void Display(void); /******************************* * Macros ******************************* */ #define Delay(x) DELAY = x; while(--DELAY){ Nop(); Nop(); } #define TXascii(in) TXREG = in; while(!TXSTAbits.TRMT) /////// Main program ////////////////////////////////////////////////////////// /******************************* * main ******************************* */ void main() { Initial(); // Initialize everything InitTX(); // and the UART as well BIGNUM = 9999; Start(); ASCII4(); // Convert BIGNUM Takes 353 cycles Stop(); LCDSTRING[0] = THOUSANDS; LCDSTRING[1] = HUNDREDS; LCDSTRING[2] = TENS; LCDSTRING[3] = ONES; Send(); // Send cycle count to PC for display LCDSTRING[4] = '.'; // Use decimal point as separator BIGNUM = 9999; Start(); ASCII4D(); // Convert BIGNUM Takes 1498 cycles Stop(); LCDSTRING[5] = THOUSANDS; LCDSTRING[6] = HUNDREDS; LCDSTRING[7] = TENS; LCDSTRING[8] = ONES; Send(); // Send this cycle count to PC for display Display(); // Verify correct conversions on LCD Delay(50000); Delay(50000); Delay(50000); Delay(50000) // Two-second pause NUMBER = 199; Start(); ASCII(); // Convert NUMBER Takes 98 cycles Stop(); LCDSTRING[0] = ' '; LCDSTRING[1] = HUNDREDS; LCDSTRING[2] = TENS; LCDSTRING[3] = ONES; Send(); // Send cycle count to PC for display LCDSTRING[4] = '.'; // Use decimal point as separator NUMBER = 199; Start(); ASCIID(); // Convert NUMBER Takes 357 cycles Stop(); LCDSTRING[5] = ' '; LCDSTRING[6] = HUNDREDS; LCDSTRING[7] = TENS; LCDSTRING[8] = ONES; Send(); // Send this cycle count to PC for display Display(); // Verify correct conversions on LCD Sleep(); // Sleep forever } /******************************* * 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 } /******************************* * InitTX * * This function initializes the UART for its TX output function. It assumes * Fosc = 4 MHz. For a different oscillator frequency, use Figure 6-3c to * change BRGH and SPBRG appropriately. ******************************* */ void InitTX() { RCSTA = 0b10010000; // Enable UART TXSTA = 0b00100000; // Enable TX SPBRG = 12; // Set baud rate BAUDCON = 0b00111000; // Invert TX output } /******************************* * Start * * This function clears Timer0 and then starts it counting. ******************************* */ void Start() { T0CON = 0b00001000; // Set up Timer0 to count CPU clock cycles TMR0H = 0; // Clear Timer0 TMR0L = 0; T0CONbits.TMR0ON = 1; // Start counting } /******************************* * Stop * * This function stops counting Timer0, and reads the result into CYCLES. ******************************* */ void Stop() { T0CONbits.TMR0ON = 0; // Stop counting CYCLES = TMR0L; // Form CYCLES from TMR0H:TMR0L CYCLES += (TMR0H * 256); CYCLES -= 3; // Remove 3 counts so back-to-back Start-Stop } // functions produce CYCLES = 0 /******************************* * Send * * This function converts CYCLES to four ASCII-coded digits and sends * the result to the PC for display. ******************************* */ void Send() { BIGNUM = CYCLES; // Load ASCII4's input parameter ASCII4(); // Convert TXascii('\r'); // Send carriage return TXascii('\n'); // Send line feed TXascii(THOUSANDS); // Send four-digit number TXascii(HUNDREDS); TXascii(TENS); TXascii(ONES); } /******************************* * 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 } /******************************* * ASCII * * This function converts the unsigned char parameter passed to it * in NUMBER, that ranges between 0 and 255, to three ASCII-coded digits * by performing successive subtractions. * Simplified by Chad Kersey. Takes up to 98 cycles. ******************************* */ void ASCII() { ONES = TENS = HUNDREDS ='0'; //Initialize to ASCII zeroes while (NUMBER >= 100) { HUNDREDS++; NUMBER -= 100; } // Form HUNDREDS while (NUMBER >= 10) { TENS++; NUMBER -= 10; } // Form TENS ONES += NUMBER; // Form ONES } /******************************* * ASCIID * * This function converts the unsigned char parameter passed to it * in NUMBER, that ranges between 0 and 255, to three ASCII-coded digits * by performing successive divisions. Takes up to 357 cycles. ******************************* */ void ASCIID() { ONES = '0' + (NUMBER % 10); // Form ONES NUMBER = NUMBER / 10; TENS = '0' + (NUMBER % 10); // Form TENS HUNDREDS = '0' + (NUMBER / 10); // Form HUNDREDS } /******************************* * 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 } /******************************* * ASCII4D * * 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 divisions. Takes up to 1498 cycles. ******************************* */ void ASCII4D() { ONES = '0' + (BIGNUM % 10); // Form ONES BIGNUM = BIGNUM / 10; TENS = '0' + (BIGNUM % 10); // Form TENS BIGNUM = BIGNUM /10; HUNDREDS = '0' + (BIGNUM % 10); // Form HUNDREDS THOUSANDS = '0' + (BIGNUM / 10); // Form THOUSANDS }