Compass, Baro Alt, and Temp Code

If anyone's interested, here's the code I used, slightly modified and spliced from the internet. This is for the SCP1000-D01, with my temperature running about 35 degrees F hot which for now I'm attributing to the heating from the amperage:// define spi bus pins#define SLAVESELECT 10 //CSB#define SPICLOCK 13 //SCK#define DATAOUT 11 //MOSI#define DATAIN 12 //MISO#define UBLB(a,b) ( ( (a) << 8) | (b) )#define UBLB19(a,b) ( ( (a) << 16 ) | (b) )//Addresses#define REVID 0x00 //ASIC Revision Number#define OPSTATUS 0x04 //Operation Status#define STATUS 0x07 //ASIC Status#define START 0x0A //Constant Readings#define PRESSURE 0x1F //Pressure 3 MSB#define PRESSURE_LSB 0x20 //Pressure 16 LSB#define TEMP 0x21 //16 bit tempchar rev_in_byte;int temp_in;unsigned long pressure_lsb;unsigned long pressure_msb;unsigned long temp_pressure;unsigned long pressure;float altitude;void setup(){byte clr;pinMode(DATAOUT, OUTPUT);pinMode(DATAIN, INPUT);pinMode(SPICLOCK,OUTPUT);pinMode(SLAVESELECT,OUTPUT);digitalWrite(SLAVESELECT,HIGH); //disable deviceSPCR = B01010011; //MPIE=0, SPE=1 (on), DORD=0 (MSB first), MSTR=1 (master), CPOL=0 (clock idle when low), CPHA=0 (samples MOSI on rising edge), SPR1=0 & SPR0=0 (500kHz)clr=SPSR;clr=SPDR;delay(10);Serial.begin(9600);delay(500);Serial.println("Initialize High Speed Constant Reading Mode");write_register(0x03,0x09);}void loop(){rev_in_byte = read_register(REVID);pressure_msb = read_register(PRESSURE);pressure_msb &= B00000111;pressure_lsb = read_register16(PRESSURE_LSB);pressure_lsb &= 0x0000FFFF;pressure = UBLB19(pressure_msb, pressure_lsb);pressure /= 4;altitude = (1 - pow((float)pressure/101325,0.19025515825))*(288.15/0.00199074074);Serial.print("Altitude ft [");Serial.print(altitude);Serial.println("]");temp_in = read_register16(TEMP);temp_in = temp_in / 20;temp_in = 1.8 * temp_in - 3;Serial.print("TEMP F [");Serial.print(temp_in , DEC);Serial.println("]");delay(1500);}char spi_transfer(volatile char data){SPDR = data; // Start the transmissionwhile (!(SPSR & (1<<SPIF))) // Wait for the end of the transmission{};return SPDR; // return the received byte}char read_register(char register_name){char in_byte;register_name <<= 2;register_name &= B11111100; //Read commanddigitalWrite(SLAVESELECT,LOW); //Select SPI Devicespi_transfer(register_name); //Write byte to devicein_byte = spi_transfer(0x00); //Send nothing, but we should get back the register valuedigitalWrite(SLAVESELECT,HIGH);delay(10);return(in_byte);}float read_register16(char register_name){byte in_byte1;byte in_byte2;float in_word;register_name <<= 2;register_name &= B11111100; //Read commanddigitalWrite(SLAVESELECT,LOW); //Select SPI Devicespi_transfer(register_name); //Write byte to devicein_byte1 = spi_transfer(0x00);in_byte2 = spi_transfer(0x00);digitalWrite(SLAVESELECT,HIGH);in_word = UBLB(in_byte1,in_byte2);return(in_word);}void write_register(char register_name, char register_value){register_name <<= 2;register_name |= B00000010; //Write commanddigitalWrite(SLAVESELECT,LOW); //Select SPI devicespi_transfer(register_name); //Send register locationspi_transfer(register_value); //Send value to record into registerdigitalWrite(SLAVESELECT,HIGH);}/-------------------------------------------------------------------------------------------------------------------------------This is the code I used to get a decent compass heading. There's a lot of extra fluff in this code, and its not modified at all:#include#includeint magReading = 0;int XmagValue = 0;int YmagValue = 0;int Azimuth = 0;void setup(){Serial.begin(9600);Wire.begin();}void magRead(int outputMode){// int HMC6352Address = 0x42;// Shift the device's documented slave address (0x42) 1 bit right// This compensates for how the TWI library only wants the// 7 most significant bits (with the high bit padded with 0)// slaveAddress = HMC6352Address >> 1; // This results in 0x21 as the address to pass to TWIint slaveAddress = 0x21; // This is calculated from HMC6352's address, see comments aboveint ramDelay = 100; // us, delay between a RAM write command and its effect, at least 70usint getDelay = 10; // ms, delay between a get data command and its effect, at least 6msbyte magData[2];int i;switch (outputMode){case 0:Wire.beginTransmission(slaveAddress);Wire.send(0x47); // Write to RAM commandWire.send(0x4E); // Output Mode control byte addressWire.send(0x00); // 0x00 for Heading modeWire.endTransmission();break;case 1:Wire.beginTransmission(slaveAddress);Wire.send(0x47); // Write to RAM commandWire.send(0x4E); // Output Mode control byte addressWire.send(0x03); // 0x03 for Magnetometer X modeWire.endTransmission();break;case 2:Wire.beginTransmission(slaveAddress);Wire.send(0x47); // Write to RAM commandWire.send(0x4E); // Output Mode control byte addressWire.send(0x04); // 0x04 for Magnetometer Y modeWire.endTransmission();break;default:Wire.beginTransmission(slaveAddress);Wire.send(0x47); // Write to RAM commandWire.send(0x4E); // Output Mode control byte addressWire.send(0x00); // default to Heading modeWire.endTransmission();}delayMicroseconds(ramDelay); // RAM write needs 70 microseconds to respondWire.beginTransmission(slaveAddress);Wire.send("A"); // The "Get Data" commandWire.endTransmission();delay(getDelay); // Get Data needs 6 milliseconds to respondWire.requestFrom(slaveAddress, 2); // Request the 2 byte data (MSB comes first)i = 0;while(Wire.available() && i < 2){magData[i] = Wire.receive();i++;}magReading = magData[0]*256 + magData[1];}void loop(){magRead(0);Azimuth = magReading;magRead(1);XmagValue = magReading;magRead(2);YmagValue = magReading;Serial.print("Mag X: ");Serial.print(XmagValue);Serial.print(" Mag Y: ");Serial.print(YmagValue);Serial.print(" Azimuth: ");Serial.print(-int(atan2(YmagValue,XmagValue)*57));Serial.print(" degrees ");Serial.print(int(Azimuth/10));Serial.println(" degrees ");delay(500);}
E-mail me when people leave their comments –

You need to be a member of diydrones to add comments!

Join diydrones

Comments

  • I have tested a midified version of this - seems a bit simpler when you remove the servo code(?):

    /*
    HMC6532 compass to servo test
    With 2Wire HMC6532 code by vaibhav bhawsar
    http://recombine.net/blog/article/49/hmc6352-sparkfun-compass-and-a...)
    and Parallax servo code by voidnoise
    http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1201077061

    HMC6532 connections:
    SDA to Analog pin 4 and SCL to analog pin 5
    No pullup resistors on SDA and SCL
    Using 3v instead of 5v to the Vcc of the compass module.

    */

    // include the SoftwareSerial library so you can use its functions:
    #include
    #define rxPin 8
    #define txPin 9
    // set up a new serial port
    SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);

    // include the Wire library to read from the compass
    #include
    int HMC6352Address = 0x42;
    // This is calculated in the setup() function
    int slaveAddress;
    byte headingData[2];
    int i, headingValue;



    void setup()
    {
    // Shift the device's documented slave address (0x42) 1 bit right
    // This compensates for how the TWI library only wants the
    // 7 most significant bits (with the high bit padded with 0)
    slaveAddress = HMC6352Address >> 1; // This results in 0x21 as the address to pass to TWI
    Serial.begin(115200);
    Serial.println("serial started: ");
    Wire.begin();

    // define pin modes for tx, rx:
    pinMode(rxPin, INPUT);
    pinMode(txPin, OUTPUT);
    // set the data rate for the SoftwareSerial port
    mySerial.begin(2400);

    changeServo(0, 50);
    delay(500);
    changeServo(0, 100);
    }


    void loop()
    {
    // Send a "A" command to the HMC6352
    // This requests the current heading data
    Wire.beginTransmission(slaveAddress);
    Wire.send("A"); // The "Get Data" command
    Wire.endTransmission();
    delay(10); // The HMC6352 needs at least a 70us (microsecond) delay
    // after this command. Using 10ms just makes it safe
    // Read the 2 heading bytes, MSB first
    // The resulting 16bit word is the compass heading in 10th's of a degree
    // For example: a heading of 1345 would be 134.5 degrees
    Wire.requestFrom(slaveAddress, 2); // Request the 2 byte heading (MSB comes first)
    i = 0;
    while(Wire.available() && i < 2)
    {
    headingData[i] = Wire.receive();
    i++;
    }
    headingValue = headingData[0]*256 + headingData[1]; // Put the MSB and LSB together

    Serial.print("Current heading: ");
    Serial.print(int (headingValue / 10)); // The whole number part of the heading
    Serial.print(".");
    Serial.print(int (headingValue % 10)); // The fractional part of the heading
    Serial.println(" degrees");
    delay(200);

    headingValue= headingValue/4; //compensate for limited servo rotation angle
    changeServo(0, headingValue);
    // delay(150); // try to get rid of jittering

    }

    int changeServo(int chan, int posi){
    // position is expressed in degrees: 0-180
    // then converted to 300-1250 range
    int pw = posi;
    pw= (pw * 5) + 300;
    byte lsb = pw;
    byte msb = pw >> 8;
    int ramp = 0;


    mySerial.print(33, BYTE); //!
    mySerial.print(83, BYTE); //S
    mySerial.print(67, BYTE); //C
    mySerial.print(chan, BYTE); //channel
    mySerial.print(ramp, BYTE); //rampspeed
    mySerial.print(lsb, BYTE); //LSB
    mySerial.print(msb, BYTE); //MSB
    mySerial.print(13, BYTE);
    }
  • Just working with what I have. I checked the altitude I was getting from the scp1000, compared it against the local altimeter setting and it was spot on. I don't believe higher fidelity is necessary.
  • T3
    Are you fully aware that at 60USD there is a calibrated altitude meter with ASCII and binary serial output?
    www.aerialrobotics.eu/altigps/altigps-en.pdf
    There is a long way of calibrating and recalculating the altitude to ground level.
This reply was deleted.