Делаем вольтметр
И снова здравствуйте! В третьей части этого курса я показал, как можно использовать встроенный в микроконтроллер АЦП. Сегодня я покажу как подключить LCD 16-и символьный 2-х строчный индикатор и используя материал из предыдущей части отобразить на индикаторе измеренное напряжение на входе АЦП, т.е. сделаем простейший вольтметр.
В Proteus я зашел в библиотеку компонентов, нашел в ней дисплей LM016L и подключил его к схеме, взятой из предыдущей части, следующим образом:
И сохранил проект.
Если сейчас запустить симуляцию, то LCD дисплей будет просто светиться и ничего не отображать. Так и должно быть, ведь для него не написано еще ни одной строчки в программе и микроконтроллер не знает, что с ним делать. Для того чтобы дисплей заработал нужно запустить AtmelStudio, создать новый проект и скопировать весь код из предыдущего урока.
В функции port_ini() нужно добавить порт к которому будет подключен дисплей. Так как режим у нас 4-битный, то нам вполне хватит ножек, даже останутся. В данном случае – это PORTB. Делается это следующим образом:
DDRB=0xFF;
PORTB=0x00;
Для инициализации дисплея необходимо через определенные промежутки три раза передать двоичное число 11, и тогда контроллер дисплея "поймёт", что от него хотят именно того, чтобы он общался с нами в 4-х битном режиме, и чтобы он в данный режим как-то переключился. Напишем функцию инициализации дисплея. Код данной функции нужно разместим перед функцией main()
void LCD_ini(void)
{
}
И эту функцию нужно вызвать в функции main().
port_ini(); //Инициализируем порты
ADC_ini(); //Инициализируем АЦП
LCD_ini(); //Инициализируем АЦП
В теле данной функции, судя по диаграмме инициализации из технической документации необходимо подождать сначала не менее 15 миллисекунд
void LCD_ini(void)
{
_delay_ms(15); //Ждем 15 мс
Дальше необходимо как-то передавать контроллеру дисплея байты. Но так как байты сразу передать не получиться, ибо у нас даже ножки данных половина не подключены, то передавать нужно полубайты. Так как это не совсем простой процесс, предлагаю завести под это дело ещё одну функцию и назвать её send_half_byte. В качестве входного параметра ей нужно передавать unsigned char, так как у нас 4-битных переменных не бывает, мы просто не будем использовать в данной переменной первые 4 бита.
void send_half_byte(unsigned char c)
{
}
Сначала необходимо сдвинуть наш входной аргумент влево на 4 бита, так как приходиться работать со старшими разрядами шины (4-7). И не просто сдвинуть, а этому же аргументу и присвоить, написав после операции сдвига знак равно.
void send_half_byte(unsigned char c)
{
c<<=4;
Сначала я напишу несколько макроподстановок для удобства работы с линиями E и RS, то есть их включение и выключение.
#include <util/delay.h>
#define e1 PORTB|=0b00001000 //установка линии E в 1
#define e0 PORTB&=0b11110111 //установка линии E в 0
#define rs1 PORTB|=0b00000100 //установка линии RS в 1 (данные)
#define rs0 PORTB&=0b11111011 //установка линии RS в 0 (команда)
В функции передачи полубайта необходимо включить линию E, для того чтобы сказать дисплею, что мы будем передавать команду. Затем подождать 50 микросекунд, стереть информацию на ножках 4-7 порта B, остальные ножки трогать не будем, потом установить нужные биты на шине данных из переменной c, в которой находятся данные биты. Потом отключить линию E и подождать ещё 50 микросекунд.
Теперь весь код этой функции будет выглядеть так:
void send_hal_fbyte(unsigned char c)
{
c<<=4;
e1; //включаем линию Е
_delay_us(50);
PORTB&=0b00001111; //стираем информацию на входах 4-7, остальное не трогаем
PORTB|=c;
e0; //выключаем линию Е
_delay_us(50);
}
Теперь необходимо в контроллер дисплея передать двоичное число 11 три раза в функции LCD_ini, также применяя соответствующие задержки, взяв их из даташита дисплея. В данном примере это дисплей модели LCD-1602.
_delay_ms(15); //Ждем 15 мс
send_half_byte(0b00000011);
_delay_ms(4);
send_half_byte(0b00000011);
_delay_us(100);
send_half_byte(0b00000011);
_delay_ms(1);
Дальше передаём двоичное число 10 таким же образом
_delay_ms(1);
send_half_byte(0b00000010);
_delay_ms(1);
Контроллер дисплея должен "догадаться", что мы его переключаем в 4 битный режим, и следующая команда будет же с полноправным байтом, переданным поочередно и причем в этой команде уже будет конкретная команда перевода в 4-битный режим. Но для полноправных команд необходимо написать другую функцию send_byte, расположив ее код после функции send_half_byte.
void send_byte(unsigned char c, unsigned char mode)
{
}
В эту функцию необходимо передавать уже два аргумента, один — это данные, а другой - это режим, то есть мы здесь будем говорить, данные мы будем передавать или команду.
C помощью условия необходимо узнать, команда в нашу функцию пришла или данные, и среагировать на это установкой в соответствующее состояние шины RS
void send_byte(unsigned char c, unsigned char mode)
{
if (mode==0) rs0;
else rs1;
Добавим ещё одну переменную
else rs1;
unsigned char hc=0;
Сдвинув вправо на 4 пункта наш байт отправим результат в данную переменную. Тем самым в младшую тетраду байта поместим старшую
unsigned char hc=0;
hc=c>>4;
Передадим сначала её в функцию send_half_byte, а затем и саму нетронутую переменную c. Не важно, что будет в её старшей части, так как функция send_half_byte работает только с младшей тетрадой.
hc=c>>4;
send_half_byte(hc); send_half_byte(c);
}
Теперь применяя вышенаписанную функцию необходимо передать следующий байт, взятый из даташита в функции LCD_ini
_delay_ms(1);
send_byte(0b00101000, 0); //4бит-режим и 2 линии
_delay_ms(1);
Передадем следующий байт
_delay_ms(1);
send_byte(0b00001100, 0); //включаем изображение на дисплее, курсоры никакие не включаем
_delay_ms(1);
Передаём последнюю команду в функции инициализации дисплея
_delay_ms(1);
send_byte(0b00000110, 0); //курсор (хоть он у нас и невидимый) будет двигаться влево
_delay_ms(1);
}
Весь код функции будет выглядеть так:
void LCD_ini(void)
{
_delay_ms(15); //Ждем 15 мс
send_half_byte(0b00000011);
_delay_ms(4);
send_half_byte(0b00000011);
_delay_us(100);
send_half_byte(0b00000011);
_delay_ms(1);
send_half_byte(0b00000010);
_delay_ms(1);
send_byte(0b00101000, 0); //4бит-режим и 2 линии
_delay_ms(1);
send_byte(0b00001100, 0); //включаем изображение на дисплее, курсоры никакие не включаем
_delay_ms(1);
send_byte(0b00000110, 0); //курсор (хоть он у нас и невидимый) будет двигаться влево
_delay_ms(1);
}
На этом инициализация дисплея закончена.
В следующей части урока попробуем поработать с выводом данных на экран дисплея.
Если есть вопросы и предложения по этому уроку, пишите комментарии буду рад ответить на ваши вопросы.
Часть 1
Часть 2-1 Часть 2-2
Часть 3-1 Часть 3-2
Мой блог в ЖЖ: http://evgenij-byvshev.livejournal.com
Когда-нибудь я мечтаю сделать своего хоть простенького робота!)) Вот тогда ваши труды мне пригодятся)
__
Участник comment chalenge
Привет!
Этот пост был выбран Академией Голоса и попал в список программы поддержки качественных образовательных постов.
Ссылка на твой пост будет опубликована в отчете Академии.
Спасибо за полезный контент (ノ◕ヮ◕)ノ*:・゚✧