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