temp_3.c
来自「8051试验程序 基础教材」· C语言 代码 · 共 277 行
C
277 行
// -----------------------------------------------------------------------------
// Temp_3.c
// -----------------------------------------------------------------------------
// Copyright (C) 2005 Silicon Laboratories, Inc.
//
// AUTH: BW
// DATE: 23 JUL 01
//
// This program prints the C8051F0xx die temperature out the hardware
// UART at 9600bps. Assumes an 18.432MHz crystal is attached between
// XTAL1 and XTAL2.
//
// The ADC is configured to look at the on-chip temp sensor. The sampling
// rate of the ADC is determined by the constant <SAMPLE_RATE>, 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 <INT_DEC>
// samples, the ADC updates and stores its result in the global variable
// <temperature>, which holds the current temperature in hundredths of a
// degree. 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 <INT_DEC>, you gain 1 bit of effective
// resolution. For example, <INT_DEC> = 256 gain you 4 bits of
// resolution: 4^4 = 256.
//
// Also note that the ADC0 is configured for 'LEFT' justified mode. In
// this mode, the MSB of the ADC word is located in the MSB position of
// the ADC0 high byte. Using the data in this way makes the magnitude
// of the resulting code independent of the number of bits in the
// ADC (12- and 10-bits behave the same).
//
// Target: C8051F00x or C8051F01x
// Tool chain: IAR Systems EW8051
// -----------------------------------------------------------------------------
// Includes
// -----------------------------------------------------------------------------
#include <ioC8051f000.h> // SFR declarations
#include <stdio.h>
// -----------------------------------------------------------------------------
// 16-bit SFR Definitions for 'F00x
// -----------------------------------------------------------------------------
__sfr __no_init volatile unsigned short DP @ 0x82; // data pointer
__sfr __no_init volatile unsigned short TMR3RL @ 0x92; // Timer3 reload value
__sfr __no_init volatile unsigned short TMR3 @ 0x94; // Timer3 counter
__sfr __no_init volatile unsigned short ADC0 @ 0xbe; // ADC0 data
__sfr __no_init volatile unsigned short ADC0GT @ 0xc4; // ADC0 greater than window
__sfr __no_init volatile unsigned short ADC0LT @ 0xc6; // ADC0 less than window
__sfr __no_init volatile unsigned short RCAP2 @ 0xca; // Timer2 capture/reload
__sfr __no_init volatile unsigned short T2 @ 0xcc; // Timer2
__sfr __no_init volatile unsigned short DAC0 @ 0xd2; // DAC0 data
__sfr __no_init volatile unsigned short DAC1 @ 0xd5; // DAC1 data
// -----------------------------------------------------------------------------
// Global CONSTANTS
// -----------------------------------------------------------------------------
#define BAUDRATE 9600 // Baud rate of UART in bps
#define SYSCLK 18432000 // SYSCLK frequency in Hz
#define SAMPLE_RATE 50000 // Sample frequency in Hz
#define INT_DEC 4096 // integrate and decimate ratio
#define LED P1_bit.P16 // LED='1' means ON
#define SW1 P3_bit.P37 // SW1='0' means switch pressed
#define ADCEN ADC0CN_bit.ADCEN
#define EA IE_bit.EA
#define TR1 TCON_bit.TR1
#define TI SCON_bit.TI
#define ADCINT ADC0CN_bit.ADCINT
// -----------------------------------------------------------------------------
// Function PROTOTYPES
// -----------------------------------------------------------------------------
void SYSCLK_Init(void);
void PORT_Init(void);
void UART0_Init(void);
void ADC0_Init(void);
void Timer3_Init(int counts);
__interrupt 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
WDTCN = 0xde; // disable watchdog timer
WDTCN = 0xad;
SYSCLK_Init(); // initialize oscillator
PORT_Init(); // initialize crossbar and GPIO
UART0_Init(); // initialize UART0
Timer3_Init(SYSCLK / SAMPLE_RATE); // initialize Timer3 to overflow
// at sample rate
ADC0_Init(); // init ADC
ADCEN = 1; // enable ADC
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
temperature = temperature - 42880;
temperature = (temperature * 100L) / 156;
temp_int = temperature / 100;
temp_frac = temperature - (temp_int * 100);
printf("Temperature is %+02d.%02d\n", temp_int, temp_frac);
LED = ~SW1; // LED reflects state of switch
}
}
// -----------------------------------------------------------------------------
// Initialization Subroutines
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// SYSCLK_Init
// -----------------------------------------------------------------------------
//
// This routine initializes the system clock to use an 22.1184MHz crystal
// as its clock source.
//
void SYSCLK_Init(void)
{
int i; // delay counter
OSCXCN = 0x67; // start external oscillator with
// 18.432MHz crystal
for (i = 0; i < 256; i++); // XTLVLD blanking interval (>1ms)
while (!(OSCXCN & 0x80)); // Wait for crystal osc. to settle
OSCICN = 0x88; // select external oscillator as SYSCLK source
// and enable missing clock detector
}
// -----------------------------------------------------------------------------
// PORT_Init
// -----------------------------------------------------------------------------
//
// Configure the Crossbar and GPIO ports
//
void PORT_Init(void)
{
XBR0 = 0x04; // Enable UART0
XBR1 = 0x00;
XBR2 = 0x40; // Enable crossbar and weak pull-ups
PRT0CF |= 0x01; // enable TX0 as a push-pull output
PRT1CF |= 0x40; // enable P1.6 (LED) as push-pull output
}
// -----------------------------------------------------------------------------
// UART0_Init
// -----------------------------------------------------------------------------
//
// Configure the UART using Timer1, for <baudrate> and 8-N-1.
//
void UART0_Init(void)
{
SCON = 0x50; // SCON: mode 1, 8-bit UART, enable RX
TMOD = 0x20; // TMOD: timer 1, mode 2, 8-bit reload
TH1 = -(SYSCLK / BAUDRATE / 16); // set Timer1 reload value for baudrate
TR1 = 1; // start Timer1
CKCON |= 0x10; // Timer1 uses SYSCLK as time base
PCON |= 0x80; // SMOD = 1
TI = 1; // Indicate TX ready
}
// -----------------------------------------------------------------------------
// ADC0_Init
// -----------------------------------------------------------------------------
//
// Configure ADC0 to use Timer3 overflows as conversion source, to
// generate an interrupt on conversion complete, and to use left-justified
// output mode. Enables ADC end of conversion interrupt. Leaves ADC
// disabled.
//
void ADC0_Init(void)
{
ADC0CN = 0x05; // ADC0 disabled; normal tracking
// mode; ADC0 conversions are initiated
// on overflow of Timer3; ADC0 data is
// left-justified
REF0CN = 0x07; // enable temp sensor, on-chip VREF,
// and VREF output buffer
AMX0SL = 0x0f; // Select TEMP sens as ADC mux output
ADC0CF = 0x80; // ADC conversion clock = SYSCLK/16
ADC0CF |= 0x01; // PGA gain = 2
EIE2 |= 0x02; // enable ADC interrupts
}
// -----------------------------------------------------------------------------
// Timer3_Init
// -----------------------------------------------------------------------------
//
// Configure Timer3 to auto-reload at interval specified by <counts> (no
// interrupt generated) using SYSCLK as its time base.
//
void Timer3_Init(int counts)
{
TMR3CN = 0x02; // Stop Timer3; Clear TF3;
// use SYSCLK as timebase
TMR3RL = -counts; // Init reload values
TMR3 = 0xffff; // set to reload immediately
EIE2 &= ~0x01; // disable Timer3 interrupts
TMR3CN |= 0x04; // start Timer3
}
// -----------------------------------------------------------------------------
// Interrupt Service Routines
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// ADC0_ISR
// -----------------------------------------------------------------------------
//
// ADC0 end-of-conversion ISR
// Here we take the ADC0 sample, add it to a running total <accumulator>,
// and decrement our local decimation counter <int_dec>.
// When <int_dec> reaches zero, we post the decimated result in
// the global variable <result>.
#pragma vector=0x7B
__interrupt void ADC0_ISR(void)
{
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
ADCINT = 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 >> 12;
accumulator = 0L; // reset accumulator
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?