Электронный уровень на ADXL335

Электронный уровень – один из возможных способов применения акселерометра ADXL335. Схема построена на МК ATmega48PA с индикацией на ярких LED-индикаторах.

Наверное, у всех так бывает, когда найденная с большим трудом и купленная за деньги микросхема вдруг перестает быть так необходима, как казалось до этого. И потом, она долго и бережно, хранится в течении нескольких лет и кажется, до нее вот-вот дойдет дело и она обязательно пригодится. В моем случае, одной из таких «крайне необходимых» покупок стал аналоговый трехосевой акселерометр ADXL335 от Analog Devices. Акселерометр имеет три аналоговых выхода, которые соответствуют осям X, Y и Z ортогональной системы координат и может использоваться для определения угла наклона, относительно вектора земной силы тяготения. Причем, это его «побочный» эффект, основное же назначение акселерометра – измерение ускорения, но об этом в другой сказке. Более подробно о ADXL335 можно почитать здесь.

%d1%81%d1%80%d0%b0%d0%b2%d0%bd%d0%b5%d0%bd%d0%b8%d0%b5-%d1%81-%d1%81%d0%bf%d0%b8%d1%87%d0%ba%d0%be%d0%b9

Сама микросхема акселерометра представляет собой маленький (очень маленький) квадратик размером с спичечную головку. Поэтому покупать его лучше в сборе с монтажной платой иначе придется как следует напрячь зрение и заточить паяльник. Что и пришлось сделать мне потому, что я купил эту микросхему сразу после ее поступления в продажу (даже быстрее Китайцев) и о вариантах, напаенных на монтажную плату, не было и речи. Монтажную плату я тогда развел еще в Sprint-Layot-е, на ней имеется место под стабилизатор напряжения и шунтирующие конденсаторы, выводы всех трех осей выведены на одну сторону. Микросхема приклеивается «лапками кверху» на плату и от нее к соответствующим пятачкам на плате тянутся проводки-волоски. Иначе рядовому радиолюбителю припаять такое чудо не под силу.

%d0%bf%d0%bb%d0%b0%d1%82%d0%b0-%d0%b0%d0%ba%d1%81%d0%b5%d0%bb%d0%b5%d1%80%d0%be%d0%bc%d0%b5%d1%82%d1%80%d0%b0

Применение платы-переходника упростило настройку уровня и поэтому он настраивается как обычный маслянно-пузырьковый — переворачивая уровень и корректируя положение платы-переходника добиваемся одинаковых показаний «в обе стороны». Программное переключение измерения отклонения от вертикальной или горизонтальной оси не реализовано. Вместо этого на плату выведена перемычка «джампер» при помощи которой можно выбрать нужную ось относительно которой будут производиться измерения.

%d0%b8%d0%bd%d0%b4%d0%b8%d0%ba%d0%b0%d1%86%d0%b8%d1%8f

Акселерометр питается напряжением 3.3В, поэтому при стыковке с микроконтроллером это нужно учитывать. Я просто питаю все вместе с МК одним напряжением, тем самым избежав необходимости согласования уровней. Микроконтроллер ATmega48PA используется только потому, что был. Его можно вполне заменить на любой из «мега-серии» и даже «тини». Дополнительный усилитель напряжения положенный в таких случаях не используется, а т.к. выходное напряжение микросхемы акселерометра меняется совсем в небольшом диапазоне (примерно 500мВ), то точность показаний в основном зависит от разрядности АЦП. В данном случае 10-битный АЦП ATmega48 работает в обычном режиме и постоянно, т.е. стартует сразу после конфигурации и по ходу программы не останавливается:

———————————————-
Config Adc = Single , Prescaler = 128 , Reference = Avcc
Start Adc
———————————————-

Еще одна особенность работы АЦП в «мегаконтроллере», с которой я сталкиваюсь уже не первый раз, это неверные показания значения АЦП возвращаемые переменной при однократном запросе. Т.е. если АЦП работает постоянно, и мы решили внезапно (неожиданно для него) узнать что там у него на входе, то он нам вернет значение (например) 510. Если следом опросить его еще раз, то получим значение 508, а потом следующие значения станут стабильно 505. Чтобы обмануть это явление, не вникая в особенности строения микроконтроллера, я в подпрограмме опрашиваю АЦП несколько раз подряд, так сказать «разминаю дырочку», а потом беру только последнее значение:

———————————————-
For Count = 0 To 10                                     
     Get_adc = Getadc(5)                                  
Next
———————————————-

Для индикации уровня наклона используется яркий светодиодный индикатор с общим анодом в режиме динамической индикации. LED-индикатор это принципиальное решение потому, что в реальных условиях на стройке, показания ЖК индикатора совершенно не читабельны. Да и стройка часто бывает в зимнее время года (при минусовой температуре) тогда ЖК индикатор совершенно бесполезен. Трехсегментный LED-индикатор подключен к порту C микроконтроллера, динамическая индикация организована программно путем простого сравнения заранее подготовленных данных. Сначала приравниваем значение АЦП переменным соответствующим цифрам на индикаторе. Важно приравнивать всегда именно в таком порядке иначе в неподходящий момент может произойти прерывание (которое мы не учли в более сложной программе) из-за чего в показаниях произойдет сбой:

———————————————-
Dig2 = Get_adc      
Dig3 = Dig2        
———————————————-

Затем разделяем полученное значение на десятки (2-й сегмент):

———————————————-
Dig2 = Dig2 Mod 100                                     
Dig2 = Dig2 / 10
Dig2 = Abs(Dig2)
———————————————-

И единицы (3-й сегмент):

———————————————-
Dig3 = Dig3 Mod 10                                      
Dig3 = Abs(Dig3)
———————————————-

Сотни и тысячи в данном случае не используются потому, что значение АЦП колеблется примерно от 400 до 600. Также не используется преобразование значения АЦП в градусы по причине невозможности верного тарирования индикации. Зато применяется индикация положения уровня – ниже нормы, норма и выше нормы. Для этого используется 1-й сегмент индикатора:

———————————————-
Portc = &B00000100                                     
Select Case Dig1
      Case 0 : Portd = &B10111111
      Case 1 : Portd = &B11110111
      Case 2 : Portd = &B11111110
End Select
Waitms 5
———————————————-

Индикация положения уровня зависит от значения АЦП. За норму принято значение АЦП 500, как среднее между показаниями. Также, если значение АЦП больше 500 показания на индикаторе увеличиваются, а если меньше 500 то… тоже увеличиваются, но при этом знак индикация положения уровня меняется на противоположный:

———————————————-
If Get_adc > 500 Then                                  
      Get_adc = Get_adc — 500 : Dig1 = 2
Elseif Get_adc < 500 Then                               
      Get_adc = Get_adc — 500 : Dig1 = 1  
Else
      Get_adc = 0 : Dig1 = 0
End If
———————————————-

Непосредственно сама динамическая индикация двух цифр организована простой подстановкой комбинации лог. состояния выводов соответственно нужной цифре:

———————————————-
Portc = &B00000010                                     
Select Case Dig2
      Case 0 : Portd = &B11000000
      Case 1 : Portd = &B11111001
      Case 2 : Portd = &B10100100
      Case 3 : Portd = &B10110000
      Case 4 : Portd = &B10011001
      Case 5 : Portd = &B10010010
      Case 6 : Portd = &B10000010
      Case 7 : Portd = &B11111000
      Case 8 : Portd = &B10000000
      Case 9 : Portd = &B10010000
End Select
Waitms 5

Portc = &B00000001                                     
Select Case Dig3
Case 0 : Portd = &B11000000
      Case 1 : Portd = &B11111001
      Case 2 : Portd = &B10100100
      Case 3 : Portd = &B10110000
      Case 4 : Portd = &B10011001
      Case 5 : Portd = &B10010010
      Case 6 : Portd = &B10000010
      Case 7 : Portd = &B11111000
      Case 8 : Portd = &B10000000
      Case 9 : Portd = &B10010000
 End Select
 Waitms 5
———————————————-

Стоит также отметить, что динамическая индикация и опрос АЦП организованы в основном цикле, а вот подготовка (пересчет) данных для индикации обрабатывается в прерывании по переполнению Timer1 примерно каждые 65мсек.:

———————————————-
Config Timer1 = Timer , Prescale = 8                       
On Timer1 Digit                                            
Enable Interrupts
Enable Timer1
———————————————-
Do                                                         
     Gosub Acp                                               
     Gosub Led                                               
Loop
End
———————————————-
Acp:                                                       
     …….
Return
———————————————-
Digit:                                                     
     …….
Return
———————————————-
Led:                                                       
     Portc = &B00000100                                     
     Select Case Dig1
        …….
     End Select
     Waitms 5

     Portc = &B00000010                                      
     Select Case Dig2
        …….
     End Select
     Waitms 5

     Portc = &B00000001                                      
     Select Case Dig3
        …….
     End Select
     Waitms 5
Return
———————————————-

Также здесь в основном цикле фигурирует только оператор Gosub, а все самое интересное происходит по ссылкам в подпрограммах. Такой способ удобен тем, что он не захламляет основной цикл бесконечным количеством условий. Так удобнее «включать», «выключать» исполнение соответствующих условий (REM), удобно отслеживать место, где происходит сбой, да и просто можно меньше крутить колесиком мыши в поисках нужного куска кода. В остальном исходник хорошо прокомментирован и разобраться в нем не составит труда даже начинающему «программастеру», поэтому перейдем к паяльнику. Для наладки схемы создан простейший проект в Proteus-е, в котором и было обкатано 90% исходного кода.

%d1%81%d0%b8%d0%bc%d1%83%d0%bb%d1%8f%d1%82%d0%be%d1%80

Реально спаянное на «монтажке» устройство, от симуляции в Proteus-е практически не отличается потому, что при разработке данного устройства его практическое применение не планировалось — т.с. конструкция выходного дня. Однако, устройство получилось интересное и возможно в будущем будет доведено до товарного состояния.

%d0%bc%d0%b0%d0%ba%d0%b5%d1%82%d0%ba%d0%b0

Принципиальная электрическая схема (как говорят в ж. Радио) нарисована в DipTrace, чтобы в последствии можно было без труда состряпать печатную плату:

%d1%81%d1%85%d0%b5%d0%bc%d0%b0

Вывод AVcc микроконтроллера напрямую соединен с Vcc потому, что именно при таком соединении удалось значительно снизить «прыганье» последней цифры на индикаторе, т.е. стабилизировать работу АЦП. Вполне вероятно, что это не лучший метод, но в данном случае он оказался эффективнее дросселя и конденсатора. Также, при желании, можно добавить в исходный код программы алгоритм усреднения считанных значений АЦП или метод цифровой фильтрации (например Калмана), что позволит совершенно исключить неприятный эффект «прыганья» последней цифры. Однако в этом случае возможно понижение скорости обсчета данных АЦП и соответственно увеличение времени реакции уровня на изменение угла наклона.

Схема питается от 9В аккумулятора типа «Крона«, но это только мое решение и питать можно чем угодно. Потребляемый ток в основном зависит от типа применяемых LED-индикаторов и частоты динамической индикации. Можно вообще убрать микросхему стабилизатор напряжения и питать схему батарейкой-таблеткой CR2032. Но для этого придется программно компенсировать понижение напряжения батареи, чтобы не «уплывал» ноль. Неплохо было бы еще добавить пищалку, когда уровень стоит ровно, т.е. когда на дисплее «-00«.

Здесь можно посмотреть кино о том, как это работает

А здесь можно скачать исходник в Bascom, HEX, картинку с фьюзами и проект в Proteus

Схема в DipTrace