338 lines
6.2 KiB
C
338 lines
6.2 KiB
C
/*
|
|
* ladder.c:
|
|
*
|
|
* Gordon Henderson, June 2012
|
|
***********************************************************************
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <math.h>
|
|
|
|
#include <wiringPi.h>
|
|
#include <piFace.h>
|
|
|
|
#ifndef TRUE
|
|
# define TRUE (1==1)
|
|
# define FALSE (1==2)
|
|
#endif
|
|
|
|
#undef DEBUG
|
|
|
|
#define NUM_LEDS 8
|
|
|
|
|
|
// Map the LEDs to the hardware pins
|
|
// using PiFace pin numbers here
|
|
|
|
#define PIFACE 200
|
|
|
|
const int ledMap [NUM_LEDS] =
|
|
{
|
|
// 0, 1, 2, 3, 4, 5, 6, 7, 8
|
|
200, 201, 202, 203, 204, 205, 206, 207
|
|
} ;
|
|
|
|
|
|
// Some constants for our circuit simulation
|
|
|
|
const double vBatt = 9.0 ; // Volts (ie. a PP3)
|
|
const double capacitor = 0.001 ; // 1000uF
|
|
const double rCharge = 2200.0 ; // ohms
|
|
const double rDischarge = 68000.0 ; // ohms
|
|
const double timeInc = 0.01 ; // Seconds
|
|
|
|
double vCharge, vCap, vCapLast ;
|
|
|
|
|
|
|
|
/*
|
|
* setup:
|
|
* Program the GPIO correctly and initialise the lamps
|
|
***********************************************************************
|
|
*/
|
|
|
|
void setup (void)
|
|
{
|
|
int i ;
|
|
|
|
wiringPiSetupSys () ;
|
|
|
|
if (piFaceSetup (200) == -1)
|
|
exit (1) ;
|
|
|
|
// Enable internal pull-ups
|
|
|
|
for (i = 0 ; i < 8 ; ++i)
|
|
pullUpDnControl (PIFACE + i, PUD_UP) ;
|
|
|
|
// Calculate the actual charging voltage - standard calculation of
|
|
// vCharge = r2 / (r1 + r2) * vBatt
|
|
//
|
|
//
|
|
// -----+--- vBatt
|
|
// |
|
|
// R1
|
|
// |
|
|
// +---+---- vCharge
|
|
// | |
|
|
// R2 C
|
|
// | |
|
|
// -----+---+-----
|
|
|
|
vCharge = rDischarge / (rCharge + rDischarge) * vBatt ;
|
|
|
|
// Start with no charge
|
|
|
|
vCap = vCapLast = 0.0 ;
|
|
}
|
|
|
|
|
|
/*
|
|
* introLeds
|
|
* Put a little pattern on the LEDs to start with
|
|
*********************************************************************************
|
|
*/
|
|
|
|
void introLeds (void)
|
|
{
|
|
int i, j ;
|
|
|
|
|
|
printf ("Pi Ladder\n") ;
|
|
printf ("=========\n\n") ;
|
|
printf (" vBatt: %6.2f volts\n", vBatt) ;
|
|
printf (" rCharge: %6.0f ohms\n", rCharge) ;
|
|
printf (" rDischarge: %6.0f ohms\n", rDischarge) ;
|
|
printf (" vCharge: %6.2f volts\n", vCharge) ;
|
|
printf (" capacitor: %6.0f uF\n", capacitor * 1000.0) ;
|
|
|
|
// Flash 3 times:
|
|
|
|
for (j = 0 ; j < 3 ; ++j)
|
|
{
|
|
for (i = 0 ; i < NUM_LEDS ; ++i)
|
|
digitalWrite (ledMap [i], 1) ;
|
|
delay (500) ;
|
|
for (i = 0 ; i < NUM_LEDS ; ++i)
|
|
digitalWrite (ledMap [i], 0) ;
|
|
delay (100) ;
|
|
}
|
|
|
|
// All On
|
|
|
|
for (i = 0 ; i < NUM_LEDS ; ++i)
|
|
digitalWrite (ledMap [i], 1) ;
|
|
delay (500) ;
|
|
|
|
// Countdown...
|
|
|
|
for (i = NUM_LEDS - 1 ; i >= 0 ; --i)
|
|
{
|
|
digitalWrite (ledMap [i], 0) ;
|
|
delay (100) ;
|
|
}
|
|
delay (500) ;
|
|
}
|
|
|
|
|
|
/*
|
|
* winningLeds
|
|
* Put a little pattern on the LEDs to start with
|
|
*********************************************************************************
|
|
*/
|
|
|
|
void winningLeds (void)
|
|
{
|
|
int i, j ;
|
|
|
|
// Flash 3 times:
|
|
|
|
for (j = 0 ; j < 3 ; ++j)
|
|
{
|
|
for (i = 0 ; i < NUM_LEDS ; ++i)
|
|
digitalWrite (ledMap [i], 1) ;
|
|
delay (500) ;
|
|
for (i = 0 ; i < NUM_LEDS ; ++i)
|
|
digitalWrite (ledMap [i], 0) ;
|
|
delay (100) ;
|
|
}
|
|
|
|
// All On
|
|
|
|
for (i = 0 ; i < NUM_LEDS ; ++i)
|
|
digitalWrite (ledMap [i], 1) ;
|
|
delay (500) ;
|
|
|
|
// Countup...
|
|
|
|
for (i = 0 ; i < NUM_LEDS ; ++i)
|
|
{
|
|
digitalWrite (ledMap [i], 0) ;
|
|
delay (100) ;
|
|
}
|
|
delay (500) ;
|
|
}
|
|
|
|
|
|
/*
|
|
* chargeCapacitor: dischargeCapacitor:
|
|
* Add or remove charge to the capacitor.
|
|
* Standard capacitor formulae.
|
|
*********************************************************************************
|
|
*/
|
|
|
|
void chargeCapacitor (void)
|
|
{
|
|
vCap = (vCapLast - vCharge) *
|
|
exp (- timeInc / (rCharge * capacitor)) + vCharge ;
|
|
|
|
#ifdef DEBUG
|
|
printf ("+vCap: %7.4f\n", vCap) ;
|
|
#endif
|
|
|
|
vCapLast = vCap ;
|
|
}
|
|
|
|
void dischargeCapacitor (void)
|
|
{
|
|
vCap = vCapLast *
|
|
exp (- timeInc / (rDischarge * capacitor)) ;
|
|
|
|
#ifdef DEBUG
|
|
printf ("-vCap: %7.4f\n", vCap) ;
|
|
#endif
|
|
|
|
vCapLast = vCap ;
|
|
}
|
|
|
|
|
|
/*
|
|
* ledBargraph:
|
|
* Output the supplied number as a bargraph on the LEDs
|
|
*********************************************************************************
|
|
*/
|
|
|
|
void ledBargraph (double value, int topLedOn)
|
|
{
|
|
int topLed = (int)floor (value / vCharge * (double)NUM_LEDS) + 1 ;
|
|
int i ;
|
|
|
|
if (topLed > NUM_LEDS)
|
|
topLed = NUM_LEDS ;
|
|
|
|
if (!topLedOn)
|
|
--topLed ;
|
|
|
|
for (i = 0 ; i < topLed ; ++i)
|
|
digitalWrite (ledMap [i], 1) ;
|
|
|
|
for (i = topLed ; i < NUM_LEDS ; ++i)
|
|
digitalWrite (ledMap [i], 0) ;
|
|
}
|
|
|
|
|
|
/*
|
|
* ledOnAction:
|
|
* Make sure the leading LED is on and check the button
|
|
*********************************************************************************
|
|
*/
|
|
|
|
void ledOnAction (void)
|
|
{
|
|
if (digitalRead (PIFACE) == LOW)
|
|
{
|
|
chargeCapacitor () ;
|
|
ledBargraph (vCap, TRUE) ;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ledOffAction:
|
|
* Make sure the leading LED is off and check the button
|
|
*********************************************************************************
|
|
*/
|
|
|
|
void ledOffAction (void)
|
|
{
|
|
dischargeCapacitor () ;
|
|
|
|
// Are we still pushing the button?
|
|
|
|
if (digitalRead (PIFACE) == LOW)
|
|
{
|
|
vCap = vCapLast = 0.0 ;
|
|
ledBargraph (vCap, FALSE) ;
|
|
|
|
// Wait until we release the button
|
|
|
|
while (digitalRead (PIFACE) == LOW)
|
|
delay (10) ;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
***********************************************************************
|
|
* The main program
|
|
***********************************************************************
|
|
*/
|
|
|
|
int main (void)
|
|
{
|
|
unsigned int then, ledOnTime, ledOffTime ;
|
|
unsigned int ourDelay = (int)(1000.0 * timeInc) ;
|
|
|
|
setup () ;
|
|
introLeds () ;
|
|
|
|
// Setup the LED times - TODO reduce the ON time as the game progresses
|
|
|
|
ledOnTime = 1000 ;
|
|
ledOffTime = 1000 ;
|
|
|
|
// This is our Gate/Squarewave loop
|
|
|
|
for (;;)
|
|
{
|
|
|
|
// LED ON:
|
|
|
|
(void)ledBargraph (vCap, TRUE) ;
|
|
then = millis () + ledOnTime ;
|
|
while (millis () < then)
|
|
{
|
|
ledOnAction () ;
|
|
delay (ourDelay) ;
|
|
}
|
|
|
|
// Have we won yet?
|
|
// We need vCap to be in the top NUM_LEDS of the vCharge
|
|
|
|
if (vCap > ((double)(NUM_LEDS - 1) / (double)NUM_LEDS * vCharge)) // Woo hoo!
|
|
{
|
|
winningLeds () ;
|
|
while (digitalRead (PIFACE) == HIGH)
|
|
delay (10) ;
|
|
while (digitalRead (PIFACE) == LOW)
|
|
delay (10) ;
|
|
vCap = vCapLast = 0.0 ;
|
|
}
|
|
|
|
// LED OFF:
|
|
|
|
(void)ledBargraph (vCap, FALSE) ;
|
|
then = millis () + ledOffTime ;
|
|
while (millis () < then)
|
|
{
|
|
ledOffAction () ;
|
|
delay (ourDelay) ;
|
|
}
|
|
|
|
}
|
|
|
|
return 0 ;
|
|
}
|