Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Универсальный LCD идикатор(GPIO,I2C)
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
pokk
Добрый день, в одном из проектов, подключил LCD индикатор через расширитель порта по I2C, но код получился, как-то не очень надежный, в общем сейчас появилось по больше времени, и решил ещё раз все обдумать и сделать нормальный модуль LCD, который можно в любой проект пихать. Но пока только какая то каша в голове.
В общем вот примерно как-то так было, во время всех while, переключался на другие процессы через ОС.
Теперь меня интересует, как бы все это сделать без ОС,( для самообразования!!).
ну и желательно, прозрачный код, но это уже не обязательно.
CODE

//================================================================================
void DisplayUpdate(unsigned char *buf){
unsigned char LcdCountChar;
unsigned char GetCharTemp;
for(LcdCountChar=0;LcdCountChar<40;LcdCountChar++){
if(LcdCountChar==0){
WriteLCDcommand(ADDRESS_FIRST_ROW);
}
if(LcdCountChar==20){
WriteLCDcommand(ADDRESS_SECOND_ROW);
}
GetCharTemp=UTF_conversion(buf[LcdCountChar]);
WriteLCDdata(GetCharTemp);
}
}
//================================================================================
void WriteLCDdata(unsigned char data){
SetRS;
WriteLCD_Nibble(data);
data=data<<4;
WriteLCD_Nibble(data);
}
//================================================================================
void WriteLCD_Nibble(unsigned char data){
SetE;
SetW;
//------------------------
GlobalData_Lcd=data;
Pcf8575_Send_data(GlobalData_Lcd,GlobalData_Led_key_lcd);
//PortLCD=(PortLCD&0xFF0F)|(data&0xF0);
while(Pcf8575_Send_ok==1){} //Передача завершилась
//------------------------
ClrE;
}

Как вот это:
Код
while(Pcf8575_Send_ok==1){} //Передача завершилась

вынести в самый верх что бы можно было по опрашивать в main?

Была идея все данные закинуть в стек, а потом, их выдавать.
где все функции будут запускаться в том порядке как их и устанавливали, но тогда получается на каждый чих( SetE;)
внутри WriteLCD_Nibble надо делать тоже функцию, и все это в большую очередь выстроиться, ну и тут так же стала проблема в том что разные параметры передается,и помимо установки в стек обработчиков, надо ещё и параметры устанавливать.
Код
void Lcd_init(void){
    Lcd_pin_init();
    LCD_ON();
    //----------------
    RTOS_SetTask(lcd_set_8bit_mode(0),0,100);      
    RTOS_SetTask(WriteLCDcommand,0,100);         
    RTOS_SetTask(WriteLCDcommand(0x30),0,0);     
    RTOS_SetTask(WriteLCDcommand(0x30),0,0);      
    RTOS_SetTask(WriteLCDcommand(0x3C),0,0);      
    RTOS_SetTask(lcd_cursor_mode(LCD_ENABLE,CURSOR_ENABLE,BLINK),0,0);
    RTOS_SetTask(WriteLCDcommand(0x1),0,0);  
    
    RTOS_SetTask(Start_UpadeDispaly,0,0);  
    return
}


Думал сделать на КА, жестко прописать какие функции за кем вызываються, но тут
1) теряется читабельность(хотя с этим я уже мерился, так 1 раз все это прописать и больше туда возвращаться не планирую).
2) когда следуют одинаковые функции друг за другом типа 2 раза вызов функции WriteLCDcommand с разным параметром.
как тут быть даже не знаю, делал ещё пред настройку(как бы буфер на 2 функции вперед), установку функции Next, которая будет выполнятся после установленной, но тут получилось все запутано совсем.

Подскажите в какую сторону двигаться?.








k155la3
Если хотите уйти от "расширителей", крайне неэффективных для I2C.
Предлагается к рассмотрению.
1. На каком-либо процессоре реализовать свой "расширитель", а более правильно - универсальный контроллер LCD
с различными интерфейсами - I2C, SPI, serial итп.
2. Входной интерфейс девайса п.1 - SPI (и/или USART). Первый - простой и надежный. Второй даст возможность
делать "выносной" дисплей, например в виде панели оператора, если использовать RS485.
3. Протокол - делаем какой удобно и надежно. Если это будет MODBUS - получим панель оператора.

Такой себе "OPC-сервер" sm.gif

4. Алгоритм выдачи инф. на дисплей, для упрощения можно использовать следующий.
4.1. Выдача инф. через SPI интерфейс выполняется задачей с низким приоритетом, по таймеру + флаги обновления (нет смысла выдавать инф. на дисплей, если она уже там отображается). Таймер - 0.2 .... 0.5 с. Выдача идет "пакетом", без квитирования и задержек на максимальной скорости, соотв-но зацикл невозможнн.
4.2. Выдача инф. по 4.1. производится из видео-RAM (образ экрана LCD в требуемом формате).
4.3. Изменение буфера RAM выполняется асинхронно из любой задачи, из которой требуется вывод на LCD.

Плюс такого подхода в том, что при выводе на LCD не требуется аппаратно через SPI обновлять содержимое экрана.
Это будет сделано автоматичиески, максимум через таймаут 4.1.


pokk
Цитата
1. На каком-либо процессоре реализовать свой "расширитель", а более правильно - универсальный контроллер LCD

LCD, дисплей примитивный hd44780, так что сильно жырно для него использовать отдельный МК, если я правильно понял.
Цитата
4.2. Выдача инф. по 4.1. производится из видео-RAM (образ экрана LCD в требуемом формате).
4.3. Изменение буфера RAM выполняется асинхронно из любой задачи, из которой требуется вывод на LCD.

Все так и сделано.
Цитата
4.1. Выдача инф. через SPI интерфейс выполняется задачей с низким приоритетом, по таймеру + флаги обновления (нет смысла выдавать инф. на дисплей, если она уже там отображается). Таймер - 0.2 .... 0.5 с. Выдача идет "пакетом", без квитирования и задержек на максимальной скорости, соотв-но зацикл невозможнн.

Блин а тут не чисто SPI,I2C, управляющие выводы RS,RW,E идут от процессора а через расширитель только данные, изначально было так проше, что бы на 1 символ не приходилось 3 байта гнать
k155la3
Цитата(pokk @ Apr 2 2018, 16:07) *
(1) LCD, дисплей примитивный hd44780, так что сильно жырно для него использовать отдельный МК, если я правильно понял.
(2) Блин а тут не чисто SPI,I2C, управляющие выводы RS,RW,E идут от процессора а через расширитель только данные, изначально было так проше, что бы на 1 символ не приходилось 3 байта гнать

(1) По стоимости PCF8574 вполне сопоставима с недорогими контроллерами.
(2) Оставить SPI, специфический алгоритм общения с LCD вынести в контроллер. "Тормозные" операции, вроде таймаутов для LCD, не будут выполняться в базовой системе. Подобные
Код
while(Pcf8575_Send_ok==1){}

и прочим, которые упрятаны в Pcf8575_Send_data();
Цитата
Подскажите в какую сторону двигаться?.

(непонятно, что за RTOS)
Код
void Lcd_init(void){
    Lcd_pin_init();
    LCD_ON();
    //----------------
    RTOS_SetTask(lcd_set_8bit_mode(0),0,100);      
    RTOS_SetTask(WriteLCDcommand,0,100);        
    RTOS_SetTask(WriteLCDcommand(0x30),0,0);    
    RTOS_SetTask(WriteLCDcommand(0x30),0,0);      
    RTOS_SetTask(WriteLCDcommand(0x3C),0,0);      
    RTOS_SetTask(lcd_cursor_mode(LCD_ENABLE,CURSOR_ENABLE,BLINK),0,0);
    RTOS_SetTask(WriteLCDcommand(0x1),0,0);  
    
    RTOS_SetTask(Start_UpadeDispaly,0,0);  
    return
}


примерно так
Код
void SystemGo_init(void)
{
    Lcd_pin_init();
    OtherHW_pin_init();
    Lcd_Test(); delay(500); Lcd_Clear();
    //----------------
    RTOS_SetTask( TimersTask(), PRTY_0 );      // Реализация софт-таймеров на базе аппаратных таймеров
    RTOS_SetTask( LCDUpdateTask(), PRTY_2 );      // Выдача на LCD, если есть что  
    RTOS_SetTask( MainTask(), PRTY_1 );                // Управление нашим папилацем.
    // ---------------
    RTOS_Run();
    //return
}

ps - в реальности скобочки после функций-задач надо убрать.
pokk
Цитата
(2) Оставить SPI, специфический алгоритм общения с LCD вынести в контроллер. "Тормозные" операции, вроде таймаутов для LCD, не будут выполняться в базовой системе.
Благодарю, в следующий раз по думаю в этом направлении, но пока увы, уже плата готова.
Цитата
(непонятно, что за RTOS)

Это не RTOS, а просто объектный такой код, для понятия алгоритма, вот поспешил и не исправил, правильнее было так написать
Код
STACK_SetTask(lcd_set_8bit_mode(0),0,100);      
STACK_SetTask(WriteLCDcommand,0,100);        
STACK_SetTask(WriteLCDcommand(0x30),0,0);    
STACK_SetTask(WriteLCDcommand(0x30),0,0);      
STACK_SetTask(WriteLCDcommand(0x3C),0,0);      
STACK_SetTask(lcd_cursor_mode(LCD_ENABLE,CURSOR_ENABLE,BLINK),0,0);
STACK_SetTask(WriteLCDcommand(0x1),0,0);

Это я хотел, забуферизировать порядок вызова функций.
Цитата
примерно так

Это то понятно, а дальше как уходить от while, которая появляется в третей вложенной функции? Особенно интересно без средств ОС(переключения контекста).

Как по максимуму сгруппировать все while , что бы потом спихнул все на DMA и ждешь 1 флаг завершения инициализации/обновления LCD ?

ae_
Есть давно известная схема подключения HD44780-совместимого дисплея к МК с помощью 74HC164 в 8-бит режиме(только запись) по 3 GPIO. Есть библиотеки для разных МК, искать по запросу "74hc164 hd44780". Цена в розницу для 74HC164 ~0.2$

rx3apf
Да и младшие STM8 не сильно дороже (оптом 30, в розницу 50 центов). Чем с расширителем плохо - межбайтовые времянки все равно надо выдерживать. Вероятно, в ниббловом режиме через расширитель или параллельно этим можно и DMA с таймером озадачить, конечно (если есть). Если есть свободный UART - логичнее бы туда строкой плюнуть и пусть уже отдельный контроллер разбирается. Мне вот понравилось навесить модуль на прерывание таймера (125 us), по запросу копирую буфер экрана в память индикатора без каких-то непроизводительных задержек. На этом же прерывании и тех же линиях данных и опрос клавиатуры с авторепитером.
k155la3
Цитата(pokk @ Apr 3 2018, 12:08) *
. . . .
(1) Это то понятно, а дальше как уходить от while, которая появляется в третей вложенной функции? Особенно интересно без средств ОС(переключения контекста).

(2) Как по максимуму сгруппировать все while , что бы потом спихнул все на DMA и ждешь 1 флаг завершения инициализации/обновления LCD ?


1. Использование работы периферии процессора в режиме прерываний "на полную".
В частности - SPI + IRQ + DMA. Достаточно "толкнуть" процесс и не трогать его пока не завершится передача.
(Никаких wile. Никаких RTOS). Это, конечно, процессоро-зависимое (запуск "в паре" DMA+USART/SPI + IRQ).

2. см. п.1 + все, что было мною высказано выше.
Если работать с LCD по его протоколу, то скорость ограничена, иногда требуются таймауты. DMA "не рулит".
Может это и можно реализовать, "рваный" режим DMA. Не знаю. И имеет ли это смысл.


Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.