t2cal33x.c

来自「8051试验程序 基础教材」· C语言 代码 · 共 386 行

C
386
字号
//-----------------------------------------------------------------------------
// T2Cal33x.c
//-----------------------------------------------------------------------------
// Copyright (C) 2005 Silicon Laboratories, Inc.
//
// AUTH: PD, GV
// DATE: 04 FEB 03
//
// This program is used to measure the temperature sensor on an 'F33x
// device.  It uses 1-point calibration and stores the offset value
// in FLASH memory.  The program outputs temperature values in 100ths
// of a degree Celsius with UART.
// Target: C8051F33x
//

//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------

#include <ioC8051f330.h>                 // SFR declarations
#include <stdio.h>
#include <stdbool.h>

//-----------------------------------------------------------------------------
// 16-bit SFR Definitions for 'F33x
//-----------------------------------------------------------------------------

__sfr __no_init volatile unsigned short TMR2RL   @ 0xca;                 // Timer2 reload value
__sfr __no_init volatile unsigned short TMR2     @ 0xcc;                 // Timer2 counter
__sfr __no_init volatile unsigned short ADC0     @ 0xbd;                 // ADC Data Word Register

//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------

#define SYSCLK      24500000           // SYSCLK frequency in Hz
#define BAUDRATE        9600           // Baud rate of UART in bps
#define TIMER2_RATE     1000           // Timer 2 overflow rate in Hz


#define LED P1_bit.P13                       // LED='1' means ON
//-----------------------------------------------------------------------------
// Temperature Sensor Calibration PARAMETERS
//-----------------------------------------------------------------------------
#define AMB_TEMP           25          // Ambient Calibration Temperature
                                       // (degC)

#define TEMP_SENSOR_GAIN   2860        // Temp Sensor Gain in (uV / degC)

#define VREF               2430        // ADC Voltage Reference (mV)

#define SOAK_TIME          15          // Soak Time in Seconds


//-----------------------------------------------------------------------------
// Global VARIABLES
//-----------------------------------------------------------------------------

// TEMP_OFFSET allocates two bytes of code memory space in FLASH
// that will be used to store the calibrated temperature value
unsigned int const __code TEMP_OFFSET = 0xFFFF;

//-----------------------------------------------------------------------------
// Function PROTOTYPES
//-----------------------------------------------------------------------------

void SYSCLK_Init (void);
void ADC0_Init (void);
void UART0_Init (void);
void PORT_Init (void);
void Timer2_Init (int);

int get_temp (void);
void calibrate(void);
unsigned int measure(void);
void wait_one_second (void);

//-----------------------------------------------------------------------------
// MAIN Routine
//-----------------------------------------------------------------------------

void main (void) {

   unsigned temperature;

   // Disable Watchdog timer
   PCA0MD &= ~0x40;                    // WDTE = 0 (clear watchdog timer
                                       // enable)
   PORT_Init();                        // Initialize Port I/O
   SYSCLK_Init ();                     // Initialize Oscillator

   ADC0_Init ();                       // Init ADC0
   Timer2_Init(SYSCLK/TIMER2_RATE);    // Init Timer 2
   UART0_Init();

   ADC0CN_bit.AD0EN = 1;                          // Enable ADC0

   if (TEMP_OFFSET == 0xFFFF) {        // TRUE if first-time to execute
      printf ("Calibrating...\n");
      calibrate ();                    // execute calibration sequence
   } else {
      printf ("Not calibrating.\n");
   }

   while (1) {
      // example of how to read the temperature
      LED = 1;
      temperature = get_temp ();
      LED = 0;
      printf ("Temperature = %+02d hundredths degrees C\n", temperature);
   }
}

//-----------------------------------------------------------------------------
// Initialization Subroutines
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// PORT_Init
//-----------------------------------------------------------------------------
//
// Configure the Crossbar and GPIO ports.
//
// P0.4 - UART TX
// P0.5 - UART RX
// P3.3 - LED

void PORT_Init (void)
{
   P0SKIP  |= 0x01;                    // Skip P0.0 for external VREF
   P0MDIN  |= 0x01;                    // Configure P0.0 as analog input.
   P0MDOUT |= 0x10;                    // enable UTX as push-pull output
   P1MDOUT |= 0x08;                    // enable LED as push-pull output
   XBR0    = 0x01;                     // Enable UART on P0.4(TX) and P0.5(RX)
   XBR1    = 0x40;                     // Enable crossbar and weak pull-ups
}

//-----------------------------------------------------------------------------
// SYSCLK_Init
//-----------------------------------------------------------------------------
//
// This routine initializes the system clock to use the internal oscillator
// at its maximum frequency.
// Also enables the Missing Clock Detector.
//

void SYSCLK_Init (void)
{
   OSCICN |= 0x03;                     // Configure internal oscillator for
                                       // its maximum frequency
   RSTSRC  = 0x04;                     // Enable missing clock detector

}

//-----------------------------------------------------------------------------
// ADC0_Init ADBUSY, LP tracking, no Interrupt, ADC disabled
//-----------------------------------------------------------------------------
//
// Configure ADC0 to use ADBUSY as conversion source, and to sense the output
// of the temp sensor.  Disables ADC end of conversion interrupt. Leaves ADC
// disabled.
//
void ADC0_Init (void)
{
   ADC0CN = 0x40;                      // ADC0 disabled; LP tracking
                                       // mode; ADC0 conversions are initiated
                                       // on a write to ADBusy
   AMX0P  = 0x10;                      // Temp sensor selected at + input
   AMX0N  = 0x11;                      // Single-ended mode

   ADC0CF = (SYSCLK/3000000) << 3;     // ADC conversion clock <= 3MHz

   ADC0CF &= ~0x04;                    // Make ADC0 right-justified
   REF0CN = 0x0e;                      // enable temp sensor, VREF = VDD, bias
                                       // generator is on.

   EIE1 &= ~0x08;                      // Disable ADC0 EOC interrupt
}

//-----------------------------------------------------------------------------
// UART0_Init
//-----------------------------------------------------------------------------
//
// Configure the UART0 using Timer1, for <BAUDRATE> 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 &= ~0x0B;                  // T1M = 1; SCA1:0 = xx
      CKCON |=  0x08;
   } else if (SYSCLK/BAUDRATE/2/256 < 4) {
      TH1 = -(SYSCLK/BAUDRATE/2/4);
      CKCON &= ~0x0B;                  // T1M = 0; SCA1:0 = 01
      CKCON |=  0x09;
   } else if (SYSCLK/BAUDRATE/2/256 < 12) {
      TH1 = -(SYSCLK/BAUDRATE/2/12);
      CKCON &= ~0x0B;                  // T1M = 0; SCA1:0 = 00
   } else {
      TH1 = -(SYSCLK/BAUDRATE/2/48);
      CKCON &= ~0x0B;                  // T1M = 0; SCA1:0 = 10
      CKCON |=  0x02;
   }

   TL1 = TH1;                          // init Timer1
   TMOD &= ~0xf0;                      // TMOD: timer 1 in 8-bit autoreload
   TMOD |=  0x20;
   TCON_bit.TR1 = 1;                            // START Timer1
   SCON0_bit.TI0 = 1;                            // Indicate TX0 ready
}

//-----------------------------------------------------------------------------
// Timer2_Init SYSCLK no Interrupt
//-----------------------------------------------------------------------------
//
// Configure Timer2 to auto-reload at interval specified by <counts> (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 |= 0x10;                      // Timer2 uses SYSCLK as its timebase

   TMR2RL  = -counts;                  // Init reload values
   TMR2    = TMR2RL;                   // Init Timer2 with reload value
   IE_bit.ET2 = 0;                            // disable Timer2 interrupts
   TMR2CN_bit.TR2 = 1;                            // start Timer2
}

//-----------------------------------------------------------------------------
// Support Subroutines
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// wait_soak_time
//-----------------------------------------------------------------------------
//
// This routine waits for the number of seconds indicated in the constant
// <SOAK_TIME>.
//
void wait_soak_time (unsigned char soak_time)
{
   unsigned char i;

   for( i = soak_time; i != 0; i--) {
      wait_one_second();
      printf ("Soaking...%d\n", (int) i);
   }
}

//-----------------------------------------------------------------------------
// wait_one_second
//-----------------------------------------------------------------------------
//
// This routine uses timer 2 to insert a delay of approximately one second.
// Timer 2 overflows <TIMER2_RATE> times per second
//
void wait_one_second (void)
{
   unsigned int count;
   TMR2CN_bit.TF2H = 0;                           // Clear Timer2 overflow flag
   TMR2CN_bit.TR2 = 1;                            // Start Timer2

   for (count = TIMER2_RATE; count != 0; count--) {
      while (!TMR2CN_bit.TF2H);                   // wait for overflow
      TMR2CN_bit.TF2H = 0;                        // clear overflow indicator
   }

   TMR2CN_bit.TR2 = 0;                            // Stop Timer2
}

//-----------------------------------------------------------------------------
// calibrate
//-----------------------------------------------------------------------------
//
void calibrate (void)
{

   bool EA_state=IE_bit.EA;                    // Preserves EA state
   unsigned char __xdata * codePtr;      // Used to write calibration
                                       // Value into FLASH memory
   unsigned int __code* pread;      // FLASH read pointer

   long temp_offset;                   // stores returned value from ADC
   pread = (unsigned int __code *) TEMP_OFFSET;

   wait_soak_time(SOAK_TIME);          // let temperature of device stabilize
   temp_offset= (long) measure ();     // Read oversampled ADC code

   // now calculate the 0 DEG C offset value using <temp_offset>, the
   // temp sensor gain (TEMP_SENSOR_GAIN), and the ambient temperature.

   temp_offset = temp_offset - ((long) AMB_TEMP *
                 TEMP_SENSOR_GAIN / VREF * 65536 / 1000);

   codePtr=(unsigned char __xdata*) &TEMP_OFFSET;
                                       // Point to TEMP_OFFSET

   IE_bit.EA = 0;                             // Disable interrupts


   FLKEY=0xA5;                         // Input first key code
   FLKEY=0xF1;                         // Input second key code,
                                       // FLASH is now unlocked

   PSCTL |= 0x01;                      // Enable FLASH Writes
   *codePtr = (temp_offset>>8);        // Write high byte of temp_gain

   PSCTL &= ~0x01;                     // disable FLASH Writes

   codePtr++;                          // Move to low byte of
                                       // TEMP_OFFSET in FLASH to
                                       // Store low byte of temp_gain

   FLKEY=0xA5;                         // Input first key code
   FLKEY=0xF1;                         // Input second key code,
                                       // FLASH is now unlocked

   PSCTL |= 0x01;                      // Enable FLASH Writes

   *codePtr =temp_offset;              // Write low byte of temp_gain


   PSCTL = 0x00;                       // Disable FLASH Writes
   IE_bit.EA = EA_state;                      // Restore interrupt state

}

//-----------------------------------------------------------------------------
// measure
//-----------------------------------------------------------------------------
//
// This routine averages 16383 ADC samples and returns a 16-bit unsigned
// result.
//
unsigned int measure (void)
{
   unsigned i;                         // Sample counter
   unsigned long accumulator=0L;       // Here's where we integrate the
                                       // ADC samples
   unsigned int currval;

   ADC0CN_bit.AD0INT = 0;
   ADC0CN_bit.AD0BUSY = 1;

   // read the ADC value and add to running total
   i = 0;
   do
   {
      while (!ADC0CN_bit.AD0INT);                 // Wait for conversion to complete
      ADC0CN_bit.AD0INT = 0;                      // Clear end-of-conversion indicator

      currval=ADC0;                    // Store latest ADC conversion
      ADC0CN_bit.AD0BUSY = 1;                     // Initiate conversion
      accumulator += currval;          // Accumulate
      i++;                             // Update counter
   } while (i != 16383);
   return (unsigned int) (accumulator >> 8);
   // shift to obtain a 16-bit result (14 + 10 = 24 - 8 = 16) bits
}


int get_temp (void)
{
   unsigned int ADC_code;
   long result;

   ADC_code = measure();

   result = ADC_code - TEMP_OFFSET;

   // result = result * (VREF / 65536) * (1000 / TEMP_SENSOR_GAIN) * ( 100 )
   // the equation above is re-arranged for fixed-point math.

   result = result * (long) VREF / 256 * 1000 / TEMP_SENSOR_GAIN * 100 / 256;

   return (int) result;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?