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

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

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

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


Вы здесь » Программирование ATMEL в BASCOM. » Вопросы - ответы » Как зделать более точную задержку чем Wait?


Как зделать более точную задержку чем Wait?

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

1

Делаю частотомер. Остановился на измерении количества импульсов с помощью Counter на портах Т0(1).
Часть кода:
  Start Counter0
  Waitms Wtime
  Stop Counter0
Считает нормально. Но Wait не точное время, соответственно измерения не точные. Пробовал запускать TIMER1, и считать по переполнению.
Frequensy:
  Counter0 = 0
  Timer1 = 65286            '$crystal = 16000000, Prescale = 64, задержка 1mS - 250 тиков таймера.
  Overcounter = 0
  Start Counter0 : Start Timer1
  Waitms 300                 'Время для ожидания прерывания. Мне нужно максимальное время измерения 256 mS.
Return
'----------------
Schet:                           'Прерывание TIMER1
  Stop Counter0
  Stop Timer1
  Timercounter = Counter0 'Частота на входе Т0, без подсчета переполнений.
Return
Подсказали, что таймер стартует тоже с задержкой.
Какие способы создания задержек еще существуют?

-1

2

Код:
$regfile = "m8adef.dat"
$crystal = 4000000
$hwstack = 12
$swstack = 12
$framesize = 32
Dim Znach_timer1 As Word
Config Timer1 = Timer , Prescale = 1
Stop Timer1
Timer1 = Znach_timer1
On Timer1 Puls
Start Timer1
Enable Interrupts
Enable Timer1
'Получаемый интервал  (65536-Znach_timer1)/4000000=0,008384 секунд
'Изменяя значение Znach_timer1 до 65535 можете задать интервал  с точностью до  0,00000025 секунд
'для получение других интервалов можно менять прескализацию, частоту МК, выбрать др. таймеры

Do
  Znach_timer1 = 32000                                      '
Loop

Puls:
   Stop Timer1
   Timer1 = Znach_timer1
   Start Timer1
Return

End

Отредактировано Niya (2018-12-12 10:53:15)

+1

3

Пользовался таким способом (ассемблер).

Код:
delay14:                                      ' п/п задержки
LDI R18, 14                                ' в регистр R18 значение SPEED
delay14loop:
DEC R18                                   ' уменьшение на 1 содержимого R18
BRNE delay14loop                    ' переход, пока флаг Z не будет равен 0
ret                                           ' выход из п/п задержки после выполнения 14 тактов

В данном случае - задержка на 14 тактов МК.
Можно "растянуть" до 255... ;)

Отредактировано Nord (2018-12-12 14:04:03)

0

4

Чот я не понял, зачем вообще частотомеру иметь задержку. Обычно меряют не количество импульсов за время, а интервал. ;) Это быстрее работает (считай чисто аппаратно, минимум кода) и позволяет сократить время измерения.

0

5

Nord
Понимаю этой частью кода можно заменить Wait. Но в (ассемблер) полный "0".
Если МК работает на частоте 16мГц, такт 1/16000000 = 4 mkS, 0.004 Ms.
Мне нужно 256 mS, это 256/0.004 = 64000 тактов.
Правильно понимаю? Если это так, значит то, что надо. o.O
В моем случае перед МК стоит ВЧ делитель на 64, или 256(переключается). Если придется мерить без делителя, то 1кГц, 100mS.
Настораживает этот коммент:' выход из п/п задержки после выполнения ~14 тактов. Именно значек примерно. :unsure:

0

6

RDW
С этого начал. Захват импульса по порту ICP1. В Меге8 PB0. Столкнулся с вечным прерыванием если на входе нет импульсов, и как остановить прерывание после подсчета периода сигнала для продолжения работы основной программы.

-1

7

rom-i написал(а):

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

Значит алгоритм неправильный.
Берём таймер, который считает время.
Берём любой тип прерывания, например INT0.

Вариант 1:

- Если счет ещё не запускался, то по приходу на INT импульса, сбрасывается таймер (счет) и запускается (хотя правильнее его сбрасывать после подсчета, на завершении).
- Если счет запущен, то приход импульса на INT останавливает счёт и ведётся подсчет времени работы таймера (чтение из него значения).

Недостатки данного варианта: требуется два импульса "старт/стоп", т.е. как бы два такта, меньше производительность. Если такой подход точный ненужен, то делаем вторым вариантом.

Вариант 2:

- Запускаем таймер и ждём, когда сработает прерывание по INT.
- Если придет импульс по INT, то сразу читаем значения из счетчика таймера и сбрасываем его (сам счет).

Недостаток алгоритма: если долго нет импульсов, то таймер/счетчик переполняется, для этого можно предусмотреть механизм вывода макс значения счета, что будет говорить об отсутствии импульсов на входе прерывания.

Оба алгоритма используют аппаратный таймер (что не влияет на погрешность счета) и прерывание, которое очень быстро отрабатывает. В итоге на основной код выполнения программы МК это всё не влияет.
Таймер лучше сразу использовать 16 разрядный.

Я этот алгоритм даже использовал для подсчета скорости выполнения кода программы с разным набором данных/алгоритма. Типа бэнчмарк, только результат был в мс.

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

0

8

rom-i написал(а):

Понимаю этой частью кода можно заменить Wait. Но в (ассемблер) полный "0". Если МК работает на частоте 16мГц, такт 1/16000000 = 4 mkS, 0.004 Ms.Мне нужно 256 mS, это 256/0.004 = 64000 тактов.Правильно понимаю?

Можно сделать вложенный цикл: 250 отсчетов по 255.

Только если известна длительность задержки, то зачем такой компот ?
На проще ли использовать Waitms 256 ? ;)
При использовании кварца погрешности минимальны...
Недостаток, что программа "замрет" на 256 mS...

0

9

rom-i написал(а):

Настораживает этот коммент:' выход из п/п задержки после выполнения ~14 тактов. Именно значек примерно.

Остался от экспериментов... ;)
Убрал.

0

10

rom-i,
Вы  как будто не слышите что говорят. Спросили как получить разные интервалы, вроде, накидал код....А Вы все с эти wait-ом возитесь. Я Вам в другой ветке ответил , как можно избавиться от

rom-i написал(а):

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

Тут RDW Вам разжевал этот алгоритм. Вот Вам переделанный выше код по

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

Берём таймер, который считает время.
Берём любой тип прерывания, например INT0.
Вариант 1:
- Если счет ещё не запускался, то по приходу на INT импульса, сбрасывается таймер (счет) и запускается (хотя правильнее его сбрасывать после подсчета, на завершении).
- Если счет запущен, то приход импульса на INT останавливает счёт и ведётся подсчет времени работы таймера (чтение из него значения).
.

Код:
$regfile = "m8adef.dat"
$crystal = 4000000
$hwstack = 12
$swstack = 12
$framesize = 32
Dim Flag_int0 As Boolean , Flag_net_impulsov As Boolean
Dim Znach_timer1 As Word
Dim Sledim_za_vrem As Word
Config Timer1 = Timer , Prescale = 1
Enable Timer1  
On Timer1 Perepolnenie
Config Int0 = Rising
Enable Int0
On Int0 Puls
Enable Interrupts
Do
 'если нет импульсов в течении 8 сек останавливаем таймер
If Flag_net_impulsov = 1 Then 
   Flag_net_impulsov = 0
   Sledim_za_vrem = 0 
   Stop Timer1 
   Timer1 = 0
end if
 'тут делаем с Znach_timer1 что хотим                                                      '
Loop
End

Puls:
   Sledim_za_vrem=0
   Toggle Flag_int0
   If Flag_int0 = 1 Then Start Timer1
   If Flag_int0 = 0 Then
      Stop Timer1
      Znach_timer1 = Timer1
      Timer1 = 0
   End If
Return
'--------Прерывания от переполнения таймера-----------------------------
'Если был запушен таймер от INT0, но
'не было следующего импульса, чтобы остановить таймер
',то будем следить за переполненияи от таймер
Perepolnenie:
 Incr Sledim_za_vrem
If Sledim_za_vrem > 500 Then Flag_net_impulsov = 1          '  ~8 секунд
Return

Отредактировано Niya (2018-12-12 14:50:38)

+1

11

Niya
Код Ваш вполне понятен. Первое прерывание по INT сбрасывает таймер счета, второе начинает. Третье сбрасыват, четвертое начинает. И так с частотой 5мГц. Прерывание ни кто не отменял. Когда программе работать? Измерение частоты у мну занимает 7% Мега8 общей программы. Вся пока занимает 87%. Да, и точность измерения Т количеством тиков таймера не сильно точен.
Спасибо за предложение, но тема задана именно про создание точных задержек.

0

12

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

Можно сделать вложенный цикл: 250 отсчетов по 255.

Только если известна длительность задержки, то зачем такой компот ?
На проще ли использовать Waitms 256 ?
При использовании кварца погрешности минимальны...
Недостаток, что программа "замрет" на 256 mS...

Программа по любому замрет на время измерения. Это нормально, и не хуже. Иначе будет мельтешить цифрами. Тем более основная часть программы, измерение напряженности поля. Здесь работает АЦП. Тоже есть дрейф, и эфирные шумы.
Этот компот нужен для точности. Waitms 256, далеко не 256 мСек. Даже протеус это показывает.
Вот как реализовать Ваш подход(тоесть заменить Wait на Ваше предложение)?
ИП+ частотомер

Отредактировано rom-i (2018-12-12 18:07:25)

0

13

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

конкретно это как?

Зная входную частоту и информацию о пред делители, можно подсчитать с определенной точностью период входного сигнала:

http://s5.uploads.ru/t/kS6aV.gif
Заполнение периода более высокой частотой с дальнейшим подсчетом количеством импульсов. Понятно, что: чем ближе частота входного сигнала к заполняемому - тем больше погрешность и меньше точность измерения.

В нашем случае, роль "заполнителя" выступает таймер.

Сильнее некуда уже разжевывать.  :D

По этому:

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

допустим измеряем в 1 случае 1_000_000 гц а во втором случае 1_000_010 гц?

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

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

Отредактировано RDW (2018-12-12 19:04:04)

0

14

rom-i написал(а):

Waitms 256, далеко не 256 мСек. Даже протеус это показывает.

Протеус правду показывает только в одном случае - после нажатия "Стоп"... ;)
Это - симулятор, а не анализатор... ;)

rom-i написал(а):

Вот как реализовать Ваш подход (тоесть заменить Wait на Ваше предложение)?

bulat943 в #17 расписал.
Осталось вам только свои (нужные) значения подставить... ;)

0

15

rom-i написал(а):

Да, и точность измерения Т количеством тиков таймера не сильно точен.

Это кто такое сказал? Вроде, во всех книжках написано, что точное время надо получать таймерами. Одной из функцией таймеров и есть получение точных интервалов времени. При частоте 8 МГц(прескал =1) можете получить интервалы  с точностью до 1/8*10^6=0.125мкс! Этого мало?
Что   составляет ~0,000049%  от Ваших 256мс.
Простым кодом ,на родном Bascom типа этого ( при 8Мгц)

Код:
Config Timer1 = Timer , Prescale = 64
Enable Timer1

Zaderzka:
   Start Timer1
   Do
                                           '
   Loop Until Timer1 = 31910
   Stop Timer1
   Timer1 = 0

получите свои 256мс с точностью в микросекундах (Bascom показывает 256,0498 мс)

Или можете  пойти путем предложенным товарищем bulat943.Но там  надо вычислять количество циклов, их перевести в кол-во тактов(за сколько тактов выполняется каждая команда Ассамблера) , такты на время....

Отредактировано Niya (2018-12-13 00:58:25)

0

16

Niya
Вот мне, и ненравиться считать задержку TIMER1. Частоту поднял до 16мГц. Что бы получить 256мС, нужно в таймере выставить Prescale = 64. Не меньше. Даже при предделителе 64, 1 тик в моей схеме это 6.5кГц. 8 таймер будет переполняться.
Хочу попробовать как предлогает bulat943
Но там ничего не понимаю. В Баском на уровне первого класса, в асемблере "-0".
Как с этим кодом общаться, и как его вставить вместо Wait.
Start Counter0
Wait
Stop Counter0

Отредактировано rom-i (2018-12-13 08:09:13)

0

17

rom-i написал(а):

Частоту поднял до 16мГц.

Наоборот надо уменьшать, а не увеличивать. Например при 1 Мгц  выставив колчество тиков =250 , прескализацию 1024 для Timer0 вы получите  :
250*1024/1_000_000=0,256 с
свои желанные 256 мс

Код:
Config Timer0 = Timer , Prescale = 1024
Enable Timer0

Zaderzka:
   Start Timer0
   Do
                                           '
   Loop Until Timer0 = 250
   Stop Timer0
   Timer0 = 0


и можете обратиться к этой метке Zaderzka когда требуется. Если не хотите уменьшить частоту , то при тех же конфигурациях , но при частоте 8Мгц получите 32 мс . Прогнав  его через цикл 8 раз , опять получите свои 256 мс. Так что, вариантов много.........

Отредактировано Niya (2018-12-13 09:43:39)

0

18

Niya
Тогда начинается парадокс.
Нелзя уменьшать частоту посколько, CounterX может правильно считать только <40% от тактовой.
Решил сделать так:
$crystal = 16000000
Config Timer1 = Timer , Prescale = 1
On Timer1 Schet
'***************************
Frequensy:
  Overtime = 0
  Overcounter = 0
  Counter0 = 0
  Timer1 = 32768

  Start Counter0 : Start Timer1
  Waitms 300
Return
'------------------------------------
Schet:
  Incr Overtime
  If Overtime = 63 Then
     Stop Counter0 : Stop Timer1
     Timercounter = Counter0
  End If
Return
В железе нечем проверить(нет частотомера). Протеус? Врет, или нет...... завышает.
На вход подаю 1мГц, на индикаторе 256.013мГц вместо 256.000мГц.

0

19

bulat943
Не затруднит комменты добавить к этим строкам кода. Попробовать делать разное время задержек.
ldi  r18, 82
    ldi  r19, 43
    ldi  r20, 0
L1: dec  r20
    brne L1
    dec  r19
    brne L1
    dec  r18
    brne L1
    lpm
    nop
Правда, говорил мой батя: пробуют девочьки, а потом рожают.)))

Отредактировано rom-i (2018-12-13 21:34:50)

-1

20

Код:
Для МК 8 Мгц, прескализация=1
'Такты: nop -1,Push-2,ldi-1,Dec-1,brne-1/2,breq-1/2,pop-2,rjmp-2

Vremja:
   $asm
      Push r16      'Cохраняем содержимое регистра r16
      push r17      'Cохраняем содержимое регистра r17
      push r18      'Cохраняем содержимое регистра r18
      ldi r18,10    'Записываем в r18 константу задержки
Wt1:
      Dec R18       'Уменьшаем значение регистра r18
      breq wt4      'если содержимое r18=0,то переходим на wt4
      ldi r17,255
Wt2:
      dec r17
      breq wt1
      ldi r16,255
Wt3:
      Dec R16
      brne wt3      'Если не ноль , то продолжаем цикл
      rjmp wt2
Wt4:
      pop r18       'Восстанавливаем содержимое регистров
      pop r17
      pop r16
   $end Asm

как определить временные интервалы
Например Wt3: цикл выполняется 255 раз.
КомандаDec-выполняется за 1 такт
Команда Brne - за 1 такт.если не вызывает перехода;за 2 такта , если вызывает
Значит всего тактов 3, а в цикле 3*255=765. Время на цикл 765*(1/8*10^6)=95.625 мкс
Wt2 крутить этот цикл Wt3 255 раз значит получаем время 24,384375 мс
  +255 раз выполняется rjmp - 2 такта 255*2= 510*0,125мкс=0,06375 мс
  Общее время  двух циклов Wt2,Wt3 =24,448125 мс
  Wt1 прогоняет все это дело еще 10 раз получаем 244,48125 мс
  У нас 16 -ая строка выполняется 1 раз -это 1 такт, 20-255 раз, 24-255*255= 65025
  65 281*0,125мкс=8,160125 мс
  3раза  Push, 3 раза Pop - 12 тактов*0,125мкс=0,0015 мс
  Итого получаем:244,48125+8,160125+ 0,0015=252,642875 мс
  Могу ошибится где-то, пусть товарищи поправять
  .....все это нудно .............но надеюсь смысл понятен

Отредактировано Niya (2018-12-13 22:42:11)

0

21

bulat943
И не только здесь. Оказывается в МК идут аппаратные задержки. Не может он быть таким быстрым. Нашел статью про это. Старт порта для захвата импульса, уже задержка в 2 такта. И ТД. Но хорошо, что эта задержка не плавает. Ее можно(нужно) корректировать. В моей пруге она составила 77 тактов TIMER1, с Prescale = 1. При любых временных задержках. 256, 64, 1. Даже со временем измерения 1мС, все равно 77 тактов. Это радует, что все стабильно.

0

22

$regfile = "2313def.dat"                                    ' Частотомер 50.00 Герц
$crystal = 4000000                                          ' компилятор BASCOM

In_hertz Alias Pind.6

Declare Sub Byte2led(data_2byte As Word)

Dim Tempb As Byte , Data_2byte As Word , Tempw As Word
Dim Data_1 As Byte , Data_2 As Byte , Data_3 As Byte , Data_4 As Byte
Dim Tyscha As Byte , Sotka As Byte , Desaytka As Byte , Edinica As Byte , Timercounter As Single

Config Portb = Output : Portb = 255
Config Pind.6 = Input

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

Config Timer1 = Timer , Prescale = 8 , Capture Edge = Rising
On Capture1 Captmr
Enable Capture1

Enable Interrupts                                           ' разрешаем прерывания и включаем таймер

Lcd "Start..."

' =======================   С Т А Р Т   =========================
Start_main_prog:

  Cls
  Timercounter = 25000000 \ Timercounter                    ' на входе - частота в 2 раза выше, чем от генератора сигнала!
  Tempw = Timercounter
  Lcd Tempw

Goto Start_main_prog

' =========================================================
Captmr:                                                     ' Считаем импульсы, как-бы наполняем пачками между импульсами
   Timercounter = Capture1
   Timer1 = 0
Return

0

23

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

удалил свои посты,надо уходить отсюда-толку здесь ноль

Непонятно....Прочитал всю ветку.Вроде, вы выступаете консультирующей стороной. Какой толк должен быть? Должны прислушываться?

Отредактировано Niya (2018-12-15 18:53:36)

0

24

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

0

25

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

уйма вопросов но вроде как спросить не у кого

Сначала НАУЧИСЬ их ПРАВИЛЬНО задавать, а уж потом констатировать тех, кто тебе на них СОИЗВОЛИТ ответить!   
И ещё, запомни главное - здесь тебе НИКТО и НИЧЕГО не должен, посему веди себя скромно, проси МАЛО и уходи БЫСТРО (Пётр I)

0

26

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

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

Как сказал товарищ NMi тут никто ничего никому не должен. И заходят, наверное, когда есть свободное время. Советами, знаниями тут ребята делятся(пишу по своему опыту).  Главное, чтобы маякнули, а решение должен найти сам. Не должны же тебе тут  готовый код писать? Так что, думаю не стоит так категорически рассуждать .
ЗЫ: Ладно, пофлудили мы тут уже знатно...

0

27

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

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

Так надо озвучить эту "уйму" - коллективный разум пока не запретили... ;)
Для того и форум.

А уходить...  :dontknow:
ИМХО - самый адекватный русскоязычный форум по Bascom.
Есть и другие, но они полузамороженные...

0

28

Nord, почему у вас тут 14 тактов?

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

delay14:                                      ' п/п задержки
LDI R18, 14                                ' в регистр R18 значение SPEED
delay14loop:
DEC R18                                   ' уменьшение на 1 содержимого R18
BRNE delay14loop                    ' переход, пока флаг Z не будет равен 0
ret                                           ' выход из п/п задержки после выполнения 14 тактов


LDI- 1 такт
DEC -1 такт
BRNE- 1/2 такта
ret-4 такта
+вызвать подпрограмму , это еще 3 такта(если RCALL)
Получам:
1+14x(1+2)+4+3=50, 50-1=49тактов , потому что BRNE один раз вызывает переход- выполнятся за 1 такт
Итого -49 тактов. Может, вы имели ввиду 14 циклов?

Отредактировано Niya (2018-12-16 09:11:27)

0

29

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

Nord, почему у вас тут 14 тактов?
Может, вы имели ввиду 14 циклов?

Код не мой, возможно, его автор это и имел в виду... ;)
Это фрагмент кода отсюда: Кириллица на китайских OLED дисплеях

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

0

30

Спасибо, я понял.

-1


Вы здесь » Программирование ATMEL в BASCOM. » Вопросы - ответы » Как зделать более точную задержку чем Wait?