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 + -
显示快捷键?