Администрация форума не несёт ответственности за достоверность информации и оставляет за собой право редактировать или в особых случаях даже удалять посты без предупреждения. Спасибо за понимание.

Программирование ATMEL в BASCOM.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.



Таймер.

Сообщений 1 страница 30 из 35

1

Продолжаю дальше изучать AVR и BASCOM. Теперь возник вопрос по таймеру. По сравнению с  классическими контроллерами архитектуры MCS-51, в AVR таймеры имеют больше режимов работы . Но с этой гибкостью гибкостью необходимо разобраться.
Допустим, стоит задача сделать секундомер, который будет измерять время с точностью до сотых долей секунды. Тактируем контроллер от кристалла 4 МГц.
Моя логика работы в этом случае.  Выбираем режим сравнения с очисткой регистров таймера, делитель тактовой частоты =1.  Загружаем в регистр OCR1A значение 40000 и ждем прерывания. Получился вот такой код

Код:
$regfile = "m8def.dat"                                      'настройки
$crystal = 4000000
$hwstack = 40
$swstack = 16
$framesize = 32

Config Portd.6 = Input                                      'конфигурирование  портов

Config Timer1 = Timer , Prescale = 1 , Compare A = Set , Clear Timer = 1       'конфигурирование  таймера

'обЪявление  переменных
Dim Endtime As Word
Dim Counttime As Word

On Oc1a Compa                                               'подпрограмма  обраб. прерываний

Endtime = 40000

Compare A = Endtime                                         'задание предела  счёта  таймера
Counttime = 0                                               'очистим переменную

Enable Interrupts                                           'разрешение  прерываний
Enable Oc1a

Do                                                          ' ждем нажатия кнопки

Loop Until Portd.6 = 0
'"старт" счета времени

Start Timer1

Do                                                          ' ждем нажатия кнопки
Loop Until Portd.6 = 0
'"СТОП" счета
Stop Timer1

'вывод значения Counttime на индикатор
'дальше какой-то код
'
'


Compa:                                                      'обработка  препрывания
  Counttime = Counttime + 1
Return

End

В итоге, после компиляции в строке
Compare A = Endtime
ошибка 46 : Assigment error [COMPARE A:0 ENDTIME:6]

Не понятно из-за чего такой косяк вылазит? Что не так?

Отредактировано spin (2012-11-04 10:40:37)

0

2

Пример взят тут http://www.avr.ru/beginer/bascom/article3 . В моей версии хелпа по слову TIMER0, TIMER1 есть только структурная схема таймера и небольшое описание к этой схеме. Может у меня хелп к BASCOM'у урезанный?  o.O

Судя по datasheet'у, после перехода по прерыванию значение регистров TCNTxH и TCNTxL обнулятся. После этого счет будет идти дальше до достижения значения 40 000. Таким образом прерывание выполняться вечно не будет.

Но вопрос остался открытым - что это за ошибка 46, которую выдает компилятор?

Кроме того, в datasheet'е указывается, что с каждым тактом счетчик таймера может увеличиваться или уменьшаться. Это зависит от настроек таймера. Если делать вставки на асме, то ясно. Каким образом задавать эти настройки в BASCOM'е, не используя вставок на асме?

Отредактировано spin (2012-11-01 19:52:51)

0

3

Спасибо, конечно, за код. В этом коде мне понятно все. Ну и перезагружать таймер в прерывании - этот прием достаточно известный. Прошу меня сильно не пинать (простите "чайника"  :blush: ), но мне хочется разобраться более детально.
По-моему, в этом коде есть недостаток - выполнение прерывания выполняется не всегда одинаковое количество тактов. Иногда это кардинально может повлиять на точность разрабатываемого устройства. В некоторых случаях, при нехватке памяти для записи программы, можно будет оптимизировать этот кусок кода, использовав аппаратные возможности контроллеров, которые заложены разработчиками.
Т.е. хочется понять - это ограниченные возможности самого BASCOM'a или неумение использовать его возможности.

В приведенном мной листинге программы речь идет об ATMega8. Вот на нем попробую остановиться.

RDW написал(а):

В АТмегах: все таймера как правило нужно перегружать самому (ручками/в коде), счет идёт в большую сторону.

Смотрим datasheet ATMega8, стр. 87, режим Clear Timer on Compare Match (CTC) . Там говорится, что при достижении счетчика (TCNT1) значения, которое хранится в регистрах OCR1A или ICR1, генерируется прерывание и сбрасывается значение счетчика (режим сброса по совпадению). Т.е. в этом режиме можно не беспокоиться: счетчик сбросится сам, аппаратурно. Вот и есть соблазн использовать именно этот режим в случае секундомера. Или я чего-то не так понял?
Теперь, после выбора режима работы таймера, осталось описать все это в листинге. Токмо не понятно как без вставок на асме...  :confused:

P.S. Режим таймера по совпадению похож на режим таймера с автозагрузкой архитектуры MCS-51 (хочешь-не хочешь, а все таки аналогии какие-то проводятся сами по себе). С MCS-51 я знаком значительно лучше, чем с AVR.

0

4

Вопрос решился. Ошибка была в строке Compare A = Endtime. Надо было написать Compare1a = Endtime и все работает  :blush:

Вот этот кусок компилится без проблем

Код:
$regfile = "m8def.dat"                                      'настройки
$crystal = 4000000
$hwstack = 40
$swstack = 16
$framesize = 32

Config Portd.6 = Input                                      'конфигурирование  портов

Butt Alias Portd.6

Config Timer1 = Counter , Edge = Falling , Compare A = Set , Clear Timer = 1
       'конфигурирование  таймера
Dim Counttime As Word

Dim Endtime As Word

On Oc1a Compa                                               'подпрограмма  обраб. прерываний

Endtime = 40000                                             'задание предела  счёта  таймера

Compare1a = Endtime
Counttime = 0                                               'очистим переменную

Enable Interrupts                                           'разрешение  прерываний
Enable Oc1a

Do                                                          ' ждем нажатия кнопки

Loop Until Butt = 0
'"старт" счета времени

Start Timer1

Do                                                          ' ждем нажатия кнопки
Loop Until Butt = 0
'"СТОП" счета времени
Stop Timer1

'вывод значения Counttime на индикатор
'
'
'


Compa:                                                      'обработка  препрывания
  Incr Counttime
Return

End

0

5

Я не говорил, что в Вашем коде есть ошибки и он не прозрачен.  Напротив - все понятно.
Но я только начинаю изучать AVR и BASCOM. Т.е. мне хочется знать возможности камня и понять как им управляет BASCOM. Нашел в в datasheet'е такой режим работы таймера. Захотелось попробовать реализовать этот режим на практике.  Кроме того, в этом режиме можно подцепить на ногу светодиод и железка сама будет им мигать. Или генерировать какой-то сигнал на этом выводе, используя возможности камня.
Пример кода - это всего лишь "проба пера".

RDW написал(а):

И ещё, команда "INCR" увеличивает только 1 регист, т.е. байт, на word - скорее всего не будет корректно работать.

В хелпе указывается, что инкрементируется именно переменная, а не регистр. Симулятор то же инкрементирует переменную. В железе пока не пробовал...

0

6

Доброй ночи! Вопрос знатокам "Bascom" возможно ли применение таймера для обработки нажатия кнопок? у меня проблема с дребезгом контактов, постоянно проскакивает  меню, приходится возвращаться в исходную позицию.  Если есть пример реализаций будьте добры помогите. в прерываний через INT0 не все гладко, с задержками туго работает использую микроконтроллер Атмега16 .

0

7

Toha написал(а):

возможно ли применение таймера для обработки нажатия кнопок?

Да. :) Хорошо сочетается с динамической индикацией по таймеру (если кнопок не больше чем разрядов индикатора). :)

0

8

Дабы не плодить темы, спрошу здесь. ;)

Споткнулся об настройку таймера на минимум.
Конечная задача - получить прерывание не более, чем каждые 5 мксек.
Тактирование - RC 8 МГц. Только RC.

Получается:
С таймером2

Код:
'Config Timer2 = Timer , Prescale = 1 , Compare A = Toggle

Enable Compare2a
OCR2A = 1
On Compare2a Pulse:               'подпрограмма обработки прерывания Timer2
Enable INTERRUPTS                'включение прерываний

Получаем прерывание через 30 мксек !
http://s8.uploads.ru/t/jCpZW.jpg
С задержками на Waitus

Код:
tim = 3

Do

PORTC.0 = 0
Waitus tim
PORTC.0 = 1
Waitus tim

Loop

Получаем переключение пина каждые 5 мксек
http://s3.uploads.ru/t/NRyUP.jpg
Настройки ЛА в Протеусе одинаковы в обоих случаях.

Вот тут и вопросы...
Неужели аппаратный таймер не умеет работать быстрее, чем Waitus ?
Как же тогда эти "уайты" отсчитываются, если таймеры такие медленные ? ;)

0

9

Попробуй OCR2A =215

0

10

bulat943 написал(а):

Попробуй OCR2A =215

Пробовал... Начал с 260.
Если бы было все так просто... ;)

Как-то раньше, работая с бОльшими интервалами, проблем не было...
А тут надо очень короткие получить.

Вводит в заблуждение еще, что один такт МК при 8 МГц получается в 0,125 мксек (1 / 8000000 = 0,000_000_125 сек).
Значит, при Prescale = 1 требуется отсчитать 5 мксек / 0,125 мксек = 40 тактов.
Или те же OCR2A = 215...
Однако, фактически получается, что эти 40 (в моем случае 30) тактов "кто-то" отсчитывает без меня... ;)
Причем, если OCR2A = ... будет больше 3, то длительность начинает возрастать...

0

11

а зачем Compare2a?это же прерывание по совпадению...когда таймер досчитает до OCR2A =1 сработает прерывание
сделайте проще-
Config Timer2 = Timer , Prescale =1
Timer2pre=215
On timer2 Pulse
..........
Pulse:
Timer2 =Timer2pre
toggle PORTC.0
return

0

12

bulat943 написал(а):

а зачем Compare2a?это же прерывание по совпадению...

Пришел к этому варианту в ходе поисков решения... ;)

Попробовал предложенное - ЛА Протеуса показывает 45 мксек...

0

13

Можно программу и протеус,опробую

0

14

bulat943 написал(а):

Можно программу и протеус,опробую

https://yadi.sk/d/STxt4spRlWE6tQ

0

15

Nord написал(а):

Конечная задача - получить прерывание не более, чем каждые 5 мксек.
Тактирование - RC 8 МГц. Только RC.

200 тысяч прерываний в секунду, т. е. каждые 40 тактов. Подпрограмма прерываний должна быть с флагом Nosave и написана на ассемблере с сохранением требуемых регистров. И выполнение должно занимать не больше 30 тактов.

Nord написал(а):

Однако, фактически получается, что эти 40 (в моем случае 30) тактов "кто-то" отсчитывает без меня

Тратится время на вход и выход из прерывания и сохранение и восстановление регистров.

Зачем это понадобилось? Возможно есть другие способы решения.
Потому что 200 тысяч прерываний это много.
МК не сможет ничего делать кроме как обрабатывать прерывания.

0

16

Скорее всего так и есть,не успевает...

0

17

Пётр написал(а):

Зачем это понадобилось? Возможно есть другие способы решения. Потому что 200 тысяч прерываний это много. МК не сможет ничего делать кроме как обрабатывать прерывания.

Минимальный тайм-слот в протоколе 1-Wire - 5 мксек.
Отсюда и пляшем...
Воюю с 1-Wire Slave... ;)

В протоколах передачи WS2812 тоже мксек, но там как-то успевается все... ;)
Правда, частоту МК приходится задирать до 16 МГц.

Если не получится решить этот вопрос, то придется забросить этот проект на уровне Bascom...

0

18

Вместо waitus 5 попробуйте вставить
$asm
ldi  r18, 13
L1:
   dec  r18
    brne L1
    nop
$end Asm

Отредактировано bulat943 (2019-01-13 18:28:02)

0

19

bulat943 написал(а):

Вместо waitus 5 попробуйте

Этот вариант тоже имеется в виду, но изначально вопрос не в этом...

Протокол 1-Wire...
Инициализация ведомых:
- мастер опускает шину в "0" на 480 мксек
- мастер "отпускает" шину
- через 5...15 мксек мастер проверяет шину
- ведомый опускает шину в "0" на 120 мксек (не менее)
- мастер: если на шине "0" - значит "кто-то есть"

Вот и фишка - надо отсчитать 5...15 мксек (один-три тайм-слота), чтоб выдать сигнал присутствия.
Как вариант, можно отслеживать состояние шины и плясать уже отсюда, но тогда "плывут" временнЫе параметры протокола.
Вот тут Эмуляция 1-Wire устройства я уже наступил на эти грабли изначально... ;)
Поэтому пошел по пути отсчета тайм-слотов, чтоб соблюсти временнЫе параметры...

0

20

У меня вопрос по таймеру.
Регулирую яркость светодиода с помощью таймера.
В прерывании таймера пишу:

Код:
   Set Led
    Ocr2a = Br_led

Далее его тушу по совпадению.
Баском делает так

Код:
ldi R26,$3f
ldi r27,$01
ld r24,x
sts 00b3,r24

Можно ли сократить так?

Код:
  !lds r24,{Br_led }
  Ocr2a = R24

0

21

kip написал(а):

Можно ли сократить так?

В чем смысл ?
Оба шага - одно и то же... ;)

0

22

смысл в скорости обработки прерывания, и размере кода. Параллельно на таймере 0 работает динамическая индикация. Соответственно прерывание таймера 2 вносит артефакты в индикацию. Скорость обработки прерывания критична. Кроме того, сохранять/восстанавливать регистры 1 или 3 разница есть? Итого, скорость обработки моего варианта существенно быстрее, чем баскома.
В железе загрузил, пока работает. Но в асме не силён. По этому и вопрос, правильно или нет.

0

23

kip написал(а):

смысл в скорости обработки прерывания, и размере кода. Параллельно на таймере 0 работает динамическая индикация. Соответственно прерывание таймера 2 вносит артефакты в индикацию. Скорость обработки прерывания критична. Кроме того, сохранять/восстанавливать регистры 1 или 3 разница есть? Итого, скорость обработки моего варианта существенно быстрее, чем баскома. В железе загрузил, пока работает. Но в асме не силён. По этому и вопрос, правильно или нет.

Bascom откровенно тормозит на циклах и дисплеях (они сами тормозные).

Задача заменить эту строку ?
Ocr2a = Br_led

Она будет выполняться одинаково, т.к. по сути - практически асс. операция...
!Ocr2a = { Br_led )

0

24

'=======================================
  Обработка_прерывания_compare2a:
'----------------------------------------------------------------------

    !push R16   'Сохранение регистра

    !lds R16 , {Br_led}
    !sts Ocr2a , R16

    !pop R16    'Восстановление регистра

    !reti        'Выход из прерывания

'----------------------------------------------------------------------
  Return            'На всякий случай
'=======================================

При условии, что "Br_led"  -  байтовая переменная

+1

25

А насколько это быстрее, чем Ocr2a = Br_led ?

Отредактировано Nord (2019-04-27 18:04:23)

0

26

Nord, я ж вроде расписал выше. Привёл код, что формирует баском. Он задействует регистры 27 и 26, кроме 24. Которые ещё и перед/после прерывания нужно сохранять/восстанавливать. В общем перечитай пост выше.
-----------------------------------------------------------------
Конечно байтовая. Таймер то 8 битный. Иначе конфликт.
Спасибо, Саша.

0

27

kip написал(а):

Он задействует регистры 27 и 26, кроме 24


Не факт, можете потерять данные. Лучше сохранить и восстановить 1 регистр, чем иметь глюк или срыв крыши у МК.

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

0

28

Nord написал(а):

А насколько это быстрее, чем Ocr2a = Br_led ?


Не быстрее, но неизвестно какой регистр будет использован при текущей компиляции.

+1

29

Я смотрю в протеусе, дизасемблер. Он мне и показывает, что делает баском.
http://sd.uploads.ru/t/mpPE2.jpg

0

30

kip написал(а):

Nord, я ж вроде расписал выше. Привёл код, что формирует баском. Он задействует регистры 27 и 26, кроме 24. Которые ещё и перед/после прерывания нужно сохранять/восстанавливать.

Там вопрос звучал "Можно ли сократить так?"... ;)
Александр объяснил (обоим) ;)

sasha_1973 написал(а):

но неизвестно какой регистр будет использован при текущей компиляции.

Следовательно - надо отследить неиспользуемый в данный момент регистр.

0