Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Сорри но опять инициализация LCD
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
John23
Здравствуйте!
Понимаю что до дыр затёртая тема, но всё же прочитав подобные темы не смог применить к своей инициализации. У меня Atmega 128, с ней портом С подсоединён двустрочный LCD основаный на HD44780. Провожу всеми описываемую инициализацию, но результата нет.
Если не сильно надоело отвечать на подобные вопросы подскажите пожалуйста как быть.
Имеется вот такой вот примитивчик инициализации...

Код
void delay_ms(unsigned short ms)
   {
        unsigned short outer1, outer2;
        outer1 = 200;
        while (outer1) {
                outer2 = 1000;
                while (outer2) {
                        while ( ms ) ms--;
                        outer2--;
                }
                outer1--;
        }
   }
//-------------------------------------------------------------------------------------
//инициализация дисплея
//-------------------------------------------------------------------------------------
//VLED - PC0
//RS   - PC1
//R/W  - PC2
//E    - PC3
//DB4..DB7 - PC4..PC7
//N  - line number (2)
//F  - font type (5x8)
//DL - data length (4 bit)
//D  - display
//C  - cursor
//B  - blink

void Write_8Bit(int value, int pause)
{
  PORTC=value;
  sbi(PORTC,3);
  cbi(PORTC,3);
  PORTC=0xF1;/установить DB4-DB7 в HI
  delay_ms(pause);  
}

void Write_4Bit(int hi, int low, int pause)
{
  PORTC=hi;//старший полубайт
  sbi(PORTC,3);
  cbi(PORTC,3);
  PORTC=low;//младший полубайт
  sbi(PORTC,3);
  cbi(PORTC,3);  
  PORTC=0xF1;//установить DB4-DB7 в HI
  delay_ms(pause);  
  }

void disp_init(void)
{
   DDRC=0xFF;// порт С на выход
  PORTC=0x01;// включить питание
  delay_ms(40);  //пауза после включения питания

for(int c=0; c<3; c++) //3 раза устанавливается 8 битный режим
{
  Write_8Bit(0x31, 40);
}

  Write_4Bit(0x21,0x01,40); // переход в 4 битный режим
  Write_4Bit(0x21,0x81,40); //переход в 4 битный режим, повтор
  Write_4Bit(0x01,0x81,40); //выключить дисплей
  Write_4Bit(0x01,0x61,40); //установить направление сдвига курсора
  Write_4Bit(0x01,0xF1,40); //включить индикатор и разрешить курсор, установить его тип
  Write_4Bit(0x01,0x11,40); //очистить индикатор и курсор домой
}

На дисплее ничего не происходит , кроме того что он светится при подаче на него питания. При посылке битов всегда добавляю 1 для того чтобы питание не пропало, потому как оно физически подсоеденено к PC0. Подскажите что у меня не так.
Заранее спасибо.
Сергей Борщ
Цитата(John23 @ Jan 23 2008, 15:43) *
Подскажите что у меня не так.
Во-первых посмотрите листинг. 99%, что тело вашей задержки выкинуто оптимизатором. Объявите параметр ms как volatile или перепишите внутренний цикл так: while ( ms-- ) __no_operation(); (это если иар, если WinAVR - while ( ms-- ) __asm__ __volatile__ ("nop" : : );
во-вторых "переход в 4 битный режим, повтор" - лишнее.
Freeze Anti
Сейчас не помню уже, но функцию Write_8Bit(0x31, 40); придется, наверное, убрать из-под цикла... там после каждого раза - разные задержки... после первого - 4,1мс, после второго - 100мкс, я мог что-то напутать, поэтому вам необходимо свериться с даташитом... там все написано...
Qwertty
Цитата(Freeze Anti @ Jan 23 2008, 20:36) *
Сейчас не помню уже, но функцию Write_8Bit(0x31, 40); придется, наверное, убрать из-под цикла... там после каждого раза - разные задержки... после первого - 4,1мс, после второго - 100мкс, я мог что-то напутать, поэтому вам необходимо свериться с даташитом... там все написано...

Не нужно, это рекомендуемые МИНИМАЛЬНЫЕ задержки, если времени лишнего много, то и так нормально.
Кстати - какая тактовая частота процессора? Если выше 10Мгц, то между
Код
sbi(PORTC,3);
  cbi(PORTC,3);

неплохо было бы добавить задержку, на пару тактов процессора.
Интересное решение - передавать нибблы отдельно. Не подскажете, чем оно вызвано?
Freeze Anti
Что-то я тут не понял... функция void disp_init(void)... вы какие значения передаете?.. окуда вы их взяли?.. непожи они на те, которые в даташите написаны... и еще... "переход в 4 битный режим" и "переход в 4 битный режим повтор" у вас - разные команды... посмотрите повнимательнее, что они делают...

и еще... а зачем создавать функцию delay_ms, если подобная функция есть в библиотеке... в WinAVR, например, в библиотеке utils/delay.h есть функции _delay_ms и _delay_us...
Kirill Frolov
Цитата(John23 @ Jan 23 2008, 16:43) *
применить к своей инициализации. У меня Atmega 128, с ней портом С подсоединён двустрочный LCD основаный на HD44780. Провожу всеми описываемую инициализацию, но результата нет.


Половина подобных проблем решается осциллографом.

Цитата
Имеется вот такой вот примитивчик инициализации...
Код
void delay_ms(unsigned short ms)
   {
        unsigned short outer1, outer2;
        outer1 = 200;
        while (outer1) {
                outer2 = 1000;
                while (outer2) {
                        while ( ms ) ms--;
                        outer2--;
                }
                outer1--;
        }
   }


Такой код НЕ РАБОТАЕТ в реальной жизни. Советую использовать один аппаратный таймер для счёта времени. Тем более если речь про миллисекунды, а не микро или наносекунды. Попутно этот таймер может ШИМ выдавать или чего-нибудь в этом роде.

Но это ещё не всё. Код в котором нужен delay(), опять же, не на микросекунды или наносекунды, а миллисекунды -- В РЕАЛЬНОЙ ЖИЗНИ НЕ РАБОТАЕТ. Просто потому, что из-за вот этой delay() колом встают все другие процессы, которые у вас есть, вроде же очевидно. Нет, я конечно немного лукавлю, и в простых совсем случаях именно такой код и работает, когда у вас кроме дисплея ничего нет, например.

Цитата
//VLED - PC0
//RS - PC1
//R/W - PC2
//E - PC3
//DB4..DB7 - PC4..PC7


Я обычно таким (см. выше) вещам даю символические имена. Иначе код неочевидный получается. Да хоть через #define.

Цитата
Код
void Write_8Bit(int value, int pause)
{
  PORTC=value;
  sbi(PORTC,3);
  cbi(PORTC,3);
  PORTC=0xF1;/установить DB4-DB7 в HI
  delay_ms(pause);  
}


Во-первых здесь не delay_ms() нужен, а delay(~15uS), насколько я помню, хотя могу и ошибаться. Во-вторых, к сожалению (опять же могу ошибаться), у вас только 4-битный интерфейс, а при использовании 8-битного имеется возможность читать бит готовности в 7-м бите и таким образом исключить задержки. Хотя, практически, с ними даже проще -- реализуется автомат который просыпается не чаще чем в 15мкс (или за сколько там команды выполняются, наизусть не помню) и посылает обновления по байтику.

Цитата
Подскажите что у меня не так.


Нечёткий код, весьма вероятно содержащий ошибку. Промоделируйте ситуацию на компьютере -- замените все "PORTC=" записью в файл выводимых битиков с отметкой времени (виртуального, понятно, или реализуйте честные задержки с помощью средств ОС) -- и смотрите в чём не сходится с даташитом.
Qwertty
И еще что заметил - первый переход в 4 битный режим выполняется тогда, когда дисплей еще в 8 битном. Так что первый раз должно быть примерно так:
Код
Write_8Bit(0x21, 40); // первый перевод в 4-х битный режим

А вот повтор уже должен быть в 4-х битном, как у Вас и сделано.
И еще вопрос - компилятор видимо ИАР?
John23
Здравствуйте попытаюсь оправдаться. Пользовался рекомендациями отсюда, потому именно такой порядок инициализации а не другой, вот только задержки не в микро- а в миллиекундах.
Пользуюсь WinAvr, но к сожалению не обнаружил ни util/delay.h(у меня таких библиотек не оказалось) ни других полезных функций для задержки, кроме тех которые описаны в avr/delay.h, то есть я увидил там только _delay_loop2() и _delay_loop1(), мне они показались непонятными и я содрал свою функцию с какого то обсуждения(к стати у меня их уже 3 и у всех разная реализация, даже не знаю кому верить).Поэтому хотел бы узнать где можно взять эти и другие полезные библиотечки.
Частота кварца по идее должна стоять 4, точно не уверен, но по моему там по умолчанию так стоит.
Полубиты решил записать функциями исключительно ради того чтоб меньше текста вылаживать на форум, до этого всё было тупо по порядку написано и без циклов, мне так же показалось это неудобным- вот и переписал немного.

Цитата(Сергей Борщ @ Jan 23 2008, 18:19) *
Во-первых посмотрите листинг. 99%, что тело вашей задержки выкинуто оптимизатором. Объявите параметр ms как volatile или перепишите внутренний цикл так: while ( ms-- ) __no_operation(); (это если иар, если WinAVR - while ( ms-- ) __asm__ __volatile__ ("nop" : : );
во-вторых "переход в 4 битный режим, повтор" - лишнее.

Попробовал поправить цикл:
1)обьявил ms как volatile цыкл работает вечено
2)__asm__ __volatile__ ("nop" : : ); - компилятор почему то не знает
3)поставил asm("nop"); - компилятр не ругался но цыкл опять же работает вечно
4)"переход в 4 битный режим, повтор" - убрал, но скорее всего из за задержек пока это результата не дало
Я так понимаю нужно для начала найти цивилизованную delay_ms и delay_us(), которыми все успешно пользуются, подскажите где можно взять, а то почему то в моём WinAvr их нет.
aesok
Цитата(John23 @ Jan 24 2008, 11:07) *
Я так понимаю нужно для начала найти цивилизованную delay_ms и delay_us(), которыми все успешно пользуются, подскажите где можно взять, а то почему то в моём WinAvr их нет.


Скачайте отсюда последнию версию:
http://sourceforge.net/projects/winavr/

Анатолий.
smk
Цитата
Я так понимаю нужно для начала найти цивилизованную delay_ms и delay_us(), которыми все успешно пользуются, подскажите где можно взять, а то почему то в моём WinAvr их нет.


Подключите файл:
#include <util/delay.h>

и пользуйтесь:
_delay_ms(1000);//задержка 1 с. Чтобы работало, используйте ключик оптимизации (например -О1). Ну и прерывания удлиняют задержку, рекомендуется для точного отсчета прерывания отключить на время задержки.
John23
Цитата(aesok @ Jan 24 2008, 12:16) *
Скачайте отсюда последнию версию:
http://sourceforge.net/projects/winavr/

Скачал новый WinAvr20071221 и опять проблемы начались:
- он не запускается почему то
- раньше я bat файл запускал который компилил проэкт, а затем переоткрывал его в AvrStudio, там видимо с makefile несоответствие
Я видел что люди WinAvr плагином к AvrStudio прикручивают, как мне сделать так же и как переправить makefile. wassat.gif
Qwertty
Цитата(John23 @ Jan 24 2008, 12:14) *
Я видел что люди WinAvr плагином к AvrStudio прикручивают, как мне сделать так же и как переправить makefile. wassat.gif

Скачать свежую студию с сервиспаками, старую снести, новую поставить. Она сама, в процессе установки найдет WinAvr. Makefile в студии можно использовать внешний. Или она сама его сгенерит.
John23
Не стал заморачиваться с неработающим у меня WinAvr 20071221. Поставил назад старый. Перебрал варианты, содрал _delay_ms() из библиотеки - задержка то вроде работает, но всё равно единственное что делает экранчик - так это горит при подаче питания.
Может переписать как то заново?
Надоел уже мне этот экранчик порядком, обидно тратить столько времини для того чтобы привести к жизни этот противный кусочек железа, выполняющий не такую уж важную роль.
Спасибо за участие.
Kirill Frolov
Цитата(John23 @ Jan 24 2008, 11:07) *
Здравствуйте попытаюсь оправдаться. Пользовался рекомендациями отсюда, потому именно такой порядок инициализации а не другой, вот только задержки не в микро- а в миллиекундах.


Для этого существуют ДАТАШИТЫ. А не сайты с сомнительным и не всегда коррректным содержанием.

Цитата
1)обьявил ms как volatile цыкл работает вечено


Не вечно, а достаточно долго.

Цитата
2)__asm__ __volatile__ ("nop" : : ); - компилятор почему то не знает


Я тоже...

Цитата
3)поставил asm("nop"); - компилятр не ругался но цыкл опять же работает вечно


Потому, что и как в случае с volatile цикл перестаёт выкидываться оптимизатором компилятора и начинает-таки исполняться. Просто у вас время задано неверно.

Цитата
Я так понимаю нужно для начала найти цивилизованную delay_ms и delay_us(), которыми все успешно пользуются, подскажите где можно взять, а то почему то в моём WinAvr их нет.


Ещё раз -- в реальных программах delay() не бывает.
Freeze Anti
Да не... на инициализацию дисплея можно и delay поставить... все равно полностью устройство еще не работает и можно немного погонять процессор вхолостую...

еще... советую использовать в пересылке
верхнего полубайта

PORTC = (value >> 4);

нижнего полубайта

PORTC = (value & 0x0F);

если у вас на этом порту еще что-то висит (например, часто вешают на порт старшими регистрами биты состояния дисплея), то к каждой из строчек стоит добавить

| (PORTC & 0xF0);

ИМХО, так понятней, что вы хотите сделать...

а вообще посмотрите примеры к WinAVR... может найдете что-то интересное для себя... в частности, там есть примеры работы с дисплеем...
John23
Спасибо, поэксперементирую ещё. Надо же его всё таки включать когда то.
hd44780
Возьми LCD модуль из avrLib, попробуй.
У меня 3 разных дисплея (два 2x16, один 4x20), на всех работало без проблем.
Я даже алгоритм портировал на cvAVR, работает.
smk
Цитата
Не стал заморачиваться с неработающим у меня WinAvr 20071221. Поставил назад старый.

WinAVR2007 работает с AVR Studio 4.13, а WinAVR2006 работает с AVR Studio 4.12. Павильней было бы поставить свежую студию с сервиспаками.

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

Попробуйте эти библиотеки. Нажмите для просмотра прикрепленного файла

Цитата
Возьми LCD модуль из avrLib, попробуй.

Код громоздкий. при попытке разрешить прерывания глобально у меня прога виснет. там только lcdProgressBar() мне нравится и lcdPrintData().
John23
Доброго времени суток!
Цитата
Попробуйте эти библиотеки. lsd.rar

Стянул библиотечку, действительно понятное описание и читабельный код, спасибо за ссылочку)).
Содрал код инициализации и добавил лишь VLED ножку на которую даётся питание, проверил пошагово - всё работае так как написано, а продвижения все равно нет, он всего лиш загорается при подаче питания.
Если не трудно читать, то вот что есть на инициализации:
Код
//-------------------------------------------------------------------------------------
//инициализация дисплея
//-------------------------------------------------------------------------------------
#define F_CPU 1000000UL  // 1 MHz
//----------
#define VLED 0          //power
#define LCD_RS    1     //define MCU pin connected to LCD RS
#define LCD_RW    2     //define MCU pin connected to LCD R/W
#define LCD_E    3    //define MCU pin connected to LCD E
#define LCD_D4    4    //define MCU pin connected to LCD D3
#define LCD_D5    5    //define MCU pin connected to LCD D4
#define LCD_D6    6    //define MCU pin connected to LCD D5
#define LCD_D7    7    //define MCU pin connected to LCD D6
#define LDP PORTC    //define MCU port connected to LCD data pins
#define LCP PORTC    //define MCU port connected to LCD control pins
#define LDDR DDRC    //define MCU direction register for port connected to LCD data pins
#define LCDR DDRC    //define MCU direction register for port connected to LCD control pins
//VLED - PC0
//RS   - PC1
//R/W  - PC2
//E    - PC3
//DB4..DB7 - PC4..PC7

void _delay_ms(double __ms)
{
    uint16_t __ticks;
    double __tmp = ((F_CPU) / 4e3) * __ms;
    if (__tmp < 1.0)
        __ticks = 1;
    else if (__tmp > 65535)
    {
        //    __ticks = requested delay in 1/10 ms
        __ticks = (uint16_t) (__ms * 10.0);
        while(__ticks)
        {
            // wait 1/10 ms
            _delay_loop_2(((F_CPU) / 4e3) / 10);
            __ticks --;
        }
        return;
    }
    else
        __ticks = (uint16_t)__tmp;
    _delay_loop_2(__ticks);
  
}

void LCDsendCommand(uint8_t cmd)    //Sends Command to LCD
{
    LDP=(cmd&0b11110000)|1<<VLED;
    LCP|=1<<LCD_E;        
    _delay_ms(1);
    LCP&=~(1<<LCD_E);
    _delay_ms(1);
    LDP=((cmd&0b00001111)<<4)|(1<<VLED);    
    LCP|=1<<LCD_E;        
    _delay_ms(1);
    LCP&=~(1<<LCD_E);
    _delay_ms(1);
}
void LCDinit(void)//Initializes LCD
{
    LDP=1<<VLED;
    LCP=1<<VLED;
        _delay_ms(15);
    //LDP=0x00;
    //LCP=0x00;
    LDDR|=1<<LCD_D7|1<<LCD_D6|1<<LCD_D5|1<<LCD_D4;
    LCDR|=1<<LCD_E|1<<LCD_RW|1<<LCD_RS;
   //---------one------
    LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4|1<<VLED; //4 bit mode
    LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;        
    _delay_ms(1);
    LCP&=~(1<<LCD_E);
    _delay_ms(1);
    //-----------two-----------
    LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4|1<<VLED; //4 bit mode
    LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;        
    _delay_ms(1);
    LCP&=~(1<<LCD_E);
    _delay_ms(1);
    //-------three-------------
    LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|0<<LCD_D4|1<<VLED; //4 bit mode
    LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;        
    _delay_ms(1);
    LCP&=~(1<<LCD_E);
    _delay_ms(1);
    //--------4 bit--dual line---------------
    LCDsendCommand(0b00101000);
   //-----increment address, cursor shift------
    LCDsendCommand(0b00001110);
}

Я просто вызываю LCDinit() из main(). Может на момент инициализации нужно запретить глобально прерывания может это мешает тоже?
John23
Уважаемые знатоки, благодарю за помощь, проблема решена благодаря моему сообразительному другу.
Проблема оказалась не в порядке посылки команд и выставления задержек а в коварном подстроичном резисторе регулирующем контрастность. На самом деле значок курсора выводился уже около двух недель , только благодаря резистору я его не видел.
Совет начинающим - если вдруг инициализация не проходит НЕ исключайте этой ошибки и обязательно проверяйте етот самый резистор.
Всем спасибо, тема закрыта.
Pyku_He_oTTyda
Даже когда индикатор не инициализирован, его половина "закрашивается черным" при регулировке контрастности
John23
Здравствуйте.
Цитата
Даже когда индикатор не инициализирован, его половина "закрашивается черным" при регулировке контрастности

Да уж теперь то я понимаю как много времени зря потерял из за незнания. Но поймите, плата с атмегой и дисплейчиком мне досталась в наследство и поэтому ничего о том как всё устроено и что должно быть отрегулировано не знал.
Я начал подозревать что подсветка и питание мк - реализованы отдельно, так как на форуме читал что должны подсветится знакоместа, оказалось не так, мне помогли в принципиальных схемах разобраться и нашли этот резистор, после этого притензии только к разработчику схемы(ну и к себе - за то что раньше не догадался).
Pyku_He_oTTyda
я не дока в индикаторах, но когда первый раз подключил, первым делом покрутил подстроечникsmile.gif
John23
Да уж, я даже не догадывался что для маленького дисплейчика тоже реализовали подстройку контрастности. Просто не подумал, я за собой заметил что зачастую ищу ошибку в чём то сложном, вместо того чтоб проверить самое банальное. Как говорится- посыпаю голову пеплом, но рад что могу двигаться дальше, а точнее пока ползти smile.gif. Впереди куча всего что прийдётся делать впервые.
j_serg
Уважаемый John23. За AVR и С я взялся буквально месяц назад. Наберусь смелости и дам совет. Мой совет будет в общем, о хорошо забытой рекомендации. В кратце расскажу о своих мытарствах. LCD взял МТ-10-Т7 -- единственное, что было в нашем захолустье. Попутно скачал с какого-то форума рекомендации бедолаги, который смог запустить эту стекляшку только с помощью группы поддержки самой фирмы(фирма МЭЛТ). Хорошо, что запросы не надо было сочинять на английском. Ушло у него на это около 10 дней, если я правильно помню. Естественно я пошел по пути его рекомендаций и потерял несколько дней. Потом плюнул и скачал ДШ. с сайта фирмы и за пару часов получил рабочий код. Ваш LCD очень популярный и информации на него много. И вот выводы из приобретенного опыта.
Язык Си слишком вольный, особенно для начинающего. Не используйте отточенные конструкции опытных Си-шников, т.к. есть вероятность сразу не въехать в алгоритм и долго няньчиться с проблемой. Пишите может быть и не оптимально, но как можно проще для своего понимания и у вас все заработает. В будущем это мнение возможно и поменяется. У меня уже тоже появились затыки и я уже позвонил на форум.
John23
Спасибо за совет smile.gif , всегда рад здравым мыслям. Копаться в ДШ сразу желания не было, поэтому сначала поискал в инете как это делают другие ( к стати тоже натыкался на вышеупомянутого бедолагу smile.gif ), после того как их советы не помогли покопался в ДШ, к моему недоумению это тоже было безрезультатно. Спасением стал этот форум, уважаемые участники которого мне всячески старались помочь. Но жалко что проблемма была такой глупой и неожиданной - просто контраст на нуле.
А касательно языка С, для меня он удобнее потому что пишу на нём не первый год (с асмом ,как ни стыдно признаться, разбираться лень, хотя в институте заставляли). До недавнего времени писал приложения под винду и волей случая сейчас приходится вникать в другую область программирования, поэтому сейчас тяжковато.
j_serg
Цитата(John23 @ Jan 31 2008, 14:41) *
Спасибо за совет smile.gif , всегда рад здравым мыслям. Копаться в ДШ сразу желания не было, поэтому сначала поискал в инете как это делают другие ( к стати тоже натыкался на вышеупомянутого бедолагу smile.gif ), после того как их советы не помогли покопался в ДШ, к моему недоумению это тоже было безрезультатно. Спасением стал этот форум, уважаемые участники которого мне всячески старались помочь. Но жалко что проблемма была такой глупой и неожиданной - просто контраст на нуле.
А касательно языка С, для меня он удобнее потому что пишу на нём не первый год (с асмом ,как ни стыдно признаться, разбираться лень, хотя в институте заставляли). До недавнего времени писал приложения под винду и волей случая сейчас приходится вникать в другую область программирования, поэтому сейчас тяжковато.


Вам проще. Я в институте учил Паскаль, да и программистом никогда не работал. К томуже был перерыв в 16 лет, а вот теперь снова пришлось взяться и взяться с ходу за С. Тяжеловато по началу мыслить на С.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.