/* ; This demo for the MAXQ2000 uses an LCD and a thermistor to display the ; current temperature. ; ; Features demostrated in this demo: ; 1) LCD controller ; 2) Timers ; 3) Hardware multiplier ; 4) SPI communication ; 5) Analog to digital conversion with external hardware (MAX1407) ; 6) Serial communication ; ; Functional overview: ; The timer is set to generate an interrupt at a regular interval. On an ; interrupt, the part performs a temperature reading, updates the LCD, and ; outputs the current temperature to the serial port. The units will also ; toggle between Celcius and Farhenheit after 20 interrupts. ; ; Parts required: ; (1) MAXQ2000 EV-KIT with attached LCD ; (1) 51K Ohm resistor ; (1) Thermistor ; ; Wiring requirements: ; ; The thermistor should be wired as follows: ; ; 51K Ohm between pin 1 of J7 and GND (1407:IN0 & GND) ; Thermistor between pin 1 and pin 7 of J7 (1407:IN0 & 1407:OUT2) ; Short between pin 7 and 8 of J7 (1407:OUT2 & 1407:FB2) ; ; These switches should be turned on: ; ; SW1.3 through SW1.8 ; SW3.1 through SW3.8 ; ; Once everything has been wired, you can run the demo from within IAR's ; Embedded Workbench IDE. After the demo is running, you should see the ; current temperature displayed on the LCD in degrees Celcius. ; */ #include #include #define USE_SERIAL 1 #if (USE_SERIAL) #include #endif #define WR_ADC 0x080 // 10 00000 0 #define WR_MUX 0x082 // 10 00001 0 #define WR_DAC2 0x08A // 10 00101 0 #define WR_RUN 0x0BA // 10 11101 0 #define RD_ADC 0x0C0 // 11 00000 0 #define RD_DATA 0x0C4 // 11 00010 0 #define RD_DAC2 0x0CA // 11 00101 0 #define RD_STAT 0x0CC // 11 00110 0 unsigned char celsius = 0; int count = 0; unsigned int sendSPI(unsigned int spib) { SPIB = spib; // Load the data to send while(SPICN_bit.STBY); // Loop until the data has been sent. SPICN_bit.SPIC = 0; // Clear the SPI tansfer complete flag. return SPIB; } unsigned int getADCReading() { unsigned int spiData; sendSPI(RD_ADC); // Read the 1407's ADC register. spiData = sendSPI(0x0FF); spiData |= 0x01; // Set the start conversion bit. sendSPI(WR_ADC); // Write the new value back into sendSPI(spiData); // the 1407 register. do { sendSPI(RD_STAT); // Read the 1407's Status register. spiData = sendSPI(0x0FF); } while((spiData & 0x02) == 0x00); // Bit 1 indicates AtoD conversion complete. sendSPI(RD_DATA); // Send the command to read the 1407's Data register. SPICF = 0x04; // Set up SPI to 16-bit mode. spiData = sendSPI(0x0FFFF); // Read the Data register. SPICF = 0x00; // Put SPI back into 8-bit mode. return spiData; } void init1407() { unsigned int spiData; int i; PD5 |= 0x070; // Set SPI output pins (CS, SCLK, DOUT) as output. PD5 &= ~0x080; // Set SPI input pin (DIN) as input. SPICK = 0x10; // Configure SPI for rising edge, sample input SPICF = 0x00; // on inactive edge, 8 bit, divide by 16. SPICN_bit.MSTM = 1; // Set Q2000 as the master. SPICN_bit.SPIEN = 1; // Enable SPI. P05 &= ~0x10; // Set /CS low. sendSPI(WR_RUN); // Make sure 1407 is up and running by putting // it into RUN mode. sendSPI(WR_ADC); // Set up the 1407 ADC to sample at 30Hz, unbuffered, sendSPI(0x10); // in unipolar mode. Also sets the PGA to 1. sendSPI(WR_MUX); // Set up the 1407 MUXs. The positive MUX is set to sendSPI(0x2C); // REF and the negative MUX is set to IN0. sendSPI(RD_ADC); // Read the 1407's ADC register. spiData = sendSPI(0x0FF); spiData |= 0x81; // Set the calibration & start conversion bit. sendSPI(WR_ADC); // Write the new value back into sendSPI(spiData); // the 1407 register. do { sendSPI(RD_STAT); // Read the 1407's Status register. spiData = sendSPI(0x0FF); } while((spiData & 0x02) == 0x00); // Bit 1 indicates AtoD conversion complete. sendSPI(WR_DAC2); // Set up the DAC2 to output 1.25V. (FB2 // must be directly connected to OUT2). SPICF_bit.CHR = 1; // Set SPI to 16-bit mode. sendSPI(0x0FFC0); SPICF_bit.CHR = 0; // Put SPI back into 8-bit mode. for(i = 0; i < 3; i++) // You must do three ADC readings on the 1407 { // before the results become valid. getADCReading(); } } int convertToTemp(unsigned int adc) { double temp = -0.00135477 * (double)adc + 69.17; return (int)temp; } #if (USE_SERIAL) int putchar(int ch) { while(SCON0_bit.TI == 0); // Wait until we can send. SCON0_bit.TI = 0; // Clear the sent flag. SBUF0 = ch; // Send the char. return ch; } void initSerial() { SCON0_bit.SM1 = 1; // Set to Mode 1. SCON0_bit.REN = 1; // Enable receives. SMD0_bit.SMOD = 1; // Set baud rate to 16 times the baud clock. // PR0 = 0x3AFB; // Set the phase for 115200 with a 16MHz crystal. asm("move M2[9], 0x3AFB"); SCON0_bit.TI = 0; // Clear the transmit flag. SBUF0 = 0x0D; // Send a carriage return to start of communication. } #endif show100s(int val) { if(val == 1) { LCD1 |= 32; LCD2 |= 4; } } show10s(int val) { switch(val) { case 0: LCD1 |= 14; LCD2 |= 112; break; case 1: LCD1 |= 2; LCD2 |= 64; break; case 2: LCD1 |= 6; LCD2 |= 176; break; case 3: LCD1 |= 6; LCD2 |= 224; break; case 4: LCD1 |= 10; LCD2 |= 192; break; case 5: LCD1 |= 12; LCD2 |= 224; break; case 6: LCD1 |= 12; LCD2 |= 240; break; case 7: LCD1 |= 6; LCD2 |= 64; break; case 8: LCD1 |= 14; LCD2 |= 240; break; case 9: LCD1 |= 14; LCD2 |= 224; break; } } void show1s(int val) { switch(val) { case 0: LCD0 |= 224; LCD3 |= 14; break; case 1: LCD0 |= 32; LCD3 |= 8; break; case 2: LCD0 |= 96; LCD3 |= 22; break; case 3: LCD0 |= 96; LCD3 |= 28; break; case 4: LCD0 |= 160; LCD3 |= 24; break; case 5: LCD0 |= 192; LCD3 |= 28; break; case 6: LCD0 |= 192; LCD3 |= 30; break; case 7: LCD0 |= 96; LCD3 |= 8; break; case 8: LCD0 |= 224; LCD3 |= 30; break; case 9: LCD0 |= 224; LCD3 |= 28; break; } } void showTemp(int temp) { #if (USE_SERIAL) printf("Temperature is "); #endif // Clear the display of everything but the degrees mark and the temperature units (F or C). LCD0 = 28; LCD1 = 0; LCD2 = 0; LCD3 = ((celsius == 0) ? 192 : 64); LCD4 = ((celsius == 0) ? 0 : 32); if(celsius != 0) { // Convert to Fahrenheit. temp = (int)(((double)temp) * 9.0 / 5.0 + 32.0); } if(temp > 99) { show100s(1); // Show a '1' on the LCD. temp -= 100; // Adjust the temperature variable. #if (USE_SERIAL) putchar('1'); // Output a '1' to the serial port. #endif } show10s(temp / 10); // Show the 10's place on the LCD. show1s(temp % 10); // Show the 1's place on the LCD. #if (USE_SERIAL) putchar((temp / 10) + '0'); // Output the 10's place to the serial port. putchar((temp % 10) + '0'); // Output the 1's place to the serial port. if(celsius == 0) { printf(" degrees Celsius. \r"); // Output the units on the serial port. } else { printf(" degrees Fahrenheit. \r"); // Output the units on the serial port. } #endif } void readTemp() { int adc = getADCReading(); // Read the thermistor value. int temp = convertToTemp(adc); // Convert this value to degrees Celsius. showTemp(temp); // Show the result. } void initTimer() { T2V0 = 0x00000; // Set current timer value. T2R0 = 0x00001; // Set reload value. T2C0 = 0x00000; // Set compare value to below the reload so it never generates an interrupt. T2CFG0_bit.T2DIV = 7; // Set div 128 mode. T2CNA0_bit.TR2 = 1; // Start the timer. T2CNA0_bit.T2POL0 = 1; // Set polarity for T2OE0 to high. T2CNA0_bit.ET2 = 1; // Enable interrupts. T2CNB0_bit.T2OE1 = 1; // Enable timer output. // IMR |= 0x08; // Enable the interrupts for module 3. asm("move M8[6].3, #1"); } //The interrupt handler for Timer 0. Occurs whenever the timer overflows. #pragma vector = 3 __interrupt void timerInterrupt() { //Change the units occasionally. if(++count == 20) { count = 0; celsius = ~celsius; } readTemp(); //Get and display the current temperature. T2CNB0_bit.TF2 = 0; //Clear the overflow flag. T2CNB0_bit.TCC2 = 0; //Clear the overflow flag. } void initLCD() { LCRA = 0x03E0; // LCRA_bit.FRM = 7; // Set up frame frequency. // LCRA_bit.LCCS = 1; // Set clock source to HFClk / 128. // LCRA_bit.DUTY = 0; // Set up static duty cycle. // LCRA_bit.LRA = 0; // Set R-adj to 0. // LCRA_bit.LRIGC = 1; // Select external LCD drive power. LCFG_bit.PCF = 0x0F;// Set up all segments as outputs. LCFG_bit.OPM = 1; // Set to normal operation mode. LCFG_bit.DPE = 1; // Enable display. } void main() { #if (USE_SERIAL) initSerial(); #endif initTimer(); init1407(); initLCD(); __enable_interrupt(); while(1); }