"Вы читаете о роботах и программировании и думаете: «Было бы здорово сделать что-то подобное самому!» Теми, кем эта идея овладевает чуть больше просто мыслей смотрят кто и как делал своего робота. Читают статьи, смотрят видео. На картинках все понятно. В видеороликах тоже обычно показываются уже готовые продукты, а также сжато показываются технологии их изготовления. И вроде бы то же всё понятно: отпилил, прикрутил, припаял, соединил, запрограммировал вон на той программе вот этим кодом."

пятница, 14 февраля 2020 г.

14.02.20 Аналоговые и цифровые сигналы, обработка в микроконтроллере Arduino UNO




Как  и какие сигналы обрабатываются в микроконтроллере? Что такое аналоговый сигнал? Чем отличается от цифрового? На представленной ниже схеме указаны возможные сигналы на выходе и входе микроконтроллера. Аналоговый сигнал - непрерывный сигнал, значение которого мы знаем в любой момент времени. Цифровой сигнал - значения известны через равные промежутки времени и значений только два - 0 и 1.


На выше представленной схеме рассмотрены штатные команды (функции) языка Wiring
На официальном сайте пишут: "...is programmed using the Arduino programming language (based on Wiring)".
Фактически — нет никакого особого языка программирования и программы пишутся на C/C++, а компилируются и собираются с помощью широко известного avr-gcc (в версии для Windows — WinAVR).
Все особенности сводятся к тому, что имеется набор библиотек, включающий в себя некоторые функции (вроде pinMode) и объекты (вроде Serial), а при компиляции Вашей программы среда разработки создает временный .cpp файл, в который кроме Вашего кода включается еще несколько строчек, и полученный результат скармливается компилятору а затем линковщику с нужными параметрами.
К сожалению за все нужно платить, за универсальность тоже. Расплата это размер и скорость выполнения программы. Иногда штатные функции нам не всегда на 100% полезны, иногда возникают ситуации что они избыточны. Именно для этого мы рассмотрим альтернативные способы работы с сигналами в микроконтроллере. Начнем с цифровых сигналов.
В микроконтроллере Arduino UNO, имеются 3 порта работы с цифровыми сигналами B, C, D.
https://raspberry3.ru/wp-content/uploads/2017/05/arduinopinout-1024x724.jpg 
Каждый порт представляет собой три 8-ми битный регистр, в котором каждый бит имеет свой вывод(ногу, пин), два доступных для записи чтения и один только для чтения. Регистр DDRx (где х имя порта) отвечает за представления ножки как выхода или входа в зависимости от того что записано в данный бит 1- выход 0- вход. Таким образом записывая в соответствующий бит регистра 0 или 1  мы определяем его как вход или выход. Регистр PORTx ответственно отвечает зато  что находится на  выходе высокий или низкий уровень сигнала. Регистр PINx доступен только для чтения и позволяет считывать уровень сигнала на соответствующем выходе. Например:

DDRD = 0xff;
PORTD= 0b11000010;

Двумя строчками мы определили все выводы порта D (pin 0..7), как выходы где высокий уровень(HIGH) на pin 1,6,7 на остальных выводах низкий (LOW) 
Иногда обращаться ко всему порту бывает затруднительно, поэтому вместо digitalWrite()  можно использовать:

PORTD |= 1<<3; // УСТАНАВЛИВАЕМ НА pin_2 высокий уровень сигнала
PORTD &= ~(1<<3); //устанавливаем на pin_2 низкий уровень сигнала

В Н И М А Н И Е

команда PORTD = 1<<3; ЗАПИШЕТ в регистр 0b00000100, будьте осторожны. Соответственно PORTD = ~(1<<3) ----> 0b111110111.

Теперь что касается чтения с выводов порта. Условие которое определяет уровень сигнала на выводе (PIND & (1<<PD3)) если истинно то HIGH, ложно LOW.
С цифровыми сигналами разобрались. Теперь аналоговый сигнал.
 

Для работы с аналоговым сигналом необходимо преобразовать его в цифровой, для этого используется аналого-цифровой преобразователь (АЦП)

АЦП Arduino UNO имеет разрешение 10 бит, т.е. позволяет выводить значения в десятичном виде от 0 до 1023. В относительных единицах деление шкалы 5/1024 = 4.9 мВ;
analogRead(pin) -- Функция считывает значение с указанного аналогового входа. Возвращает: int (0 to 1023).
Считывание значение с аналогового входа занимает примерно 100 микросекунд (0.0001 сек), т.е. максимальная частота считывания приблизительно 10,000 раз в секунду.
analogReference(type) -- определяет опорное напряжение относительно которого происходят аналоговые измерения. Type принимает одно из следующих значений:
DEFAULT: стандартное опорное напряжение 5 В (на платформах с напряжением питания 5 В) или 3.3 В (на платформах с напряжением питания 3.3 В).
INTERNAL: встроенное опорное напряжение 1.1 В на микроконтроллерах ATmega168 и ATmega328, и 2.56 В на ATmega8.
EXTERNAL: внешний источник опорного напряжения, подключенный к выводу AREF (рекомендуется подключать к выводу AREF через резистор 5 кОм).
Примеч.: Опорное напряжение можно установить, используя функцию analogReference или при помощи битов REFT[1:0] в регистре ADMUX.
Используйте внутреннее опорное напряжение 1.1 В для точных измерений внешних напряжений:
analogReference(INTERNAL1V1); // выбираем внутреннее опорное напряжение 1.1В 
Разовая выборка - это на самом деле то, что Arduino делает при вызове функции analogRead()

Непрерывная выборка:
Хорошей идеей при непрерывной выборке сигнала является использование прерываний.
Микроконтроллеры ATMega328 и ATMega2560 могут быть переведены в режим непрерывной выборки (free running mode). В этом режиме АЦП запускается автоматически после завершения предыдущей обработки. Для включения режима непрерывной выборки необходимо установить три регистра: ADMUX, ADCSRA и ADCSRB

ADCSRB = 0x00;
ADMUX = 0b01100000;//A0
ADCSRA = 0b11101111;//делитель 128
//функция для работы с АЦП по прерыванию
volatile int result;
ISR(ADC_vect)
 { result = ADCH;
}
Продолжение следует