|
|
  |
Не получается записать в регистр TCNT0 таймера, Atmega8515 |
|
|
|
May 24 2015, 07:59
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 13-03-09
Из: Москва
Пользователь №: 46 073

|
Приветствую! Хочу сформировать интервал времени по таймеру В даташите Atmega8515 написано, что можно напрямую работать с регистром TCNT0 таймера Делаю побитную инверсию этого регистра com TCNT0 Получаю ошибку компиляции test_1.asm(158): error: Invalid register т.е. как я понимаю, мой проект в AVR не понимает имя этого регистра При этом на определение PORTB компилятор не ругается out PORTB,temp_inv и на включение/ выключение таймера тоже не ругается clr temp_timer out TCCR0,temp_timer Описание в начале программы есть: .include "8515def.inc" Что не так ?
Сообщение отредактировал esr - May 24 2015, 08:00
|
|
|
|
|
May 24 2015, 08:11
|
Местный
  
Группа: Участник
Сообщений: 326
Регистрация: 30-05-06
Пользователь №: 17 602

|
Цитата(esr @ May 24 2015, 11:59)  Приветствую! Хочу сформировать интервал времени по таймеру В даташите Atmega8515 написано, что можно напрямую работать с регистром TCNT0 таймера Делаю побитную инверсию этого регистра com TCNT0 Что не так ?  А с какими регистрами может работать команда com ? Может быть, в этом причина?
|
|
|
|
|
May 24 2015, 16:38
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 13-03-09
Из: Москва
Пользователь №: 46 073

|
Цитата(mcheb @ May 24 2015, 12:11)  А с какими регистрами может работать команда com ? Может быть, в этом причина? Спасибо откликнувшимся, да действительно в этом причина была. Вот так получилось, через промежуточный регистр: ; Инвертируем регистр таймера TCNT0 через считывание - инверсию -обратную запись с помощью промежуточного регистра clr temp_inv in temp_inv,TCNT0 ; Переписываем из регистра (счётчика) таймера в промежуточный регист com temp_inv ; Инвертируем побитно в промежуточном регистре out TCNT0,temp_inv ; Записываем обратно в таймер инвертированное значения Ну и потом запускаю заново таймер и дальше идёт программа. Оказывается этот регистр (счётчик) TCNT0 не регистр вовсе, а порт получается ? Потому что с ним команда in прошла, которая для портов ввода-вывода действует ? А это в документации и не отражено нигде вроде бы .... Цитата(Xenia @ May 24 2015, 12:41)  А зачем вы это делаете? Если вы работаете с таймером 0 по прерыванию (переполнение), то в TCNT0 надо константу записывать, а не инверсию ему делать. Так задача поставлена. Надо сначала интервал в таймере накопить, потом его считать оттуда, а потом в течение этого интервала нечто выполнять. Поэтому эту константу для записи нужно из этого-же таймера и доставать.
Сообщение отредактировал esr - May 24 2015, 16:39
|
|
|
|
|
May 25 2015, 07:23
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 13-03-09
Из: Москва
Пользователь №: 46 073

|
Цитата(rx3apf @ May 25 2015, 02:30)  Это как бы самоочевидно из архитектуры AVR и вполне внятно описано в даташитах - регистры периферийных устройств, конфигурации, собственно портовые ноги это пространство ввода/вывода. Арифметические и логические команды работают только с регистрами общего назначения r0...r31 (с некоторыми ограничениями). Да, конечно, теперь уже немного становится очевидно. После того как довольно много времени у меня ушло на разбор этой ошибки. Цитата(demiurg1978 @ May 25 2015, 06:33)  Чуть позже вы столкнетесь с тем, что временных интервалов требуется несколько, а у ATMEGA8515 всего два аппаратных таймера. Если вам нужны времянки от мс и выше, и особая точность не нужна, то вам нужны "программные таймеры". А это как? По прерыванию от кнопки начать бесконечный программный цикл и выходить из него по следующему прерыванию от кнопки? Пример кода можете показать ?
|
|
|
|
|
May 25 2015, 07:56
|
Местный
  
Группа: Участник
Сообщений: 333
Регистрация: 19-12-13
Из: Новосибирск
Пользователь №: 79 709

|
Кнопка - человеко-интерфейс. А значит очень медленный. Кнопки можно и нужно опрашивать в основном цикле. Для создания временных интервалов, задержек - программные таймеры. Примерное описание, что это такое. Есть аппаратный таймер, который отщелкивает каждое заранее определенное время. Скажем, 1 мс. В прерывании таймера устанавливаем флажок. В обычном цикле проверяем флажок. Если он сброшен, выходим. Если установлен, дальше уже зависит от реализации. У меня сделано так: очередь таймеров. Структура: статус таймера, счетчик. Когда флаг установлен, перебираем очередь таймеров. Если таймер активен, декремент счетчика. Если не ноль, следующий таймер. Если ноль, в статусе устанавливаем флаг, следующий таймер, пока не закончится очередь таймеров.
|
|
|
|
|
May 25 2015, 16:13
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 13-03-09
Из: Москва
Пользователь №: 46 073

|
Цитата(demiurg1978 @ May 25 2015, 11:56)  У меня сделано так: очередь таймеров. Структура: статус таймера, счетчик. Когда флаг установлен, перебираем очередь таймеров. А что значит очередь таймеров? Их там всего два ?
|
|
|
|
|
May 25 2015, 19:06
|
Местный
  
Группа: Участник
Сообщений: 333
Регистрация: 19-12-13
Из: Новосибирск
Пользователь №: 79 709

|
Аппаратных два. А программных можно наделать хоть несколько десятков. CODE //======================================================================== .equ ST_TCNT = TCNT0 .equ ST_TIMSK = TIMSK .equ ST_OCIE = OCIE0 .equ ST_OCR = OCR0 .equ ST_TCCR = TCCR0 .equ CS0 = CS00 .equ CS1 = CS01 .equ CS2 = CS02 //========================================================================
//======================================================================== .equ SYS_TICK = 1 // Период системного таймера 1 мс //========================================================================
//======================================================================== .equ ST_SIZE = 2 //========================================================================
//======================================================================== //--------------------- Флаги системных таймеров ------------------------- Def_Flag SYS_TICK_FLG //------------------------------------------------------------------------
//------------------------------------------------------------------------ .equ ST_UNLOCK_FLG = 0 // Флаг активности таймера. .equ ST_TIME_OUT_FLG = 1 // Время вышло. //========================================================================
.dseg
//======================================================================== //-------------------- Очередь системных таймеров ------------------------ .set NUM_ST = -1 .set ST_QUANTITY = 0
.macro Def_Sys_Timer .set NUM_ST = (NUM_ST+1) .set ST_QUANTITY = (ST_QUANTITY+1) .set @0 = NUM_ST .message "System Timer Defined!" .endmacro
Def_Sys_Timer ST_DRV_LCD Def_Sys_Timer ST_KBD Def_Sys_Timer ST_PROC_GAME_1 Def_Sys_Timer ST_PROC_GAME_2
ST_CNT_QUEUE: .byte ST_QUANTITY*(ST_SIZE+1) //========================================================================
.cseg
//======================================================================== .macro Init_System_Timer clr r16 out ST_TCNT, r16 in r16, ST_TIMSK sbr r16, 1<<ST_OCIE out ST_TIMSK, r16 outi ST_OCR, (XTAL/64/1000) in r16, ST_TCCR sbr r16, 1<<CS0 | 1<<CS1 out ST_TCCR, r16 .endmacro
.macro ReRun_Sys_Timer in r16,ST_OCR subi r16,-(XTAL/64/1000) out ST_OCR,r16 .endmacro //========================================================================
//======================================================================== Sys_Timer_Comp: push r16 in r16,SREG push r16
ReRun_Sys_Timer
sbr FLAGS,1<<SYS_TICK_FLG
pop r16 out SREG,r16 pop r16 reti //========================================================================
//======================================================================== //-------------------------- Установка таймера --------------------------- .macro par_timer .db @0, @1, tab_l(@2) .endmacro
.macro Set_Timer ldi r17,HIGH(@0*2) ldi r16,LOW(@0*2) rcall _Set_Timer .endmacro
_Set_Timer: push XL push XH push ZL push ZH movw ZH:ZL, r17:r16 lpm XL,Z+ mov r16,XL lsl XL add XL,r16 clr XH subi XL,LOW(-ST_CNT_QUEUE) sbci XH,HIGH(-ST_CNT_QUEUE) ldi r17, 3 _Set_Timer_Cycle: lpm r16, Z+ st X+, r16 dec r17 brne _Set_Timer_Cycle pop ZH pop ZL pop XH pop XL ret //------------------------------------------------------------------------
//-------------------------- Проверка таймера ---------------------------- .macro Proc_Timer ldi r17,HIGH(@0*2) ldi r16,LOW(@0*2) rcall _Proc_Timer .endmacro
_Proc_Timer: push XL push XH push ZL push ZH movw ZH:ZL, r17:r16 lpm XL, Z+ mov r16, XL lsl XL add XL, r16 clr XH subi XL,LOW(-ST_CNT_QUEUE) sbci XH,HIGH(-ST_CNT_QUEUE) clt ld r16, X ldi r17, 1<<ST_TIME_OUT_FLG and r17, r16 breq Proc_Timer_End st X, r16 set Proc_Timer_End: pop ZH pop ZL pop XH pop XL ret //========================================================================
//======================================================================== Service_Timers: // Служба таймеров. sbrs FLAGS,SYS_TICK_FLG // Флаг очередного отсчета системного таймера установлен? ret // Нет, выход. cbr FLAGS,1<<SYS_TICK_FLG // Установлен, сброс флага. ldy ST_CNT_QUEUE // Указатель на начало очереди системных таймеров. clr CNT Service_Timers_ST_Cycle: ld r16,Y // Считывание байта-статуса системного таймера. sbrs r16,ST_UNLOCK_FLG // Таймер заблокирован? rjmp Process_Next_System_Timer // Да, переход к обработке следующего таймера. ldd r24,Y+1 // Считывание младшего байта таймера. ldd r25,Y+2 // Считывание старшего байта таймера. sbiw r24,1 // Уменьшаем значение таймера на единицу. std Y+1,r24 // Сохранение значения таймера. std Y+2,r25 // Сохранение значения таймера. brne Process_Next_System_Timer // Если время не вышло, то переход к обработке следующего таймера. sbr r16,1<<ST_TIME_OUT_FLG // Установка флага завершения работы таймера. Save_ST_Flags: st Y,r16 // Запись статуса таймера. Process_Next_System_Timer: adiw YL,3 // Смещение указателя на следущий таймер. inc CNT cpi CNT,ST_QUANTITY // Значение счетчика таймеров равно количеству таймеров? brlo Service_Timers_ST_Cycle // Меньше, обрабатываем следующие таймеры. Service_Timers_End: ret //========================================================================
Пример применения: CODE //======================================================================== Main: wdr rcall Service_Timers rcall Drv_Lcd rcall KBD_DRV rcall Proc_Game rjmp Main //========================================================================
//======================================================================== Keys_None: sbrs FSM_FLAGS, KEYS_PRESSED_FLG // Если что-то нажато, то пропуск команды. ret Read_Keys_Current Save_Keys_Prev // Сохранение текущего состояния клавиатуры. Set_Timer Par_Tim_Debounce // Установка задержки устранения дребезга. Set_State _KEYS_DOWN ret
Keys_Down: Proc_Timer Par_Tim_Debounce brtc Keys_Down_End sbrs FSM_FLAGS, KEYS_PRESSED_FLG rjmp Keys_Set_None Comp_Last_Curr_Keys breq Keys_Down_A rjmp Keys_Set_None Keys_Down_A: setb FSM_FLAGS, DEFINE_KEYS_FLG #if (HOLD==NO) rjmp Keys_Set_Wait_Up #elif (HOLD==YES) Set_Timer Par_Tim_Hold Set_State _KEYS_HOLD #endif Keys_Down_End: ret
Par_Tim_Debounce: par_timer ST_KBD, 1<<ST_UNLOCK_FLG, DEBOUNCE_DELAY
|
|
|
|
|
May 26 2015, 05:41
|
Знающий
   
Группа: Свой
Сообщений: 708
Регистрация: 8-05-11
Из: Чг
Пользователь №: 64 861

|
Цитата(esr @ May 25 2015, 19:13)  А что значит очередь таймеров? Их там всего два ? кстати очень полезно будет для начинающих про софтовые таймеры и прочие основные идеи работы с мелкими мк: "Осевые технологии. Пишем свою микрооперационную систему " в хакере (журнал такой, официально издающийся) 123, 2009 или (возможно, автор тот же, не знаю точно) тут http://easyelectronics.ru/avr-uchebnyj-kur...a-vvedenie.html
|
|
|
|
|
May 26 2015, 17:41
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 13-03-09
Из: Москва
Пользователь №: 46 073

|
Цитата(demiurg1978 @ May 25 2015, 23:06)  Аппаратных два. А программных можно наделать хоть несколько десятков. ... Спасибо! То что надо для моего проектика. Цитата(Onkel @ May 26 2015, 09:41)  "Осевые технологии. Пишем свою микрооперационную систему " ... Это для меня ещё рановато смотреть.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|