求助 C51F500开发板AD的一个程序 求讲解
时间:10-02
整理:3721RD
点击:
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <compiler_defs.h>
#include <C8051F500_defs.h> // SFR declarations
#include <stdio.h>
//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------
#define SYSCLK 24000000 // 系统时钟频率(Hz)
#define BAUDRATE 115200 // UART波特率,单位为bps
#define ANALOG_INPUTS 8 // 衡量AIN引脚数,
// 跳过UART0引脚
#define INT_DEC 256 // 集成和抽取比
#define TIMER0_RELOAD_HIGH 0 // Timer0的高字节寄存器
#define TIMER0_RELOAD_LOW 255 // Timer0的低字节寄存器
//-----------------------------------------------------------------------------
// 函数原型
//-----------------------------------------------------------------------------
void OSCILLATOR_Init (void);
void PORT_Init (void);
void TIMER2_Init (void);
void ADC0_Init (void);
void UART0_Init (void);
void Timer0_wait (int ms);
INTERRUPT_PROTO (ADC_ISR, INTERRUPT_ADC0_EOC);
INTERRUPT_PROTO (TIMER2_ISR, INTERRUPT_TIMER2);
//-----------------------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------------------
// ADC0 decimated value, one for each analog input
SEGMENT_VARIABLE (RESULT[ANALOG_INPUTS], U32, xdata);
// ADC0 input matrix. Bit-wise OR with 0x10 to get the ADC0MX setting for P2
U8 PIN_TABLE[ANALOG_INPUTS] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 };
U8 AMUX_INPUT = 0; // Index of analog MUX inputs
// Integrate accumulator for the ADC samples from input pins
U32 accumulator[ANALOG_INPUTS];
//-----------------------------------------------------------------------------
// MAIN Routine
//-----------------------------------------------------------------------------
void main (void)
{
U8 i; // Loop counter
U32 measurement; // Voltage measurement
SFRPAGE = ACTIVE_PAGE; // Set for PCA0MD and for printf()
PCA0MD &= ~0x40; // Disable the watchdog timer
OSCILLATOR_Init (); // Initialize system clock
PORT_Init (); // Initialize crossbar and GPIO
TIMER2_Init (); // Init Timer2 to trigger ADC
UART0_Init (); // Initialize UART0 for printf's
ADC0_Init (); // Initialize ADC0
// Initialize global variable
for (i = 0; i < ANALOG_INPUTS; i++)
{
accumulator[i] = 0;
}
EA = 1; // Enable global interrupts
while (1)
{
EA = 0; // Disable interrupts
printf ("\f");
for (i = 0; i < ANALOG_INPUTS; i++)
{
// 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 the port pins is then:
//
// Vref (mV)
// measurement (mV) = --------------- * Result (bits)
// (2^12)-1 (bits)
//
// Then multiply the result by 2.27 to account for the 0.44 gain
// applied earlier
measurement = RESULT[i] * 2400 / 4096 * 227 / 100;
printf("P2.%bu voltage: %4ld mV\n", PIN_TABLE[i], measurement);
}
EA = 1; // Re-enable interrupts
Timer0_wait(20); // Wait before displaying new values
}
}
//-----------------------------------------------------------------------------
// Initialization Subroutines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// OSCILLATOR_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// This routine initializes the system clock to use the internal 24 MHz
// oscillator as its clock source. Also enables missing clock detector reset.
//
//-----------------------------------------------------------------------------
void OSCILLATOR_Init (void) //振荡器
{
U8 SFRPAGE_save = SFRPAGE;
SFRPAGE = CONFIG_PAGE;
OSCICN = 0x87; // 配置内部振荡器forits的最高frequencyEnable的时钟丢失检测器
RSTSRC = 0x04;
SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// PORT_Init
//-----------------------------------------------------------------------------
//
// Return Value: None
// Parameters: None
//
// Configure the Crossbar and GPIO ports.
//
// P0.0 - analog VREF
// P0.4 - digital push-pull UART TX
// P0.5 - digital open-drain UART RX
//
// P1.3 - digital push-pull LED
//
// P2.0 - P2.7 analog ADC inputs
//
//-----------------------------------------------------------------------------
void PORT_Init (void) //光电记录跟踪
{
U8 SFRPAGE_save = SFRPAGE;
SFRPAGE = CONFIG_PAGE;
P0SKIP |= 0x01; // Skip P0.0 (VREF)
P0MDOUT |= 0x10; // Set TX pin to push-pull
P0MDIN &= ~0x01; // Set VREF to analog
P1MDOUT |= 0x08; // Enable LED as a push-pull output
P2SKIP = 0xFF; // Skip all of P2 for analog inputs
P2MDIN = 0x00; // Configure all of P2 as analog inputs
XBR0 = 0x01; // Enable UART0
XBR2 = 0x40; // Enable crossbar and weak pull-ups
SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// TIMER2_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Configure Timer2 to 16-bit auto-reload and generate an interrupt at 10 us
// intervals. Timer2 overflows automatically triggers ADC0 conversion.
//
//-----------------------------------------------------------------------------
void TIMER2_Init (void)
{
U8 SFRPAGE_save = SFRPAGE;
SFRPAGE = ACTIVE_PAGE;
TMR2CN = 0x00; // Stop Timer2; Clear TF2;
// use SYSCLK as timebase, 16-bit
// auto-reload
CKCON |= 0x10; // Select SYSCLK for timer 2 source
TMR2RL = 65535 - (SYSCLK / 10000); // Init reload value for 10 us
TMR2 = 0xFFFF; // Set to reload immediately
ET2 = 1; // Enable Timer2 interrupts
TR2 = 1; // Start Timer2
SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// ADC0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Configures ADC0 to make single-ended analog measurements on Port 0 according
// to the values of <ANALOG_INPUTS> and <PIN_TABLE>.
//
//-----------------------------------------------------------------------------
void ADC0_Init (void)
{
U8 SFRPAGE_save = SFRPAGE;
SFRPAGE = ACTIVE_PAGE;
// Initialize the Gain to account for a 5V input and 2.25 VREF
// Solve the equation provided in Section 9.3.1 of the Datasheet
// The 5V input is scaled by a factor of 0.44 so that the maximum input
// voltage seen by the pin is 2.2V
// 0.44 = (GAIN/4096) + GAINADD * (1/64)
// Set GAIN to 0x6CA and GAINADD to 1
// GAIN = is the 12-bit word formed by ADC0GNH[7:0] ADC0GNL[7:4]
// GAINADD is bit ADC0GNA.0
ADC0CF |= 0x01; // Set GAINEN = 1
ADC0H = 0x04; // Load the ADC0GNH address
ADC0L = 0x6C; // Load the upper byte of 0x6CA
ADC0H = 0x07; // Load the ADC0GNL address
ADC0L = 0xA0; // Load the lower nibble of 0x6CA
ADC0H = 0x08; // Load the ADC0GNA address
ADC0L = 0x01; // Set the GAINADD bit
ADC0CF &= ~0x01; // Set GAINEN = 0
ADC0CN = 0x03; // ADC0 disabled, normal tracking,
// conversion triggered on TMR2 overflow
// Output is right-justified
REF0CN = 0x33; // Enable on-chip VREF and buffer
// Set VREF to 2.25V setting
ADC0MX = 0x10 | PIN_TABLE[AMUX_INPUT]; // Set ADC input to initial setting
ADC0CF = ((SYSCLK / 3000000) - 1) << 3; // Set SAR clock to 3MHz
EIE1 |= 0x04; // Enable ADC0 conversion complete int.
AD0EN = 1; // Enable ADC0
SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// UART0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Configure the UART0 using Timer1, for <BAUDRATE> and 8-N-1.
//-----------------------------------------------------------------------------
void UART0_Init (void)
{
U8 SFRPAGE_save = SFRPAGE;
SFRPAGE = CONFIG_PAGE;
SCON0 = 0x10; // SCON0: 8-bit variable bit rate
// clear RI0 and TI0 bits
// Baud Rate = [BRG Clock / (65536 - (SBRLH0:SBRLL0))] x 1/2 x 1/Prescaler
#if ((SYSCLK / BAUDRATE / 2 / 0xFFFF) < 1)
SBRL0 = -(SYSCLK / BAUDRATE / 2);
SBCON0 |= 0x03; // Set prescaler to 1
#elif ((SYSCLK / BAUDRATE / 2 / 0xFFFF) < 4)
SBRL0 = -(SYSCLK / BAUDRATE / 2 / 4);
SBCON0 &= ~0x03;
SBCON0 |= 0x01; // Set prescaler to 4
#elif ((SYSCLK / BAUDRATE / 2 / 0xFFFF) < 12)
SBRL0 = -(SYSCLK / BAUDRATE / 2 / 12);
SBCON0 &= ~0x03; // Set prescaler to 12
#else
SBRL0 = -(SYSCLK / BAUDRATE / 2 / 48);
SBCON0 &= ~0x03;
SBCON0 |= 0x02; // Set prescaler to 48
#endif
SBCON0 |= 0x40; // Enable baud rate generator
TI0 = 1; // Indicate TX0 ready
SFRPAGE = SFRPAGE_save;
}
#ifdef SDCC
// SDCC does not include a definition for putchar(), which is used in printf()
// and so it is defined here. The prototype does not need to be explicitly
// defined because it is provided in stdio.h
//-----------------------------------------------------------------------------
// putchar
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : character to send to UART
//
// This function outputs a character to the UART.
//-----------------------------------------------------------------------------
void putchar (char output)
{
if (outptrr0ut == '\n')
{
while (!TI0);
TI0 = 0;
SBUF0 = 0x0D;
}
while (!TI0);
TI0 = 0;
SBUF0 = output;
}
#endif
//-----------------------------------------------------------------------------
// Interrupt Service Routines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Timer2_ISR
//-----------------------------------------------------------------------------
//
// This routine changes to the next Analog MUX input whenever Timer2 overflows
// for the next ADC sample. This allows the ADC to begin setting on the new
// input while converting the old input.
//
//-----------------------------------------------------------------------------
INTERRUPT (TIMER2_ISR, INTERRUPT_TIMER2)
{
TF2H = 0; // Clear Timer2 interrupt flag
// Set up the AMUX for the next ADC input
if (AMUX_INPUT == (ANALOG_INPUTS - 1))
{
ADC0MX = PIN_TABLE[0] | 0x10;
}
else
{
ADC0MX = PIN_TABLE[AMUX_INPUT+1] | 0x10;
}
}
//-----------------------------------------------------------------------------
// ADC0_ISR
//-----------------------------------------------------------------------------
//
// This ISR averages <INT_DEC> samples for each analog MUX input then prints
// the results to the terminal. The ISR is called after each ADC conversion,
// which is triggered by Timer2.
//
//-----------------------------------------------------------------------------
INTERRUPT (ADC_ISR, INTERRUPT_ADC0_EOC)
{
static U16 int_dec = INT_DEC; // Integrate/decimate counter
// A new result is posted when
// int_dec is 0
U8 i; // Loop counter
AD0INT = 0; // Clear ADC conversion complete
// overflow
accumulator[AMUX_INPUT] += ADC0; // Read the ADC value and add it to the
// running total
// Reset sample counter <int_dec> and <AMUX_INPUT> if the final input was
// just read
if(AMUX_INPUT == (ANALOG_INPUTS - 1))
{
int_dec--; // Update decimation counter
// when the last of the analog inputs
// is sampled
if (int_dec == 0) // If zero, then post the averaged
{ // results
int_dec = INT_DEC; // Reset counter
// Copy each averaged ADC0 value into the RESULT array
for(i = 0; i < ANALOG_INPUTS; i++)
{
// Copy averaged values into RESULT
RESULT[i] = accumulator[i] / int_dec;
// Reset accumulators
accumulator[i] = 0x00000000;
}
}
AMUX_INPUT = 0; // Reset input index back to P0.1
}
// Otherwise, increment the AMUX channel counter
else
{
AMUX_INPUT++; // Step to the next analog mux input
}
}
//-----------------------------------------------------------------------------
// Support Subroutines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Timer0_wait
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters :
// 1) int ms - number of milliseconds to wait
// range is positive range of an int: 0 to 32767
//
// This function configures the Timer0 as a 16-bit timer, interrupt enabled.
// Using the internal osc. at 24.5MHz with a prescaler of 1:8 and reloading the
// T0 registers with TIMER0_RELOAD_HIGH/LOW, it will wait for <ms>
// milliseconds.
// Note: The Timer0 uses a 1:12 prescaler
//-----------------------------------------------------------------------------
void Timer0_wait(int ms)
{
U8 SFRPAGE_save = SFRPAGE;
SFRPAGE = ACTIVE_PAGE;
TH0 = TIMER0_RELOAD_HIGH; // Init Timer0 High register
TL0 = TIMER0_RELOAD_LOW ; // Init Timer0 Low register
TMOD |= 0x01; // Timer0 in 16-bit mode
CKCON &= 0xFC; // Timer0 uses a 1:12 prescaler
TR0 = 1; // Timer0 ON
while(ms)
{
TF0 = 0; // Clear flag to initialize
while(!TF0); // Wait until timer overflows
ms--; // Decrement ms
}
TR0 = 0; // Timer0 OFF
SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// End Of File
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <compiler_defs.h>
#include <C8051F500_defs.h> // SFR declarations
#include <stdio.h>
//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------
#define SYSCLK 24000000 // 系统时钟频率(Hz)
#define BAUDRATE 115200 // UART波特率,单位为bps
#define ANALOG_INPUTS 8 // 衡量AIN引脚数,
// 跳过UART0引脚
#define INT_DEC 256 // 集成和抽取比
#define TIMER0_RELOAD_HIGH 0 // Timer0的高字节寄存器
#define TIMER0_RELOAD_LOW 255 // Timer0的低字节寄存器
//-----------------------------------------------------------------------------
// 函数原型
//-----------------------------------------------------------------------------
void OSCILLATOR_Init (void);
void PORT_Init (void);
void TIMER2_Init (void);
void ADC0_Init (void);
void UART0_Init (void);
void Timer0_wait (int ms);
INTERRUPT_PROTO (ADC_ISR, INTERRUPT_ADC0_EOC);
INTERRUPT_PROTO (TIMER2_ISR, INTERRUPT_TIMER2);
//-----------------------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------------------
// ADC0 decimated value, one for each analog input
SEGMENT_VARIABLE (RESULT[ANALOG_INPUTS], U32, xdata);
// ADC0 input matrix. Bit-wise OR with 0x10 to get the ADC0MX setting for P2
U8 PIN_TABLE[ANALOG_INPUTS] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 };
U8 AMUX_INPUT = 0; // Index of analog MUX inputs
// Integrate accumulator for the ADC samples from input pins
U32 accumulator[ANALOG_INPUTS];
//-----------------------------------------------------------------------------
// MAIN Routine
//-----------------------------------------------------------------------------
void main (void)
{
U8 i; // Loop counter
U32 measurement; // Voltage measurement
SFRPAGE = ACTIVE_PAGE; // Set for PCA0MD and for printf()
PCA0MD &= ~0x40; // Disable the watchdog timer
OSCILLATOR_Init (); // Initialize system clock
PORT_Init (); // Initialize crossbar and GPIO
TIMER2_Init (); // Init Timer2 to trigger ADC
UART0_Init (); // Initialize UART0 for printf's
ADC0_Init (); // Initialize ADC0
// Initialize global variable
for (i = 0; i < ANALOG_INPUTS; i++)
{
accumulator[i] = 0;
}
EA = 1; // Enable global interrupts
while (1)
{
EA = 0; // Disable interrupts
printf ("\f");
for (i = 0; i < ANALOG_INPUTS; i++)
{
// 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 the port pins is then:
//
// Vref (mV)
// measurement (mV) = --------------- * Result (bits)
// (2^12)-1 (bits)
//
// Then multiply the result by 2.27 to account for the 0.44 gain
// applied earlier
measurement = RESULT[i] * 2400 / 4096 * 227 / 100;
printf("P2.%bu voltage: %4ld mV\n", PIN_TABLE[i], measurement);
}
EA = 1; // Re-enable interrupts
Timer0_wait(20); // Wait before displaying new values
}
}
//-----------------------------------------------------------------------------
// Initialization Subroutines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// OSCILLATOR_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// This routine initializes the system clock to use the internal 24 MHz
// oscillator as its clock source. Also enables missing clock detector reset.
//
//-----------------------------------------------------------------------------
void OSCILLATOR_Init (void) //振荡器
{
U8 SFRPAGE_save = SFRPAGE;
SFRPAGE = CONFIG_PAGE;
OSCICN = 0x87; // 配置内部振荡器forits的最高frequencyEnable的时钟丢失检测器
RSTSRC = 0x04;
SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// PORT_Init
//-----------------------------------------------------------------------------
//
// Return Value: None
// Parameters: None
//
// Configure the Crossbar and GPIO ports.
//
// P0.0 - analog VREF
// P0.4 - digital push-pull UART TX
// P0.5 - digital open-drain UART RX
//
// P1.3 - digital push-pull LED
//
// P2.0 - P2.7 analog ADC inputs
//
//-----------------------------------------------------------------------------
void PORT_Init (void) //光电记录跟踪
{
U8 SFRPAGE_save = SFRPAGE;
SFRPAGE = CONFIG_PAGE;
P0SKIP |= 0x01; // Skip P0.0 (VREF)
P0MDOUT |= 0x10; // Set TX pin to push-pull
P0MDIN &= ~0x01; // Set VREF to analog
P1MDOUT |= 0x08; // Enable LED as a push-pull output
P2SKIP = 0xFF; // Skip all of P2 for analog inputs
P2MDIN = 0x00; // Configure all of P2 as analog inputs
XBR0 = 0x01; // Enable UART0
XBR2 = 0x40; // Enable crossbar and weak pull-ups
SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// TIMER2_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Configure Timer2 to 16-bit auto-reload and generate an interrupt at 10 us
// intervals. Timer2 overflows automatically triggers ADC0 conversion.
//
//-----------------------------------------------------------------------------
void TIMER2_Init (void)
{
U8 SFRPAGE_save = SFRPAGE;
SFRPAGE = ACTIVE_PAGE;
TMR2CN = 0x00; // Stop Timer2; Clear TF2;
// use SYSCLK as timebase, 16-bit
// auto-reload
CKCON |= 0x10; // Select SYSCLK for timer 2 source
TMR2RL = 65535 - (SYSCLK / 10000); // Init reload value for 10 us
TMR2 = 0xFFFF; // Set to reload immediately
ET2 = 1; // Enable Timer2 interrupts
TR2 = 1; // Start Timer2
SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// ADC0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Configures ADC0 to make single-ended analog measurements on Port 0 according
// to the values of <ANALOG_INPUTS> and <PIN_TABLE>.
//
//-----------------------------------------------------------------------------
void ADC0_Init (void)
{
U8 SFRPAGE_save = SFRPAGE;
SFRPAGE = ACTIVE_PAGE;
// Initialize the Gain to account for a 5V input and 2.25 VREF
// Solve the equation provided in Section 9.3.1 of the Datasheet
// The 5V input is scaled by a factor of 0.44 so that the maximum input
// voltage seen by the pin is 2.2V
// 0.44 = (GAIN/4096) + GAINADD * (1/64)
// Set GAIN to 0x6CA and GAINADD to 1
// GAIN = is the 12-bit word formed by ADC0GNH[7:0] ADC0GNL[7:4]
// GAINADD is bit ADC0GNA.0
ADC0CF |= 0x01; // Set GAINEN = 1
ADC0H = 0x04; // Load the ADC0GNH address
ADC0L = 0x6C; // Load the upper byte of 0x6CA
ADC0H = 0x07; // Load the ADC0GNL address
ADC0L = 0xA0; // Load the lower nibble of 0x6CA
ADC0H = 0x08; // Load the ADC0GNA address
ADC0L = 0x01; // Set the GAINADD bit
ADC0CF &= ~0x01; // Set GAINEN = 0
ADC0CN = 0x03; // ADC0 disabled, normal tracking,
// conversion triggered on TMR2 overflow
// Output is right-justified
REF0CN = 0x33; // Enable on-chip VREF and buffer
// Set VREF to 2.25V setting
ADC0MX = 0x10 | PIN_TABLE[AMUX_INPUT]; // Set ADC input to initial setting
ADC0CF = ((SYSCLK / 3000000) - 1) << 3; // Set SAR clock to 3MHz
EIE1 |= 0x04; // Enable ADC0 conversion complete int.
AD0EN = 1; // Enable ADC0
SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// UART0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Configure the UART0 using Timer1, for <BAUDRATE> and 8-N-1.
//-----------------------------------------------------------------------------
void UART0_Init (void)
{
U8 SFRPAGE_save = SFRPAGE;
SFRPAGE = CONFIG_PAGE;
SCON0 = 0x10; // SCON0: 8-bit variable bit rate
// clear RI0 and TI0 bits
// Baud Rate = [BRG Clock / (65536 - (SBRLH0:SBRLL0))] x 1/2 x 1/Prescaler
#if ((SYSCLK / BAUDRATE / 2 / 0xFFFF) < 1)
SBRL0 = -(SYSCLK / BAUDRATE / 2);
SBCON0 |= 0x03; // Set prescaler to 1
#elif ((SYSCLK / BAUDRATE / 2 / 0xFFFF) < 4)
SBRL0 = -(SYSCLK / BAUDRATE / 2 / 4);
SBCON0 &= ~0x03;
SBCON0 |= 0x01; // Set prescaler to 4
#elif ((SYSCLK / BAUDRATE / 2 / 0xFFFF) < 12)
SBRL0 = -(SYSCLK / BAUDRATE / 2 / 12);
SBCON0 &= ~0x03; // Set prescaler to 12
#else
SBRL0 = -(SYSCLK / BAUDRATE / 2 / 48);
SBCON0 &= ~0x03;
SBCON0 |= 0x02; // Set prescaler to 48
#endif
SBCON0 |= 0x40; // Enable baud rate generator
TI0 = 1; // Indicate TX0 ready
SFRPAGE = SFRPAGE_save;
}
#ifdef SDCC
// SDCC does not include a definition for putchar(), which is used in printf()
// and so it is defined here. The prototype does not need to be explicitly
// defined because it is provided in stdio.h
//-----------------------------------------------------------------------------
// putchar
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : character to send to UART
//
// This function outputs a character to the UART.
//-----------------------------------------------------------------------------
void putchar (char output)
{
if (outptrr0ut == '\n')
{
while (!TI0);
TI0 = 0;
SBUF0 = 0x0D;
}
while (!TI0);
TI0 = 0;
SBUF0 = output;
}
#endif
//-----------------------------------------------------------------------------
// Interrupt Service Routines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Timer2_ISR
//-----------------------------------------------------------------------------
//
// This routine changes to the next Analog MUX input whenever Timer2 overflows
// for the next ADC sample. This allows the ADC to begin setting on the new
// input while converting the old input.
//
//-----------------------------------------------------------------------------
INTERRUPT (TIMER2_ISR, INTERRUPT_TIMER2)
{
TF2H = 0; // Clear Timer2 interrupt flag
// Set up the AMUX for the next ADC input
if (AMUX_INPUT == (ANALOG_INPUTS - 1))
{
ADC0MX = PIN_TABLE[0] | 0x10;
}
else
{
ADC0MX = PIN_TABLE[AMUX_INPUT+1] | 0x10;
}
}
//-----------------------------------------------------------------------------
// ADC0_ISR
//-----------------------------------------------------------------------------
//
// This ISR averages <INT_DEC> samples for each analog MUX input then prints
// the results to the terminal. The ISR is called after each ADC conversion,
// which is triggered by Timer2.
//
//-----------------------------------------------------------------------------
INTERRUPT (ADC_ISR, INTERRUPT_ADC0_EOC)
{
static U16 int_dec = INT_DEC; // Integrate/decimate counter
// A new result is posted when
// int_dec is 0
U8 i; // Loop counter
AD0INT = 0; // Clear ADC conversion complete
// overflow
accumulator[AMUX_INPUT] += ADC0; // Read the ADC value and add it to the
// running total
// Reset sample counter <int_dec> and <AMUX_INPUT> if the final input was
// just read
if(AMUX_INPUT == (ANALOG_INPUTS - 1))
{
int_dec--; // Update decimation counter
// when the last of the analog inputs
// is sampled
if (int_dec == 0) // If zero, then post the averaged
{ // results
int_dec = INT_DEC; // Reset counter
// Copy each averaged ADC0 value into the RESULT array
for(i = 0; i < ANALOG_INPUTS; i++)
{
// Copy averaged values into RESULT
RESULT[i] = accumulator[i] / int_dec;
// Reset accumulators
accumulator[i] = 0x00000000;
}
}
AMUX_INPUT = 0; // Reset input index back to P0.1
}
// Otherwise, increment the AMUX channel counter
else
{
AMUX_INPUT++; // Step to the next analog mux input
}
}
//-----------------------------------------------------------------------------
// Support Subroutines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Timer0_wait
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters :
// 1) int ms - number of milliseconds to wait
// range is positive range of an int: 0 to 32767
//
// This function configures the Timer0 as a 16-bit timer, interrupt enabled.
// Using the internal osc. at 24.5MHz with a prescaler of 1:8 and reloading the
// T0 registers with TIMER0_RELOAD_HIGH/LOW, it will wait for <ms>
// milliseconds.
// Note: The Timer0 uses a 1:12 prescaler
//-----------------------------------------------------------------------------
void Timer0_wait(int ms)
{
U8 SFRPAGE_save = SFRPAGE;
SFRPAGE = ACTIVE_PAGE;
TH0 = TIMER0_RELOAD_HIGH; // Init Timer0 High register
TL0 = TIMER0_RELOAD_LOW ; // Init Timer0 Low register
TMOD |= 0x01; // Timer0 in 16-bit mode
CKCON &= 0xFC; // Timer0 uses a 1:12 prescaler
TR0 = 1; // Timer0 ON
while(ms)
{
TF0 = 0; // Clear flag to initialize
while(!TF0); // Wait until timer overflows
ms--; // Decrement ms
}
TR0 = 0; // Timer0 OFF
SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// End Of File
//-----------------------------------------------------------------------------