pokk 0 2 апреля, 2018 Опубликовано 2 апреля, 2018 · Жалоба Добрый день, в одном из проектов, подключил LCD индикатор через расширитель порта по I2C, но код получился, как-то не очень надежный, в общем сейчас появилось по больше времени, и решил ещё раз все обдумать и сделать нормальный модуль LCD, который можно в любой проект пихать. Но пока только какая то каша в голове. В общем вот примерно как-то так было, во время всех while, переключался на другие процессы через ОС. Теперь меня интересует, как бы все это сделать без ОС,( для самообразования!!). ну и желательно, прозрачный код, но это уже не обязательно. //================================================================================ 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 26 2 апреля, 2018 Опубликовано 2 апреля, 2018 · Жалоба Если хотите уйти от "расширителей", крайне неэффективных для I2C. Предлагается к рассмотрению. 1. На каком-либо процессоре реализовать свой "расширитель", а более правильно - универсальный контроллер LCD с различными интерфейсами - I2C, SPI, serial итп. 2. Входной интерфейс девайса п.1 - SPI (и/или USART). Первый - простой и надежный. Второй даст возможность делать "выносной" дисплей, например в виде панели оператора, если использовать RS485. 3. Протокол - делаем какой удобно и надежно. Если это будет MODBUS - получим панель оператора. Такой себе "OPC-сервер" :) 4. Алгоритм выдачи инф. на дисплей, для упрощения можно использовать следующий. 4.1. Выдача инф. через SPI интерфейс выполняется задачей с низким приоритетом, по таймеру + флаги обновления (нет смысла выдавать инф. на дисплей, если она уже там отображается). Таймер - 0.2 .... 0.5 с. Выдача идет "пакетом", без квитирования и задержек на максимальной скорости, соотв-но зацикл невозможнн. 4.2. Выдача инф. по 4.1. производится из видео-RAM (образ экрана LCD в требуемом формате). 4.3. Изменение буфера RAM выполняется асинхронно из любой задачи, из которой требуется вывод на LCD. Плюс такого подхода в том, что при выводе на LCD не требуется аппаратно через SPI обновлять содержимое экрана. Это будет сделано автоматичиески, максимум через таймаут 4.1. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
pokk 0 2 апреля, 2018 Опубликовано 2 апреля, 2018 · Жалоба 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 26 2 апреля, 2018 Опубликовано 2 апреля, 2018 · Жалоба (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 0 3 апреля, 2018 Опубликовано 3 апреля, 2018 (изменено) · Жалоба (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 ? Изменено 3 апреля, 2018 пользователем pokk Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ae_ 2 3 апреля, 2018 Опубликовано 3 апреля, 2018 · Жалоба Есть давно известная схема подключения HD44780-совместимого дисплея к МК с помощью 74HC164 в 8-бит режиме(только запись) по 3 GPIO. Есть библиотеки для разных МК, искать по запросу "74hc164 hd44780". Цена в розницу для 74HC164 ~0.2$ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rx3apf 0 3 апреля, 2018 Опубликовано 3 апреля, 2018 · Жалоба Да и младшие STM8 не сильно дороже (оптом 30, в розницу 50 центов). Чем с расширителем плохо - межбайтовые времянки все равно надо выдерживать. Вероятно, в ниббловом режиме через расширитель или параллельно этим можно и DMA с таймером озадачить, конечно (если есть). Если есть свободный UART - логичнее бы туда строкой плюнуть и пусть уже отдельный контроллер разбирается. Мне вот понравилось навесить модуль на прерывание таймера (125 us), по запросу копирую буфер экрана в память индикатора без каких-то непроизводительных задержек. На этом же прерывании и тех же линиях данных и опрос клавиатуры с авторепитером. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
k155la3 26 3 апреля, 2018 Опубликовано 3 апреля, 2018 · Жалоба . . . . (1) Это то понятно, а дальше как уходить от while, которая появляется в третей вложенной функции? Особенно интересно без средств ОС(переключения контекста). (2) Как по максимуму сгруппировать все while , что бы потом спихнул все на DMA и ждешь 1 флаг завершения инициализации/обновления LCD ? 1. Использование работы периферии процессора в режиме прерываний "на полную". В частности - SPI + IRQ + DMA. Достаточно "толкнуть" процесс и не трогать его пока не завершится передача. (Никаких wile. Никаких RTOS). Это, конечно, процессоро-зависимое (запуск "в паре" DMA+USART/SPI + IRQ). 2. см. п.1 + все, что было мною высказано выше. Если работать с LCD по его протоколу, то скорость ограничена, иногда требуются таймауты. DMA "не рулит". Может это и можно реализовать, "рваный" режим DMA. Не знаю. И имеет ли это смысл. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться