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

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

У акселерометра есть два интерфейса для обмена данными — i2c и SPI. Использовать мы будем последний, благо я еще не забыл как это делать, да и разводка платы подразумевает его использование. Сам акселерометр обладает следующими характеристиками: 

  • Напряжение питания 2.16 — 3.6 в.
  • Измерение ускорения по трём осям
  • Два диапазона измерения 2G/8G
  • Два настраиваемых выхода для прерываний
  • Самодиагностика
  • Обнаружение кликов (постукиваний)
  • Встроенный фильтр
  • Корпус LGA14

Пожалуй, последняя характеристика является минусом данного датчика, он очень мелкий и я рад что мне не придётся ничего паять 🙂 Сразу предупреждаю, что меня одолело графоманство и поэтому букв будет много, запаситесь терпением. У чипа 14 ног, их назначение описано в таблице ниже, а картинка показывает нумерацию выводов и расположение  осей:

Номер выводаИмяНазначение
1Vdd_IOПитание ножек I/O
2GNDЗемля
3ReservedЗарезервировано. Подключать к питанию
4GNDЗемля
5GNDЗемля
6VddПитание
7CSВыбор интерфейса. Если на ноге лог. 1, то акселерометр думает, что используется i2c, в противном случае – SPI.
8INT 1Вывод прерывания 1
9INT2Вывод прерывания 2
10GNDЗемля
11ReservedЗарезервировано, подключить к земле
12SDOВ режиме SPI эта нога служит для передачи данных к мастеру (MISO). Если используется i2c интерфейс, то логический уровень на этой ноге определяет младший бит адреса. Т.е. если на ней лог. 0, то адрес устройства —  0x1C, в противном случае адрес будет 0x1D
13SDASDISDOЕсли используется i2c интерфейс, то этот вывод используется для передачи данных (SDA). В режиме SPI эта нога служит для приёма данных от мастера (MOSI). Если используется 3-х проводной режим SPI, то через этот вывод происходит двусторонний обмен данными.
14SCLSPCЕсли используется i2c интерфейс, то этот вывод используется для передачи тактовых импульсов (SCL), в режиме SPI он тоже используется для тактирования (SCK)

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

На картинке изображены 4 линии интерфейса SPI, каждый бит подписан:

  • DO7..DO0 — байт данных отправленный акселерометром в микроконтроллер
  • DI7..DI0 — байт данных переданный микроконтроллером в акселерометр
  • AD5..AD0 — адрес записываемого/считываемого регистра
  • RW — если бит=0 то байт данных DI7..DI0 будет записан в регистр по адресу AD5..AD0, в противном случае (RW=1) байт данных DO7..DO0 будет прочитан из регистра по адресу AD5..AD0
  • MS — используется если мы хотим прочитать/записать несколько регистров подряд. Если бит сброшен, то после передачи адреса мы будем считывать/записывать один и тот же регистр вне зависимости от того, сколько раз будет предпринята попытка чтения/записи. Если же этот бит установлен, то адрес будет автоматически увеличиваться на единицу после каждой записи или чтения. 

Следующие четыре простых примера помогут понять как писать/читать регистры акселерометра:

Чтение одного регистра

Для того чтобы прочитать содержимое одного регистра (например с адресом 0x0F) нужно проделать следующую последовательность действий: 

  1. Вывод CS прижать к земле.
  2. Передать первый байт (0x8F) который содержит адрес считываемого регистра, сброшеный бит MS (так как мы читаем только один регистр) и установленый бит RW (ведь мы читаем данные)
  3. Передать любой байт. Ведь интерфейс SPI так устроен, что слейв (наш акселерометр) не может передавать данные по своей инициативе. Поэтому он начнет передавать значение хранящееся в регистре только в момент передачи микроконтроллером второго байта (который по сути будет просто проигнорирован).
  4. Прочитать значение из регистра данных SPI (то, что пришло от акселерометра) 
  5. Установить высокий логический уровень на выводе CS

Если нам требуется очень быстро читать один и тот же регистр, то можно постоянно повторять шаги 3 и 4.

Запись одного регистра

Она не сложней чтения, попробуем записать байт  0x47 в регистр с адресом 0x20. Для этого нужно: 

  1. Вывод CS прижать к земле
  2. Передать первый байт (0x20) который содержит адрес записываемого регистра, сброшеный бит MS (так как мы пишем только один регистр) и сброшенный бит RW (ведь мы пишем данные)
  3. Передать новое значение регистра (0x47)
  4. Установить высокий логический уровень на выводе CS

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

Чтение нескольких регистров

Очень удобная вещь, можно взять и за один раз прочитать всю память акселерометра 🙂 Для того чтоб начать чтение, указываем адрес с которого нужно начать (например 0x0F) . А потом просто читаем байт за байтом. Алгоритм такой:

  1. Вывод CS прижать к земле.
  2. Передать первый байт (0xCF) который содержит адрес считываемого регистра, установленный бит MS (так как мы читаем несколько регистров) и установленый бит RW (ведь мы читаем данные)
  3. Передать любой байт. Ведь интерфейс SPI так устроен, что слейв (наш акселерометр) не может передавать данные по своей инициативе. Поэтому он начнет передавать значение хранящееся в регистре только в момент передачи микроконтроллером второго байта (который по сути будет просто проигнорирован).
  4. Прочитать значение из регистра данных SPI (то, что пришло от акселерометра) 
  5. Повторять шаги 3 и 4 пока не прочитаем столько регистров сколько нужно. Адрес чтения будет увеличиваться на единицу сам.
  6. Установить высокий логический уровень на выводе CS

 Запись нескольких регистров

Работает аналогично чтению нескольких регистров т.е. после каждой записи адрес автоматически увеличивается на единицу. Запишем три байта 0x47, 0x10 и 0x40 в регистры с адресами 0x20, 0x21 и 0x22:

  1. Вывод CS прижать к земле
  2. Передать первый байт (0x60) который содержит адрес первого записываемого регистра (0x20), установленый бит MS (так как мы пишем в несколько регистров) и сброшенный бит RW (ведь мы пишем данные)
  3. Передать новое значение (0x47) регистра 0x20
  4. Передать новое значение (0x10) регистра 0x21
  5. Передать новое значение (0x40) регистра 0x22
  6. Установить высокий логический уровень на выводе CS

Осталось только разобраться, какие регистры есть у акселерометра и для чего они нужны. 

Who_Am_I (0x0F)

Регистр, содержащий идентификатор акселерометра LIS302DL. Значение можно только прочитать, читаться будет 0x3b. Ничем другим регистр не примечателен

CTRL_REG1 (0x20)

 Первый регистр настройки. Его биты в таблице ниже: 

DR (0)PD (0)FS (0)STP (0)STM (0)Zen (1)Yen (1)Xen (1)

DR – бит настраивает частоту выборки. Если он установлен, то частота 400Гц, если сброшен то 100Гц.  Скорее всего, влияет на точность измерений.PD – бит управления питанием. Бит сброшен – питание выключено и наоборот. Пока не установлен этот бит, бесполезно добиваться от акселерометра каких-то измерений.FS – бит выбора диапазона измерений. Бит сброшен – диапазон ±2.0g, если установлен, то диапазон измерений ±8.0gSTP и STM – биты управления режимом самодиагностики. Если верить аппноуту AN2335, то возможны следующие комбинации:

STPSTMНазначение
00Самодиагностика выключена
01Самодиагностика. Режим P
10Самодиагностика. Режим M
11Запрещенная комбинация

Zen – бит разрешает генерацию сигнала готовности  данных для оси Z. Даже если сбросить бит, ускорение по этой оси будет измеряться, но флаг готовности данных (в регистре STATUS_REG)  не выставится.Yen – то же самое только для оси YXen – то же самое только для оси X

CTRL_REG2 (0x21)

Второй регистр настройки 

SIM (0)BOOT (0)FDS (0)HP_FF_WU2(0)HP_FF_WU1(0)HP_coeff2(0)HP_coeff1(0)

SIM – бит выбора режима SPI. Если установлен, то акселерометр переключится в трёхпроводной режим SPI. (приём и передача будет происходить по одному проводу). По умолчанию он сброшен и SPI работает в обычном 4-х проводном режиме.BOOT – при записи единицы в этот бит, происходит сброс всех настроек акселерометра по умолчанию.  Регистры статуса не сбрасываются.FDS – включить/выключить фильтр. Если бит установлен, то притяжение земли не оказывает влияние на измерения и наоборот. Проще говоря, если фильтр включен, то пока к акселерометру не прикладывается ускорение, в регистрах данных X,Y,Z будут нули (или почти нули). Если же выключить фильтр, то данные в регистрах X,Y,Z будут зависеть от ориентации акселерометра в пространстве. Как-то так.HP_FF_WU2 и HP_FF_WU1 – включают/выключают фильтр верхних частот для двух модулей генерирующих прерывания (FF_WU1 и FF_WU2). Частота среза фильтра настраивается при помощи бит HP_coeff2 и HP_coeff1:

HP_coeff2HP_coeff1Частота среза  (Бит DR=0)Частота среза  (Бит DR=1)
002 Гц8 Гц
011 Гц4 Гц
100.5 Гц2 Гц
110.25 Гц1 Гц

CTRL_REG3 (0x21)

Регистр настройки прерываний 

IHL(0)PP_OD(0)I2CFG2(0)I2CFG1(0)I2CFG0(0)I1CFG2(0)I1CFG1(0)I1CFG0(0)

IHL – если бит сброшен, то при возникновении прерывания, на ногах INT1 и INT2 появится логическая единица. Если бит установлен, то пока прерывание не случилось  на  выводах INT1 и INT2 присутствует логическая единица, а в момент возникновения прерывания, на вывод подается логический ноль.PP_OD – тип выводов INT1 и INT2. 0 – push-pull, 1 – открытый коллектор.При помощи бит I2CFG [2..0] и I1CFG [2..0] можно выбрать источник который будет вызывать прерывания INT1 и INT2. 

I1(2)_CFG2I1(2)_CFG1I1(2)_CFG0Источник
000Прерывание выкл. Нога подключена к земле.
001FF_WU_1
010FF_WU_2
011FF_WU_1 или FF_WU_2
100Данные готовы
111Прерывание от клика

FF_WU_1 и FF_WU_2 это два независимых блока предназначенных для генерации прерываний в случае если ускорение по одной или нескольким осям, выйдет за заданный порог.

HP_FILTER_RESET (0x23)

Регистр-пустышка непонятного назначения. Если у нас включен фильтр верхних частот, и мы прочитаем содержимое этого регистра, то в регистры Out_X, Out_Y и Out_Z запишутся нули. Кстати как я понял тут важен сам факт чтения регистра, а не те данные, которые прочитались из него.

STATUS_REG (0x27)

Регистр статуса, каждый бит которого, является флагом определённого события: 

 ZXYOR (0) ZOR (0)YOR (0)XOR (0) ZYXDA (0)ZDA (0)YDA(0) ZDA (0)

ZXYOR – Данные в регистрах Out_X, Out_Y и Out_Z были перетёрты новыми значениями, а их предыдущее содержимое не успели прочитать.ZOR – Данные в регистре Out_Z перетёрлись новыми, до того как были прочитаны старые.YOR – Данные в регистре Out_Y перетёрлись новыми, до того как были прочитаны старые.XOR – Данные в регистре Out_X перетёрлись новыми, до того как были прочитаны старые.ZYXDA – Доступны новые данные в регистрах Out_X, Out_Y и Out_ZZDA – Доступны новые данные в регистре Out_ZYDA – Доступны новые данные в регистре Out_YXDA – Доступны новые данные в регистре Out_X

OUT_X (0x29)

Восьмибитный регистр данных, в который записывается ускорение по оси X

OUT_Y (0x2b)

Восьмибитный регистр данных, в который записывается ускорение по оси Y

OUT_Z (0x2d)

Восьмибитный регистр данных, в который записывается ускорение по оси Z

Теперь начинается самое интересное. У акселерометра есть два независимых модуля, которые умеют самостоятельно читать данные из регистров Out_XOut_YOut_Z и на их основе генерировать прерывания которые будут возникать при определённых условиях. Для настройки каждого модуля используются 4 регистра которые будут описаны ниже. Кстати для удобства отладки можно прицепить к ногам INT1/INT2 по светодиоду через резистор. Тогда если прерывание случится это будет сразу видно.

FF_WU_CFG_1(0x30), FF_WU_CFG_2(0x34)

Регистр настраивает условия возникновения прерывания.

  AOI (0)  LIR (0)ZHIE  (0)  ZLIE (0)YHIE (0)YLIE (0)XHIE (0)XLIE (0)

AOI – бит определяет в каком случае надо сгенерировать прерывание. Если он сброшен, то прерывание возникнет, когда произойдет ЛЮБОЕ из событий  выбранных битами XHIE/YHIE/ZHIE/XLIE/YLIE/ZLIE. Если бит установлен, то чтоб прерывание возникло, нужно чтоб случились ВСЕ события выбранные битами XHIE/YHIE/ZHIE/XLIE/YLIE/ZLIE.LIR – если бит стоит, то когда мы будем читать регистр FF_WU_SRC_1(2), его содержимое будет обнуляться.XHIE/YHIE/ZHIE — если бит выставлен, то акселерометр начинает следить за состоянием соответствующего регистра данных, и когда значение ускорения по соответствующей оси превысит пороговое — будет выставлен флаг в регистре FF_WU_SRC_1(2) .XLIE/YLIE/ZLIE — если бит выставлен, то акселерометр начинает следить за состоянием соответствующего регистра данных, и когда значение ускорения по соответствующей оси станет меньше порогового — будет выставлен флаг в регистре FF_WU_SRC_1(2) .Картинка ниже проясняет, что такое «меньше порогового» — зеленый прямоугольник и «больше порогового» — синий прямоугольник:

FF_WU_SRC_1(0x31), FF_WU_SRC_2 (0x35)

 Флаговый регистр. Если бит LIR (в регистре FF_WU_CFG_Х) установлен, то при считывании этого регистра, он обнуляется. Если до этого произошло прерывание, то сразу после чтения, обе ноги INT1/INT2 переключатся в исходное состояние.

—-IA  (0)  ZH (0)  ZL (0)  YH (0)YL  (0)  XH (0)  XL(0)

IA— если бит установлен, то прерывание случилосьZH/YH/XH — если бит установлен то ускорение по соответствующей оси превысило порогZL/YL/XL — если бит установлен то ускорение по соответствующей оси стало меньше порогаЕстественно, первые шесть бит будут устанавливаться только в том случае, если мы установили биты XHIE/YHIE/ZHIE/XLIE/YLIE/ZLIE в регистре FF_WU_CFG_1(2).

FF_WU_THS_1(0x32),  FF_WU_THS_2 (0x36) 

Регистр для задания порогового значения ускорения

D7 (0)D6(0) D5(0)  D4(0)D3(0)D2 (0)D1  (0)D0(0)

DCRM — задаёт режим сброса счётчика. 0 – счётчик сбрасывается , 1 – счётчик уменьшается.THS6… THS0 – пороговое значение

FF_WU_DURATION_1(0x33), FF_WU_DURATION_1(0x37)

Задаёт минимальную продолжительность события.  Если частота выборки 400 Гц, то регистр позволяет задавать значение от 0 до 637.5 мсек с шагом 2.5 мсек. В случае если частота выборки 100 Гц, то значение может изменяться в диапазоне от 0 до 2.55 сек с шагом 10 мсек. Назначение этого регистра можно понять из картинки ниже:

В какой-то момент времени случается событие (FreeFall event) которое должно вызвать прерывание (например ускорение по оси X стало больше порогового). Сразу после этого, где-то внутри акселерометра начинает тикать счётчик. Когда его значение (counter value) сравняется со значением регистра FF_WU_DURATION_1(2) то прерывание возникнет и на ноге INT1(2) сменится логический уровень. Однако может быть так, что счётчик досчитает до какого-то значения, а потом событие вызывающее прерывание исчезнет (ускорение упало ниже порогового). Тут есть два варианта развития событий: Если бит DCRM сброшен, то счётчик сразу же сбросится в ноль и ему придётся начать отсчёт заново, когда ускорение превысит порог. Если же бит был установлен, то счётчик начнет уменьшать свое значение с той же скоростью с какой он его увеличивал. Я так понял что это защита от ложных срабатываний. Если регистр FF_WU_DURATION_1(2) содержит ноль, то прерывание наступит моментально как только произойдет нужное событие.  Если же не ноль, то прерывание сработает не сразу,  а спустя некоторый промежуток времени в течении которого событие вызвавшее прерывание должно сохраняться.

Все остальные регистры предназначены для настройки блока генерирующего прерывание всякий раз, когда совершают клик или двойной клик. Клик — это событе в ходе которого ускорение по некоторой оси превышает определённый порог (CLICK_THS) и опускается ниже этого порога раньше чем пройдет заданный промежуток времени (CLICK_TIMELIMIT): 

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

На картинке выше показано в какие моменты будет возникать прерывание по двойному (4) и одиночному (3) клику. Для обоих случаев ускорение изменяется одинаково (красный график). На обоих графиках отмечен такой паметр как Latency (CLICK_LATENCY). Он задает врменной интервал в течении которого не будут детектироваться клики и двойные клики. В случае если у нас настроены прерывание по двойному клику, то отсчет времени начинается сразу после совершения второго клика. Ну а для одиночного клика  — сразу после его совершения. Примечательно, что если у нас сброшен бит LIR (регистр CLICK_CFG), то активный уровень на ноге INT1(2) будет сохранятся в течении этого временного интервала, а потом сам сбросится.

CLICK_CFG (0x38)

Регистр для выбора осей по которым отслеживаются клики 

LIR(0)Double_Z(0)Single_Z(0)Double_Y(0)Single_Y(0)Double_X(0)Single_X(0)

LIR  — если бит стоит, то когда мы будем читать регистр CLICK_SRC, его содержимое будет обнуляться, а логический уровень на ногах INT1(2) будет сбрасываться в исходное состояние. Если бит сброшен, то логический уровень на ногах INT1(2) сборосится сам через интервал времени указаный в регистре CLICK_LATENCYDouble_Z/X/Y — включено отслеживание двойных кликов по соответствующим осямSingle_Z/X/Y — включено отслеживание одиночных кликов по соответствующим осям

CLICK_SRC (0x39)

Флаговый регистр

IA (0)Double_Z(0)Single_Z(0)Double_Y(0)Single_Y(0)Double_X(0)Single_X(0)

IA — Прерывание случилосьDouble_Z/X/Y  — произошло прерывание по двойному кликуSingle_Z/X/Y — произошло прерывание по одиночному клику 

CLICK_THSY_X (0x3B)

Регистр задает пороговые значения ускорения для осей X и Y. Если ускорение превысит порог, то акселерометр активирует режим обнаружения кликов. Другими словами: Если настроить определенный порог, и делать клики в процессе которых ускорение не превысит пороговое значение — акселерометр не посчитает что клик был сделан. По идее если нам не нужно отслеживать появление кликов по некоторым осям, то пороги для них задавать нет смысла. Но на практике я столкнулся со странным поведением когда включил обнаружение кликов по оси Z и не задал пороги для X и Y. Прерывания возникали через раз или вообще переставали срабатывать. Возможно это какая-то бага в самом датчике или я что-то не правильно понял.

THSy3 (0)THSy2(0)THSy1 (0)THSy0 (0)THSx3 (0)THSx2 (0)THSx1(0)THSx0(0)

THSy3 … THSy0 —  пороговое ускорение для оси Y. THSx3 … THSx0 —  пороговое ускорение для оси X.

CLICK_THSZ (0x3C)

THSz3(0)THSz2(0)THSz1(0)THSz0(0)

THSz3 … THSz0 —  пороговое ускорение для оси Z.

CLICK_TimeLimit (0x3D)

Регистр задающий временной интервал в течении которого ускорение должно успеть упасть ниже порогового чтоб клик был опознан. Отсчёт времени начинается после того как ускорение по выбранной оси превысило порог. Дивпазон от 0 до 127.5 мсек с шагом 0.5 мсек.

CLICK_Latency (0x3E)

Регистр задающий временной интервал в течении которого клики не будут детектироваться. Отсчет времени начинается после совершения двойного или одиночного клика. Диапазон от 0 до 255 мсек.

CLICK_Window (0x3F)

Регистр задает максимальный промежуток между двумя кликами в диапазоне от 0 до 255 мсек. Т.е. чем меньше число тем быстрей нужно делать двойной клик чтоб прерывание сработало. 

Практическое применение

Вот мы и добрались до практической части этой статьи. Я написал три примера использования этого акселерометра. Для первого нужно подключить к микроконтроллеру USB-UART преобразователь чтоб видеть какое ускорение изменяется, для двух других его можно не подключать, а просто раскомментировать строчку которая зажгет светодиод на платке дискавери. Код инициализации SPI и UARTa я опустил. Его можно посмотреть скачав проект полностью. Тоже самое и с некоторыми функциями типа записи/чтения регистров итд. 

Пример 1

В этом примере микроконтроллер просто читает ускорение из акселерометра и выводит его в UART в дружественном для пользователя виде. UART терминал надо настроить на скорость 9600, 1 стоп бит, без проверки чётности. Скачать пример полностью можно здесь.

int main(void) {
  char str[4];
  usart_init(); //Инициализация UART
  spi_init(); //Инициализация SPI
  // Включить акселерометр. Это минимальная инициализация.
  setReg(LIS302DL_CTRL_REG1, (1<<PD_CTRL_REG1) );
  // Теперь просто читаем ускорение из трёх регистров
  // и выводим их в UART
  while(1) {
    delay();
    itoa((int8_t) getReg(LIS302DL_OUT_X),&amp;str); send_str(&amp;str); send_str(",");
    itoa((int8_t) getReg(LIS302DL_OUT_Y),&amp;str); send_str(&amp;str); send_str(",");
    itoa((int8_t) getReg(LIS302DL_OUT_Z),&amp;str); send_str(&amp;str); send_str("\n");
  }
}

Пример 2

Пример показывает как настроить прерывания от блока FF_WU_1. Скачать код примера.

int main(void) {
  char str[4];
  usart_init(); //Инициализация UART
  spi_init(); //Инициализация SPI
  enable_int(); //Включить прерывание по нарастающему фронту на ноге PE0
  getReg(LIS302DL_FF_WU_SRC1_REG);
  // Читаем этот регистр чтоб обнулить его. Это на тот случай, если прерывание
  // случилось, и мы нажали сброс на контроллере чтоб повторить эксперимент
  // Включаем акселерометр
  setReg(LIS302DL_CTRL_REG1,(1<<PD_CTRL_REG1) | (1<<ZEN_CTRL_REG1) |
               (1<<XEN_CTRL_REG1) | (1<<YEN_CTRL_REG1));
  // Включаем фильтр, чтоб ориентация акселерометра в пространстве
  // не влияла на измерения
  setReg(LIS302DL_CTRL_REG2,(1<<FDS_CTRL_REG2));
  // Разрешаем прерывания от FF_WU_1. Когда оно случится на ноге INT1
  // появится высокий логический уровень
  setReg(LIS302DL_CTRL_REG3, (1<<I1CFG0_CTRL_REG3) );
  // Задаем пороговое значение
  setReg(LIS302DL_FF_WU_THS1_REG, 55);
  // Прерывание будет возникать когда ускорение по любой оси превысит пороговое
  // значение.
  setReg(LIS302DL_FF_WU_CFG1_REG,(1<<AOI_FF_WU_CFG_REG) | (1<<LIR_FF_WU_CFG_REG)
     | (1<<ZHIE_FF_WU_CFG_REG) | (1<<YHIE_FF_WU_CFG_REG) | (1<<XHIE_FF_WU_CFG_REG));
  // Ожидаем прерывания
  while(1) {
     ;
  }
}

void EXTI0_IRQHandler(void) {
  if(EXTI_GetITStatus(EXTI_Line0) != RESET) {
    // Этот код исполнится когда акселерометр как следует тряхнут
    // Если нет UARTа то можно просто подмигнуть светодиодом раскомментировав строку ниже
    // led_enable();
    send_str("Interrupt occurred\n");
    EXTI_ClearITPendingBit(EXTI_Line0);
  }
}

Пример 3

Программа заставляет акселерометр обнаруживать двойной клик и выдавать прерывание. Скачать полную версию.

int main(void){
  char str[4];
  usart_init(); //Инициализация UART
  spi_init(); //Инициализация SPI
  enable_int(); //Включить прерывание по нарастающему фронту на ноге PE0
  getReg(LIS302DL_CLICK_SRC_REG);
  // Читаем этот регистр чтоб обнулить его. Это на тот случай, если прерывание
  // по клику случилось, и мы нажали сброс на контроллере чтоб повторить эксперимент
  // Включаем акселерометр
  setReg(LIS302DL_CTRL_REG1,(1<<PD_CTRL_REG1) | (1<<ZEN_CTRL_REG1) |
      (1<<XEN_CTRL_REG1) | (1<<YEN_CTRL_REG1));
  // Включаем фильтр, чтоб ориентация акселерометра в пространстве
  // не влияла на измерения
  setReg(LIS302DL_CTRL_REG2,(1<<FDS_CTRL_REG2));
  // Разрешаем прерывания от модуля обнаружения кликов. Когда он случится, на ноге INT1
  // появится высокий логический уровень
  setReg(LIS302DL_CTRL_REG3, (1<<I1CFG0_CTRL_REG3) | (1<<I1CFG1_CTRL_REG3)
                                       | (1<<I1CFG2_CTRL_REG3) );
  // Задаем пороговое значение, начиная с которого начинают отслеживаться клики
  // только для оси Z, другие нам не нужны. Но если для них не задавать порог, то 
  // начинаются какие-то странные глюки (подробнее в статье).
  setReg(LIS302DL_CLICK_THSZ_REG, 0x0F);
  setReg(LIS302DL_CLICK_THSY_X_REG, 0xFF);
  // Прерывание будет возникать когда произойдет двойной клик по оси Z
  setReg(LIS302DL_CLICK_CFG_REG,(1<<LIR_CLICK_CFG_REG | (1<<Double_Z_CLICK_CFG_REG) ) );
  // Задаем TIMELIMIT и LATENCY
  setReg(LIS302DL_CLICK_TIMELIMIT_REG,0x10);
  setReg(LIS302DL_CLICK_LATENCY_REG,0x10);
  // Задаем максимальную задержку между кликами. Чем меньше число
  // тем быстрей надо кликать
  setReg(LIS302DL_CLICK_WINDOW_REG,0xFE);
  // Ожидаем прерывания
  while(1){
    ;
  }
}

void EXTI0_IRQHandler(void) {
  if(EXTI_GetITStatus(EXTI_Line0) != RESET) {
    // Этот код исполнится когда акселерометр совершит двойной клик
    // Если нет UARTа то можно просто подмигнуть светодиодом раскомментировав строку ниже
    // led_enable();
    send_str("Interrupt occurred\n");
    EXTI_ClearITPendingBit(EXTI_Line0);
  }
}

Если хотите почитать еще про этот акселерометр, то рекомнедую аппноуты от производителя: AN2335 и AN2579. Ну и даташит конечно же. В качестве заключения могу сказать что акселерометр мне понравился. Разобрался я сравнительно быстро, а вот статью эту писал аж две недели. Поэтому могут быть мелкие ошибки и неточности. Если вы нашли таковые, то пишите в комментарии, будем исправлять. Спасибо за внимание.

Добавить комментарий