PIC Урок 10. LCD 20×4. 8-битный режим. Часть 2



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

 

Перейдём в файл lcd.c и начнём потихоньку писать библиотеку, используя накопленный опыт программирования других типов контроллеров.

Добавим макросы для ножек управления дисплеем

 

#include "lcd.h"

//--------------------------------------------------------------

#define rs RC4

#define rw RC5

#define e RC6

//--------------------------------------------------------------

 

Напомню, что ножка rs — это ножка для переключения режима данных — данные/команда. То есть если мы передаём данные, то на данной ножке мы предварительно устанавливаем высокий уровень, а если команду, то низкий.

Ножка rw служит для переключения режима направления данных. Если на ней уровень низкий, то мы данные в контроллер дисплея пишем, а если высокий, то читаем.

Ножка e — это ножка выбора дисплея. Перед передачей или приёмом данных мы на неё подаём низкий уровень, а после передачи мы уровень подаём высокий.

Время между опусканием и подниманием данной ножки регламентировано. Также регламентировано и время минимального нахождения ножки в высоком состоянии перед тем как записать данные и должно быть не менее 300 наносекунд. Данное время мы никак не будем программно выдерживать, так как мы ножку будем поднимать сразу после отправки данных и до следующей отправки у нас и так пройдёт. Также известно общее минимальное время для отправки данных в контроллер дисплея, то есть время всего цикла. Оно должно быть не менее 500 наносекунд. Но мы не будем выдерживать такие малые интервалы. Мы подождём побольше на всякий случай, по крайней мере так было в примере для контроллера, которые предоставила компания-производитель платы. Оставим такое же, когда будем писать функцию отправки байта в контроллер дисплея.

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

 

#define e RC6

//--------------------------------------------------------------

void LCD_delay()

{

  int i;

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

}

//--------------------------------------------------------------

 

Добавим функцию инициализации ножек портов

 

//--------------------------------------------------------------

void LCD_PORT_init()

{

  TRISC=0X00;

  TRISD=0X00;

}

//--------------------------------------------------------------

 

Добавим функцию отправки байта в контроллер дисплея

 

//--------------------------------------------------------------

void sendbyte(unsigned char c, unsigned char mode)

{

  PORTD=c;

  if(mode==0) rs=0;

  else rs=1;

  rw=0;

  e=0;

  LCD_delay();

  e=1;

}

//------------------------------------------------

 

В данной функции будет 2 параметра. Первый — это непосредственно значение отправляемого байта, а второй — это тип отправки — данные или команда.

 

 

Сначала мы сразу отправляем наш байт в регистр порта C, чтобы на его ножках выставились уровни, соответствующие значению нашего байта, так как именно ножки данного порта подключены к ножкам данных дисплея. Затем мы выставляем уровень на ножке RS в зависимости от того, команду или данные мы будем отправлять в дисплей. Далее мы устанавливаем низкий уровень на ножке RW, говоря контроллеру дисплея о том, что мы будем его использовать в режиме записи. Мы можем конечно установить данный уровень на этапе инициализации, так как читать мы из контроллера дисплея ничего не будем, но так всё-таки будет универсальнее, вдруг, когда-то будем работать в режиме чтения. Далее мы опускаем ножку E, применяем задержку, и затем поднимаем данную ножку. Данные должны будут уйти в дисплей.

Добавим функцию инициализации

 

//------------------------------------------------

void LCD_Init()

{

}

//------------------------------------------------

 

Начнём теперь писать непосредственно функцию инициализации дисплея.

Очистим дисплей

 

void LCD_Init()

{

  sendbyte(0X01,0);//Clear Display

 

Используется вот такая функция

 

 

Зададим контроллеру дисплея использовать 8-битный режим, режим 2х линий (для 4-х строчного — это 4 линии) и формат 5х8

 

sendbyte(0X01,0);//Clear Display

sendbyte(0X38,0);//Function set: 8-bit bus mode,

//2-line display mode is set (2004 - 4-line), 5x8 dots format

 

Вот описание данной команды

 

 

Включим дисплей, отключим курсор и мигание последнего символа

 

//2-line display mode is set (2004 - 4-line), 5x8 dots format

sendbyte(0X0c,0);//Display ON, Cursor OFF, blink OFF

 

Описание команды:

 

 

Зададим направление написания текста влево

 

sendbyte(0X0c,0);//Display ON, Cursor OFF, blink OFF

sendbyte(0X06,0);//direction left to right

 

Описание команды

 

 

 

Установим курсор в начальное положение

 

  sendbyte(0X06,0);//direction left to right

  sendbyte(0X80,0);//SET POS LINE 0

}

 

Вот описание данной команды

 

 

Память DDRAM контроллера дисплея — это память, которая хранит коды символов, отображаемых в данный момент на дисплее. Вот мы и ставим указатель на 0 адрес данной памяти.

Эта память в дисплее 2004 распределена следующим образом по строкам

 

 

С инициализацией закончили.

Теперь добавим функцию вывода строки символов на дисплей в текущую позицию

 

//------------------------------------------------

void LCD_String(char* st)

{

  unsigned char i=0;

  while(st[i]!=0)

  {

    sendbyte(st[i],1);

    i++;

  }

}

//------------------------------------------------

 

Мы посылаем здесь байты с кодами символов в контроллер дисплея до тех пор, пока не встретимся с нулём. Это и есть окончание строки. Также обратите внимание, что режим мы используем уже для передачи данных, а не команд, так как пишем уже напрямую в DDRAM. Поэтому во втором аргументе функции передачи байта у нас 1, а не 0.

Выше только что написанной нами функции LCD_String добавим функцию установки указателя в требуемую позицию

 

//------------------------------------------------

void LCD_SetPos(unsigned char x, unsigned char y)

{

  switch(y)

  {

    case 0:

      sendbyte((unsigned char)(x|0x80),0);

      break;

    case 1:

      sendbyte((unsigned char)((0x40+x)|0x80),0);

      break;

    case 2:

      sendbyte((unsigned char)((0x14+x)|0x80),0);

      break;

    case 3:

      sendbyte((unsigned char)((0x54+x)|0x80),0);

      break;

  }

}

//------------------------------------------------

 

Данная функция во входных аргументах имеет значения координат по горизонтали и вертикали.

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

Пока нам функций для работы с дисплеем хватит, поэтому перейдём в заголовочный файл lcd.h и добавим прототипы на функции, которые нам потребуется вызывать из внешних модулей

 

#include <xc.h>

//--------------------------------------------------------------

void LCD_PORT_init();

void LCD_Init();

void LCD_String(char* st);

void LCD_SetPos(unsigned char x, unsigned char y);

//--------------------------------------------------------------

 

Ну и теперь наконец-то мы можем что-то вывести на наш дисплей. Перейдём в файл main.c и добавим код в функцию main()

 

void main()

{

  LCD_PORT_init();

  LCD_Init();

  LCD_String((char*)"String 1");

  LCD_SetPos(2,1);

  LCD_String((char*)"String 2");

  LCD_SetPos(4,2);

  LCD_String((char*)"String 3");

  LCD_SetPos(6,3);

  LCD_String((char*)"String 4");

  while(1)

 

Мы сначала готовим порты, затем инициализируем наш дисплей. Самую первую строку мы выводим в нулевую позицию первой строки, а далее уже все остальные строки выводим на другие строки дисплея в определённые позиции, используя при этом нами написанную функцию позиционирования. Также помним, что строки и колонки считаются с 0, а не с 1.

Собираем проект, и если он нормально собрался, то попытаемся прошить наш контроллер.

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

Откроем свойства проекта и выберем слева наш программатор

 

 

Выберем справа вверху данного диалога пункт «Power», затем ставим галочку в квадратик, заставляя тем самым программатор питать нашу схему, напряжение оставим 5 вольт

 

 

Применим настройки и попробуем прошить проект. Для этого нажмём соответствующую кнопку в панели инструментов среды программирования MPLAB X

 

 

В процессе прошивания контроллера могут выдаваться некоторые предупреждения типа такого

 

 

С таким предупреждением мы можем смело согласиться. Здесь нас IDE предупреждает о том, чтобы мы не забывали, что иногда контроллеры питаются напряжением 3,3 вольта, и в этом случае мы рискуем его вывести из строя. Но мы знаем, что у нас плата питается напряжением 5 вольт, поэтому смело соглашаемся.

После прошивки мы должны увидеть вот такую картину

 

 

Все наши строки выведены на дисплей, правда контрастность слабовата. Возможно не хватает мощности питания от программатора.

Поэтому попробуем подключить к плате блок питания.

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

Теперь мы увидим вот такую картину (правда, возможно, придется перепрошить контроллер)

 

 

Теперь совсем другое дело!

Итак, сегодня мы с вами сделали очень много полезного. Мы теперь можем прошивать контроллер прямо из среды программирования, также у нас появилась возможность отлаживать код в реальном контроллере. Также мы подключили новую плату с контроллером. Ну и также мы выполнили основную цель занятия: мы научились программировать символьный дисплей на контроллере HD44780. Теперь в последующих программах мы можем выводить на него некоторую информацию.

Всем спасибо за внимание!

 

 

Предыдущая часть Программирование МК PIC Следующий урок

 

Исходный код

 

Техническая документация на дисплей LCD2004

 

 

Купить программатор (неоригинальный) можно здесь: PICKit3

Купить программатор (оригинальный) можно здесь: PICKit3 original

Отладочную плату PIC Open18F4520-16F877A можно приобрести здесь: PIC Open18F4520-16F877A

Дисплей LCD 20×4 можно приобрести тут: Дисплей LCD 20×4</p

 

 

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

 

PIC LCD 20x4. 8-битный режим

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

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

*