/* >Sol_Arduino V1.0 Prototype Code< This code provided for general use under Creative Commons Attribution/Share Alike 3.0 Written by Joel Murphy for Rachel's Electronics http://www.rachelselectronics.com Presentation of this firmware is AS IS. The author makes no guarantees, promises, or pledges regarding functionality. */ #include //sleep library #include //watchdog timer library #include //EEPROM library // > MCP ADDRESS BYTE < #define MCP B01011100 //Control Byte / Slave Address = 0.1.0.1 / 1.1.A0.R/W // > MCP COMMAND BYTES < #define Write_W0 B00000000 //Write WiperO command #define Read_W0 B00001100 //Read Wiper0 command #define Inc_W0 B00000100 //Incriment Wiper0 Command #define Dec_W0 B00001000 //Decriment Wiper0 Command #define TCON_R B01001100 //Read the Terminal Control Register #define TCON_W B01000000 //Write to the Terminal Control Register // > MCP CONFIG SETTINGS < #define W0_ENABLE B00001111 //W0 not in shutdown, all pins connected "on" #define W0_DISABLE B00001110 //W0 not in shutdown, P0B disconnected "off" //in 'off' the sense pin of the 3808 feels +V //and RESET is in high Z // > TNC ADDRESS BYTE < #define TNC B10010000 //Control Byte / Slave Address = 1.0.0.1.A2.A1.A0.R/W // > TNC POINTER BYTES < #define TA B00000000 //Temperature Register Pointer #define TNCON B00000001 //Configuration Register Pointer #define HYST B00000010 //Hysteresis Setting Register #define LIMIT B00000011 //Limit Setting Register // > TNC CONFIG SETTINGS #define S_DOWN B00000001 //put the TNC into shutdown mode #define SHOT B10000001 //TNC One Shot. take a reading and then shutdown //9 bit resolution = 30mS conversion time #define sleepTime 75 //number of 8 second sleep cycles word Temp; //used to hold two byte temperature value from TNC75A word Wiper; //used to hold wiper position read from DigiPot W0 register int Voltage; //used to hold calculated voltage value int time; //used to keep track of time slept int light; //used to hold photoResistor sensor value int addr; //current address in EEPROM to log data // > PINS < int Trip = 12; //connected to TPS3803 RESET pin int powerGate = 8; //connected to gate of P-MOSFET to control power to board int LED = 13; //connected to LED for feedback and to act as a test load int photoR = 0; //connected to photocell to register ambient light (analog pin 0) char temp_L; //degrees in C left of decimal. written in 2's complimnet byte temp_R; //degrees in C right of the decimal. int volt_R; //voltage right of decimal. volatile byte wdt=0; //used as sleep counter incrimented in watchdog ISR boolean highPROM = false; boolean endPROM = false; void setup() { Serial.begin(9600); pinMode(LED,OUTPUT); pinMode(powerGate,OUTPUT); pinMode(Trip,INPUT); // SET UP FOR SLEEPING setup_watchdog(); // set prescaller and enable interrupt set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here Power Down uses the least current // system clock is turned off, so millis won't be reliable! setup_I2C(); // I2C initialization addr = check_EE(); // on restart, get the next location to store data digitalWrite(powerGate,LOW); // pull down on P-channel MOSFET to turn on board } void loop(){ checkLine(); getData(); delay(2); system_sleep(); } //**************************************************************** void getData(){ byte V; //voltage byte byte L; //ambient light level byte byte T; //temperature byte // get and store voltage I2C_Write(MCP,TCON_W,W0_ENABLE); //attach all digipot pins for (int i = 0; i<=255; i++){ I2C_Write(MCP,Write_W0,i); //increment wiper position from 0 delay(20); //until TCP3803 trips if (digitalRead(Trip)){ //and make a note of the wiper location Wiper = I2C_Read(MCP,Read_W0); break; } } I2C_Write(MCP,Write_W0,0); //set the digipot wiper position to 0 I2C_Write(MCP,TCON_W,W0_DISABLE); //disconnect GND from risistor ladder in DigiPot Voltage = 315560/Wiper; //magic number derived thru testing! V = Voltage/1000; //V-ref in TCP3803 = nominal 1.226V volt_R = Voltage - V*1000; //http://www.rachelselectronics.com/blog/Sol_Arduino volt_R /= 10; //volt_R holds value right of decimal (i don't like floats!) switch (V){ //format data for storage in 1 byte case 2: V = volt_R; //MSB is 0 if we're under 3.00V lower 7 bits hold voltage right of decimal. break; case 3: V = volt_R + 128; //MSB is 1 if we're over 3.00V lower 7 bits hold voltage right of decimal. break; } logData(V); // get and store ambient light data light = analogRead(photoR); L = light/4; logData(L); // get and store temperature data Temp = I2C_Read(TNC,TA); // temp data stored in 2 byte 2's copmliment, degrees Celcius T = Temp >> 8; // high byte holds value left of decimal temp_R = (bitRead(Temp,7)*5); // low byte holds value right of decimal logData(T); } //**************************************************************** int check_EE(){ int a; byte temp = EEPROM.read(0); // read EEPROM location 0 to see if we have already logged data switch(temp){ // case 0xFF: // 0xFF means EEPROM is empty EEPROM.write(0,0x0F); // 0x0F in location 0 means we are in lower half of EEPROM a = 2; // start logging data at location 2 in EEPROM EEPROM.write(1,addr); // save the next location to log data in location 1 (always!) break; case 0x0F: // next data address is in lower half of EEPROM a = EEPROM.read(1); // recall the next location to store data break; case 0xF0: // next data address is in upper half of EEPROM a = EEPROM.read(1) + 256; // recall the next location to store data highPROM = true; // note that we are in upper half of EEPROM break; case 0x00: endPROM = true; break; default: Serial.print("EE error "); Serial.println(temp,HEX); } return a; } //**************************************************************** void logData(byte d){ if (endPROM == true){ //when there's no more EEPROM return; //get out of here! } EEPROM.write(addr,d); //log the data in the next available EEPROM location addr++; if (addr == 256){ //when we enter the high byte address of EEPROM highPROM = true; //make a note of it in the highPROM flag EEPROM.write(0,0xF0); //make a note of it in the EEPROM } if (addr == 512){ //when we get to the end of memory EEPROM.write(0,0x00); //make a note in the EEPROM endPROM = true; //make a note in the endPROM flag return; //get out of here! } EEPROM.write(1,addr); //keep track of current EEPROM location } //**************************************************************** void system_sleep() { digitalWrite(powerGate,HIGH); // turn off board ADCSRA |= (0< 0){ inByte = Serial.read(); switch(inByte){ case 'D': dumpData(); break; case 'C': eraseData(); break; default: Serial.println("X"); } } } //**************************************************************** void dumpData(){ byte d = EEPROM.read(0); Serial.print("page "); Serial.println(d,DEC); d = EEPROM.read(1); Serial.print("address "); Serial.println(d,DEC); for (int i=2; i 0){ inByte = Serial.read(); if (inByte == 'N'){ Serial.println("cancel erase"); return; } } if (t%50 == 0){Serial.print(".");} delay (10); } Serial.println(); Serial.print("erasing... "); for (int j=0; j<512; j++){ EEPROM.write(j,0xFF); delay(5); } Serial.println("done erasing"); addr = check_EE(); printDirections(); for (int i=0; i<200; i++){ if (Serial.available() > 0){ inByte = Serial.read(); if(inByte == 'D'){ dumpData(); }else{ Serial.println("not a valid command"); } } } } //**************************************************************** void printDirections(){ Serial.println("EEPROM dump"); Serial.println("enter 'D' to dump"); Serial.println("enter 'C' to erase all"); } //**************************************************************** /* THIS FUNCTION READS TWO BYTES FROM THE I2C SLAVE ERROR FEEDBACK FUNCTION BELOW */ int I2C_Read(byte address,byte command){ byte data_L; byte data_H; int data; TWCR = (1<READ ME< > PROTOTYPE < Sol_Arduino V 1.0 Solar powered arduino platform with rechargeable battery, power management and sensors The prototype circuit includes: CHARGING CIRCUITRY: PowerFilm flexi solar panel (Jameco #228030) 6800uF-6.3V capacitor S-808 3.5V voltage detector (used as trigger on cap charge) 2N3904 Transistor (inverter) BS250 P-channel MOSFET (acts as switch to charge battery) BATTERY MANAGEMENT: MCP4551 digital potentiometer (single, 100K, I2C) TCP3803 adjustable voltage detector The TPS3803 RESET pin is connected to digitalPin 12 along with a pullup resistor. The MCP4551 wiper pin is connected to the TPS3803 SENSE pin TPS3803 internal Vref is 1.226V. When Voltage on the SENSE pin is below Vref, RESET output is Low. When Voltage on SENSE is above Vref, RESET is high Z and digitalPin 2 will get pulled up. SLEEPING NOTES Atmel will sleep between sensor readings Sleep mode: PWR_DOWN for least current draw Length of sleep = sleepTime * 8seconds Uses P-MOSFET to turn off high side of board during sleep (0.2mA!) SENSOR NOTES Ambient light sensor (photoresistor) Temperature (TCN75A) Power Outrigger on bottom edge of board allows access to +V and GND for accessorizing FOR MORE INFORMATION AND DEVELOPMENT NOTES: www.rachelselectronics.com/blog I2C overview: TWO ANALOG PINS TAKEN OVER TO USE I2C: Analog 5 = SCL Analog 4 = SDA FUNCTION CALLS: I2C_Write(save address,command/pointer,data); used to send one byte of data over I2C line word = I2C_Read(slave address,command/pointer); used to read 2 bytes of data over I2C line EEPROM USAGE: The EEPROM is mapped thusly: 0x000: Holds information about what page the next available byte location is in EEPROM 0x0F = First Page = Locations 0x000 to 0x0FF 0xF0 = Second Page = Locations 0x100 to 0x1FF 0x001: Holds number corresponding to the next available address for writing data If we're on the first page, the byte is read and applied directly If we're on the second page, the byte is adjusted upward before it's used Every 10 minutes, data is read and stored in successive EEPROM locations: Voltage, Ambient Light Level, Tempurature(C) EEPROM can be dumped over the serial line by sending a 'D' within two seconds of receivin 'A' EEPROM can be erased by sending 'C'. After erasure, all memory locations = 0xFF */