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

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

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

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


Вы здесь » Программирование ATMEL в BASCOM. » Вопросы - ответы » Вызов подпрограммы с частотой 1Гц


Вызов подпрограммы с частотой 1Гц

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

1

Доброго всем участникам времени! Подскажите, пожалуйста, начинающему...
Мне нужно, чтобы подрограмма вызывалась с частотой 1Гц, то есть 1 раз в секунду. Как я понимаю, логика следующая:

1. программируем таймер и делаем прерывание по нему
2. в подробграмме обработки прерывания огранизуем пропуск определённого количества запусков
3. после пропуска нужного количества - запускаем нужную подрограмму

К сожалению, я не смог найти информацию, как расчитать всё это дело, исходя из частоты кварца и частоты запуска подпрограммы. То есть как лучше подобрать кварц (может быть, чтобы его частота кратно делилась на какое-то число), как выбрать значение прескалера и какое количество запусков пропускать.

0

2

Я бы так сделал.
1. Кварц 8Мгц, Timer1 с прескалером 64. Прерывание каждые 0.5 сек.
2. В прерывании устанавливаем в 1 любую переменную (пример T1). Она будет являться флагом, что наступило прерывание.
3. Вводим программный счётчик Dim Count as Byte: Count=0
В основном теле программы:
Do
If T1=1 Then
incr Count
if count=2 then
.
что-то делаем
.
Count=0
end if
reset T1
Loop
end
Можно ещё сбрасывать значение таймера, что бы не считал до 65535, тогда программный счётчик Count уже будет не нужен:

Timer1:      'Обработчик прерывания Timer1
Stop Timer1
Timer1=50000 'Как пример, надо подбирать
set T1
start Timer1
Return
В таком случае флаг T1 будет устанавливаться 1 раз в сек., но в основном теле не забываем его сбрасывать.

Отредактировано Tankor (2015-10-01 21:05:23)

0

3

Ну или берём ХМега, ставим на вход часовой кварц (32768Гц), конфигурируем его и получаем выполнение подпрограммы/прерывание раз в сек (без всяких таймеров).

зы: кстати я заметил, что в этом семействе, эта штука как-то странно работает, попахивает настоящей мультизадачностью.  :crazyfun:

Отредактировано RDW (2015-10-01 22:04:53)

0

4

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

Ну или берём ХМега, ставим на вход часовой кварц (32768Гц), конфигурируем его и получаем выполнение подпрограммы/прерывание раз в сек (без всяких таймеров).

зы: кстати я заметил, что в этом семействе, эта штука как-то странно работает, попахивает настоящей мультизадачностью. 

Отредактировано RDW (Сегодня 22:04:53)

Таким макаром можно и на мегу на Timer2 поставить часовой.

+1

5

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

Мне нужно, чтобы подрограмма вызывалась с частотой 1Гц, то есть 1 раз в секунду

первый вариант, нужен кварц 32 768 Гц (часовой)

$map       ' Получаем карту распределения памяти компилятором Bascom
  $regfile = "m8def.dat"       ' Используемый контроллер
  $crystal = 1000000       ' 2000000  ' 4000000  ' 8000000
  $framesize = 32
  $hwstack = 40
  $swstack = 16

'Настройка TIMER2 в режиме асинхронного генератора
'Config Timer2 = Timer , Async = On , Prescale = 64 , Compare = Toggle       ' Делитель 32768 / 64 / 256 = 0,5 сек (прерывание TIMER2 = 2 раза в секунду)
  Config Timer2 = Timer , Async = On , Prescale = 128 , Compare = Toggle       ' Делитель 32768 / 128 / 256 = 1 сек (прерывание TIMER2 = 1 раз в секунду)
'Ссылка на подпрограмму обработчика прерывания TIMER2, для работы часов
  On Timer2 Обработка_прерывания_timer2 Nosave       ' Ссылка на подпрограмму обработчика прерывания TIMER2

  Dim Флаг_прерывание_timer2 As Byte

'--------------  Разрешаем работу необходимых прерываний  ----------------------
  Enable Timer2
'------------  Разрешаем работу всех включенных прерываний  --------------------
  Enable Interrupts
'===============================================================================

'                   Г Л А В Н Ы Й         Ц И К Л
  Главный_цикл:
'===============================================================================

      If Флаг_прерывание_timer2 <> 0 Then

          'Попадаете сюда 1 раз в секунду
          Gosub Ваша_подпрограмма

          Флаг_прерывание_timer2 = 0
          Goto Главный_цикл
      End If

   Idle
  Goto Главный_цикл
End
'===============================================================================

'               И С П О Л Ь З У Е М Ы Е    П О Д П Р О Г Р А М М Ы

'===============================================================================

'===============================================================================
  Ваша_подпрограмма:
'-------------------------------------------------------------------------------

    'Делаете то, что Вам нужно

'-------------------------------------------------------------------------------
  Return
'===============================================================================


'===============================================================================
' Подпрограмма обработки прерывания TIMER2, происходит 1 или 2 раза в секунду, в зависимости от настроек TIMER2
'===============================================================================
  Обработка_прерывания_timer2:
'-------------------------------------------------------------------------------
   'Сохраняем регистры, которые используем в обработке прерывания
    !Push R30

    !ldi R30 , 1
    !sts {Флаг_прерывание_timer2} , R30

   'Восстанавливаем ранее сохраненные регистры
    Выход_прерывание_timer2:
    !Pop R30
'-------------------------------------------------------------------------------
  Return
'===============================================================================

http://s6.uploads.ru/t/ueO8T.jpg


второй вариант, без кварца, прерывание каждые 1,0035 сек

$map       ' Получаем карту распределения памяти компилятором Bascom
  $regfile = "m8def.dat"       ' Используемый контроллер
  $crystal = 1000000       ' 2000000  ' 4000000  ' 8000000
  $framesize = 32
  $hwstack = 40
  $swstack = 16

'Настройка TIMER2
  Config Timer2 = Timer , Prescale = 1024       ', Compare = Toggle       ' Делитель 32768 / 128 / 256 = 1 сек (прерывание TIMER2 = 1 раз в секунду)
'Ссылка на подпрограмму обработчика прерывания TIMER2, для работы часов
  On Timer2 Обработка_прерывания_timer2 Nosave       ' Ссылка на подпрограмму обработчика прерывания TIMER2

  Dim Предустановка_timer2 As Byte : Предустановка_timer2 = 11
  Dim Количество_прерываний_timer2 As Byte : Количество_прерываний_timer2 = 3

  Dim Флаг_прерывание_timer2 As Byte
  Dim Счетчик_прерываний_timer2 As Byte : Счетчик_прерываний_timer2 = Количество_прерываний_timer2

'--------------  Разрешаем работу необходимых прерываний  ----------------------
  Timer2 = Предустановка_timer2
  Enable Timer2
'------------  Разрешаем работу всех включенных прерываний  --------------------
  Enable Interrupts
'===============================================================================

'                   Г Л А В Н Ы Й         Ц И К Л
  Главный_цикл:
'===============================================================================

      If Флаг_прерывание_timer2 <> 0 Then

          'Попадаете сюда 1 раз в секунду
          Gosub Ваша_подпрограмма

          Флаг_прерывание_timer2 = 0
          Goto Главный_цикл
      End If

   Idle
  Goto Главный_цикл
End
'===============================================================================

'               И С П О Л Ь З У Е М Ы Е    П О Д П Р О Г Р А М М Ы

'===============================================================================

'===============================================================================
  Ваша_подпрограмма:
'-------------------------------------------------------------------------------

    'Делаете то, что Вам нужно

'-------------------------------------------------------------------------------
  Return
'===============================================================================


'===============================================================================
' Подпрограмма обработки прерывания TIMER2, происходит 1 или 2 раза в секунду, в зависимости от настроек TIMER2
'===============================================================================
  Обработка_прерывания_timer2:
'-------------------------------------------------------------------------------
   'Сохраняем регистры, которые используем в обработке прерывания
    !Push R30

    !lds R30 , {Предустановка_timer2}
    !sts tcnt2 , R30

    !lds R30 , {Счетчик_прерываний_timer2}
    !tst R30       'Проверка на 0
    !BREQ Переустановка_таймера       ' Перейти если равно

    !dec R30       'Уменьшаем счетчик на 1

   'Восстанавливаем ранее сохраненные регистры
    Выход_прерывание_timer2:
    !sts {Счетчик_прерываний_timer2} , R30
    !Pop R30

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

  '----------------------------
   Переустановка_таймера:
    !ldi R30 , 1
    !sts {Флаг_прерывание_timer2} , R30

    !lds R30 , {Количество_прерываний_timer2}
    !rjmp Выход_прерывание_timer2
'-------------------------------------------------------------------------------
  Return
'===============================================================================

третий вариант, без кварца, прерывание каждые 1000 ms

$map       ' Получаем карту распределения памяти компилятором Bascom
  $regfile = "m8def.dat"       ' Используемый контроллер
  $crystal = 1000000       ' 2000000  ' 4000000  ' 8000000
  $framesize = 32
  $hwstack = 40
  $swstack = 16

'Настройка TIMER1
'Время в ms = 1000 * ((f_МК / Prescale) / (65536 - Предустановка_timer1))

'Время в ms = 1000 * ((1000000 / 64) / (65536 - 49911))
'Время в ms = 1000 * ((15625) / (15625))
'Время в ms = 1000 * 1

  Config Timer1 = Timer , Prescale = 64 , Clear Timer = 0
'Ссылка на подпрограмму обработчика прерывания TIMER1
  On Timer1 Обработка_прерывания_timer1 Nosave       ' Ссылка на подпрограмму обработчика прерывания TIMER1

  Dim Предустановка_timer1 As Word : Предустановка_timer1 = 49911

  Dim Флаг_прерывание_timer1 As Byte

'--------------  Разрешаем работу необходимых прерываний  ----------------------
  Timer1 = Предустановка_timer1
  Enable Timer1
'------------  Разрешаем работу всех включенных прерываний  --------------------
  Enable Interrupts
'===============================================================================

'                   Г Л А В Н Ы Й         Ц И К Л
  Главный_цикл:
'===============================================================================

      If Флаг_прерывание_timer1 <> 0 Then

          'Попадаете сюда 1 раз в секунду
          Gosub Ваша_подпрограмма

          Флаг_прерывание_timer1 = 0
          Goto Главный_цикл
      End If

   Idle
  Goto Главный_цикл
End
'===============================================================================

'               И С П О Л Ь З У Е М Ы Е    П О Д П Р О Г Р А М М Ы

'===============================================================================

'===============================================================================
  Ваша_подпрограмма:
'-------------------------------------------------------------------------------

    'Делаете то, что Вам нужно

'-------------------------------------------------------------------------------
  Return
'===============================================================================


'===============================================================================
' Подпрограмма обработки прерывания TIMER1
'===============================================================================
  Обработка_прерывания_timer1:
'-------------------------------------------------------------------------------
   'Сохраняем регистры, которые используем в обработке прерывания
    !Push R30

   'Переустанавлеваем TIMER1
    !lds R30 , {Предустановка_timer1 + 1}
    !sts tcnt1h, R30
    !lds R30 , {Предустановка_timer1}
    !sts tcnt1l, R30

    !ldi R30 , 1
    !sts {Флаг_прерывание_timer1} , R30

   'Восстанавливаем ранее сохраненные регистры
    !Pop R30

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



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

К сожалению, я не смог найти информацию, как расчитать всё это дело, исходя из частоты кварца и частоты запуска подпрограммы.


Выдал поиск:

тема

сообщение

ещё тема

Отредактировано sasha_1973 (2015-10-02 02:40:10)

0

6

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

Таким макаром можно и на мегу на Timer2 поставить часовой.

Точность RC генератора МК - сомнительная, всё зависит от задачи. В ХМега ненужно использовать никакие таймеры (внутренние ресурсы) и работает она одновременно от нескольких источников тактирования (один может быть вообще PLL (с разгоном ядра) и при этом независимый, точный отсчет). Да и вообще, сравнили тоже мне... :D

0

7

А что, у меги Timer2 зависимый ?  И при чём тут RC генератор? Повесить часовой кварц на Timer2 и пусть себе работает, ни кого не трогает, отсчитывает себе секунды. А МК может и поспать. А для вычислений стабильности RC хватит.

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

Да и вообще, сравнили тоже мне...

Ну конечно, на работу за углом мы на Бентли ездим, а не пешком, чё-тут сравнивать.

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

Подскажите, пожалуйста, начинающему...

Не боитесь, что  поцарапает? :hobo:

+1

8

Если я всё правильно понял, то нужно так:

- выбираем кварц такой, чтобы ровно делился на "разрядность" таймера (256 или 65536, в зависимости от таймера), и чтобы это значение нацело делилось затем на значение прескалера.

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

0

9

В идеале - да (всё правильно).

0

10

Давно сделал себе табличку для 8 и 16 битных таймеров. Может кому пригодится.
Частота и период переполнения.

http://s3.uploads.ru/t/4PXug.jpg

Отредактировано SIvan (2015-10-04 12:18:28)

+2

11

Немного упрощу способ №3 от sasha_1973 в 6-ом сообщении.

Для 10 МГц
Код:
$crystal = 10000000
$regfile = "m8def.dat"

$hwstack = 32
$swstack = 10
$framesize = 40

Config Timer1 = Timer , Prescale = 1024 , Clear Timer = 1
Ocr1a = 9766
On Oc1a Onesecond

Enable Interrupts
Enable Oc1a

Label1:
' =================
' Main programm
' =================
Goto Label1

Onesecond:
' =================
' Тут делается то, что нужно делать раз в секунду (Ну почти. Раз в 1.0000384 секунды)
' =================
Return

End
Для 8 МГц
Код:
$crystal = 8000000
$regfile = "m8def.dat"

$hwstack = 32
$swstack = 10
$framesize = 40

Config Timer1 = Timer , Prescale = 256 , Clear Timer = 1
Ocr1a = 31250
On Oc1a Onesecond

Enable Interrupts
Enable Oc1a

Label1:
' =================
' Main programm
' =================
Goto Label1

Onesecond:
' =================
' Тут делается то, что нужно делать раз в секунду
' =================
Return

End

Разница в $crystal, prescale и OCR1A.
Кратко: таймеру1 задано значение OCR1A, при совпадении с которым генерируется прерывание и таймер при этом обнуляется. Рассчитывать OCR1A нужно исходя из тактовой частоты МК, предделителя таймера (prescale)
Делим частоту МК на предделитель, получаем частоту, с которой считает таймер1. Делим единицу на полученную частоту, получаем количество времени между счетами таймера. Нужный нам "интервал срабатывания" (в данном случае 1 секунда) делим на это количество времени. Получаем значение для OCR1A.
8 000 000 / 256  =  31 250  Гц
1 / 31 250 = 0.000032 Сек
1 / 0.000032 = 31 250 (OCR1A)

10 000 000  /  1 024 = 9 765.625 Гц
1 / 9 765.625 = 0.0001024 Сек
1 / 0.0001024 = 9 765.625 = 9 766 (OCR1A)

Таким способом можно отмерять весьма точные интервалы. Правда, зависит от  точности кварца.

0

12

Для beginer!

Ещё один, довольно важный момент!

Не напутайте с фьюзами!

С завода, МК серии ATMEGA, идут с частотой 1 МГц, для всех манипуляций с частотой, нужно программировать фьюзы. Можно конечно и программно сменить частоту (правда, только в меньшую сторону), но наверно пока не стоит туда залазить.

Почитать можно:

здесь

здесь

здесь

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

Отредактировано sasha_1973 (2015-10-07 05:13:37)

0


Вы здесь » Программирование ATMEL в BASCOM. » Вопросы - ответы » Вызов подпрограммы с частотой 1Гц