реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Помогите разобраться с символьным ЖКИ, HD44780
Pavel V.
сообщение Feb 20 2007, 10:49
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 211
Регистрация: 3-06-06
Пользователь №: 17 742



Уже второй день пытаюсь оживить символьный ЖКИ под IAR. До этого момента использовал CodeVision и встроенную в него библиотеку, которая всегда работала как часы.

С IAR пришлось разбираться второпях, до этого с ним дела не имел.

Нашел кучу исходников библиотек для работы с HD44780, но толком ни одна так и не заработала. Пришлось разбираться самому, в результате чего была создана некая компиляция из кусков разных библиотек.

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

С железом это никак не может быть связано - с CodeVision все работало хорошо.

Много игрался с задержками, думал из-за них, но они как будто не влияют на этот глюк.

К сообщению прицепляю код, помогите, пожалуйста, разобраться! Или, быть может, у кого-то есть готовая библиотека для работы с этими ЖКИ?

Контроллер - ATmega48, частота 1 МГц.

Сообщение отредактировал Pavel V. - Feb 20 2007, 10:52
Прикрепленные файлы
Прикрепленный файл  main.txt ( 303 байт ) Кол-во скачиваний: 105
Прикрепленный файл  lcd.txt ( 4.59 килобайт ) Кол-во скачиваний: 162
 


--------------------
Good News Everyone!
Go to the top of the page
 
+Quote Post
prottoss
сообщение Feb 20 2007, 11:18
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Цитата(Pavel V. @ Feb 20 2007, 14:49) *
Уже второй день пытаюсь оживить символьный ЖКИ под IAR. До этого момента использовал CodeVision и встроенную в него библиотеку, которая всегда работала как часы.

С IAR пришлось разбираться второпях, до этого с ним дела не имел.

Нашел кучу исходников библиотек для работы с HD44780, но толком ни одна так и не заработала. Пришлось разбираться самому, в результате чего была создана некая компиляция из кусков разных библиотек.

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

С железом это никак не может быть связано - с CodeVision все работало хорошо.

Много игрался с задержками, думал из-за них, но они как будто не влияют на этот глюк.

К сообщению прицепляю код, помогите, пожалуйста, разобраться! Или, быть может, у кого-то есть готовая библиотека для работы с этими ЖКИ?

Контроллер - ATmega48, частота 1 МГц.
Не разбирался с тонкостями кода, но все пестрит программными задержками. ИМХО лучше анализировать флаг готовности ЖКИ

Вот здесь http://electronix.ru/forum/index.php?showtopic=10934 есть исходники для данного ЖКИ. Есть и мое творение. smile.gif


--------------------
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Feb 20 2007, 11:35
Сообщение #3


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(Pavel V. @ Feb 20 2007, 09:49) *
К сообщению прицепляю код, помогите, пожалуйста, разобраться! Или, быть может, у кого-то есть готовая библиотека для работы с этими ЖКИ?
На первый взгляд больших "плюх" не видно, кроме задержек в инициализации - обратите на них пристальное внимание. Но есть недочеты:
Код
void LcdWriteNibble (unsigned char a)
{
E=0;   // эта команда не нужна - после выполнения любой команды у вас E возвращается в 0.
delay_us(2);  // не нужно
LCDPORT&=0x0f;
LCDPORT|=(a&0xf0);
delay_us(2); // не нужно
E=1;
delay_us(2); // не нужно
E=0;
delay_us(2); // не нужно.
}              

void WaitBusy (void)
{
delay_us(300);   // достаточно 40 мкс.
}  

void LcdWriteCommand (unsigned char a)
{
E=0;    // эта команда не нужна - см. LcdWriteNibble(), в LcdWriteData то же самое.
RS=0;    
LcdWriteNibble(a);
LcdWriteNibble(a<<4);
WaitBusy();
}

void LcdInit (unsigned char a)
{
   LCDDDR = 0xFF; //3F
   LCDPORT = 0x00;  
   E=0;             // это не нужно - вы его сбросили предыдущей командой.
   RS=0;           // аналогично
  delay_ms(20);  // здесь надо примерно 200 мс
  LcdWriteNibble(0x30);
  delay_ms(7);    // здесь надо 50 мс минимум
  LcdWriteNibble(0x30);
  delay_us(200); // здесь надо 50 мс минимум
  LcdWriteNibble(0x30);  
  WaitBusy();     // здесь уже можно 200 мкс
  LcdWriteNibble(0x20); // это лишнее - см. следующую команду
  WaitBusy();                  
  if (a==1) LcdWriteCommand(0x20);
  else LcdWriteCommand(0x28);
  LcdWriteCommand(0x08);
  LcdWriteCommand(0x01);
  delay_ms(30); // предыдущая команда исполняется 1.6мс максимум
  LcdWriteCommand(0x06);
  LcdWriteCommand(0x0c);
  delay_ms(30); // предыдущая команда исполняется 40 мкс, дополнительная задержка не нужна.
}

И подумайте - надо ли вам передавать параметр в эту функцию? Вы по ходу выполнения программы будете его менять? Если нет, напишите две функции инициализации и вызывайте нужную в конкретном проекте - зачем вам лишний код в рабочей программе?

В общем видно, что вы надергали код из разных библиотек не разбираясь. Посмотрите, у вас void tlcd_write_byte() делает то же самое, что и LcdWriteCommand(), LcdWriteData().


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Pavel V.
сообщение Feb 20 2007, 20:11
Сообщение #4


Местный
***

Группа: Свой
Сообщений: 211
Регистрация: 3-06-06
Пользователь №: 17 742



Что-то никак не получается ничего..

prottoss, я и Ваш код пробовал, не работает почему-то. У меня вопрос - при подключении по 4-битной шине, куда именно должны на шину подключаться пины DB4,5,6,7?

У меня в железе вот какой расклад:

PORTD.0 - RS
PORTD.1 - R/W
PORTD.2 - E
PORTD.3
PORTD.4 - DB4
PORTD.5 - DB5
PORTD.6 - DB6
PORTD.7 - DB7

Не подскажете, как должны при этом выглядеть настройки?

У меня сейчас вот так:

// Шина данных
#define LCD_PORTDATA PORTD
#define LCD_PINDATA PIND
#define LCD_DDRDATA DDRD

// Порт управления
#define LCD_PORTCTRL PORTD
#define LCD_PINCCTRL PIND
#define LCD_DDRCTRL DDRD

// Линии управления LCD
#define LCD_wire_RS (1 << PD0)
#define LCD_wire_RW (1 << PD1)
#define LCD_wire_E (1 << PD2)
#define LCD_wire_BL (1 << PD3) // (BackLight)

Правильно? Или в программе подразумевается, что шина данных должна находиться на порту, отличном от порта с линиями управления?

UPDATE
Ура! Заработало! Подправил свой исходный текcт в соответствии с рекомендациями Сергея Борщ. Теперь все стабильно smile.gif Видимо, все-таки с задержками у меня какая-то фигня была. Приведу текст к более красивому виду и выложу, мало ли кому пригодится!

Теперь на повестке дня чтение данных из АЦП по SPI.

Сообщение отредактировал Pavel V. - Feb 20 2007, 20:33


--------------------
Good News Everyone!
Go to the top of the page
 
+Quote Post
Николай Z
сообщение Aug 21 2007, 09:40
Сообщение #5


Местный
***

Группа: Участник*
Сообщений: 418
Регистрация: 20-08-07
Пользователь №: 29 930



Цитата(Pavel V. @ Feb 21 2007, 00:11) *
....
Приведу текст к более красивому виду и выложу, мало ли кому пригодится!
...
Теперь на повестке дня чтение данных из АЦП по SPI.


Не не стоит выкладывать... sad.gif
Везде полно реально работающих примеров для любой конкретной эволюшн борд...
Go to the top of the page
 
+Quote Post
zltigo
сообщение Aug 21 2007, 12:17
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(Николай Z @ Aug 21 2007, 12:40) *
Везде полно реально работающих примеров для любой конкретной эволюшн борд...

Moderator:
Не стоит поднимать старые темы без всякой на то нужды и давать бесполезные советы.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
vashurin
сообщение Apr 9 2008, 10:57
Сообщение #7





Группа: Новичок
Сообщений: 9
Регистрация: 8-04-08
Пользователь №: 36 568



Привет всем.

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

я сталкнулся с той-же проблемой что и автор форума.
раньше писал на CVAR и там все было без проблем.

интересно автор решил эту проблему ???
Go to the top of the page
 
+Quote Post
artemm
сообщение Jun 4 2008, 07:39
Сообщение #8


Частый гость
**

Группа: Свой
Сообщений: 80
Регистрация: 23-07-07
Из: Украина, г. Сумы
Пользователь №: 29 306



не помню где содрал, но у меня работает в иаре
Файл LCD.h
------------------------------------------------------------------------------------------------------------------------------
#include "delay.h"

// LCD pins
#define DB7 0x80
#define DB6 0x40
#define DB5 0x20
#define DB4 0x10
#define ENABLE 0x04
#define RS1 0x01

// Port
#define LCDDDR DDRA
#define LCDPORT PORTA
#define LCDPIN PINA
// General defines
#define DATA 0x01
#define CTRL 0x00

//#define LCDPORT PORTD //для AVR PORTB4 .. PORTB7-ШД
#define E PORTA_Bit2 //вывод ОМЭВМ для подкл. E
#define RS PORTA_Bit0 //---||--- RS

//#define LCDDDR DDRD
//#define LCDPIN PIND



//**************************************************
//запись старшей тетрады числа

void LcdWriteNibble (unsigned char a)
{
//E=0;
delay_us(30);
LCDPORT&=0x0f;
LCDPORT|=(a&0xf0);
delay_us(50);
E=1;
delay_us(50);
E=0;
//delay_us(2);
}
//**************************************************
//ожидание сброса флага ожидания
void WaitBusy (void)
{
delay_us(70);
}
//**************************************************
//запись команды
void LcdWriteCommand (unsigned char a)
{
E=0;
RS=0;
LcdWriteNibble(a);
LcdWriteNibble(a<<4);
WaitBusy();
}
//**************************************************
// инициализация модуля HD44780
//a=1 - однострочный дисплей
//a!=1 - двустрочный
//курсор выключен,автоинкремент адреса,нет сдвига
//экрана
void LcdInit (unsigned char a)
{
DDRA = (1<<DDA2);
PORTA_Bit2 = 0;
delay_ms(50);
LCDDDR = 0xFF; //3F
LCDPORT = 0x00;
E=0;
RS=0;
delay_ms(100);
delay_ms(100);
delay_ms(100);
delay_ms(100);
LcdWriteNibble(0x30);
delay_ms(100);
delay_ms(100);
delay_ms(100);
LcdWriteNibble(0x30);
delay_ms(100);
delay_ms(100);
delay_ms(100);
LcdWriteNibble(0x30);
WaitBusy();
delay_us(100);
delay_us(100);
delay_us(100);
LcdWriteNibble(0x20);
WaitBusy();
if (a==1) LcdWriteCommand(0x20);
else LcdWriteCommand(0x28);
LcdWriteCommand(0x08);
LcdWriteCommand(0x01);
delay_ms(2);
LcdWriteCommand(0x06);
LcdWriteCommand(0x0c);
//delay_ms(30);
}

//**************************************************
//запись символа

void LcdWriteData (unsigned char a)
{
E=0;
RS=1;
delay_us(20);
LcdWriteNibble(a);
LcdWriteNibble(a<<4);
WaitBusy();
}

/***********************************************************************
Write a control or data byte to the display. Control: 1=Ctrl, 0=Data
If data (control=0) set position with lcd_goto first.
Since the LCD is driven in 4-bit modus, we write the MSB nibble first
and the the LSB nibble.
***********************************************************************/
void tlcd_write_byte(unsigned char control, unsigned char byte)
{
if ((byte & 0x80) == 0x80) LCDPORT |= DB7; else LCDPORT &= ~DB7;
if ((byte & 0x40) == 0x40) LCDPORT |= DB6; else LCDPORT &= ~DB6;
if ((byte & 0x20) == 0x20) LCDPORT |= DB5; else LCDPORT &= ~DB5;
if ((byte & 0x10) == 0x10) LCDPORT |= DB4; else LCDPORT &= ~DB4;
if (control == 1) LCDPORT |= RS1; else LCDPORT &= ~RS1;
LCDPORT |= ENABLE;
LCDPORT &= ~ENABLE;
if ((byte & 0x08) == 0x08) LCDPORT |= DB7; else LCDPORT &= ~DB7;
if ((byte & 0x04) == 0x04) LCDPORT |= DB6; else LCDPORT &= ~DB6;
if ((byte & 0x02) == 0x02) LCDPORT |= DB5; else LCDPORT &= ~DB5;
if ((byte & 0x01) == 0x01) LCDPORT |= DB4; else LCDPORT &= ~DB4;
if (control == 1) LCDPORT |= RS1; else LCDPORT &= ~RS1;
LCDPORT |= ENABLE;
LCDPORT &= ~ENABLE;
WaitBusy();
}
/***********************************************************************
Write strings to the display. Set position with tlcd_goto first.
Text will wrap if to long to show on one line.
***********************************************************************/
void tlcd_write_string(char *ptr)
{
while (*ptr != 0x00) tlcd_write_byte(DATA,*ptr++);
}

/***********************************************************************
Goto specified column and line. 1,1 is the upper left corner.
***********************************************************************/
void tlcd_goto(unsigned char column, unsigned char line)
{
unsigned char addr;
line--;
column--;
addr = (line * 64) + column;
tlcd_write_byte(CTRL, addr | 0x80);
}

//**************************************************
//установка курсора в позицию adr


void LcdSetPosition(unsigned char adr)
{
LcdWriteCommand(adr|0x80);
}

//**************************************************
//очистка экрана
void LcdClrScr()
{
LcdWriteCommand(0x01);
delay_ms(60);
}

//------------------------------------------------------------------------------
void LcdSetCGAdress(unsigned char adr)
{
LcdWriteCommand((adr&0x7f)|0x40);
}
//------------------------------------------------------------------------------


------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------



Файл delay.h

------------------------------------------------------------------------------------------------------------------------------

#include <intrinsics.h> //функции циклов

#define f_cpu (16000000) //Частота задающего генератора(ГЦ)




#define delay_us(temp) (__delay_cycles((temp * f_cpu) / 1000000));
/* макрос задержки на "temp" микросекунд. точная задержка при целом значении
задающей частоты генератора в МГц (1, 2, 3, 4, ..., 10, 11, ...) */// 571 + 2, 387 + 2

#define delay_ms(temp) (__delay_cycles((temp * f_cpu) / 1000));
/* макрос задержки на "temp" миллисекунд. точная задержка при целом значении
задающей частоты генератора в кГц (1, 2, 3, 4, ..., 10, 11, ...) */

#define delay_s(temp) (__delay_cycles(temp * f_cpu));
/* макрос задержки на "temp" секунд. точная задержка при целом значении
задающей частоты генератора в Гц (1, 2, 3, 4, ..., 10, 11, ...) */
------------------------------------------------------------------------------------------------------------------------------
Go to the top of the page
 
+Quote Post
alux
сообщение Jun 11 2008, 16:24
Сообщение #9


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Нашел классный исходник! Классный - от слова класс. wink.gif
Правда, написан на C++ под GCC. Но при желании, можна подправить под IAR. Сам не пробовал, пока не было необходимости. Но обязательно использую этот исходник в следующем проекте.
Прикрепленные файлы
Прикрепленный файл  LCD_HD44780_C___library.zip ( 19.36 килобайт ) Кол-во скачиваний: 59
 
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 11 2008, 22:35
Сообщение #10


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(alux @ Jun 11 2008, 19:24) *
Но обязательно использую этот исходник в следующем проекте.
Согласно комментариям в шапках каждого файла этот исходник распространяется под лицензией GPL. Вы готовы раскрыть исходные коды своего следующего проекта?

Кода немного, имеет смысл посмотреть как написан этот исходник (для осваивающих плюсы образец неплохой) и написать самому. По коду (смотрел бегло):
- вместо передачи в LCD::send() признака команда/данные как параметра лучше написать две функции. Причем одна из них может сбрасывать RS и вызывать вторую, а вторая в конце выставлять RS. Таким образом после любой операции с дисплеем RS в единице и при вызове второй функции его принудительно выставлять не нужно. Хороший компилятор может сгенерить из этих двух функций одну с двумя точками входа.
- при загрузке знакосинтезатора нет смысла передавать 8 байтов параметрами, эффективнее передать указатель на массив. Финт: поскольку 3 старших бита не выводятся, можно в старший из них записать единичку, девятым байтом в массив дописать ноль и таким образом превратить массив в С-строку. Потом можно заметить, что загружать можно все символы сразу одной командой (чаще всего требуется один раз при старте загрузить нужное количество символов и в процессе работы они не перегружаются). Потом становится видно, что после посылки команды установки адреса CGRAM дальнейшая загрузка очень похожа на вывод строки. Таким образом вся загрузка вырождается в посылку команды установки CGRAM и вызов функции вывода строки.
- функции, которые вызываются только один раз (конструктор, например) можно сделать встроенными.
- константы, заданные через #define (команды дисплея) можно перенести внутрь класса как static const члены или enum (что логичнее).

В общем критиковать всегда легко smile.gif


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
z80ru
сообщение Jun 26 2008, 15:03
Сообщение #11





Группа: Новичок
Сообщений: 1
Регистрация: 26-06-08
Пользователь №: 38 572



Может и мне советом поможите, по замене МТ-10Т7 на HD44780 ? В приёмнике Р45 http://www.p-45.narod.ru/version2.html иходник на С http://www.p-45.narod.ru/files/rcv45v2-mt10t7-v02.c WinAvr. Беда в том,что там на 2-ух портах висит и ЖК и клава. Да ещё через hc595. Сам пробывал... или лишние ноги инициализируются сами wacko.gif или на ЖК бред полный с анимацией. smile3046.gif
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 12:27
Рейтинг@Mail.ru


Страница сгенерированна за 0.01521 секунд с 7
ELECTRONIX ©2004-2016