|
|
  |
Странное поведение портов!, Мега32 - что может быть??? |
|
|
|
May 16 2006, 18:58
|

учащийся
    
Группа: Свой
Сообщений: 1 065
Регистрация: 29-10-05
Из: города контрастов
Пользователь №: 10 249

|
Я Вас может быть неправильно понял но не могу интерпретировать эти предложения с одним смыслом :
"Нет - я вообще ничего не читаю из LCD!!! Мало того, если я отсоединяю LCD то ничего ровным счетом не меняется! Дело не в дисплее. Я выдаю на мл. линии "0", переключаю порт на прием, выжидаю паузу - и читаю. И читаю те самые нули, которые я же туда и выдал."
и вот это :
"Если отключаем LCD, и код, его обслуживающий, то все работает правильно. Мало того, если прерывание возникает не в период обращения к дисплею, то тоже все нормально. Функция работы с LCD настраивает старшую тетраду на выход, младшая - остается на прием."
--------------------
Зачем лаять на караван , когда на него можно плюнуть?
|
|
|
|
|
May 16 2006, 20:05
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(_artem_ @ May 16 2006, 21:58)  Я Вас может быть неправильно понял но не могу интерпретировать эти предложения с одним смыслом :
"Нет - я вообще ничего не читаю из LCD!!! Мало того, если я отсоединяю LCD то ничего ровным счетом не меняется! Дело не в дисплее. Я выдаю на мл. линии "0", переключаю порт на прием, выжидаю паузу - и читаю. И читаю те самые нули, которые я же туда и выдал."
и вот это :
"Если отключаем LCD, и код, его обслуживающий, то все работает правильно. Мало того, если прерывание возникает не в период обращения к дисплею, то тоже все нормально. Функция работы с LCD настраивает старшую тетраду на выход, младшая - остается на прием." Связать можно, в первом случае, я полагаю, код, обслуживающий LCD, не был отключен. А просто был отсоединен экран. Во втором случае код отключен тоже. Проблема помоему очевидна, и скрывается в коде, обслуживающем LCD. Похоже, что операция вывода байта на экран должна быть атомарной операцией (нельзя переключать порт передав только старшую тетраду данных). Как уже писал ранее, один из путей решения проблемы - запрещать прерывания, на время работы с LCD.
|
|
|
|
|
May 16 2006, 23:06
|
Участник

Группа: Новичок
Сообщений: 38
Регистрация: 12-09-05
Пользователь №: 8 464

|
[/quote] Что касается выдачи данных, то для того, чтобы передать байт в дисплей по четырехпроводному интерфейсу, нужно проделать следующее:
OutPort(data & 0xf0) OutPort(data << 4)
т.о. младшие биты передаются нулями. Если я отключаю устройство от порта, то я не могу различить то ли я читаю те нули, что передал сам же, то ли это те нули, которые вызваны отсутствием устройства на шине. [/quote]
Вообще-то если предвидится прерывание кода изменения состояния порта иной подпрограммой которая может изменять состояние того же порта то логично делать примерно так
cbr Data,0b00001111; сброс мл. части команды/данных cli; in CopyPort,Port; cbr CopyPort,0b11110000; сброс ст. части состояния порта or CopyPort,Data; получили в старшей части то что надо out Port,CopyPort; sei; и состояние мл. части порта осталось неизменным
|
|
|
|
|
May 17 2006, 05:54
|
Местный
  
Группа: Свой
Сообщений: 235
Регистрация: 9-02-05
Пользователь №: 2 526

|
Цитата(_artem_ @ May 16 2006, 22:58)  Я Вас может быть неправильно понял но не могу интерпретировать эти предложения с одним смыслом :
"Нет - я вообще ничего не читаю из LCD!!! Мало того, если я отсоединяю LCD то ничего ровным счетом не меняется! Дело не в дисплее. Я выдаю на мл. линии "0", переключаю порт на прием, выжидаю паузу - и читаю. И читаю те самые нули, которые я же туда и выдал."
и вот это :
"Если отключаем LCD, и код, его обслуживающий, то все работает правильно. Мало того, если прерывание возникает не в период обращения к дисплею, то тоже все нормально. Функция работы с LCD настраивает старшую тетраду на выход, младшая - остается на прием." В первом случае отключался только LCD, во втором - и код, его обслуживающий.
|
|
|
|
|
May 17 2006, 06:40
|
Местный
  
Группа: Свой
Сообщений: 235
Регистрация: 9-02-05
Пользователь №: 2 526

|
Цитата(_artem_ @ May 17 2006, 01:23)  Мне это так не кажется - передача тетрады для порта половина которого работает не передачу а остальная на прием как такового значение не имеет - в любом случае в PORTB регистр записывается байт. Для авр все равно и я честно говоря не видел ограничений на манипуляцию с gpio портами (было маленькое примечание о переходе с приема на передачу и наоборот и то что при чтении порт опаздывает как минимум на один машинный цикл но не 10 микросек при 16 МГц тактовой). Если предположить что нули выдаются дисплеем потому что может затягиватся сигнал Е на входе дисплея и при этом дисплей каким то макаром работает на передачу - не подтверждается так как без физически подключенного дисплея те же самые нули (если я правильно понял написанное). Без кода и схемы никак . Это код вывода байта в дисплей void LCD_Write (unsigned char CMD, char type) { char Data; CONFIG_CONTROL_PINS; /*#define CONFIG_CONTROL_PINS LCD_E_PORT_DIR |=(1<<LCD_E_PIN); LCD_RS_PORT_DIR |= (1<<LCD_RS_PIN); LCD_RW_PORT_DIR |=(1<<LCD_RW_PIN);*/ SET_DATA_LINES_OUT; /*#define SET_DATA_LINES_OUT LCD_DATA_PORT_DIR = ((1<<LCD_D4) | (1<<LCD_D5) | (1<<LCD_D6) | (1<<LCD_D7))*/ CLEAR_LCD_E; // Disable LCD if (type == DATA) SET_LCD_DATA; else SET_LCD_CMD; // Set LCD to command OUT_DATA_PORT(CMD & 0xf0); //выдаем в порт старший полубайт /* #define OUT_DATA_PORT(data) SET_LCD_READ; CLEAR_DATA_PINS; LCD_DATA_PORT |=0;/*data*/ ;SET_LCD_WRITE*/ GENERATE_E_STROB; // Write data to LCD OUT_DATA_PORT(CMD <<4); //выдаем в порт младший полубайт GENERATE_E_STROB; // Write data to LCD Short_Delay(50); } А вот так выглядит та часть обработчика прерывания, которая опрашивает доп. устройство: char PORTB_config = DDRB; DDRB &= ~((1<<PB0) | (1<<PB1) | (1<<PB3) | (1<<PB4)); __delay_cycles(10); //10 тактов генератора if ((PINB & 0x1b) ) { if (PT_status & PT_LINE_ACTIVE) PT_status |= PT_ACTIVE; else PT_status |=PT_LINE_ACTIVE; } else { if (PT_status & PT_LINE_ACTIVE) PT_status &=~PT_LINE_ACTIVE; else PT_status &= ~PT_ACTIVE; } DDRB = PORTB_config; Вот, так обстоят дела. На сегодня доподлинно мне известно, что весь бардак из-за линии РВ5 (общей у LCD и доп. устройства). Всегда читается последний записанный бит (в случае, если прерывание встряло в работу функции обмена с дисплеем), а не фактическое состояние линии доп. устройства. /* #define OUT_DATA_PORT(data) SET_LCD_READ; CLEAR_DATA_PINS; LCD_DATA_PORT |=0;/*data*/ ;SET_LCD_WRITE*/ Пардон, в этой строчке опечатка - это было сделано в проверочных целях, на самом деле все обстоит так: /* #define OUT_DATA_PORT(data) SET_LCD_READ; CLEAR_DATA_PINS; LCD_DATA_PORT |=data ;SET_LCD_WRITE*/
Эскизы прикрепленных изображений
|
|
|
|
|
May 17 2006, 10:35
|
Местный
  
Группа: Свой
Сообщений: 235
Регистрация: 9-02-05
Пользователь №: 2 526

|
Цитата(_artem_ @ May 17 2006, 14:06)  Можно отрассировать по выходу из обработчика прерывания содержимое стека, точнее адресс куда программа вернется после инструкции RETI когда проблема произошла? Можно прямо перед выходом из обработчика прерываний в одну переменную сохранить содержимое стека а в другую флаг присутствия проблемы установленный в : if ((PINB & 0x1b) ) { ....... } else { flag = 1; }
потом в конце вывода в дисплей проверить флаг и если он установлен вывести значение стека на дислпеы или уарт и затем сбросить флаг после . И потом конечно листинг ассемблера с С кодом вместе (как минимум куска на кторый указывает стек).
Еше один вопрос - читается ли 0 все время когда вывод на лсд или иногда ?
Можно также на время OUT_DATA_PORT запретить прерывание dlja vyvoda obeix tetrad :
__disable_interrupts(); OUT_DATA_PORT; __enable_interrupts();
и сообшить результат. При чтении порта РВ4 я вижу то, что быо выдано на эту линию в обработчике дисплея только в том случае, если прерывание возникло во время обмена с дисплеем.
|
|
|
|
|
May 17 2006, 11:54
|
Местный
  
Группа: Свой
Сообщений: 232
Регистрация: 22-02-06
Из: Воронеж
Пользователь №: 14 589

|
В общем так: Самый простой выход из ситуации это, как уже говорилось Цитата запрещать прерывания, на время работы с LCD Если это недопустимо и если точно известно, что период следования прерываний больше времени работы обслуживателя LCD, то можно сделать так: Код char flag = 0; // флаг разрешения обслуживания LCD ................. while ( flag == 0 ); // ждать, пока небыло прерывания [LCD] // процедура обслуживания LCD flag = 0; // запретить обслуживание LCD
................. // в конце обработчика прерывания if ( flag == 0 ) { flag = 1; } // если был запрет на обслуживание LCD, то разрешить его. Успехов.
--------------------
Истина рождается в спорах; но когда страсти кипят, истина испаряется.
|
|
|
|
|
May 17 2006, 15:49
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(Sergio66 @ May 17 2006, 18:35)  Я только что проделал такой эксперимент - я отключтл дисплей, отключил доп. устройство и запустил программу так, как будто все подключено. Только функция работы с дисплеем выдает все "1" во все линии порта В. В обработчике прервания я вижу PINB в "1"! Т.е. ноги висят в воздухе, я выдаю на них "1", потом переключаюсь на прием, и вижу на них те же "1"! Может быть я просто имею "битую" микросхему? Нет  микросхема не битая. Вы выводите 1 в Port, тем самым вы подключаете внутренний Pull-up резистор, и МК ведет себя совершенно адекватно считывая 1 с соответствующего PinX. Проведите пожалуйста такой эксперимент как вам посоветовал _artem: __disable_interrupts(); OUT_DATA_PORT; __enable_interrupts(); или: asm("cli"); //вывод обеих тетрад на LCD asm("sei"); Должно все работать
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|