Давайте немного отдохнём от сложных модулей и поработаем с нашим старым добрым символьным дисплеем, собранном на контроллере HD44780, в котором доступно для отображения 80 символов, организованных в 4 строки по 20 символов в каждой.
В 10 уроке мы подключали данный режим, используя все его контакты данных, в 8-битном режиме. Но последнее время всё больше актуальна возможность контроллера дисплея работать в 4-битном режиме, когда мы подключаем только 4 ножки данных и передаём по ним байты данных только по ножкам D4-D7, сначала один полубайт, потом второй.
Также нам такой режим потребуется не только для экономии ножек портов, а ещё для того, чтобы мы могли работать с переходником, который преобразует сигналы последовательной шины I2C в сигналы параллельной шины. Данный переходник используется именно для такого дисплея и для связи его с дисплеем используется именно 4-битный способ передачи данных. Поэтому и родился такой внеочередной урок.
Плату и контроллер мы будем использовать те же, что и в 10 уроке, только подключать в разъём мы дисплей не будем, а подключим его туда с помощью проводов, пропустив ненужные контакты D0-D3.
Подключение будет выглядеть вот таким вот способом
Проект за основу мы возьмём из 10 урока с именем LCD2004_8BIT и назовём его LCD2004_4BIT.
Откроем проект в MPLAB.X, сделаем его главным, а в настройках убедимся, что программатор не будет питать схему, так как питать мы её будем от внешнего источника питания.
Идём сразу в файл lcd.h и добавим там макрос частоты тактирования, так как мы будем использовать стандартные задержки
#include <xc.h>
//--------------------------------------------------------------
#define _XTAL_FREQ 4000000
//--------------------------------------------------------------
Так как отправлять информацию физически в контроллер дисплея мы будем только по 4 проводам (полубайтами или тетрадами), то перейдём в файл lcd.c сначала в функцию настройки портов LCD_PORT_init, удалим всё её тело, и для порта D инициализируем направление передачи данных только нужным ножкам, а заодно то же самое проделаем и для порта C, так как используем мы там только 3 ножки
void LCD_PORT_init()
{
TRISC4=0;
TRISC5=0;
TRISC6=0;
TRISD4=0;
TRISD5=0;
TRISD6=0;
TRISD7=0;
}
Также в связи с тем же ниже этой функции напишем функцию передачи полубайта (тетрады) в 4-битный порт контроллера дисплея
//--------------------------------------------------------------
void sendhalfbyte(unsigned char c)
{
c<<=4;
PORTD&=0b00001111;
PORTD|=c;
e=1;
__delay_us(1);
e=0;
__delay_us(50);
}
//--------------------------------------------------------------
Сначала мы сдвинем наш входной аргумент влево на 4 бита, так как работаем мы со старшими разрядами шины (4-7). И не просто сдвинем, а этому же аргументу и присвоим, написав после операции сдвига знак равно.
Затем мы стираем информацию на информационных входах, сгенерируем импульс на линии E, и немного подождём.
Соответственно, функцию передачи целого байта sendbyte в шину мы также обязаны исправить.
Первым делом удалим из её тела передачу числа в порт C
PORTD=c;
Создадим локальную переменную
void sendbyte(unsigned char c, unsigned char mode)
{
unsigned char hc=0;
После определения режима передачи данных или команды мы присвоим данной переменной старшую часть нашего байта
else rs=1;
hc=c>>4;
Удалим весь код после данной операции из тела функции и передадим в шину сначала старшую тетраду байта, а затем младшую
hc=c>>4;
sendhalfbyte(hc);sendhalfbyte(c);
}
Функцию инициализации LCD_Init нам тоже придётся подправить, так как инициализация 4-битного режима несколько отличается от инициализации 8-битного
Причём проще тело функции будет не подправить, а полностью переписать, поэтому мы данное тело удалим.
Мы, конечно, не будем строго придерживаться данному алгоритму, особенно таймингам, так как дисплеи попадаются разного качества, поэтому алгоритм в теле нашей функции будет применён из выстраданной практики, ибо с такими дисплеями мы работаем уже давно.
Первым делом сразу задержка на 50 милисекунд, дадим включиться дисплею
void LCD_Init()
{
__delay_ms(50);
Очистим все уровни на участвующих ножках шины
__delay_ms(50);
PORTC &= ~0x70;
PORTD &= ~0xF0;
Подождём ещё немного
PORTD &= ~0xF0;
__delay_ms(100);
Дальше передадим серию команд, по которым контроллер дисплея поймёт, что с ним хотят общаться именно по 4 проводам
__delay_ms(100);
sendhalfbyte(0x03);
__delay_us(4500);
sendhalfbyte(0x03);
__delay_us(4500);
sendhalfbyte(0x03);
__delay_us(200);
sendhalfbyte(0x02);
Настроим режимы. От той же самой операции для 8-битного режима наша операция будет отличаться только 1 битом
sendhalfbyte(0x02);
__delay_ms(1);
sendbyte(0x28, 0);//mode 4 bit, 2 lines (from our large display is 4 lines, font 5x8
Остальное практически не изменилось, за исключением некоторых деталей, мы установили курсор на место (невизуальный или воображаемый, визуального у нас нет)
sendbyte(0x28, 0);//mode 4 bit, 2 lines (from our large display is 4 lines, font 5x8
sendbyte(0x0C,0);//Display ON, Cursor OFF, blink OFF
__delay_ms(1);
sendbyte(0x01,0);// Clear Display
__delay_ms(2);
sendbyte(0x06,0);// direction left to right
__delay_ms(1);
sendbyte(0x02,0);//Cursor reset
sendbyte(0X80,0);//SET POS LINE 0
__delay_ms(2);
}
Ниже функции инициализации добавим также функцию очистки дисплея, она нам непременно пригодится
//--------------------------------------------------------------
void LCD_Clear(void)
{
sendbyte(0x01, 0);
__delay_us(1500);
}
//--------------------------------------------------------------
Добавим в заголовочном файле на данную функцию прототип, попробуем собрать код и прошить контроллер.
А вот и результат
Так как мы сегодня быстро справились со своей задачей, то мы ещё можем написать небольшой тест, который будет выводить цифры в реальном времени, что сделает наш тест немного динамичнее.
Для этого сначала перейдём в файл main.h и добавим там возможность работы со строковыми функциями
#include <xc.h>
#include <stdio.h>
#include <string.h>
Далее идём в файл main.c и добавим там глобальный символьный массив
#include "main.h"
//------------------------------------------------
char str01[30]={'\0'};
//------------------------------------------------
Затем переходим в функцию main() и начала очистим дисплей через 2 секунды после отображения наших строк
Объявим локальную переменную для счёта
void main()
{
unsigned int i = 0;
После вывода строк на дисплей подождём 2 секунды и очистим дисплей
LCD_String((char*)"String 4");
__delay_ms(2000);
LCD_Clear();
А теперь мы в бесконечный цикл добавим вот такой вот алгоритм
while(1)
{
i++
;
sprintf(str01,"%5u",i);
LCD_SetPos(4,3);
LCD_String(str01);
sprintf(str01,"%5u",65536-i);
LCD_SetPos(10,3);
LCD_String(str01);
__delay_ms(200);
}
Мы инкрементируем наш счётчик, выводим показания в определённую позицию, а также в другую позицию мы выводим показания данного счётчика, но вычтенные из числа 65536. Таким образом, согласно задержке, примерно 5 раз в секунду наши данные будут обновляться на дисплее. Мы используем затирание лишних символов для того, чтобы постоянно не очищать дисплей.
Соберём код, прошьём контроллер и посмотрим результат нашей работы на практике
Всё отлично работает!
Таким образом, данный урок нас научил работать с символьным дисплеем в 4-битном режиме, что позволило нам освободить целых 4 ножки порта.
Всем спасибо за внимание!
Предыдущий урок Программирование МК PIC Следующий урок
Купить программатор (неоригинальный) можно здесь: PICKit3
Купить программатор (оригинальный) можно здесь: PICKit3 original
Отладочную плату PIC Open18F4520-16F877A можно приобрести здесь: PIC Open18F4520-16F877A
Дисплей LCD 20×4 можно приобрести тут: Дисплей LCD 20×4
Смотреть ВИДЕОУРОК (нажмите на картинку)
Класс!!!
Подскажите как можно подправить прошивку, если к примеру данные RD0-RD3, а управляющие сигналы RD4 -> RS, RD5 -> E? Спасибо.
В исходном коде sendbyte(unsigned char c, unsigned char mode) — не исправлена.
Там — unsigned char hc=0;
PORTD=c; — а это надо вычеркнуть
———
Alex:
void sendhalfbyte(unsigned char c)
{
//c<<=4;
PORTD&=0b11110000;
PORTD|=c;
e=1;
__delay_us(1);
e=0;
__delay_us(50);
}
-то есть убираем сдвиг.
Ну и соотвественно TRISD меняем в инициализации.