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

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

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

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


Вы здесь » Программирование ATMEL в BASCOM. » Таймеры, ШИМ и все про них » Timer1 Выдаёт одно и тоже значение


Timer1 Выдаёт одно и тоже значение

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

1

$regfile = "m8def.dat"                                      'проц
$crystal = 8000000                                          'частота

Config Lcd = 16 * 2                                         ' конфигурация дисплея
Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.5 , Db6 = Portb.6 , Db7 = Portb.7 , E = Portc.1 , Rs = Portc.0

Dim A As Word                                               'переменные
Dim T As Single                                             'переменные
Dim F As Single                                             'переменные
Dim C As Single                                             'переменные
Dim D As Single                                             'переменные
Dim E As Single                                             'переменные

On Int0 Padschet                                            'При прерывании перейти на метку Padschet

Config Int0 = Rising

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

Config Timer1 = Timer , Prescale = 1                        ' конфигурация таймера1
Stop Timer1                                                 'останавливаем
Timer1 = 0                                                  'оюнулим его
D = 1.25                                                 
Enable Int0                                                 'разрешаем прерывани

Do                                                          'Начало цикла

Loop                                                       'Конец чикла

Padschet:
Stop Timer1                                                 'останавливаем
Disable Int0

A = Timer1                                                  'забираем данные, которые пришли за время таймера 1

T = D * A
E = T
F = 1 / E
Waitms 100                                                  'задержка 0.25 с
Cls                                                         'Очищаем дисплей
'Lcd "F = "                                                  'Выводим на дисплей F =
Lcd A                                                       'Выводим на дисплей значение переменной F

Timer1 = 0

Enable Int0
Start Timer1                                                'запускаемTimer1
Return

0

2

Таймер нужно разрешить, попробуй так:

On Int0 Padschet                                            'При прерывании перейти на метку Padschet

Config Int0 = Rising
Config Timer1 = Timer , Prescale = 1                        ' конфигурация таймера1
Stop Timer1                                                 'останавливаем
Timer1 = 0                                                  'оюнулим его
D = 1.25                                                 

Enable Int0                                                 
Enable Timer1
Enable Interrupts                                           'разрешаем прерывание

Здесь можно так:
Padschet:
A = Timer1                                                  'забираем данные, которые пришли за время таймера 1

'Stop Timer1                                                 'останавливаем
Disable Int0

Отредактировано Karavan (2008-04-23 15:21:24)

0

3

Ничего не вышло переменная А = 119 хотя время прерывания Int0 разное. Я уже 4 дня никак ни въеду как мне мерять время между прерываниями.

0

4

А если попробывать написать через If Pinb.0 = 1 Then Goto  Padschet:
Что думаете? Завтра папробую.

0

5

У меня в такой последовательности всё работало на комментарии внимания не обращай это просто кусок программы:
      Config Timer3 = Timer , Prescale = 64                 'конфигурим таймер3.
      Config Int0 = Rising                                              'конфигурим прерывание
      On Timer3 Sonar                                       'Если счётчик переполнен, то идём в Sonar
      On Int0 _echo                                         'Если получили эхоОтвет, то идём в _echo

'      Enable Timer0                                         'СЮДА ВООБЩЕ НЕ СМОТРИМ расстояние до объекта или глубина

Enable Timer3                                               'периодичность запросов в случае отсутствия эха
'       in      r24, ETIMSK                                  'СЮДА ВООБЩЕ НЕ СМОТРИМ
'      ori     r24, 4                                            'СЮДА ВООБЩЕ НЕ СМОТРИМ
  '     !Out ETimsk , R24                                'СЮДА ВООБЩЕ НЕ СМОТРИМ
'       Etimsk = 1                                           ''СЮДА ВООБЩЕ НЕ СМОТРИМ Enable Timer3'периодичность запросов в случае отсутствия эха

Enable Int0                                                 ' РАЗРЕШИМ ВНЕШНЕЕ прерывание, вызываемое декодером эхо-сигнала
'       Eimsk = 1                                            'Enable Int0 прерывание, вызываемое декодером эхо-сигнала
'ЕСЛИ ИСПОЛЬЗУЕТСЯ НЕСКОЛЬКО ПРЕРЫВАНИЙ, ТО НАДО ДЕЛАТЬ ТАК vvv
'       in      r24, EIMSK                            'СЮДА ВООБЩЕ НЕ СМОТРИМ
'      ori     r24, 1                                    "ЭТО ПРОСТО ПАМЯТКА, ЧТОБЫ НЕ ЗАБЫТЬ
  '     !Out Eimsk , R24

      Start Timer3                                          'запустить таймер отсчёта периодов
'ДАЛЕЕ ВСТАВЛЯЕШЬ СВОИ ПРОЦЕДУРЫ ОБРАБОТКИ ПРЕРЫВАНИЙ, НАПРИМЕР:
     Sonar:
..................
Return                                     
_echo:
       Exo = Timer0
       If Exo > 127 Then Exo = 127
       If G(nn) = Exo Then Incr Color(nn)                   'Добавить изменение цвета
       If G(nn) < Exo Then                                  'Timer0
       Incr Nn
       Color(nn) = 0
        G(nn) = Exo                                         'Timer0
       End If
Return           

через "IF" работать будет, но проц грузится на 100%, ЛУЧШЕ РАЗОБРАТЬСЯ С ПРЕРЫВАНИЕМ

Отредактировано Karavan (2008-04-24 11:05:00)

0

6

Нихрена не понятно!

0

7

ПЕРЕКОММЕНТИРОВАЛ у меня всё работало через прерывание, правда на 128 меге, я думаю, что это не принципиально.

Отредактировано Karavan (2008-04-24 11:23:57)

0

8

Ты компилировал мой код? Проверял в железе или протеусе?
Мог не править, я понял где ковычки то не то.

Отредактировано Set (2008-04-24 11:49:04)

0

9

Нет, я делал подобный алгоритм на железе. Куски из него и привёл в посте. всё работало по прерыванию. Попробуй изменить прескалер. У меня кажется он глючил иногда

0

10

Что такое прескалер :|
У тубя какая версия компилятора

0

11

Ага прескалер -предделитель .
Ночная смена сказывается

0

12

Это твоя строка: Config Timer1 = Timer , Prescale = 1
А это - моя: Config Timer3 = Timer , Prescale = 64                 'конфигурим таймер3.
                                                                   ^ ^
прескалер - это делитель опорной частоты
может в Асю?

Отредактировано Karavan (2008-04-24 12:23:47)

0

13

Да нет я понял, Тормажу. Я чуть выше написал. Попробывал, эфект 0 только значения разные

Отредактировано Set (2008-04-24 12:32:36)

0

14

частотомер чтоли лепишь?

0

15

4 в 1
Ещё саветы будут?
Стоп у тебя в программе при переполнении таймера происходит прерывание и прога идёт на метку Sonar. У меня этого нет и при переполнении он начинает считать сначала или нет?

Отредактировано Set (2008-04-24 12:47:03)

0

16

Попробуй может подойдёт. Вроде работала когда-то.

$regfile = "M8def.dat"
$crystal = 4000000
$baud = 19200

Dim W As Word , Channel As Byte , Ugol As Word              'Single
Dim Period As Word

Config Int0 = Rising
Config Adc = Single , Prescaler = Auto , Reference = Avcc
Config Lcd = 16 * 2                                         'configure lcd screen
Config Timer1 = Timer , Prescale = 64

Stop Timer1
Timer1 = 0
Cursor Off
Cls
'Now give power to the chip
Enable Int0                                                 'enable the interrupt
Enable Interrupts

On Int0 Int0_int                                            'Initialise the INT0 Interrupt
Rem On Int0 Int0_int Nosave     'Initialise the INT0 Interrupt
Rem Use The Nosave Option When You Dont Want The Internal Registers To Be Saved/restored In
Rem The Interrupt Routine

  Start Adc
Rem The Interrupt Handler For The Int0 Interrupt
Rem                        Дроссель
      Locate 1 , 4 : Lcd "аpocce»Д"                         '; Ugol
      Locate 1 , 16 : Lcd "%"
Channel = 6
Do
         Locate 2 , 1 : Lcd Period ; "  "
Ugol = 10 * W                                               '
Ugol = Ugol / 102                                           '
  Waitms 10                                                 '0
      Select Case Ugol                                      'УБИРАЕМ ДРОЖАНИЕ
      Case Is < 10                                          'ЗНАЧЕНИЙ ADC НА
      Locate 1 , 13 : Lcd "  " ; Ugol                       'ДИСПЛЕЕ
      Case Is < 100                                         '
      Locate 1 , 13 : Lcd " " ; Ugol                        '
      Case 100                                              '
      Locate 1 , 13 : Lcd Ugol                              '
      End Select
Loop

Int0_int:

     Stop Timer1
     Period = Timer1
      Timer1 = 0
       Start Timer1
     W = Getadc(channel)
Rem You Can Perform More Actions Here
Return                                                      'notice the return

0

17

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

Стоп у тебя в программе при переполнении таймера происходит прерывание и прога идёт на метку Sonar. У меня этого нет и при переполнении он начинает считать сначала или нет?

Да по кругу

0

18

Буду пробовать. Мысли всякие появились. Буду в раёне 21 00

0

19

Вроде понял. При прерывании Int0 т.е. повышающий фронт, прграмма останавливает таймер, далее идёт вывод информации на дисплей. В конце запускаем таймер, но так как импульсы продалжали двигаться тудже наступает следующее прерывание. в результате чего моя переменная А=119.
Я думаю так. Лечиться всё это дело так:

Do                                                          'Начало цикла

T = D * A
E = T
F = 1 / E
Waitms 100                                                  'задержка 0.25 с
Cls                                                         'Очищаем дисплей
'Lcd "F = "                                                  'Выводим на дисплей F =
Lcd A                                                       'Выводим на дисплей значение переменной F

Timer1 = 0
Loop                                                       'Конец чикла

А в прерывании всё лишнее убирается.
Если я не прав то можете поправить.

Отредактировано Set (2008-04-26 12:34:27)

0

20

Я не утверждаю на 100%, но я старался делать обработку прерывания как можно короче, в процессе можно запретить все прерывания, а после вывода на дисплей разрешить. Если есть железо: залей прогу и попробуй - это автотестер для корбюраторных двигателей. Измеряет обороты и угол опережения зажигания.
Удачи!

Отредактировано Karavan (2008-04-25 23:06:19)

0

21

У тебя тут мало команд которые моглибы внести значителиные погрешности в счёте, а у меня и вывод на дисплей и операции с плавающей точкой которые значительно убивают время.
Так что ты прав:

я старался делать обработку прерывания как можно короче,

Int0_int:

     Stop Timer1
     Period = Timer1
      Timer1 = 0
       Start Timer1
     W = Getadc(channel)
Rem You Can Perform More Actions Here
Return                                                                            Твой код
---------------------------------------------------------------------------------------------
Padschet:
Stop Timer1                                                                                    Мой код
Disable Int0
A = Timer1                                                  'забираем данные, которые пришли за время таймера 1
T = D * A
E = T
F = 1 / E
Waitms 100                                                  'задержка 0.25 с
Cls                                                         'Очищаем дисплей
'Lcd "F = "                                                  'Выводим на дисплей F =
Lcd A                                                       'Выводим на дисплей значение переменной F
Timer1 = 0
Enable Int0
Start Timer1                                                'запускаемTimer1
Return

Отредактировано Set (2008-04-26 12:33:31)

0

22

А может стоит строки

Код:
do
T = D * A
E = T
F = 1 / E
Waitms 100                                                  'задержка 0.25 с
Cls                                                         'Очищаем дисплей
'Lcd "F = "                                                  'Выводим на дисплей F =
Lcd A          
loop

вынести в основной цикл?
а в прерывании оставить

Код:
Padschet:
Stop Timer1                                                                                    Мой код
A = Timer1                                                  'забираем данные, которые пришли за время таймера 1
Timer1 = 0
Start Timer1                                                'запускаемTimer1
Return

0

23

Ты наверное невнимательно прочитал. Именно это я и имел в виду.
Делать обработку прерывания как можно короче.

0

24

ИМХО проще всего в прерывании выставить флаг (Bit):

Код:
Padschet:
Stop Timer1                                                                                    Мой код
A = Timer1                                                  'забираем данные, которые пришли за время таймера 1
Timer1 = 0
Start Timer1                                                'запускаемTimer1
Set Flag                        
Return

и в основном цикле смотреть его значение:

Код:
Do
If Flag = 1 Then                                       'прерывание произошло
 T = D * A
 E = T (смысл?)
 F = 1 / E
 Waitms 100                                             'задержка 0.25 с
 Cls                                                         'Очищаем дисплей
 'Lcd "F = "                                               'Выводим на дисплей F =
 Lcd A
 Reset Flag                                                'сброс флага прерывания
End If
loop

При в ходе в прерывание ВСЕ регистры сохраняются в стеке, для частотомера лучше сохранять только нужные (использовать Nosave), это тоже даст выигрыш в скорости выполнения и объеме кода, что-то типа этого:

Код:
On Int0 Padschet Nosave 

Padschet:
 push r24
 push r25
 push r26
 push r27
 in r24,sreg
 push r24
  Stop Timer1                                               ' Мой код
  A = Timer1                                                'забираем данные, которые пришли за время таймера 1
  Timer1 = 0
  Start Timer1                                              'запускаемTimer1
  Set Flag                                                     'ставим флажок
 pop r24
 !Out Sreg , R24
 pop r27
 pop r26
 pop r25
 pop r24
Return

Удачи :-)

0

25

Проблема уже давно решена можно закрыть тему.
А как проще каждый решает для себя сам.

0

26

В протеусе значения скачут аццки.

0

27

вот простой способ измерения времени между импульсами

Timer1 в режиме захвата

Timer1 может работать в режиме "Capture" (захвата). Это значит, что Timer1 считает тактовые импульсы через предделитель, и, когда на вход ICP (portd.6, 11 нога) приходит импульс, содержимое Timer1 копируется в регистр Input Capture. Таким способом можно точно измерить время между двумя импульсами:

Config Timer1 - Timer, Prescale = 1|8|64|256|1024, Capture Edge = Rising|Falling

interrupt-timer1-capture.bas

$regfile = "2313def.dat"
$crystal = 4000000

'Config Pind.6 = Output
Config Timer1 = Timer , Prescale = 64 , Capture Edge = Rising

Dim Wtime As Byte
Dim Timercounter As Word

On Capture1 Captmr

Wtime = 100
Timercounter = 0

Enable Interrupts
Enable Capture1

Do
  'Set Portd.6
  Waitms Wtime
  'Reset Portd.6
  Waitms Wtime
  Cls
  Lcd "pwidth: " ; " " ; Capture1
Loop

Captmr:
  Timercounter = Capture1
  Timer1 = 0
Return

End

В подпрограмме прерывания значение Timer1 (Capture1 - это второе имя этого регистра) копируется в Timercounter. Затем Timer1 очищается. При последующем импульсе на ICP входе цикл повторяется. Следовательно, Timercounter считает время между импульсами на ICP.

0

28

SyncMVGP
да, всё работает! А каким образом подсчитать частоту? Если делим частоту avr на кол-во импульсов - получается какая-то фигня.
Либо как указать длину измерения, скажем, в секунду?

Будет ли правильно работать следующий код?

Код:
$regfile = "2313def.dat"
$crystal = 4000000

' configure lcd display
Config Lcd = 16 * 2
Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.5 , Db6 = Portb.6 , Db7 = Portb.7 , E = Portb.1 , Rs = Portb.0

Config Timer1 = Counter , Edge = Falling , Prescale = 1
Stop Counter1
Dim R As Single
Dim Rpm As Word
Cls

Do
  Counter1 = 0
  Start Counter1
  Waitms 100
  Stop Counter1
   R = Counter1
   R = R * 10
   Rpm = R
  Locate 1 , 1
  Lcd "RPM: " ; Rpm ; "       "

Loop

End

В протеусе всё ок

Отредактировано validol (2009-12-11 17:02:56)

0

29

Странный баг - вышеприведенный код работает в 2313, но не работает в ATmega8. Выход генератора кидаю на 11-ю ногу (Т1).

Гуру, подскажите, в чем может быть проблема?

Отредактировано validol (2009-12-12 06:03:50)

0

30

А каким образом подсчитать частоту?

f = 1 / T
Т  -- период   (время от импульса до импульса)

$regfile = "m8def.dat"

лутше Stop Timer1 Start Timer1 а не   Stop Counter1          'останавливаем

Значение таймера имеет конец и равен 65536 после чего начнёт считать сначала.
Формула такая
PRESCALE * 65536 / ЧАСТОТА ПРОЦА = ВРЕМЯ ПЕРЕПОЛНЕНИЯ
Чтобы высчитать его  время (допустим округлить до 1 сек) надо
ВРЕМЯ * ЧАСТОТА ПРОЦА / PRESCALE = Число Timer1 за 1 сек
Число таймера - Число Timer1 за 1 сек = Число которое надо вбить как ноль  Timer1

У тебя:             
1* 65536 / 4000000 = 0,016384с
значит когда у тебя команда

Start Counter1           'Завпустить таймер
  Waitms 100             ' Задержка 0.1с это больше 0,016384с.
отсюда следует что за это время задержки таймер переполняеться и начинает считать с ноля 6.1 раза.
  Stop Counter1          ' Остановить таймер

Вроде так.

Rpm на дисплее чему равен?

Отредактировано Set (2009-12-14 22:32:43)

0


Вы здесь » Программирование ATMEL в BASCOM. » Таймеры, ШИМ и все про них » Timer1 Выдаёт одно и тоже значение