Category Archives: Arduino

No updates? I blame writers block…

Yeah, that’s the ticket.

So where am I as I start 2013.  Well, My Arduino based weather thingy is basically working.  The rain counter still dead… the now obsolete Maxim DS2423 seems a bad design choice now.  There must be a better way to keep track of the tipping rain bucket ( 5o tips per inch) that is non-volatile for those power outage times.

My Arduino based “make your own work bench tool” project is sort of stalled. Though I did find a neat oversize retro cabinet to put it in. (So 1980’s)

I’ll close up this update by sharing an old project… the Live For Speed Outgauge Bus Arduino interface (gear and RPM meter).

PC Network UDP to Serial conversion:  “PC CODE” and the Schematic.

Arduino Code: (pre-IDE 1.0)

 //----[ OutGaugeBus ]------------------------------------------------------
 // Name : OGBUS.PDE
 //-------------------------------------------------------------------------
 // Purpose : Receive serial commmands from "Live For Speed" INSIM OUTGAUGE
 // : Client and then display real-time dashboard information
 // : on Arduino based output devices, such as LED's.
 // : Live For Speed References:
 // : LFS/DOCS/INSIM.TXT
 // : http://en.lfsmanual.net/wiki/InSim_Tutorials
 // : http://www.brunsware.de/insim/
 // : See Also: http://www.lfs.net/
 //-------------------------------------------------------------------------
 // Date : 25 Oct, 2007 ( Started as a Parallax SX28 project )
 // Version : 2.11
 // Modified: 12/22/2010 11:30:34 AM
 // Author : Pete Willard
 // :
 //Additional:
 // Credits : * Mike McRoberts - Earthshine Design -
 // : Arduino Starter Kit PDF
 // :
 // : * Hacktronics - http://www.hacktronics.com/Tutorials
 // :
 // : * Arduino ShiftOut tutorial
 // :
 // : To keep code "recognizable", available references were used
 // : and changed very little from reference sources listed above.
 //-------------------------------------------------------------------------
 // Notes : Includes using a 74HC595 Shift Register for the Bar Graph
 // : and discrete 7-segment display for gear indicator
 // :
 // : Commands come from OGBUS.EXE (DevC++ UDP Client) and convert
 // : INSIM OUTGAUGE data into serial packet data for Arduino
 // : INSIM Client Software will send ALL vaalues every update
 // : but can send as little as Clear Command "C0"
 // :
 // : Expansion:
 // : With a little creative wiring, it would be possible to
 // : daisy chain multiple serial Arduino boards or if USB is
 // : used, multiple OGBUS clients can be run at one time
 // :
 // : Command Examples:
 // : (Comma Separated Values) Any Order up to 24 Characters
 // : Format: <command></command>,<command></command>...
 // : C0 = Clear All Outputs
 // : G0-G8 = Gear Indicator
 // : R0-R8 = RPM Bargraph
 // : S0|S1 = Shift Light Pin On|Off (binary)
 // : P0|P1 = Pit Limiter Pin On|Off (binary)
 // :
 //-------------------------------------------------------------------------

//----[ Variables ]--------------------------------------------------------
 const int buffsize = 25; // Buffer Size
 char buffer[buffsize]; // Incoming Serial Data Buffer
 int debug = 0; // Set to NON-ZERO to test with Serial Monitor
 int ledCount = 8; // The number of LEDs in the Bar Graph LED
 //-------------------------------------------------------------------------
 // Seven segment LED layout for the Gear Indicator
 // Arduino pins must be sequential
 int GIstartpin = 2;
 // Arduino pin: 2,3,4,5,6,7,8
 byte seven_seg_digits[9][7] = { { 0,0,0,0,1,0,1 }, // = R
 { 0,0,1,0,1,0,1 }, // = N
 { 0,1,1,0,0,0,0 }, // = 1
 { 1,1,0,1,1,0,1 }, // = 2
 { 1,1,1,1,0,0,1 }, // = 3
 { 0,1,1,0,0,1,1 }, // = 4
 { 1,0,1,1,0,1,1 }, // = 5
 { 1,0,1,1,1,1,1 }, // = 6
 { 0,0,0,0,0,0,0 }, // = 7 (blank)
 };
 // a b c d e f g ------> LED segment
 //-------------------------------------------------------------------------
 // Bargraph Values for 8 LED Bargraph
 // Only 8 values of BYTE are needed to light the 8 bargraph LED's
 // sequentially
 // NOTE: Most Bargraph LED's are "10 unit" so I have bottom 2 and top 2
 // LED's tied together.
 // Part Number used: AVAGO "HDSP-4832" 3-Green 4-Yellow 3-Red
 // Mouser Part Number: 630-HDSP-4832
 // The Shift Register lowest outputs start with Green Anodes of the
 // Bargraph.
 //
 byte bargraph[9] = {0x00,0x01,0x03,0x07,0x0F,0x1F,0x3F,0x7F,0xFF};
 //-------------------------------------------------------------------------
 // LED PINS - optional since we are low on pins
 int shiftlight = 12;
 //int pitlimit = 13; // Pick one
 //int lowfuel = 13;
 //-------------------------------------------------------------------------
 // 74HC595 Pin Setup
 int latchPin = 9; // Pin connected to ST_CP (12) of 74HC595
 int clockPin = 10; // Pin connected to SH_CP (11) of 74HC595
 int dataPin = 11; // Pin connected to DS (14) of 74HC595

//----[ SETUP ]-----------------------------------------------------------
 void setup() {
 // Speed needs to match INSIM - Outgauge Client Configuration setting
 Serial.begin(19200);
 Serial.flush();

// Set all pins to Outut Mode
 int a;
 for(a=0;a < 13;a++){ pinMode(a, OUTPUT); 
 } 
} 

//----[ MAIN LOOP ]------------------------------------------------------ 
void loop()  { 
// Mike McRoberts serial input command routines 
// from the "Serial Controlled Mood Lamp" example 
// in Arduino Starter Kit Manual from Earthshine Design 
if (Serial.available() > 0) {
 int index=0;
 delay(10); // let the buffer fill up
 int numChar = Serial.available();
 if (numChar>buffsize) {
 numChar=buffsize;
 }
 while (numChar--) {
 buffer[index++] = Serial.read();
 }
 splitString(buffer); // Process Serial Packet
 }
 }

//----[ SubRoutines ]----------------------------------------------------

void splitString(char* data) {
 // also from "Serial Controlled Mood Lamp" example

if (debug) {
 Serial.print("Data entered: ");
 Serial.println(data);
 }

// Sequentially De-Tokenize the Serial Commands received
 char* parameter;
 parameter = strtok (data, " ,");
 while (parameter != NULL) {
 // Pass result to parseCMD for each Command received
 parseCMD(parameter);
 // remove processed commands from the list
 parameter = strtok (NULL, " ,");
 }

// Clear the text and serial buffers
 for (int x=0; x<buffsize; x++) {
 buffer[x]='\0';
 }
 Serial.flush();
 }

//=======================================================================
 void parseCMD(char* data) {
 // Flexible, easily expanded Command Parser
 // based on "Serial Controlled Mood Lamp" example
 // *** Marvelous coding by Mike MCRoberts

//--[gear]---------------------------------------
 if ((data[0] == 'G') || (data[0] == 'g')) {
 // Have command, now get Argument "value" while removing whitespace
 int ArgVal = strtol(data+1, NULL, 10);
 // then limit the results to what we expect for this command
 ArgVal = constrain(ArgVal,0,8);
 sevenSegWrite(ArgVal);

if (debug) {
 Serial.print("Gear is set to: ");
 Serial.println(ArgVal);
 }
 }

//--[shift light]--------------------------------
 if ((data[0] == 'S') || (data[0] == 's')) {
 int ArgVal = strtol(data+1, NULL, 10);
 ArgVal = constrain(ArgVal,0,1);
 digitalWrite(shiftlight,ArgVal);

if (debug) {
 Serial.print("SHIFT is set to: ");
 Serial.println(ArgVal);
 }
 }

//--[reset]--------------------------------------
 if ((data[0] == 'C') || (data[0] == 'c')) {
 int ArgVal = strtol(data+1, NULL, 10);
 ArgVal = constrain(ArgVal,0,1);

sevenSegWrite(8);
 shiftWrite(0x00);

if (debug) {
 Serial.print("Clear Outputs");
 }
 }

//--[rpm bar graph]-----------------------------
 if ((data[0] == 'R') || (data[0] == 'r')) {
 int ArgVal = strtol(data+1, NULL, 10);
 ArgVal = constrain(ArgVal,0,8);

shiftWrite(bargraph[ArgVal]);

if (debug) {
 Serial.print("RPM is set to: ");
 Serial.println(ArgVal);
 }
 }

} // End parseCMD Loop

//=======================================================================
 void sevenSegWrite(byte digit) {
 byte pin = GIstartpin;
 for (byte segCount = 0; segCount < 7; ++segCount) {
 digitalWrite(pin, seven_seg_digits[digit][segCount]);
 ++pin;
 }
 }
 //=======================================================================
 void shiftWrite(byte Rdata){
 // prepare the register for data
 digitalWrite(latchPin, LOW);
 // shift out the bits:
 shiftOut(dataPin, clockPin, MSBFIRST, Rdata);
 //Set the latch pin high to enable the outputs
 digitalWrite(latchPin, HIGH);
 }

Weather Shield

I grew tired of working with a solderless breadboard and was worrying about the wires falling out of the makeshift  INSIDE portion of the DALLAS 1-wire weather station circuit I am working on (also the interface to other assorted 1-wire stuff outside) so I decided it was time for a PCB. The board contains a 2-wire BMP085 pressure sensor BOB and level converter… as well as a 1-wire temperature sensor.  This board contains the 1-wire bus connection (RJ45) to the outside world.

 

Here is the design I came up with:

Current Weather Station

Arduino Mega

AAG One Wire Weather Instrument Series 2. (Wind Speed, Temperature, Wind Direction)  DS18B20 temperature, DS2423 (wind speed) DS2450(wind vector)

Hobby Boards: Humidity/Temperature Board – Built from my own parts

Rain Gauge (See my post about it)

BMP085 – Pressure Sensor

Internal Temperature via DS18B20

1-Wire Power Injector (see my “how to make a PCB guide):

In progress: COSM upload – nope.

FAIL:  Adding COSM/PACHUBE support ran me out of working RAM… so project for upload of data is scrapped at the moment.

Barometric Pressure

While looking at low cost pressure sensors in the Mouser Electronics catalog, I located the FREESCALE MPXAZ6115A as a possible sensor for my project. The sensor has the following statistics;

Device: MPX6115, MAX PSI 16.7, MAX kPa 115.

Since barometric pressure here hovers at around 100kPa or so, this sensor would do just fine. The analog output of the sensor is relative to the min/max pressure range of the sensor.

According to my initial tests, the sensor would output about 4.06 volts at 100kPa.

The built-in analog input on the Arduino would also keep the circuit simple and after a few tests I was able to determine the offset value I needed to get correct readings for the localized barometric pressure.
In my case… testing showed that the magic number is 0.13.

// Nominal Transfer Value:
// Vout = VS x (0.009 x P – 0.095)
// ± (Pressure Error x Temp. Factor x 0.009 x VS)
// VS = 5.1 ± 0.25 Vdc

float Vin;
float P;

void setup()
{
Serial.begin(9600);
}

void loop()
{
Vin = (5.0/1024.0) * analogRead(0);
Vin = Vin + 0.13;     // Offset Adjustment
 Serial.print(Vin);
 Serial.println(" Volts");

P=((Vin/5.0)+0.095)/0.009;
 Serial.print(P);
 Serial.println(" kPa");

Vin = (P * 0.2952999);
 Serial.print(Vin);
 Serial.println(" Inches of Mercury");
delay(2000);
}

I’m using a LADYADA Boarduino on a solder-less breadboard for testing. The sensor hookup is dead simple with only one exception that makes it tricky. The part I selected is designed to be surface mounted.

I decided to create a carrier board using the board layout software I prefer called SprintLayout from ABACOM in Germany. Other than 5V power and ground connections, the Vout from the carrier board goes directly to the Arduino Analog(0) pin.

To create the PCB board, I use the GOOTIE toner transfer method to apply the layout on the PCB for etching. (google search “gootie PCB” for more info)

Having developed a dislike for the chemical etchant that Radio Shack sells; Ferric Chloride, I have also adopted the etchant that
Gootie describes.

It is based on the swimming pool chemical Muratic Acid and Hydrogen Peroxide in a 1 to 2 ratio. It’s fast, non-opaque and does not require heating or excessive agitation.

Note: I also recently picked up a used GBC Creative Laminator at the local Goodwill for $14.00. It does an excellent job of applying the toner to the copper on the PCB to be etched. Using an hand iron was OK, but the results were not always predictable.

My method of making PCB’s at home.

 

Here is the Layout:

Legacy Recovery: Arduino and Parallax SHT-11 BoB

July 3, 2008

As a part of my ongoing project and seemingly never ending interest in what’s going on outside my window, I purchased a a PARALLAX humidity and temperature sensor.  Basically, the Parallax part is a surface mount  Sensirion Temperature/Humidity Sensor nicely mounted on a PC board that has 8-PIN DIL pin out for insertion into a solder-less breadboard.

It’s available from MOUSER and from PARALLAX directly.

To get it working, the circuit itself is dead easy.  The Parallax part has additional SMD pullups and capacitors right in the 8-pin DIL package so we are only dealing with a few wires.  I don’t even need to really show a schematic… the details are in the code.

The code is not really my own creation at all.  It is a collection of good ideas from others who have already dealt with this device.

   
//==========================================================================//
//                                                                          //
//   SHT-11 Humidity & Temperature      Version 1.00     December 2008      //
//                                                                          //
//   NOTICE:  This is for ARDUINO IDE VERSION 18!                           //
//   Some methods used are no longer needed.                                //
//                                                                          //
//   Written for the Arduino ATmega168 Diecimila and installed and tested   //
//   on December 12,2008                                                    //
//                                                                          //
//   Multiple Internet references were used, combined and modified          //
//   for this example, such as Arduino forums and nuelectronics.com         //
//                                                                          //
//==========================================================================//
// Devices Used:                                                            //
// Boarduino:  USB Powered - Diecimila                                      //
// http://www.ladyada.net/make/boarduino/index.html                         //
// The Boarduino is a Solderless Breadboard compatible Arduino              //
//                                                                          //
// Parallax Sensirion SHT-11 module                                         //
// http://www.parallax.com   (Look for    "SensirionDocs.pdf" )             //
//                                                                          //
//                  The parallax module is a breadboard compatible carrier  //
//                  with the SMD sensor installed by parallax               //
//                  NOTE: Different Pinout than SMD sensor from Sensirion   //
//==========================================================================//
// Notes:                                                                   //
//                                                                          //
// The Parallax module contains built-in Pullup and  Data Pin resistors     //
// Sensor Carrier     Boarduino                                             //
// Data Pin 1   --   Arduino pin 10                                         //
// Clock Pin 3  --   Arduino pin 11                                         //
// Vss Pin 4    --   Arduino GND                                            //
// Vdd Pin 8    --   Arduino 5V                                             //
//==========================================================================//

//==========================================================================//
//                            Preamble                                      //
//==========================================================================//
#define  LED 13

#define  T_CMD  0x03                // See Sensirion Data sheet
#define  H_CMD  0x05
#define  R_STAT 0x07
#define  W_STAT 0x06
#define  RST_CMD 0x1E

//==========================================================================//
// SHT11 Sensor Coefficients from Sesirion Data Sheet
const float C1=-4.0;               // for 12 Bit
const float C2= 0.0405;            // for 12 Bit
const float C3=-0.0000028;         // for 12 Bit
//const float D1=-40.0;              // for 14 Bit @ 5V
//const float D2=0.01;               // for 14 Bit DEGC
const float T1=0.01;               // for 14 Bit @ 5V
const float T2=0.00008;            // for 14 Bit @ 5V
//==========================================================================//
// Sensor Variables
int shtClk   =  11;                // Clock Pin
int shtData  =  10;                // Data Pin
int ioByte;                        // data transfer global -  DATA
int ackBit;                        // data transfer glocal  - ACKNOWLEDGE
float retVal;                      // Raw return value from SHT-11
float temp_degC;                   // working temperature
float temp_degF;                   // working tempeature
float r_temp;                      // raw working temp
float r_humid;                     // Raw working humidity
float dew_point;
float dew_pointF;
//==========================================================================//
// coding variables
int dly;
int timewait;
byte bitmask;

//==========================================================================//
//                                                                          //
//                            Code Body                                     //
//                                                                          //
//==========================================================================//

void setup()

{
    
    
    pinMode(shtClk, OUTPUT);        // Initialize the pins
    digitalWrite(shtClk, HIGH);     // Clock
    pinMode(shtData, OUTPUT);       // Data
    pinMode(LED, OUTPUT);           // LED
    Serial.begin(9600);             // open serial Port for 9600 Baud
    
    Serial.println("Resetting Sensor..");
    SHT_Connection_Reset();
    
    // Fast Flash LED to say we are ready
    digitalWrite(LED, HIGH);
    delay(500);
    digitalWrite(LED, LOW);
    delay(500);
    digitalWrite(LED, HIGH);
    delay(500);
    digitalWrite(LED, LOW);
    //-----------------------------
    
    Serial.println("Starting Temperature & Humidity reading every 5 seconds.");
    
}


//==========================================================================//
void loop()
//==========================================================================//

{
 // SHT-11 Get Temperature
    
    Serial.println("------------------------------------------------------------------------------");

    SHT_Measure(T_CMD);                    // retVal = Temperature reading
    r_temp = retVal;
    
    temp_degC = SHT_calc_tempC( retVal);  // Convert to Celcius
    Serial.print("Temperature: ");
    serialPrintFloat(temp_degC);
    Serial.print("C");
    Serial.print('\t');
    
    temp_degF = SHT_calc_tempF( retVal);  // Convert to Fahrenheit
    Serial.print("| Temperature: ");;
    serialPrintFloat(temp_degF);
    Serial.print("F");
    Serial.print('\t');
    Serial.println();

    // SHT-11 Get Humidity
    SHT_Measure(H_CMD);                     // retVal = humidity reading
    r_humid = retVal;                       // Store raw humidity value
    Serial.print("Humidity: ");

    // Linear conversion
    float rh_lin = C3 * retVal * retVal + C2 * retVal + C1;

    // Temperature compensated RH
    float rh_true = (temp_degC * (T1 + T2 * retVal) + rh_lin);
    if(rh_true>100)rh_true=100;       // deal with rh being outside
    if(rh_true<0.1)rh_true=0.1;       // a physical possible range
    serialPrintFloat(rh_true);
    Serial.print("%");
    Serial.print('\t');

    // calculate Dew Point
    dew_point=calc_dewpoint(rh_true,temp_degC); //calculate dew point
    dew_pointF = 9 * dew_point/5 + 32;
    
    Serial.print("| Dew point:   ");
    serialPrintFloat(dew_point);
    Serial.print("C");
    Serial.print("   ");
    serialPrintFloat(dew_pointF);
    Serial.print("F");
    
    Serial.println();
    
    // Slow Flash activity LED and create pause between scans
    //  ...in this case, 5 secs)
    timewait = 0;
    while (timewait < 5)
    {
        
        digitalWrite(LED, HIGH);
        delay(500);
        digitalWrite(LED, LOW);
        delay(500);
        timewait++;
        
    }
}


//--[ Subroutines ]---------------------------------------------------
void SHT_Write_Byte(void)
{

    pinMode(shtData, OUTPUT);
    shiftOut(shtData, shtClk, MSBFIRST, ioByte);
    pinMode(shtData, INPUT);
    digitalWrite(shtData, LOW);
    digitalWrite(shtClk, LOW);
    digitalWrite(shtClk, HIGH);
    ackBit = digitalRead(shtData);
    digitalWrite(shtClk, LOW);
    
}

//--------------------------------------------------------------------
int shiftIn()
{

    int cwt;
    cwt=0;
    bitmask=128;
    while (bitmask >= 1)
    {
        
        digitalWrite(shtClk, HIGH);
        cwt = cwt + bitmask * digitalRead(shtData);
        digitalWrite(shtClk, LOW);
        bitmask=bitmask/2;
        
    }
    
    return(cwt);
    
}


//--------------------------------------------------------------------
void SHT_Read_Byte(void)
{

    ioByte = shiftIn();
    digitalWrite(shtData, ackBit);
    pinMode(shtData, OUTPUT);
    digitalWrite(shtClk, HIGH);
    digitalWrite(shtClk, LOW);
    pinMode(shtData, INPUT);
    digitalWrite(shtData, LOW);
    
}

//--------------------------------------------------------------------
void SHT_Start(void)
{
    

    // generates a sensirion specific transmission start
    // This where Sensirion is not following the I2C standard
    //       _____         ________
    // DATA:      |_______|
    //           ___     ___
    // SCK : ___|   |___|   |______
    
    digitalWrite(shtData, HIGH);     // Data pin high
    pinMode(shtData, OUTPUT);
    digitalWrite(shtClk,  HIGH);     // clock high
    digitalWrite(shtData,  LOW);     // data low
    digitalWrite(shtClk,   LOW);     // clock low
    digitalWrite(shtClk,  HIGH);     // clock high
    digitalWrite(shtData, HIGH);     // data high
    digitalWrite(shtClk,  LOW);      // clock low
    
}


//--------------------------------------------------------------------
void SHT_Connection_Reset(void)
{

// Connection reset: DATA-line=1 and at least 9 SCK cycles followed by start
// 16 is greater than 9 so do it twice
//      _____________________________________________________         ________
// DATA:                                                     |_______|
//          _    _    _    _    _    _    _    _    _        ___    ___
// SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______|   |__|   |______
    
    shiftOut(shtData, shtClk, LSBFIRST, 0xff);
    shiftOut(shtData, shtClk, LSBFIRST, 0xff);
    SHT_Start();
    
    
}


//--------------------------------------------------------------------
void SHT_Soft_Reset(void)
{

    SHT_Connection_Reset();
    
    ioByte = RST_CMD;
    ackBit = 1;
    SHT_Write_Byte();
    delay(15);
    
}


//--------------------------------------------------------------------
void SHT_Wait(void)
{

    // Waits for SHT to complete conversion
    delay(5);
    dly = 0;
    while (dly < 600)
    {
        
        if (digitalRead(shtData) == 0) dly=2600;
        delay(1);
        dly=dly+1;
        
    }

    
}


//--------------------------------------------------------------------
void SHT_Measure(int SHT_CMD)
{
    
    //--------------------------------------------------------------------
    SHT_Soft_Reset();
    SHT_Start();
    ioByte = SHT_CMD;
    
    SHT_Write_Byte();          // Issue Command
    SHT_Wait();                // wait for data ready
    ackBit = 0;               // read first byte
    
    SHT_Read_Byte();
    int msby;                  // process it as Most Significant Byte (MSB)
    msby = ioByte;
    ackBit = 1;
    
    SHT_Read_Byte();          // read second byte
    retVal = msby;           // process result to combine MSB with LSB
    retVal = retVal * 0x100;
    retVal = retVal + ioByte;
    if (retVal <= 0) retVal = 1;
    
}


//--------------------------------------------------------------------
int SHT_Get_Status(void)
{
    
    //--------------------------------------------------------------------
    SHT_Soft_Reset();
    SHT_Start();
    ioByte = R_STAT;
    
    SHT_Write_Byte();
    SHT_Wait();
    ackBit = 1;
    
    SHT_Read_Byte();
    return(ioByte);
    
}


//--------------------------------------------------------------------
int SHT_calc_tempC( float w_temperature)
//--------------------------------------------------------------------

{
    
    // calculate temp with float
    float temp1;
    
    // Per the data sheet, these are adjustments to results
    temp1 = w_temperature * 0.01;  // divide by 100
    temp1 = temp1 - (int)40;       // Subtract 40
    return (temp1);
    
}


//--------------------------------------------------------------------
int SHT_calc_tempF( int w_temperature)
{

    // calculate temp with float
    int temp1;
    temp1 = w_temperature * 0.018;
    temp1 = temp1 - (int)40;
    return (temp1);
    
}


//--------------------------------------------------------------------
float calc_dewpoint(float h,float t)
// calculates dew point
// input:   humidity [%RH], temperature [°C]
// output:  dew point [°C]

{
    float logEx,dew_point;
    logEx=0.66077+7.5*t/(237.3+t)+(log10(h)-2);
    dew_point = (logEx - 0.66077)*237.3/(0.66077+7.5-logEx);
    return dew_point;
    
}


//--------------------------------------------------------------------
void serialPrintFloat( float f)
{

    // print results properly with float decimal value
    int i;
    Serial.print((int)f);
    Serial.print(".");
    i = (f - (int)f) * 100;
    Serial.print( abs(i) );
    
}