Page 1
//----------------------------------------------------------------------------// F330DC_FeaturesDemo.c
//----------------------------------------------------------------------------// Copyright 2006 Silicon Laboratories, Inc.
// http://www.silabs.com
//
// Program Description:
//
// This program demonstrates the features available on the ToolStick
// F330 Daughter Card.
//
// Based on the setting of a level-sensitive interrupt pin, the firmware
// will either blink the green LED or PWM the LED. The blinking speed
// or the PWM duty cycle is set based on the value of the potentiometer.
// Voltage across the potentiometer is measured using the on-chip 10-bit ADC.
//
// The program also outputs the status of the LED to the UART at a baud rate
// defined by <BAUDRATE>.
//
// How To Test:
// 1) Connect the ToolStickF330DC to the PC and download the code
// 2) Turn the potentiometer and see that the blink rate increases or decreases
// 3) Connect to the ToolStickF330DC using ToolStickTerminal and see that
// the UART output changes as the potentiometer is turned
// 4) In ToolStickTerminal, toggle GPIO0/RTS to force the firmware to
// switch modes.
// 5) Turn the potentiometer and see that the brightness of the LED changes
// and check that the output of the UART also changes.
//
//
// FID:
33X000030
// Target:
ToolStickF330DC
// Tool chain:
//
Keil C51 7.50 / Keil EVAL C51
Silicon Laboratories IDE version 2.6
//
// Release 1.0
// -Initial Revision (GP)
// -06 AUG 2006
//
//----------------------------------------------------------------------------// Includes
//----------------------------------------------------------------------------#include <C8051F330.h>
// SFR declarations
#include <stdio.h>
#include <stdlib.h>
//----------------------------------------------------------------------------// SFR and Bit Definitions
//----------------------------------------------------------------------------sfr16 ADC0
= 0xBD;
sfr16 TMR2RL = 0xCA;
sfr16 TMR2
= 0xCC;
sfr16 TMR3RL = 0x92;
sfr16 TMR3
= 0x94;
// ADC result
// Timer2 reload value
// Timer2 counter
// Timer3 reload value
// Timer3 counter
sbit LED
= P1^3;
// LED='1' means ON
//----------------------------------------------------------------------------// Global Constants
//----------------------------------------------------------------------------#define SYSCLK
3000000L
#define BAUDRATE
115200
#define PRINT_RATE
20
// SYSCLK frequency in Hz
// Baud rate of UART in bps
// Times per second to update on UART
#define OVERFLOWS_NEEDED (SYSCLK / 65536 / PRINT_RATE)
#define ADC_CLOCK
100000
#define ADC_SAMPLE_RATE 100
#define ADC_COUNTS
1024
#define MAX_BLINK_RATE 40
#define MIN_BLINK_RATE 1
// SAR clock
// Timer 2 overflow rate in Hz
// Number of ADC counts
// Max blink rate in Hz for Timer mode
// Min blink rate in Hz for Timer mode
#define BLINK_DIFF (MAX_BLINK_RATE - MIN_BLINK_RATE) // For easy calculations
// Firmware states = les 2 modes pour toolstick terminal
#define TIMER_MODE
0
// Uses the Timer to blink the LED
#define PWM_MODE
1
// Use a PCA channel to PWM the LED
//----------------------------------------------------------------------------// Function Prototypes
//----------------------------------------------------------------------------void OSCILLATOR_Init (void);
void PORT_Init (void);
void TIMER0_Init (void);
void TIMER2_Init (int counts);
void TIMER3_Init (void);
void ADC0_Init (void);
void PCA0_Init (void);
void UART0_Init (void);
void INT0_Init (void);
void Print_String (char pstring[]);
// ISRs defined: INT0_ISR, TIMER0_ISR, TIMER3_ISR, ADC0_ISR.
//----------------------------------------------------------------------------// Global Variables
//----------------------------------------------------------------------------bit Blink_State
= TIMER_MODE;
int PWM_Duty_Cycle = 0;
int Blink_Rate
bit update
// Starts with blinking the LED
// Percentage from 0 to 100
= 0;
// From MIN_BLINK_RATE to MAX_BLINK_RATE
= 0;
// Forces a UART update
// Simply counts the number of times
long Num_LED_Flashes = 0;
// the LED blinks
//----------------------------------------------------------------------------// MAIN Routine
//----------------------------------------------------------------------------void main (void)
{
PCA0MD &= ~0x40;
// WDTE = 0 (clear watchdog timer
// enable)
OSCILLATOR_Init ();
PORT_Init ();
TIMER0_Init ();
// Initialize system clock to 24.5 Mhz
// Initialize crossbar and GPIO
// Initialize Timer0 for UART update
TIMER2_Init (SYSCLK / 12 / ADC_SAMPLE_RATE); // Init Timer2 for ADC
TIMER3_Init ();
// Init timer used to blink LED
PCA0_Init ();
// Init PCA Module 0 to blink LED
ADC0_Init ();
// Enable ADC0
INT0_Init ();
UART0_Init ();
EA = 1;
// Enable /INT0
// Enable UART using global settings
// Enable global interrupts
while (1) {}
}
//----------------------------------------------------------------------------// Interrupt Service Routines
//-----------------------------------------------------------------------------
//----------------------------------------------------------------------------// INT0_ISR
//----------------------------------------------------------------------------//
// INT0_ISR is triggered upon a level transition on the /INT0 pin.
// If /INT0 is logic high, the firmware switches to a state that blinks the LED
// If /INT0 is logic low, the fimware applies PWM wave to the LED to control
// the brightness.
//
//----------------------------------------------------------------------------void INT0_ISR (void) interrupt 0
{
if (IT01CF & 0x08)
// Currently active-high
{
IT01CF &= ~0x08;
// Switch to active-low
Blink_State = TIMER_MODE;
// State is now Timer mode
update = 1;
// Switch to Timer Mode
CR
= 0;
// Stop PCA Counter
XBR1 &= ~0x01;
// Remove CEX0 from Crossbar
TMR3CN |= 0x04;
// Start Timer3
}
else
{
IT01CF |= 0x08;
// Switch to active-high
Blink_State = PWM_MODE;
// State is now PWM mode
update = 1;
// Switch To PWM Mode
TMR3CN &= ~0x04;
XBR1 |= 0x01;
CR
= 1;
// Stop Timer3
// Put CEX0 on Crossbar (P1.3)
// Start PCA Counter
}
}
//----------------------------------------------------------------------------// TIMER0_ISR
//----------------------------------------------------------------------------//
// This ISR is triggered upon a Timer0 overflow. It is used to update the
// UART with the status of the LED.
//
//-----------------------------------------------------------------------------
void TIMER0_ISR (void) interrupt 1
{
static int overflows = 0;
// Timer0 is used to schedule the number of times per second the status is
// printed to the UART. Since Timer0 and Timer1 share a SYCLK prescaler, it
// is easier to use the prescaler only for Timer1 (UART baud rate) and run
// Timer0 from SYSCLK. Running Timer0 from SYSCLK requires keeping track
// of the number of Timer0 overflows to schedule a reasonable UART update
// rate. Updating on every Timer0 overflow would print too fast.
// The benefit is that there is more flexibility in scheduling the update
// rate as it is no longer any dependent on the fixed UART prescaler.
overflows++;
// Time to print
if (overflows == OVERFLOWS_NEEDED)
{
if ((Blink_State == TIMER_MODE) & update)
// Timer mode
{
putchar ('\f');
// Clear screen
Print_String ("LED Blink Rate: ");
// Add a hundreds digit if <MAX_BLINK_RATE> requires one
putchar ((Blink_Rate / 10) + 0x30);
putchar ((Blink_Rate % 10) + 0x30);
// Tens digit
// Ones digit
Print_String (" Hz\n");
update = 0;
}
else if ((Blink_State == PWM_MODE) & update)
{
// PWM mode
putchar ('\f');
// Clear screen
Print_String ("LED PWM Duty Cycle: ");
putchar ((PWM_Duty_Cycle / 100) + 0x30);
// Hundreds digit
putchar (((PWM_Duty_Cycle / 10) % 10) + 0x30); // Tens digit
putchar ((PWM_Duty_Cycle % 10) + 0x30);
// Ones digit
Print_String (" %\n");
update = 0;
}
overflows = 0;
// Reset the count
}
}
//----------------------------------------------------------------------------// ADC0_ISR
//----------------------------------------------------------------------------//
// ADC0_ISR is triggerered upon the completion of an ADC conversion. The ISR
// calculates the Blink_Rate or PWM_Duty_Cycle based on the voltage
// across the potentiometer.
//
// Blink mode:
// A full-scale reading will configure the Timer to blink the LED at
// <MAX_BLINK_RATE>
// A zero reading will configure the Timer the LED to blink at <MIN_BLINK_RATE>
//
// PWM mode:
// A full scale value will configure the PCA to use a duty cycle of 100%
// A zero reading will configure the PCA to use a duty cycle of 0%
//
//----------------------------------------------------------------------------void ADC0_ISR (void) interrupt 10
{
unsigned int ADC_result;
unsigned long reload_speed, percentage;
static int PWM_Duty_Cycle_Old = 0;
static int Blink_Rate_Old
AD0INT = 0;
= 0;
// Clear conversion complete flag
ADC_result = ADC0;
if (Blink_State == TIMER_MODE)
{
if (ADC_result == 0x03FF)
{
// Assume max reading indicates VDD
// and not (VDD - 1 LSB)
reload_speed = MAX_BLINK_RATE;
}
else
{
reload_speed = (long) (ADC_result * BLINK_DIFF);
reload_speed = reload_speed / ADC_COUNTS;
reload_speed += MIN_BLINK_RATE;
}
Blink_Rate = reload_speed;
// Set global variable
if (Blink_Rate != Blink_Rate_Old) {
update = 1; }
Blink_Rate_Old = Blink_Rate;
TMR3RL = - ((unsigned int) (SYSCLK / 12 / reload_speed));
}
else
{
if (ADC_result == 0x03FF)
{
// Assume max reading indicates VDD
// and not (VDD - 1 LSB)
percentage = 255;
PWM_Duty_Cycle = 100;
}
else
{
percentage = (long) ADC_result * (long) 256;
percentage = (long) percentage / (long) ADC_COUNTS;
PWM_Duty_Cycle = (int) ( ((long)ADC_result * (long)100) / (long)ADC_COUNTS );
}
if (PWM_Duty_Cycle != PWM_Duty_Cycle_Old) {
update = 1; }
PWM_Duty_Cycle_Old = PWM_Duty_Cycle;
// Set new PCA0 Module0 PWM duty cycle
PCA0CPH0 = (char) percentage;
}
}
//----------------------------------------------------------------------------// TIMER3_ISR
//----------------------------------------------------------------------------//
// This ISR is triggered upon a Timer3 overflow. The ISR simply toggles
// the state of the LED and keeps track of the number of times the LED blinks.
//
//----------------------------------------------------------------------------void TIMER3_ISR (void) interrupt 14
{
TMR3CN &= ~0x80;
// Clear Timer3 Flags
LED = !LED;
Num_LED_Flashes++;
}
//----------------------------------------------------------------------------// Initialization Subroutines
//-----------------------------------------------------------------------------
//----------------------------------------------------------------------------// OSCILLATOR_Init
//----------------------------------------------------------------------------//
// Return Value : None
// Parameters : None
//
// This function initializes the system clock to use the internal 24.5/8 MHz
// oscillator as its clock source. Also enables missing clock detector reset.
//
//----------------------------------------------------------------------------void OSCILLATOR_Init (void)
{
OSCICN = 0x80;
// Configure internal oscillator for
// its lowest frequency
RSTSRC = 0x04;
// Enable missing clock detector
}
//----------------------------------------------------------------------------// 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
// P0.6 digital open-drain /INT0
// P1.3 digital push-pull
// P1.6 analog
LED (and CEX0 depending on Blink_State)
Potentiometer (ADC input)
//
//----------------------------------------------------------------------------void PORT_Init (void)
{
P1MDIN = 0xBF;
// P1.6 is analog, rest of P1 digital
P0MDOUT = 0x10;
// P0.4 is push-pull
P1MDOUT = 0x08;
// P1.3 is push-pull
P0SKIP = 0xCF;
// Skip all of P0 except for UART0 pins
P1SKIP = 0x47;
// Skip P1.6 and push CEX0 to P1.3
P0
|= 0x60;
// Set port latch for pins RX and /INT0
// to configure as inputs
XBR0
= 0x01;
// Enable UART
XBR1
= 0x40;
// Enable Crossbar; pull-ups enabled
}
//----------------------------------------------------------------------------// TIMER0_Init
//----------------------------------------------------------------------------//
// Return Value : None
// Parameters : None
//
// Initializes the Timer in 16-bit reload mode using SYSCLK as the time base.
//
//----------------------------------------------------------------------------void TIMER0_Init (void)
{
// Initialize Timer0; set global variable for number overflows to reach
// interrupt rate set by <PRINT_RATE>
TMOD |= 0x01;
// Mode 1 - 16-bit counter
CKCON |= 0x04;
// Use SYSCLK as timebase
TL0
= 0;
// Clear Timer0 low byte
TH0
= 0;
// Clear Timer0 high byte
IE
|= 0x02;
TR0 = 1;
}
// Enable Timer0 Interrupts
// Enable Timer 0
//----------------------------------------------------------------------------// TIMER2_Init
//----------------------------------------------------------------------------//
// Return Value : None
// Parameters :
// 1) int counts - number of milliseconds of delay
//
range is postive range of integer: 0 to 32767
//
// Configure Timer2 to 16-bit auto-reload and generate an interrupt at
// interval specified by <counts> using SYSCLK/12 as its time base.
//
//----------------------------------------------------------------------------void TIMER2_Init (int counts)
{
TMR2CN = 0x00;
// Stop Timer2; Clear TF2;
// use SYSCLK/12 as timebase
CKCON &= ~0x30;
// Timer2 clocked based on T2XCLK;
TMR2RL = -counts;
// Init reload values
TMR2 = 0xffff;
// Set to reload immediately
ET2
= 0;
// Disable Timer2 interrupts
TR2
= 1;
// Start Timer2
}
//----------------------------------------------------------------------------// TIMER3_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Configure Timer3 to 16-bit auto-reload and generate an interrupt at
// interval specified by <counts> using SYSCLK/12 as its time base.
//
// Initially sets Timer3 to overflow at the maximum blink rate. The Timer3 ISR
// is used to toggle the LED.
//
//----------------------------------------------------------------------------void TIMER3_Init (void)
{
// Stop Timer3; Clear flags;
TMR3CN = 0x00;
// use SYSCLK/12 as timebase
CKCON &= ~0xC0;
// Timer3 clocked based on T3XCLK;
TMR3RL = -(SYSCLK / 12 / MIN_BLINK_RATE); // Init reload values
TMR3 = 0xffff;
// Set to reload immediately
EIE1 |= 0x80;
// Enable Timer3 interrupts
TMR3CN |= 0x04;
// Start Timer3
}
//----------------------------------------------------------------------------// ADC0_Init
//----------------------------------------------------------------------------//
// Return Value : None
// Parameters : None
//
// This function initializes the ADC to measure potetiometer connected
// to P1.6 in single-ended mode. Also enables the internal voltage reference.
//
//----------------------------------------------------------------------------void ADC0_Init (void)
{
ADC0CN = 0x02;
// Disable ADC0
// Normal Track Mode
// Enable conversion on Timer2 overflow
AMX0P = 0x0E;
// P1.6 is the positive input
AMX0N = 0x11;
// GND is the negative input
ADC0CF = (SYSCLK/ADC_CLOCK) << 3; // ADC conversion clock <= 3MHz
// Make ADC0 right-justified
ADC0CF &= ~0x04;
EIE1 |= 0x08;
// Enable ADC0 conversion-complete
// interrupts
REF0CN = 0x0A;
AD0EN = 1;
// VREF = VDD, bias generator is on.
// Enable ADC0
}
//----------------------------------------------------------------------------// UART0_Init
//----------------------------------------------------------------------------//
// Return Value : None
// Parameters : None
//
// Configure the UART1 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;
TMOD &= ~0xf0;
// Init Timer1
// TMOD: timer 1 in 8-bit autoreload
TMOD |= 0x20;
TR1 = 1;
// START Timer1
TI0 = 1;
// Indicate TX0 ready
}
//----------------------------------------------------------------------------// PCA0_Init
//----------------------------------------------------------------------------//
// Return Value : None
// Parameters : None
//
// Configure Module0 to 8-bit PWM. The duty cycle is initially set to 50%. The
// duty cycle will actually be determined by the value of the potentiometer.
//
// The PCA counter isn't started until the user switches to PWM mode.
//
//----------------------------------------------------------------------------void PCA0_Init (void)
{
// Configure PCA time base; overflow interrupt disabled
PCA0CN = 0x00;
// Stop counter; clear all flags
PCA0MD = 0x08;
// Use SYSCLK as time base
PCA0CPM0 = 0x42;
// Module 0 = 8-bit PWM mode
// Configure initial PWM duty cycle = 50%
PCA0CPH0 = 256 - (256 * 0.5);
}
//-----------------------------------------------------------------------------
// INT0_Init
//----------------------------------------------------------------------------//
// Return Value : None
// Parameters : None
//
// Configure /INT0 (P0.6) to be a level-sensitive interrupt pin.
// Starts active-low, but the INT0 ISR will switch this back and forth.
//
//----------------------------------------------------------------------------void INT0_Init (void)
{
IT01CF = 0x06;
// Configure /INT0 to P0.6
// Active High
IT0 = 0;
// /INT0 is level sensitive
EX0 = 1;
// Enable /INT0 interrupts
}
//----------------------------------------------------------------------------// Support Functions
//-----------------------------------------------------------------------------
//----------------------------------------------------------------------------// Print_String
//----------------------------------------------------------------------------//
// Return Value : None
// Parameters :
//
1) char pstring[] - null terminated character string
//
// Prints the strings stored in pstring to the UART.
//
//----------------------------------------------------------------------------void Print_String (char pstring[])
{
unsigned char i = 0;
while (pstring[i])
{
putchar(pstring[i++]);
}
}
//----------------------------------------------------------------------------// End Of File
//-------------------------------------
Was this manual useful for you? yes no
Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Download PDF

advertisement