Shark Tag Microcontroller
Platform
Erik
Dawe
ed267
Introduction
This
goal of this project was to develop a working bench-top microcontroller
platform for a shark tag. It is to be used for on-animal, in-situ data logging
applications involving sharks and potentially other large pelagics.
For
this project I used the Atmel Mega32 microcontroller to develop the core
platform and functionality of a data archival tag. The tasks ranged from
logging sensor data to developing a simple user interface that requires only
the addition of a laptop and a custom RS232 serial cable in the field. I used
an off-the-shelve SD (Secure Digital) card using flash memory for large
capacity multi-read/write data storage. The microcontrollerÕs ADCs (analog to
digital converters) were used to convert analog voltages produced by select
sensors into digital format. These digital sensor values are then sent to the
SD card by the microcontroller for storage using a rudimentary SPI (Serial
Peripheral Interface) communication protocol. The user is able to download the
recorded data from the tag to a computer via an RS232 serial link using hyperterminal or the serial communication utility of their
choice. This data is recalled from flash by the tag and sent to hyperterminal in a 1 x n matrix that is easily parsed in MATLab. In essence, my tag platform is a data logger with a
simple interface that allows the user to prepare it for deployment and to
download data upon recovery.
Ultimately, this tag is a tool to be used by scientists, engineers, or
any variety of field technician.
Rationale
When I was seven my grandfather gave me a National Geographic VHS
on sharks. Since then I have harbored a mild obsession with sharks and
strove to learn all that I can about these fascinating yet poorly understood
creatures of the ocean. My interest
has matured into a desire to build tools for helping scientists to better study
these animals. Building my own shark tag is the consummate dovetailing of my
interests in engineering and sharks. As this is a microprocessor design course,
the focus of this project is on the design of a microprocessor based tag
platform that can be developed into an ocean ready tag at a later date.
Being
an engineer and having had the opportunity to work with sharks and whales in a
scientific capacity, I developed a strong interest in the engineering of
technology used to humanely study ocean life. The purpose of tagging an animal
in the wild is to collect data for the purposes of biology, ecology, or
conservation that cannot be made by direct observation. I have some specific
ideas on improving current methods and science, and feel developing my own tag
via the ECE 476 final project was a great place to get started.
Logical Structure/Function
This
project is a mlange of work done in hardware and software. The main functional
elements of this project are the logging of sensor data to flash memory, and
the user interface. The logging and storage of data must be robust, and the
user interface must be simple, easy to understand, and prevent the user from
doing something they donÕt want to do (like accidentally erasing data from a
tag before it has been downloaded). The data logging aspect has three main
components: the sensors, the analog to digital converter (ADC), and the flash
memory. The user interface is primarily a menu system accessed via hyperterminal that allows the user to prepare the tag for
deployment and to download data acquired during a deployment.
A
sensor on the tag works by measuring some environmental property and producing
a calibrated analog voltage that is correlated to the actual property under
measurement (pressure, temperature, etc). My tag platform can work with any
sensor that has an analog or digital output within the range of 0-5V. A temperature and pressure sensor were used for this
project. However, for this stage of development, my sensor choice was really
immaterial and more to illustrate overall platform functionality. One of the
ideas is to make a portable platform that can be adapted for whatever sensor a
scientist has an interest in using. Any sensor actually used in a tag must be
seriously vetted for hydrostatic pressure compliance as animals tagged in the
ocean can at times dive to significant depths that cause certain components to
fail. This type of evaluation takes weeks of pressure cycling components under
load, not to mention a pressure test facility.
Continuing
on, the analog voltages produced by the sensors are read by the ADC and
converted to either an 8 or 10 bit (depending on the needed resolution) digital
value. The Mega32 sports eight 10bit ADCs, three of which were used for this
project. Once a digital voltage is acquired, it is stored in a 512 byte data
buffer on the microcontroller. When the buffer is full, its contents are
written to memory and the buffer is cleared and filled up again with sensor
data. This continues ad infinitum until the data logging mode of the tag is
arrested by an LOW command on the RESET pin. For storage I used flash memory in
the form of a SD/MMC card. While these cards have a sophisticated data
communication protocol that allows them to be used by high-tech electronics
such a digital cameras and computers, they also support a simple SPI protocol
that is used by many microcontrollers including the Mega32. The memory
architecture of an SD card is divided into groups, which are divided into
sectors, which are divided into blocks composed of 512 bytes. The nature of
these cards is such that memory must be written in discrete 512 byte/block
chunks. Any data sent outside of a 512 byte block will no be saved and will
cause an error in the write command. All information relating to memory
allocation or user defined settings are stored in the Mega32Õs EEPROM, and
neither settings nor data is lost when the tag is powered down.
The
user interface is essential a menu system that is displayed on a computer
screen via a RS232 serial connection and serial communication terminal of
preference. It comes up each time the tag is power-up or reset. This includes
post deployment power up. Care was taken into providing a forgiving environment
that permits the entering of spurious text submissions. The user simply enters
the listing/function of the menu that they are interested in, and navigates as
prompted by the menu. A picture of the menu can be seen below in Figure 1.
The
tag will not record data until it is armed. Once it is armed, it will wait for
a saltwater switch to sense that it is in the water (and ideally on an animal).
The tag has a blinking LED that indicates that it is in fact armed and waiting
to go in the water. When the saltwater switch is tripped, this LED will stop
blinking and another LED will blink to indicate that it has entered data
logging mode and exited the mode where it is simply armed and waiting. It will then commence logging sensor
data. Data logging will continue on until arrested by a reset command, sent by
asserting LOW on the RESET pin.
As
this is a data archival tag, the tag will need to be recovered in order to retrieve
data. Thus, the tag will need some means of releasing from its attachment to
the animal. The only tried and tested way of doing releases in the ocean is by
using Nichrome burn wire releases. These work by
putting a potential across a Nichrome wire in
saltwater. The sea water acts as a conductor, and current flows through the NaCl ions in the sea water from the Nichrome
wire to an anode. In the process, the Nichrome wire
dissolves away. In the menu the user will set the deployment/release time. The tag
will not begin counting down to release time until the saltwater switch is
tripped and it begins logging data. Upon this time, a voltage will be applied
to the Nichrome wire. The tag will not begin counting
down to release time until the saltwater switch is tripped.
Once
the tag is recovered, the user will exit data logging mode by means of a RESET.
This can be done in the field with a 9V battery and two leads connecting to the
RESET pin and a ground pin. Once a serial communication application is open,
the user can check that data was logged to memory by querying the tag with a #
command from the main menu prompt. The user can then read and download the data
from the tag via a read command. The data can be logged directly to a text file
and imported to MATLab for parsing and post
processing.
Hardware
Figure 2.
As
this project is an element of a larger project which I will hopefully finish
developing and actually deploy, in light of the time limitations placed on this
project, no efforts were made to package the hardware. Having had experience
designing tags from a mechanical end, two of the biggest considerations are
size and weight. To achieve satisfactory results for either of these involved
numerous trade-offs whose consequences endure and hence require debated and
thoughtful consideration. Thus, all hardware was left in a form most conducive
to prototyping and modification. An STK500 board was used for ease in
programming the Mega32 and for accessing ports for prototyping. A breadboard
was used for constructing and prototyping the circuits for the sensors and the
SD card. A nice SD card prototyping breakout board bought from www.Sparkfun.com.
All other component were available in the ECE 476 lab.
The general setup can be seen below in Figure 2.
Figure 3.
The SD card used requires a 2.7-3.6V supply
voltage, and so for convenience an external 3.2 volt regulator was used. The SD
card also uses Low Voltage logic levels. As the Mega32 outputs standard 5V TTL logic
levels, these levels needed to be regulated down to not damage the SD card.
This was done by constructing a simple two diode and
one resistor voltage regulator consisting of two forward biased diodes in
series that can be seen in Figure 2 and Figure 3. This was done for the Data
In, CLK, and Chip Select SPI lines going to the SD card. Although the SD card
Data Out line is at a lower voltage level, it was not stepped up as its logical
high output is still well within the range of a 5V TTL signal. However, in a
final version it may be prudent to step it up as an increased signal will yield
a better signal to noise ratio. However, all of this level adjusting could be
eliminated by using a Mega32L, which runs half as fast (8MHz) as a Mega32 and
has Low Voltage level logic and power requirements. This will almost surely be
done as it simplifies design and consumes less power, something critical in tag
design. Further, we donÕt need to sample data that fast and 16MHz is overkill.
See Figure 3. for the interface and connections
between the Mega32 and the SD card.
The
sensors used where an LM34 temperature sensor, and a Freescale
MPXM2010GS pressure sensor found kicking around the lab. There accompanying
circuitry was trivial. A non-inverting operational amplifier with a gain of 2
was used for the temperature sensor. As mentioned above, these sensors served
as stand-ins for future and undoubtedly more expensive sensors yet to be
determined and vetted.
Software
There are two main aspects of
software design for the tag. One is the menu system and user serial I/0 interface, and the other are the functions used for tag
operation, data logging, and talking to the SD card. All code was embedded C
code written and compiled in the CodeVision
programming environment. Hyperterminal was used to
read out the serial line. It was set for 9600 baud, 8 data bits, no parity, 1
stop bit, and no flow control.
The menu has a forgiving interface
that allows for erasing mistyped characters and writes like a normal text
editor, unlike the standard serial Hyperterminal
interface which requires hitting enter and going to the next line to reenter a
mistyped key. It runs a transmitting and received function called tx_rx_loop()
which is interrupt driven and fires every time Timer0 overflows, updating the
screen with the current buffer values. As Timer0 is an 8bit timer, this occurs
every 16e6MHz/256=62500Hz. The menu system is driven by a function called menu() which calls tx_rx_loop()
and accepts user input. The user input is sent to a buffer called linein[]
and is handled accordingly. The menu itself is essentially a giant case
statement/state machine that depending on the user input allows for different
functionality. Each case looks simply for the first letter in the buffer linein[],
so if a command is typed incorrectly, it still takes the user to the correct
destination provide the first letter was correct. This means a lazy person
could simply type the first letter of each command to navigate through the
menu. The menu allows for arming the tag, downloading data, checking number of
full memory blocks, and interrogating the SD card by calling function defined
elsewhere in the program designed for specific tasks. Once the called function
performs its duty, it is exited and the program returns to the case statement,
and thus the main menu prompt. To let the user know that the tag is in fact
armed while in menu browsing mode, once armed, the text entered by the user
will be sandwiched by right pointing arrows. Once the menu is exited, a
flashing LED will continue to let the user know the tag is armed and waiting
for deployment and the saltwater switch to be tripped.
The other software for the Mega32
runs the data logging functions and allows for communication with the SD card.
This was the most challenging code to write, and despite looking at several
examples for similar SPI communication with an SD card, in the end I used such
code as a guide and wrote my own. This was the only way to really know what was
going on and the only way I was able to get things to work. While all of the
functions are important, the most critical first function to get working was a
function to initialize the SD card into SPI mode. Doing this correctly required
understand the default behavior of the SD card and what is needed to exit this default
behavior. In doing this I became intimately family with the SANDISK SD card
data sheet. The
SPI mode of operation is simple and utilizes only a CLK, chip select (CS), and
Data In and Data Out line for communication and data transfer; a subset of the
standard SD card data lines. The SPI communication lines were initialized in
software by setting B.4 for CS, B.5 for MOSI, B.6 for MISO, and B.7 of the CLK.
Also critical is setting up the SPI configuration register where SPCR =
0b01011110 and SPSR = 1.
When powered up, the SD card starts
up not in SPI mode but in its normal mode of operation known as bus mode. The SD Card is based on commands and data
bit-streams that are initiated by a start bit and terminated by a stop bit. The
SPI channel is byte oriented. Every command (sent or received) or data block is
built of eight bit bytes and is byte aligned (multiples of eight clocks) to the
CS signal. Like the SD Bus protocol, the SPI messages are built from command,
response and data-block tokens. Commands like read and write have data
transfers associated with them that are sent via tokens that are transmitted
MSB first. Upon power up, to enter SPI mode, the CS signal must be asserted
negative during the reception of the reset command, CMD0. This is needed to
disable what is known as a Cyclic Redundancy Check (CRC) which is
intended to protect the SD Card commands, responses and data transfer against
transmission errors on the SD Card bus. One CRC is generated for each unique
command and is checked for every response on the CMD line. A CRC mismatch
forces an error and nullifies any command sent. For data blocks, a CRC is
generated for each data line per transferred block. It is necessary to disable
CRC checking to enter SPI mode. Since the card powers up in SD Bus mode, one
command must be send in this mode, thus CMD0 must be followed by a valid CRC
byte or it wonÕt be recognized. Although the card is in bus mode, when starting
up and only when starting up the reset command can be sent using SPI. The
default command structure/protocol for SPI mode is such that the CRC checking is disabled. To
get here we must send a valid CRC command that tells the SD card to disable CRC
until further notice and enter SPI mode. The reset command, CMD0, always
generates the same 7 bit CRC of 4A(hex). Adding an end
bit Ņ1Ó (basically a bit0 from bit7 making a full byte) creates a complete CRC
byte of 95(hex). The complete CMD0 sequence appears as 40 00 00 00 00
95 (hex). Once this command is received, the SD card ignores all new CRC bits and
is effectively in SPI mode. Once in SPI mode the card will respond with the SPI
R1 response. Reception and examination of this response is critical to knowing
if the card is ready and doing what you think it is doing. It sends a unique
response for each command. Once in SPI mode, all the communication
between host (Mega32) and SD is controlled by the host/master. The host starts
every bus transaction by asserting the CS signal low. It should be noted and
obvious that every time the card is power cycled, the SD cad must be
reinitialized to reenter SPI mode.
While
all the SD Card commands are available in SPI mode, utilizing them proved
difficult. I believe this was due to timing issues relating to the sending and
receiving of data tokens for different commands which I did not fully
understand despite my best attempts. I was able to get the single block write
command (CMD24) and the single block read command (CMD17) to work in functions
for reading and writing data from the SD card. While there are multiple block
read and write commands, there implementation was nontrivial. I thus
implemented the single block commands multiple times to satisfactory results.
Worth noting when looking at the code was the sending of multiple dummy bytes spi(0xFF)
to the SD card. This was suggested by a TA who used an SD card to store data in
a project the previous year. This, along with strategic delays inserted in the
code (whose locations were found by trial and error and dumb luck) to allow
time for the SD card to talk back to the microcontroller,r led to reliable code which has yet to hiccup. It
should be noted that the SPI clock must be kept under 400KHz during
initialization of the SD card. Afterwards, it can be raised to as high as
32MHz.
All
of the data reading and writing, both to the internal buffer and to the SD card
is driven by a Timer1 compare match interrupt. Timer1 is run with a clock
division of divide by 64, which yields a frequency of 250KHz. This is then set
to a compare match interrupt set to 249, which yields an interrupt every
millisecond. This serves as the general time base for all data logging
operations and runs the read and write functions as well as the countdown timer
for the Nichrome wire release. This time base can
easily be set higher or lower if a faster sampling sensor, such as audio or
heart rate, is added. Driving the sampling this ways allows for the option of
sample different sensors at different rates.
Problems
The
biggest obstacle in completing this project was figuring out how to reliably
talk to the SD card. After several full days of fibrillating and a little but
of dumb luck I was able to figure things out.
Relevant Standards
For
my project I programmed in ANSI C in the Code Vision Environment. I also used
an RS232 serial communication to talk to Hyerterminal
and to download data from the tag to a text file.
Social Impact/Ethical
Considerations
The
social impact of my project is relatively small. This project will eventually
lead to the full development of an ocean ready/deployable shark tag. While
there are great efforts made in the humane deployment of tags for cetaceans
(mainly because most of the animals are either threatened or endangered),
sharks and large pelagics get less humane treatment.
I hope to change that by making more humane tags that also gather more
scientifically significant data. I am concurrently working on a heart rate
sensor for a whale for my M.Eng Project which will be
able to be adapted for a shark. I plan to make my tags as non-invasive as
possible and to gather better data, but for shorter periods of time, thus
reducing the amount the tagged animal is molested.
Safety
This
project had no real safety concerns. There is no wireless and thus no
chance to cause interference with other projects.
Results
Upon
completion of this project I was able to log data from sensors to a large
memory storage device, which could then downloaded for
post processing and analysis. The data was accurately stored and I was able to
sample and store all data within reasonable data sampling limits. This platform
is now ready to be fitted with properly vetted sensors, packaged, and tested.
The biggest question is whether the Mega32 will survive pressure testing.
However, having pressure tested other microchips, I am optimistic of it chances
as proving idoneous.
Conclusion
I
was able to achieve all of the functionality I had set out to achieve for this
project. I was able to successfully create a microcontroller platform that logs
data from sensors and stores it in a large memory device. I was also able to write
into the code practical functionality for the final tag such as channels that
read a saltwater switch and start data logging, and flashes LEDÕs to indicate
to the user in the field what the tag is doing. I was also able to allow the
user to set a release time based on the time of deployment, independent of the
time when the tag is armed.
Appendix: Acknowledgements,
References, Materials, Source Code
I
would like to thank instructor Bruce Land and TAs Rob, Chris, and Adrian for
their support throughout the semester; Jason my old labmate
for helping me when I got lost programming; Al Bradely
for inspiring me to learn about electronics; Mark Johnson and Tom Hurst for
teaching me about engineering tags, inspiring my design, and sending me whale
tagging; Barbara Block for her support in my pursuit of building shark tags and
taking me shark tagging; and most of all my mom and dad, Jean and Barry, and my
grandparents, Rina and Bill, for inspiring me and
giving me the confidence that I can do anything I put my mind to despite being
an idiot.
References
http://www.cs.ucr.edu/~amitra/sdcard/ProdManualSDCardv1.9.pdf (SD card data sheet)
http://instruct1.cit.cornell.edu/courses/ee476/Serialcom
http://instruct1.cit.cornell.edu/courses/ee476/SPI/index.html
Materials
and Cost
STK500 Prototype Board -1
$15
Atmel Mega32 -1 $8
White Board -1 $6
2 Pin Flat Jumper Cable -1 $1
1 Pin header -3 $.05
10 Pin header -2 $.50
STK500 Power Supply -1 $5
2GB SanDisk SD/MMC -1
$20
Sparkfun SD/MMC breakout board-1
$10
Sensors, Resistors, Diodes, Opamp, etc
$1.06
Total
Cost = $67.21
Source Code
#include <Mega32.h>
#include <stdio.h>
#include <string.h>
#include <delay.h>
#include <spi.h>
//spice
#define STOP 50
#define SEND_BUFFER_CAPACITY 128
#define BUFFER_ROLLOVER_MASK 127
#define begin {
#define end }
// r1 response codes (from SD Card Product Manual v1.9
section 5.2.3.1)
#define R1_IN_IDLE_STATE (1<<0) // The
card is in idle state and running initializing process.
#define R1_ERASE_RESET
(1<<1) // An erase sequence was cleared before executing because of an
out of erase sequence command was received.
#define R1_ILLEGAL_COMMAND (1<<2) // An illegal command code was
detected
#define R1_COM_CRC_ERROR (1<<3) // The CRC check of the last
command failed.
#define R1_ERASE_SEQ_ERROR (1<<4) // An error in the sequence of erase
commands occured.
#define R1_ADDRESS_ERROR (1<<5) // A
misaligned address, which did not match the block length was used in the
command.
#define R1_PARAMETER
(1<<6)
// The command's argument (e.g. address, block length) was out of
the allowed range for this card.
// R1 bit (1<<7) is always 0
#define BLOCK_SIZE 512
// SD Card defaults to 512 byte block size
#define key_enter 0x0D
#define key_backspace 0x08
#define cts_size 5
//c prototypes
void main(void);
void menu(void);
void initialize(void);
unsigned char InitSD(void);
unsigned char SD_Command(unsigned
char*);
unsigned char SD_WriteBlock(unsigned
long, unsigned char*);
unsigned char SD_ReadBlock(unsigned
long, unsigned char*);
void log_data_to_sd_card(void);
void read_logged_data_from_sd_card(void);
void erase_data_fcn(void);
void saltwater_switch(void);
//pointers,eeprom
//int eeprom_print_value;
eeprom int eeprom_number_of_full_memory_blocks;
eeprom int set_seconds;
eeprom int set_minutes;
eeprom int set_hours;
//global variables
int go_log_data;
// sets 1ms pop for data logging
int
pop_1ms;
int exit_menu;
int saltwater_switch_on;
int saltwater_switch_tripped;
int
count;
int
pop_50ms;
unsigned char buffer[512];
char *mystring
= "erase and rewind";
int
timer;
int number_of_full_memory_blocks;
int end_data_log = 0; //this variable will correlate to a push
button which use pushes to end data log mode says done logging data
int read_logged_data = 0;
unsigned char newline[]=
"\n\n\r>\0\0";
char line_return[]
= "\r>";
char double_newline[]
= "\n\n\r>\0\0";
char term[] = {' ', key_backspace}; //////////////magic line
int tenths_of_a_second_counter =1;
int seconds_counter =0;
int minutes_counter =0;
int hours_counter =0;
int temp;
//We define several buffers of this
size. The rollover is for when we
want to compute x % SEND_BUFFER_CAPACTIY, then
//we compute x & BUFFER_ROLLOVER_MASK; clearly, this is more efficient.
char send_buffer[SEND_BUFFER_CAPACITY];
// This buffer holds characters destined to go out directly on the USART.
int send_buffer_read_position = 0;
int send_buffer_write_position = 0;
//Many of the buffers we define here are circular buffers,
so that there are no synchronization problems with accessing
//them. We write
to the write_position, read from the read_position, and wrap around when nececarry
with BUFFER_ROLLOVER_MASK;
char current_in_buffer[SEND_BUFFER_CAPACITY];
int cib_size = 0;
//This buffer holds the current input line, before the user
has hit enter. It is not circular, it just has its size.
char recv_buffer[SEND_BUFFER_CAPACITY];
int recv_buffer_read_position = 0;
int recv_buffer_write_position = 0;
//This buffere holds characters as
they are received by the USART. It
is circular. The difference between
this and
//current_in_buffer is that this
holds raw input keys, while current_in_buffer holds
the resulting line. recv_buffer
//may hold backspaces, enters, invalid characters, etc...
char line_in
[SEND_BUFFER_CAPACITY]; //This holds a complete input line, after it has been
entered.
char line_out[SEND_BUFFER_CAPACITY];
//This holds a line to be printed, after the main has created it.
int line_in_size;
int line_out_size;
#define key_enter 0x0D
#define key_backspace 0x08
#define cts_size 5
interrupt [USART_RXC] void usart_receive(void){
//read one
character, and put it into recv_buffer. also update write_position
recv_buffer[recv_buffer_write_position] = UDR;
recv_buffer_write_position = (recv_buffer_write_position+1)
& BUFFER_ROLLOVER_MASK ;
}
interrupt [USART_TXC] void usart_transmit(void){
//unused
}
interrupt [USART_DRE] void usart_empty(void){
//as long
as there are characters to send, we send them. this buffer
wraps around, just like read_buffer.
//there are no chars to send when our read position catches up to
the write position.
if( send_buffer_read_position != send_buffer_write_position ){
UDR = send_buffer[send_buffer_read_position];
send_buffer_read_position = (send_buffer_read_position+1)
& BUFFER_ROLLOVER_MASK ;
}
}
//This function copies from a buffer, into the send
buffer. It is fairly striaghtforward.
We just iteratre
//through the characters, write it to the send_buffer, and update send_buffer_write_position.
void write_to_send_buffer(char*
buffer, int size){
int i;
for(i=0; i<size;
i++){
send_buffer[send_buffer_write_position] = buffer[i];
send_buffer_write_position = (send_buffer_write_position+1)
& BUFFER_ROLLOVER_MASK;
}
}
// writes a command prompt with the current line of input
text. At the end, we print an extra
//space and backspace, so that when cib_size
shrinks, we don't have extra characters at the end.
void push_cib_through_send_buffer(void){
char beg[] = "\r>";
//char term[] = {' >', key_backspace}; //////////////magic line
write_to_send_buffer(beg, 2);
write_to_send_buffer(current_in_buffer, cib_size);
write_to_send_buffer(term, 2);
}
//implements the I/O for the tag.
void tx_rx_loop(void){
char cib_refresh_requested=0; //this is to be set whenever the input
line needs to be reprinted
//newline[]
= "\n\n\r>\0\0";
////////////////////////
while(recv_buffer_read_position!=recv_buffer_write_position){ //while there are still new charactes off the USART
char read_char;
read_char = recv_buffer[recv_buffer_read_position];
recv_buffer_read_position = (recv_buffer_read_position+1)
& BUFFER_ROLLOVER_MASK ;
//depending on
the character we just read, we do a number of different things.
if(read_char == key_backspace){
//backspace, shrink the buffer by one.
if(cib_size>0) cib_size--;
}else if( read_char>=32
&& read_char<=126 ){
//standard ascii
character, write it to current_in_buffer.
current_in_buffer[cib_size] = read_char;
cib_size++;
}else if( read_char == key_enter ){
//we have a new line of text ready, we copy it to line_in.
int i;
for(i=0; i<cib_size; i++){
line_in[i] = current_in_buffer[i];
}
push_cib_through_send_buffer();
write_to_send_buffer(newline, 3);
line_in_size = cib_size;
cib_size = 0;
}
cib_refresh_requested = 1; //in any of these cases, we need
to print out the in buffer again.
}
//we only
write characters out if the send_buffer
is currently empty.
if( send_buffer_read_position==send_buffer_write_position ){
if(line_out_size>0){
//char line_return[2] = "\r";
make global
//char double_newline[4] = "\n\n\r";
//in case the line we are printing is shorter than the line that is here
right now, we pad it
//with spaces.
while(line_out_size<25){
line_out[line_out_size] = ' ';
line_out_size++;
}
write_to_send_buffer(line_return, 1); //we return the
beginning of the line
write_to_send_buffer(line_out, line_out_size);
//we print out the data that is to be printed
line_out_size = 0; //mark that the line has been
printed.
write_to_send_buffer(double_newline, 3); //produce a new prompt
push_cib_through_send_buffer(); //reprint
whatever the current input is.
}else if( cib_refresh_requested ){
//if the input string was modified, we need to print it out again.
push_cib_through_send_buffer();
}
}
}
void flush_line_out(){ // fcn
to flush out line
while(line_out_size>0){
tx_rx_loop();
}
}
void wait_for_line_in(){ //fcn
to set linesize equal to zero and be ready for
another line
while(line_in_size==0){
tx_rx_loop();
}
}
interrupt [TIM0_OVF]
timer0_overflow(void){} //timer0 ovrlfw interrupt which drives the user interface
/////////////////////////////////////////////////////////////////////////////end
awful printing business. yayy!!!
// about main
//condition exists that tag cannot log data while menu
option is on
//entering menu will stop data logging. tag
can be armed while menu is on, but
//it can't log data
// exit exits menu and puts tag into data logging mode,
where it will wait for
//NaCl switch
to start data logging.
//this will require an initial adc running, looking fora
non zero value for 1
//second or something like that.
void main(void){
initialize();
while(1){
//InitSD();
menu();
saltwater_switch();
log_data_to_sd_card();
menu();
}
}
void initialize(void){
//this initializes everything
int i;
int timer = 100;
int menu_exit;
unsigned char adc;
unsigned char _adcl;
unsigned char _adch;
unsigned char check_saltwater_switch
= 1;
int number_of_full_memory_blocks
= 0;
UCSRA = 0b00000000 ;
UCSRB = 0b11111000 ;
//enabe timer as well as interrupts
UCSRC = 0b10000110 ;
UBRRH = 0 ;
UBRRL =
103;
//using a 16 MHz crystal (9600 baud)
TIMSK =
0b00001001;
//set bit0 = T0 ovrflw interrupt enable; bit3
= T1 output comp/match enable
TCCR0 =
0x01;
// interrupt for T0, clk I/O, no prescaling
DDRC =
0xFF;
PORTC =
0xFF;
//DDRB = 0xFF;
//PORTB =
0x00;
TCCR1A = 0;
// ha, need to fix something // initialize timer 0
TCCR1B = 0b0001011;
// timer 1 will generate interrupts every 1 millisecond -- must set
//wgm12, bit 3 to one to clear on compare match! ha!wgm
// set prescaler to 250 kHz (clkIO/64)
SPCR =
0b01011110;
SPSR = 1;
//set up i/o data direction
DDRB.4 = 1;
//CS
DDRB.5 = 1;
//output MOSI
DDRB.6 = 0;
//input MISO
DDRB.7 = 1;
//output SCLK
DDRD.4 = 1;
//set up nichrome burnwire
port. will use pin A.4. set
as output, then set value to be low
PORTD.4 =1;
//sets port pin high (led is active low!). reverse for
nichrome
InitSD(); //initialize
the sd card
OCR1AH = 0;
OCR1AL =
249;
// set compare register A to trigger at 1 ms
DDRC=0b11111111; //initialize
PORTC for blinking led for logging and waiting to for salt water switch
#asm
//enable interrupts
sei
#endasm
}
// Interrupt Timer 1, Compare Match B
//interrupt [TIM1_OVF] void TIMER1_OVF(void)
interrupt [TIM1_COMPB] void
TIMER1_COMPB(void)
//sets 1ms true interrupt for calling in other fcns
{
//pop_1ms = 1;
// sets 1ms pop for data logging, this will be our general data logging
time base
if (timer!=0)
timer--;
}
void menu(void)
//this fcn runs the hyperterminal
menu, and it exited when the user quits
{
exit_menu =0;
while(!exit_menu)
//the while needs a condition from armed
{
unsigned char temperature;
unsigned char pressure;
int number_of_blocks_erased;
int erase_block_number
= 0;
tx_rx_loop();
sprintf(line_out, "--------TAG USER MENU--------");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
sprintf(line_out, "Arm Tag");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
sprintf(line_out, "Disarm Tag");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
sprintf(line_out, "Check Sensors");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
sprintf(line_out, "Set Release Time");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
sprintf(line_out, "# Blocks of Data Logged");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
sprintf(line_out, "Read Data");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
sprintf(line_out, "Erase Data");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
sprintf(line_out, "Help");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
sprintf(line_out, "Quit");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
wait_for_line_in();
switch(line_in[0]){
case 'A':
case 'a':
term[0] ='>';
//changes prompt to indicate tag armed
sprintf(line_out, "The tag is now
armed!!!");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
go_log_data =1; //sets variable that with
NaCl-H20 switch starts data logging
break;
case 'D':
case 'd':
term[0] = ' ';
sprintf(line_out, "The tag has been
disarmed");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
break;
case 'C':
case 'c':
//read one value from adc
to see that sensor returns normal value
ADMUX =
0b00100000 ; //use internal reference voltage, left adjust, analog in pin 0
with no differential pg212
ADCSRA = 0b11000111 ; //enbale
adc, set longest clock division time.
while(ADCSRA.6 ==1);
temperature = ADCH;;
ADMUX =
0b00100001 ; //use internal vref, left adjust, analog
in pin 1 with no differential p212
ADCSRA = 0b11000111 ; //enbale
adc, set longest clock division time.
while(ADCSRA.6 ==1);
pressure = ADCH;
sprintf(line_out, "temp sensor value
is %d, pressure sensor value is %d", temperature, pressure );
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
break;
case 'S':
case 's':
sprintf(line_out, "Enter the release
time in seconds, minutes, and hours."); //write code to set burntime for nichrome
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
sprintf(line_out, "Enter the seconds
in ## format");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
wait_for_line_in();
sscanf(line_in, "%d",
&temp); //converts chars to ints
set_seconds = temp;
//stores seconds value in eeprom. same is repeated for min and hours below
sprintf(line_out, "you entered %d
seconds", set_seconds );
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
sprintf(line_out, "Enter the minutes
in ## format");
//write code to set burntime for nichrome
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
wait_for_line_in();
sscanf(line_in, "%d",
&temp);
set_minutes = temp;
sprintf(line_out, "you entered %d
minutes", set_minutes );
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
sprintf(line_out, "Enter the hours
in ## format");
//write code to set burntime for nichrome
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
wait_for_line_in();
sscanf(line_in, "%d",
&temp);
set_hours = temp;
sprintf(line_out, "you entered a
release time of %d hours %d minutes %d seconds",set_hours
, set_minutes,set_seconds );
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
break;
case 'E':
case 'e':
number_of_blocks_erased =eeprom_number_of_full_memory_blocks;
sprintf(line_out, "Are you sure you
want to erase data?\r");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
sprintf(line_out,
"Yes/No?\n\n\r");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
wait_for_line_in();
{
//openning bracket to sequester internal
yes/no switch from larger menu switch
switch(line_in[0]){
case 'Y':
case 'y':
delay_ms(10);// sprintf(line_out, "bill covile was
here");
if(eeprom_number_of_full_memory_blocks!=0){
erase_block_number = 0;
//InitSD();
//delay_ms(2);
//printf("bill covile was
here");
//delay_ms(2);
while(erase_block_number
<= eeprom_number_of_full_memory_blocks){
memset(buffer, 0, 512);
SD_WriteBlock(erase_block_number<<9,
buffer); //
increment block number [512 =2^9] and write it
erase_block_number++;
}
eeprom_number_of_full_memory_blocks = 0;
}
sprintf(line_out, "All %d blocks
have been erased", number_of_blocks_erased);
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
break;
case 'N':
case 'n':
break;
default:
sprintf(line_out, "Unrecognized
command. Please try again");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
delay_ms(50);
break;
}
//closing bracket to sequester internal yes/no switch from larger menu
switch
break;
case 'H':
case 'h':
sprintf(line_out, "Help Menu to
arrive soon");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
break;
case 'Q':
case 'q':
sprintf(line_out, "The program will
quit now");
line_out_size = strlen(line_out);
flush_line_out();
saltwater_switch_tripped = 0;
exit_menu = 1;
break;
case '#':
case 'N':
case 'n':
case 'B':
case 'b':
sprintf(line_out, "Number of full
data blocks %d", eeprom_number_of_full_memory_blocks
);
line_out_size = strlen(line_out);
flush_line_out();
break;
case 'R':
case 'r':
read_logged_data=1;
delay_ms(10);
read_logged_data_from_sd_card(); //call function that read data from sd
card
break;
default:
sprintf(line_out, "That is not a
recognized command shit4brains");
line_out_size = strlen(line_out);
flush_line_out();
line_in_size = 0;
break;
} //switch close
} //while close
}
}
///////////////////////////fcns
for sd card
initialize, write, read,
etc//////////////////////////////////////////////////////////
// sd
initialization fcn
unsigned char InitSD(void)
{
unsigned int i
= 0;
unsigned char status;
//
This is the only command required to have a valid CRC
//
After this command, CRC values are ignore unless
explicitly enabled using CMD59
unsigned char CMD0_GO_IDLE_STATE[] =
{0x00,0x00,0x00,0x00,0x00,0x95};
//initalize
unsigned char CMD1_SEND_OP_COND[] =
{0x01,0x00,0x00,0x00,0x00,0xFF};
unsigned char CMD55_APP_CMD[] =
{55,0x00,0x00,0x00,0x00,0xFF};
unsigned char ACMD41_SD_SEND_OP_COND[] =
{41,0x00,0x00,0x00,0x00,0xFF};
//TIMSK =
0b00001000;
//turn off Timer 0 interrupt
//
TCCR0 = 0x00; //and
stop timer
//
We need to give SD Card about a hundred clock cycles
to boot up
for(i = 0; i
< 16; ++i)
{ spi(0xFF);
//dummy bytes sent this is an improvement
spi(0xFF);
//
status = spi(0xFE);
//start token
}
PORTB.4
= 1;
//
Wait for the SD Card to go into IDLE state
i = 0;
do
{
status = SD_Command(CMD0_GO_IDLE_STATE);
delay_ms(10);
//
fail and return
if(i++ > 50)
{
printf("Error 1");
//note delta here
return 1;
}
}
while( status != 0x01 );
//
Wait for SD Card to initialize
i = 0;
do
{
status = SD_Command(CMD1_SEND_OP_COND);
delay_us(10);
if(i++ > 50)
{
printf("Error 2");
return 2;
}
}
while( (status & R1_IN_IDLE_STATE) != 0 );
//
Send CMD55, required to precede all "application specific" commands
status = SD_Command(CMD55_APP_CMD);
// Do not check response here
//
Send the ACMD41 command to initialize SD Card mode (not supported by MMC cards)
i = 0;
do
{
status = SD_Command(ACMD41_SD_SEND_OP_COND);
//
Might return 0x04 for Invalid Command if MMC card is connected
if(i++ > 50)
{
printf("Error 3");
return 3;
}
}
while( (status & R1_IN_IDLE_STATE) != 0 );
PORTB.4=1;
return 0;
}
// sd
read fcn
unsigned char SD_ReadBlock(unsigned
long addr, unsigned char *buf)
{
unsigned int i;
unsigned char status;
unsigned char CMD17_READ_SINGLE_BLOCK[] = {17,0x00,0x00,0x00,0x00,0xFF};
CMD17_READ_SINGLE_BLOCK[1] = ((addr &
0xFF000000) >> 24);
CMD17_READ_SINGLE_BLOCK[2] = ((addr &
0x00FF0000) >> 16);
CMD17_READ_SINGLE_BLOCK[3] = ((addr &
0x0000FF00) >> 8);
CMD17_READ_SINGLE_BLOCK[4] = ((addr &
0x000000FF));
PORTB.4=0;
//
Send the read command
status = SD_Command(CMD17_READ_SINGLE_BLOCK);
if(status != 0)
{
//
ABORT: invalid response for read single command
return 1;
}
//
Now wait for the "Start Block" token (0xFE)
//
(see SanDisk SD Card Product Manual v1.9 section
5.2.4. Data Tokens)
do
{
//status
= spi(0xFF);
//delta here
//status
= spi(0xFF);
status = spi(0xFE); //start token
}
while(status != 0xFE);
//
Read off all the bytes in the block
for(i = 0; i
< BLOCK_SIZE; ++i)
{
status = spi(0xFF);
*buf = status;
// printf("..%d\n\r",
*buf);
buf++;
}
//
Read CRC bytes
status = spi(0xFF);
status = spi(0xFF);
PORTB.4=1;
//
Following a read transaction, the SD Card needs 8 clocks after the end
//
bit of the last data block to finish up its work.
//
(from SanDisk SD Card Product Manual v1.9 section
5.1.8)
spi(0xFF);
return 0;
}
// sd
write a block of data fcn
unsigned char SD_WriteBlock(unsigned
long addr, unsigned char *buf)
{
unsigned int i;
unsigned char status;
unsigned char CMD24_WRITE_SINGLE_BLOCK[] =
{24,0x00,0x00,0x00,0x00,0xFF};
CMD24_WRITE_SINGLE_BLOCK[1] = ((addr &
0xFF000000) >> 24);
CMD24_WRITE_SINGLE_BLOCK[2] = ((addr &
0x00FF0000) >> 16);
CMD24_WRITE_SINGLE_BLOCK[3] = ((addr &
0x0000FF00) >> 8);
CMD24_WRITE_SINGLE_BLOCK[4] = ((addr &
0x000000FF));
PORTB.4=0;
//
Send the read command
status = SD_Command(CMD24_WRITE_SINGLE_BLOCK);
if(status != 0)
{
//
ABORT: invalid response for read single command
return 1;
}
//
Now wait for the "Start Block" token (0xFE)
//
(see SanDisk SD Card Product Manual v1.9 section
5.2.4. Data Tokens)
//v.1do
//v.1{
spi(0xFF);
spi(0xFF);
spi(0xFE); //start token
//v.1status
= spi(0xFF);
//v.1}
while(status != 0xFE);
//
Write bytes all the bytes in the block
for(i = 0; i
< 512; ++i)
{
// printf("--%d\n\r", &buf);
//v.1status
= spi(*buf);
//v.1buf++;
spi(buffer[i]);
}
//
Read CRC bytes
spi(0xFF);
spi(0xFF);
status = spi(0xFF);
//printf("status
= %d\n\r", status);
status &= 0x1F;
//printf("status2
= %d\n\r", status);
if (status != 0x05){
printf("damnation");
return 1;
}
while(spi(0xFF)!= (char)0xFF);
return 0;
//v.1PORTB.4=1;
//
Following a read transaction, the SD Card needs 8 clocks after the end
//
bit of the last data block to finish up its work.
//
(from SanDisk SD Card Product Manual v1.9 section
5.1.8)
spi(0xFF);
spi(0xFF);
//delta
return 0;
}
// sd
write multipleblocks of data
unsigned char SD_Write_Multiple_Block(unsigned
long addr, unsigned char *buf)
{
unsigned int i;
unsigned char status;
unsigned char CMD25_WRITE_Multiple_BLOCK[] =
{25,0x00,0x00,0x00,0x00,0xFF};
CMD25_WRITE_Multiple_BLOCK[1] = ((addr &
0xFF000000) >> 24);
CMD25_WRITE_Multiple_BLOCK[2] = ((addr &
0x00FF0000) >> 16);
CMD25_WRITE_Multiple_BLOCK[3] = ((addr &
0x0000FF00) >> 8);
CMD25_WRITE_Multiple_BLOCK[4] = ((addr &
0x000000FF));
PORTB.4=0;
//
Send multiple write command
status = SD_Command(CMD25_WRITE_Multiple_BLOCK);
if(status != 0)
{
//
ABORT: invalid response for read single command
return 1;
}
//
Now wait for the "Start Block" token (0xFE)
//
(see SanDisk SD Card Product Manual v1.9 section
5.2.4. Data Tokens)
//v.1do
//v.1{
spi(0xFF);
spi(0xFF);
spi(0xFE); //start token
//v.1status
= spi(0xFF);
//v.1}
while(status != 0xFE);
//
Write bytes, all the bytes in the block
for(i = 0; i
< 512; ++i)
{
// printf("--%d\n\r", &buf);
//v.1status
= spi(*buf);
//v.1buf++;
spi(buffer[i]);
}
//
Read CRC bytes
spi(0xFF);
spi(0xFF);
status = spi(0xFF);
//printf("status
= %d\n\r", status);
status &= 0x1F;
//printf("status2
= %d\n\r", status);
if (status != 0x05){
printf("damnation");
return 1;
}
while(spi(0xFF)!= (char)0xFF);
return 0;
//v.1PORTB.4=1;
//
Following a read transaction, the SD Card needs 8 clocks after the end
//
bit of the last data block to finish up its work.
//
(from SanDisk SD Card Product Manual v1.9 section
5.1.8)
spi(0xFF);
spi(0xFF);
//delta
return 0;
}
// sd
send a command fcn
unsigned char SD_Command(unsigned
char* cmd)
{
unsigned int i;
unsigned char response;
unsigned char savedSD_CS;
savedSD_CS = PORTB.4;
//
SD Card Command Format
//
(from Section 5.2.1 of SanDisk SD Card Product Manual
v1.9).
//
Frame 7 = 0
//
Frame 6 = 1
//
Command (6 bits)
//
Address (32 bits)
//
Frame 0 = 1
//
Set the framing bits correctly (never change)
cmd[0] |=
(1<<6);
cmd[0]
&= ~(1<<7);
cmd[5] |=
(1<<0);
//
Send the 6 byte command
PORTB.4=0;
for(i = 0; i
< 6; ++i)
{
spi(*cmd);
cmd++;
}
//
Wait for the response
i = 0;
do
{
response = spi(0xFF);
if(i > 100)
{
break;
}
i++;
}
while(response == 0xFF);
PORTB.4=0;
//
Following any command, the SD Card needs 8 clocks to finish up its work.
//
(from SanDisk SD Card Product Manual v1.9 section
5.1.8)
spi(0xFF);
PORTB.4
= savedSD_CS;
return(response);
}
void log_data_to_sd_card(void){
int exit = 1;
unsigned long write_block_number =
0;
int j = 0;
int end_data_log
= 1;
int seconds_counter
=0;
//reinitialize timer variables as there were used in saltwater switch
int minutes_counter
=0;
int hours_counter
=0;
//long block_number= 1024; //3906250; //the number of addressable
512 byte blocks in a 2GB SD card
//set up SPI!
//bit 7 SPIE=0
no ISR
//bit 6 SPE=1
enable spi
//bit 5 DORD=0 msb first
//bit 4 MSTR=1
Mega32 is spi master
//bit 3 CPLO=1
clock polarity
//bit 2 CPHA=1
clock phase
//bit 1,0 rate sel=10 along with SPRC=1
sets clk to f/32 = 500 kHz
SPCR =
0b01011110;
SPSR = 1;
//set up i/o data direction
DDRB.4 = 1;
//CS
DDRB.5 = 1;
//output MOSI
DDRB.6 = 0;
//input MISO
DDRB.7 = 1;
//output SCLK
//PORTB.4 =
1;
DDRD.4 = 1;
//set up nichrome burnwire
port. will use pin A.4. set
as output, then set value to be low
PORTD.4 =1;
//sets port pin high (led is active low!). reverse for
nichrome
InitSD(); //initialize
the sd card
DDRD.6 =
0; //set direction of port
d.6 as an input for switch, button sw0 right now
PORTD.6 =1;
//activate pullup resistor
if(go_log_data){
printf("Setting
up buffer\n\n\r");
while((write_block_number
<3906250) && (end_data_log)) //390625 is
the number of blocks on a 2GB SD card
{ int
temperature, pressure;
if(seconds_counter == set_seconds && minutes_counter==set_minutes && hours_counter==set_hours)
PORTD.4
=0; //start nichrome burn: turns on led by setting port D.4 low(led active low!) reverse for nichrome
//if(PORTD.6==0) //nacl
switch
//PORTD.7
=0;
if(timer==0)
//ever 100ms, take a measurement and store it to the buffer.
{{timer = 100;
tenths_of_a_second_counter++;}
if(tenths_of_a_second_counter==10)
//initialize tenths to 1
{tenths_of_a_second_counter = 0;
seconds_counter++;
PORTC=(PORTC ^ 0b10000000);}
//blinks LED, C.7 to indicated tag is logging data
if(seconds_counter==60)
//initialize seconds to 1
{seconds_counter = 0;
minutes_counter++;
}
if(minutes_counter==60)
{minutes_counter==0;
hours_counter++;}
//if clock time = set time start nichrome burn
by turning port high
ADMUX =
0b00100000 ;
//use internal reference voltage, right adjust, analog in pin 0 with no
differential pg212
ADCSRA = 0b11000111 ;
//enbale adc, set
longest clock division time.
while(ADCSRA.6 ==1);
pressure = ADCH;
buffer[j] = pressure;
j++;
printf("Elapsed
time %d:%d:%d\n\n\r",hours_counter , minutes_counter, seconds_counter
);
ADMUX =
0b00100001 ; //use internal vref, right adjust,
analog in pin 1 with no differential p212
ADCSRA = 0b11000111 ; //enbale
adc, set longest clock division time.
printf("Tag
set to release at time %d:%d:%d\n\r",set_hours ,
set_minutes, set_seconds );
while(ADCSRA.6 ==1);
temperature = ADCH;
buffer[j] = temperature;
j++;
//printf("jcount %d\n\r",j);
//printf("bill
coville was here");
}
if(j>=512)
// when buffer is full, write buffer to SD card
{
j=0;
//printf("Begin
writing block %d\n\n\r", write_block_number);
SD_WriteBlock(write_block_number<<9, buffer); // increment
block number [512 =2^9] and write it
memset(buffer,
0, 512);
// clear/replace all 512 buffer elements with the null character
//reset j
write_block_number++;
number_of_full_memory_blocks = write_block_number;
eeprom_number_of_full_memory_blocks = number_of_full_memory_blocks;
}
//increment block number to write to next block
}
//printf("End
writing 2 blocks of code, block %d and block %d\n\n\r", (write_block_number)-1, (write_block_number));
//delay_ms(50);
/* Write directly the value full memory blocks to the EEPROM
*/
printf("End logging data from sensors\n\n\r");
}
go_log_data=0; //disable log data variable
term[0] =' '; //reset menu arrow
indicator
PORTC.7
=1;
}
//fcn for reading data from sd card written by log_data_to_sd_card(void)
void read_logged_data_from_sd_card(void){
int j;
int read_block_number = 0;
//long block_number= 1024; //3906250; //the number of addressable
512 byte blocks in a 2GB SD card
//set up SPI!
//bit 7 SPIE=0
no ISR
//bit 6 SPE=1
enable spi
//bit 5 DORD=0 msb first
//bit 4 MSTR=1
Mega32 is spi master
//bit 3 CPLO=1
clock polarity
//bit 2 CPHA=1
clock phase
//bit 1,0 rate sel=10 along with SPRC=1
sets clk to f/32 = 500 kHz
SPCR =
0b01011110;
SPSR = 1;
//set up i/o
data direction
DDRB.4 = 1;
//CS
DDRB.5 = 1;
//output MOSI
DDRB.6 = 0;
//input MISO
DDRB.7 = 1;
//output SCLK
PORTB.4 =
1;
InitSD(); //initialize
the sd card
if(read_logged_data
&& (eeprom_number_of_full_memory_blocks
!=0)){
delay_ms(10);
printf("Number
of blocks written %d\n\n\r",eeprom_number_of_full_memory_blocks
);
delay_ms(100);
while(read_block_number < eeprom_number_of_full_memory_blocks) {
printf("
delay_ms(50);
SD_ReadBlock(read_block_number<<9,buffer); //add 512 and read block number
printf("Finished
reading block number %d from SD buffer\n\n\r", read_block_number);
delay_ms(50);
printf("Begin
printing block number %d to screen\n\r", read_block_number);
delay_ms(50);
for(j=0; j<512; j++)
// change for 1024 for(j=0; j<512; j++)
{
printf("%d\n\r", buffer[j]);
delay_ms(1);
//printing delay
}
printf("End
printing block %d\n\n\r", read_block_number);
read_block_number++;
}
printf("DONE\n\n\n\r");
read_logged_data=0;
}
else /*if ((read_logged_data ==0) || (eeprom_number_of_full_memory_blocks == 0))*/ {
delay_ms(10);
printf("There is no data in memory to read\n\r");
}
}
void saltwater_switch(void)
//this is a fcn that will read NaCl-H20 switch
and set salt_water
{
int saltwater_switch = 1;
unsigned char check_saltwater_switch;
if(go_log_data ==1)
{
while(saltwater_switch)
{
if(timer==0) //ever 100ms, take a measurement and
store it to the buffer.
{timer = 100;
tenths_of_a_second_counter++;}
if(tenths_of_a_second_counter==10)
//initialize tenths to 1
{tenths_of_a_second_counter = 1;
seconds_counter++;
PORTC=(PORTC ^ 0b01000000);} //use C.6 for armed and
waiting led (led6 for now)
ADMUX =
0b00100010 ;
//use internal reference voltage, right adjust, analog in pin 2 with no
differential pg212
ADCSRA = 0b11000111 ;
//enbale adc, set
longest clock division time.
while(ADCSRA.6 ==1);
check_saltwater_switch = ADCH;
printf("value = %d\n\r", check_saltwater_switch);
if(check_saltwater_switch
> 200)
saltwater_switch=0;
PORTC.6 = 1;
//resets C.6 led to high to turn off led once switch is tripped
}
}
}
///////////////////////////////////////end
sd
business////////////////////////////////////////////////////////////////////