Arizona Chris
Joined: 20 Dec 2014 Posts: 69 Location: Arizona
|
Adafruit Magnetometer Compass Board and New Haven Serial LCD |
Posted: Sun Jun 21, 2015 8:23 pm |
|
|
Greetings all,
I wish to share with you my experiences in using these two new ground breaking products, one superb HMC5883L breakout board and a new series of LCD displays from Jameco. I have to first tell you I have spent every waking hour in the past month diving head first into the triple axis magnetometer learing the significance of every byte of data and pouring over the graphs and data sheets on this very fine Honywell product.
Several manufacturers sell breakout boards for this tiny surface mount part, but let me tell you this - The Adafruit version is the only one with complete 5v interface circuitry built in, and the a killer $9 price too! I bought a handful of them and they work very well indeed.
You can read about this product here: http://www.adafruit.com/product/1746
Second, Jameco now sells a new line of LCD displays that are serial driven, have a awesome contrasty transreflective screen and are a fraction of the cost of anybody elses in this quality range. I'm using this LCD - a 20 x 4 model in the code below, and you can use the functions/drivers I have in this program to operate the display. You might
buy a handful of these as well. ;)
Here is a link to the Jameco catalog with the displays:
20 x 4: http://www.jameco.com/webapp/wcs/stores/servlet/Product_10001_10001_2118686_-1
16 x 2: http://www.jameco.com/webapp/wcs/stores/servlet/Product_10001_10001_2118651_-1
I bought several of each.
About the Magenetometer.
This is a triple axis magnetometer which uses three tiny magneto-resistive sensors, made of a nickel iron alloy called "permalloy". The chip mounts them as part of a bridge and includes a digitally selectable internal amp to select different field ranges. A 12 bit a/d converter sends all data out a two wire serial port using I2C format.
If your are unfamiliar with I2C format, here is a nice small write up I found that explains it pretty well. After reading this you will get a good handle on what the code is doing:
http://robot-electronics.co.uk/acatalog/I2C_Tutorial.html
Description of the code below. The code is written as a continous loop that reads the magnetometer, sends the results to the display. I wrote everything up as a few separate functions to allow more flexibility in the applications. Our use for now is robot navigation.
Code: |
//****************************************************************************
//Chris Schur
//Adafruit HMC5883L magnetometer - 16F877A)
//Date: 6/16/15
//****************************************************************************
/*Description of this Program:
Version 8 - continuous reading version of 7.*/
//I/O Designations ---------------------------------------------------
// RB0: Status LED output
// RB1: LCD output
// RB2: Piezzo Speaker output
// RC3: INPUT - SCL - to magnetometer
// RC4: INPUT - SDA - to magnetometer
//--------------------------------------------------------------------
//Include Files:
#include <16F877A.h>
#include "math.h" //required for compass
//Directives and Defines:
#fuses NOPROTECT,HS,NOWDT //xtal is used
#use delay(crystal=10MHz) //xtal speed
//set up i2c - data, clock pins are here hardware on 877a.part uses slow spec.
#use I2C(master, sda=PIN_C4, scl=PIN_C3, slow, FORCE_HW) //HARDWARE IMPLEMENT
#use fast_io(ALL) //must define tris below in main when using this
// HMC5883 required Registers
#define W_DATA 0x3C //Used to perform a Write operation
#define R_DATA 0x3D //Used to perform a Read operation
#define CON_A 0x00 //Sets up measurement and sampling parameters.
#define CON_B 0x01 //Send continuous MeVARurement mode.
#define MOD_R 0x02 //Read/Write Register, Selects the operating mode. Default =
Single meVARurement
#define X_MSB 0x03 //Read Register, Output of X MSB 8-bit value.
#define X_LSB 0x04 //Read Register, Output of X LSB 8-bit value.
#define Z_MSB 0x05 //Read Register, Output of Z MSB 8-bit value.
#define Z_LSB 0x06 //Read Register, Output of Z LSB 8-bit value.
#define Y_MSB 0x07 //Read Register, Output of Y MSB 8-bit value.
#define Y_LSB 0x08 //Read Register, Output of Y LSB 8-bit value.
//for LCD:
#use rs232(baud=9600, xmit=Pin_B1, bits=8, parity=N,stream=SERIALNH)
//****************************************************************************
//Global Variables:
int16 n; //counting var
int8 M_data[6]; //Array - 6 units 8 bit Measured datas (compass)
int16 Xm=0,Ym=0,Zm=0; //16 bit X,Y,Z variables (compass)
float bearing; //final compass reading.
//****************************************************************************
//Functions/Subroutines, Prototypes:
//for compass only:
void hmc5883_write(int add, int data); //write to function
int16 hmc5883_read(int add); //Read from function
void hmc5883_init(); //Sets up starting conditions
void read_reg(); //reads compass registers, calc xyz
float calc_heading(); //calculates returns bearing.
//For New Haven LCD only:
void LCDCLR();
void LCDLN2();
void LCDLN3();
void LCDLN4();
//****************************************************************************
//-- Main Program
//****************************************************************************
void main(void) {
// Set TRIS I/O directions, define analog inputs, compartors:
set_tris_A(0b11111);
set_tris_B(0b11001000);
set_tris_C(0b11111111); //set both sda and sclk for inputs (float)
set_tris_D(0b11111111);
set_tris_E(0b111);
output_low(Pin_B0); //status off
delay_ms(1000); //LCD warmup time
//SET BRIGHTNESS OF LCD TO MID RANGE. (DEFAULT = 1)
fputc(0xFE,SERIALNH); //Command Prefix
fputc(0x53,SERIALNH); //set cursor command
fputc(8,SERIALNH); //LCD backlight - 4 is mid 0-8
delay_ms(250);
LCDCLR();
delay_ms(250);
fprintf(SERIALNH,"CBOT-1");
delay_ms(250);
LCDLN2();
fprintf(SERIALNH,"READY");
//start compass single read: ----------------------------------------------
hmc5883_init(); //Initialize compass settings.
while(true) {
read_reg(); //read compass registers, calc xyz
bearing = calc_heading(); //calculates & returns final compass bearing
LCDCLR();
delay_ms(10);
fprintf(SERIALNH,"H= %f ",bearing);
delay_ms(50);
}
} //niam
//********* Functions which have prototypes at top of program ****************
//for compass only:
void hmc5883_write(int add, int data) {
i2c_start();
i2c_write(W_DATA); //0x03
i2c_write(add);
i2c_write(data);
i2c_stop(); }
int16 hmc5883_read(int add) {
int retval;
i2c_start();
i2c_write(W_DATA); //0x03
i2c_write(add);
i2c_start();
i2c_write(R_DATA); //0x3D
retval=i2c_read(0);
i2c_stop();
return retval; }
void hmc5883_init() {
hmc5883_write(MOD_R, 0x00); //0x02, 0x00
delay_ms(100);
hmc5883_write(CON_A, 0x10); //0x00, 0x10
delay_ms(100);
hmc5883_write(CON_B, 0x20); //0x01, 0x20
delay_ms(100); }
void read_reg() { //read compass registers
//read registers in compass
M_data[0]=hmc5883_read(0x04); //Read X (LSB)
M_data[1]=hmc5883_read(0x03); //Read X (MSB)
M_data[2]=hmc5883_read(0x08); //Read Y (LSB)
M_data[3]=hmc5883_read(0x07); //Read Y (MSB)
M_data[4]=hmc5883_read(0x06); //Read Z (LSB)
M_data[5]=hmc5883_read(0x05); //Read Z (MSB)
//Create Word from Highbyte and Lowbyte data:
Xm=make16(M_data[1],M_data[0]);
Ym=make16(M_data[3],M_data[2]);
Zm=make16(M_data[5],M_data[4]);
}
float calc_heading() {
//Calculate using math.h function the bearing.
float Heading = atan2((signed int16)Ym,(signed int16)Xm)* 180 / pi + 180;
//correct for this equation yielding values 180 off:
if (Heading < 180)
Heading = Heading + 180;
else if (Heading > 180)
Heading = Heading - 180;
else if (Heading == 180)
Heading = 0;
return Heading;
}
//For New Haven LCD only:
//Clears LCD Display:
void LCDCLR() {
fputc(0xFE,SERIALNH); //Command Prefix
fputc(0x51,SERIALNH); //Clear screen
}
//Sets LCD to line 2 start point
void LCDLN2() {
fputc(0xFE,SERIALNH); //Command Prefix
fputc(0x45,SERIALNH); //set cursor command
fputc(0x40,SERIALNH); //Set cursor to next line, pos 40 = start line 2
}
//Sets LCD to line 3 start point
void LCDLN3() {
fputc(0xFE,SERIALNH); //Command Prefix
fputc(0x45,SERIALNH); //set cursor command
fputc(0x14,SERIALNH); //Set cursor to next line, pos 14 = start line 3
}
//Sets LCD to line 4 start point
void LCDLN4() {
fputc(0xFE,SERIALNH); //Command Prefix
fputc(0x45,SERIALNH); //set cursor command
fputc(0x54,SERIALNH); //Set cursor to next line, pos 54 = start line 4
}
|
|
|