Главная » Статьи » Проекты

работа с TIMER1 в режиме захвата. Измеряем частоту сигнала

 

 Таймеры помимо прерывания по переполнению, могут работать в режиме захвата значения, это означает что по пришествии импульса на ногу ICP значение счетчика копируется в регистр хранеия Input Capture. Это дает нам возможность измерять время между соседними импульсами изменяющегося сигнала, тобишь его период и далее, если требуется, высчитать частоту. Для примера использую atmega32 и выведу показания на ЖКИ дисплей. Вывод ICP в atmega32 находится на 20 ноге (PortD.6), туда и заводим сигнал:

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


 
Prescale = 1|8|64|256|1024

и фронт по которому будет происходить захват значения:


 
Capture Edge = Rising|Falling
 От того какой предделитель выбран зависит минимальная частота измеряемого сигнала. Например при значении предделителя 64, переполнение таймера при частоте кварца 16 МГц будет происходить каждые 0,26214 сек. Значит минимальная частота которую точно сможем измерить ~ 4Гц.
 Максимальная же частота (по идее) упирается в тактовую частоту применяемого кварца. Но proteus почему-то некисло врет после 50 кГц. Поэтому пока оставлю этот вопрос =)

 В программе предусмотрена проверка значения таймера1, на случай того, если в нем окажется 0, для того чтобы предотвратить деление на этот 0. Что может произойти с МК в противном случаем, можете глянуть здесь.

 


$regfile = "m32def.dat"
$crystal = 16000000

' указываем конфигурацию подключения дисплея к портам МК

Config Lcdpin = Pin, Rs=Portc.5, E=Portc.4, Db4=Portc.0, Db5=Portc.1, Db6=Portc.2, Db7=Portc.3

Config Lcd = 16*2                      ' тип используемого дисплея

'настраиваем таймер в режим захвата по восходящему фронту

Config Timer1 = Timer , Prescale = 64 , Capture Edge = Rising

Dim Timercounter As Word
Dim Period As Single                   ' период измеряемого сигнала
Dim F1 As Single
Dim F As Word                          ' переменная для хранения значения частоты

Const T = 0.000004                     ' примерное время в секундах за которое значение
                                       ' счетчика увеличивается на 1

On Capture1 Zaxvat

Timercounter = 0
Waitms 50
Enable Interrupts
Enable Capture1

Cursor Off

Do                                    ' главный цикл программы

If Timercounter = 0 Then              ' проверка значения переменной
 F = 0                                ' если 0, то частота тоже 0

 Else                                 ' в обратном случае высчитываем частоту

 Period = Timercounter * T            ' определяем период
 F1 = 1 / Period                      ' считаем частоту
 F = Abs(F1)                          ' округляем до целого

EndIf

'выводим показания на дисплей

Cls
Lcd "Frequency, Hz:"
Lowerline
Lcd F

Waitms 100

Loop

Zaxvat:
 Timercounter = Timer1                ' копируем значение таймера в переменную
 Timer1 = 0                           ' обнуляем таймер
Return

End

 Нога ICP у меня висит в воздухе и ни к чему не подключена. 

 

 Как видите, ловит нормальный радиационный электромагнитный фон =) 
Причем наводки сильнее в местах скопления электробытовой техники, получился простой детектор электромагнитной активности, способствующей  разжижению мозга))
 Файлы проекта, можно скачать ниже:
 
Файл прошивки



 Заснял свеженькое видео, которое демонстрирует работу таймера1 в режиме захвата на Atmega8 (ошибся с делителем поэтому заместо 50 Гц показывает ~65 Гц)
 
ave!
Категория: Проекты | Добавлено: 21.04.2011
Просмотров: 39789 | Комментарии: 21 | Теги: ATmega32, ЖКИ, Timer1 | Рейтинг: 4.5/6
Всего комментариев: 21
21 sany2   (07.11.2015 08:23) [Материал]
Вполне достаточно-подключал много раз

20 ssql   (05.11.2015 23:50) [Материал]
А как выход оборотов с коммутатора подключить на pin контроллера? очень часто мелькают схемы со стабилитроном и резистором, достаточно ли этого?

19 samogon120   (13.04.2014 04:11) [Материал]
подскажите как написать в баскоме прогу которая генерирует прямоугольный сигнал(меандр), частота чтобы плавно задавалась от 1Гц до 5000Гц
и выводилась на экран
вот что я написал , не судите строго , в прерывании от таймера я просто загружаю в него число которое является суммой константы и значения ацп измеренного с переменного резистора,за счет этого при поворачивании ручки резистора изменяется частота вызова подпрограммы по переполнению таймера
$regfile = "m88pdef.dat"
$crystal = 16000000
$hwstack = 40
$swstack = 16
$framesize = 32

'Config Lcdpin = Pin , Db4 = Portc.4 , Db5 = Portc.5 , Db6 = Portd.0 , Db7 = Portd.1 , E = Portd.7 , Rs = Portd.6
'Config Lcd = 20 * 4
'Initlcd
'Cls
'Cursor Off

Config Timer1 = Timer , Prescale = 8

'Timer1 = 65445
' Timer1 = Divid

Config Portb.1 = Output
On Timer1 Strobe

Enable Interrupts
Enable Timer1

Config Adc = Single , Prescaler = Auto , Reference = Avcc
Const Multk = 330
Dim A As Word
Dim T As Word
Dim B0 As Bit
Dim Freq As Word
Dim Divid As Word
Dim Divid2 As Word
Dim Adcw2 As Integer
Dim Adcw As Word
Dim Adcw3 As Word
Dim Coef As Single
Dim Cnt As Byte
Dim B1 As Bit

'Dim Freqstr As String * 5
'Dim Freqstrf As String * 5
'Dim Coefstr As String * 4
'Dim Coefstrf As String * 4
'Dim Adcwstr As String * 4
'Dim Adcwstrf As String * 4
'Dim B3 As Bit
'Divid2 = 50

'Locate 1 , 1
'Lcd "Àac¿o¿a"
'Locate 2 , 1
'Lcd "㻸¿e»Ä½oc¿Ä"
'Divid = 1000
Do

Incr T
' If T = 1 Then Gosub Setdiv1
'If T = 255 Then Gosub Setdiv2

'if b0=1 then gosub freqcount1 else gosub freqcount2
Adcw = Getadc(6)

If Adcw = 0 Then Adcw = 1
If Adcw > 1010 Then Adcw = 1010

If T = 100 Then Gosub Label1

Loop
End

'Divid = Divid2
'Freqstr = Str(divid2)
'Freqstrf = Format(freqstr , "00000")
'Locate 1 , 1
'Lcd Freqstrf
'Adcwstr = Str(adcw)
'Adcwstrf = Format(adcwstr , "0000")
'Locate 2 , 1
'Lcd Adcw

Strobe:
'Start Timer1
Timer1 = Divid2

If B0 = 0 Then Gosub Sten Else Gosub Stdis
Return
Sten:

Set Portb.1

B0 = 1
Return
Stdis:

Reset Portb.1

B0 = 0

Return

'Setdiv1:
' T = 0

' Divid2 = Adcw * 10
' Divid = Divid2
'' Divid = 1000

' Return

' Freqcount1:
' Incr T
' Return
'Freqcount2:
' Incr A
' If T <> Divid2 Then Gosub Setdiv1

' Return

' Label1:
'Divid2 = 0
' Return

Label1:
T = 0
If Adcw <= 20 Then Divid2 = Adcw * Multk : Tccr1b = &B00000010
If Adcw <= 40 Then Divid2 = Adcw * Multk : Tccr1b = &B00000010
If Adcw <= 60 Then Divid2 = Adcw * Multk : Tccr1b = &B00000010
If Adcw <= 80 Then Divid2 = Adcw * Multk : Tccr1b = &B00000010
If Adcw <= 100 Then Divid2 = Adcw * Multk : Tccr1b = &B00000010
If Adcw <= 120 Then Divid2 = Adcw * Multk : Tccr1b = &B00000010
If Adcw <= 140 Then Divid2 = Adcw * Multk : Tccr1b = &B00000010
If Adcw <= 160 Then Divid2 = Adcw * Multk : Tccr1b = &B00000010
If Adcw <= 180 Then Divid2 = Adcw * Multk : Tccr1b = &B00000010
If Adcw >= 200 Then Divid2 = Adcw + 63336 : Tccr1b = &B00000010
If Adcw >= 290 Then Divid2 = Adcw + 64246 : Tccr1b = &B00000010
If Adcw >= 380 Then Divid2 = Adcw + 64489 : Tccr1b = &B00000010
If Adcw >= 470 Then Divid2 = Adcw + 64566 : Tccr1b = &B00000010
If Adcw >= 560 Then Divid2 = Adcw + 64576 : Tccr1b = &B00000010
If Adcw >= 650 Then Divid2 = Adcw + 64553 : Tccr1b = &B00000010
If Adcw >= 740 Then Divid2 = Adcw + 64510 : Tccr1b = &B00000010
If Adcw >= 830 Then Divid2 = Adcw + 64456 : Tccr1b = &B00000010
If Adcw >= 920 Then Divid2 = Adcw + 64394 : Tccr1b = &B00000010
If Adcw >= 1010 Then Divid2 = Adcw + 64350 : Tccr1b = &B00000010
Return

18 samogon120   (13.04.2014 03:58) [Материал]
у меня заработало на меге 48 только код подправил
$regfile = "m48def.dat"
$crystal = 16000000
$hwstack = 45
$swstack = 20
$framesize = 40

Config Lcdpin = Pin , Db4 = Portc.4 , Db5 = Portc.5 , Db6 = Portd.0 , Db7 = Portd.1 , E = Portd.7 , Rs = Portd.6
Config Lcd = 16 * 2
Initlcd
Cls
Cursor Off

Config Timer1 = Timer , Prescale = 64 , Capture Edge = Rising

Dim Timercounter As Word
Dim Period As Single
Dim F1 As Single
Dim F As Word
Dim Coefstr As String * 4
Dim Coefstrf As String * 4
Dim Adcw As Word
Dim B0 As Bit
Dim Adcw2 As Integer
Dim Adcw3 As Word
Const T = 0.000004

On Capture1 Zaxvat

Timercounter = 0
Waitms 50
Enable Interrupts
Enable Capture1

Cursor Off

Do

If Timercounter = 0 Then
F = 0

Else

Period = Timercounter * T
F1 = 1 / Period
F = Abs(f1)

EndIf
Coefstr = Str(f)
Coefstrf = Format(coefstr , " ")
Locate 1 , 1
Lcd "«ac¿o¿a" ; " " ; Coefstrf ; "¡å"
Waitms 100

Loop

Zaxvat:
Timercounter = Timer1
Timer1 = 0
Return

End

17 Антошин   (18.04.2013 10:02) [Материал]
Конечно,может не очень по теме, Гц * 60=об/мин,но в ДВС рабочий ход проходит за два
оборота вала,соответственно 1 импульс за два оборота,цилиндров 2,4,6,8 и может быть 12(т.е. какая то переменная из eeprom),сюда бы добавить два порога для ЭПХХ,один для
сигнализации превышения частоты ващения... Чудесный тахометр бы получился...

16 exersizze   (18.04.2013 08:46) [Материал]
А почему нельзя, умножаем частоту на 60 и получаем значение в об/мин

15 Антошин   (17.04.2013 22:06) [Материал]
На Меге16 получилось!Вопрос:А Герцы можно перевести в Об/мин?

+1   Спам
14 virb   (29.03.2013 13:30) [Материал]
Потолок измерений определить довольно сложно, поскольку чем выше частота, тем сильнее "разброс" показаний. Вернее сказать дискретность показаний увеличивается, например при частоте 40 кГц на устройстве отображается то 41666, то вдруг 62500 (разница целых 20834 Гц). Если еще выше поднять частоту (например до 50 кГц), то устройство тормозит, это можно заметить по частоте обновления символов на экране (при частоте 50 кГц частота обновления примерно 1 сек). Максимум что может выдать устройство это около 64000 Гц.

13 exersizze   (29.03.2013 00:27) [Материал]
virb, интересно а какой потолок измерений получился ?

12 virb   (28.03.2013 02:29) [Материал]
Попробовал на 8 меге - работает. Сначала не мог никак проверить, потом приволок с работы генератор частоты и проверил. Надо амплитуду сигнала от 1,5 и выше вольт ставить, при меньшей амплитуде не замечает. При маленьких значениях частоты на дисплее отображается та же частота что и подается, а при увеличении частоты значение на дисплее становится чуть больше, чем подается (например, при 100 Гц отображается 102 Гц, при 1000 Гц - 1024 Гц).

11 Aleks8383   (27.12.2012 11:52) [Материал]
К стати у меня на 8 меге тоже неработает,пальцем касаешься вывода циферки бегают по экрану,а если подключить генератор даже 1 кгц непоказывает при кварце 12мгц.Показывает только одно число 4886(помоему точно непомню ).

10 exersizze   (26.12.2012 12:56) [Материал]
На восьмой меге тоже должно работать, тем более что в симуляторе то пошло. Может с подключением что не так или фьюзы

9 marss70   (25.12.2012 22:38) [Материал]
Переделав проект на мегу 8 обнаружено, что в пртеусе работает, а в железе нет. Или же этот МК не подходит, только мега 32?

+1   Спам
8 exersizze   (22.01.2012 02:14) [Материал]
этим вопросом задаются многие)) попробуй;)

7 top   (21.01.2012 23:51) [Материал]
Это правда, что при делении на 0 происходит разрушение кристалла?

6 exersizze   (14.12.2011 15:23) [Материал]
Самое простое было бы сделать на задержке, только незнаю насколько точно получиться отсчитывать время:
Code
A = word
waitms A


Поэтому, когда промежуток слишком большой (как у тебя 0,01-10 сек), конфигурируем таймер на прерывание по переполнению, в прерывании увеличиваем значение переменной. Время, через которое происходит увеличение переменной, можно подсчитать. Пускай сделали так, чтобы переполнение происходило каждые 0,01 сек. Все, зная значение переменной, знаем сколько точно прошло времени: к примеру в переменной лежит число 156, значит счетчик протикал 1,56 сек. А дальше привязываем к значению нашей переменной выполнение нужных действий.

5 pchela5   (14.12.2011 13:47) [Материал]
Камрад, такой вопрос - как лучше организовать формирование точного сигнала на ноге контроллера определенной длительности - от 0,01 до 10 секунд например?

4 pchela5   (14.12.2011 13:42) [Материал]
Ага, спасибо - я так и предполагал. Надо будеть фьюзы поглядеть - может у меня от внутреннего генератора сейчас камень работает - все идет к этому.

3 exersizze   (14.12.2011 12:51) [Материал]
T=(1/F)*n тут Т-константа, n-предделитель, F-частота работы камня

2 pchela5   (14.12.2011 11:58) [Материал]
Как считается константа Const T = 0.000004 ? Что-то я не догнал краями. У меня при кварце 11,059 и такой константе считает верно, но до частоты 62500 (снимаю со счетчика). Ставишь на более высокие ноги - 124кГц и более - не считает. Предделитель - 64, как в примере.

1 tenevikus   (26.04.2011 23:34) [Материал]
wacko

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]






авторизация