Уважаемые пользователи Голос!
Сайт доступен в режиме «чтение» до сентября 2020 года. Операции с токенами Golos, Cyber можно проводить, используя альтернативные клиенты или через эксплорер Cyberway. Подробности здесь: https://golos.io/@goloscore/operacii-s-tokenami-golos-cyber-1594822432061
С уважением, команда “Голос”
GOLOS
RU
EN
UA
evgenij-byvshev
7 лет назад

Программирование микроконтроллеров. Часть 4-1

Делаем вольтметр

  И снова здравствуйте! В третьей части этого курса я показал, как можно использовать встроенный в микроконтроллер АЦП. Сегодня я покажу как подключить 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

11
105.241 GOLOS
На Golos с February 2017
Комментарии (2)
Сортировать по:
Сначала старые