Sunday, July 26, 2015

The Raspberry Pi and a Neo-6M GPS


Previously I have posted tutorials on how to interface a GPS to an Arduino, but this time I wanted to use a Raspberry Pi. Here is an easy and inexpensive Instructable I have posted, and expansion into other projects will follow.

http://www.instructables.com/id/Raspberry-Pi-the-Neo-6M-GPS/

The GPS module is less than $20


Thursday, July 9, 2015

Arduino ACS712 Current Sensor

The ACS712 is a very easy to use bi-directional current sensor. It comes in 5, 20, and 30 amp versions, and there's only one line of code that needs to be changed depending on which unit you have. This sensor outputs a small voltage that increases with current flowing through the sensor. It isolates the current being monitored from the Arduino, so there's no risk to the Arduino. Most breakout boards come with the needed resistors and caps already installed, so physical hookup consists of +5vdc, gnd, and analog out to one of the Arduino analog inputs. The polarity sensitive current sense pins connect in series with one of the power wires to the device being monitored (either production, or consumption).

In the picture above, looking at the lower right image, the left terminal is the more positive terminal, and the right terminal is the more negative terminal. If you reverse these, you will see negative current readings when you expect positive current readings.

Parts needed:
Arduino UNO
ACS712 5a (20a, or 30a options)

ACS712 Datasheet



Code:

/*
Measuring Current Using ACS712
*/
const int analogIn = A0;
int mVperAmp = 185; // use 185 for 5A Module, 100 for 20A Module and 66 for 30A Module
int RawValue= 0;
int ACSoffset = 2500; 
double Voltage = 0;
double Amps = 0;

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

void loop(){
 
 RawValue = analogRead(analogIn);
 Voltage = (RawValue / 1023.0) * 5000; // Gets you mV
 Amps = ((Voltage - ACSoffset) / mVperAmp);
 
 
 Serial.print("Raw Value = " ); // shows pre-scaled value 
 Serial.print(RawValue); 
 Serial.print("\t mV = "); // shows the voltage measured 
 Serial.print(Voltage,3); // the '3' after voltage allows you to display 3 digits after decimal point
 Serial.print("\t Amps = "); // shows the voltage measured 
 Serial.println(Amps,3); // the '3' after voltage allows you to display 3 digits after decimal point
 delay(2500); 
 
}

Additional reading:
http://henrysbench.capnfatz.com/henrys-bench/acs712-current-sensor-user-manual/

Thursday, July 2, 2015

Solar Powered Arduino Projects

Do you have a wireless project, but wonder how to keep it powered? Wonder no more, as we demonstrate a solar powered / charged Arduino solution.

Parts:

Arduino UNO
Adafruit Power Boost 500 Shield
Adafruit 2000 mAh LiPo battery
Adafruit RGB I2C LCD
Sunkingdom 5w PV panel

The solar panel keeps the Power Boost 500 LiPo charged and powering the Arduino and attached sensors. The Power Boost 500 shield manages the charging of the LiPo battery, and acts as a UPS, maintaining power during periods of sun, and no sun. It provides up to 1 amp of 5v power to your project, which is plenty for most remote sensor projects.

Code for this project (and more details on the Power Boost 500) can be found at http://arduinotronics.blogspot.com/2015/04/arduino-ups-battery-shield.html

Wireless WiFi Weather Server - http://arduinotronics.blogspot.com/2015/06/wifi-weather-web-server.html



Wednesday, June 10, 2015

Jameco Poll - Who are the electronic hobbyists of America?

Below is an excerpt of a poll run by Jameco Electronics

Who are we? Read the whole article and see if you are a match. I personally am in the greater than 35 years, as I started around 9 years of age.

Who are the electronic hobbyists of America?

Nerds or not, more than half of the Great American Electronic Hobbyists Census participants reported that their first experience with electronics involved taking something apart and nearly all reported having soldered before the age of 18. After their initial experience with the soldering iron, nearly half of all hobbyists continued on with their electronics education, making electronics both their avocation and vocation.

A hobby that most likely started during the teenage years (or earlier) has continued to pique interest. The average hobbyist has 35 years of electronics under their belt and an additional 25% have been working with electronics for 50 or more years. It was interesting that almost half of the participants received some sort of formal training in electronics, but also that just as many were self-taught.
When it comes to a reading preference amongst our participants, 42% prefer reading a technical publication over other types of publications, while 27% choose to read news. When we asked our hobbyists which other hobbies they enjoy, it was clear that electronics knowledge and skills play a role in more than just their electronics hobby; 10% reported that music was their second most favorite hobby, 9% told us they prefer woodworking second to electronics (which may or may not correlate to 83% reporting they’ve used an ax or saw within the past year) and 6.4% of participants named computing as their second favorite hobby.

It was somewhat astonishing to learn that the majority of participants (practically 98%) were male despite the fact that 19% of those graduating with bachelor degrees in engineering are women. This may have a correlation with time restrictions between work and family life; we discovered that the average age of our participating hobbyist is 56.

Monday, June 8, 2015

The Arduino Powered Lighthouse

I was helping a friend build a 3' lighthouse, and he felt it could use some "animation". I suggested a Arduino controlled beacon. We didn't want to go to the hassle of building a motorized unit, so I designed a simulated rotating beacon. I picked a 3 watt white LED, but since the Arduino can't control that much current by itself, I used a IRL520 MOSFET. A MOSFET requires a 10k resistor from the gate to ground to turn it off when it's not active. I connected it to a PWM pin, so I could control the brightness of the LED.

Warning! A 3w LED can pull about 700ma of current at 3.3v, so even though we are only PWM'ing at 50% (except for that 50ms 100% pulse), you should have a separate 1a 3.3v supply.

The sketch below fades the LED in and out, and gives a super bright flash between the ramp up and ramp down, simulating the affect of being in the direct line of the bulb on a rotating beacon,

Enjoy!




int cycle=30;
int strobe=cycle*10; // calculate strobe delay
int maxFade=100; // maximum brightness before strobe
int ledPin = 11;    // MOSFET connected to digital pin 11

void setup() {
  // nothing happens in setup
}

void loop() {
  // fade in from min to max in increments of 2 points:
  for (int fadeValue = 0 ; fadeValue <= maxFade; fadeValue += 2) {
    // sets the value (range from 0 to maxFade):
    analogWrite(ledPin, fadeValue);
    // wait for "cycle" milliseconds to see the dimming effect
    delay(cycle);
  }
analogWrite(ledPin, 255); // simulate a rotating beacon catching your eye
delay(strobe); // hold full brightness for strobe delay
analogWrite(ledPin, maxFade);
  // fade out from maxFade to min in increments of 2 points:
  for (int fadeValue = maxFade ; fadeValue >= 0; fadeValue -= 2) {
    // sets the value (range from 0 to maxFade):
    analogWrite(ledPin, fadeValue);
    // wait for "cycle" milliseconds to see the dimming effect
    delay(cycle);
  }
}



Saturday, June 6, 2015

Arduino Hx711 Digital Scale

After finding a broken scale in the trash at work, I decided to remove the load cell and build a digital scale with an Arduino. The output of the load cell is too minute for an Arduino to read on it's own, so I picked up a <$5 amplifier module online to convert the reading into a signal the Arduino can read. The Hx711 module is a 24 bit ADC, which offers high resolution and amplification. It's also designed for scale / load cell applications, so talking to it requires a minimum of code.

Connections are fairly simple. You will need a 4 wire load cell, and those typically have Green, White, Red, and Black wires.

Connect as follows:
Red: E +
White: A +
Green: A -
Black: E -

B- & B+ could be used for another load cell, but we are not using these.

On the other side of the module:

GND: Arduino GND
DT: Arduino A2 (can change this in code)
SCK: Arduino A3 (can change this in code)
VCC: Arduino +5

Library:

You will need to download the library files (the library files at dfrobot will not install properly using the add library function, these will).

Per the instructions at dfrobot, you may have to adjust a value in the Hx711.h file in the library to zero your scale. Mine did not need that.

Code:

/* sample for digital weight scale of hx711
 * library design: Weihong Guan (@aguegu)
 * library host on
 *https://github.com/aguegu/ardulibs/tree/3cdb78f3727d9682f7fd22156604fc1e4edd75d1/hx711
 */

// Hx711.DOUT - pin #A2
// Hx711.SCK - pin #A3

#include <Hx711.h>
Hx711 scale(A2, A3);

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

void loop() {
  Serial.print(scale.getGram(), 1);
  Serial.println(" g");
  delay(200);
}





Thursday, June 4, 2015

Arduino Westminster Chimes Door Bell

I was repairing a Heath Zenith SL-6180 wireless doorbell, in the process, figured out how to manually trigger the bells without using the remote. I then thought, why not have an arduino trigger the bells based on motion sense, floor pad sensor, or pushbutton. The door bell I'm using plays a very nice version of Westminster Chimes. Open it up, find the transistor labeled Q5 on the board and attach a wire to the base (center pin) to an arduino output. Connect a wire from battery negative to Arduino negative. When you want the chimes to ring, pulse the pin you have connected to Q5 - digitalWrite(pin, HIGH);

Other applications could be a audio notification when you get an email, a tweet, or completion of a task.

Monday, June 1, 2015

Wifi Weather Web Server

It's Alive, It's Alive. Ok, sounds better if done with a Dr. Frankenstein accent, but the Arduino WiFi wireless weather Server is alive. Starting with a Arduino UNO, we then stacked a Arduino WiFi shield, a adafruit Lithium Polymer battery shield, and a Sparkfun Protoshield with a Embedded Adventures BME280 breakout and a 3.3v - 5v level shifter. A 5v solar panel is on it's way to keep this charged,

Arduino UNO
Arduino WiFi
Adafruit LIPO
Sparkfun Protoshield
Embedded Adventures BME280 (schematics)
Embedded Adventures Level Shifter

You can see it in real time at http://sspence65.ddns.net (be patient)

Code (Video below)
#include <SPI.h>
#include <WiFi.h>


#include <BME280_MOD-1022.h>

#include <Wire.h>

IPAddress dns(192, 168, 254, 254);
IPAddress ip(192, 168, 254, 16);  
IPAddress gateway(192, 168, 254, 254); 
IPAddress subnet(255, 255, 255, 0); 

float temp, humidity,  pressure, pressureMoreAccurate, tempF, inHg, rH;
double tempMostAccurate, humidityMostAccurate, pressureMostAccurate;


char ssid[] = "your ssid";      // your network SSID (name)
char pass[] = "your password";   // your network password
int keyIndex = 0;                 // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;

WiFiServer server(80);

// print out the measurements

void printCompensatedMeasurements(void) {

char buffer[80];

  temp      = BME280.getTemperature();
  humidity  = BME280.getHumidity();
  pressure  = BME280.getPressure();
  
  pressureMoreAccurate = BME280.getPressureMoreAccurate();  // t_fine already calculated from getTemperaure() above
  
  tempMostAccurate     = BME280.getTemperatureMostAccurate();
  humidityMostAccurate = BME280.getHumidityMostAccurate();
  pressureMostAccurate = BME280.getPressureMostAccurate();

  Serial.print("Temperature  ");
 
  tempF = tempMostAccurate * 1.8 + 32.0;
  Serial.print(tempF);
 
  Serial.print(" ");
  Serial.print(char(176));
  Serial.println("F");
  
  Serial.print("Humidity     ");
 
  rH = humidityMostAccurate;
  Serial.print(rH);
  Serial.println(" %");

  Serial.print("Pressure     ");
 
  inHg = pressureMostAccurate * 0.0295299830714;
  Serial.print(inHg, 2);
  Serial.println(" in. Hg");
}


void setup() {
  Wire.begin();
  
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if ( fv != "1.1.0" )
    Serial.println("Please upgrade the firmware");

  // attempt to connect to Wifi network:

  
  WiFi.config(ip, dns, gateway, subnet); 
  
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }
  server.begin();
  // you're connected now, so print out the status:
  printWifiStatus();
}


void loop() {
  
  uint8_t chipID;
  
  chipID = BME280.readChipId();
  
  // find the chip ID out just for fun
  //Serial.print("ChipID = 0x");
  //Serial.print(chipID, HEX);
  
 
  // need to read the NVM compensation parameters
  BME280.readCompensationParams();
  
  // Need to turn on 1x oversampling, default is os_skipped, which means it doesn't measure anything
  BME280.writeOversamplingPressure(os1x);  // 1x over sampling (ie, just one sample)
  BME280.writeOversamplingTemperature(os1x);
  BME280.writeOversamplingHumidity(os1x);
  
  // example of a forced sample.  After taking the measurement the chip goes back to sleep
  BME280.writeMode(smForced);
  while (BME280.isMeasuring()) {
    Serial.println("Measuring...");
    delay(50);
  }
  Serial.println("Done!");
  
  // read out the data - must do this before calling the getxxxxx routines
  BME280.readMeasurements();
  
  // Example for "indoor navigation"
  // We'll switch into normal mode for regular automatic samples
  
  BME280.writeStandbyTime(tsb_0p5ms);        // tsb = 0.5ms
  BME280.writeFilterCoefficient(fc_16);      // IIR Filter coefficient 16
  BME280.writeOversamplingPressure(os16x);    // pressure x16
  BME280.writeOversamplingTemperature(os2x);  // temperature x2
  BME280.writeOversamplingHumidity(os1x);     // humidity x1
  
  BME280.writeMode(smNormal);
   
  while (1) {
    
    
    while (BME280.isMeasuring()) {


    }
    
    // read out the data - must do this before calling the getxxxxx routines
    BME280.readMeasurements();
    printCompensatedMeasurements();
    
    delay(2000); // do this every 5 seconds
    Serial.println();
  
  
  // listen for incoming clients
  WiFiClient client = server.available();
  if (client) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          // output the value of each sensor

            client.print("Temperature ");
            client.println(tempF);
            client.print("&deg;");
            client.print("F");
            client.println("<br />");
            client.print("Humidity ");
            client.println(rH);
            client.print(" %");
            client.println("<br />");
            client.print("Pressure ");
            client.println(inHg);
            client.print(" in. Hg");
            client.println("<br />");
          
          client.println("</html>");
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);

    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  }
}


}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}



Upgrading Arduino WiFi Shield Firmware

I have a couple of new wifi projects I'm working on, and was getting the message to upgrade my firmware on the WiFi shield, as well as the browser was not able to load the web page on the Arduino. I've tried upgrading firmware before, with unhappy results, as the firmware files on Github (where most of the instructionals send you) were defective and bricked my shield. I just finished upgrading 3 shields, including the one that was bricked, so I'm confident these instructions work.

How do you know if you have a problem?

The following code in the example wifi webserver sketch will send a message to the Serial Monitor that it's time for a firmware upgrade:


  String fv = WiFi.firmwareVersion();
  if ( fv != "1.1.0" )
    Serial.println("Please upgrade the firmware");

If it is out of date, you'll need a couple of things:


  • USB cable with mini-B plug (Playstation3) not micro-B (Kindle).
  • Atmel Flip Software
  • wifi firmware files (\libraries\WiFi\extras\binary - no need to download) 

Find the jumper on your wifi shield (should be disabled) and enable it (before plugging in the cable).

Plug the mini-USB cable into the wifi shield. I recommend having the WiFi shield plugged into a unpowered Arduino to prevent static issues. Plug the other end of the mini-USB into your computer.

Set your path to include the directory where batchisp.exe (from the Flip install) is located. Mine happened to be C:\Program Files (x86)\Atmel\Flip 3.4.7\bin

To do this, just open a command line windows and type:

path=%path%;C:\Program Files (x86)\Atmel\Flip 3.4.7\bin

the cd to the folder where your wifi firmware files are located.

cd yourarduinofolder\libraries\WiFi\extras\binary

in the command line window, enter:

batchisp.exe -device AT32UC3A1256 -hardware usb -operation erase f memory flash blankcheck loadbuffer wifi_dnld.elf program verify start reset 0

you should see the following:


Shield responds with solid Blue LED.
Press the shield reset button.  Blue LED extinguishes.
Unplug the mini-USB cable and plug it back in again.

Now type the following in the command line window:

batchisp.exe -device AT32UC3A1256 -hardware usb -operation erase f memory flash blankcheck loadbuffer wifiHD.elf program verify start reset 0

you should see the following:


Press the Shield reset button.
Remove the short from J3
Unplug the micro-USB cable

Now when you upload the wifi server example, you will no longer get the out of date firmware message, and your web browser will be able to connect to the arduino ip address shown in the serial monitor.

Thanks to the instructions at http://mssystems.emscom.net/helpdesk/knowledgebase.php?article=50 which helped greatly.




Wednesday, May 27, 2015

555 Timer Projects

Why did I order Fifty 555 bipolar timers? Because they were $5.50 with free shipping. Now what do I do with them?

  • Monostable mode: in this mode, the 555 functions as a "one-shot". Applications include timers, missing pulse detection, bouncefree switches, touch switches, frequency divider, capacitance measurement, pulse-width modulation (PWM) etc
  • Astable - free running mode: the 555 can operate as an oscillator. Uses include LED and lamp flashers, pulse generation, logic clocks, tone generation, security alarms, pulse position modulation, etc.
  • Bistable mode or Schmitt trigger: the 555 can operate as a flip-flop, if the DIS pin is not connected and no capacitor is used. Uses include bouncefree latched switches, etc.

Here are some ideas! -

50 555 Circuits

http://www.555-timer-circuits.com/

DIY Electric Fence

PWM Motor Driver and LED dimmer



Friday, May 22, 2015

Perfuino, the Arduino for Prototypers

Yes, it's another barebones Arduino, but the additional prototyping space makes it a unique and very handy board to have. The Atmega328 is socketed, so if you do something crazy, you are back in business for under $5. At a cost of $16, it's a affordable alternative to the commercial clones. It does not include a USB interface, so a FTDI cable for ICSP programmer will be necessary (headers at upper left). Only 3 days left on the kickstarter, so get in fast!

https://www.kickstarter.com/projects/hackarobot/perfuino-uno-build-your-custom-arduino-compatible

Tuesday, May 19, 2015

Ham Radio Shield for Arduino

Would you like a complete 2m / 1.25m / 70cm ham radio that connects like a shield to an Arduino? Can be used with a Raspberry Pi as well. Onboard Lipo charger / controller also powers your Arduino. Make your own TNC / Packet Radio, Repeater, Echo Link node, and more! 200mw, with an optional 10w amplifier. Coming soon! - https://www.hobbypcb.com/products/rs-uv3

The HobbyPCB RS-UV3 radio module is a 144/220/450 MHz FM transceiver board. The RS-UV3 is a low cost transceiver solution for Packet Radio, repeaters, Echolink stations, base station and mobile applications. The RS-UV3 supports multiple interfaces including microphone/speaker, line level audio (soundcard), TTL serial control and Arduino Shield connections. The RS-UV3 has an built-in battery charger and provides conditioned power for the Arduino controller.

Monday, May 18, 2015

Measuring Voltage with an Arduino and an External AREF

The Arduino Uno has 6 analog inputs, designed for measuring a voltage. Other versions of the Arduino can have several more. Voltages are analog, meaning they can have a range of values, versus digital, which only has two, on or off. Whether you are reading a potentiometer, a TMP36 or LM35 temperature sensor, or even the voltage of a battery, these devices output an analog signal. Many devices are strictly in the analog world.

The Arduino is very good at measuring these voltages, as long as they are in the 0-5v range (UNO) or 0-3.3v range on some other models. The issue we run into is that although the 5v is assumed, sometimes it's not 5v. If you have your Arduino plugged into your computer USB, or have a lot of devices connected to your Arduino, that 5v can be as low as 4.8 volts.

Why does this matter? The Arduino analog to digital converter has 1024 steps so 5v / 1024 = 0.0048828125 per step. But if the voltage was 4.8 volts, then each step would equal 0.0046875. Doesn't seem like a big difference does it? With a sensor like the TMP36, that difference could equal several degrees of inaccuracy.

So how do we correct this? Well, powering your Arduino from a 9v source through the barrel connector is a big help, as the onboard voltage regulator will do a good job of enforcing that the INTERNAL reference is really 5v. For real precision, a EXTERNAL reference is best.

We are using a LM4040 precision voltage source from Adafruit, which takes a nominal 5v input, and delivers a precision voltage reference of 2.048 and 4.096 volts, regardless of your supply voltage to the Arduino. By connecting one of these outputs to your AREF pin, and specifying the AREF voltage (verify with your meter), you now can precisely measure a analog signal from 0 - AREF voltage.

If your signal is greater than the AREF voltage, you can use resistors to create a voltage divider to bring it back into range.
http://arduinotronics.blogspot.com/2012/04/voltage-monitor.html

Resources:
https://blog.udemy.com/arduino-voltmeter/
https://learn.adafruit.com/tmp36-temperature-sensor/using-a-temp-sensor
http://tronixstuff.com/2013/12/12/arduino-tutorials-chapter-22-aref-pin/


Here is a sample sketch showing how to use a EXTERNAL reference, like the Adafruit LM4040.

WARNING!
When using AREF, always specify analogReference(EXTERNAL); before doing an analog read, as you could short the internal reference, damaging the Arduino. I recommend you upload this sketch before connecting the AREF pin.

#define aref_voltage 4.096 

int ADCPin = 1; //using A1 input for this sketch
int ADCReading;

void setup(){

  Serial.begin(9600);

  analogReference(EXTERNAL);

}

void loop(){

  ADCReading = analogRead(ADCPin);  
 
  Serial.print("ADC reading = ");
  Serial.print(ADCReading);     // the raw analog reading
 
  // converting that reading to voltage, which is based off the reference voltage
  float voltage = ADCReading * aref_voltage;
  voltage /= 1024.0; 
 
  // print out the voltage
  Serial.print(" - ");
  Serial.print(voltage); Serial.println(" volts");

}

.

Monday, May 11, 2015

Reading a Current Shunt with an Arduino

Current shunts are very popular with the Ham Radio, boating, electric vehicle and solar / wind off grid folks, as they allow them to monitor solar and wind power production, power consumption of devices, and the estimated amp hours left in the battery bank, sort of like a "gas gauge" for your batteries.

See our complete Off Grid Power Monitoring System at http://www.green-trust.org/jmc/

Previous ADS1115 Arduino / Raspberry Pi post!

Unlike the solid state hall effect types, current shunts drop a small voltage across a calibrated resistor, indicating the amps being passed through the shunt. This allows shunts to report massive amounts of current, in excess of a 1000 amps, depending on the design of the shunt.

Common shunts are rated at 50mv, 75mv, and 100mv output at maximum current (do not exceed 66% of name plate current). The Arduino has a few issues with these shunts. Since the maximum output is just 100 millivolts compared to the Arduino's range of 0-5v, it's like trying to read a 5 inch ruler from 10 miles away (worse with the 50mv and 75mv versions). The second issue is the Arduino has a 10 bit analog to digital converter (ADC), so a 100amp / 100mv shunt would have a 4.88 mv per step resolution, or about 5 amps per step (a total of 1024 steps).

We can solve this with a higher bit ADC with an onboard amplifier. We chose a 16 bit ADC that has over 64000 steps (+/- 32768), and up to 16x amplification. This matches a 100mv shunt very well.

The ADC we chose is the adafruit ADS1115. It has 4 single ended channels, or two differential channels. We chose to use differential mode, to eliminate electrical interference (the third issue) in the monitoring circuit, giving us very stable results. This means we can use two shunts per ADS1115. The ADS1115 can have 4 different user selectable I2C addresses, so with only 2 data lines (SCL & SDA), you can monitor up to 8 shunts.

Connections:

Connections are very simple. Adafruit gives a very comprehensive tutorial on connecting and using this sensor for a variety of different purposes, and you can read about it (and download the library) at https://learn.adafruit.com/adafruit-4-channel-adc-breakouts. For our purposes, this is what we needed:

VDD - Arduino +5v
GND to Arduino GND
SCL to Arduino A5
SDA to Arduino A4
ADDR to Arduino GND (one of 4 possible address combinations, see adafruit tutorial for the the others)
A0 to Current Shunt
A1 to Current Shunt




Code:

Although we are using a 100a / 100mv shunt, if you are using a 75mv or 50mv shunt, we added two additional lines in the code you can uncomment depending on which shunt you are using.



#include <Wire.h>
#include <Adafruit_ADS1015.h>

Adafruit_ADS1115 ads;  /* Use this for the 16-bit version */

void setup(void)
{
  Serial.begin(9600);
  
  ads.setGain(GAIN_SIXTEEN);    // 16x gain  +/- 0.256V  1 bit = 0.125mV  0.0078125mV
  
  ads.begin();
}

void loop(void)
{
  int16_t results;
  
  results = ads.readADC_Differential_0_1();  
    
  Serial.print("Amps: "); 
  
  float amps = ((float)results * 256.0) / 32768.0;
  //amps = amps * 1.333; //uncomment for 75mv shunt
  //amps = amps * 2; //uncomment for 50mv shunt
  
  Serial.println(amps); 

  delay(5000);
}


Saturday, May 9, 2015

The New Bosch BME280 (Temp, Humidity, BMP)

Bosch has a new, very accurate all in one sensor chip that does Temperature, Humidity, and Barometric Pressure readings. It's called the BME280. Embedded Adventures has put that chip on a handy breakout board with signal conditioning (MOD-1022) and priced it fairly at $17. It's a 3v I2C unit, so to use it with a Arduino UNO, you will need a bi-directional level shifter, which they also have as the MOD-1003S for an additional $10.

This is the most accurate unit I have found, and is very easy to use. The library and sample code are available on the MOD-1022 page above, and the MOD-1003S level shifter requires no code to use.

There are only 4 wires to connect from the MOD-1022 to the MOD-1003S (VDD -> +3.3v, SCL -> B2), SDA -> B1, Gnd), and 4 wires from the MOD-1003S to the Arduino (+5v, SCL(B2 ->A5), SDA(B1->A4), Gnd). Download and install the library, and upload the example sketch included with the library, and you are on your way (in metric). For US measurements, you will have to convert Celsius to Fahrenheit, and hPa to InHg.

The example sketch communicates with serial defaulting to 115200, so make sure your serial monitor is set accordingly.

See schematic after the code.

Code:

/*

Copyright (c) 2015, Embedded Adventures
All rights reserved.

Contact us at source [at] embeddedadventures.com
www.embeddedadventures.com

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.

- Neither the name of Embedded Adventures nor the names of its contributors
  may be used to endorse or promote products derived from this software
  without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
THE POSSIBILITY OF SUCH DAMAGE.

*/

// BME280 MOD-1022 weather multi-sensor Arduino demo
// Written originally by Embedded Adventures

#include <BME280_MOD-1022.h>

#include <Wire.h>

// Arduino needs this to pring pretty numbers

void printFormattedFloat(float x, uint8_t precision) {
char buffer[10];

  dtostrf(x, 7, precision, buffer);
  Serial.print(buffer);

}


// print out the measurements

void printCompensatedMeasurements(void) {

float temp, humidity,  pressure, pressureMoreAccurate;
double tempMostAccurate, humidityMostAccurate, pressureMostAccurate;
char buffer[80];

  temp      = BME280.getTemperature();
  humidity  = BME280.getHumidity();
  pressure  = BME280.getPressure();
  
  pressureMoreAccurate = BME280.getPressureMoreAccurate();  // t_fine already calculated from getTemperaure() above
  
  tempMostAccurate     = BME280.getTemperatureMostAccurate();
  humidityMostAccurate = BME280.getHumidityMostAccurate();
  pressureMostAccurate = BME280.getPressureMostAccurate();
  Serial.println("                Good  Better    Best");
  Serial.print("Temperature  ");
  printFormattedFloat(temp, 2);
  Serial.print("         ");
  printFormattedFloat(tempMostAccurate, 2);
  Serial.println();
  
  Serial.print("Humidity     ");
  printFormattedFloat(humidity, 2);
  Serial.print("         ");
  printFormattedFloat(humidityMostAccurate, 2);
  Serial.println();

  Serial.print("Pressure     ");
  printFormattedFloat(pressure, 2);
  Serial.print(" ");
  printFormattedFloat(pressureMoreAccurate, 2);
  Serial.print(" ");
  printFormattedFloat(pressureMostAccurate, 2);
  Serial.println();
}


// setup wire and serial

void setup()
{
  Wire.begin();
  Serial.begin(115200);
}

// main loop

void loop()
{

  uint8_t chipID;
  
  Serial.println("Welcome to the BME280 MOD-1022 weather multi-sensor test sketch!");
  Serial.println("Embedded Adventures (www.embeddedadventures.com)");
  chipID = BME280.readChipId();
  
  // find the chip ID out just for fun
  Serial.print("ChipID = 0x");
  Serial.print(chipID, HEX);
  
 
  // need to read the NVM compensation parameters
  BME280.readCompensationParams();
  
  // Need to turn on 1x oversampling, default is os_skipped, which means it doesn't measure anything
  BME280.writeOversamplingPressure(os1x);  // 1x over sampling (ie, just one sample)
  BME280.writeOversamplingTemperature(os1x);
  BME280.writeOversamplingHumidity(os1x);
  
  // example of a forced sample.  After taking the measurement the chip goes back to sleep
  BME280.writeMode(smForced);
  while (BME280.isMeasuring()) {
    Serial.println("Measuring...");
    delay(50);
  }
  Serial.println("Done!");
  
  // read out the data - must do this before calling the getxxxxx routines
  BME280.readMeasurements();
  Serial.print("Temp=");
  Serial.println(BME280.getTemperature());  // must get temp first
  Serial.print("Humidity=");
  Serial.println(BME280.getHumidity());
  Serial.print("Pressure=");
  Serial.println(BME280.getPressure());
  Serial.print("PressureMoreAccurate=");
  Serial.println(BME280.getPressureMoreAccurate());  // use int64 calculcations
  Serial.print("TempMostAccurate=");
  Serial.println(BME280.getTemperatureMostAccurate());  // use double calculations
  Serial.print("HumidityMostAccurate=");
  Serial.println(BME280.getHumidityMostAccurate()); // use double calculations
  Serial.print("PressureMostAccurate=");
  Serial.println(BME280.getPressureMostAccurate()); // use double calculations
  
  // Example for "indoor navigation"
  // We'll switch into normal mode for regular automatic samples
  
  BME280.writeStandbyTime(tsb_0p5ms);        // tsb = 0.5ms
  BME280.writeFilterCoefficient(fc_16);      // IIR Filter coefficient 16
  BME280.writeOversamplingPressure(os16x);    // pressure x16
  BME280.writeOversamplingTemperature(os2x);  // temperature x2
  BME280.writeOversamplingHumidity(os1x);     // humidity x1
  
  BME280.writeMode(smNormal);
   
  while (1) {
    
    
    while (BME280.isMeasuring()) {


    }
    
    // read out the data - must do this before calling the getxxxxx routines
    BME280.readMeasurements();
    printCompensatedMeasurements();
    
    delay(5000); // do this every 5 seconds
    Serial.println();
  }
}