|
Универсальный LCD идикатор(GPIO,I2C), Алгоритм |
|
|
|
Apr 2 2018, 09:50
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 3-07-11
Пользователь №: 66 028

|
Добрый день, в одном из проектов, подключил 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, которая будет выполнятся после установленной, но тут получилось все запутано совсем. Подскажите в какую сторону двигаться?.
|
|
|
|
|
 |
Ответов
|
Apr 2 2018, 13:07
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 3-07-11
Пользователь №: 66 028

|
Цитата 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 байта гнать
|
|
|
|
|
Apr 2 2018, 15:30
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(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 - в реальности скобочки после функций-задач надо убрать.
|
|
|
|
|
Apr 3 2018, 09:08
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 3-07-11
Пользователь №: 66 028

|
Цитата (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 ?
Сообщение отредактировал pokk - Apr 3 2018, 09:22
|
|
|
|
|
Apr 3 2018, 20:30
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(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. Не знаю. И имеет ли это смысл.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|