Работа с ЖКИ на контроллере HD44780 и его аналогах
- Сообщения: 30
- Зарегистрирован: Ср окт 19, 2011 23:28:03
Запустил на 4 МГц, заработало. А надо на 8 МГц. Что надо сделать: изменить задержки delay с 15 до 30 или в как то по другому. чтобы грамотно было?
- Реклама
- Сообщения: 160
- Зарегистрирован: Сб дек 08, 2012 16:40:40
vetdoktor, на чём пишете программу? На Асме или С?
грамотно - выставлять задержки по даташиту на индикатор, см стр.16 "Инициализация"vetdoktor писал(а):Запустил на 4 МГц, заработало. А надо на 8 МГц. Что надо сделать: изменить задержки delay с 15 до 30 или в как то по другому. чтобы грамотно было?
я бы эту либу для себя с нуля написал, согласно своим потребностям и не ковыряясь в чужом коде
Коктейль "Рекурсивный": 20% спирта, 30% воды, 50% коктейля "Рекурсивный"...
- Сообщения: 160
- Зарегистрирован: Сб дек 08, 2012 16:40:40
+1unalex писал(а): я бы эту либу для себя с нуля написал, согласно своим потребностям и не ковыряясь в чужом коде
Это позволит и понять, как оно работает и быть уверенным в коде
- Сообщения: 30
- Зарегистрирован: Ср окт 19, 2011 23:28:03
- Реклама
- Сообщения: 112
- Зарегистрирован: Вс фев 24, 2013 19:02:22
Доброго времени суток, есть ли возможность нарисовать свой символ и вывести его на экран? Код желательно в CodeVision AVR) Хочу понять сам принцип.
Сюда перенёс.
Gudd-Head
Сюда перенёс.
Gudd-Head
- Сообщения: 191
- Зарегистрирован: Вт дек 27, 2011 01:13:21
1.HD44780 достаточно медленный. Поэтому при написании кода необходимо строго следить за длительностью сигналов
2. сам контроллер имеет 3 управляющие линии E - выбор кристала RS - команда/данные и RW - чтение/запись
3. на все время когда нет обращения к контроллеру на линиях E и RS должен быть логический ноль
4. драйвер управления сегментами как правило имеет вход подачи питания для регулировки (через подстроечный резистор). изменяя подаваемое напряжение добиваются контрасного свечения курсора (сегментов)
5. после включения питания контроллер требует многошаговой процедуры инициализации
6. далее работа с ним проста. Подается команда а затем данные, относящиеся к этой команде. Не забывайте что для обработки каманды (данных) контроллеру требуется время, так что код обращения должен это учитывать. я лично при програмировании дополнительно проверял бит занятости прежде чем начать новую транзакцию.
прорисовка символов с кодами 00..07 определяется пользователем потем записи в ОЗУ знакогенератора
пользователю доступны 8 программируемых символов при 5*8 точек или 4 символа для 5*10 точек (в этом случае символы адресуются через один те 00, 02, 04, 06)
команда 01АА АААА устанавливает указатель на область ОЗУ знакогенератора
матрица символа кодируется с помощью 8 (или 16 для символа 5*10 в этом случае 5 старших байтов не используются) байтов данных. 5 младших бит каждого байта соответствуют одной строке знака. 1 -- пиксел включен, три старших бита не используются. При рисовании символа можно залазить в область подчеркивания для курсора. Младший бит прорисовывает самый правый пиксел. Первый байт прорисовывает верхнюю строку пикселов - последний нижнюю
Алгоритм доступа таков. Устанавливаем адрес ОЗУ на начало соответствующего символа и последовательно записываем 8/16 байт
В дальнейшием когда поместим в DRAM код символа 00..07 знакогенератор возмет прорисовку из соответствующей области ОЗУ
2. сам контроллер имеет 3 управляющие линии E - выбор кристала RS - команда/данные и RW - чтение/запись
3. на все время когда нет обращения к контроллеру на линиях E и RS должен быть логический ноль
4. драйвер управления сегментами как правило имеет вход подачи питания для регулировки (через подстроечный резистор). изменяя подаваемое напряжение добиваются контрасного свечения курсора (сегментов)
5. после включения питания контроллер требует многошаговой процедуры инициализации
6. далее работа с ним проста. Подается команда а затем данные, относящиеся к этой команде. Не забывайте что для обработки каманды (данных) контроллеру требуется время, так что код обращения должен это учитывать. я лично при програмировании дополнительно проверял бит занятости прежде чем начать новую транзакцию.
прорисовка символов с кодами 00..07 определяется пользователем потем записи в ОЗУ знакогенератора
пользователю доступны 8 программируемых символов при 5*8 точек или 4 символа для 5*10 точек (в этом случае символы адресуются через один те 00, 02, 04, 06)
команда 01АА АААА устанавливает указатель на область ОЗУ знакогенератора
матрица символа кодируется с помощью 8 (или 16 для символа 5*10 в этом случае 5 старших байтов не используются) байтов данных. 5 младших бит каждого байта соответствуют одной строке знака. 1 -- пиксел включен, три старших бита не используются. При рисовании символа можно залазить в область подчеркивания для курсора. Младший бит прорисовывает самый правый пиксел. Первый байт прорисовывает верхнюю строку пикселов - последний нижнюю
Алгоритм доступа таков. Устанавливаем адрес ОЗУ на начало соответствующего символа и последовательно записываем 8/16 байт
В дальнейшием когда поместим в DRAM код символа 00..07 знакогенератор возмет прорисовку из соответствующей области ОЗУ
Вывод на LCD собственных знаков и символов - http://www.picbasic.ru/forum/9-803-1
там даже софтинка прилагается.
там даже софтинка прилагается.
- Сообщения: 112
- Зарегистрирован: Вс фев 24, 2013 19:02:22
Спасибо большое за то, что откликнулись! А как это законнектить с CodeVision AVR? К сожалению, до гуру программирования МК не дорос пока, начал осваивать с языка С, так как его я знаю более менее) Подключать к МК научился, выводить текст и данные научился, но хочу до конца довести задумку. Очень надеюсь на Вашу помощь и помощь форумчан!sa-ta писал(а):Вывод на LCD собственных знаков и символов - http://www.picbasic.ru/forum/9-803-1
там даже софтинка прилагается.
На CodeVision Выглядит примерно так
Спойлер
Код: Выделить всё
// Alphanumeric LCD Module functions
#asm
.equ __lcd_port=0x15 ;PORTC
#endasm
#include <lcd.h>
#include <delay.h>
//#define DEBUG
// Global variables defination
typedef unsigned char byte;
//Тут определяем как будт выглядеть символ(ы)
//поле 5х8
flash byte ch0[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f};
flash byte ch1[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x1f};
flash byte ch2[8]={0x00,0x00,0x00,0x00,0x00,0x1f,0x1f,0x1f};
flash byte ch3[8]={0x00,0x00,0x00,0x00,0x1f,0x1f,0x1f,0x1f};
flash byte ch4[8]={0x00,0x00,0x00,0x1f,0x1f,0x1f,0x1f,0x1f};
flash byte ch5[8]={0x00,0x00,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f};
flash byte ch6[8]={0x00,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f};
flash byte ch7[8]={0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f};
//функция регистрации самопальных символов
void define_char(byte flash *pc,byte char_code)
{
byte i,a;
a=(char_code<<3) | 0x40;
for (i=0; i<8; i++) lcd_write_byte(a++,*pc++);
}
//В данном случае символы нужны для отображения урвня
//так он и выводится.
void display_level(unsigned char _level)
{
#ifndef DEBUG
unsigned char k,j;
lcd_gotoxy(8,1);
for (k=0;k<=_level;k++)
//Сам символ выводится как обычно функцией lcd_putchar()
lcd_putchar(k);
for (j=k;j<8;j++)
lcd_putsf(" ");
#endif
}
void main(void)
{
...
...
lcd_init(16);
lcd_gotoxy(0,0);
define_char(ch0,0);
define_char(ch1,1);
define_char(ch2,2);
define_char(ch3,3);
define_char(ch4,4);
define_char(ch5,5);
define_char(ch6,6);
define_char(ch7,7);
lcd_clear();
lcd_putsf("LCD TEST");
lcd_gotoxy(0,1);
lcd_putsf("Signal ");
for(i=0;i<8;i++)
{
display_level(i);
delay_ms(100);
};
}//end of main
Последний раз редактировалось Gudd-Head Чт фев 28, 2013 08:57:41, всего редактировалось 1 раз.
Причина: Нарушение п.2.5 Правил Форума
Причина: Нарушение п.2.5 Правил Форума
Купи два беляша и собери из них кошку
Labor est etiam ipse voluptas Труд уже сам по себе есть наслаждение (*Формула любви)
Ave novie-nostra ales Если один человек построил - другой завсегда разобрать может....(*Формула Любви).
Labor est etiam ipse voluptas Труд уже сам по себе есть наслаждение (*Формула любви)
Ave novie-nostra ales Если один человек построил - другой завсегда разобрать может....(*Формула Любви).
- Сообщения: 191
- Зарегистрирован: Вт дек 27, 2011 01:13:21
Кто может подсказать (уже подзабыл) если я пошлю команду 40Н для установки указателя на адрес 0 программируемого символа можно затем переслать сразу 64 байта данных для всех 8 символов или после записи данных одного символа необходимо самому передвигать указатель на адрес следующего символа. то есть существует ли автоинкремент при доступе к ОЗУ знакогенератора
O_l_e_g, зависит от проведенной инициализации. В инициализации включается эта функция. В сети обычно инициализация со включенной функцией автоинкремента. Проше попробовать) У меня такое работает на 16 знаковом дисплее. Я вывожу адрес первого знакоместа, а потом шлю 16 байт данных.
Единственное не понял, что Вы имели в виду под "64 байтами для 8 символов"
Зачем 64 байта для 8 символов?
Единственное не понял, что Вы имели в виду под "64 байтами для 8 символов"
Ставим плюсы: )
Насколько я понял человек собрался свои собственные символы выводить.ibiza11 писал(а):Единственное не понял, что Вы имели в виду под "64 байтами для 8 символов"Зачем 64 байта для 8 символов?
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
а йопт))) похоже на то)
вот нашел у себя в рабочем проекте
Функция lcd_put_byte() уже с задержкой, а lcd_set_address() без задержки, поэтому после первых нет функции задержки, а после вторых есть delay(107).
вот нашел у себя в рабочем проекте
Код: Выделить всё
void lcd_cgram_init(void) //процедура инициализации пользовательского знакогенератора
{
lcd_set_address(CGRAM_START_ADDRESS); //установка начального адреса CGRAM
delay (107); //танцы с бубном :)
unsigned char i;
for (i=0; i<8; i++) //правая стрелка
lcd_put_byte(RightArrow[i]);
for (i=0; i<8; i++) //левая стрелка
lcd_put_byte(LeftArrow[i]);
for (i=0; i<8; i++) //правая стрелка - остановленная
lcd_put_byte(RightArrowStop[i]);
for (i=0; i<8; i++) //левая стрелка - остановленная
lcd_put_byte(LeftArrowStop[i]);
for (i=0; i<8; i++) //основание степени (10^)
lcd_put_byte(Exp[i]);
for (i=0; i<8; i++) //запятая
lcd_put_byte(Dot[i]);
lcd_set_address(DDRAM_START_ADDRESS); //установка курсора в начальное положение ОЗУ
delay(107);
}Ставим плюсы: )
Товарищи, а вы в 4-х битном режиме делаете процедуру сброса?

В ДШ она производится при печати каждого байта, судя по диаграмме работыRepeated procedures for an 4-bit bus interface
Noise causing transfer mismatch between the four upper and lower bits can be corrected by a reset triggered by consecutively writing a “0000” instruction five times. The next transfer starts from the lower four bits and then first instruction “Function set” can be executed normally. Please insert the synchronization function in the head of procedures.
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
- Сообщения: 882
- Зарегистрирован: Ср фев 22, 2012 01:25:21
Я в 4-х битном работаю так:
Спойлер
Код: Выделить всё
//НАСТРАИВАЕМЫЕ ДЕФАЙНЫ (порты и линии портов для работы с LED дисплеем)
#define LCDDataPORT PORTD /*порт данных LCD*/
#define LCDDataDDR DDRD /*программирование линий данных LCD*/
#define LCD_D4 4 /*линия данных D4*/
#define LCD_D5 5 /*линия данных D5*/
#define LCD_D6 6 /*линия данных D6*/
#define LCD_D7 7 /*линия данных D7*/
#define LCDControlPORT PORTD /*порт линий управления LCD*/
#define LCDControlDDR DDRD /*программирование линий управления LCD*/
#define LCD_RS 2 /*линия управления RS*/
#define LCD_E 3 /*линия управления E*/
//НЕНАСТРАИВАЕМЫЕ ДЕФАЙНЫ
#define INLINE inline __attribute__((__always_inline__))
#define NOINLINE __attribute__((__noinline__))
#define LCDCommandCurHome 0x02 /*LCD переместить курсов в позицию 0,0*/
#define LCDCommandCurOn 0x0E /*LCD показать курсор*/
#define LCDCommandCurBlink 0x0F /*LCD мигающий курсор*/
#define LCDCommandCurOff 0x0C /*LCD выключить курсор*/
#define LCDCommandCurLeft 0x10 /*LCD курсор переместить влево*/
#define LCDCommandCurRight 0x14 /*LCD курсор переместить вправо*/
#define LCDCommandDispClear 0x01 /*LCD очистить данные дисплея*/
#define LCDCommandDispBlank 0x08 /*LCD скрыть данные (но не стирать)*/
#define LCDCommandDispVisible 0x0C /*LCD отобразить данные*/
#define LCDCommandDispShiftLeft 0x18 /*LCD сдвиг информации на дисплее влево*/
#define LCDCommandDispShiftRight 0x1C /*LCD сдвиг информации на дисплее вправо*/
#define LCDCommandDispModeProg 0x08|0x04 /*0x08 - программирование режима дисплея (присутствует всегда)*/
/*0x04 - отображение данных включено,*/
/*0x02 - курсор включен, 0x01 - курсор мерцает*/
//----------------------------------------------------------------------------------------------
//задержка для строб импульса
NOINLINE void LCDStrobeDelay (void)
{
_delay_ms (1);
}
//строб импульс
NOINLINE void LCDEStrobe (void)
{
LCDControlPORT|= (1<<LCD_E);
LCDStrobeDelay ();
LCDControlPORT &= ~(1<<LCD_E);
LCDStrobeDelay ();
}
//Функция инициализации LCD
void LCDInit (void)
{
LCDDataPORT &= ~(1<<LCD_D7|1<<LCD_D6|1<<LCD_D5|1<<LCD_D4); //очистить линии данных
LCDDataDDR |= (1<<LCD_D7|1<<LCD_D6|1<<LCD_D5|1<<LCD_D4); //линии данных на вывод
LCDControlPORT &= ~(1<<LCD_E|1<<LCD_RS); //очистить линии управления
LCDControlDDR |= (1<<LCD_E|1<<LCD_RS); //линии управления на вывод
//_delay_ms (50); //закомментировать, если в фузах контроллера запрограммирована задержка при старте 64мс
LCDDataPORT |= (1<<LCD_D5|1<<LCD_D4);
LCDEStrobe ();
_delay_ms (5);
LCDEStrobe ();
LCDEStrobe ();
LCDDataPORT &= ~(1<<LCD_D4);
LCDEStrobe ();
LCDSendCommand (0x28); //режим - 4 бита, 2 строки
LCDSendCommand (LCDCommandDispModeProg); //режим дисплея (определен в дефайнах)
}
//----------------------------------------------------------------------------------------------
//Функция установки курсора в нужную позицию
void LCDCurGotoXY (unsigned char x, unsigned char y)
{
if (y == 1)
x |= 0x40;
LCDSendCommand (0x80 | x);
}
//----------------------------------------------------------------------------------------------
//Функция загрузки графического символа в LCD
void LCDCharDefine (unsigned char *pMas, unsigned char SimbNum){
unsigned char temp = (0x40 | (SimbNum<<3));
for (unsigned char i=0; i<8; i++){
LCDSendCommand (temp++);
LCDSendChar (pgm_read_byte (pMas++));
}
}
//----------------------------------------------------------------------------------------------
//Функция отправки команды на LCD
//АРГУМЕНТ - код команды
void LCDSendCommand (unsigned char byte)
{
LCDDataPORT &= ~(1<<LCD_D7|1<<LCD_D6|1<<LCD_D5|1<<LCD_D4); //очистить линии данных
LCDDataPORT |= ((byte & 0b11110000) >> (4-LCD_D4)); //вывод старшей тетрады команды
LCDEStrobe (); //строб импульс
LCDDataPORT &= ~(1<<LCD_D7|1<<LCD_D6|1<<LCD_D5|1<<LCD_D4); //очистить линии данных
LCDDataPORT |= ((byte & 0b00001111) << (LCD_D4)); //вывод младшей тетрады команды
LCDEStrobe (); //строб импульс
}
//----------------------------------------------------------------------------------------------
//функция вывода символа на LCD дисплей (в текущую позицию)
//АРГУМЕНТ - код символа
void LCDSendChar (unsigned char byte)
{
LCDControlPORT |= 1<<LCD_RS; //признак загрузки символа
LCDSendCommand (byte); //вывод символа
LCDControlPORT &= ~(1<<LCD_RS);
}
//----------------------------------------------------------------------------------------------
//Функция очистки буфера дисплея в SRAM (32 байта)
void LCDClearBuf (void)
{
for (unsigned char i=0; i<32; i++)
LCDBuffer [i] = 0x20;
} - Сообщения: 37
- Зарегистрирован: Вт мар 06, 2012 19:59:00
Доброго времени суток. У меня периодически пропадает нижняя строка на дисплее WH1602L-TMI-CTW.Причем верхняя работает нормально и на нее выводиться текст, а на нижней просто пустая строчка.Данная ситуация проявляется и на других новых дисплеях.Кто-нибудь сталкивался с такой проблемой?
Также,хотел узнать как защитить дисплей от наводок. Мое усройство через полевик включает ЦЗ(центральный замок) с авто, а он жрет 4А.После срабатывания ЦЗ,иногда на дисплее появляется мусор.
Также,хотел узнать как защитить дисплей от наводок. Мое усройство через полевик включает ЦЗ(центральный замок) с авто, а он жрет 4А.После срабатывания ЦЗ,иногда на дисплее появляется мусор.
На одном изделии, стоящем в "плохих" электромагнитных условиях у меня тоже нижняя строка пропадает(4-битный режим). Лечу автоматической реинициализацией каждую минуту. Хватает т.к. на экран смотрят не чаще чем раз в полгода.Babulesnik писал(а):Кто-нибудь сталкивался с такой проблемой?
Знакомый юзает Winstar-ы в режиме 8-битной шины, говорит никогда глюков не было.
А не пробовали разделить питание силовое и сигнальное? И к тому же всякие там моторчики и катушки нужно шунтировать диодом(между плюсом и минусом потребителя- естественно так, чтобы не было КЗ при включении).
- Сообщения: 37
- Зарегистрирован: Вт мар 06, 2012 19:59:00
Спасибо.Стоит диод шотки ss36. А в каком смысле разделить питание ?vitalik_1984 писал(а):А не пробовали разделить питание силовое и сигнальное? И к тому же всякие там моторчики и катушки нужно шунтировать диодом(между плюсом и минусом потребителя- естественно так, чтобы не было КЗ при включении).


