Você está na página 1de 20

//----------------------------------------------------------------------------// F12x_ADC0_ExternalInput.

c
//----------------------------------------------------------------------------// Copyright 2005 Silicon Laboratories, Inc.
// http://www.silabs.com
//
// Program Description:
//
// This program measures the voltage on an external ADC input and prints the
// result to a terminal window via the UART.
//
// The system is clocked using the internal 24.5MHz oscillator multiplied
// up to 49MHz by the on-chip PLL. Results are printed to the UART from a loop
// with the rate set by a delay based on Timer 2. This loop periodically reads
// the ADC value from a global variable, Result.
//
// The ADC makes repeated measurements at a rate determined by
SAMPLE_RATE using
// Timer 3. The end of each ADC conversion initiates an interrupt which calls an
// averaging function. <INT_DEC> samples are averaged then the Result value
updated.
//
// 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.
//
// The ADC input multiplexer is set for a single-ended input at AIN0.1. The input
// amplifier is set for unity gain so a voltage range of 0 to Vref (2.43V) may
// be measured. Although voltages up to Vdd may be applied without damaging
the

// device, only the range 0 to Vref may be measured by the ADC.


// The input is available at the 8-position board-edge connector, J20, on the
// C8051FX20-TB.
//
// A 100kohm potentiometer may be connected as a voltage divider between
// VREF and AGND as shown below:
//
// --------//
//

|
8 o| AGND ----|

//

o| VREF ----|<-|

//

o| AIN0.1 | |

//

o|

//

o|

//

o|

//

o|

//

1 o|

//

--------

//---------//
// How To Test:
//
// 1) Download code to a 'F12x device that is connected to a UART transceiver
// 2) Connect serial cable from the transceiver to a PC
// 3) On the PC, open HyperTerminal (or any other terminal program) and connect
//

to the COM port at <BAUDRATE> and 8-N-1

// 4) Connect a variable voltage source (between 0 and Vref)


//

to AIN 0.1, or a potentiometer voltage divider as shown above.

// 5) HyperTerminal will print the voltage measured by the device if


//

everything is working properly

//
// FID:

12X000022

// Target:

C8051F12x

// Tool chain:

Keil C51 7.50 / Keil EVAL C51

// Command Line: None


//
//
// Release 1.0
//

-Initial Revision (clm)

//

-19-May-06

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

#include <c8051f120.h>

// SFR declarations

#include <stdio.h>

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


//-----------------------------------------------------------------------------

sfr16 ADC0

= 0xbe;

// ADC0 data

sfr16 RCAP2

= 0xca;

// Timer2 capture/reload

sfr16 RCAP3

= 0xca;

// Timer3 capture/reload

sfr16 TMR2

= 0xcc;

// Timer2

sfr16 TMR3

= 0xcc;

// Timer3

sfr16 RCAP4

= 0xca;

// Timer4 capture/reload

sfr16 TMR4

= 0xcc;

// Timer4

sfr16 DAC0

= 0xd2;

// DAC0 data

sfr16 DAC1

= 0xd2;

// DAC1 data

//----------------------------------------------------------------------------// Global Constants


//-----------------------------------------------------------------------------

#define BAUDRATE
#define SYSCLK

115200
49000000

// Baud rate of UART in bps


// Output of PLL derived from (INTCLK*2)

#define SAMPLE_RATE 50000


#define INT_DEC

256

#define SAR_CLK

2500000

// Sample frequency in Hz
// Integrate and decimate ratio
// Desired SAR clock speed

#define SAMPLE_RATE_DAC 100000L


#define SAMPLE_DELAY 50

sbit LED = P1^6;


sbit SW1 = P3^7;

// Delay in ms before taking sample

// LED='1' means ON
// SW1='0' means switch pressed

//----------------------------------------------------------------------------// Function Prototypes


//-----------------------------------------------------------------------------

void OSCILLATOR_Init (void);


void PORT_Init (void);
void UART1_Init (void);

void ADC0_Init (void);


void TIMER3_Init (int counts);
void ADC0_ISR (void);
void Wait_MS (unsigned int ms);
void DAC0_Init (void);
void TIMER4_Init(int counts);
void Set_DACs(void);
//----------------------------------------------------------------------------// Global Variables
//-----------------------------------------------------------------------------

long Result;

// ADC0 decimated value

//----------------------------------------------------------------------------// main() Routine


//-----------------------------------------------------------------------------

void main (void)


{
long measurement;

WDTCN = 0xde;

// Measured voltage in mV

// Disable watchdog timer

WDTCN = 0xad;

OSCILLATOR_Init ();
PORT_Init ();
// UART1_Init ();

// Initialize oscillator
// Initialize crossbar and GPIO
// Initialize UART1

TIMER3_Init (SYSCLK/SAMPLE_RATE); // Initialize Timer3 to overflow at

TIMER4_Init(SYSCLK/SAMPLE_RATE_DAC);

ADC0_Init ();

// sample rate

// Init ADC

SFRPAGE = ADC0_PAGE;
AD0EN = 1;

// Enable ADC

EA = 1;

// Enable global interrupts

while (1)
{
EA = 0;

// Disable interrupts

// The 12-bit ADC value is averaged across INT_DEC measurements. The


result is
// then stored in Result, and is right-justified
// The measured voltage applied to AIN 0.1 is then:
//
//

Vref (mV)

// measurement (mV) = --------------- * Result (bits)


//

(2^12)-1 (bits)

measurement = Result * 2430 / 4095;


DAC0_Init();
Set_DACs();

EA = 1;

// Re-enable interrupts

// SFRPAGE = UART1_PAGE;

//printf("AIN0.1 voltage: %ld mV\n",measurement);

//SFRPAGE = CONFIG_PAGE;
//LED = ~SW1;

// LED reflects state of switch

SFRPAGE = DAC0_PAGE;

Wait_MS(SAMPLE_DELAY);

// Wait 50 milliseconds before taking

// another sample
}
}

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


//-----------------------------------------------------------------------------

//----------------------------------------------------------------------------// OSCILLATOR_Init
//----------------------------------------------------------------------------//
// Return Value : None
// Parameters : None
//
// This function initializes the system clock to use the internal oscillator
// at 24.5 MHz multiplied by two using the PLL.
//
//-----------------------------------------------------------------------------

void OSCILLATOR_Init (void)


{
int loop;

// Software timer

char SFRPAGE_SAVE = SFRPAGE;

SFRPAGE = CONFIG_PAGE;

OSCICN = 0x83;

// Save Current SFR page

// Set SFR page

// Set internal oscillator to run


// at its maximum frequency

CLKSEL = 0x00;

// Select the internal osc. as


// the SYSCLK source

//Turn on the PLL and increase the system clock by a factor of M/N = 2
SFRPAGE = CONFIG_PAGE;

PLL0CN = 0x00;

// Set internal osc. as PLL source

SFRPAGE = LEGACY_PAGE;
FLSCL = 0x10;

// Set FLASH read time for 50MHz clk


// or less

SFRPAGE = CONFIG_PAGE;
PLL0CN |= 0x01;

// Enable Power to PLL

PLL0DIV = 0x01;

// Set Pre-divide value to N (N = 1)

PLL0FLT = 0x01;

// Set the PLL filter register for


// a reference clock from 19 - 30 MHz
// and an output clock from 45 - 80 MHz

PLL0MUL = 0x02;

// Multiply SYSCLK by M (M = 2)

for (loop=0; loop < 256; loop++); // Wait at least 5us


PLL0CN |= 0x02;

// Enable the PLL

while(!(PLL0CN & 0x10));

// Wait until PLL frequency is locked

CLKSEL = 0x02;

// Select PLL as SYSCLK source

SFRPAGE = SFRPAGE_SAVE;

// Restore SFR page

//----------------------------------------------------------------------------// PORT_Init
//----------------------------------------------------------------------------//
// Return Value : None
// Parameters : None
//
// This function configures the crossbar and GPIO ports.
//
// P0.4 digital push-pull

UART TX

// P0.5 digital open-drain

UART RX

// P1.6 digital push-pull


// AIN0.1 analog

LED
Analog input (no configuration necessary)

//----------------------------------------------------------------------------void PORT_Init (void)


{
char SFRPAGE_SAVE = SFRPAGE;

SFRPAGE = CONFIG_PAGE;

// Save Current SFR page

// set SFR page

XBR0

= 0x00;

XBR1

= 0x00;

XBR2

= 0x44;

// Enable crossbar and weak pull-up


// Enable UART1

P0MDOUT |= 0x01;

// Set TX1 pin to push-pull

P1MDOUT |= 0x40;

// Set P1.6(LED) to push-pull

SFRPAGE = SFRPAGE_SAVE;

// Restore SFR page

//----------------------------------------------------------------------------// UART1_Init
//----------------------------------------------------------------------------//
// Return Value : None
// Parameters : None
//
// Configure the UART1 using Timer1, for <baudrate> and 8-N-1.
//
//----------------------------------------------------------------------------//void UART1_Init (void)
//{
//char SFRPAGE_SAVE = SFRPAGE;

// Save Current SFR page

// SFRPAGE = UART1_PAGE;
//SCON1 = 0x10;

// SCON1: mode 0, 8-bit UART, enable RX

//SFRPAGE = TIMER01_PAGE;
//TMOD &= ~0xF0;
//TMOD |= 0x20;

// TMOD: timer 1, mode 2, 8-bit reload

// 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 &= ~0x13;
//CKCON |= 0x01;

// Clear all T1 related bits


// T1M = 0; SCA1:0 = 01

// } 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 &= ~0x13;
// CKCON |= 0x02;

// Clear all T1 related bits


// T1M = 0; SCA1:0 = 10

// }

//TL1 = TH1;
//TR1 = 1;

// Initialize Timer1
// Start Timer1

// SFRPAGE = UART1_PAGE;
// TI1 = 1;

// Indicate TX1 ready

// SFRPAGE = SFRPAGE_SAVE;

// Restore SFR page

//}

//----------------------------------------------------------------------------// ADC0_Init
//----------------------------------------------------------------------------//
// Return Value : None
// Parameters : None
//
// Configure ADC0 to use Timer3 overflows as conversion source, to
// generate an interrupt on conversion complete, and to use right-justified
// output mode. Enables ADC end of conversion interrupt. Leaves ADC disabled.
//
//----------------------------------------------------------------------------void ADC0_Init (void)
{
char SFRPAGE_SAVE = SFRPAGE;

// Save Current SFR page

SFRPAGE = ADC0_PAGE;

ADC0CN = 0x04;

// ADC0 disabled; normal tracking


// mode; ADC0 conversions are initiated
// on overflow of Timer3; ADC0 data is
// right-justified

REF0CN = 0x07;

// Enable temp sensor, on-chip VREF,

// and VREF output buffer

AMX0CF = 0x00;

// AIN inputs are single-ended (default)

AMX0SL = 0x01;

// Select AIN0.1 pin as ADC mux input

ADC0CF = (SYSCLK/SAR_CLK) << 3;


ADC0CF |= 0x00;

EIE2 |= 0x02;

SFRPAGE = SFRPAGE_SAVE;

// ADC conversion clock = 2.5MHz

// PGA gain = 1 (default)

// enable ADC interrupts

// Restore SFR page

//----------------------------------------------------------------------------// TIMER3_Init
//----------------------------------------------------------------------------//
// Return Value : None
// Parameters :
// 1) int counts - calculated Timer overflow rate
//

range is postive range of integer: 0 to 32767

//
// Configure Timer3 to auto-reload at interval specified by <counts> (no
// interrupt generated) using SYSCLK as its time base.
//
//----------------------------------------------------------------------------void TIMER3_Init (int counts)

{
char SFRPAGE_SAVE = SFRPAGE;

// Save Current SFR page

SFRPAGE = TMR3_PAGE;

TMR3CN = 0x00;

// Stop Timer3; Clear TF3;

TMR3CF = 0x08;

// use SYSCLK as timebase

RCAP3 = -counts;

// Init reload values

TMR3

// Set to reload immediately

= RCAP3;

EIE2 &= ~0x01;


TR3

= 1;

// Disable Timer3 interrupts


// start Timer3

SFRPAGE = SFRPAGE_SAVE;

// Restore SFR page

//----------------------------------------------------------------------------// Interrupt Service Routines


//-----------------------------------------------------------------------------

//----------------------------------------------------------------------------// ADC0_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>.
//

//----------------------------------------------------------------------------void ADC0_ISR (void) interrupt 15


{
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--;

if (int_dec == 0)

// Update decimation counter

// If zero, then post result

{
int_dec = INT_DEC;

// Reset counter

Result = accumulator >> 8;


accumulator = 0L;

// Reset accumulator

}
}

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


//-----------------------------------------------------------------------------

//----------------------------------------------------------------------------// Wait_MS
//----------------------------------------------------------------------------//
// Return Value : None
// Parameters:
// 1) unsigned int ms - number of milliseconds of delay
//

range is full range of integer: 0 to 65335

//
// This routine inserts a delay of <ms> milliseconds.
//
//----------------------------------------------------------------------------void Wait_MS(unsigned int ms)
{
char SFRPAGE_SAVE = SFRPAGE;

// Save Current SFR page

SFRPAGE = TMR2_PAGE;

TMR2CN = 0x00;

// Stop Timer3; Clear TF3;

TMR2CF = 0x00;

// use SYSCLK/12 as timebase

RCAP2 = -(SYSCLK/1000/12);

// Timer 2 overflows at 1 kHz

TMR2 = RCAP2;

ET2 = 0;

// Disable Timer 2 interrupts

TR2 = 1;

// Start Timer 2

while(ms)
{
TF2 = 0;

// Clear flag to initialize

while(!TF2);

// Wait until timer overflows

ms--;

// Decrement ms

TR2 = 0;

// Stop Timer 2

SFRPAGE = SFRPAGE_SAVE;

// Restore SFRPAGE

void DAC0_Init(void){

char SFRPAGE_SAVE = SFRPAGE;

// Save Current SFR page

SFRPAGE = DAC0_PAGE;

DAC0CN = 0x94;

// Enable DAC0 in left-justified mode


// managed by Timer4 overflows

SFRPAGE = LEGACY_PAGE;

REF0CN |= 0x03;

// Enable the internal VREF (2.4v) and


// the Bias Generator

SFRPAGE = SFRPAGE_SAVE;

// Restore SFR page

void TIMER4_Init (int counts)


{
char SFRPAGE_SAVE = SFRPAGE;

// Save Current SFR page

SFRPAGE = TMR4_PAGE;

TMR4CN = 0x00;

// Stop Timer4; Clear overflow flag (TF4);


// Set to Auto-Reload Mode

TMR4CF = 0x08;

// Configure Timer4 to increment;


// Timer4 counts SYSCLKs

RCAP4 = -counts;

// Set reload value

TMR4 = RCAP4;

// Initialzie Timer4 to reload value

EIE2 |= 0x04;
TR4 = 1;

// Enable Timer4 interrupts


// Start Timer4

SFRPAGE = SFRPAGE_SAVE;

// Restore SFR page

void TIMER4_ISR (void) interrupt 16


{
TF4 = 0;
Set_DACs();
}

// Clear Timer4 overflow flag

void Set_DACs(void)
{
char SFRPAGE_SAVE = SFRPAGE;

// Save Current SFR page

//static unsigned phase_acc = 0;

// Holds phase accumulator

//int SIN_temp, COS_temp;


// unsigned char index;

// Temporary 16-bit variables


// Index into SINE table

// phase_acc += PHASE_ADD;

// Increment phase accumulator

// index = phase_acc >> 8;

// SIN_temp = SINE_TABLE[index];

//index += 64;

// Read the table value

// 90 degree phase shift

// COS_temp = SINE_TABLE[index];

// Add a DC bias to change the the rails from a bipolar (-32768 to 32767)
// to unipolar (0 to 65535)
// Note: the XOR with 0x8000 translates the bipolar quantity into
// a unipolar quantity.

SFRPAGE = DAC0_PAGE;
DAC0 = 15*Result;

//SFRPAGE = DAC1_PAGE;

// Write to DAC0

// DAC1 = 0x8000 ^ COS_temp;

SFRPAGE = SFRPAGE_SAVE;

// Write to DAC1

// Restore SFR page

//----------------------------------------------------------------------------// End Of File


//-----------------------------------------------------------------------------

Você também pode gostar