Archive for the ‘electronics’ Category

Arduino tilt sensor using MMA7260Q

Monday, November 3rd, 2008

I’ve playing with the MMA7260Q accelerometer. Following the indications in

I connected X,Y and Z of the MMA7260Q breakout to A0, A1 and A2 of the Arduino. Then, GS1 and GS2 connected to ground to set the range to 1.5g. Ah, and of course, I connected ^SLEEP to VCC.

I managed to put together this piece of code that ouputs the tilt angles ρ(rho) , φ(phi); and Θ(heta) in degrees. I does automatic autozero calibration so before getting sensible results you should tilt the sensor around +/-90 degrees in every axis.

#include <math.h>
#include <float.h>
#include <limits.h>
 
 
int valx = 0;
int valy = 0;
int valz = 0;
 
int xaxis = 0;
int yaxis = 1;   
int zaxis = 2;   
 
float xa=0;
float ya=0;
float za=0;
 
 
 
 
int minx = INT_MAX;
int maxx = 0;
int miny = INT_MAX;
int maxy = 0;
int minz = INT_MAX;
int maxz = 0;
 
int g0x = 0;
int g0y = 0;
int g0z = 0;
 
long time1 = 0;
long time2 = 0;
 
float rho = 0;
float phi = 0;
float theta = 0;
 
 
void setup()
{
  Serial.begin(9600);
  Serial.println("RST\r\n");
  pinMode(xaxis,INPUT);
  pinMode(yaxis,INPUT);
  pinMode(zaxis,INPUT);
  time1=millis();
  time2=millis();
}
 
void loop()
{
 
  valx = analogRead(xaxis);    // read the value from the sensor
  valy = analogRead(yaxis);    // read the value from the sensor
  valz = analogRead(zaxis);    // read the value from the sensor
 
  int pfx = valx;
  int pfy = valy;
  int pfz = valz;
 
  autoZeroCalibration(pfx,pfy,pfz);
 
  int fx = (pfx - g0x);
  int fy = (pfy - g0y);
  int fz = (pfz - g0z);
 
  float ax = fx*(3.3/(1024.0*0.800));
  float ay = fy*(3.3/(1024.0*0.800));
  float az = fz*(3.3/(1024.0*0.800));
 
  //
  rho =   atan(ax/sqrt(pow(ay,2)+pow(az,2)))*(360/(2*3.1592));  
  phi =   atan(ay/sqrt(pow(ax,2)+pow(az,2)))*(360/(2*3.1592));  
  theta = atan(sqrt(pow(ay,2)+pow(ax,2))/az)*(360/(2*3.1592));  
 
  printAngles();
 
}
 
void autoZeroCalibration(int pfx, int pfy, int pfz)
{
    if ((pfx < minx)||(pfy < miny)||(pfz < minz)||(pfx > maxx)||(pfy > maxy)||(pfz > maxz)) {
     // autozero calibration
     if (pfx < minx) minx = pfx;
     if (pfy < miny) miny = pfy;
     if (pfz < minz) minz = pfz;
 
     if (pfx > maxx) maxx = pfx;
     if (pfy > maxy) maxy = pfy;
     if (pfz > maxz) maxz = pfz;
 
     g0x = ((maxx - minx)/2)+minx;
     g0y = ((maxy - miny)/2)+miny;
     g0z = ((maxz - minz)/2)+minz;
 
     printValues();
  }
}
void printFloat(float value, int places) {
   // this is used to cast digits
   int digit;
   float tens = 0.1;
   int tenscount = 0;
   int i;
   float tempfloat = value;
 
   // if value is negative, set tempfloat to the abs value
   // make sure we round properly. this could use pow from  
   //<math.h>, but doesn't seem worth the import
   // if this rounding step isn't here, the value  54.321 prints as  
   //54.3209
 
   // calculate rounding term d:   0.5/pow(10,places)
   float d = 0.5;
   if (value < 0)
     d *= -1.0;
   // divide by ten for each decimal place
   for (i = 0; i < places; i++)
     d/= 10.0;
   // this small addition, combined with truncation will round our  
   // values properly
   tempfloat +=  d;
 
   // first get value tens to be the large power of ten less than value
   // tenscount isn't necessary but it would be useful if you wanted  
   // to know after this how many chars the number will take
 
   if (value < 0)
     tempfloat *= -1.0;
   while ((tens * 10.0) <= tempfloat) {
     tens *= 10.0;
     tenscount += 1;
   }
 
 
   // write out the negative if needed
   if (value < 0)
     Serial.print('-');
 
   if (tenscount == 0)
     Serial.print(0, DEC);
 
   for (i=0; i< tenscount; i++) {
     digit = (int) (tempfloat/tens);
     Serial.print(digit, DEC);
     tempfloat = tempfloat - ((float)digit * tens);
     tens /= 10.0;
   }
 
   // if no places after decimal, stop now and return
   if (places <= 0)
     return;
 
   // otherwise, write the point and continue on
   Serial.print('.');
 
   // now write out each decimal place by shifting digits one by one  
   // into the ones place and writing the truncated value
   for (i = 0; i < places; i++) {
     tempfloat *= 10.0;
     digit = (int) tempfloat;
     Serial.print(digit,DEC);
     // once written, subtract off that digit
     tempfloat = tempfloat - (float) digit;
   }
}
 
void printAngles()
{
   if (millis()-time1 > 1000) {
    time1 = millis();
    Serial.print("rho: ");
    printFloat(rho,3);
    Serial.print(" phi: ");
    printFloat(phi,3);
    Serial.print(" theta: ");
    printFloat(theta,3);
    Serial.print("\r\n");
  }
}
 
void printValues()
{
  if ((millis() - time2) > 800) {
    time2=millis();
    Serial.print("minx: ");
    Serial.print((int)minx,DEC);
    Serial.print(".");
    Serial.print((minx-(int)minx)*1000,DEC);
    Serial.print(" miny: ");
    Serial.print((int)miny,DEC);
    Serial.print(".");
    Serial.print((miny-(int)miny)*1000,DEC);
    Serial.print(" minz: ");
    Serial.print((int)minz,DEC);
    Serial.print(".");
    Serial.print((minz-(int)minz)*1000,DEC);
    Serial.print("\r\n");
 
    Serial.print("maxx: ");
    Serial.print((int)maxx,DEC);
    Serial.print(".");
    Serial.print((maxx-(int)maxx)*1000,DEC);
    Serial.print(" maxy: ");
    Serial.print((int)maxy,DEC);
    Serial.print(".");
    Serial.print((maxy-(int)maxy)*1000,DEC);
    Serial.print(" maxz: ");
    Serial.print((int)maxz,DEC);
    Serial.print(".");
    Serial.print((maxz-(int)maxz)*1000,DEC);
    Serial.print("\r\n");
  }
}

Arduino sleep mode - Waking up when receiving data on the USART

Wednesday, October 15th, 2008

I’ve been playing with the Arduino sleep modes and i wanted to be able to wake up from the sleep when receiving data on the serial port. Mainly, because in my project I’m using the XBee in the API mode and the tricks exposed in http://www.arduino.cc/playground/Learning/ArduinoSleepCode and http://www.libelium.com/squidbee/index.php?title=Save_power_in_SquidBee_-_sleep_mode involve putting Arduino in SLEEP_MODE_PWR_DOWN and using an extra pin on the arduino to monitor the RX pin and detecting LOW.

I didn’t like that much that solution so I started to look into other ways of doing it without using an extra pin and without risk of losing data in the serial interface. Because as I understood it using SLEEP_MODE_PWR_DOWN requires to send first a burst of data to the serial interface in order to wake up the arduino. And it takes a while for the Arduino to become fully functional so that means that you will lose/miss data in the serial interface. That was something that didn’t fit my project.

In order to be able to sleep but without missing serial data I used POWER_MODE_IDLE, a power saving mode that leaves the USART on and then using the functions defined in power.h (you have to use arduino-12 to get power.h) I disabled all other modules that I don’t need to cut down the power consumption. When any data is received in the USART the Arduino will be brought back to normal power mode (USART uses interrupts and any interrupt makes the ATmega168 to exit the power saving mode).

See the actual code in this

/* Sleep Demo Serial
 * -----------------
 * Example code to demonstrate the sleep functions in a Arduino. Arduino will wake up
 * when new data is received in the serial port USART
 * Based on Sleep Demo Serial from http://www.arduino.cc/playground/Learning/ArduinoSleepCode 
 *
 * Copyright (C) 2006 MacSimski 2006-12-30 
 * Copyright (C) 2007 D. Cuartielles 2007-07-08 - Mexico DF
 * 
 *  With modifications from Ruben Laguna  2008-10-15
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
 
#include <avr/power.h>
#include <avr/sleep.h>
 
 
 
int sleepStatus = 0;             // variable to store a request for sleep
int count = 0;                   // counter
 
 
void setup()
{
 
  Serial.begin(9600);
}
 
void sleepNow()
{
    /* Now is the time to set the sleep mode. In the Atmega8 datasheet
     * http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf on page 35
     * there is a list of sleep modes which explains which clocks and 
     * wake up sources are available in which sleep modus.
     *
     * In the avr/sleep.h file, the call names of these sleep modus are to be found:
     *
     * The 5 different modes are:
     *     SLEEP_MODE_IDLE         -the least power savings 
     *     SLEEP_MODE_ADC
     *     SLEEP_MODE_PWR_SAVE
     *     SLEEP_MODE_STANDBY
     *     SLEEP_MODE_PWR_DOWN     -the most power savings
     *
     *  the power reduction management <avr/power.h>  is described in 
     *  http://www.nongnu.org/avr-libc/user-manual/group__avr__power.html
     */  
 
  set_sleep_mode(SLEEP_MODE_IDLE);   // sleep mode is set here
 
  sleep_enable();          // enables the sleep bit in the mcucr register
                             // so sleep is possible. just a safety pin 
 
  power_adc_disable();
  power_spi_disable();
  power_timer0_disable();
  power_timer1_disable();
  power_timer2_disable();
  power_twi_disable();
 
 
  sleep_mode();            // here the device is actually put to sleep!!
 
                             // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
  sleep_disable();         // first thing after waking from sleep:
                            // disable sleep...
 
  power_all_enable();
 
}
 
 
void loop()
{
  // display information about the counter
  Serial.print("Awake for ");
  Serial.print(count);
  Serial.println("sec");
  count++;
  delay(1000);                           // waits for a second
 
  // compute the serial input
  if (Serial.available()) {
    int val = Serial.read();
    if (val == 'S') {
      Serial.println("Serial: Entering Sleep mode");
      delay(100);     // this delay is needed, the sleep 
                      //function will provoke a Serial error otherwise!!
      count = 0;
      sleepNow();     // sleep function called here
    }
    if (val == 'A') {
      Serial.println("Hola Caracola"); // classic dummy message
    }
  }
 
  // check if it should go asleep because of time
  if (count >= 10) {
      Serial.println("Timer: Entering Sleep mode");
      delay(100);     // this delay is needed, the sleep 
                      //function will provoke a Serial error otherwise!!
      count = 0;
      sleepNow();     // sleep function called here
  }
}

Upgrading Xbee Series 2 (XbeeShield) to Xbee ZB with Arduino

Saturday, September 6th, 2008

As stated in this digi page is possible to upgrade/convert a Xbee Series 2.5 to a Xbee ZB (with full standard Zigbee capabilities). Xbee Series 2.5 is just another name for the forme Series 2, so the upgrade procedure is exactly the same.

The procedure if fairly straighforward

  1. Remove ATmega168 from Arduino board
  2. Insert XbeeShield into Arduino
  3. Change both jumpers in XbeeShield to USB
  4. Connect Arduino to the computer using the USB cabke
  5. Download the ZNet 2.5 to ZB Conversion Kit here
  6. Start the X-CTU 5.1.4.1 software
  7. xbee01
  8. Select the proper COM port (should be Usb serial port (COMX))
  9. Click on Test Query. The following dialog should appear indicating that X-CTU found the Xbee in that COM port and giving you some information about the Xbee module version, etc. In my case it was a ZB24-B with 1220 firmware
  10. xbee02
  11. Go to the Modem Configuration tab
  12. Download the ZNet 2.5 to ZB Conversion Kit here if you didn’t do it earlier
  13. Uncompress the ZIP
  14. xbee11
  15. Select the “Download new versions” button.
  16. xbee12
  17. Press the “File” source button
  18. Select the xbee_zb.zip file to add the firmware set to X-CTU
  19. Back to the Modem Configuration tab. Select “Always update firmware” checkbox and select XB24-ZB (or XB24P-ZB if you have a PRO module) and the function set that you want for the module (router, coordinator, end device, each one in two differente flavor AT or API). In my case I selected XB24-ZB and COORDINATOR API. Check the product manual to find out about API and AT modes and the different firmwares for each set
  20. xbee03
  21. Press “Write” and X-CTU will start uploading the firmware to the module
  22. xbee04 xbee05
  23. The firmware upgrade is complete
  24. NOTE: Make sure that the configuration for DIO7 is DISABLED as this XBee pin is connected to the RST in the Arduino. If you leave the default option (1 - CTS) random resets after a couple of seconds may occur

Arduino and DS1620 digital temperature sensor

Sunday, August 31st, 2008

I received a couple of Arduinos Diecimilla that I bought from Libelium.

My first project with Arduino has been interfacing with DS1620 digital temperature sensor.

Picture 17

It was really easy it just a matter of connecting pin 3, 4 and 5 on the Arduino to RST, CLK and DQ on the DS1620. The source code in this post will read the temperature from the DS1620 using the 3 wire interface and it will output the result to the serial interface in the Arduino.

IMG_0329

I mostly use the information of PC Parallel Port Interfacing with DS1620 Digital Thermometer / Thermostat page to learn how to interface to this thermometer and the information on the SerialPortExample page to learn how to output to the serial port.

The DS1620 measures temperatures from -55°C to +125°C in 0.5°C increments. As you can see in the code reading a DS1620 sensor is way more complicated than reading an analog LM35 temperature sensor (and the LM35 gives you more precision and also takes one pin instead of three) so probably is a LM35 is a better option if you want an easy way to get the temperature in your arduino project.

Source code:

/*
  DS160 example
 
  Reading temperature from DS1620 digital temperature sensor 
  and showing the result via serial interface.
 
 
  Arduino    DS1620
  pin 3  ->    RST
  pin 4  ->    CLK
  pin 5  ->    DQ
 
  by Ruben Laguna
  based on examples from Tom Tigoe <http://www.arduino.cc/en/Reference/SoftwareSerialExample>
  and phanderson <http://www.phanderson.com/printer/ds1620/ds1620.html>
  written: 30 Aug 2008
 
 
*/
 
// include the SoftwareSerial library so you can use its functions:
#include <SoftwareSerial.h>
 
#define rxPin 0
#define txPin 1
#define ledPin 13
#define buttonPin 2
 
#define rstPin 3
#define clkPin 4
#define dqPin 5
 
 
 
 
// set up a new serial port
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);
byte pinState = 0;
 
void setup()  {
  // define pin modes for tx, rx, led pins:
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(rstPin, OUTPUT);
  pinMode(clkPin, OUTPUT);
  pinMode(dqPin, OUTPUT);
 
  // set the data rate for the SoftwareSerial port
  mySerial.begin(9600);
}
 
 
void loop() {
  int val = digitalRead(buttonPin);
 
    rst_low();
 
    clk_high();
    rst_high(); //all data transfer are initiated by driving RST high
    write_command(0x0c); // write config command
    write_command(0x02); // cpu mode
    rst_low();
    delay(200); //wait until the configuration register is written 
 
    clk_high();
    rst_high();
    write_command(0xEE); //start conversion
    rst_low();
    delay(200);
 
    clk_high();
    rst_high();
    write_command(0xAA);
    int raw_data = read_raw_data();
    rst_low();
 
    mySerial.print("temperature:");
    mySerial.print(raw_data/2);
    mySerial.println(" C");
 
 
    delay(100);
 
 
  // toggle an LED just so you see the thing's alive.  
 
  toggle(13);
 
}
 
 
void toggle(int pinNum) {
  // set the LED pin using the pinState variable:
  digitalWrite(pinNum, pinState); 
  // if pinState = 0, set it to 1, and vice versa:
  pinState = !pinState;
}
 
void write_command(int command)
/* sends 8 bit command on DQ output, least sig bit first */ 
{
  int n, bit;
 
  for(n=0;n<8;n++)
  {
    bit = ((command >> n) & (0x01));
    out_bit(bit);
  }
}
 
int read_raw_data(void)
{
  int bit,n;
  int raw_data=0;
 
  pinMode(dqPin,INPUT);
 
     /* jam the dq lead high to use as input */
  for(n=0;n<9;n++)
  {
     clk_low();
     bit=(digitalRead(dqPin));
     clk_high();
     raw_data = raw_data | (bit <<  n);
  }
  pinMode(dqPin, OUTPUT);
  return(raw_data);
}
 
void out_bit(int bit) 
{
  digitalWrite(dqPin, bit);  /* set up the data */
  clk_low();             /* and then provide a clock pulse */   
  clk_high();
}
 
void clk_high(void)
{
  digitalWrite(clkPin,HIGH);
}
 
void clk_low(void)
{
  digitalWrite(clkPin,LOW);
}
 
void rst_high(void)
{
   digitalWrite(rstPin,HIGH);
}
 
void rst_low(void)
{
   digitalWrite(rstPin,LOW);
}