AVR Урок 32. Дисплей LCD 20×4. Расширяем функционал

 

 

 

 

Урок 32

Дисплей LCD 20×4. Расширяем функционал

 

 

Сегодня мы продолжим работу с символьным дисплеем 20×4 и попробуем немного расширить его функционал. Зачем это потребуется, мы узнаем в более поздних уроках.

Дисплей мы подключим обычным 4-битным образом, ну, вернее мы его вообще не будем подключать, он у нас с прошлого урока подключен.

Сразу перейдём к проекту. Проект был назван MyLCD80, файлы lcd.h, lcd.c и main.h были перенесены и подключены из предыдущего урока по подключению посредством шины SPI двух контроллеров друг к другу. Ну, так как у нас контроллер ATmega8A, то файлы были взяты из проекта для данного контроллера.

В файл main.h подключим ещё библиотеку для работы со строками

 

#include <stdlib.h>

#include <string.h>

 

А в главный модуль подключим только main.h, а остальное оставим пустым. После этого иметь он будет вот такой простой вид

 

#include "main.h"

//—————————————-

int main(void)

{

  while(1)

  {

  }

}

 

Добавим обычную инициализацию порта D

 

#include "main.h"

//—————————————-

void port_ini(void)

{

  PORTD=0x00;

  DDRD=0xFF;

}

//—————————————-

 

И вызовем данную функцию в main()

 

int main(void)

{

  port_ini(); //инициализируем порты

 

А весь остальной код для main() возьмём с урока по переходнику I2C кроме инициализации I2C и в конце добавим задержку

 

port_ini(); //инициализируем порты

LCD_ini(); //инициализируем дисплей

clearlcd();//очистим дисплей

setpos(0,0);

str_lcd("String 1");

setpos(2,1);

str_lcd("String 2");

setpos(4,2);

str_lcd("String 3");

setpos(6,3);

str_lcd("String 4");

_delay_ms(2000);

while(1)

 

Соберём на всякий случай и проверим работу кода в протеусе

 

Image00

 

Теперь прошьём контроллер и посмотрим результат на живом дисплее

 

Image01

 

Всё у нас работает. Также мы видим резистор, подключеный к подсветке, чтобы ограничить ток и уберечь светодиоды от несвоевременного выхода из строя.

Продолжим дальше.

Вообщем, задача у нас такая. Нам нужно написать функцию, которая будет выводить все 80 символов из одного буфера. Зачем это нужно? Я планирую в будущем попработать с картой SD и там надо будет выводить немалые тексты, а короткими строками это делать не очень удобно. Да и вообще данная функция не помешает нашей библиотеке, и, может быть, когда нибудь пригодится.

Зайдём в файл lcd.c и добавим туда функцию

 

//—————————————-

void str80_lcd (char str1[])

{

}

//—————————————-

 

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

 

void str80_lcd (char str1[])

{

unsigned char n;

 

И будем потихоньку выводить все строки.

Первые 20 символов строки буфера мы выведем в первую строку дисплея

 

unsigned char n;

sendbyte(0x80,0);//1 строка

for(n=0;n<=19;n++)

   sendcharlcd(str1[n]);

 

Здесь мы сначала устанавливаем текущий адрес в DDRAM и в цикле отправляем байты в данную память дисплея.

Дальше мы применим хитрость, используя организацию памяти контроллера дисплея, лишний раз заглянув в его даташит

 

Image02

 

Как мы видим, адресация у нас продолжается на 3 строке, поэтому мы её и выведем

 

for(n=0;n<=19;n++)

  sendcharlcd(str1[n]);

for(n=40;n<=59;n++)//на 3ю строку перейдём автоматически в силу организации DDRAM дисплея

  sendcharlcd(str1[n]);

 

 

Затем установим указатель на 2 строку и выведем её на дисплей

 

for(n=40;n<=59;n++)//на 3ю строку перейдём автоматически в силу организации DDRAM дисплея

   sendcharlcd(str1[n]);

sendbyte(0xC0,0);//2 строка

for(n=20;n<=39;n++)

   sendcharlcd(str1[n]);

 

Также как и выше, мы используем таблицу и без позиционирования выведем строку 4

 

  for(n=20;n<=39;n++)

     sendcharlcd(str1[n]);

  for(n=60;n<=79;n++)//на 4ю строку перейдём автоматически в силу организации DDRAM дисплея

     sendcharlcd(str1[n]);

}

 

Вот, в принципе, и вся функция.

Вернёмся в главный модуль и добавим строку большой длины, чтобы её потом вывести. Символов в строке будет 512. А 512 потому, что в блоке SD-карты у нас ровно столько байтов. Текст возьмём любой. Здесь я его немного сокращу, а то мало ли она какая авторская и индексные роботы yandex и google нас за это по головке не погладят

 

#include "main.h"

//—————————————-

char buffer[512]="The … read operation…";//буфер данных для вывода

//—————————————-

 

Соответственно, в приложенном архиве с проектом строка будет полностью.

Вывод строк мы оставим в main() и после задержки попробуем вызвать нашу функцию. На не нужно использовать никакое позиционирование, так как у нас и так всё в функции позиционируется отлично

 

_delay_ms(2000);

str80_lcd(buffer);

 

Ну давайте соберём код и запустим его сначала в протеусе

 

Image03

 

Всё отлично отображается. Прошьём контроллер и проверим на настоящем дисплее

 

Image04

 

Точно так же всё работает прекрасно.

Только есть одна загвоздка, мы видим только часть текста, то есть от 512 символов мы видим только 80.

Ну давайте тогда придумаем, как нам пошагать по всему буферу.

Добавим ещё одну задержку в код и также ещё кое-что

 

str80_lcd(buffer);

_delay_ms(1000);

str80_lcd(buffer+20);

 

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

Тем самым мы начнём вывод уже с тех символов, которые в предыдущем выводе у нас были на 2 строке, так как в строке у нас 20 символов.

Попробуем собрать код. В протеусе можно уже не смотреть, будем смотреть на настоящем дисплее. Поэтому прошьём контроллер и посмотрим

 

Image05

 

И через секунду текст у нас переместился вверх и дисплей нам в нижней строке показал следующие 20 символов.

Покажем ещё 20 символов

 

str80_lcd(buffer+20);

_delay_ms(1000);

str80_lcd(buffer+40);

 

Посмотрим результат

 

Image06

 

Текст сместился вверх ещё на одну строку.

А теперь, чтобы нам не мучиться и не писать так для каждой строки, сделаем всё это в цикле, добавив для начала локальную переменную для счётчика в main()

 

int main(void)

{

  unsigned int i;

  port_ini(); //инициализируем порты

 

По идее, здесь хватило бы и типа поменьше, но мы потом ещё попробуем посдвигать текст посимвольно. Закомментируем предыдущий код вывода наших 80-символьных страниц и добавим цикл

 

// str80_lcd(buffer+40);

for (i=0;i<=22;i++) {str80_lcd(buffer+i*20);_delay_ms(1000);}

 

Проверим результат. Конечно в рамках веб-страницы этот эффект не покажешь, поэтому смотрите видеоурок, ссылкой на который является картинка, размещённая в конце страницы. Покажу только последнюю страницу текста

 

Image07

 

Мы видим, что в конце у нас вывелась ещё дальнейшая область памяти, там у нас самая первая строка, которую мы вызывали в начале программы. Заодно мы увидели организацию памяти в контроллере.

Теперь закомментируем последнюю написанную страничку кода и напишем другой цикл, который будет сдвигать текст посимвольно

 

//for (i=0;i<=22;i++) {str80_lcd(buffer+i*20);_delay_ms(1000);}

for (i=0;i<=432;i++) {str80_lcd(buffer+i);_delay_ms(100);}

 

Здесь мы уже точно отняли 80 от величины буфера, поэтому текст должен будет вывести без лишней области памяти

 

Image08

 

Мы видим, что ничего лишнего уже не вывелось. Обязательно посмотрите видеоверсию урока. Выглядит очень красиво.

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

Теперь мы можем на дисплее спокойно выводить и читать небольшие тексты.

 

Предыдущий урок Программирование МК AVR Следующий урок

 

Исходный код

 

Программатор и дисплей можно приобрести здесь:

Программатор (продавец надёжный) USBASP USBISP 2.0

Дисплей LCD 20×4

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

AVR Дисплей LCD 20×4. Расширяем функционал

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*