light_find

light_find
//----------------------------------------------------------------------------// Light_find.c
//----------------------------------------------------------------------------// Author: Baylor Electromechanical Systems
//
// Operates on an external 18.432MHz oscillator.
//
// Target: Cygnal Educational Development Board / C8051F020
// Tool chain: KEIL C51 6.03 / KEIL EVAL C51
//
// This program dives a stepper motor and reads the voltage drop from across a
// photo resistor that is mounted on the shaft of the stepper motor. The user
// initiates the initial motor rotation by pressing button P3.7. At each
// step of the motor, the program reads 256 samples of the voltage into ADC0.0.
// It calculates the average by adding each sample to a running accumulator and
// shifting right by 8 bits (divide by 256). 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.
//
// It then compares the average voltage drop across the photo resistor to a
// previous value of the lowest voltage drop and saves that value if it is
// lower than the previous value. A low voltage drop coresponds to a brighter
// light. After a full rotation is achieved, the stepper motor reverses
// direction and returns to the position where the brightest light was measured.
// The program waits for the user to again press button P3.7 before it returns
// to the start position of the stepper motor.
//
// Assumes an 18.432MHz crystal is attached between XTAL1 and XTAL2.
//
// The system clock frequency is stored in a global constant SYSCLK. The
// target UART baud rate is stored in a global constant BAUDRATE. The
// ADC0 sampling rate is stored in a global constant SAMPLERATE0.
//
// 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).
//
//----------------------------------------------------------------------------// Includes
//----------------------------------------------------------------------------#include <c8051f020.h>
#include <stdio.h>
// SFR declarations
//----------------------------------------------------------------------------// 16-bit SFR Definitions for 'F02x
//----------------------------------------------------------------------------sfr16 DP
sfr16 TMR3RL
= 0x82;
= 0x92;
// data pointer
// Timer3 reload value
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
sfr16
TMR3
ADC0
ADC0GT
ADC0LT
RCAP2
T2
RCAP4
T4
DAC0
DAC1
=
=
=
=
=
=
=
=
=
=
0x94;
0xbe;
0xc4;
0xc6;
0xca;
0xcc;
0xe4;
0xf4;
0xd2;
0xd5;
//
//
//
//
//
//
//
//
//
//
Timer3 counter
ADC0 data
ADC0 greater than window
ADC0 less than window
Timer2 capture/reload
Timer2
Timer4 capture/reload
Timer4
DAC0 data
DAC1 data
//----------------------------------------------------------------------------// Global CONSTANTS
//----------------------------------------------------------------------------#define
#define
#define
#define
SYSCLK
BAUDRATE
SAMPLERATE0
INT_DEC
18432000
9600
50000
256
sbit LED = P1^6;
sbit SW1 = P1^7;
//
//
//
//
SYSCLK frequency in Hz
Baud rate of UART in bps
ADC0 Sample frequency in Hz
integrate and decimate ratio
// LED='1' means ON
// SW1='0' means switch pressed
//----------------------------------------------------------------------------// Function PROTOTYPES
//----------------------------------------------------------------------------void SYSCLK_Init (void);
void PORT_Init (void);
void UART0_Init (void);
void ADC0_Init (void);
void Timer3_Init (int counts);
int stpdrvr(int cmd);
void delay_ms(int ms);
//----------------------------------------------------------------------------// MAIN Routine
//----------------------------------------------------------------------------void main (void)
{
long result,minvalue;
light
int steps;
counter
int minstep;
brightest light
// AIN0 results & value at bright
// steps from start postition
// stores the location of
WDTCN = 0xde;
WDTCN = 0xad;
// disable watchdog timer
SYSCLK_Init ();
PORT_Init ();
// initialize oscillator
// initialize crossbar and
UART0_Init ();
// initialize UART0
GPIO
ADC0_Init ();
Timer3_Init (SYSCLK/SAMPLERATE0);
// init ADC
// initialize Timer3 to overflow at
// sample rate
AD0EN = 1;
EA = 1;
interrupts
// enable ADC
// Enable global
stpdrvr(0x00);
// reset device
while(1)
{
while (!SW1)
// the BIG loop
// begin search on button
press
{
steps = 0;
minvalue = 65535;
// initilize variables
// 65535 is above range (~no
light)
minstep = 0;
while(steps < 48)
// will step though motor 48 times 1
rev
{
static unsigned int_dec=INT_DEC;
// integrate/decimate
// 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
while(int_dec > 0)
{
accumulator += ADC0;
// read ADC value
and add
// to
running total
int_dec--;
// update
decimation counter
}
int_dec = INT_DEC;
// reset
counter
light
result = accumulator >> 8;
accumulator = 0L;
// reset accumulator
if (result < minvalue)
// check if brighter
// than
previous brightest
{
minvalue = result;
// if
brightest so far,
// save
value and position
minstep = steps;
}
printf ("Position '%d' voltage is %ldmV\n", steps,
//
voltage);
delay_ms(150);
stpdrvr(0x01);
// step motor one step
steps++;
// increment step counter
clockwise
}
delay_ms(3000);
// pause to verify one
// revolution is
complete
while(steps >= minstep)
// step counter clockwise to
point
// of brightest
light
{
delay_ms(150);
stpdrvr(0x02);
steps--;
}
stpdrvr(0);
// Set all stepper drivers to 0 to
// stop current consumption
while (SW1) {
}
// pause to verify if it is
brightest light
// before pressing button
again for reset
while(steps > 0)
// restart stepper at beginning
position
{
delay_ms(150);
stpdrvr(0x02);
steps--;
}
stpdrvr(0);
}
// Set all stepper drivers to 0 to
// stop current consumption
}
}
//----------------------------------------------------------------------------// Initialization Subroutines
//-----------------------------------------------------------------------------
//----------------------------------------------------------------------------// SYSCLK_Init
//----------------------------------------------------------------------------//
// This routine initializes the system clock to use an 18.432MHz 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
P0MDOUT |= 0x01;
// enable TX0 as a push-pull output
P1MDOUT |= 0x40;
// enable P1.6 (LED) as push-pull output
P2MDOUT = 0x0F;
// PORT 2 CONFIGURATION
}
//----------------------------------------------------------------------------// UART0_Init
//----------------------------------------------------------------------------//
// Configure the UART0 using Timer1, for <baudrate> and 8-N-1.
//
void UART0_Init (void)
{
SCON0
= 0x50;
// SCON0: 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;
// SMOD00 = 1
TI0
= 1;
// Indicate TX0 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.
// Note: here we also enable low-power tracking mode to ensure that minimum
// tracking times are met when ADC0 channels are changed.
//
void ADC0_Init (void)
{
ADC0CN = 0x45;
// ADC0 disabled; low-power 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 = 0x00;
// Select AIN0 as ADC mux output
ADC0CF = (SYSCLK/2500000) << 3;
// ADC conversion clock = 2.5MHz
ADC0CF &= ~0x07;
// PGA gain = 1
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
}
//----------------------------------------------------------------------------// Local Functions
//----------------------------------------------------------------------------//----------------------------------------------------------------------------// stpdrvr
//----------------------------------------------------------------------------//
//
Function: Implments the full step drive for a unipolar stepper motor
//
Parameters: cmd = 0 (off); cmd = 1 (CW); cmd = 2 (CCW)
//
Return: bit pattern to send to P2
int stpdrvr(int cmd)
{
int step;
//
int fwave[5] = {0x00, 0x0A, 0x09, 0x05, 0x06};
// for full step
int fwave[9] = {0x00, 0x0A, 0x08, 0x09, 0x01, 0x05, 0x04, 0x06, 0x02};
// for half step
switch(cmd)
{
case 0: step = 0; break;
case 1: step = step-1;
if(step < 1)
step = 4;
break;
case 2: step = step+1;
if(step > 4)
step = 1;
break;
default: step = 0;
}
P2 = fwave[step];
// clockwise step
// counterclockwise step
return fwave[step];
}
//----------------------------------------------------------------------------// delay_ms
//----------------------------------------------------------------------------//
// an approximate x ms delay
void delay_ms(int ms)
{
int y;
int z;
for (y=1; y<=63; y++) for (z=1; z<= ms; z++);
}
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