При отпускании B3, при оцифровке, вы фактически даёте команду 74HC595 на загрузку данных в выходной регистр. Вы уверены что это правильно? ---- P.S. На мой взгляд, работа схемы на грани фола. Я бы не экономил выводы контроллера (если нужно сделать надёжное изделие).
При отпускании B3, при оцифровке, вы фактически даёте команду 74HC595 на загрузку данных в выходной регистр. Вы уверены что это правильно?
Делал испытания и все прекрасно. Дело в том что в момент оцифровки запрещена передача данных в регистры. Поэтому данные на выводы не будут меняться. Мы можем хоть 100 раз дергать этой ногой а данные так и останутся. Вот если я бы передавал данные в момент оцифровки это было бы ужасно.
Ниже библиотека работы с Шиной передачи данных для этих экранов экраны могут быть 2х типов 1-LCD(HD44780) - управляется одним регистром 595 2-LED (7 семисегментник до 4digit) - управляется двумя регистрами 595 Спойлер
Код:
/* ************************************************************************** */ /* Для работы укажите подключеные дисплеи обязательно минимум 1 дисплей */ /* в скобках вы определяете номер регистра который соотвествует дисплею, */ /* запятыми выделяются дисплеи, порядок это будет порядковый номер дисплея */ /* П Р И М Е Р */ /* Обьявление 1 дисплея LCD и 3-х LED */ /* #define SPI_LCD {0} */ /* #define SPI_LED {1,3,5} */
/* определение функциональных ножек МК */ /* просто укажите букву порта как в примере */ /* #define SPI_PORT_SIMBOL B */
/* также укажите номер пина */ /* #define SS_PIN 2 */
/* Если порт пина отличается просто укажите букву порта пина */ /* #define SS_PORT_SIMBOL B */
/* ************************************************************************* */ /* Надо определить рабочие дисплеи указав его регистр работы от 0 */ /* #define SPI_LCD {0} */ /* #define SPI_LED {1,3,5} */ /* ************************************************************************* */
#include <MY\adc.h> /* ************************************************************************** */ //****** макрос для работы с портами *******/ /* ************************************************************************** */ #ifndef CONCAT #define CONCAT(x,y) x ## y #define DDR(x) CONCAT(DDR,x) #define PORT(x) CONCAT(PORT,x) #define PIN(x) CONCAT(PIN,x) #endif
/* ************************************************************************** */ /********* Если хедер обьявлен в другом файле *********/ /********* следующие определения будут игнорированы *********/ /* ************************************************************************** */ #ifndef _BUS_SPI_INCLUDED #define _BUS_SPI_INCLUDED
/* ************************************************************************** */ /* Configure Harware SPI - if you connect dispay to phisical SPI */ /* ************************************************************************** */ /* ************************************************************************** */ /********* Если вы не определили порты и пины *********/ /********* тогда будут сделаны определения по дефольту *********/ /* ************************************************************************** */ #ifndef SPI_PORT_SIMBOL #define SPI_PORT_SIMBOL B #endif
/* ************************************************************************** */ /********* Расположение пинов SPI зависит от МК *********/ /* ************************************************************************** */ #define SPI_MOSI_PIN 3 #define SPI_SCK_PIN 5
//Если порт пина SS не определен пользователем тогда берется порт SPI #ifndef SPI_SS_PORT_SIMBOL #define SPI_SS_PORT SPI_PORT #define SPI_SS_DDR SPI_DDR #define SPI_SS_RPIN SPI_RPIN #else //Если определен пользователем тогда назначаем все связи к определеному порту #define SPI_SS_PORT PORT(SPI_SS_PORT_SIMBOL) #define SPI_SS_DDR DDR(SPI_SS_PORT_SIMBOL) #define SPI_SS_RPIN PIN(SPI_SS_PORT_SIMBOL) #endif
//Если пин SS не определен пользователем тогда берется 2 ножка #ifndef SPI_SS_PIN #define SPI_SS_PIN 2 #endif
/* ************************************************************************* */ //определение длины буфера для передачи в регистры 1регистр = 1байт буфера //Длина определяется автоматически если выбран один LCD и один LED или больше /* ************************************************************************* */ #ifndef SPI_LCD #define SPI_REG_BUF_LENGTH (sizeof(spi_led)*2) #else #ifndef SPI_LED #define SPI_REG_BUF_LENGTH (sizeof(spi_lcd)) #else #define SPI_REG_BUF_LENGTH (sizeof(spi_lcd)+sizeof(spi_led)*2) #endif #endif
/* ************************************************************************* */ /* специальные макросы которые определят дисплей с какой шиной будут работать*/ /* ************************************************************************* */
/* ************************************************************************* */ /* ************ К О Н Е Ц О П Р Е Д Е Л Е Н И Й ********** */ /* ************************************************************************* */
/* ************************************************************************* */ /* ******** Буфер хранящий информацию помещаемую в регистры 595 ****** */ /* ************************************************************************* */ char spi_reg_buf[SPI_REG_BUF_LENGTH];
/* ************************************************************************* */ /* ******** Функция синхронизации буфера с регистрами 595 ****** */ /* ************************************************************************* */ void spi_reg_buf_send() { char i=SPI_REG_BUF_LENGTH; unsigned char reg, temp, pin_was_out, ss_pin_pos=SPI_SS_GET; reg=SREG; #asm("cli") /* ************************************************************************* */ /* ******** мы должны синхронизировать полностью буфера ****** */ /* ******** со всеми регистрами 595, до нового прерывания ****** */ /* ************************************************************************* */
pin_was_out=IS_SPI_SS_PINOUT; //сохраняем направление пина SS для будущего востановления /* ************************************************************************* */ /* ****** Если пиг SS в положение IN, ждем окончания АЦП ****** */ /* ****** преобразования и включаем пиноут ****** */ /* ************************************************************************* */ if (!pin_was_out) {WAIT_ADC_CONVERSION;SPI_SS_PIN_OUT;} /* ************************************************************************* */ /* ****** ставим на землю пин SS ****** */ /* ************************************************************************* */ SPI_SS_PIN_DN;
//SPDR=0;while(!(SPSR & (1<<SPIF)));//без этой команды не работает правильно while(i>0) { i--; SPDR=spi_reg_buf[i]; while(!(SPSR & (1<<SPIF)));//Wait to write data to SPI } SPI_SS_PIN_UP; #asm("nop"); if (!ss_pin_pos) {SPI_SS_PIN_DN;} if (reg&(1<<SREG_I)) {#asm("sei")} }
/* ************************************************************************* */ /* ******** Функция инициализации интерфейса S P I ****** */ /* ************************************************************************* */
#endif //#ifndef _MY_BUS_INCLUDED /* ************************************************************************* */ /* ************ К О Н Е Ц ********** */ /* ************************************************************************* */
библиотека LCD дисплея Спойлер
Код:
#ifndef _BUS_LCD_DISPLAY_INCLUDED #define _BUS_LCD_DISPLAY_INCLUDED /***** LCD дисплей, в отличие от LED будет работать на первой оперделенной шине *****/
#ifdef SPI_LED_LENTGH unsigned char spi_led_buf[SPI_LED_LENTGH][4][2]; #define SPI_LED_ADR(NR) ((unsigned int *)&(spi_led_buf[NR][0][0])) #define SPI_LED_BUF(NR,POS) ((unsigned int *)(spi_led_buf[NR][POS][0])) #define LED_BUF(NR,POS) ((unsigned int *)(sw_led_buf[NR][POS][0])) #endif
#ifdef SW_LED_LENTGH unsigned char sw_led_buf[SW_LED_LENTGH][4][2]; #define SW_LED_ADR(NR) ((unsigned int *)&(sw_led_buf[NR][0][0])) #define SW_LED_BUF(NR,POS) ((unsigned int *)(sw_led_buf[NR][POS][0])) #ifndef LED_BUF #define LED_BUF(NR,POS) ((unsigned int *)(sw_led_buf[NR][POS][0])) #endif #endif
//Universal functions //Round function unsigned int round(unsigned int Number){ unsigned int Num; Num=Number/10; if ((Number%10)>4) {Num++;} return Num; }
void led7_cleanscr(unsigned int *led_buffer) { //led_buffer это ссылка на участок 2 байт памяти которые пренадлежат конкретному LED дисплею //итого мы запишем 4 разряда по 2 байта = 8 байт char i=0; while(i<4){ (*led_buffer)=0; i++; } } void led7_cleandigit(unsigned int *led_buffer, unsigned char pos) { (*(led_buffer+pos))=0; }
void led7_setpoint(unsigned int *led_buffer, unsigned char pos) { //pos&=0b00000011; //защита от переполнения позиции макс=3 (*(led_buffer+pos))|=(1<<S_H); } #define SPI_LED7_SETPOINT(led_nr,pos) (led7_setpoint(SPI_LED_ADR(led_nr),pos))
void led_put_num4d(unsigned int *led_buffer, unsigned int Number){ //led_buffer это ссылка на участок 2 байт памяти которые пренадлежат конкретному LED дисплею //итого мы запишем 4 разряда по 2 байта = 8 байт unsigned int Num,Temp; unsigned char Rest,i=4; Num=Number; Temp=Num;
/* ************************************************************************** */ //****** Макросы для записи данных в LED SPI или SW *******/ /* ************************************************************************** */ #define LEDSW_BIN_PUT(LedNR, A) led_put_bin(SW_LED_ADR(LedNR), A) #define LEDSPI_BIN_PUT(LedNR, A) led_put_bin(SPI_LED_ADR(LedNR), A)
#pragma used-
#endif //#ifndef _BUS_LED_DISPLAY_INCLUDED
Последний раз редактировалось amd9800 Ср авг 05, 2015 20:30:57, всего редактировалось 1 раз.
Я вас прекрасно понимаю. Ну для клавы всегда можно будет выделить один провод. Это для случаев когда устройство находится где то на расстояние 2-4 метра, а экран (экраны) + клавиатура в удобном месте.
Либо ситуация хочу собрать простое устройство которая собирает данные. у устройства выход на данную шину. И периодически могу подключатся к устройству и на экран смотреть информацию.
Вот это значение пробуйте изменить и тестируйте, может помочь. Мне иногда приходилось ставить 300-350 кГц для симуляции. По поводу библиотеки LCD, почему не хотите сделать "универсально", т.е. не только писать в дисплей, но и читать дисплей? Тогда и глюков меньше будет.
Заголовок сообщения: Re: Работа с ЖКИ на контроллере HD44780 и его аналогах
Добавлено: Пт авг 07, 2015 10:41:55
Друг Кота
Карма: 67
Рейтинг сообщений: 1060
Зарегистрирован: Чт сен 18, 2008 12:27:21 Сообщений: 19733 Откуда: Столица Мира Санкт-Петербург
Рейтинг сообщения:0 Медали: 1
amd9800 писал(а):
И как же мне в данном случае читать дисплей
Зачем вам его читать?
_________________ [ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ] Измерить нннада?
Заголовок сообщения: Re: Работа с ЖКИ на контроллере HD44780 и его аналогах
Добавлено: Пт авг 07, 2015 10:49:43
Друг Кота
Карма: 67
Рейтинг сообщений: 1060
Зарегистрирован: Чт сен 18, 2008 12:27:21 Сообщений: 19733 Откуда: Столица Мира Санкт-Петербург
Рейтинг сообщения:0 Медали: 1
Если все тайминги выдержать, то и читать ничего не надо... ... если, конечно, не используется какой-то хитрый алгоритм отображения.
_________________ [ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ] Измерить нннада?
Таковым хитрым алгоритмом может быть, например, использование буфера. Например, для дисплея 2x16 заводим массив buf[2][16]. А потом код вроде этого:
Код:
void any_timer_interrupt() { static uint8_t col = 0; static uint8_t row = 0; if (col >= 16) { col = 0; if (++row >= 2) row = 0; ks0066SetCommand(установка на начало строки row); // RS = 0 } else { ks0066SetData(buf[row][col]); // RS = 1; col++; } }
И это прерывание вызывать по таймеру, например, один раз в 100мкс. Этого времени вполне достаточно для отработки дисплея. Весь экран будет обновляться за 34 команд (32 данных + 2 смены строки), то есть, частота обновления картинки при периоде 100мкс будет около 300Гц.
В основном коде любая функция вывода на экран сведётся всего лишь к записи данных в нужные ячейки буфера buf, при этом никаких задержек не нужно вообще - о выводе изменившегося буфера на экран позаботится данное прерывание.
Естественно, инициализировать дисплей нужно как обычно, и только после инициализации запускать этот таймер.
Последний раз редактировалось WiseLord Пт авг 07, 2015 13:15:42, всего редактировалось 1 раз.
Вот именно что взлетит, и никаких задержек не понадобится вообще. Команды (данные) в дисплей за счёт таймера будут посылаться не чаще 50мкс (либо как настроишь таймер - если дисплей позволяет, можно и чаще).
P.S. Вот за часа полтора даже простейшую библиотеку на этом принципе набросал (всё равно самому скоро понадобится) + демо-проект для Proteus.
Частота обновления экрана 115 Гц (с лихвой достаточно), интервал между командами дисплею 256 мкс (аналогично - с лихвой достаточно). Никаких задержек на работу с дисплеем не требуется (кроме необходимых по даташиту при инициализации дисплея).
Таковым хитрым алгоритмом может быть, например, использование буфера. Например, для дисплея 2x16 заводим массив buf[2][16].
Правильно говорите Я как раз тоже об этом думал. Но вот после этого у меня появилось куча вопросов как сделать библиотеку достаточно универсальной. Ведь есть куча нюансов. Дисплеи могут быть 1, 2 и 4х строчные. Также строка может иметь 16 и 20 символов длины. А также минус этого метода то что буферы всех дисплеев будут сильно забивать RAM, а ее очень мало на МК.
Давайте тогда обсуждать алгоритм работы библиотеки с буфером.
Также у меня был вариант создания кольцевого буфера в котором будут помещаться команды.
Код, приведённый выше, работает для дисплеев размера 16x2. Для любого другого дисплея будет лишь самую малость отличаться инициализация и команда позиционирования. Это всё легко разрулить через те же макросы KS0066_HEIGHT и KS0066_WIDTH, в зависимости от совокупности значений которых и реализовывать эти отличия. Размер массива buf[KS0066_WIDTH][KS0066_HEIGHT] будет выбираться автоматически.
По какому методу лучше синхронизировать буфер с дисплеем? вот один пример. Например настраиваем таймер и запускаем прерывание каждые 100us. Один символ из буфера дисплея помещается в буфер регистра. Если дисплеев несколько тогда со всех дисплеев по одной букве(или ниблу) перемещается в регистр. Потом данные из буфера регистра отправляются в сами регистры. Но вот когда нужно посылать команды на дисплее как поступать? Например инициализация или очистка дисплея.
Добавить еще одну очередь команд, приоритетную. или ячейку, в которую помещаете команду и ставите флажок исполнения - как только она исполнится, в прерывании флажок должен будет снят и можно слать следующую. А в прерывании делать проверку на этот флажок - если он поднят, исполнить команду занесённую в ячейку и снять флажок.
Можно конечно более грубо - запретить прерывания, отправить команду, сбросить таймер и разрешить прерывания.
Не понимаю, зачем такие сложности. Нет никакой причины посылать в дисплей какие-либо команды. Просто пишем в буфер даные - это покрывает все необходимые нужды.
Потому что через регистры 595 могу только передавать информацию. И как же мне в данном случае читать дисплей ума не приложу. Но я готов обсудить любые изменения - предлагайте...
Это понятно Но если вы прислушаетесь к Albert_V и не будете так уж сильно экономить на выводах МК, то могу предложить такие варианты:Спойлер1 - тут надо позаботиться о том, чтобы при чтении флага занятости на выходе 595-го были единицы. 2 - "правильный" вариант, еще один вывод МК задействован, но зато в соответствии с ДШ на дисплей линии данных переводятся в третье состояние и нет проблемы считывать данные из дисплея. Далее создаете еще одну функцию, например:
Код:
SPI_READ_DATA(data, lcd_nr)
в которой надо будет управлять регистром 74НС595 и давать команду чтения. При этом проверяете выбранный пин МК на 0 или 1, это и будет флаг BF. Может быть можно использовать тот пин МК, что управляет ST_CP? Это просто идея, интересно, что скажут профи?
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения