#include #include // Include the SoftwareSerial library with Arduino 0007 or later version #include #include #include #define SoftrxPin 2 // SoftwareSerial port on pin 2 (RX from the GPS) #define SofttxPin 3 // Not used, but needed to in order to declare SoftwareSerial; SoftwareSerial mySerial = SoftwareSerial(SoftrxPin, SofttxPin); // Set up a new serial port // SPI EEPROM Interface #define SLAVESELECT 10 // Select the digital 10 pin for the SPI connection of the EEPROM 1 pin (CS) #define DATAOUT 11 // Select the digital 11 pin for the SPI connection of the EEPROM 5 pin (MOSI, write) #define DATAIN 12 // Select the digital 12 pin for the SPI connection of the EEPROM 2 pin (MISO, read) #define SPICLOCK 13 // Select the digital 13 pin for the SPI connection of the EEPROM 6 pin (SCK) // Instructions and Operation Codes for the SPI EEPROM #define WREN 6 // Write Enable: 0000 x 110 #define WRDI 4 // Write Disable: 0000 x 100 #define RDSR 5 // Read Status Register: 0000 x 101 #define WRSR 1 // Write Status Register: 0000 x 001 #define READ 3 // Read Sequence: 0000 x 011 #define WRITE 2 // Write Sequence: 0000 x 010 // Analog Pins (0 ~ 5) int potPin1 = 1; // Select the input pin for sensor baseline (AUXILIARY) int potPin2 = 2; // Select the input pin for sensor variation (SENSING) int modePin = 3; // Used to select between read & writemode. +5V means "write mode," GND means "read mode" int potPin4 = 4; // If set to +5V, the eeprom will be reset. // Digital Pins (0 ~ 13) int ledPin4 = 4; // Select the pin for data LED (green) int ledPin5 = 5; // Select the pin for data LED (yellow) int ledPin6 = 6; // Select the pin for data LED (red), ON during the highest gas level int writemode1 = 7; // Write mode LED (on when EEPROM space available, green LED); int writemode2 = 8; // Write mode LED (on when NO EEPROM space available, red LED); int readmode = 9; // Read mode LED (on/blinking, when reading from EEPROM); Also steady on when acquiring GPS data int val0 = 0; // Variable to store value from sensor (baseline) int val1 = 0; // Variable to store value from sensor (variation) int val2 = 0; // Variable to store value we're interested in (val2 = val1 - val0) int erase; // Used as "erase / reset counter" flag variable; int addr = 0; // Used for EEPROM storage int address = 0; // Used for SPI interface byte e_out; // Used for reading from EEPROM byte e_in; // Used for writing to EEPROM byte clr; // Used for clearing SPI registers int writemode; // Indicates if program is in "read" or "write" mode" int count = 0; // Counter used to keep track of EEPROM byte USAGE -- doesn't work, cause will reset when power is lost byte page = 0; // Used for EEPROM page (0 ~ 255) byte Maxpage = 255; char EEPROMbuffer[32] = " "; // This array stores SPI EEPROM data. // 32-byte x 256 Pages = 8192 bytes = 8K bytes // VARIABLE USED IN GPS FUNCTION int byteGPS = -1; // Initialize variable that reads in GPS bytes. "-1" indicates "no data available" at serial port. char GPSbuffer[300] = " "; // This array stores GPS data. It will be overwritten until "$GPRMC" string is found during data acquisition. // Will hold this data (if valid) until stored in EEPROM char SensorBuff[2] = " "; int buffplace = 0; // Indicate place within GPSbuffer array char gprmc[7] = "$GPRMC"; // This is a constant array. It holds the string "$GPRMC". "$GPRMC" indicates the beginning of the GPS data string that we're interested in. int GPSFound = 0; // Counter used to count through "$GPRMC". Has this location been found in GPSbuffer? If YES, continue, Otherwise, // Read in new DATA and override GPSbuffer array int commas[13]; // This array keeps track of comma positions + checksum indication in entire "$GPRMC" data string int com = 0; // This integer keeps track of position within commas array char status; // Used as FLAG indicating validity of GPS data. 'A' means valid. (see GPS NMEA protocol) boolean acquire = true; /////////////////////////////////***********************************///////////////////////////////// void setup() { pinMode(SoftrxPin, INPUT); // Declare rx pin as INPUT pinMode(ledPin4, OUTPUT); // Declare the ledPin as an OUTPUT pinMode(ledPin5, OUTPUT); // Declare the ledPin as an OUTPUT pinMode(ledPin6, OUTPUT); // Declare the ledPin as an OUTPUT pinMode(writemode1, OUTPUT); // Declare the ledPin as an OUTPUT pinMode(writemode2, OUTPUT); // Declare the ledPin as an OUTPUT pinMode(readmode, OUTPUT); // Declare the ledPin as an OUTPUT pinMode(SLAVESELECT, OUTPUT); pinMode(DATAOUT, OUTPUT); pinMode(DATAIN, INPUT); pinMode(SPICLOCK, OUTPUT); digitalWrite(SLAVESELECT, HIGH); // Disable SPI EEPROM digitalWrite(ledPin4, HIGH); digitalWrite(ledPin5, HIGH); digitalWrite(ledPin6, HIGH); digitalWrite(writemode1, HIGH); digitalWrite(writemode2, HIGH); digitalWrite(readmode, HIGH); beginSerial(4800); mySerial.begin(4800); // Set the data rate for the software serial port for (int i=0; i < 300; i++) { // Initialize a buffer for received data GPSbuffer[i] = ' '; } // Set the SPI Control Register (SPCR) to the binary value: SPCR = 01010000 // Interrupt Disable, SPI Enable, MSB 1st, Arduino in master mode, Clock idle when low, Sample data on the rising edge of the clock, Fastest SPI speed SPCR = (1< 1000) { eeprom_write_byte((unsigned char *) 0, 0); // page = 0 Serial.println("Counter has been reset"); } // Erase first! page = eeprom_read_byte((unsigned char *) 0); count = 32 * (int)page; // Serial.print(" Page number: "); // Serial.print((int)page); // Serial.println(" "); // Serial.print(" Count number: "); // Serial.print(count); // Serial.println(" "); // Check if board assigned to be in "read" or "write mode" writemode = analogRead(modePin); // +5V means "write mode and GND means "read mode" if (writemode > 1000) writemode = 1; else writemode = 0; if (writemode == 1 && page < Maxpage) { // addr => 32-byte page and Maxpage = 256 pages in case of AT25640A (8K bytes) digitalWrite(readmode, HIGH); // Current internal EEPROM can take up to 512 bytes. digitalWrite(writemode1, LOW); // Light up "write mode" green LED on digital pin 10 digitalWrite(writemode2, HIGH); // red LED is off-state since EEPROM space is available now val0 = analogRead(potPin1); // Read the value from the sensor (baseline, A), analog pin 1 val1 = analogRead(potPin2); // Read the value from the sensor (variation, S), analog pin 2 val2 = val1 - val0; // Determine the sensor value writeLEDs(); // Call writeLEDs function if (val2 >= 0) { // Only save values above 2ppm to eeprom (anything below could be noise) // Serial.print("Sensor value: "); // Serial.println(val2); char convert[3] = " "; // Delete convert variable using EEPROMbuffer sprintf(convert, "%d", val2); // Convert val2 (integer) to char string ////////////****** First save to 32-byte buffer and save its data (32 byte = 1page) to an external EEPROM at one time ******//////////// for (int i=0; i < 3; i++) { EEPROMbuffer[i] = convert[i]; addr = addr + 1; } delay(50); // Keep track how many values stored in eeprom readGPS(); // Call GPS read function delay(50); write_eeprom(); // Call SPI EEPROM write function // for (int i=0; i < 32; i++) // Serial.print(EEPROMbuffer[i]); page = page + 1; eeprom_write_byte((unsigned char *) 0, page); delay(30000); acquire = true; } } else { // When "read mode" or "write mode" but addr > eepromSize, digitalWrite(writemode1, HIGH); digitalWrite(writemode2, LOW); // Light up "write mode" red LED on digital pin 11 when no EEPROM space is available now } // or when "read mode" if (writemode == 0) { // When "read mode", reading from an external EEPROM ledBlink(); // Blink "read mode" LED (ledPin12) 6 times to indicate that download will begin address = 0; // Go to address place "0" in the EEPROM to begin reading from the SPI EEPROM for (int i=0; i < count; i++) { // Only read as many values as written in "count" variable e_out = read_eeprom(address); // Read one byte at a time from the SPI EEPROM address = address + 1; printByte(e_out); // Print the ASCII representation of "e_out" delay(50); } Serial.println("DOWNLOAD COMPLETE"); delay(10000); } // End of if (writemode == 0) } // End of main loop /////////////////////////////////***********************************///////////////////////////////// // FUNCTIONS // void readGPS() { // Check "count" variable => the number of saved data // Check 'h' position while(acquire) { digitalWrite(readmode, LOW); // Light up "read mode" big yellow LED on digital pin 12 when acquiring GPS data byteGPS = mySerial.read(); // Read a byte of the software serial port if (byteGPS != -1) { // Check if the port is empty yet, initial value = -1 GPSbuffer[buffplace] = byteGPS; // If there is serial port data, put it in the buffer buffplace++; if (byteGPS == 13) { // If the received byte is equal to 13, the end of transmission, ASCII 13 = '\r' a carriage return character com = 0; GPSFound = 0; for (int i=1; i < 7; i++) { // Verify if the received line of data currently stored in GPSbuffer array starts with "$GPRMC" if (GPSbuffer[i] == gprmc[i-1]) { // Compare to "gprmc" constant array GPSFound++; } } if(GPSFound == 6) { // Current dataline stored in GPSbuffer array starts with "$GPRMC" // Now go through data to find comma positions in the data line for (int i=0; i < 300; i++) { if (GPSbuffer[i] == ',') { // Check for the position of the "," separator commas[com] = i; // Total 11 "," in GPS string com++; } if (GPSbuffer[i] == '*') { // Check for the "Checksum" data commas[11] = i; com++; } } com = commas[1]; // Second comma (,) position status = GPSbuffer[com+1]; if(status == 'A') { // Only if Status is (A= Valid), save the data // Serial.println(""); // Write to the serial port // Serial.println("---------------------------------------------------------------------"); EEPROMbuffer[addr] = 9; // Tab between Sensor and GPS values, ASCII 9 = tab addr = addr + 1; for (int i=0; i < 10; i++) { for (int j = commas[i]; j < (commas[i+1]-1); j++) { // Serial.print(GPSbuffer[j+1]); // Print the data after the comma (,) if((i > 1 && i < 6) || i == 8) { // When i = 2, 3, 4, 5, and 8 EEPROMbuffer[addr] = GPSbuffer[j+1]; addr = addr + 1; } } // Serial.println(""); // Print the new line } EEPROMbuffer[addr] = 10; // Line feed after each set (Sensor + GPS values), ASCII 10 = line feed addr = 0; // Serial.print("Checksum: "); // com = commas[11]; // Serial.print(GPSbuffer[com+1]); // Serial.print(GPSbuffer[com+2]); // Serial.println(""); // Serial.println("---------------------------------------------------------------------"); // Serial.println(" "); acquire = false; } // End of if(status == 'A') } // End of if(GPSFound == 6) If yes, continue and process the data for (int i=0; i < 300; i++) { GPSbuffer[i] = ' '; } buffplace = 0; // Reset the buffer or if not $GPRMC data com = 0; // Reset commas array index GPSFound = 0; // Reset verification/counter variable status = ' '; // Reset status flag } // End of if (byteGPS == 13) If the received byte is equql to 13, the end of transmission } // End of else (byteGPS is not equal to -1) => if some data is available } // End of while(acquire) } // End of readGPS() /////////////////////////////////***********************************///////////////////////////////// void ledBlink() { // Blink "read mode" LED 6 times to indicate that download will begin for (int i=0; i < 6; i++) { digitalWrite(readmode, HIGH); delay(500); digitalWrite(readmode, LOW); delay(500); } } /////////////////////////////////***********************************///////////////////////////////// void writeLEDs() { // CO and OZ sensors have the different values for their threshold levels if (val2 > 0) { // Check the sensor value (currently calibratred for POT, not for the sensors) digitalWrite(ledPin4, LOW); // Light up green LED on digital pin 4 } else { digitalWrite(ledPin4, HIGH); // Is it necessary? } if (val2 > 5) { digitalWrite(ledPin5, LOW); // Light up yellow LED on digital pin 5 } else { digitalWrite(ledPin5, HIGH); } if (val2 > 5) { digitalWrite(ledPin6, LOW); // Light up red LED on digital pin 6 } else { digitalWrite(ledPin6, HIGH); } } /////////////////////////////////***********************************///////////////////////////////// char spi_transfer(volatile char data) { SPDR = data; // Start the transmission while ( !(SPSR & (1<>8)); // Send MSByte address first spi_transfer((char)(address)); // Send LSByte address for (int i=0; i < 32; i++) { spi_transfer(EEPROMbuffer[i]); // Send and write 32 bytes of data from the EEPROMbuffer array } digitalWrite(SLAVESELECT,HIGH); // Release the SPI EEPROM delay(1000); // Wait for the EEPROM to finish writing } /////////////////////////////////***********************************///////////////////////////////// byte read_eeprom(int EEPROM_address) { int data; digitalWrite(SLAVESELECT,LOW); // Select the SPI EEPROM spi_transfer(READ); // Send a READ instruction to the EEPROM spi_transfer((char)(EEPROM_address>>8)); // Send MSByte address first spi_transfer((char)(EEPROM_address)); // Send LSByte address data = spi_transfer(0xFF); // Get data byte by sending a dummy byte to the EEPROM for shifting the data out digitalWrite(SLAVESELECT,HIGH); // Release the SPI EEPROM return data; }