www.pudn.com > C8051F30x.rar > Temp_3.c
//----------------------------------------------------------------------------- // Temp_3.c //----------------------------------------------------------------------------- // Copyright (C) 2004 Silicon Laboratories, Inc. // // AUTH: BW // DATE: 24 JUN 02 // // This program prints the C8051F30x die temperature out the hardware // UART at 9600bps. Uses the calibrated internal 24.5MHz oscillator as the // system clock source. // // The ADC is configured to look at the on-chip temp sensor. The sampling // rate of the ADC is determined by the constant, which is given // in Hz. // // The ADC0 End of Conversion Interrupt Handler retrieves the sample // from the ADC and adds it to a running accumulator. Every // samples, the ADC updates and stores its result in the global variable // , which contains the accumulated result. The sampling technique of // adding a set of values and decimating them (posting results every (n)th // sample) is called 'integrate and dump.' It is easy to implement and // requires very few resources. // // For each power of 4 of , you gain 1 bit of effective resolution. // For example, = 4096 gain you 6 bits of resolution: 4^6 = 4096. // // Target: C8051F30x // Tool chain: KEIL C51 6.03 / KEIL EVAL C51 // //----------------------------------------------------------------------------- // Includes //----------------------------------------------------------------------------- #include // SFR declarations #include //----------------------------------------------------------------------------- // 16-bit SFR Definitions for 'F30x //----------------------------------------------------------------------------- sfr16 DP = 0x82; // data pointer sfr16 TMR2RL = 0xca; // Timer2 reload value sfr16 TMR2 = 0xcc; // Timer2 counter sfr16 PCA0CP1 = 0xe9; // PCA0 Module 1 Capture/Compare sfr16 PCA0CP2 = 0xeb; // PCA0 Module 2 Capture/Compare sfr16 PCA0 = 0xf9; // PCA0 counter sfr16 PCA0CP0 = 0xfb; // PCA0 Module 0 Capture/Compare //----------------------------------------------------------------------------- // Global CONSTANTS //----------------------------------------------------------------------------- #define SYSCLK 24500000 // SYSCLK frequency in Hz #define BAUDRATE 9600 // Baud rate of UART in bps #define SAMPLE_RATE 100000 // Sample frequency in Hz #define INT_DEC 4096 // integrate and decimate ratio sbit LED = P0^2; // LED='1' means ON sbit SW2 = P0^3; // SW2='0' means switch pressed //----------------------------------------------------------------------------- // Function PROTOTYPES //----------------------------------------------------------------------------- void SYSCLK_Init (void); void PORT_Init (void); void UART0_Init (void); void ADC0_Init (void); void Timer2_Init (int counts); void ADC0_ISR (void); //----------------------------------------------------------------------------- // Global VARIABLES //----------------------------------------------------------------------------- long result; // ADC0 decimated value //----------------------------------------------------------------------------- // MAIN Routine //----------------------------------------------------------------------------- void main (void) { long temperature; // temperature in hundredths of a // degree C int temp_int, temp_frac; // integer and fractional portions of // temperature // Disable Watchdog timer PCA0MD &= ~0x40; // WDTE = 0 (clear watchdog timer // enable) SYSCLK_Init (); // initialize oscillator PORT_Init (); // initialize crossbar and GPIO UART0_Init (); // initialize UART0 Timer2_Init (SYSCLK/SAMPLE_RATE); // initialize Timer2 to overflow at // sample rate ADC0_Init (); // init ADC0 AD0EN = 1; // enable ADC0 EA = 1; // Enable global interrupts while (1) { EA = 0; // disable interrupts temperature = result; EA = 1; // re-enable interrupts // calculate temperature in hundredths of a degree (14-bit full scale) temperature = temperature - 8700; temperature = (temperature * 10000L) / 3277; temp_int = temperature / 100; temp_frac = temperature - (temp_int * 100); printf ("Temperature is %+02d.%02d\n", temp_int, temp_frac); LED = ~SW2; // LED reflects state of SW2 } } //----------------------------------------------------------------------------- // Initialization Subroutines //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // SYSCLK_Init //----------------------------------------------------------------------------- // // This routine initializes the system clock to use the internal 24.5MHz // oscillator as its clock source. Also enables missing clock detector reset. // void SYSCLK_Init (void) { OSCICN |= 0x03; // configure internal oscillator for // its maximum frequency} RSTSRC = 0x04; // enable missing clock detector } //----------------------------------------------------------------------------- // PORT_Init //----------------------------------------------------------------------------- // // Configure the Crossbar and GPIO ports. // P0.0 - // P0.1 - // P0.2 - LED (push-pull) // P0.3 - SW2 // P0.4 - UART TX (push-pull) // P0.5 - UART RX // P0.6 - // P0.7 - C2D // void PORT_Init (void) { XBR0 = 0x0c; // skip LED and Switch in crossbar // assignments XBR1 = 0x03; // UART0 TX and RX pins enabled XBR2 = 0x40; // Enable crossbar and weak pull-ups P0MDOUT |= 0x14; // enable TX0 and LED as a push-pull // outputs } //----------------------------------------------------------------------------- // UART0_Init //----------------------------------------------------------------------------- // // Configure the UART0 using Timer1, for and 8-N-1. // void UART0_Init (void) { SCON0 = 0x10; // SCON0: 8-bit variable bit rate // level of STOP bit is ignored // RX enabled // ninth bits are zeros // clear RI0 and TI0 bits if (SYSCLK/BAUDRATE/2/256 < 1) { TH1 = -(SYSCLK/BAUDRATE/2); CKCON |= 0x10; // T1M = 1; SCA1:0 = xx } else if (SYSCLK/BAUDRATE/2/256 < 4) { TH1 = -(SYSCLK/BAUDRATE/2/4); CKCON |= 0x01; // T1M = 0; SCA1:0 = 01 CKCON &= ~0x12; } else if (SYSCLK/BAUDRATE/2/256 < 12) { TH1 = -(SYSCLK/BAUDRATE/2/12); CKCON &= ~0x13; // T1M = 0; SCA1:0 = 00 } else { TH1 = -(SYSCLK/BAUDRATE/2/48); CKCON |= 0x02; // T1M = 0; SCA1:0 = 10 CKCON &= ~0x11; } TL1 = 0xff; // set Timer1 to overflow immediately TMOD |= 0x20; // TMOD: timer 1 in 8-bit autoreload TMOD &= ~0xD0; // mode TR1 = 1; // START Timer1 TI0 = 1; // Indicate TX0 ready } //----------------------------------------------------------------------------- // ADC0_Init //----------------------------------------------------------------------------- // // Configure ADC0 to use Timer2 overflows as conversion source, to // generate an interrupt on conversion complete, and to sense the output of // the temp sensor. Enables ADC end of conversion interrupt. Leaves ADC // disabled. // void ADC0_Init (void) { ADC0CN = 0x02; // ADC0 disabled; normal tracking // mode; ADC0 conversions are initiated // on overflow of Timer2; AMX0SL = 0xf8; // select temp sensor as mux input ADC0CF = (SYSCLK/6000000) << 3; // ADC conversion clock <= 6MHz ADC0CF |= 0x02; // PGA gain = 2 REF0CN = 0x0e; // enable temp sensor, VREF = VDD, bias // generator is on. EIE1 |= 0x04; // enable ADC0 EOC interrupt } //----------------------------------------------------------------------------- // Timer2_Init //----------------------------------------------------------------------------- // // Configure Timer2 to auto-reload at interval specified by (no // interrupt generated) using SYSCLK as its time base. // void Timer2_Init (int counts) { TMR2CN = 0x00; // STOP Timer2; Clear TF2H and TF2L; // disable low-byte interrupt; disable // split mode; select internal timebase CKCON |= 0x20; // Timer2 uses SYSCLK as its timebase TMR2RL = -counts; // Init reload values TMR2 = 0xffff; // set to reload immediately ET2 = 0; // disable Timer2 interrupts TR2 = 1; // start Timer2 } //----------------------------------------------------------------------------- // Interrupt Service Routines //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ADC0_ISR //----------------------------------------------------------------------------- // // ADC0 end-of-conversion ISR // Here we take the ADC0 sample, add it to a running total , and // decrement our local decimation counter . When reaches // zero, we post the decimated result in the global variable . // void ADC0_ISR (void) interrupt 8 using 3 { static unsigned int_dec=INT_DEC; // integrate/decimate counter // we post a new result when // int_dec = 0 static long accumulator=0L; // here's where we integrate the // ADC samples AD0INT = 0; // clear ADC conversion complete // indicator accumulator += ADC0; // read ADC value and add to running // total int_dec--; // update decimation counter if (int_dec == 0) { // if zero, then post result int_dec = INT_DEC; // reset counter result = accumulator >> 6; accumulator = 0L; // reset accumulator } }