Ответ

Предупреждение: в данной теме не было сообщений более 730 дней.
Если не уверены, что хотите ответить, то лучше создайте новую тему.
Имя:
E-mail:
Тема:
Иконка:

Визуальная проверка:
Без рук и топоренка построена избенка:
Денег нет, но вы ...:
Джигурда: "Какие ... госуслуги!?":

подсказка: нажмите alt+s для отправки или alt+p для предварительного просмотра сообщения


Сообщения в этой теме

Автор: pumpkin
« : 27 Мая 2012, 13:06:38 »

Правильно сделал. Завершаешь Getatkbd совершенно корректно.

А обработчик прерывания - это просто процедура, и ничто, в принципе, не должно мешать срабатыванию в нем других прерываний. Надо просто за стэком-регистрами следить.
Автор: Andy
« : 27 Мая 2012, 08:05:39 »

Совершенно верно. И все это делается уже в прерывании. Многие мануалы говорят, что так нельзя делать, но если очень хочется... Все отлично работает.

И если быть до конца точным, таемер функцию не вырубит, а поставит флаг, по которому функция отключится, скорее всего в ней есть цикл проверки этого флага.
Автор: pumpkin
« : 27 Мая 2012, 07:57:30 »

Перед вызовом Getatkbd() активируешь таймер, который вырубит его, если тот не успеет отработать в отведенный ему для этого интервал времени?
Автор: Andy
« : 26 Мая 2012, 19:34:02 »

Итак, надо не дать зависнуть функции Getatkbd(), разработчики пердусмотрели ее аварийное завершение при установки флага ERR в 1.

Конфигурим наш чип и прерывания, чип - Atmega128. Некоторые функции ассемблера заточены только под него, курите даташит на ваш чип, в комментах будет указано.
Цитировать
$crystal = 11059200                                         \'Кварц- 11,0592 МГц          .
$regfile = "m128def.dat"
$hwstack = 100                                              \' Размер аппаратного стека
$swstack = 50                                               \' Размер программного стека
$framesize = 50                                             \' Размер фрема

\'------Клавиатура Ps/2 -прерывание Int4 ------------------------------------
Config Keyboard = Pine.4 , Data = Pine.3 , Keydata = Keydata

\'------Кофигурим  таймер и время таймаута - 6 миллисикунд, программе обработки пофиг какой предделитьель здесь стоит, он задается стартом таймера на асме, смотрите ниже.  
Config Timer0 = Timer , Prescale = 256   \'Поэтому эта строка не обязательна, но после нее таймер сразу стартует!                   
On Timer0 Tout Nosave  \' В принципе можно отставить только эту строку
Stop Timer0  \'Останавливаем его
Timer0 = 0    \'Обнуляем
Disable Timer0  \' И отключаем нафиг.

\'------Конфигурим обработчик прерывания клавиатуры
On Int4 Isr4 Nosave
Disable Int4

\'-----Обработчик прерывания таймера----
Tout:
Set Err     \'Ставим ERR в 1
Return


Цитировать
 
\'Подпрограмма взятия символа из прерывания и предварительной обработки
Kbdinput:
\'Cursor On
B = 0
Enable Int4
Do
Loop Until B <> 0                                           \'ждем пока символ не упадет в B
Disable Int4
Bsimvol = Chr(b)                                            \'Превращаем принятый код в символ
Bznac = Val(bsimvol)                                        \'Превращаем принятый символ в число                                                           \'Контрольная печать в ком порт
Gosub Pik                                                   \'Пищим
Return

\'Обработчик прерывания INT4
Isr4:
$asm
 push r16           \' Сохраняем регистры
 push r25
 push r26
 push r27
 push r24
 in r24,sreg
 push r24
 in r24,EIMSK     \' И конфигуратор внешних прерываний, КУРИТЕ даташит на чип!
 push r24
 in r24,Eifr         \' И регистр статуса внешних прерываний, КУРИТЕ даташит на чип!
 push r24

 \'----Отключаем INT4!
  in  r25,EIMSK
  cbr  r25,16
  Out Eimsk , R25

 \'----Обнуляем Timer0
  ldi  r25,0
  Out Tcnt0 , R25


 SEI      \'Вот теперь можно снова включить прерывания!

 \'----Включаем  Timer0--
  in  r25,TIMSK
  sbr  r25,1
  Out Timsk , R25

 \'----Стартуем Timer0, сдесь можно изменить предделитель 6 - 256 4 - 64 2 - 8 КУРИТЕ даташит!
  in  r25,TCCR0
  sbr  r25,6
  Out Tccr0 , R25

 rCall Getsymbol        \' Вызываем Getsymbol, которая вызывает Getatkbd(), сразу отюда у меня вызвать не получилось, возможно получится у вас. Вызывать надо так - rCall _Getatkbd

 CLI             \'Отключаем прерывания




 \'----Останваливаем  Timer0--
  in  r25,TCCR0
  cbr  r25,7
  Out Tccr0 , R25

\'  ----Отключаем Timer0-
  in  R25,TIMSK
  cbr  R25,1
  Out Timsk , R25

   \'----Обнуляем Timer0
  ldi  R25,0
  Out Tcnt0 , R25

 pop r24
 !out Eifr,r24              \'Восстанавливаем регистры
 pop r24
 !out eIMSK,r24
 pop r24
 !out sreg,r24
 pop r24
 pop r27                                                   
 pop r26
 pop r25
 pop r16
 $end Asm
 Return


\' Воспомогательная функция, напрямую компилятор выдавал ошибку, хотя в помощи эта функция вызывалась напрямую, возможно проблема в конкретном коде.
Getsymbol:
B = Getatkbd()
Return



Автор: pumpkin
« : 24 Мая 2012, 22:41:44 »

Выкладывай. Интересно  :)
Автор: Andy
« : 24 Мая 2012, 17:53:47 »

Кажися я сделал это! мне удалось скрестить ежа с ужом - сделать прерывание в прерывание - таймаут. Обернул Getatkbd()  в ассемблерный код, который позволяет делать это. Сейчас клавиатуру можно тыкать туда-сюда - и ничего не зависает, а раньше зависало! Я доволен как слон, если интересен код - выложу. Буду тестить в боевых условиях.
Автор: Andy
« : 24 Мая 2012, 07:53:10 »

Предыдущие разборки с прерыванием и клавиатурой не прошли даром, все работает. Но иногда, когда дивайс держит паузу и считает секунды, заодно и опрашивая переменную b, где хранится принятый байт с клавы, дивайс зависает. Такое ощущение, что клава, от нечего делать дергает сигналом, дивайс уходит в прерывание, а там ничего больше нет. Глюк непостоянный и трудноотлавливаемый. Чортова функция Getatkbd() улетает в транс, таймаута у нее нет. В мануале написано, что вывести ее из транса можно установив Set ERR в прерывании, например, а у меня уже эта функция из прерывания вызывается. Посему такой вопрос - Как правильно организовать прерывание в прерывании? Слышал это возможно, но толком описания нет.

Хелп, плиз. Алгоритм должен выглядит примерно так - нажата кнопка, по int0 уходим на обработчик, в нем включаем снова прерывания, запускаем таймер 0 который при переполнении тупо включает Set ERR. Уходим в  Getatkbd().
Автор: Andy
« : 30 Сентября 2010, 14:52:29 »

Сегодня код прошол проверку в реальных боевых условиях, пока ошибок нет! Тихо радуюсь...

А пока филосовское отступление. Флаги - это сила! Они, плюс таймера и прерывания - основа операционных систем с вытясняющей многозадачностью и всем таким. Юзайте флаги - и будет вам Щасте!

У уважаемого DIHALT-а есть отличный набор статей на эту тему, с удовольствием сошлюсь:

http://easyelectronics.ru/avr-uchebnyj-kurs-arxitektura-programm.html#more-279

http://easyelectronics.ru/avr-uchebnyj-kurs-arxitektura-programm-chast-2.html#more-288

http://easyelectronics.ru/avr-uchebnyj-kurs-arxitektura-programm-chast-3.html#more-290

Я, как начинающий быдлокодер завис где-то между первым и вторым уровнем, но с интересом поглядываю на третий - флаговые автоматы. Но стараюсь писать свой код молульно, и нововведения встраиваются в код проекта легко, радуя внезапным уменьшением скомпиллированого кода и изчезновением глюков.

Терпеть не могу си, за его птичий синтаксис, бейсик это мое все, и что на нем можно делать красивый код уже доказано для меня. Например то же меню. Сравните сишное меню у того жеDIHALT-а

http://easyelectronics.ru/organizaciya-drevovidnogo-menyu.html#more-316

и баскомовское нано меню за авторством pumpkin-а и меня  :-[ (типа примазался)

http://minilabmaster.com/cgi-bin/yabb2/YaBB.pl?num=1246889930/0

  так же хочу выразить огромную благодарность pumpkin-у за профессионализм и поддержку.
Автор: Andy
« : 29 Сентября 2010, 17:11:31 »

Cовершенно верно, флаг. Пока код отлично работает, даже в проекте. Единственно B = 0  впихал внутрь подпрограммы Kbdinput, для крастоты и автоматики. Все вроде пока красиво.

С буферами будет позже топик. Буфер ком порта и организация протокола, сейчас работаю над этим. А где буфер ком порта там и тайм-аут. А где тайм-аут, там и таймеры. Сейчас неплохо в них разобрался, классная вещь! Спасибо, pumpkin! Все круто!
Автор: pumpkin
« : 28 Сентября 2010, 18:22:37 »

Цитировать
Например тикает счетчик секунд и его надо прервать с помощью прерывания в любой момент.... Буду думать, наводка на буфер очень перспективна на мой взгляд. 
Точнее назвать это флагом, я думаю, который устанавливается по прерыванию, а счетсик проверяет его состояние постоянно. А можно и прямо в обработчик прерывания воткнуть вызов тормоз счетчика. Вариантов как всегда уйма :)
Автор: pumpkin
« : 28 Сентября 2010, 18:09:37 »

Все правильно. Но ты изменил принцип организации ввода. Можно его назвать "real-time", что-ли, или "синхронным". В играх примерно так ввод устроен. Тебе, возможно, так и нужно. У тебя буфер перестал быть буфером. Обработчик прерывания ориентируется не на "свободность" буфера, а на состояние некоторого флажка, роль которого исполняет B, разрешая или блокируя ввод.

Таким образом очистка буфера (Bcurr = 0) теряет смысл, свободен он или нет нигде не проверяется. Более того, от Bcurr можно вообще избавиться. Так как обработчик заполняет "буфер" только при B = 0, то он может совать символ прямо в B, без промежуточного Bcurr.

Цитировать
Enable Interrupts

On Int0 Kbd                                                 \' обработчик прерывания

Cls

B = 0

Enable Int0                                                 \'включаем прерывания

\'Главная программа
Do
Gosub Kbdinput                                              \'Уходим в подпрограмму приема символа
Cls
Locate 1 , 1                                                \'Типа печатаем символ
Lcd B


B = 0                                                       \'Разблокируем следующий цикл приема символа, пока не 0 прерывания работают вхолостую
Loop

\'Подпрограмма взятия символа из прерывания и предварительной обработки
Kbdinput:
Do
Loop Until B <> 0                                           \'ждем пока символ не упадет в B
Bsimvol = Chr(b)                                            \'Всякая предворительная обработка символа
Bznac = Val(bsimvol)
Printbin B                                                  \'Контрольная печать в ком порт
Gosub Pik                                                   \'Пищим
Return

\'Обработчик прерывания
Kbd:
If B = 0 Then                                               \'Переменная пуста, можно заполнять B
B = Getatkbd()                                              \' Что и делаем
Else                                                        \' Иначе
Dummy = Getatkbd()                                          \' Игнорируем все, пропуская символы
End If
Return


\'Пищалка
Pik:
Sound Speaker , 10 , 947
Return
Автор: Andy
« : 28 Сентября 2010, 16:52:42 »

Но код далеко не идеален, мне нужно свободно либо ожидать ввода символа, либо брать его из прерывания напрямую. Например тикает счетчик секунд и его надо прервать с помощью прерывания в любой момент.... Буду думать, наводка на буфер очень перспективна на мой взгляд.
Автор: Andy
« : 28 Сентября 2010, 16:35:45 »

Попробовал твой пример, он немного не так работает как надо, видимо надо
Kbd:
If B <> 0 Then

исправить на

Kbd:
If B = 0 Then

Немного изменил идиологию алгоритма, игнорируем символы в прерывании, пока не обработаем переменную. Поменял местами переменную буфера и символа, так мне удобнее. Пока код не дает сбоев в учебном примере, буду эксперементировать.  Зацени:


Цитировать

Enable Interrupts

On Int0 Kbd                                                 \' обработчик прерывания

Cls

Bcurr = 0                                                   \'обнуляем переменные
B = 0


Enable Int0                                                 \'включаем прерывания

\'Главная программа
Do
Gosub Kbdinput                                              \'Уходим в подпрограмму приема символа
Cls
Locate 1 , 1                                                \'Типа печатаем символ
Lcd B


B = 0                                                       \'Разблокируем следующий цикл приема символа, пока не 0 прерывания работают вхолостую
Loop






\'Подпрограмма взятия символа из прерывания и предварительной обработки
Kbdinput:
Do
Loop Until Bcurr <> 0                                       \'ждем пока символ не упадет в буфер
B = Bcurr                                                   \'Буфер присваиваем универсальной переменной
Bcurr = 0                                                   \'Очищаем буфер
Bsimvol = Chr(b)                                            \'Всякая предворительная обработка символа
Bznac = Val(bsimvol)
Printbin B                                                  \'Контрольная печать в ком порт
Gosub Pik                                                   \'Пищим
Return

\'Обработчик прерывания
Kbd:
If B = 0 Then                                               \'Переменная пуста, можно заполнять буфер                                           \' буфер свободен
Bcurr = Getatkbd()                                          \' Что и делаем
Else                                                        \' Иначе
Dummy = Getatkbd()                                          \' Игнорируем все, пропуская символы
End If
Return


\'Пищалка
Pik:
Sound Speaker , 10 , 947
Return

Автор: Andy
« : 27 Сентября 2010, 08:47:32 »

Интерестно, обязательно попробую, у меня была подобная мысьль об этом, но я ее почему-то забраковал и в код она так и не отлилась...
Автор: pumpkin
« : 24 Сентября 2010, 18:53:44 »

Сорри за отсутствие, времени не было.

По теме.
Если делать по науке, надо организовать буфер клавиатуры, типа FIFO (first in – first out).
Обработчик прерывания добавляет в буфер очередную кнопку, если нет места в буфере – игнорирует нажатую кнопку.
Основной код в своем цикле извлекает из буфера очередной символ и обрабатывает его.
В простейшем случае буфер может иметь длину в один символ.

Например так:

Цитировать
\' B - это будет типа буфер
\' BCurr - текущий обрабатываемый символ, т.к. основной
\'         код не должен работать с буфером напрямую
\' Dummy - просто переменная

Dim B As Byte      
Dim BCurr As Byte
Dim Dummy As Byte    

\' Включаем прерывания и вешаем обработчик на клаву
\' Надеюсь правильно этот кусок написал ))

Enable Interrupts
On Int0 Kbd
Enable Int0

\'======= Как бы основной код =================
Do
If B <> 0 Then \' Если в буфере что-то есть,
BCurr = B      \'   то забираем символ в BCurr,
B = 0          \'   сбрасываем буфер
\' ..............................................................
\' .... Делаем обработку уже символа "BCurr", который не испортится, в "B" уже не лезем.
\' .... Рисуем на экране и т.д. Можно здесь пикнуть.
\' ..............................................................

End If
Loop
\' ============================================

\' Обработчик клавиатуры. Если буфер пуст (равен 0) загоняет в него нажатый символ,
\' иначе игнорирует нажатие

Kbd:
If B <> 0 Then \' буфер свободен
B = Getatkbd() \' загоняем в него символ
\' Здесь можно пикнуть
Else           \' буфер занят
Dummy = Getatkbd()  \' пропускаем нажатую кнопку
End If
Return
В результате чего, пока буфера не пустой, то новые нажатия будут игнорироваться. И обрабатываемый в текущий момент символ не будет неожиданно изменен на полпути, так как вся обработка идет над BCurr, который недоступен обработчику прерывания.

Но с другой стороны, если работет более простой код, то и усложнять не надо.