Акселерометр. Гироскоп. Магнитометр.

В данной статье мы рассмотрим несколько датчиков: акселерометр, гироскопы и магнитометр. Эта статья стала послесловием недавней задачи, которую мы решаем. Считывание данных с этих датчиков было сделано, чтобы создать простейшую инерциальную навигационную систему, которая должна определять углы Эйлера твердого тела. Мы же посмотрим на возможности этих устройств, расскажем про подбор фильтров, питания, особенностей установки. Покажем наглядно на графиках качественные отличия и как обычно предоставим код для микроконтроллеров AVR для всех перечисленных в статье датчиков. Сразу отмечу, что рассказать в статье сразу про 3 датчика было осознанным действием. Ты увидишь далее, что считывание и запись данных в них - совершенно шаблонное действие.Нашими подопечными будут следующие датчики:

1. Гироскоп MMA7455L

2. Акселерометр L3G4200D

3.  Гироскоп + магнитометр LSM303DLM.

Для начала ликбез:

В нашей статье гироскопом называется устройство, которое измеряет угловую скорость. Акселерометром - измеряющее 3 составляющих ускорения (и ускорение свободного падения тоже, оно абсолютно равноправно.). Магнитометром - измеряющее 3 составляющих магнитного поля.

Не стоит питать возвышенных чувств к полупроводниковым датчикам. Несмотря на передовые технологии, которые реализовали в этих устройствах фирмы Analog Devices и ST, они никак чисто из-за физики своего устройства и как следствие - погрешностей, уровню шумов и чувствительности, неинвариантности к внешним условиям применения не способны заменить механические датчики, применяемые военными в тех устройствах, которые имеют специальное назначение. Эти датчики были созданы для портативных устройств . Их задача - определять углы поворота твердого тела, углы наклона по отношению к вектору силы тяжести при допущении, что ускорение твердого тела мало, а также в задачах навигации на открытой местности магнитометр хорошо справится с указанием на север. Все датчики из статьи - новые (ну может за исключением MMA7455L) . Их разработали пару лет назад и поставляют до сих пор. Например гироскоп L3G4200D был установлен фирмой Apple в iPhone 4. Учитывая динамику этих датчиков можно смело сказать, что они будут доступны еще как минимум 3 года.

Все датчики имеют цифровой канал связи. С ними можно работать через I2C и SPI. Я выбрал I2C, почему:

1. На плате, на которой я их протестировал, не было возможностей для использования  SPI. SPI требует число ножек контроллера, равное (n+3), где n - число устройств на шине. Получается 6 ножек. Это перебор. Столько не было.

2. Эти датчики - очень медленные. Их скорость преобразования - не более 200-400 Гц . Я использую самые медленные настройки и имею что-то около 60 Гц. С такими скоростями отлично справится I2C. На самом деле, проведем расчет: I2C запущена и отлично держит скорость работы 100 кГц.  Максимальная заявленная скорость - 400 кГц. В публикациях, где веселые китайцы делают устройство инерциальной навигации на них, они разогнали их до 722кГц благодаря работе на ПЛИС, они очень гибко снимают с них данные - по сути параллельно по мере возникновения прерывания о готовности нового результата. Работа I2C не зависит от скорости работы. В этом очень большое преимущество - при отладке можно хоть переключателем данные слать как в старых аппаратах телеграфа и смотреть на мигание светодиода - определять какое число пришло. Итак типовая операция "прочитать регистр" содержит в себе 4 действия(каждое действие - посылка байта):

1. выдать условие "старта" и передать адрес устройства.

2. передать адрес регистра для считывания

3.  выдать условие "старта" и передать адрес устройства, выставив бит чтения.

4.  получить байт без подтверждения.

5. дождаться условия "стоп"

Без учета задержек на принимаемом устройстве мы получаем номинально около 30 бит, что означает 30 тактов работы устройства I2C.  При скорости 100 кГц и частоте преобразования 100 Гц на каждое преобразование мы имеем 1000 тактов работы устройства I2C. Нужно учесть, что одно измерение - это 3 оси и 6 регистров данных. Это говорит о том, что шина I2C сможет эффективно работать более, чем с 5 устройствами подобного рода на одной шине. Ну или с 2 при выставленной максимальной скорости преобразования на них. Если использовать режим считывания нескольких регистров, то это число можно поднять не более, чем в 2 раза. Однако тут сидят подводные камни, о чем позже.

Важные параметры питания датчиков:

1. Эти штуки питаются от 2.4 до 3.6 вольт напряжения. (min до 1.8 вольт - напряжение питания ввода/вывода). Их линии ввода-вывода не толерантные к 5 вольт.

2. Важно не устанавливать их вблизи силовых дорожек. Также нельзя их ставить вблизи импульсных источников питания. Все это приведет к большому увеличению шума и мы это покажем наглядно.

3. Лично я питаю их от линейного источника питания, на вход которого подается стабилизированное питание от импульсного преобразователя.

4. Превышение напряжения питания 3.6 вольт может не вывести датчик из строя, однако он будет работать хуже или даже неправильно: уменьшится чувствительность, будут потери данных в регистрах инициализации и ошибки при работе i2c. Это сложно детектировать, поэтому очень важен выбор питания. Никаких выбросов и провалов по земле не должно быть. При наличии силовой части в устройстве - нужно полностью разделить земли и использовать хороший стабилизатор входного питания.

Особенности подключения:

1. Подтянуть линии SDL, SDA к верхнему уровню.

Здесь используются резисторы 10 КОм. Это много для шины I2C, рекомендуется не более 4.7 КОм и даже 1 КОм. Это актуально для тех, кто будет использовать датчики в режиме высокой скорости I2C. При таких подтяжках на 400 КГц фронты будут безнадежно завалены.

2. Сага о преобразователях уровней. Их приходится использовать. Одна особенность, на которую я напоролся. Очень долго промучался с этим. Это касается преобразователей уровней от фирмы MAX. На рисунке изображен правильный вариант подключения:

Вот смотрите. Шина I2C использует 3 состояния. Ей нужно Z состояние тоже. Поэтому я в преобразователе подтянул этот вход к верхнему уровню. ОДНАКО, особенно внимательные заметили наверно, что эта микросхема как бы разделена на двое: слева - всё, что касается 1 напряжения питания, допустим, это 3.3 вольта, правая часть  - как бы другая сторона 5 вольт. Так вот, даже во всех там рекламных чудо публикациях производитель для наглядности использует этот факт, в структурной схеме вы также увидите этот прием. Не тут то было, вход 3 state НЕ ТОЛЕРАНТЕН к 5 вольт. Если вы подтянете его к 5 вольт - откроется защитный диод и в некоторых случая микросхема защелкнется, в других будет греться и тоже не выполнять свою функцию. Это просто жесть и введение в заблуждение разработчика, однако, производителю на это наплевать. На данный вопрос, фирма MAX не прислала никакого ответа. Подтягивать 3state нужно к тому напряжению, которое слева, хотя он и расположен по ту сторону баррикад. Отмечу, что 3state - это всего лишь включение внутренних подтяжек к верхнему уровню. Это нужно для того, чтобы когда устройство на шине I2C переходит выводами в Z состояние, сохранялась определенность потенциала линии. Скорее всего, трансивер I2C реализован в виде открытых коллекторов, в которых 2 состояния: 0 и Z.

Слева на картинке вы видите чудо линейный преобразователь LM1117. Это дерьмо характерно тем, что может вместо 3.3 вольт выдать что-то в диапазоне 3.3 - 4.1 вольт и убить нафиг девайс. И зависит его поведение от длины дорожек, от нагрузки (потребляемого тока). Но больше - от проводов, т.е. длины питающих линий. В чем дело - я не знаю, купил в Терре. Вот тут, кстати, обсуждение этого глюка. Я думаю - контрафакт. Я решил эту проблему - выведением преобразователя в зону повышенного потребления - нагрузил резисторами. Это греется, но работает.  Это происшествие прибило мои датчики. Они все равно работали, но неверно. Да, кондеры на входе и на выходе есть. Всё сделано по даташиту, они просто не уместились на этой картинке. Из-за этого происшествия время поднятия этих датчиков выросло недели на 2. Уже позднее я выпаял этот преобразователь и поставил другой. Он выдавал уже нормально 3.3 вольта. Прием вывода преобразователя в зону повышенного потребления - это старый инструмент. Впервые я столкнулся с необходимостью этого на дешевых AC/DC. Дело в том, что при резко изменяющейся нагрузке, например, включению реле, такие устройства при низком потреблении не способны быстро отдать ток. Их динамика зависит от текущего тока потребления и если их вывести в зону номинальных токов, то они будут лучше стабилизировать выходное напряжение. Эту проблему может также решить блокирующий конденсатор.

Итак, теперь перейдем к делу.

Рутина I2C.  

Сразу хочу отметить, я уже точно не помню, откуда у меня появились некоторые исходники для I2C, помню что для чтения и записи я немного их поменял, а вот файлы twimaster.h, twimaster.c от другого автора.

Работу с I2C я построил следующим образом:

- twimaster - для работы с i2c непосредственно.

- I2C_IO - драйвер для операций ввода-вывода, т.е. чтения и записи в регистры устройства.

Эта основа универсальна для всех датчиков и  всех контроллеров AVR, я ее приложу в конце статьи.

Датчики.

MMA7455L. 3х осевойАкселерометр от Analog Devices.

Digital Output (I2C/SPI)
• 3mm x 5mm x 1mm LGA-14 Package
• Self-Test for Z-Axis
• Low Voltage Operation: 2.4 V – 3.6 V
• User Assigned Registers for Offset Calibration
• Programmable Threshold Interrupt Output
• Level Detection for Motion Recognition (Shock, Vibration, Freefall)
• Pulse Detection for Single or Double Pulse Recognition
• Sensitivity (64 LSB/g @ 2g and @ 8g in 10-Bit Mode)
• Selectable Sensitivity (±2g, ±4g, ±8g) for 8-bit Mode
• Robust Design, High Shocks Survivability (5,000g)
• RoHS Compliant
• Environmentally Preferred Product
• Low Cost
Typical Applications
• Cell Phone/PMP/PDA: Image Stability, Text Scroll, Motion Dialing,
Tap to Mute
• HDD: Freefall Detection
• Laptop PC: Freefall Detection, Anti-Theft
• Pedometer
• Motion Sensing, Event Recorder

 

 

 

 

Схема подключения:

Заметим, младший значащий бит адреса устройства будет 1, так как Iaddr0 подтянуто к верхнему уровню.

Список регистров:

Address

Name

Definition

Bit 7

Bit 6

Bit 5

Bit 4

Bit 3

Bit 2

Bit 1

Bit 0

$00

XOUTL

10 bits output value X LSB

XOUT[7]

XOUT[6]

XOUT[5]

XOUT[4]

XOUT[3]

XOUT[2]

XOUT[1]

XOUT[0]

$01

XOUTH

10 bits output value X MSB

-

-

-

-

-

-

XOUT[9]

XOUT[8]

$02

YOUTL

10 bits output value Y LSB

YOUT[7]

YOUT[6]

YOUT[5]

YOUT[4]

YOUT[3]

YOUT[2]

YOUT[1]

YOUT[0]

$03

YOUTH

10 bits output value Y MSB

-

-

-

-

-

-

YOUT[9]

YOUT[8]

$04

ZOUTL

10 bits output value Z LSB

ZOUT[7]

ZOUT[6]

ZOUT[5]

ZOUT[4]

ZOUT[3]

ZOUT[2]

ZOUT[1]

ZOUT[0]

$05

ZOUTH

10 bits output value Z MSB

-

-

-

-

-

-

ZOUT[9]

ZOUT[8]

$06

XOUT8

8 bits output value X

XOUT[7]

XOUT[6]

XOUT[5]

XOUT[4]

XOUT[3]

XOUT[2]

XOUT[1]

XOUT[0]

$07

YOUT8

8 bits output value Y

YOUT[7]

YOUT[6]

YOUT[5]

YOUT[4]

YOUT[3]

YOUT[2]

YOUT[1]

YOUT[0]

$08

ZOUT8

8 bits output value Z

ZOUT[7]

ZOUT[6]

ZOUT[5]

ZOUT[4]

ZOUT[3]

ZOUT[2]

ZOUT[1]

ZOUT[0]

$09

STATUS

Status registers

-

-

-

-

-

PERR

DOVR

DRDY

$0A

DETSRC

Detection source registers

LDX

LDY

LDZ

PDX

PDY

PDZ

INT2

INT1

$0B

TOUT

“Temperature output value” (Optional)

TMP[7]

TMP[6]

TMP[5]

TMP[4]

TMP[3]

TMP[2]

TMP[1]

TMP[0]

$0C

(Reserved)

-

-

-

-

-

-

-

-

$0D

I2CAD

I2C device address

I2CDIS

DAD[6]

DAD[5]

DAD[4]

DAD[3]

DAD[2]

DAD[1]

DAD[0]

$0E

USRINF

User information (Optional)

Ul[7]

Ul[6]

Ul[5]

Ul[4]

Ul[3]

Ul[2]

Ul[1]

Ul[0]

$0F

WHOAMI

“Who am I” value (Optional)

ID[7]

ID[6]

ID[5]

ID[4]

ID[3]

ID[2]

ID[1]

ID[0]

$10

XOFFL

Offset drift X value (LSB)

XOFF[7]

XOFF[6]

XOFF[5]

XOFF[4]

XOFF[3]

XOFF[2]

XOFF[1]

XOFF[0]

$11

XOFFH

Offset drift X value (MSB)

-

-

-

-

-

XOFF[10]

XOFF[9]

XOFF[8]

$12

YOFFL

Offset drift Y value (LSB)

YOFF[7]

YOFF[6]

YOFF[5]

YOFF[4]

YOFF[3]

YOFF[2]

YOFF[1]

YOFF[0]

$13

YOFFH

Offset drift Y value (MSB)

-

-

-

-

-

YOFF[10]

YOFF[9]

YOFF[8]

$14

ZOFFL

Offset drift Z value (LSB)

ZOFF[7]

ZOFF[6]

ZOFF[5]

ZOFF[4]

ZOFF[3]

ZOFF[2]

ZOFF[1]

ZOFF[0]

$15

ZOFFH

Offset drift Z value (MSB)

-

-

-

-

-

ZOFF[10]

ZOFF[9]

ZOFF[8]

$16

MCTL

Mode control

-

DRPD

SPI3W

STON

GLVL[1]

GLVL[0]

MOD[1]

MOD[0]

$17

INTRST

Interrupt latch reset

-

-

-

-

-

-

CLRINT2

CLRINT1

$18

CTL1

Control 1

DFBW

THOPT

ZDA

YDA

XDA

INTRG[1]

INTRG[0]

INTPIN

$19

CTL2

Control 2

-

-

-

-

-

DRVO

PDPL

LDPL

$1A

LDTH

Level detection threshold limit value

LDTH [7]

LDTH [6]

LDTH [5]

LDTH[4]

LDTH [3]

LDTH[2]

LDTH[1]

LDTH[0]

$1B

PDTH

Pulse detection threshold limit value

PDTH[7]

PDTH[6]

PDTH[5]

PDTH[4]

PDTH[3]

PDTH[2]

PDTH[1]

PDTH[0]

$1C

PW

Pulse duration value

PD[7]

PD[6]

PD[5]

PD[4]

PD[3]

PD[2]

PD[1]

PD[0]

$1D

LT

Latency time value

LT[7]

LT[6]

LT[5]

LT[4]

LT[3]

LT[2]

LT[1]

LT[0]

$1E

TW

Time window for 2nd pulse value

TW[7]

TW[6]

TW[5]

TW[4]

TW[3]

TW[2]

TW[1]

TW[0]

$1F

(Reserved)

-

-

-

-

-

-

-

-

Датчик - 2008 года. И тогда, видимо, еще не было возможности для дешевых датчиков у производителя сделать разрешающую способность - 16 бит. Здесь только 10 значащих бит. Кроме того, ВСЕ ДАННЫЕ ПО ИЗМЕРЕНИЯМ ИДУТ В ФОРМАТЕ 2'S. Это формат дополнительного кода = представление отрицательных чисел. И это нужно учитывать при выводе результатов и не жаловаться на то, что выводится какой-то бред и все положительные. Все API функции в выложенных здесь файлах - выводят в формате int16_t, поэтому такой проблемы возникнуть тут не должно.  Все остальные разъяснения приведем на примере кода.

Инициализация:

Настраиваем регистр 0x16. (замечу, что адреса регистров в шестнадцатеричной форме).

D7

D6

D5

D4

D3

D2

D1

DO

Bit

-

DRPD

SPI3W

STON

GLVL[1]

GLVL[0]

M0DE[1]

MODE[0]

Function

0

0

0

0

0

0

0

0

Default

GLVL [1:0]

00: 8g is selected for measurement range.

10: 4g is selected for measurement range.

01: 2g is selected for measurement range.

STON

0: Self-test is not enabled

1: Self-test is enabled

MODE [1:0]

00: Standby Mode

01: Measurement Mode

10: Level Detection Mode

11: Pulse Detection Mode

SPI3W

0: SPI is 4 wire mode

1: SPI is 3 wire mode

DRPD

0: Data ready status is output to INT1/DRDY PIN

1: Data ready status is not output to INT1/DRDY PIN

Table 11. Configuring the Mode using Register $16 with MODE[1:0] bits

MODE [1:0]

Function

00

Standby Mode

01

Measurement Mode

10

Level Detection Mode

11

Pulse Detection Mode

void initAxel()
	{
	writeI2Cbyte(MMA7455_I2CADDR,0x16,0b00000101);
	}

Здесь мы включили режим непрерывных измерений и в качестве диапазона измерений выбрали +/-2g.

Считывание регистров:

uint16_t axel[1];
uint16_t getAxelX()
	{
	readI2CbyteArray(MMA7455_I2CADDR,MMA7455_XOUT10,(uint8_t *)axel,2);
 
		return axel[0];
	}
 
uint16_t getAxelY()
	{
	readI2CbyteArray(MMA7455_I2CADDR,MMA7455_YOUT10,(uint8_t *)axel,2);
			return  axel[0];
	}
 
uint16_t getAxelZ()
	{
	readI2CbyteArray(MMA7455_I2CADDR,MMA7455_ZOUT10,(uint8_t *)axel,2);
	 return axel[0];
	}

Здесь мы для убыстрения считываем сразу несколько регистров. (вообще можно было считать сразу все, но для удобства понимания, я сделал так).  А теперь внимание, сейчас это число представлено в дополнительном коде. Чтобы его вывести - нужно провести операцию копирования в память, где расположена переменная int16_t, присваивание использовать довольно опасно, так как результат такого зависит от компилятора. Удобнее всего использовать memcpy, как будет показано далее.

int16_t resX;
int16_t resY;
int16_t resZ;
uint16_t X=(getAxelX()<<6);
memcpy(&resX,& X,sizeof( uint16_t ));
uint16_t Y=(getAxelY()<<6);
memcpy(&resY,& Y,sizeof( uint16_t ));
uint16_t Z=(getAxelZ()<<6);
memcpy(&resZ,& Z,sizeof( uint16_t ));

На этом всё, результат работы показан на графиках. Плата совершает вращательные реверсивные движения.  На оси проецируется центростремительное и тангенциальное ускорения тех точек, куда припаяны датчики.

Как вы видите - результат не очень. Приводить статистические данные не буду, поправку на ноль не делали.  Датчик был установлен неудачно. Те советы, которые были озвучены - не были учтены.Кроме того,  за 3 года датчики стали более совершенны и это можно будет увидеть далее.

Гироскоп L3G4200D

Этот датчик от фирмы ST. Датчики от ST по моим наблюдениям обладают лучшим соотношением цена/качество. Они меньше шумят.

1. Шкала измерений 200/500/2000 градусов в секунду

2. I2C+SPI

3. 16 битные измерения

4. Датчик температуры 8 бит.

5. Встроенные фильтры высоких и низких частот.

Схема подключения:

Вверху схемы - фильтр ФАПЧ. Он нужен обязательно. Я в инете встречал пример, где его не было. Это бред, это подтвердил производитель. Напряжение питания я выбрал 3.3 вольта.

Разбор полёта:

Список регистров

Name

Type

Register address

Default

Comment

Hex

Binary

Reserved

-

00-OE

-

-

WHO_AM_l

r

OF

000 1111

11010011

Reserved

-

10-1F

-

-

CTRL_REG1

rw

20

010 0000

00000111

CTRL_REG2

rw

21

010 0001

00000000

CTRL_REG3

rw

22

010 0010

00000000

CTRL_REG4

rw

23

010 0011

00000000

CTRL_REG5

rw

24

010 0100

00000000

REFERENCE

rw

25

010 0101

00000000

OUT_TEMP

r

26

010 0110

output

STATUS_REG

r

27

010 0111

output

OUT_X_L

r

28

010 1000

output

OUT_X_H

r

29

010 1001

output

OUT_Y_L

r

2A

010 1010

output

OUT_Y_H

r

2B

010 1011

output

OUT_Z_L

r

2C

010 1100

output

OUT_Z_H

r

2D

010 1101

output

FIFO_CTRL_REG

rw

2E

010 1110

00000000

FIFO_SRC_REG

r

2F

010 1111

output

INT1_CFG

rw

30

011 0000

00000000

INT1_SRC

r

31

011 0001

output

INT1_TSH_XH

rw

32

011 0010

00000000

INT1_TSH_XL

rw

33

011 0011

00000000

INT1_TSH_YH

rw

34

011 0100

00000000

INT1_TSH_YL

rw

35

011 0101

00000000

INT1_TSH_ZH

rw

36

011 0110

00000000

INT1_TSH_ZL

rw

37

011 0111

00000000

INT1_DURATI0N

rw

38

011 1000

00000000

Дальше также на примере кода:

uint8_t gyroInit(uint8_t l3g4200address)
	{
 
	// Включили оси x, y, z, выключили режим энергосбережения:
	writeI2Cbyte(l3g4200address, CTRL_REG1, 0b00111111);//скорость преобразования 100 Гц,полоса - 25Гц
 
	  // настройки фильтра высоких частот
	writeI2Cbyte(l3g4200address, CTRL_REG2, 0b00100011); //нижняя частота - 1 Гц.
 
	  // настройка прерываний
	writeI2Cbyte(l3g4200address, CTRL_REG3, 0b10001000); // INT1 включен, INT2 готовность данных тоже
 
	  // общие настройки: диапазон +/- 250 градусов в секунду, выключено самотестирование
	writeI2Cbyte(l3g4200address, CTRL_REG4, 0b10000000);//включена защита обновления данных при считывании
	  // включен сброс настроек при перезагрузке
	writeI2Cbyte(l3g4200address, CTRL_REG5, 0b11000000); // включен буфер FIFO, все фильтры отключены
 
	writeI2Cbyte(l3g4200address, 0x2E, 0b00000000); // включен режим, когда считывается самый свежий результат, сохраненный в FIFO.
        return (readI2Cbyte(l3g4200address,0x0F)==L3G4200D_WHOAMI); // проверка. Эй там, ты вообще жив?
	}

Результаты работы на графиках. Тип движений - те же самые.  Количество колебаний вокруг осей - разное.

На мой взгляд, данные сняты хорошо. Уровень шума в покое составляет не более 0.1-0.2% шкалы.

LSM303DLH. Акселерометр+гироскоп.  Устройство содержит в себе 2 в одном.

■ Analog supply voltage: 2.5 V to 3.3 V
■ Digital supply voltage IOs: 1.8 V
■ Power-down mode
■ 3 magnetic field channels and 3 acceleration
channels
■ ±1.3 to ±8,1 gauss magnetic field full-scale
■ ±2 g/±4 g/±8 g dynamically selectable fullscale
■ 16-bit data out
■ I2C serial interface

Не буду заострять внимание на этом датчике. Считывание данных происходит по такой же схеме.

Акселерометр.

 

Покажу графики для примера:

uint16_t AX;
uint16_t AY;
uint16_t AZ;
int16_t A_X;
int16_t A_Y;
int16_t A_Z;
uint8_t LSM303DLH_initAxel(uint8_t axelAddress)
{
writeI2Cbyte(axelAddress, CTRL_REG1_A, 0b00100111); //включили оси, режим постоянной работы
return (readI2Cbyte(axelAddress,0x0F)==axel_WHO_AM_I);
}
 
int16_t LSM303DLH_getAxel_X()
{
	AX=((readI2Cbyte(LSM303DLM_axel_ADDRESS0,0x29)<<8)+(readI2Cbyte(LSM303DLM_axel_ADDRESS0,0x28)));
	memcpy(&A_X,&AX, sizeof ( uint16_t ));
	return A_X;
}
 
int16_t LSM303DLH_getAxel_Y()
{
	AY=((readI2Cbyte(LSM303DLM_axel_ADDRESS0,0x2B)<<8)+(readI2Cbyte(LSM303DLM_axel_ADDRESS0,0x2A)));
	 memcpy(&A_Y,&AY, sizeof ( uint16_t ));
	 return A_Y;
}
 
int16_t LSM303DLH_getAxel_Z()
{
	AZ=((readI2Cbyte(LSM303DLM_axel_ADDRESS0,0x2D)<<8)+(readI2Cbyte(LSM303DLM_axel_ADDRESS0,0x2C)));
	 memcpy(&A_Z,&AZ, sizeof ( uint16_t ));
	 return A_Z;
 
}

Не ругайтесь за глобальные переменные. Они играют роль буфера - временного хранения данных. Из этих переменных берутся данные для их последующего использования. Функции же вызываются в прерывании - когда готов результат. Графики в студию:

Данные намного лучше, чем у MMA7455L. Менее шумные и более чувствительные.

Магнитометр. Принципиально - все также при считывании. Диапазон измеряется в Гауссах. От 1.3 до 8.1. Для измерения магнитного поля Земли нужно выбрать в районе 1 Гаусса.

Лучше поясним на примере кода:

   uint16_t MX=0;
   uint16_t MY=0;
   uint16_t MZ=0;
 
   int16_t M_X;
   int16_t M_Y;
   int16_t M_Z;
 
uint8_t LSM303DLH_initMagnet(uint8_t magnetAddress)
{
	writeI2Cbyte(magnetAddress, CRA_REG_M, 0b00010100); // скорость работы - 30 Гц
	writeI2Cbyte(magnetAddress, CRB_REG_M, 0b11100000); // диапазон +/- 8.1 Гаусса
	writeI2Cbyte(magnetAddress, MR_REG_M,  0b00000000); // режим непрерывных измерений
	return (readI2Cbyte(magnetAddress,0x0F)==magnet_WHO_AM_I);
}
 
int16_t LSM303DLH_getMagnet_X()
{
	MX=((readI2Cbyte(LSM303DLM_magnet_ADDRESS0,0x03)<<8)+(readI2Cbyte(LSM303DLM_magnet_ADDRESS0,0x04)));
	memcpy(&M_X,&MX, sizeof ( uint16_t ));
	return M_X;
}
 
int16_t LSM303DLH_getMagnet_Y()
{
	MY=((readI2Cbyte(LSM303DLM_magnet_ADDRESS0,0x05)<<8)+(readI2Cbyte(LSM303DLM_magnet_ADDRESS0,0x06)));
	memcpy(&M_Y,&MY, sizeof ( uint16_t ));
    return M_Y;
}
 
int16_t LSM303DLH_getMagnet_Z()
{
	MZ=((readI2Cbyte(LSM303DLM_magnet_ADDRESS0,0x07)<<8)+(readI2Cbyte(LSM303DLM_magnet_ADDRESS0,0x08)));
	memcpy(&M_Z,&MZ, sizeof ( uint16_t ));
	return M_Z;
}

Графики:

Для себя я сделал вывод, что используя магнитометр можно определять абсолютное направление на север. Даже в помещении магнитометр не выдает каких-то хаотических показаний. Его показания в целом закономерны и привязаны  к абсолютному угловому положению.

Скачать проект: исходники для всех датчиков, драйвер ввода-вывода, рутина I2C.

Leave a Reply

You must be logged in to post a comment.