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 mŽlange 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://instruct1.cit.cornell.edu/courses/ee476/FinalProjects/s2007/cd247_maw72/cd247_maw72/index.html

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("Reading block number %d from SD buffer\n\n\r", read_block_number);

        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////////////////////////////////////////////////////////////////////