Если вы счастливый обладатель платы STM32F4Discovery, но наверняка вас посещала мысль запустить акселерометр который на ней установлен. Для этого нам потребуется сама платка и переходник USB-UART через который мы будем отправлят данные в компьютер. Сам акселерометр уже подключен к микроконтроллеру как надо, если же у вас нет платы дискавери, то нужно подключить его как на рисунке ниже:
У акселерометра есть два интерфейса для обмена данными — i2c и SPI. Использовать мы будем последний, благо я еще не забыл как это делать, да и разводка платы подразумевает его использование. Сам акселерометр обладает следующими характеристиками:
- Напряжение питания 2.16 — 3.6 в.
- Измерение ускорения по трём осям
- Два диапазона измерения 2G/8G
- Два настраиваемых выхода для прерываний
- Самодиагностика
- Обнаружение кликов (постукиваний)
- Встроенный фильтр
- Корпус LGA14
Пожалуй, последняя характеристика является минусом данного датчика, он очень мелкий и я рад что мне не придётся ничего паять 🙂 Сразу предупреждаю, что меня одолело графоманство и поэтому букв будет много, запаситесь терпением. У чипа 14 ног, их назначение описано в таблице ниже, а картинка показывает нумерацию выводов и расположение осей:
Номер вывода | Имя | Назначение |
1 | Vdd_IO | Питание ножек I/O |
2 | GND | Земля |
3 | Reserved | Зарезервировано. Подключать к питанию |
4 | GND | Земля |
5 | GND | Земля |
6 | Vdd | Питание |
7 | CS | Выбор интерфейса. Если на ноге лог. 1, то акселерометр думает, что используется i2c, в противном случае – SPI. |
8 | INT 1 | Вывод прерывания 1 |
9 | INT2 | Вывод прерывания 2 |
10 | GND | Земля |
11 | Reserved | Зарезервировано, подключить к земле |
12 | SDO | В режиме SPI эта нога служит для передачи данных к мастеру (MISO). Если используется i2c интерфейс, то логический уровень на этой ноге определяет младший бит адреса. Т.е. если на ней лог. 0, то адрес устройства — 0x1C, в противном случае адрес будет 0x1D |
13 | SDASDISDO | Если используется i2c интерфейс, то этот вывод используется для передачи данных (SDA). В режиме SPI эта нога служит для приёма данных от мастера (MOSI). Если используется 3-х проводной режим SPI, то через этот вывод происходит двусторонний обмен данными. |
14 | SCLSPC | Если используется 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) нужно проделать следующую последовательность действий:
- Вывод CS прижать к земле.
- Передать первый байт (0x8F) который содержит адрес считываемого регистра, сброшеный бит MS (так как мы читаем только один регистр) и установленый бит RW (ведь мы читаем данные)
- Передать любой байт. Ведь интерфейс SPI так устроен, что слейв (наш акселерометр) не может передавать данные по своей инициативе. Поэтому он начнет передавать значение хранящееся в регистре только в момент передачи микроконтроллером второго байта (который по сути будет просто проигнорирован).
- Прочитать значение из регистра данных SPI (то, что пришло от акселерометра)
- Установить высокий логический уровень на выводе CS
Если нам требуется очень быстро читать один и тот же регистр, то можно постоянно повторять шаги 3 и 4.
Запись одного регистра
Она не сложней чтения, попробуем записать байт 0x47 в регистр с адресом 0x20. Для этого нужно:
- Вывод CS прижать к земле
- Передать первый байт (0x20) который содержит адрес записываемого регистра, сброшеный бит MS (так как мы пишем только один регистр) и сброшенный бит RW (ведь мы пишем данные)
- Передать новое значение регистра (0x47)
- Установить высокий логический уровень на выводе CS
Если вдруг потребуется быстро писать какие-либо значения в один и тот же регистр, то можно постоянно повторять 3-й шаг.
Чтение нескольких регистров
Очень удобная вещь, можно взять и за один раз прочитать всю память акселерометра 🙂 Для того чтоб начать чтение, указываем адрес с которого нужно начать (например 0x0F) . А потом просто читаем байт за байтом. Алгоритм такой:
- Вывод CS прижать к земле.
- Передать первый байт (0xCF) который содержит адрес считываемого регистра, установленный бит MS (так как мы читаем несколько регистров) и установленый бит RW (ведь мы читаем данные)
- Передать любой байт. Ведь интерфейс SPI так устроен, что слейв (наш акселерометр) не может передавать данные по своей инициативе. Поэтому он начнет передавать значение хранящееся в регистре только в момент передачи микроконтроллером второго байта (который по сути будет просто проигнорирован).
- Прочитать значение из регистра данных SPI (то, что пришло от акселерометра)
- Повторять шаги 3 и 4 пока не прочитаем столько регистров сколько нужно. Адрес чтения будет увеличиваться на единицу сам.
- Установить высокий логический уровень на выводе CS
Запись нескольких регистров
Работает аналогично чтению нескольких регистров т.е. после каждой записи адрес автоматически увеличивается на единицу. Запишем три байта 0x47, 0x10 и 0x40 в регистры с адресами 0x20, 0x21 и 0x22:
- Вывод CS прижать к земле
- Передать первый байт (0x60) который содержит адрес первого записываемого регистра (0x20), установленый бит MS (так как мы пишем в несколько регистров) и сброшенный бит RW (ведь мы пишем данные)
- Передать новое значение (0x47) регистра 0x20
- Передать новое значение (0x10) регистра 0x21
- Передать новое значение (0x40) регистра 0x22
- Установить высокий логический уровень на выводе 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, то возможны следующие комбинации:
STP | STM | Назначение |
0 | 0 | Самодиагностика выключена |
0 | 1 | Самодиагностика. Режим P |
1 | 0 | Самодиагностика. Режим M |
1 | 1 | Запрещенная комбинация |
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_coeff2 | HP_coeff1 | Частота среза (Бит DR=0) | Частота среза (Бит DR=1) |
0 | 0 | 2 Гц | 8 Гц |
0 | 1 | 1 Гц | 4 Гц |
1 | 0 | 0.5 Гц | 2 Гц |
1 | 1 | 0.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)_CFG2 | I1(2)_CFG1 | I1(2)_CFG0 | Источник |
0 | 0 | 0 | Прерывание выкл. Нога подключена к земле. |
0 | 0 | 1 | FF_WU_1 |
0 | 1 | 0 | FF_WU_2 |
0 | 1 | 1 | FF_WU_1 или FF_WU_2 |
1 | 0 | 0 | Данные готовы |
1 | 1 | 1 | Прерывание от клика |
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_X, Out_Y, Out_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),&str); send_str(&str); send_str(","); itoa((int8_t) getReg(LIS302DL_OUT_Y),&str); send_str(&str); send_str(","); itoa((int8_t) getReg(LIS302DL_OUT_Z),&str); send_str(&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. Ну и даташит конечно же. В качестве заключения могу сказать что акселерометр мне понравился. Разобрался я сравнительно быстро, а вот статью эту писал аж две недели. Поэтому могут быть мелкие ошибки и неточности. Если вы нашли таковые, то пишите в комментарии, будем исправлять. Спасибо за внимание.