#include <avr/io.h>
#define UART0_BAUD 207 /* 2400 UART0 BAUD */
#define UART1_BAUD 51 /* 9600 UART1 BAUD */
#define EZ1_SAVES 1 /* distance measurements */
#define EZ1_ELEMENT_SIZE 3 /* 3 digit readings eg 006 */
#define RFID_SAVES 1 /* RFID tag number save once */
#define RFID_ELEMENT_SIZE 10 /* 10 digit rfid number */
void ez1_sensor_init (void);
void rfid_reader_init (void);
void bounce_meter_init (void);
void solenoid_init (void);
uint8_t serial_recv_uart0 (void);
uint8_t serial_recv_uart1 (void);
void serial_send_rfid (uint8_t rfid_read);
void serial_send_uart1 (uint8_t ez1_read);
void serial_print_char (char *);
void delay (uint16_t us);
void base_height (void);
void ez1_sensor_read (void);
void clear_lcd (void);
void long_delay (void);
void ez1_2_lcd (void);
void rfid_tag_scan (void);
uint8_t rfid_tag_check (void);
void erase_tag (void);
void rfid_2_lcd (void);
uint8_t ascii_2_digit (void);
void startup_message (void);
void trampoline_height (void);
void normalize_height (void) ;
void bounce_meter (void);
void solenoid_open (void);
int main (void);
/*
* Yucky globals...these arrays the vital information
* ez1 sensor data
* rfid tag numbers
*/
uint8_t ez1_data[EZ1_SAVES][EZ1_ELEMENT_SIZE]; /* stores trampoline distance from ground */
uint8_t base[EZ1_ELEMENT_SIZE]; /* stores trampoline initial height from ground */
uint8_t rfid_data[RFID_SAVES][RFID_ELEMENT_SIZE]; /* stores rfid tag numebr */
uint8_t height10; /* trampoline height change 10s digit */
uint8_t height10_ascii; /* trampoline height change 10s digit */
uint8_t height1; /* trampoline height change 1s digit */
uint8_t height1_ascii; /* trampoline height change 1s digit */
uint8_t jump_rating; /* jump rating 8 is highest 0 is lowest */
uint8_t jump_rating_ascii; /* jump rating 8 is highest 0 is lowest + 48 */
uint8_t bounce_led; /* LEDs to turn on based on height change */
/*
* initialize UART1
* this is used by the ultrasonic sensor
* maxbotix EZ1
*/
void ez1_sensor_init (void) {
/*
* calculating baud rate:
*
* 8MHz clock and 9600
* $ echo "8000000 / 16 / 9600 - 1" | bc
* answer: 51
*
*/
UBRR1H = (UART1_BAUD >> 8); /* high order bits */
UBRR1L = UART1_BAUD; /* low order bits */
/*
* enable uart tx and rx
* enable synchronous transfer
* databits 8
*/
UCSR1B = (1 << RXEN1) | (1 << TXEN1);
UCSR1C = (1 << UCSZ11) | (1 << UCSZ10);
return;
}
/*
* initializes UART0
* this is used by the rfid reader
* parallax $39 module made by Grand Idea Studio
*/
void rfid_reader_init (void) {
/*
* calculating baud rate:
*
* 8MHz clock and 2400bps
* $ echo "8000000 / 16 / 2400 - 1" | bc
* answer: 207
*
*/
UBRR0H = (UART0_BAUD >> 8); /* high order bits */
UBRR0L = UART0_BAUD; /* low order bits */
/*
* enable uart tx and rx
* enable synchronous transfer
* databits 8
*/
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
UCSR0C = (1 << UCSZ00) | (1 << UCSZ01);
return;
}
/*
* Enable PORTB for output
*/
void bounce_meter_init (void) {
DDRB=0xFF;
PORTB=0x00;
}
/*
* Enable PORTC for output
* Close Valve
*/
void solenoid_init (void) {
DDRC=0xFF;
PORTC=0x00;
}
/*
* Wait for a byte on the serial line and return it.
*/
uint8_t serial_recv_uart0 (void) {
while (!(UCSR0A & (1 << RXC0))); /* wait for rx char */
return UDR0; /* return the char */
}
/*
* Wait for a byte on the serial line and return it.
*/
uint8_t serial_recv_uart1 (void) {
while (!(UCSR1A & (1 << RXC1))); /* wait for rx char */
return UDR1; /* return the char */
}
/*
* Send the byte on the serial line.
*/
void serial_send_rfid (uint8_t rfid_read) {
while (!(UCSR1A & (1 << UDRE1))); /* wait for tx buffer empty */
UDR1 = rfid_read; /* send byte */
return;
}
/*
* Send the byte on the serial line.
*/
void serial_send_uart1 (uint8_t ez1_read) {
while (!(UCSR1A & (1 << UDRE1))); /* wait for tx buffer empty */
UDR1 = ez1_read; /* send byte */
return;
}
/*
* Send the buffer on the serial line.
*/
void serial_print_char (char *msg) {
while (*msg != 0)
serial_send_uart1 (*msg++);
return;
}
/*
* slow it down
*/
void delay (uint16_t us)
{
while ( us ) us--;
}
/*
* Height of trampoline from ground
* Used when circuit is first powered up
* It is important to have nobody on the trampoline
*/
void base_height (void) {
uint8_t i=0;
ez1_sensor_read();
/*
* copy first sensor reading to another array
*/
while ( i < EZ1_ELEMENT_SIZE ) {
base[i] = ez1_data[0][i];
i++;
}
}
/*
* EZ1 (Ultra Sonic Sensor)
* Reads the sensor N times (N = EZ1_SAVES)
* values are available through ez1_data array
*/
void ez1_sensor_read (void) {
uint8_t ez1_read;
uint8_t j=0;
uint8_t k=0;
ez1_read = serial_recv_uart1();
if ( ez1_read == 'R' && j <= EZ1_SAVES ) {
while ( ez1_read != '\r' ) {
ez1_read = serial_recv_uart1();
/*
* Confirm that sensor has put out a ascii value
* between 0 and 9. Otherwise play the recursive
* game.
*/
if ( ez1_read >= 48 || ez1_read <= 57 ) {
ez1_data[j][k] = ez1_read;
k++;
} else {
ez1_sensor_read();
}
}
k=0;
j++;
} else {
ez1_sensor_read();
}
return;
}
/*
* Clear LCD
*/
void clear_lcd (void) {
delay(8000);
serial_send_uart1(254);
serial_send_uart1(0x01);
}
/*
* longer delay
*/
void long_delay (void) {
uint8_t i=0;
while ( i < 30 ) {
delay(65000);
i++;
}
}
/*
* display ultra sonic sensor (EZ1) data on LCD
*/
void ez1_2_lcd (void) {
uint8_t i=0;
/*
* Base distance will mostly be 19"
*/
while ( i < EZ1_ELEMENT_SIZE ) {
serial_send_uart1(base[i]);
i++;
}
i=0;
serial_send_uart1(' ');
/*
* Current Reading can be as large as 13"
*/
while ( i < EZ1_ELEMENT_SIZE ) {
serial_send_uart1(ez1_data[0][i]);
i++;
}
/*
* Subtracted value of current reading from base reading
*/
serial_send_uart1(' ');
serial_send_uart1('0');
serial_send_uart1(height10_ascii);
serial_send_uart1(height1_ascii);
/*
* Jump Rating 0-8 are elgible values
* This number determines how long the
* lp-gas valve will be open.
*/
serial_send_uart1(' ');
serial_send_uart1(jump_rating_ascii);
return;
}
/*
* read rfid tag number with parallax
* device made by Grand Idea Studio
*/
void rfid_tag_scan (void) {
uint8_t rfid_read='n';
uint8_t j=0;
uint8_t k=0;
/*
* Bounce Meter used to flash every other LED
* indicating it is time to scan a RFID tag.
*/
while ( rfid_read == 'z' ) {
rfid_read = serial_recv_uart0();
PORTB=0x55;
delay(65000);
PORTB=0xAA;
delay(65000);
}
if ( rfid_read == '\n' && j <= RFID_SAVES ) {
while ( rfid_read != '\r' && k < RFID_ELEMENT_SIZE ) {
rfid_read = serial_recv_uart0();
rfid_data[j][k] = rfid_read;
k++;
}
}
k=0;
j++;
return;
}
/*
* compare rfid tag read with approved tag list
* do not proceed if tag fails to match
*/
uint8_t rfid_tag_check (void) {
uint8_t j=0;
uint8_t k=0;
/* removed to protect the innocent in on-line code example */
uint8_t tags[][RFID_ELEMENT_SIZE] = {
{'0','0','0','0','0','0','0','0','0','0'},
{'0','0','0','0','0','0','0','0','0','0'},
{'0','4','0','0','0','0','0','0','0','0'},
};
clear_lcd();
serial_print_char("Confirming Tag");
while ( j < 3 ) {
while ( k < RFID_ELEMENT_SIZE ) {
if ( tags[j][k] == rfid_data[0][k] ) {
k++; /* See if each number matches */
} else {
j++; /* Check next tag for match */
k=0;
}
}
/*
* We have a tag match
*/
if ( k > 8 ) {
clear_lcd();
serial_print_char("Valid Tag Found ");
rfid_2_lcd(); /* Show RFID tag number on LCD */
long_delay(); /* Leave Tag up long enough to see */
erase_tag(); /* Prevent auto-startup on system reboot */
return(1);
}
}
return(0);
}
/*
* Erase RFID tag number that was scanned to enable trampoline
* This prevents the system from autostarting up
*/
void erase_tag (void) {
uint8_t i=0;
while ( i < RFID_ELEMENT_SIZE ) {
rfid_data[0][i] = 0;
i++;
}
}
/*
* display RFID tag number on LCD
* note: I am using the TX line on UART1
* for the LCD
*/
void rfid_2_lcd (void) {
uint8_t i=0;
while ( i < RFID_ELEMENT_SIZE ) {
serial_send_rfid(rfid_data[0][i]);
i++;
}
i=0;
return;
}
/*
* Simple solution to Convert seperate digits
* into one whole number.
*/
uint8_t ascii_2_digit (void) {
uint8_t ez1_num;
ez1_num = ez1_data[0][2];
ez1_num += ez1_data[0][1] * 10;
ez1_num += ez1_data[0][0] * 100;
return ez1_num;
}
/*
* LCD startup message
*/
void startup_message (void) {
clear_lcd(); /* blank LCD screen */
serial_print_char("The High-Lighter");
serial_print_char(" ");
serial_print_char("Please, scan");
serial_print_char(" ");
serial_print_char("your RFID tag.");
return;
}
/*
* trampoline height measurements
* measures distance from EZ1 sensor to trampoline bottom
* used for bounce meter and solenoid valve open duration
*/
void trampoline_height (void) {
uint8_t b; /* base height */
uint8_t c; /* current height */
uint8_t reduce=0; /* subtract 10s column */
uint8_t add=0; /* increase 1s column */
/*
* 1's digit
* adding +48 to get us to ascii numeric 0
* some subtraction code for small base 1s digits
*/
b = base[2];
c = ez1_data[0][2];
if ( b < c ) {
reduce = 1;
add = 10;
}
height1 = b - c + add;
height1_ascii = height1 + 48;
/*
* 10's digit of height
* adding +48 to get us to ascii numeric 0
*/
b = base[1];
c = ez1_data[0][1];
/*
* If the current reading is greater than the base
* we have a problem. We need to reset the base
* to the current.
*/
if ( c > b || b >= '3' ) {
base_height();
}
height10 = b - c - reduce;
height10_ascii = height10 + 48;
/*
* 100s digit
* Since this is a short range application we need to prevent
* readings like 255 so I am resetting the base to current if
* its value is not equal to zero.
*/
b = base[0];
if ( b != '0' ) {
base_height();
}
return;
}
/*
* Look at height change vs. base value
* give a rating of 0 (minimal change) and 7 (significant change)
*/
void normalize_height (void) {
if ( height10 > 1 ) {
jump_rating = 0; /* 20" or more height change */
bounce_led = 0x00; /* Do nothing! */
} else if ( height10 == 1 && height1 >= 6 ) {
jump_rating = 8; /* 16" - 19" height change */
bounce_led = 0xFF; /* LEDs to illiuminate on PCB */
} else if ( height10 == 1 && ( height1 == 4 || height1 == 5 ) ) {
jump_rating = 7; /* 14" - 16" height change */
bounce_led = 0xFE; /* LEDs to illiuminate on PCB */
} else if ( height10 == 1 && ( height1 == 2 || height1 == 3 ) ) {
jump_rating = 6; /* 12" - 13" height change */
bounce_led = 0xFC; /* LEDs to illiuminate on PCB */
} else if ( height10 == 1 && ( height1 == 0 || height1 == 1 ) ) {
jump_rating = 5; /* 10" - 12" height change */
bounce_led = 0xF8; /* LEDs to illiuminate on PCB */
} else if ( height10 == 0 && ( height1 == 8 || height1 == 9 ) ) {
jump_rating = 4; /* 8" - 9" height change */
bounce_led = 0xF0; /* LEDs to illiuminate on PCB */
} else if ( height10 == 0 && ( height1 == 6 || height1 == 7 ) ) {
jump_rating = 3; /* 6" - 7" height change */
bounce_led = 0xE0; /* LEDs to illiuminate on PCB */
} else if ( height10 == 0 && ( height1 == 4 || height1 == 5 ) ) {
jump_rating = 2; /* 4" - 5" height change */
bounce_led = 0xC0; /* LEDs to illiuminate on PCB */
} else if ( height10 == 0 && ( height1 == 3 ) ) {
jump_rating = 1; /* 3" height change */
bounce_led = 0x80; /* LEDs to illiuminate on PCB */
} else {
jump_rating = 0;
bounce_led = 0x00;
}
jump_rating_ascii = jump_rating + 48; /* Add 48 to get a ascii value for jump rating */
return;
}
/*
* bounce meter
* display normalized bounce height on LEDs
*/
void bounce_meter (void) {
PORTB = bounce_led;
return;
}
/*
* open solenoid valve based on normalized height
* aka. jump_rating which will be a multiplier of
* up to 8
*/
void solenoid_open (void) {
uint16_t valve_base=32500;
uint16_t valve_multiplier=4062;
uint16_t valve_max=65000;
uint16_t duration = 0;
PORTC=0x00; /* Close Valve */
/*
* length of time to keep valve open
*/
if ( jump_rating > 0 ) {
duration = jump_rating * valve_multiplier;
duration += valve_base;
}
if ( duration <= valve_max ) {
PORTC=0x01; /* Open Valve */
delay(duration); /* Wait a short period of time */
PORTC=0x00; /* Close Valve */
} else {
return;
}
return;
}
int main() {
uint8_t valid_tag = 0; /* Flag to confirm that a valid tag is present */
/*
* Initialize IO devices
* EZ1 - ultrasonic sensor measure distance
* RFID READER - lock, requires TAG to engage program
* Bounce Meter - LED display of normaized distance measurements
*/
ez1_sensor_init();
rfid_reader_init();
bounce_meter_init();
solenoid_init();
startup_message(); /* initial LCD message when powered up */
/*
* Initial height from sensor to trampoline
*/
base_height();
while(1) {
ez1_sensor_read(); /* take sensor read */
trampoline_height(); /* distance between sensor and trampoline */
normalize_height(); /* decide on scale of 0-7 about height change */
bounce_meter(); /* Visual Height indicator */
clear_lcd(); /* blank LCD screen */
ez1_2_lcd(); /* send sensor read to LCD */
if ( valid_tag ) {
solenoid_open(); /* solenoid open */
} else {
rfid_tag_scan(); /* scan rfid tag */
valid_tag = rfid_tag_check(); /* confirm that tag is valid */
}
}
return 0;
}