// QMC5883 compass
// For an HMC5883L chip a popular library is :
// James Sleeman's HMC5883L library from GitHub.
// Here the QMC5883L is controlled by direct I2C read/write.
//
// Copyright John Main - Free for non commercial use.
//
#include "Wire.h" // For 5883L I2C interface
#include <EEPROM.h>
#define BUTTON_CAL 2
#define LED 13
#define EEADDR 66 // Start location to write EEPROM data.
#define CALTIME 10000 // In ms.
英石aticbyte英石at,ovfl,skipped;
英石atic在tminx,maxx,miny,maxy,offx=0,offy=0;
/////////////////////////////////////////////////////////////
voidI2C_write_AddrDev_AddrReg_Byte(bytei2cAddr,byteregaddr,byted){
Wire.beginTransmission(i2cAddr);
Wire.write(regaddr);
Wire.write(d);
Wire.endTransmission();
}
/////////////////////////////////////////////////////////////
voidcalc_offsets(void){
offx=(maxx+minx)/2;
offy=(maxy+miny)/2;
}
/////////////////////////////////////////////////////////////
byte磁力计Ready(void){
// Data ready?
Wire.beginTransmission(0x0d);// Read from status reg
Wire.write(0x06);
在tnum=Wire.requestFrom((byte)0x0d,(byte)1);
英石at=Wire.read();// DOR Data out Ready (SKIPPED).
Wire.endTransmission();
ovfl=英石at&0x02;
skipped=英石at&0x04;
return(英石at&&0x01);// 0x01 is the DRDY Data Ready flag
}
/////////////////////////////////////////////////////////////
// If data is not ready x,y,z are not changed.
bytegetMagnetometerRaw(在t16_t*x,在t16_t*y,在t16_t*z){
if(!磁力计Ready())return0;
Wire.beginTransmission(0x0d);
Wire.write(0x00);// read from address zero = x,y,z registers.
在terr=Wire.endTransmission();
if(!err){
Wire.requestFrom((byte)0x0d,(byte)6);//Blocking?
while(Wire.available()<6);//Wait if above blocking then this not needed.
*x=(在t16_t)(Wire.read()|Wire.read()<<8);
*y=(在t16_t)(Wire.read()|Wire.read()<<8);
*z=(在t16_t)(Wire.read()|Wire.read()<<8);
}
return1;
}
/////////////////////////////////////////////////////////////
// Orient to board coordinates
voidgetMagnetometer(在t16_t*x,在t16_t*y,在t16_t*z){
if(!getMagnetometerRaw(x,y,z))return;
在ttmp=*y;
*y=-*x;// x is down.
*x=tmp;// y is to the right.
}
/////////////////////////////////////////////////////////////
// Blocking: Waits in this function for reading to be ready.
voidreadMagnetometer(在t16_t*x,在t16_t*y,在t16_t*z){
while(!磁力计Ready());
getMagnetometer(x,y,z);// Note: Addresses of pointers passed.
}
/////////////////////////////////////////////////////////////
voidsetup(){
pinMode(LED,OUTPUT);
pinMode(BUTTON_CAL,INPUT_PULLUP);
Wire.begin();// Start I2C
Wire.setClock(100000);// Test at high speed
Serial.begin(115200);
Serial.println("QMC5883L Digital compass: 3 axis");
Serial.println("QMC5883L start initialise.");
// Datasheet suggests this for chip startup.
I2C_write_AddrDev_AddrReg_Byte(0x0d,0x0b,1);
I2C_write_AddrDev_AddrReg_Byte(0x0d,0x09,B00000001);
Serial.println(F("DONE initialise"));
// Read EEPROM offset data
在tEEAddr=EEADDR;
EEPROM.get(EEAddr,minx);EEAddr+=sizeof(minx);
EEPROM.get(EEAddr,maxx);EEAddr+=sizeof(maxx);
EEPROM.get(EEAddr,miny);EEAddr+=sizeof(miny);
EEPROM.get(EEAddr,maxy);EEAddr+=sizeof(maxy);
calc_offsets();
}
/////////////////////////////////////////////////////////////
voidcalibrate(){
unsignedlongcalTimeWas=millis();
bytecal=1,英石artCal=1;
在tx,y,z;
floatdeg=0,deg2=0;
readMagnetometer(&x,&y,&z);
maxx=minx=x;// Set initial values to current magnetometer readings.
maxy=miny=y;
while(cal){
if(磁力计Ready())getMagnetometer(&x,&y,&z);
if(x>maxx)maxx=x;
if(x<minx)minx=x;
if(y>maxy)maxy=y;
if(y<miny)miny=y;
Serial.print("CALIBRATE ");
在tsecmillis=millis()-calTimeWas;
在tsecs=(在t)((CALTIME-secmillis+1000)/1000);
Serial.print("--> ");
Serial.println((CALTIME-secmillis)/1000);
if(secs==0){// Cal has ended
calc_offsets();
cal=0;
在tEEAddr=EEADDR;
EEPROM.put(EEAddr,minx);EEAddr+=sizeof(minx);
EEPROM.put(EEAddr,maxx);EEAddr+=sizeof(maxx);
EEPROM.put(EEAddr,miny);EEAddr+=sizeof(miny);
EEPROM.put(EEAddr,maxy);EEAddr+=sizeof(maxy);
Serial.println("EEPROM Written");// make sure this does not repeat on terminal!
}
delay(10);
}// while cal
}
/////////////////////////////////////////////////////////////
voidloop(){
英石aticunsignedlongBLTimeWas=millis();
英石atic在tx,y,z;// Raw compass output values.
英石atic在tbearing;
if(数字的Read(BUTTON_CAL)==0)calibrate();
getMagnetometer(&x,&y,&z);
在tatan2val=180/M_PI*atan2((float)(x-offx),(float)(y-offy));
bearing=(-atan2val+360)%360;
if(millis()-BLTimeWas>400){// LED toggle
BLTimeWas=millis();
英石aticbytetogLED=0;
togLED=!togLED;
if(togLED)数字的Write(LED,HIGH);else数字的Write(LED,LOW);
Serial.println(bearing);
}
}
// End of HMC5883 Serial output compass.
// QMC5883 compass and SSD1306 OLED display
//
// For an HMC5883L chip a popular library is :
// James Sleeman's HMC5883L library from GitHub.
//
// Here the QMC5883L is controlled by direct
// I2C read/write i.e. no library.
// The adafruit library is used for the SSD1306.
//
// Copyright John Main - Free for non commercial use.
//
#include "Wire.h" ;# For 5883
#include <SPI.h> ;# For SSD1306 board.
#include <EEPROM.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "I2Cdev.h"
#define OLED_MOSI 11
#define OLED_CLK 13 // LED_BUILTIN
#define OLED_DC 9
#define OLED_CS 8
#define OLED_RESET 10
#define BUTTON_CAL 2
#define BUTTON_TEST 5
#define LED 4 // LED_BUILTIN pin 13 is also SPICLK SCK
#define EEADDR 66 // Start location to write EEPROM data.
#define CALTIME 10000 // In ms.
#define SCREEN_HEIGHT 128 // Screen os rotated in sw
#define SCREEN_WIDTH 64
英石aticbyte英石at,ovfl,skipped;
英石atic在tminx,maxx,miny,maxy,offx=0,offy=0;
// SSD1306 is oriented vertically (thin x, long y).
// The SSD1306 screen s/w rotated for above orientation.
//
// SSD1306 is mounted on a long solderless breadboard,
// so is physically rotated CCW 90 degrees.
// Screen coords for center of compass screen is 128x64 pixels X,Y.
// x,y (0,0) lower left. SSD1306 drawing functions use top left.
const在t半径=64/2;
const在tmidx=半径;
const在tmidy=半径;
Adafruit_SSD1306display(OLED_DC.,OLED_RESET.,OLED_CS.);// hw spi
/////////////////////////////////////////////////////////////
// Generic I2C write to I2C device with address, i2cAddr
// Write to address regaddr within device
// Write the byte d
voidI2C_write_AddrDev_AddrReg_Byte(bytei2cAddr,byteregaddr,byted){
Wire.beginTransmission(i2cAddr);
Wire.write(regaddr);
Wire.write(d);
Wire.endTransmission();
}
/////////////////////////////////////////////////////////////
voidcalc_offsets(void){
offx=(maxx+minx)/2;
offy=(maxy+miny)/2;
}
/////////////////////////////////////////////////////////////
byte磁力计Ready(void){
// Data ready?
Wire.beginTransmission(0x0d);// Read from status reg
Wire.write(0x06);
在tnum=Wire.requestFrom((byte)0x0d,(byte)1);
英石at=Wire.read();// DOR Data out Ready (SKIPPED).
Wire.endTransmission();
ovfl=英石at&0x02;
skipped=英石at&0x04;
return(英石at&&0x01);// 0x01 is the DRDY Data Ready flag
}
/////////////////////////////////////////////////////////////
// If data is not ready x,y,z are not changed.
bytegetMagnetometerRaw(在t16_t*x,在t16_t*y,在t16_t*z){
if(!磁力计Ready())return0;
Wire.beginTransmission(0x0d);
Wire.write(0x00);// read from address zero = x,y,z registers.
在terr=Wire.endTransmission();
if(!err){
Wire.requestFrom((byte)0x0d,(byte)6);//Blocking?
while(Wire.available()<6);//Wait if above blocking then this not needed.
*x=(在t16_t)(Wire.read()|Wire.read()<<8);
*y=(在t16_t)(Wire.read()|Wire.read()<<8);
*z=(在t16_t)(Wire.read()|Wire.read()<<8);
}
return1;
}
/////////////////////////////////////////////////////////////
// Orient to board coordinates
voidgetMagnetometer(在t16_t*x,在t16_t*y,在t16_t*z){
if(!getMagnetometerRaw(x,y,z))return;
在ttmp=*y;
*y=-*x;// x is down.
*x=tmp;// y is to the right.
}
/////////////////////////////////////////////////////////////
// Blocking: Waits in this function for reading to be ready.
voidreadMagnetometer(在t16_t*x,在t16_t*y,在t16_t*z){
while(!磁力计Ready());
getMagnetometer(x,y,z);// Note: Addresses of pointers passed.
}
/////////////////////////////////////////////////////////////
voidsetup(){
pinMode(LED,OUTPUT);
pinMode(BUTTON_CAL,INPUT_PULLUP);
pinMode(BUTTON_TEST,INPUT_PULLUP);
Wire.begin();// Start I2C
Wire.setClock(100000);// Test at high speed
display.begin(SSD1306._SWITCHCAPVCC);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
// Datasheet suggests this for chip startup.
I2C_write_AddrDev_AddrReg_Byte(0x0d,0x0b,1);
I2C_write_AddrDev_AddrReg_Byte(0x0d,0x09,B00000001);
// Read EEPROM
在tEEAddr=EEADDR;
EEPROM.get(EEAddr,minx);EEAddr+=sizeof(minx);
EEPROM.get(EEAddr,maxx);EEAddr+=sizeof(maxx);
EEPROM.get(EEAddr,miny);EEAddr+=sizeof(miny);
EEPROM.get(EEAddr,maxy);EEAddr+=sizeof(maxy);
calc_offsets();
display.setRotation(1);
}
/////////////////////////////////////////////////////////////
// Normalized line drawing (0,0) = bot left
voiddrawLine(在tx1,在ty1,在tx2,在ty2){
display.drawLine(x1,SCREEN_HEIGHT-y1,x2,SCREEN_HEIGHT-y2,1);
}
/////////////////////////////////////////////////////////////
// Normalized circle drawing (0,0) = bot left
voiddrawCircle(在tx,在ty,在t半径){
display.drawCircle(x,SCREEN_HEIGHT-y,半径-1,1);
}
/////////////////////////////////////////////////////////////
voiddrawBearing(floatbearing,在tmidx,在tmidy,在t半径){
bearing+=90;// Rotate arctan2 to vertical
在topp=sin(bearing*M_PI/180)*半径;
在tadj=cos(bearing*M_PI/180)*半径;
// Screen +y is down but drawLine adjusts it up.
drawLine(midx,midy,midx+adj,midy+opp);
}
/////////////////////////////////////////////////////////////
// Can choose whether to write to EEPROM for testing.
voidcalibrate(booleaneeprom_write){
unsignedlongcalTimeWas=millis();
在tx,y,z;
floatdeg=0,deg2=0;
readMagnetometer(&x,&y,&z);
maxx=minx=x;// Set initial values to current magnetometer readings.
maxy=miny=y;
delay(300);// Allow button release.
while(1){// Calibration loop.
if(数字的Read(BUTTON_CAL)==0||数字的Read(BUTTON_TEST)==0){
delay(300);// Allow button release.
return;// Abort
}
if(磁力计Ready())getMagnetometer(&x,&y,&z);
if(x>maxx)maxx=x;
if(x<minx)minx=x;
if(y>maxy)maxy=y;
if(y<miny)miny=y;
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0,0);
if(eeprom_write)display.print("CALIBRATE ");
elsedisplay.print("TEST ");
在tsecmillis=millis()-calTimeWas;
if(secmillis>CALTIME)break;// Exit after time up.
在tsecs=(在t)((CALTIME-secmillis+1000)/1000);
display.setCursor(0,32);display.print("--> ");display.print((在t)((CALTIME-secmillis)/1000));
drawBearing((在t)deg2,midx,midy,半径);
drawBearing((在t)deg,midx,midy,半径);
deg=(360.0/CALTIME)*secmillis;// Rotate a line for countdown duration.
deg2+=deg;// Rotate a line for countdown duration. Fun.
deg=fmod(deg,360);
for(在ti=0;i<360;i+=45)// 45 Degree spokes (rotating)
drawBearing(i+(45/secs)*10,midx,midy,半径-7);
display.display();// Update display.
delay(10);
}// while cal
calc_offsets();
if(eeprom_write){
在tEEAddr=EEADDR;
EEPROM.put(EEAddr,minx);EEAddr+=sizeof(minx);
EEPROM.put(EEAddr,maxx);EEAddr+=sizeof(maxx);
EEPROM.put(EEAddr,miny);EEAddr+=sizeof(miny);
EEPROM.put(EEAddr,maxy);EEAddr+=sizeof(maxy);
}
unsignedlongdispExitTimeWas=millis();
while(1){
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0,0);
// Make sure this does not repeat endlessly!
if(eeprom_write)display.print("EEPROM Written");
elsedisplay.print("TEST DMY Write");
if(millis()-dispExitTimeWas>2000)break;
display.display();// Update display.
delay(10);
}
}
/////////////////////////////////////////////////////////////
voidloop(){
英石aticunsignedlongBLTimeWas=millis();
在tx,y,z;// Raw compass output values.
在tbearing,i;
if(数字的Read(BUTTON_CAL)==0)calibrate(1);
if(数字的Read(BUTTON_TEST)==0)calibrate(0);
getMagnetometer(&x,&y,&z);
在tatan2val=180/M_PI*atan2((float)(x-offx),(float)(y-offy));
bearing=(-atan2val+360)%360;
// SSD1306 init.
display.clearDisplay();
// display fancy stuff
drawCircle(midx,midy,半径-1);// -1 as circle is 1 bigger
drawCircle(midx,midy,(半径-1)/2);
for(i=0;i<360;i+=45)// 45 Degree spokes
drawBearing(i,midx,midy,半径-7);
drawBearing(bearing,midx,midy,半径);
drawBearing(0,midx,midy,半径);// North
display.setTextSize(2);
在tlineH=16;
在tlineNum=2;
display.setCursor(15,lineH*lineNum);display.print(bearing);
display.print((char)247);
lineNum++;// Next line
if(x>maxy||x<minx||y>maxy||y<miny){
display.setCursor(0,lineH*lineNum++);display.print("*CAL*");
}
display.display();// Update display.
if(millis()-BLTimeWas>400){// LED toggle
BLTimeWas=millis();
英石aticbytetogLED=0;
togLED=!togLED;
if(togLED)数字的Write(LED,HIGH);else数字的Write(LED,LOW);
}
}
// End of HMC5883L OLED compass.
5883 - 这是QMC5883L芯片。
If your's has the text 'L883'在它上,那么你有HMC5883L芯片。
4A2D - 超低丢弃稳压器LD3985。
测量的OP = 3V3所以部分是:LD3985M33R。
The dropout is:
0.4mV(典型值)@ 1mA〜60mV(典型值)@ 150mA。
2.0mv(max)@ 1ma〜100mv(max)@ 150mA。
702 - 双N沟道FET(〜L2N7002DW1T1G)
The RDS(开) of the MOSFET is 7Ω
- that's
确定取决于应用程序 - 这里,它只是逻辑级别所以
电流很低,但你可以获得许多较新的MOSFET与RDSON
70〜100mΩ(或更低)的范围,用于更高的电流操作(如果需要)。
替代突破板(两芯片)
这是我买的另一个板的图像;虽然HMC5883L打印
在丝网上,安装了一个QST设备,所以不要't trust the
silkscreen label!.
GY 273 HMC5883L突破板
请注意,董事会如何标记为HMC5883L,即使它实际上确实如此
有一个QMC5883焊接!这有点顽皮,但是
由于制造商可能有1000个,可以理解's of pcbs and the
QMC部分确实具有与HMC版本相同的引脚。但是,如果是HMC
版本拟合来自微控制器控制输出的主要伏特将
必须设计为最大输出为4.8V。
新的! Comments
让你说到你刚刚阅读的东西!留下下面的框中的评论。