Вопросы по борьбе с артифактами на LCD экране

Azgo
Offline
Зарегистрирован: 03.04.2022

Доброго времени суток. Возник у меня следующая ситуация:  Подключал я LCD экран к ардуинке и радовался выведенным символам на экран. Скажу сразу подключался я по 4 битной шине. Всё классно когда экран лежит рядом. Но если увеличить длину линии хотябы до 0.5 метра. В какой то момент линия начинает ловить наводки и на экране появляются артифакты. Для лечения пробовал и кондеры припаивать в цепь питания экрана и резистор переносить и запитывать экран напрямую от источника питания. Всё равно возникают артифакты. Вопрос: Как побороть артефакты на экране? Возникло две мысли которые хотел бы с вами обсудить. Что если использовать 8 битную шину? Насколько она устойчива к наводкам? и что если после отправки данных на экран по 4 или 8 битной шине, потом их считывать и сравнивать? Если сумма не сошлась, отправлять по новой на экран данные. Ну и тут вопрос по скорости передачи. Не будет ли схема с передачей и считыванием данных в 4 битном режиме слишком медленной? Жду ваши мысли по моим вопросам. 

sadman41
Offline
Зарегистрирован: 19.10.2016

Мысль есть такая: в юрисдикции общего собрания собственников МКД принять закон запрещающий экранам работать с артифактами. Как смотрите на такой вариант решения?

Эффективность решения примерно на том же уровне, что и предложенные в первопосте. 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

sadman41 пишет:

Мысль есть такая: в юрисдикции общего собрания собственников МКД принять закон запрещающий экранам работать с артифактами. Как смотрите на такой вариант решения?

Точно. А если экраны все равно будут работать с артифактами, то применить санкции. Например выслать дипломатов, или отжать активы. 

Azgo
Offline
Зарегистрирован: 03.04.2022

sadman41 пишет:

Мысль есть такая: в юрисдикции общего собрания собственников МКД принять закон запрещающий экранам работать с артифактами. Как смотрите на такой вариант решения?

Интересное решение по поводу запретить, но увы не реализуемое. 

sadman41 пишет:

Эффективность решения примерно на том же уровне, что и предложенные в первопосте. 

Порекомендуйте тогда решение чтобы было эффективным?

rkit
Offline
Зарегистрирован: 23.11.2016

Azgo пишет:

 Но если увеличить длину линии хотябы до 0.5 метра.

По-моему, решение на поверхности

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Попробуй использовать для передачи данных на дисплей 4 экранированных провода. Все экраны соединить вместе и на GND.

Ещё как вариант перейти на i2c, может даже подключить кабелем utp.

Update: Может быть даже по четырехбитной шине тоже через UTP попробовать подключить. Там как раз 4 пары. Один провод пары как сигнальный, второй на GND. И так все.

Azgo
Offline
Зарегистрирован: 03.04.2022

I2c это конечно хорошо, но вот у меня на руках сейчас контроллер от аппарата по продажи воды. Сделан на амега32 и внём весь порт б занят для экрана и еще две ноги порта д. Я год имею дело с этими контроллерами, не разу не видел чтобы экран подключённый к этому контроллеру артефачил. Вчера прозвонил шлейф от экрана до контроллера. Линия отвечающая за переключение между режимами чтение запись у экрана подключена к земле. Отсюда сделал вывод что 8 битная шина надёжней, ну и решил спросить у сообщества кто что по этому думует?.

-NMi-
Offline
Зарегистрирован: 20.08.2018

Azgo пишет:

Возникло две мысли которые хотел бы с вами обсудить. Что если использовать 8 битную шину? Насколько она устойчива к наводкам?

Тоже самое, только скорость в два раза выше, можно уменьшить в два раза тактовку и как результат - в два раза меньше глюков.

Azgo пишет:

и что если после отправки данных на экран по 4 или 8 битной шине, потом их считывать и сравнивать? Если сумма не сошлась, отправлять по новой на экран данные.

Верно мыслишь. Но придётся написать самому этот кусок кода с проверкой команд и данных на дисплей.

Azgo пишет:

Ну и тут вопрос по скорости передачи. Не будет ли схема с передачей и считыванием данных в 4 битном режиме слишком медленной? Жду ваши мысли по моим вопросам. 

Делал давно по I2C шине С ПРОВЕРКОЙ отправляемых данных на контроллер. Была та-же самая проблема - при многосуточном прогоне появлялись кракозябры. Здесь всё зависит от умения, если сможешь написать свою библиотеку или функцию - всё будет ОК. Про скорость ->> И советую почитать DiHalta, он написал на асме полный конечный автомат, который прямо в прозрачном режиме и только на железных интах последовательно отправлял данные в контроллер. Запускал одновременно ЧЕТЫРЕ дисплея по I2C - глюков не было. Единственное но - придётся изобретать что-то типа диспетчера задач или как-то делать приоритеты, чтобы "кто-то" не помешал обмену данными с контроллером. Это касаемо нескольких дисплеев, с одним, думаю, норм всё будет.

-NMi-
Offline
Зарегистрирован: 20.08.2018

Azgo пишет:

 Вчера прозвонил шлейф от экрана до контроллера. Линия отвечающая за переключение между режимами чтение запись у экрана подключена к земле. Отсюда сделал вывод что 8 битная шина надёжней, ну и решил спросить у сообщества кто что по этому думует?.

Скоростью тактовки управляешь именно ты, можешь больше, можешь меньше. Если контроллер успевает "схавать" - всё норм, если нет - возникают ошибки. Причём они имеют свойство накапливаться и артефактов становится всё больше и больше. 

Если сумеешь сделать что-то типа диспетчера экрана с последовательным выводом данных на дисплей. Допустим, 20Х4 = 80 байт. Типа буфера дисплея. Ну и далее побайтово обновляешь дисплей. Я делал раз в секунду, всё норм.

К сожалению я "остыл" к ардуино и атмелам, пересев на стм... 

Morroc
Offline
Зарегистрирован: 24.10.2016

Если проблема в накоплении, то что мешает иногда перерисовать весь экран?

Azgo
Offline
Зарегистрирован: 03.04.2022

-NMi- пишет:

Azgo пишет:

 Вчера прозвонил шлейф от экрана до контроллера. Линия отвечающая за переключение между режимами чтение запись у экрана подключена к земле. Отсюда сделал вывод что 8 битная шина надёжней, ну и решил спросить у сообщества кто что по этому думует?.

Скоростью тактовки управляешь именно ты, можешь больше, можешь меньше. Если контроллер успевает "схавать" - всё норм, если нет - возникают ошибки. Причём они имеют свойство накапливаться и артефактов становится всё больше и больше. 

 

Позвольте уточнится. Скорость тактовки это частота работы мк? Тогда такой вопрос. Тогда получается чем выше частота работы мк, тем больше вероятность артефактов?

-NMi-
Offline
Зарегистрирован: 20.08.2018

Не совсем так... контроллер (если память моя не подводит) ждёт выставления данных на шине + импульс строба, на считывание. Посему, чем чаще импульсы стробирования - тем выше тактовка.

Azgo
Offline
Зарегистрирован: 03.04.2022

Уважаемые прошу опять совета. Нашел код работы lcd экрана с чтением флага занятости. Запустил код работает, в протеуси при симулации видно что мк читает lcd экран. Но вот беда на сам экран ничего не выводится. Я уже голову сломал в чем проблема. Подскажите что не так.

LCD.c
// Подключение LCD на базе HD44780 к ATmega16 (LM016L LCD 16x2)
// сайт http://micro-pi.ru

#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include "LCD.h"

/*
  Отправляет младшую половину байта byte в LCD. Если state == 0,
  то передаётся как команда, если нет, то как данные.
*/
void lcdSendNibble(char byte, char state) {
  // Пины управления - на выход
  LCDCONTROLDDR |= 1<<LCD_RS | 1<<LCD_RW | 1<<LCD_E;
  // Пины данных - на выход
  LCDDATADDR |= 1<<LCD_D4 | 1<<LCD_D5 | 1<<LCD_D6 | 1<<LCD_D7;
  // Режим записи, RW = 0
  LCDCONTROLPORT &=  ~(1<<LCD_RW);
  // Устанавливаем 1 в RS
  if (state) {
    // если отдаём данные
	LCDCONTROLPORT |= 1<<LCD_RS;
  } else {
    LCDCONTROLPORT &= ~(1<<LCD_RS);
  }
  // Взводим строб
  LCDCONTROLPORT |= 1<<LCD_E;
  // Обнуляем пины данных
  LCDDATAPORT &= ~(1<<LCD_D4 | 1<<LCD_D5 | 1<<LCD_D6 | 1<<LCD_D7);
  // Записываем младшую
  if (byte & (1<<3)) {
    // половину байта
	LCDDATAPORT |= 1<<LCD_D7;
  }
  // byte в порт вывода данных
  if (byte & (1<<2)) {
    LCDDATAPORT |= 1<<LCD_D6;
  }

  if (byte & (1<<1)) {
    LCDDATAPORT |= 1<<LCD_D5;
  }

  if (byte & (1<<0)) {
    LCDDATAPORT |= 1<<LCD_D4;
  }
  // Пауза
  _delay_us(LCD_STROBEDELAY_US);
  // Опускаем строб. Полубайт ушёл
  LCDCONTROLPORT &= ~(1<<LCD_E);
}

/*
  Читает половину байта из LCD. Если state == 0, то читается команда,
  если нет, то данные.
*/
char lcdGetNibble(char state) {
  char temp = 0;
  // Пины управления - на выход
  LCDCONTROLDDR |=  1<<LCD_RS | 1<<LCD_RW | 1<<LCD_E;
  // Режим чтения
  LCDCONTROLPORT |= 1<<LCD_RW;
  // Устанавливаем 1 в RS
  if (state) {
    // если получаем данные
    LCDCONTROLPORT |=(1<<LCD_RS);
  } else {
    LCDCONTROLPORT &= ~(1<<LCD_RS);
  }
  // Взводим строб
  LCDCONTROLPORT |= 1<<LCD_E;
  // Пины данных - на вход
  LCDDATADDR &= ~(1<<LCD_D4 | 1<<LCD_D5 | 1<<LCD_D6 | 1<<LCD_D7);
  // с подтяжкой
  LCDDATAPORT |= 1<<LCD_D4 | 1<<LCD_D5 | 1<<LCD_D6 | 1<<LCD_D7;
  // Пауза
  _delay_us(LCD_STROBEDELAY_US);
  // Опускаем строб
  LCDCONTROLPORT &= ~(1<<LCD_E);
  // Читаем пины
  if (LCDDATAPIN & (1<<LCD_D7)) {
    // во временную переменную 
    temp |= 1<<3;
  }
    
  if (LCDDATAPIN & (1<<LCD_D6)) {
    temp |= 1<<2;
  }

  if (LCDDATAPIN & (1<<LCD_D5)) {
    temp |= 1<<1;
  }
    
  if (LCDDATAPIN & (1<<LCD_D4)) {
    temp |= 1<<0;
  }
  // возвращаем прочитанное
  return temp;
}

/*
  Читает байт из LCD. Если state == 0, то читается команда,
  если нет, то данные.
*/
char lcdRawGetByte(char state) {
  char temp = 0;
  
  temp |= lcdGetNibble(state);
  temp = temp<<4;          
  temp |= lcdGetNibble(state);
  
  return temp;
}

/*
  Отравляет байт в LCD. Если state == 0, то передаётся как команда,
  если нет, то как данные.
*/
void lcdRawSendByte(char byte, char state) {
  lcdSendNibble((byte>>4), state);          
  lcdSendNibble(byte,state);
}

/*
  Читает состояние LCD, возвращает 0xff, если флаг занятости установлен,
  и 0x00, если нет.
*/
char lcdIsBusy(void) {
/* TODO
  if (lcdRawGetByte(LCD_COMMAND) & (1<<7))
    return 0xff;
  else
    return 0x00;
*/
  _delay_ms(DELAY);
  return 0x00;
}

/*
  Выполняет начальную инициализацию дисплея. Четырёхбитный режим. 
*/
void lcdInit(void) {
  while (lcdIsBusy()) ;  
  lcdSendNibble(0b0010, LCD_COMMAND);
  while (lcdIsBusy()) ;
  lcdRawSendByte(0b00101000, LCD_COMMAND);
  while (lcdIsBusy()) ;
  lcdRawSendByte(0b00000001, LCD_COMMAND);
  while (lcdIsBusy()) ;
  lcdRawSendByte(0b00000110, LCD_COMMAND);
  while (lcdIsBusy()) ;
  lcdRawSendByte(0b00001100, LCD_COMMAND);
}

/*
  Устанавливает режим курсора: 0 - выключен, 2 - включен, 3 - моргает.
  Если на момент запуска LCD был выключен (lcdSetDisplay), то он будет включен.
*/
void lcdSetCursor(char cursor) {
  while (lcdIsBusy());
  
  lcdRawSendByte((0b00001100 | cursor), LCD_COMMAND);
}

/*
  Включает или выключает отображение символов LCD.
  При каждом вызове выключает курсор.
*/
void lcdSetDisplay(char state) {
  while (lcdIsBusy());
  
  lcdRawSendByte((0b00001000 | state), LCD_COMMAND);
}

/*
  Очищает LCD.
*/
void lcdClear(void) {
  while (lcdIsBusy()) ;
  
  lcdRawSendByte(0b00000001, LCD_COMMAND);
}

/*
  Устанавливает курсор в заданную позицию.
*/
void lcdGotoXY(char str, char col) {
  while (lcdIsBusy());
  
  lcdRawSendByte((0b10000000 | ((0x40 * str) + col)), LCD_COMMAND);
}

/*
  Сдвигает область отображения на указанное количество символов
  вправо или влево.
*/
void lcdDisplayScroll(char pos, char dir) {
  while (pos){
    while (lcdIsBusy()) ;
  
    lcdRawSendByte((0b00011000 | dir), LCD_COMMAND);
    pos--;
  }  
}

/*
  Выводит строку из RAM в позицию курсора.
*/
void lcdPuts(char *str) {
  while (*str){
    while (lcdIsBusy()) ;
    
    lcdRawSendByte(*str++, LCD_DATA);
  }
}

/*
  Выводит строку из flash в позицию курсора.
*/
void lcdPutsf(char *str) {
  while (pgm_read_byte(str)){
    while (lcdIsBusy()) ;
    
    lcdRawSendByte(pgm_read_byte(str++), LCD_DATA);
  }
}

/*
  Выводит строку из eeprom в позицию курсора.
*/
void lcdPutse(uint8_t *str) {
  while (eeprom_read_byte(str)){
    while (lcdIsBusy()) ;
    
    lcdRawSendByte((char)(eeprom_read_byte(str++)), LCD_DATA);
  }
}

/*
  Загружает символ в знакогенератор.
*/
void lcdLoadCharacter(char code, char *pattern) {
  while (lcdIsBusy());
  
  lcdRawSendByte((code<<3) | 0b01000000, LCD_COMMAND);
  
  for (char i = 0; i <= 7; i++){
    while (lcdIsBusy()) ;
        
    lcdRawSendByte(*pattern++, LCD_DATA);
  }
  while (lcdIsBusy());
  lcdRawSendByte(0b10000000, LCD_COMMAND);
}

/*
  Загружает символ из flash в знакогенератор.
*/
void lcdLoadCharacterf(char code, char *pattern) {
  while (lcdIsBusy());
  
  lcdRawSendByte((code<<3) | 0b01000000, LCD_COMMAND);
  
  for (char i = 0; i <= 7; i++){
    while (lcdIsBusy());

    lcdRawSendByte(pgm_read_byte(pattern++), LCD_DATA);
  }
  while (lcdIsBusy());
  lcdRawSendByte(0b10000000, LCD_COMMAND);
}

/*
  Загружает символ из eeprom в знакогенератор.
*/
void lcdLoadCharactere(char code, char *pattern) {
  while (lcdIsBusy());
  
  lcdRawSendByte((code<<3) | 0b01000000, LCD_COMMAND);
  
  for (char i = 0; i <= 7; i++){
    while (lcdIsBusy()) ;
        
    lcdRawSendByte(eeprom_read_byte(pattern++), LCD_DATA);
  }
  while (lcdIsBusy()) ;
  lcdRawSendByte(0b10000000, LCD_COMMAND);
}
 

main.c
// Подключение LCD на базе HD44780 к ATmega16 (LM016L LCD 16x2)
// сайт http://micro-pi.ru

#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include "LCD.h"

int main(void) {
  _delay_ms(100);
  lcdInit();
  lcdClear();
  lcdSetDisplay(LCD_DISPLAY_ON);
  lcdSetCursor(LCD_CURSOR_OFF);
  
  char text[17];
  strcpy(text, "  Hello World!  ");
  lcdGotoXY(0, 0);
  lcdPuts(text);
  strcpy(text, "site:micro-pi.ru");
  lcdGotoXY(1, 0);
  lcdPuts(text);    

  while (1);
}

 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

В протеус нет картинки или в железе ?

Azgo
Offline
Зарегистрирован: 03.04.2022

Пока в протеусе. В железене нету возможности проверить на данный момент.

Azgo
Offline
Зарегистрирован: 03.04.2022

Пока в протеусе. В железе нету возможности проверить на данный момент.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

На том же сайте где вы взяли код - есть проект для Proteus и HEX файл в проекте для Atmel Studio - с ними картинка есть !

Azgo
Offline
Зарегистрирован: 03.04.2022

Да оно работает, но если вы посмотрите функцию lcdIsBusy то вы увидите что она закоментирована. Если её раскоментировать происходит именно то о чем я писал выше.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Вы хотите странного просто. Надо большое расстояние - экранируйте линии или ставьте второй контроллер рядом с экраном.

Azgo
Offline
Зарегистрирован: 03.04.2022

Та нет, странного я не хочу. Просто зачем делать экран если можно этот вопрос в программе решить

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Если данные искажаются по дороге - то программа не поможет !!! Экран то не знает что ему приходят кривые данные и он не умеет проверять данные на правильность !!!

Взять плоский шлейф и каждый второй провод на GND с обоих концов - может и заработает.

Ещё вариант - на середину кабеля или ближе к LCD повесить повторитель.

-NMi-
Offline
Зарегистрирован: 20.08.2018

Azgo пишет:

Пока в протеусе. В железе нету возможности проверить на данный момент.

Ипать_капать ты тяжек на_падЪйом, шо пипец. 

ПрАтеус нибуЙа нипаказатель работоспособности в железе и в софте!!!

Советую забросить ЭТУ идею, ибо не_сдюжишь ты её асилить...     ((((((((((((((((((((

Azgo
Offline
Зарегистрирован: 03.04.2022

Если так рассуждать, то мы бы до сих пор сидели в каменном веке. А я хочу научится решать эту задачу

-NMi-
Offline
Зарегистрирован: 20.08.2018

Дык ты её изначально неправильно построил. Команду контроллеру нужно давать В ТЕЛЕ ОТПРАВКИ КОМАНДЫ и проверять там-же, а не как у тебя, послали и... когданить проверили. Это не правильно априори!!!

В нете есть библа ПОЛНОСТЬЮ на асме, байт в 200-300, уотт там всё сделано классно и "быстро" и она работает. Аффтора не помню, дело было лет 10 назаТ...

ssss
Offline
Зарегистрирован: 01.07.2016

Azgo пишет:
А я хочу научится решать эту задачу

Учись... у тебя вся жизнь впереди...

Никто тебе толком ничего не подскажет... помехоустойчивость наука очень тонкая... тоньше чем у комара...

Начнём с того... что пол метра шлейки уже плохое решение...