// module11.c RGD 3/10/04 // // This program will use the ICD-2 in circuit debugger to program the PIC16F887 chip // on the LCD-SD-USB Board for ME499 // // Use PCW (14-bit compiler) to compile. // Circuit configuration: // HS crystal Oscillator, crystal=4 MHz, 1 MHz instruction cycle, watch dog timer ON, Code Protect OFF #include <16F877.H> #include #include #fuses HS, WDT, NOPROTECT // This sets up the internal device fuses: HS crystal, WDT ON, Code Protect OFF #use delay (clock=4000000) // 4 MHz crystal, 1 microsecond instruction cycle time. #byte PORTA = 0x05 #byte PORTB = 0x06 #byte PORTC = 0x07 #byte PORTD = 0x08 #byte PORTE = 0x09 #use FAST_IO(A) #use FAST_IO(C) unsigned int i; // buffer variable for the detected state of PORTb unsigned int b; // bit counter for the 16-bit ADC unsigned int c; // SClk count down counter for ADCs unsigned int d; // A digit (0 1 2 3 4 5 6 7 8 9 : ; < = . /) to be displayed on the LCD module unsigned long int j; unsigned long int btd; // long 16-bit binary number for use in binary-to-decimal conversions unsigned int k; // just a useful variable unsigned int t; // long time delay variable (0 < t <= 255), in increments of 1/4 second unsigned int p; // a character (from the list below) to be printed to the LCD display short int flip; // variable for flashing LED // Variables for calculating 16-bit median values: unsigned long int v0[9] = {0,0,0,0,0,0,0,0,0}; unsigned long int v0_carry = 0; unsigned long int v1[9] = {0,0,0,0,0,0,0,0,0}; unsigned long int v1_carry = 0; // Variables for carrying out floating point calculations for calibrations etc... float x_float = 0; // Character Set for use with LDC display: // Digit character constants: byte const d0 = 48; // ASCII character "0" byte const d1 = 49; byte const d2 = 50; byte const d3 = 51; byte const d4 = 52; byte const d5 = 53; byte const d6 = 54; byte const d7 = 55; byte const d8 = 56; byte const d9 = 57; byte const EQ = 61; // "=" equals sign byte const SP = 32; // " "blank space byte const DP = 46; // "." decimal point // Upper case character constants: byte const A_ = 65; // ASCII character "A" byte const B_ = 66; byte const C_ = 67; byte const D_ = 68; byte const E_ = 69; byte const F_ = 70; byte const G_ = 71; byte const H_ = 72; byte const I_ = 73; byte const J_ = 74; byte const K_ = 75; byte const L_ = 76; byte const M_ = 77; byte const N_ = 78; byte const O_ = 79; byte const P_ = 80; byte const Q_ = 81; byte const R_ = 82; byte const S_ = 83; byte const T_ = 84; byte const U_ = 85; byte const V_ = 86; byte const W_ = 87; byte const X_ = 88; byte const Y_ = 89; byte const Z_ = 90; // Lower case character constants: byte const aa = 97; // ASCII character "a" byte const bb = 98; byte const cc = 99; byte const dd = 100; byte const ee = 101; byte const ff = 102; byte const gg = 103; byte const hh = 104; byte const ii = 105; byte const jj = 106; byte const kk = 107; byte const ll = 108; byte const mm = 109; byte const nn = 110; byte const oo = 111; byte const pp = 112; byte const qq = 113; byte const rr = 114; byte const ss = 115; byte const tt = 116; byte const uu = 117; byte const vv = 118; byte const ww = 119; byte const xx = 120; byte const yy = 121; byte const zz = 122; // ADC variables: unsigned long int setpoint; // position set point for servo, 16-bits unsigned long int error; // position error, 16-bits unsigned long int volts0; // 16-bit voltage value from ADC# 1 input A0 (0 - 65,535) unsigned long int volts1; // 16-bit voltage value from ADC# 2 input A1 // 0 = 0.0 V // 13107 = 1.0 V // 26214 = 2.0 V // 39321 = 3.0 V // 52428 = 4.0 V // 65535 = 5.0 V /////////////////////////////////////// // SUBROUTINES void init_ports(void) { SET_TRIS_A(0b00000011); // PORTA = all outputs SET_TRIS_B(0b00000000); // PORTB = all outputs SET_TRIS_C(0b00000000); // PORTC = all outputs (motor drivers and PWMs) SET_TRIS_D(0b00000000); // PORTD = all outputs SET_TRIS_E(0b00000000); // PORTE = all outputs SETUP_COUNTERS(RTCC_INTERNAL, WDT_1152MS); // Set Watch Dog Timer prescaler to 1152 ms // The Watch Dog Timer (WDT) is just an internal timer for the microprocessor that runs off // on the side independently. If the microprocessor hangs up or gets confused, the WDT // will reset the microprocessor to the first line of the executable code "main()". // To stop this from happening accidentally, we need to reset the WDT very frequently. // in this case, every second or less. Otherwise, the controller will reset automatically. // Default output values: PORT_B_PULLUPS(TRUE); // enable PORT B pullups // May need to do more than this to stabilize B3 sensitivity after ICSP // see the PIC16F8X programming PDF for more information: see section 3.4.1 on LVP mode and bit B3 PORTC = 0b00000000; // set all motor drivers and PWM outputs to OFF PORTD = 0b00000000; // set DATA bus to OFF PORTE = 0b00000000; OUTPUT_BIT(PIN_A2, 1); // ADC Chip Select (active LOW) OUTPUT_BIT(PIN_A3, 1); // ADC Serial Clock (active on FALLING Edge) // Default variable values flip = 0; i = 0; j = 0; k = 0; b = 0; t = 0; // This will be the value of the RTCC timer } ///////////////////////////////////////////////////// void delay_one_sec(t){ // delay for a long period, "t" quarters of a second, 0 < t < 255 while(t > 0){ delay_ms(250); restart_wdt(); // Strobe the amber LED: OUTPUT_BIT(PIN_A5, flip); // strobe the amber LED flip = !flip; // this is now the ENABLE pin OUTPUT_BIT(PIN_E0, flip); // strobe the green LED t = t - 1; } } /////////////////////////////////////////////////////////////////////////// void LCD_enable(void) { // send one ENABLE pulse to the LCD Display delay_ms(1); // allow data bus (PORTD) to settle OUTPUT_BIT(PIN_E0, 1); // cycle Enable pulse ON for 1 ms delay_ms(1); OUTPUT_BIT(PIN_E0, 0); delay_ms(1); restart_wdt(); } ///////////////////////////////////////////////////// void print(p){ // print a character to the LCD display OUTPUT_BIT(PIN_B6, 0); // set R/W = 0, keep set to 0 permanently unless reading from LCD OUTPUT_BIT(PIN_B7, 1); // set RS = 1 to enable writing to display PORTD = p; // set character value on data lines LCD_enable(); // send command to display the character restart_wdt(); } //////////////////////////////////////////////////////////////////////////////// void line2(void){ // set LCD cursor to the start of Line 2 OUTPUT_BIT(PIN_B7, 0); // set RS for command output PORTD = 0b11000000; LCD_enable(); // send command OUTPUT_BIT(PIN_B7, 1); // re-set RS for character output restart_wdt(); } ///////////////////////////////////////////////////////////////////////////////// void clear_display(void){ // clear the display and return cursor to the HOME position OUTPUT_BIT(PIN_B7, 0); // set RS for command output PORTD = 0b00000001; LCD_enable(); // send command OUTPUT_BIT(PIN_B7, 1); // re-set RS for character output restart_wdt(); } /////////////////////////////////////////////////////////////////////////// void init_LCD(void) { // Initialize the LCD Display (DMC16204) in 8-bit mode // Data = PORTD // E = PIN_E0 // R/W = PIN_B6 SHOULD ALWAYS BE SET R/W = 0 // RS = PIN_B7 COMMAND = 0, CHARACTER = 1 OUTPUT_BIT(PIN_E0, 0); // set LCD ENABLE = 0 delay_one_sec(2); // allow power-up // 8-bit Function Set Command, [DMC16204 User Manual, pg 31-32, example sequence pg 44] OUTPUT_BIT(PIN_B6, 0); // set RW OUTPUT_BIT(PIN_B7, 0); // set RS PORTD = 0b00111000; // set interface for 8-bit, 2-line display, 5 x 7 dot character font LCD_enable(); // cycle Enable pulse delay_ms(10); LCD_enable(); // cycle Enable pulse again to repeat command after a delay delay_ms(10); PORTD = 0b00001110; // display ON, cursor ON LCD_enable(); // cycle Enable pulse clear_display(); // clear display and place cursor at HOME position PORTD = 0b00000110; // Entry Set Mode (Increment Mode and Display Shift Mode) LCD_enable(); // cycle Enable pulse OUTPUT_BIT(PIN_B6, 0); // set R/W = 0, keep set to 0 permanently unless reading from LCD OUTPUT_BIT(PIN_B7, 1); // set RS = 1 to enable writing to display clear_display(); // clear display and place cursor at HOME position // Initialization is complete, display is ready for use } /////////////////////////////////////////////////////// void message(void){ // sends a pre-set message to the LCD OUTPUT_BIT(PIN_B7, 1); // set RS = 1 to enable writing to display clear_display(); print(I_); print(nn); print(ii); print(tt); print(ii); print(aa); print(ll); print(ii); print(zz); print(ii); print(nn); print(gg); line2(); // send cursor to the beginning of line 2 of the LCD display print(H_); print(aa); print(rr); print(dd); print(ww); print(aa); print(rr); print(ee); } /////////////////////////////////////////////////////// void message_2(void){ // sends a pre-set message to the LCD OUTPUT_BIT(PIN_B7, 1); // set RS = 1 to enable writing to display clear_display(); print(S_); print(U_); print(C_); print(C_); print(E_); print(S_); print(S_); } /////////////////////////////////////////////////////// void message_3(void){ // sends a pre-set message to the LCD OUTPUT_BIT(PIN_B7, 1); // set RS = 1 to enable writing to display clear_display(); print(D_); print(ee); print(vv); print(ii); print(cc); print(ee); print(SP); print(hh); print(aa); print(ss); print(SP); print(bb); print(ee); print(ee); print(nn); line2(); // send cursor to the beginning of line 2 of the LCD display print(rr); print(ee); print(pp); print(rr); print(oo); print(gg); print(rr); print(aa); print(mm); print(mm); print(ee); print(dd); } ////////////////////////////////////////////////////////////////////////////// void init_adc(void) { // Initialize the TLC4545 16-bit ADC // A0 & A1 = SDO Data // A2 = /CS (chip select, active LOW) // A3 = CLK restart_wdt(); OUTPUT_BIT(PIN_A2, 1); // Chip Select (active LOW) OUTPUT_BIT(PIN_A3, 1); // Serial Clock (active on FALLING Edge) delay_cycles(4); // Select ADC Chip OUTPUT_BIT(PIN_A2, 0); // Chip Select (active LOW) OUTPUT_BIT(PIN_A3, 1); // Serial Clock (active on FALLING Edge) delay_cycles(4); // Cycle Serial Clock 4 times with CS = LOW to reset ADC: OUTPUT_BIT(PIN_A3, 1); // Serial Clock (active on FALLING Edge) delay_cycles(4); OUTPUT_BIT(PIN_A3, 0); // Serial Clock (active on FALLING Edge) delay_cycles(4); OUTPUT_BIT(PIN_A3, 1); // Serial Clock (active on FALLING Edge) delay_cycles(4); OUTPUT_BIT(PIN_A3, 0); // Serial Clock (active on FALLING Edge) delay_cycles(4); OUTPUT_BIT(PIN_A3, 1); // Serial Clock (active on FALLING Edge) delay_cycles(4); OUTPUT_BIT(PIN_A3, 0); // Serial Clock (active on FALLING Edge) delay_cycles(4); OUTPUT_BIT(PIN_A3, 1); // Serial Clock (active on FALLING Edge) delay_cycles(4); OUTPUT_BIT(PIN_A3, 0); // Serial Clock (active on FALLING Edge) delay_cycles(4); OUTPUT_BIT(PIN_A3, 1); // Serial Clock (active on FALLING Edge) delay_cycles(4); OUTPUT_BIT(PIN_A2, 1); // Deselect Chip Select (active LOW) restart_wdt(); } /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // PIC16F877 goes here at RESET void main() { restart_wdt(); // Reset the WDT init_ports(); // Initialize ports init_LCD(); // Initialize LCD message(); // send initialization message to the LCD init_adc(); // Initialize the 16-bit ADCs restart_wdt(); // Reset the WDT CYCLE: // Run continuously restart_wdt(); // Reset the WDT delay_one_sec(4); // delays "n" quarters of a second message_2(); // send text message to the LCD delay_one_sec(6); // delays "n" quarters of a second message_3(); // send text message to the LCD goto CYCLE; } // main