В этой статье мы рассмотрим подключение и взаимодействие гибкого датчика (FLEX sensor) к микроконтроллеру ATmega8 (семейство AVR). Для решения этой задачи мы задействуем 10 битный аналого-цифровой преобразователь (АЦП), имеющийся в данном микроконтроллере.
Что такое гибкий датчик?
Гибкий датчик (FLEX sensor) представляет собой преобразователь, чье сопротивление изменяется если изменяется его форма (датчика). Внешний вид данного датчика показан на следующем рисунке.
Как правило, данный датчик используется для измерения изменений линейности. Когда датчик изогнут, его сопротивление сильно изменяется. Этот эффект продемонстрирован на следующем рисунке.
В нашей схеме мы будем конвертировать изменение сопротивления датчика в изменение напряжения с помощью делителя напряжения (см. рисунок ниже). Делитель напряжения в нашем случае будет состоять из постоянного резистора R1 и переменного резистора R2, роль которого будет выполнять наш гибкий датчик. Средняя точка делителя напряжения будет использоваться для измерений. Когда сопротивление резистора R2 будет изменяться, то и напряжение в средней точке делителя будет изменяться пропорционально (линейная зависимость). Таким образом, степень изогнутости (или линейности) гибкого датчика будет преобразовываться в изменение напряжения.
При проектировании схем с делителем напряжения следует принимать во внимание то, что входной ток на АЦП микроконтроллера AVR должен быть не менее 50 мкА. Поэтому следует правильно выбирать резисторы делителя напряжения чтобы минимизировать влияние нагрузки (loading effect) резистора на проходящий через делитель ток.
Мы будем использовать делитель напряжения таким образом, что при входном напряжении на нем 25В мы на его выходе будем получать напряжение 5В. Таким образом, в программе нам будет нужно умножать измеренное значение напряжение на 5 чтобы рассчитать истинное значение напряжения.
Необходимые компоненты
Аппаратное обеспечение
- Микроконтроллер ATmega8 (купить на AliExpress).
- Программатор AVR-ISP (купить на AliExpress), USBASP (купить на AliExpress) или другой подобный.
- JHD_162ALCD (ЖК дисплей 16×2) (купить на AliExpress).
- Гибкий датчик (купить на AliExpress).
- Конденсатор 1000 мкФ (купить на AliExpress).
- Конденсатор 100 нФ (5 шт.) (купить на AliExpress).
- Резистор 100 кОм (купить на AliExpress).
- Источник питания с напряжением 5 Вольт.
Реклама: ООО «АЛИБАБА.КОМ (РУ)» ИНН: 7703380158
Программное обеспечение
- Atmel Studio версии 6.1 (или выше).
- Progisp или flash magic (необязательно).
Работа схемы
Схема устройства приведена на следующем рисунке.
В представленной схеме PORTD микроконтроллера ATmega8 соединен с портом данным жидкокристаллического (ЖК) дисплея. В ЖК дисплее (если мы не хотим использовать черный цвет) можно задействовать только 14 его контактов: 8 контактов для передачи данных (7-14 или D0-D7), 2 контакта для подачи питания (1&2 или VSS&VDD или gnd&+5v), 3-й контакт для управления контрастностью, 3 контакта для управления (RS&RW&E).
В представленной схеме мы использовали только 2 контакта управления ЖК дисплея для лучшего понимания работы схемы. Бит контраста и READ/WRITE используются нечасто, поэтому они могут быть замкнуты на землю. Это обеспечивает ЖК дисплею максимальную контрастность и переводит его в режим чтения. Теперь нам всего лишь нужно контролировать контакты ENABLE и RS чтобы передавать на ЖК дисплей символы и данные. Также на нашем сайте вы можете прочитать более подробную статью о подключении ЖК дисплея к микроконтроллеру AVR.
В схеме необходимо сделать следующие соединения микроконтроллера ATmega8 с ЖК дисплеем:
PIN1 или VSS — земля
PIN2 или VDD или VCC — +5v питание
PIN3 или VEE — земля (обеспечивает максимальный контраст ЖК дисплею)
PIN4 или RS (Register Selection) – контакт PD6 микроконтроллера
PIN5 или RW (Read/Write) — земля (переводит ЖК дисплей в режим чтения что упрощает взаимодействие с ним для начинающих)
PIN6 или E (Enable) — контакт PD5 микроконтроллера
PIN7 или D0 — контакт PD0 микроконтроллера
PIN8 или D1 — контакт PD1 микроконтроллера
PIN9 или D2 — контакт PD2 микроконтроллера
PIN10 или D3 — контакт PD3 микроконтроллера
PIN11 или D4 — контакт PD4 микроконтроллера
PIN12 или D5 — контакт PD5 микроконтроллера
PIN13 или D6 — контакт PD6 микроконтроллера
PIN14 или D7 — контакт PD7 микроконтроллера
В схеме мы использовали 8-битную связь (D0-D7) ЖК дисплея с микроконтроллером, хотя можно было ограничиться и 4-битной – но в этом случае код программы стал бы немного сложнее. Таким образом, мы использовали 10 контактов ЖК дисплея, 8 из которых будут использоваться для передачи данных и 2 для управления.
Напряжение на резисторе R2 не будет полностью линейным – оно будет зашумлено. Для фильтрации этого шума параллельно резисторам делителя напряжения подключены конденсаторы.
Аналого-цифровой преобразователь (АЦП) микроконтроллера ATmega8 может быть использован на любом из четырех каналов PORTC – мы выберем канал 0 (PIN0) PORTC.
В микроконтроллере ATmega8 АЦП имеет разрешение (разрешающую способность) 10 бит, таким образом микроконтроллер способен реализовать чувствительность равную Vref/2^10, то есть если опорное напряжение (Vref) равно 5В мы получим цифровой инкремент на выходе 5/2^10 = 5мВ. Таким образом, на каждое приращение напряжения на 5 мВ мы будем получать один дополнительный инкремент цифрового выхода АЦП.
Для обеспечения работы схемы мы должны установить значения регистров АЦП следующим образом:
- Сначала мы должны активировать АЦП микроконтроллера.
- Затем необходимо установить максимальное входное напряжение для АЦП равное 5В. Это можно сделать путем установки значения опорного напряжения АЦП равного 5В.
- АЦП микроконтроллера в нашей схеме будет начинать действовать при внешнем воздействии (не от действий пользователя), поэтому нам следует установить его в режим непрерывного преобразования (free running mode): в этом режиме запуск преобразований выполняется непрерывно через определенные интервалы времени.
- В любом АЦП частота преобразования аналогового значения в цифровое и точность цифрового выхода обратно пропорциональны. То есть для лучшей точности цифрового выхода мы должны выбрать меньшую частоту. Для этого мы должны установить коэффициент деления предделителя АЦП в максимальное значение (2). Поскольку мы используем внутреннюю частоту микроконтроллера 1 МГц, то значение частоты преобразования АЦП будет равно 1000000/2.
Четыре основных принципа работы с АЦП микроконтроллера мы рассмотрели, теперь нам нужно установить правильные значения в двух регистрах АЦП.
RED (красный, ADEN): этот бит устанавливается чтобы задействовать функции АЦП в ATmega8.
BLUE (синий, REFS1, REFS0): эти два бита используются для установки опорного напряжения (максимального входного напряжения, которое мы собираемся обрабатывать). Поскольку мы будем использовать опорное напряжение равное 5В, бит REFS0 необходимо выставить в соответствии с приведенной таблицей.
LIGHT GREEN (светло зеленый, ADATE): этот бит должен быть установлен чтобы АЦП работал непрерывно (в режиме непрерывного преобразования).
PINK (розовый, MUX0-MUX4): эти 5 бит используются чтобы задать входной канал. Поскольку мы будем использовать ADC0 (PIN0) то, как следует из ниже приведенной таблицы, нам нет необходимости устанавливать все эти биты.
BROWN (коричневый, ADPS0-ADPS2): эти три бита используются для установки коэффициент деления предделителя АЦП. Поскольку мы используем коэффициент деления предделителя 2, мы должны установить только один из этих битов.
DARK GREEN (темно-зеленый, ADSC): этот бит необходимо установить для того чтобы АЦП начал осуществлять преобразование. Далее в программе мы можем его сбросить (в 0) если нам нужно будет остановить процесс аналого-цифрового преобразования.
Исходный код программы на языке С (Си) с пояснениями
Программа для рассматриваемой схемы представлена следующим фрагментом кода на языке С (Си). Комментарии к коду программу поясняют принцип работы отдельных команд.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
#include <avr/io.h> // заголовок чтобы разрешить контроль данных на контактах #define F_CPU 1000000 // задание тактовой частоты микроконтроллера #include <util/delay.h> // заголовок чтобы задействовать функции задержки в программе #define E 5 // задействуем 5-й контакт PORTD (“enable”), поскольку он соединен с контактом “enable” ЖК дисплея #define RS 6 // задействуем выбор регистра (“registerselection”) на 6-м контакте PORTD, поскольку он соединен с контактом RS ЖК дисплея void send_a_command(unsigned char command); void send_a_character(unsigned char character); void send_a_string(char *string_of_characters); int main(void) { DDRB = 0xFF; // установка portB на вывод данных DDRD = 0xFF; // установка portD на вывод данных _delay_ms(50); //задержка 50ms DDRC = 0; // установка portС на ввод данных ADMUX |=(1<<REFS0); // установка опорного напряжения для АЦП ADCSRA |=(1<<ADEN)|(1<<ADFR)|(1<<ADPS0); // активация АЦП, установка свободного режима, установка шкалы АЦП 2 float i =0; float RESISTANCE= 0;// переменная для хранения значения цифрового выхода char RESISTANCESHOW [7]; // массив символов для отображения на экране ЖК дисплея значения сопротивления send_a_command(0x01); // очистить экран 0x01 = 00000001 _delay_ms(50); send_a_command(0x38); // сообщаем ЖК дисплею что мы будем использовать 8 битный режим передачи данных/команд _delay_ms(50); send_a_command(0b00001111); //включаем курсор и мигание курсора на ЖК дисплее ADCSRA |=(1<<ADSC); //старт АЦП send_a_string ("CIRCUIT DIGEST ");// отображение строки "CIRCUIT DIGEST " send_a_command(0x80 + 0x40 + 0);// переводим курсор на 1 позицию второй строки send_a_string ("RESISTANCE=");// отображение строки "RESISTANCE=" send_a_command(0x80 + 0x40 + 11);// переводим курсор на 10 позицию второй строки while(1) { i=ADC/204.8;//поскольку мы используем 10 битный АЦП и для опорного напряжения 5В мы имеем Vref(5V)/1024=5mV(4.88mV), мы получим один цифровой инкремент для каждых 5мВ, соответственно на каждый дополнительный 1В мы будем иметь 204.8 приращения счетчика. То есть для определения истинного значения напряжения нужно выполнить следующую последовательность действий. dtostrf(RESISTANCE, 4, 1, RESISTANCESHOW); send_a_string(RESISTANCESHOW); send_a_string("K"); //dtostr(double precision value, width, precision, string that will store the numbers); // Value – число, или переменная , содержащая число //Width – общая длина числа, которое функция dtostrf должна преобразовать в строку, включающая точку и отрицательный знак числа(-). Например, если рассматриваем число -532.87, то его длина будет равна 7 (5 цифр + знак (-) + точка (.)) //Precision – задает точность преобразования, то есть сколько знаков после запятой учитывать _delay_ms(50); send_a_command(0x80 + 0x40 + 11);//возвращаем курсор на 10 позицию второй строки } } void send_a_command(unsigned char command) { PORTA = command; PORTD &= ~ (1<<RS); // устанавливаем RS в 0 чтобы сообщить ЖК дисплею что мы будем передавать команду PORTD |= 1<<E; // сообщаем ЖК дисплею чтобы он принял команду/данные _delay_ms(50); PORTD &= ~1<<E; // сообщаем ЖК дисплею что мы закончили передачу данных PORTA= 0; } void send_a_character(unsigned char character) { PORTA= character; PORTD |= 1<<RS; // сообщаем ЖК дисплею что мы будем передавать данные (не команду) PORTD |= 1<<E; // сообщаем ЖК дисплею чтобы он начал прием данных _delay_ms(50); PORTD &= ~1<<E; // сообщаем ЖК дисплею что мы закончили передачу данных PORTA = 0; } void send_a_string(char *string_of_characters) { while(*string_of_characters > 0) { send_a_character(*string_of_characters++); } } |