Дисплеи, датчики и прочие функциональные узлы, управляемые МК.
Ответить

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Вт янв 17, 2017 22:58:49

1 Это надо делать однократно, в вашем случае, по крайней мере.
ROMan2947 писал(а):2.Первую часть вопроса не понял
Зачем дергаете ногой "Е" в функции busy_flag()? И полная рекурсия там не нужна, достаточно проверять PIN7, до выхода из условия. Как, например, у Мурато Мяуконни сделано.

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 01:11:04

while(CheckBSY){} // ожидание освобождения
E = 1; // E _/-
PORT = (byte>>4) & 0x0F // на выход старший полубайт
E = 0; // E -\_

while(CheckBSY){} // ожидание освобождения (насколько помню, нужно тут ждать?)
E = 1; // E _/-
PORT = byte & 0x0F // на выход младший полубайт
E = 0; // E -\_

что нужно проверять BF каждого полубайта? :shock: в даташите вроде как на стр. 33 на диаграмме показано,что после всего байта слушаем BF

Добавлено after 15 minutes 26 seconds:
MOHCTEP писал(а):1 Это надо делать однократно, в вашем случае, по крайней мере.
ROMan2947 писал(а):2.Первую часть вопроса не понял
Зачем дергаете ногой "Е" в функции busy_flag()? И полная рекурсия там не нужна, достаточно проверять PIN7, до выхода из условия. Как, например, у Мурато Мяуконни сделано.


1. Все же не пойму, как я буду cчитывать PIND при чтении,если я однократно выставлю его на выход?
2. Так как проверку бита занятости я считаю как операция чтение,то и в соответствии с диаграммой выполняю порядок...
Да у Мурато Мяуконни сделано грамотно, но я не хочу заниматься копированием,а хочу найти и исправить ошибки в том, что я написал. иначе эти ошибки будут повторятся каждый раз. мне нужно четко знать можно так писать или нельзя.а if я использовал вместо while из-за того, что до последнего был уверен, что каждый раз для чтения BF нужно дрыгать E, вот получилась полная рекурсия

Добавлено after 1 hour 43 minutes 38 seconds:
Мурато Мяуконни писал(а):
Код:

if (PORT & P7)


это тоже абстрактность или вполне серьезный маневр? если маневр то прошу распинать его :write:

Код:

if (PORT & P7)
    return 1;       
     else return 0;



мне кажется здесь ретурны надо поменять нет?
Вложения
ййй.pdf
(120.06 KiB) Скачиваний: 240

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 06:54:06

ROMan2947 писал(а):С целью прослушки PIN7 до тех пор пока условие станет ложью.
надеюсь, вы понимаете, что рекурсия - это расход стека, который в AVR принципиально невозможно контролировать?
"пока условие станет ложью" - это в переводе на Си оператор while(!(условие));, рекурсия тут не нужна.

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 07:01:40

что нужно проверять BF каждого полубайта

Я уже не помню, давно 1602 не использовал. Но кажется там была какая-то фишка с интервалом в полубайтах. Или я уже че путаю. Кароч, если найду у себя в загашнике дисплейчик, или если найду свои старые проекты - проверю.

как я буду cчитывать PIND при чтении,если я однократно выставлю его на выход?

В том то и дело, что нужно ВСЮ задействованую шину данных перевести на ВХОД, все 4 бита подготовить к приему. И после не забыть перевести порт на выход. А как иначе, иначе то не получится, получим, что и дисплей по всем 4 проводам работает на выход, и контроллер эти же 4 провода держит на выход.

Код:
(PORT & P7)  это тоже абстрактность или вполне серьезный маневр? если маневр то прошу распинать его

это абстрактность, хотя она и работает, если определить соответствующе текстовые замены и добавить переключение порта на вход и обратно. Означает получение лог.1 по входу от пина, на котором BF приходит.
Вот она у вас тут и записана в вашем коде: if(PIND&(1<<7)) .

мне кажется здесь ретурны надо поменять нет?

Нет. Суть в том, что если по входу получили BF=1, то и return 1, для того, чтобы "пока функция проверки BF возвращает 1, выполнять пустой цикл ожидания". Кстати, при включении оптимизации этот пустой цикл while (CheckBSY) {} будет выкинут. Но и чтобы не зависнуть, если дисплей по каким-то причинам долго не отвечает, в этот цикл полезно вставить "предохранительный клапан" типа инкремента переменной с проверкой достижения некоторого порогового значения.
например:
Код:
while (CheckBSY)
{
    if (++i > 500) return 1; 
}

, а саму функцию записать как int Send_Byte(char byte) и в этой функции в ее начале определить и инициализовать переменную i
volatile int i = 0;
Таким образом после 500 неудачных попыток дождаться освобождения дисплея произойдёт выход из функции отправки байта с возвратом значения ошибки 1. Это возвращаемое значение можно использовать в вызывающей функции для контроля зависаний подключенных к контроллеру устройств. Но можно и игнорировать возвращаемое значение. Зато есть гарантия, что при любом уровне оптимизации у вас не будет выкинут пустой цикл ожидания.

.а if я использовал вместо while из-за того, что

if от while отличается тем, что if - это однократно проверяемое условие - "если истина, то выполнить, а если нет, то пропустить и идти дальше без вопросов". Напомню, что в Си "истиной" считается любое ненулевое значение, в том числе и отрицательное, а "ложью" - ноль.
while - это цикл с условием проверки - "повторять цикл до тех пор, пока проверка дает истину, как только проверка выдаст ложь, прекратить цикл и идти дальше". В while проверка условия в круглых скобках () идет постоянно с каждым новым кругом цикла в фигурных скобках {}. Условие while - в круглых скобках вызов функции считывания бита BF. Фактически, каждый раз будет считываться BF.
И я тоже уже не помню, но по-моему, там чтобы получить актуальное значение бита BF с дисплея, нужно было постоянно дергать ногой E. Могу ошибаться конечно, не помню, если честно.

, но я не хочу заниматься копированием, а хочу найти и исправить ошибки в том,

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

LCD_PORT &= 0x00; // очищаем шину данных
LCD_PORT |= DATA; // бaйт данных

- а разве нельзя записать одним шагом напрямую: LCD_PORT = DATA; мм? операции &= и |= означают сначала чтение текущего значения выходного регистра порта, затем проводят логическую операцию AND или OR с прочитанным и записываемым значениями. Так не правильнее ли вместо этого напрямую записать в выходной регистр порта сразу же нужное значение? Я думаю, очень даже правильно. Надеюсь, с этим никто из любителей спорить не будет спорить.
Другое дело, если на этом же 8-битном порту физически расположены как шина данных дисплея, так и управляющие сигналы E, RS, RW. Тут другое дело. Но тогда надо фильтровать по маске эти сигналы, чтобы не воздействовать на них.

RUN_PORT |= E; // взводим строб
_delay_us(40);
RUN_PORT &= ~E; // команда на запись
_delay_us(40);

тут ждать по 40 мкс не нужно. по даташиту, как сейчас помню, минимальная длительность сигнала E равна 0,5 мкс. Поэтому, тут хватит буквально несколько микросекунд, если с запасом на все случаи жизни.

Кстати, на первых порах совсем не нужно пытаться создать универсальный код сразу на все-все случаи. Вопервых, запаритесь сами, потому что еще не предполагаете какие могут быть случаи. Вовторых, по мере применения этих случаев вы будете находить более интересные варианты ранее написанного. Втретьих, будете тренировать навыки. Это полезнее, чем один раз написать и забыть.

ARV писал(а):"пока условие станет ложью" - это в переводе на Си оператор while(!(условие));,.

Всё верно, только наоборот :)) В переводи ИЗ Си эта запись означает "пока условие не истинно, повторять записанное в {}".
"станет ложью" и "не истина" - диаметрально разное по действию.
while(!(условие))
{
}

будет выполнять тело {} до тех пор, пока (условие) "не истина", то есть пока условие "ложь".

В противовес,
while(условие)
{
}

будет выполнять тело {} до тех пор, пока (условие) "истина", то есть, пока не станет "ложью".
Заметна разница? В построении программ крайне важна точность и логичность формулировок. "Пока станет ложью" - тоже не точно. "Пока НЕ станет ложью" - правильнее. Или "пока есть ложь". От этого зависит конечный смысл и его выражение в языке, которое меняется диаметрально всего лишь из-за неточной формулировки.

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 11:08:32

ROMan2947 (1) Точно. Прошу извинения. В свое время пытал этот флаг, но из-за возросшего кода и лени забил на него и забыл.))

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 12:20:19

И всё таки, вот никак не могу понять, почему многие упёрлись наглухо в этот пресловутый BF? Может кто-то внятно объяснит? Производитель не заявляет, что работа с ним единственно правильная. Время между посылками оговорено в даташите. В случае сбоя и частичного обновления дисплея получаем на дисплее каракули. В других дисплеях нет BF или ему подобного, их что теперь, считать неполноценными? Крутиться в цикле просто так ничего не делая, это есть фэншуй? А если по причине помехи бит не станет, то что, остаться в цикле навеки вечные? Защитным таймером то мало кто заморачивается. Но и крутиться в цикле с защитным таймером, ничего не делая, тоже ведь не комильфо! Откуда здесь возьмётся наилучшая производительность, в цикле с двумя проверками условий? Какой тогда с этого BF вообще профит?

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 13:35:41

scorpi_0n писал(а):Какой тогда с этого BF вообще профит?
Да нет его - профита особого. В недавнем холиваре ругали задержки, дескать это - не дзен. Однако, в начале инициализации, когда BF игнорится, хошь - не хошь, а задержки используются. Был разумный аргумент, что на серийном производстве можно нарваться на разброс параметров дисплея (аж в 3 раза! :)) ), ну так и BF может подвеситься. Причем, если проблема с задержками выявится практически сразу, при первом включении, то BF может подложить свинью вполне себе и рандомно.

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 14:23:27

ARV писал(а):надеюсь, вы понимаете, что рекурсия - это расход стека, который в AVR принципиально невозможно контролировать?

этого я пока не понимаю, но правильно ли я понимаю, что лучше избегать рекурсии в AVR?

ARV писал(а):"пока условие станет ложью" - это в переводе на Си оператор while(!(условие));, рекурсия тут не нужна.


данная конструкция имеет право на жизнь?
Код:
void busy_flag()
{
   DDRD      = 0x00;        // порт D на вход
   LCD_PORT  = 0xFF;        // включаем поддтяжку
   RUN_PORT |= RW_read;
   do
   {
     RUN_PORT |=  E;          //  взводим строб
     RUN_PORT &= ~E;          //  команда на чтение
   } while (!(PIND&(1<<7)));
   
}


Добавлено after 15 minutes 26 seconds:
Мурато Мяуконни писал(а):Я уже не помню, давно 1602 не использовал. Но кажется там была какая-то фишка с интервалом в полубайтах. Или я уже че путаю. Кароч, если найду у себя в загашнике дисплейчик, или если найду свои старые проекты - проверю.

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

в этом я тоже полностью солидарен.
Мурато Мяуконни писал(а): а разве нельзя записать одним шагом напрямую:

даже нужно,ну я как вы может не заметили пишу и так и не так :)) помню как то раз выложил код написанный именно просто присваиванием в тему, и мне один "КОТ" сделал замечание: "так нельзя, это СИ" хотя практика показала, что можно.

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 14:45:53

ROMan2947 писал(а):данная конструкция имеет право на жизнь?
конструкция имеет. только надо хорошенько разобраться с условием во while - вам надо, чтобы старший бит стал равным 0 или 1 для выхода из цикла? сейчас цикл закончится, если бит станет равным 1, а пока он равен 0 - цикл будет крутиться. если это не то, что вам надо - уберите восклицательный знак в скобках.

есть еще одно замечание. я не знаю, как на самом деле, но что-то мне подсказывает, что данные надо считывать во время активного строба Е, а не после того, как он будет убран. если мои подозрения верны, то цикл у вас не будет работать корректно.

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 16:53:04

ARV писал(а):конструкция имеет. только надо хорошенько разобраться с условием во while - вам надо, чтобы старший бит стал равным 0 или 1 для выхода из цикла? сейчас цикл закончится, если бит станет равным 1, а пока он равен 0 - цикл будет крутиться. если это не то, что вам надо - уберите восклицательный знак в скобках

исправлено

ARV писал(а):есть еще одно замечание. я не знаю, как на самом деле, но что-то мне подсказывает, что данные надо считывать во время активного строба Е, а не после того, как он будет убран. если мои подозрения верны, то цикл у вас не будет работать корректно.


если Ваши подозрения верны,то крах моей писанине :kill: Но здесь все верно,запись/чтение выполняется по заднему или спадающему фронту импульса.

P.S. что-то этот дисплейчик меня не на шутку изводит :facepalm:

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 17:30:36

Interfacing to the MPU
The HD44780U can send data in either two 4-bit operations or one 8-bit operation, thus allowing
interfacing with 4- or 8-bit MPUs.
· For 4-bit interface data, only four bus lines (DB4 to DB7) are used for transfer. Bus lines DB0 to DB3
are disabled. The data transfer between the HD44780U and the MPU is completed after the 4-bit data
has been transferred twice. As for the order of data transfer, the four high order bits (for 8-bit operation,
DB4 to DB7) are transferred before the four low order bits (for 8-bit operation, DB0 to DB3).
The busy flag must be checked (one instruction) after the 4-bit data has been transferred twice. Two
more 4-bit operations then transfer the busy flag and address counter data.
· For 8-bit interface data, all eight bus lines (DB0 to DB7) are used.

Figure 9 4-Bit Transfer Example


R/W=1
RS = 0

Первым читаем старший нибл по стробу E, затем младший нибл по стробу E. После этого проверяем 4-й бит старшего нибла. И так далее, пока в нем не окажется нолик.

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 18:54:20

trengtor писал(а):Первым читаем старший нибл по стробу E, затем младший нибл по стробу E. После этого проверяем 4-й бит старшего нибла. И так далее, пока в нем не окажется нолик.


:o :facepalm: это не простительное упущение :facepalm: действительно LCD сталь стабильно инициализироваться.... :beer:
Код:
void busy_flag()
{
   char BF=1;
   DDRD      = 0x00;       
   LCD_PORT  = 0xFF;       
   RUN_PORT |= RW_read;
   do
   {
     RUN_PORT |=  E;
     RUN_PORT &= ~E;
     BF=PIND;
    
     RUN_PORT |=  E;
     RUN_PORT &= ~E;   
   } while (BF&(1<<7));
   }


но с whil(1) {} пока работает не корректно.

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 19:10:18

ROMan2947 писал(а):
Код:
    LCD_PORT &= 0x00; // очищаем шину данных
    LCD_PORT |= DATA; // бaйт данных

Мурато Мяуконни писал(а): а разве нельзя записать одним шагом напрямую:

даже нужно,ну я как вы может не заметили пишу и так и не так :)) помню как то раз выложил код написанный именно просто присваиванием в тему, и мне один "КОТ" сделал замечание

Если перезаписываете порт (или переменную) целиком, как в цитате, то нужно сразу присваивать одной командой.
А если модифицируете отдельные биты, то через маску.

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 19:14:48

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

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 20:05:59

ARV писал(а):ведь могли б уже радоваться жизни :dont_know:

Даже сейчас я не соглашусь. Я учусь, и учиться я считаю надо начинать с азов и много практиковаться.У меня нет цели как можно скорее сделать какую-нибудь "игрушку" и хвастать ее. Даже в данной ситуации благодаря подсказкам, советам, замечаниям участников форума узнаю много полезного, не это ли эффект? к примеру про условную компиляцию услышал впервые,что побудило во мне огромное желание изучить этот материал.
Использовать готовое,как уже говорилось придет со временем, опытом и когда уже будет казаться, что я действительно занимаюсь двойной работой. А сейчас я занимаюсь той работой, которой никогда не занимался. :solder:

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 20:16:17

ROMan2947, обращайте больше внимания на диаграммы обмена данными в даташитах.

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 20:41:31

Вот тут:
Код:
void busy_flag()
{
   char BF=1;
...
   do
   {
...
    [b] BF=PIND;[/b]  <---- чему равен PIND? чтобы цикл повторялся, у PIND в старшем разряде должна быть 1
    
...
   } while ([b]BF&(1<<7[/b])); <--- цикл прекращается, если условие =0, и продолжается, если условие не равно 0.
   }

Как написал trengtor, нужно сначала принять оба полубайта, записывая их в промежуточную переменную, а затем в ней и проверить старший бит.
В промежуточную переменную надо не только принять, но и принять правильно, сдвинув старший полубайт на свое старшее место, а младший поместить тоже на своем месте. Либо просто принять старший полубайт и сохранить его в промежуточную переменную как есть, а следующий полубайт принять и отбросить. Затем в переменной, зная положение бита BF, проверить его.

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Ср янв 18, 2017 23:52:30

Добавлено after 2 hours 25 minutes 58 seconds:
Мурато Мяуконни писал(а):Вот тут:
Код:
void busy_flag()
{
   char BF=1;
...
   do
   {
...
    [b] BF=PIND;[/b]  <---- чему равен PIND? чтобы цикл повторялся, у PIND в старшем разряде должна быть 1
    
...
   } while ([b]BF&(1<<7[/b])); <--- цикл прекращается, если условие =0, и продолжается, если условие не равно 0.
   }

Как написал trengtor, нужно сначала принять оба полубайта, записывая их в промежуточную переменную, а затем в ней и проверить старший бит.
В промежуточную переменную надо не только принять, но и принять правильно, сдвинув старший полубайт на свое старшее место, а младший поместить тоже на своем месте. Либо просто принять старший полубайт и сохранить его в промежуточную переменную как есть, а следующий полубайт принять и отбросить. Затем в переменной, зная положение бита BF, проверить его.


в моем понимании такая картина
DDRD=0x00
PORTD=0xFF
получаем
PIND= 0b1111 1111
E;// стробируем
LCD = 0b1101 // абстрактно LCD выдал такой полубайт

BF = 0b1101 1111 // получаем на пине и пишем его в переменную

флаг занятости записался на свое место, зачем какие то еще манипуляции?
ну а раз мы должны принять весь бай то с имитируем для LCD чтение 2 полубайта
E;
~E;

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Чт янв 19, 2017 13:35:40

Если младший нибл не нужен – да, тогда просто стробим дисплей сигналом E без чтения линий D4-D7.

Re: Работа с ЖКИ на контроллере HD44780 и его аналогах

Чт янв 19, 2017 15:13:55

как практика показала данная функция проверки BF рабочая:
Код:
void busy_flag()
{
   //_delay_ms(1);
   char BF=1;
   DDRD           = 0x00;          // порт D на вход
   LCD_PORT    = 0xFF;          // включаем поддтяжку
   RUN_PORT  |=  RW;
   RUN_PORT &= ~RS;
   
do
   {
     RUN_PORT |=  E;
     RUN_PORT &= ~E;
     BF=PIND;
    
     RUN_PORT |=  E;
     RUN_PORT &= ~E;
   
   } while (BF&(1<<7));
}


Спасиьбо! всем по вискасу, я угощаю :)))
Ответить