?? control.c
字號(hào):
/*********************************************************************
*
* Project: (if you don't mind... I'll withhold the actual
* application.. Maybe you can guess..)
*
* This is a working piece of firmware used
* in an industrial application. Your application
* will be different, of course. This example may
* help in a few ways though:
* 1. I use the CCS compiler, and I use several
* of that compilers nice extensions, such
* as writing to the serial port, delays,
* bit manipulation, etc. I found the
* CCS compiler to be more than adequete
* for these PIC control applications.
* 2. The PIC communicates to an A/D chip, the
* MAXIM 192. You can copy this function.
* 3. Perhaps, this program help you size your
* application - I show the % memory
* utilization of the 16C63 I used.
* 4. I suppose you might get embedded
* programming ideas... I am a fan
* of round-robin, state-machine programming..
* Really, this is a simple program but
* the bread-n-butter of embedded control:
* monitor some sensors, look at switches,
* light some LEDs, apply a bunch of rules..
*
*
*
* Description:
* Runs on a PIC16C63, compiled with the CCS PCM compiler.
* Uses the overflow interrupt from timer1 as a timebase.
* Various debug messages are output on the serial port
* at 4800,8N and can be viewed with typical terminal
* program. Program uses a simple round-robin loop to
* monitor and handle all events and actions. Code written
* with 4MHz crystal in mind.
*
* PIC16C63 is programmed with PICSTART Plus programmer through
* through the MPLAB program. Programmer options include:
* Device = 16C63, Oscillator = XT, Watchdog = OFF, Brownout = ON,
* Code Protect = OFF, Power Up Timer = OFF.
* Normal procedure is to:
* 1) Compile with PCM in a DOS window,
* 2) In MPLAB, enable programmer and select above options,
* 3) Select File | Import and choose the .HEX file
* 4) Select Picstart Plus | Program/Verify and program part.
*
* The A/D chip used to sample analog values is the MAXIM MAX192.
*
*
* Author: Tom Coonan
* File: trash.c
* Updated: 12/14/96
* Version: 1.1
* Revisions:
* 12/10/96: - Added Self Test.
* 12/14/96: - Changed DIR_RLY polarity.
* - Changed CHARGE_MIN constant value from 839 to 800.
* - Added rule to charging that turns charger on
* when motor is running.
* - Added bMotorOn flag to help with new charger rule.
*
*
* Misc. Programming Notes:
* 1) I use a prefix notation for variables based on their type:
*
* b - boolean, will be declared as byte (8 bits)
* by - byte (8 bits)
* n - integer, declared as long ints (16 bits)
*
* Most simple counters and state variables fit into 8 bits
* and are therefore declared as byte. Only a few variables
* need the longer 16-bit length. Note what the lengths of
* types are for this compiler!
*
* 2) Chip resources used: 56% program rom, 29% data ram
*
*******************************************************************/
/*
I/O Map
Note: Currently, 'fix_io' statements are used, so we do not
have to use TRIS statements. This is OK since pins
are used as either inputs or outputs, but never change
mode.
Pin Equate I/O TRIS Bits
-----------------------------------
A7 N/C INPUT 1 TRIS Word = F0
A6 N/C INPUT 1
A5 EXTENDED INPUT 1
A4 CYCLE_SW INPUT 1
A3 MOTOR_RLY OUTPUT 0
A2 RECYCLE_RLY OUTPUT 0
A1 DIR_RLY OUTPUT 0
A0 CHARGE_RLY OUTPUT 0
B7 CHARGE_LED OUTPUT 0 TRIS Word = 03
B6 SPA_LED OUTPUT 0
B5 SERVICE_LED OUTPUT 0
B4 CYCLE1_LED OUTPUT 0
B3 CYCLE2_LED OUTPUT 0
B2 CYCLE3_LED OUTPUT 0
B1 RETRACTED INPUT 1
B0 RECYCLE_SW INPUT 1
C7 SERIAL_RX INPUT 1 TRIS Word = AC
C6 SERIAL_TX OUTPUT 0
C5 TESTJ1_7To8 INPUT 1 <--- Used to trigger Self Test
C4 ADC_CLK OUTPUT 0
C3 ADC_DOUT INPUT 1
C2 ADC_SSTRB INPUT 1
C1 ADC_DIN OUTPUT 0
C0 ADC_CS OUTPUT 0
*/
#include <16c63.h>
#fuses XT,NOPROTECT,NOWDT
/* Allows the 'delay_' functions to work correctly with our 4MHz crystal. */
#use delay(clock=4000000)
/* Tell compiler our I/O. We never change any one pin's input/output. */
#use fixed_io(a_outputs=PIN_A3,PIN_A2,PIN_A1,PIN_A0)
#use fixed_io(b_outputs=PIN_B7,PIN_B6,PIN_B5,PIN_B4,PIN_B3,PIN_B2)
#use fixed_io(c_outputs=PIN_C6,PIN_C4,PIN_C1,PIN_C0)
/* Used for debug purposes. */
#use rs232(baud=4800, xmit=PIN_C6, rcv=PIN_C7)
// Bit equates for sensors INPUTs
#define RETRACTED PIN_B1
#define EXTENDED PIN_A5
// Bit equates for Relays OUTPUTs
#define CHARGE_RLY PIN_A0
#define DIR_RLY PIN_A1
#define MOTOR_RLY PIN_A3
#define RECYCLE_RLY PIN_A2
// Bit equates for LED OUTPUTs
#define CHARGE_LED PIN_B7
#define SPA_LED PIN_B6
#define SERVICE_LED PIN_B5
// Bit equates for Switch INPUTs
#define RECYCLE_SW PIN_B0
#define CYCLE_SW PIN_A4
#define CYCLE1_LED PIN_B4
#define CYCLE2_LED PIN_B3
#define CYCLE3_LED PIN_B2
// Bit equates for A/D chip I/O
#define ADC_CS PIN_C0
#define ADC_CLK PIN_C4
#define ADC_DIN PIN_C1
#define ADC_DOUT PIN_C3
#define ADC_SSTRB PIN_C2
#define FALSE 0
#define TRUE 1
/* Voltage Equations
Due to the limited nature of PIC arithmetic, the
program logic uses the raw A/D sample values and
does not use any floating point math. Only a few
key variables are involved, therefore, all
thresholds are precomputed below and placed in
defines.
1) The A/D input accepts a 0.000V to 4.096V input
which maps to a 10 bit unsigned binary ranging
from 0x000 to 0x3FF (or, 0 to 1023).
The following equation relates the A/D voltage
input to the expected binary:
sample = 1024*(vin/4.096)
where sample is the value of the A/D number
ultimately used in the program from the A/D
(e.g. the value in nBatteryVoltage).
2) The Battery voltage is divided through a
resistor network resulting in:
vin = vbattery*0.2582
Therefore, the final equation is:
sample = 1024*(vbattery*0.2582/4.096)
3) Here is a table of voltages and samples:
Variable Voltage Sample
CHARGE_MAX 14.2 916
CHARGE_MIN 13.0 839
BATTERY_PROTECT 9.5 613
SPA_VOLTAGE 13.6 878
*/
/* What the values SHOULD be */
#define CHARGE_MAX 916
#define CHARGE_MIN 800
#define BATTERY_PROTECT 613
#define SPA_VOLTAGE 878
// Specify some hysterysis around the SPA voltage.
//
// Note: The A/D resolution is 16.0 Volts / 1024 = 15.6 mV
#define SPA_HYSTERYSIS 7
#define MAX_PENDING_CYCLES 3
/* Called on power up. */
void LampTest (void);
/* A/D driver */
long int nADSample; /* global where sample is assembled */
void GetAD (byte byChannel);
long int nBatteryVoltage; /* 16-bit integer, need for 10-bit A/D sample */
long int nAvgBatteryVoltage;
long int nBatteryVoltage_last1;
long int nBatteryVoltage_last2;
long int nBatteryVoltage_last3;
/* States and flags */
byte bCharging;
byte bEverCharged; /* Need to know if charger has ever been on */
byte byPendingCycles;
byte bMotorPaused; /* if battery volts drop below protect, pause */
byte bMotorOn;
byte bEnoughMotorJuice;
/* Service Soon flag. This gets set whenever a forward motor action
or a reverse motor action times out, or if
the battery voltage ever drops below a battery
protection voltage.
*/
byte bServiceSoon;
/* Flag is set if a forward or reverse timout has *ever* occured. */
byte bTimeoutOccured;
/* Flag is set if a battery protect voltage was ever reached. */
byte bBatteryProtect;
/* Flag is set if battery voltage has ever risen about battery protect.
This will help elliminate the service soon light coming on prematurely. */
byte bBatteryEverOK;
/* Maximum number of cycles that can be queued up. Set after reading strap */
byte byMaxCycles;
/* Primary state machine variable for the "cycle" procedure */
byte byCycleState;
/* Cycle State Machine states for variable nCycleState */
#define STATE_CYCLE_INITIAL 0
#define STATE_CYCLE_INITIAL_WAITJUICE 1
#define STATE_CYCLE_IDLE 2
#define STATE_CYCLE_CHECKJUICE 3
#define STATE_CYCLE_WAITJUICE 4
#define STATE_CYCLE_FORWARD 5
#define STATE_CYCLE_REVERSE1 6
#define STATE_CYCLE_REVERSE2 7
#define STATE_CYCLE_DONE 8
/* Number of consequitive samples of switch needed to assert switch */
#define CYCLE_SWITCH_REQUIRED_SAMPLES 50
/* Cycle switch state machine variables */
byte byCycleSwitchState;
byte bySample_CycleSwitch;
#define STATE_CYCLE_SWITCH_IDLE 0
#define STATE_CYCLE_SWITCH_SAMPLE 1
#define STATE_CYCLE_SWITCH_WAIT_RELEASE 2
/* Timer Tick Counters (used with delay define constants) */
byte byTicks_Charger_Hysterysis; /* Charger can change once per second. */
/* The delays for forward and reverse are long, so need long ints. */
long int nTicks_Reverse; /* Reverse direction timeout (long one) */
long int nTicks_Forward; /* Forward direction timeout (long one) */
long int nTicks_Paused; /* Bookmark, when we pause motor */
byte byTicks_CycleSwitch; /* Debounce for cycle switch */
byte byTicks_Delay; /* A miscellanious delay */
byte byTicks_Display; /* Last time display (e.g. RS232) */
byte byTicks_Initial_Charge; /* Brief time that Initial Charge rule applies */
/**** Delays ****/
/*
Our timing is based on the overflow of the timer1. First, here's how
we detirmine how long a "tick" is:
4MHz crystal, divided by 4 (e.g. PIC always does this) is 1MHz.
Timer 1 is a 16 bit counter. The Timer1 will be programmed to
use a DIVIDE BY 4 prescaler (see the setup_timer_1 function call).
Therefore, the number of interrupts per second is:
4,000,000 / 4 / 4 / 2^16 = 3.814... Hz
Or, 1 tick is 262ms, or roughly 1/4 second
Note: Look at the interrupt service routine to see how tick counters
are done. Basically, they are little background down counters.
*/
/* Cycle switch debounce (sort of like debounce.. see the state machine) */
#define TICKS_CYCLESWITCH 2
/* Initial charging rule is only in effect briefly after power up. */
#define TICKS_INITIAL_CHARGE 4
/* Forward direction timeout (90 seconds) */
#define TICKS_FORWARD 360
/* Reverse direction timeout (90 seconds) */
#define TICKS_REVERSE 360
/* Lamptest time duration */
#define TICKS_LAMPTEST 2
/* Minimum time between any change in charger state */
#define TICKS_CHARGER_HYST 4
/* Delay after cycle is done before direction solenoid released */
#define TICKS_CYCLE_DONEDELAY 1
/* Time period after forward-reverse changeover when sensors ignored. */
#define TICKS_IGNORE_SENSORS 4
/* Sense if the Self Test is being requested. This is done through
the RC5 input. If the switch on it is closed, this port
will read 0 which means YES run the self-test. */
int SelfTestRequested (void);
/* The self test used during manufacturing. */
void SelfTest (void);
void SelfTestFail (void); /* Called if fail.. will blink LEDs forever. */
/* Update the nBatteryVoltage variable by sampling voltage with A/D */
void GetBatteryVoltage(void);
/* Start Motor */
void StartMotor (void);
/* Stop Motor */
void StopMotor (void);
/* Forward (direction solenoid energized) */
void Forward (void);
/* Reverse (direction solenoid de-energized) */
void Reverse (void);
/* Return true if the retracted sensor is active */
int SenseRetracted (void);
/* Return true if the extended over pressure sensor is active */
int SenseExtended (void);
/* Sense if the multicycle option is enabled. This is done through
the A/D port 1. */
int MultiCyclesEnabled (void);
/* Sense if the initial retract option is enabled. This is done through
the A/D port 4. */
int InitialRetractsEnabled (void);
/* Main program and main loop */
main ()
{
/* Note: all printf calls are sent out RS232 port at 4800 baud. */
printf ("TRASH COMPACTOR V0.0\r");
/* Initially turn all relays off. */
output_low (CHARGE_RLY);
output_low (DIR_RLY);
output_low (MOTOR_RLY);
output_low (RECYCLE_RLY);
/* Initialize interface to the A/D chip. */
output_low (ADC_CLK);
output_high (ADC_CS);
/* Initialize variables */
byTicks_Charger_Hysterysis = 0;
nTicks_Reverse = 0;
nTicks_Forward = 0;
nTicks_Paused = 0;
byTicks_CycleSwitch = 0;
byTicks_Delay = 0;
byTicks_Display = 0;
byTicks_Initial_Charge = 0;
bEverCharged = FALSE;
byPendingCycles = 0;
byCycleSwitchState = 0;
byCycleState = 0;
bServiceSoon = FALSE;
bCharging = FALSE;
bMotorPaused = FALSE;
bEnoughMotorJuice = FALSE;
bTimeoutOccured = FALSE;
bBatteryProtect = FALSE;
bBatteryEverOK = FALSE;
bMotorOn = FALSE;
/* Testing! */
printf ("Sensors: ");
if (input(EXTENDED)) printf ("1");
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -