27 апреля 2013 г.

Работа с инфракрасным датчиком Sharp

Я описал как работать с АЦП в этой статье.

Теперь расскажу как работает инфракрасный датчик.


( В самом простом случае ) У него есть 3 вывода: Vcc - питание GND - земля и Vo - с которого снимаем данные.
В зависимости от расстояния меняется напряжение на выводе Vo, всё что остаётся это перевести данные из аналога в цифру.







У инфракрасных датчиков имеется (ВНЕЗАПНО!) инфракрасный светодиод ( LED ) с линзой который излучает узкий световой луч. Это излучение распространяется и отражается от  объектов находящихся в поле зрения сенсора. Угол отражения напрямую зависит от расстояния до объекта.

Отраженный луч через другую линзу попадает на позиционно-чувствительный фотоэлемент ( PSD ). Это значит что от местоположения падающего на фотоэлемент луча зависит его проводимость.

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



У дальномеров может быть как цифровой так и аналоговый выход, если выход аналоговый нужно использовать АЦП микроконтроллера для преобразования аналогового напряжения в двоичный код.

Слева приведён типичный график зависимости напряжения от расстояния датчика Sharp. Как видно он не является линейным. К тому же минимально измеряемое расстояние ограничено особенностями датчика. Выходное напряжение резко падает на определённом расстоянии и 1 значению напряжения соответствует 2 расстояния, об этом необходимо помнить при работе с сенсором.











Однако в даташите приведён также график зависимости обратного значения расстояния ( 1/см ) от напряжения и как видно на начальном участке он почти линейный и его можно использовать для вычисления формулы преобразования напряжения в расстояния.

Для этого нужно измерять выдаваемое микроконтроллером значение АЦП ( или напряжения, но с АЦП легче работать ) на живом датчике. Затем в программе обработки табличных данных ( я использовал mathcad ) построить новый график по полученным точкам.
По оси ординат (вертикальная) выставляются обратные значения расстояния, которое вычисляется по формуле которая указана в даташите датчика.

По оси ординат значения АЦП.


Теперь нужно найти уравнение прямой (синий цвет) которая проходит ближе всего ко всем точкам графика (красный цвет).

Получив уравнение можно сделать обобщение и сказать что зависимость между напряжением и расстоянием следующая

1 / (d + k) = a ⋅ ADC + b
d - расстояние в сантиметрах
k - корректирующая константа (взята из даташита)
ADC - это значение АЦП
a,b - линейные члены (значение выходит из уравнения линии тренда)

Перед равно, значение обратной величины расстояния, после уравнение полученной прямой.
Из этого можно вывести расстояние.

d = (1 / (a ⋅ ADC + b)) – k

В принципе по этой формуле можно вычислить расстояние, но тут приходится работать с дробями на микроконтроллере проще оперировать целыми числами, поэтому нужно упростить формулу и перевести в большие множители разделив частное на линейный член.
d = (1 / a) / (ADC + b / a) – k

К примеру у Sharp GP2D12 полученная в итоге формула выглядит так

d = (6787 / (ADC - 3)) - 4

Осталось проверить чтобы значение АЦП было больше 3 иначе будет деление на 0 или отрицательное расстояние.

Если просто нужно узнать есть ли предмет перед датчиком, можно проверять чтобы значение ADC не превышало необходимое нам, тогда не нужно делать никаких расчётов и просто экспериментально подобрать значения, можно даже в Proteus.

#define F_CPU 8000000UL

#include <avr/io.h>
#include <util/delay.h>

void check_sensors()
{
        if(ADCSRA & 1<<ADSC) // Если закончилось измерение напряжения
        {
                unsigned int ADCdata;
                ADCdata = ADCW; // В ADCW хранится напряжение в двоичном коде
 
                if(ADCdata <= 615) // Грубое измерение 13 см и 2.5 Вольт для SHARP GP2D120
                {
                        делать_что_угодно;
                        // TROLOLOLOLO
                }
  
                ADCSRA |= (1<<ADSC); // Регистр для начала нового преобразования 0b01000000
        }


int main()
{ 
        ADMUX = 0x00; // Считаем ножку PA0
        ADCSRA |= (1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1); // выставляем нужные биты

        while(1)
        {
               if(ADCSRA & 1<<ADSC) // ИЛИ можно здесь проверить закончилось ли преобразование чтоб меньше времени тратить
               {
                       check_sensors();
               }
              // bla bla bla
        }

}

// Или можно узнать точное значение с помощью прерывания, когда АЦП подсчитает напряжение
ISR(ADC_vect)
{    
        ADCdata = ADCW; 
        voltage_0 = ADCdata * 48875 / 10000; // ( 5000 милливольт / 1023 ) = 4.8875 ( милливольт в 1 бите )
        voltage   = voltage_0 % 10000 / 1000;  
        voltage_2 = voltage_0 % 1000 / 100;
        voltage_3 = voltage_0 % 100 / 10;
        voltage_4 = voltage_0 % 10;

        if (ADCdata > 3) // чтоб не делить на 0
        {
                range = (6787 / (ADCdata - 3)) - 4;
        }


        ADCSRA = ADCSRA | 0x40;// начинаем новый пересчёт 0b01000000
}


Комментариев нет :

Отправить комментарий