Страница 1 из 1
Счетчик ATMEGA32
Добавлено: Вс сен 28, 2014 01:17:29
feekus
Здравствуйте, помогите разобраться с вот такой программой:
#define GEN 0
#define GEN_PORT PORTB
#define GEN_DDR DDRB
#include <avr/io.h>
#include <avr/interrupt.h>
ISR(TIMER1_OVF_vect)
{
TCNT1H=0xFF;
TCNT1L=0xFF-0x14+3;
GEN_PORT^=1<<GEN;
sei();
}
int main(void)
{
GEN_DDR|=1<<GEN;
TCCR1B|=1<<CS11;
TCNT1H=0xFF;
TCNT1L=0xFF-0x14+1;
TCCR1B|=(1<<WGM12|1<<WGM13);
TIMSK|=1<<TOIE1;
sei();
while(1){}
}
В результате выполнения этой программы микроконтроллером на
выводе PB0, генерируется прямоугольный сигнал с частотой 50 кГц и
длительностью импульса 10 мкс., почему 50кГц генерируется и как выудить из программы например не 50кГц, а 62.5
Re: Счетчик ATMEGA32
Добавлено: Пн сен 29, 2014 07:54:11
pyzhman
50кГц потому, что
Изменить частоту можно, забивая в регистр счёта таймера иное значение. Для 62,5кГц (грубо) это будет
Re: Счетчик ATMEGA32
Добавлено: Пн сен 29, 2014 16:49:58
feekus
А можно по конкретней про регистр TCNT1 и метод записи
TCNT1H=0xFF- это старший байт
TCNT1L=0xFF-0x14+3 это младший байт
какое число получится если перевести его в 10 систему 4081 ?
Нашел вот такое объяснение относительно времени прерывания:
Устанавливаем значение счетного регистра TCNT1, таким образов чтобы прерывание происходило каждые 10 мс. Расчет производится по
следующей формуле
TCNT1=0xFFFF-(T*F_CPU/K)+1,
где T–желаемая длительность, F_CPU–тактовая частота контроллера
иK – коэффициент деления предделителя. Таким образом для нашей
задачи получим:
TCNT1=0xFFFF-(10*10^-6*16*10^6/8)+1=0xFFFF-0x14+1.
а как именно из него частота получается, при том что у данной программы стоит прерывание каждые 10мс(может из них получить 50кГц)
P.S я хотел получить не 62.5кГц, а 62.5 Гц. Исходя из чего выбирается коэффициент деления предделителя
Re: Счетчик ATMEGA32
Добавлено: Пн сен 29, 2014 17:02:57
eess9
4081h в десятичной будет 16513.
Я пользуюсь такой формулой: частота = F_CPU/(предделитель* TCNT1)
или
предделитель = F_CPU/(частота* TCNT1)
Предделитель выбираете из соображений оптимальности. Для ваших 16МГц и 62.5Гц на выходе имеем:
предделитель = 8, TCNT1 = 32000
предделитель = 64, TCNT1 = 4000
предделитель = 256, TCNT1 = 1000
предделитель = 1024, TCNT1 = 250
Дальше выбираете то, что на вас смотрит. Я бы взял первый вариант.
Re: Счетчик ATMEGA32
Добавлено: Пн сен 29, 2014 21:36:38
pyzhman
feekus писал(а):...не 50кГц, а 62.5
Однако, нету размерности. Посему берём предыдущую. Что вы там хотели - яснее излагайте.
Re: Счетчик ATMEGA32
Добавлено: Пн сен 29, 2014 22:18:28
vdavid
feekus Не забывайте, что счетчик считает вперед. Т.е., когда Вы записали в него число 0xffff+1-20(0x14), то до нуля вверх он отсчитает ровно 20 тактов. С учетом предделителя на 8 частота прерываний будет 16 000 000/20/8=100 0000 Гц, т.е. период будет именно 10 мс. В прерывании же записывается число на 2 меньше в предположении, что на вход в прерывание потратилось 2 такта счетчика. Лично я бы так не делал. Ведь можно задать TOP для счетчика и не заморачиваться с подсчетом тактов.
Если же Вы хотите сохранить этот код, то для получения 62.5 Гц должно быть так:
TCNT1=0xffff-16000+1
или более по-человечески
TCNT1=-16000
Ну и до кучи sei() в прерывании как бы не нужен вовсе.
eess9 Если брать код из стартового топика то Ваши советы есть неправильные. Для предделителя 8, например, полупериод будет
16 000 000/(65536-32000)/8=59.637 Гц, а частота - в два раза меньше. Для остальных предделителей все еще намного грустнее.
Re: Счетчик ATMEGA32
Добавлено: Пн сен 29, 2014 23:25:51
urry
vdavid, прежде чем давать свои выкладки в форуме, проверяйте их в симуляторе.
1.
Код: Выделить всё
В прерывании же записывается число на 2 меньше в предположении, что на вход в прерывание потратилось 2 такта счетчика.
Вы никогда не можете сказать, сколько времени займет вход в прерывание - почему именно 2 такта счетчика ? С этим борятся , прибавляя в прерывании вычисленное значение - какое-то улучшение точности есть.
ISR (TIMER1_OVF_vect)
{
TCNT1+=F_TMR1_CALC;
BITINV(PORTB,0);
}
2. Формула расчета выходной частоты предельно простая
#define FIN F_CPU/8ul
#define F_CALC 62.5
#define F_OUT (F_CALC*2)
#define F_TMR1_CALC (65536ul - (FIN_TMR1/F_OUT)) //
Проект присоединяю
Re: Счетчик ATMEGA32
Добавлено: Пн сен 29, 2014 23:57:23
vdavid
urry, Ну и чем отличаются мои -16000 от Ваших? Для чего тут нужен симулятор?
Что касается 2-х тактов, то вопрос не ко мне, а к автору кода в стартовом топике. Я лишь пытался этот код объяснить.
Re: Счетчик ATMEGA32
Добавлено: Вт сен 30, 2014 07:32:41
pyzhman
Не, я понимаю 2 такта для десятков кГц. Но ловить их на Гц? Хотя, конечно, всё зависит от задачи.
Re: Счетчик ATMEGA32
Добавлено: Вт сен 30, 2014 08:27:12
vdavid
urry
А теперь посмотрите на листинг того, что Вы написали:
Код: Выделить всё
TCNT1+=F_TMR1_CALC;
8e: 6c b5 in r22, 0x2c ; 44
90: 7d b5 in r23, 0x2d ; 45
92: 80 e0 ldi r24, 0x00 ; 0
94: 90 e0 ldi r25, 0x00 ; 0
96: 0e 94 26 01 call 0x24c ; 0x24c <__floatunsisf>
9a: 20 e0 ldi r18, 0x00 ; 0
9c: 30 e8 ldi r19, 0x80 ; 128
9e: 41 e4 ldi r20, 0x41 ; 65
a0: 57 e4 ldi r21, 0x47 ; 71
a2: 0e 94 96 00 call 0x12c ; 0x12c <__addsf3>
a6: 0e 94 fa 00 call 0x1f4 ; 0x1f4 <__fixunssfsi>
aa: 7d bd out 0x2d, r23 ; 45
ac: 6c bd out 0x2c, r22 ; 44
Посчитайте, сколько тактов будет выполняться Ваше сложение и куда фактически ускачет к тому времени таймер. Погрешность здесь будет определенно больше, чем в старттопике.
Вот так будет получше, но погрешность примерно в 5 тактов процессора тоже гарантирована.
Код: Выделить всё
TCNT1-=16000;
7a: 8c b5 in r24, 0x2c ; 44
7c: 9d b5 in r25, 0x2d ; 45
7e: 80 58 subi r24, 0x80 ; 128
80: 9e 43 sbci r25, 0x3E ; 62
82: 9d bd out 0x2d, r25 ; 45
84: 8c bd out 0x2c, r24 ; 44
А всего то и надо вместо
Код: Выделить всё
#define F_TMR1_CALC (65536ul - (FIN_TMR1/F_OUT))
написать
Код: Выделить всё
#define F_TMR1_CALC (uint16_t)(65536ul - (FIN_TMR1/F_OUT))
И размер программы чудным образом уменьшится с 876 до 242 байт.
Re: Счетчик ATMEGA32
Добавлено: Вт сен 30, 2014 09:18:43
urry
Код: Выделить всё
Погрешность здесь будет определенно больше, чем в старттопике.
увеличьте частоту хотя бы до килогерца и сами посмотрите разницу между = и += в симуляторе.
На маленькой частоте она незаметна.
Код: Выделить всё
#define F_TMR1_CALC (uint16_t)(65536ul - (FIN_TMR1/F_OUT))
эта запись не имеет смысла, число 65536 не влезает в размер uint16_t
Re: Счетчик ATMEGA32
Добавлено: Вт сен 30, 2014 09:39:04
vdavid
urry писал(а):
эта запись не имеет смысла, число 65536 не влезает в размер uint16_t
Так зато результат влезет (а мы же преобразовываем именно его). Ведь TCNT1 - два восьмибитных регистра. И никакой лонг в него не впихнуть ну никак. Да и число 65536 нужно в этой формуле как корове седло.
Какая религия не позволяет написать так?
Код: Выделить всё
#define F_TMR1_CALC - (uint16_t)(FIN_TMR1/F_OUT)
Re: Счетчик ATMEGA32
Добавлено: Вт сен 30, 2014 09:57:17
urry
Так можно. И даже можно убрать приведение типов
#define F_TMR1_CALC - (FIN_TMR1/F_OUT)
Все равно при записи в 16 битный регистр оно приводится.
Re: Счетчик ATMEGA32
Добавлено: Вт сен 30, 2014 10:29:24
vdavid
urry
Если убрать приведение типов, то все станет совсем грустно.
Предупреждение компилятора
main.c:56: warning: overflow in implicit constant conversion
и, как результат, в F_TMR1_CALC нолик.
Ну и сгенеренный код:
Код: Выделить всё
TCNT1+=F_TMR1_CALC;
8e: 6c b5 in r22, 0x2c ; 44
90: 7d b5 in r23, 0x2d ; 45
92: 80 e0 ldi r24, 0x00 ; 0 !!!!!!!!!!
94: 90 e0 ldi r25, 0x00 ; 0 !!!!!!!!!!
96: 0e 94 24 01 call 0x248 ; 0x248 <__floatunsisf>
9a: 20 e0 ldi r18, 0x00 ; 0
9c: 30 e0 ldi r19, 0x00 ; 0
9e: 4a e7 ldi r20, 0x7A ; 122
a0: 56 e4 ldi r21, 0x46 ; 70
a2: 0e 94 93 00 call 0x126 ; 0x126 <__subsf3>
a6: 0e 94 f8 00 call 0x1f0 ; 0x1f0 <__fixunssfsi>
aa: 7d bd out 0x2d, r23 ; 45
ac: 6c bd out 0x2c, r22 ; 44
В Вашим первоначальном примере приведение типов отложено на run-time, что приведет более чем к трехкратному увеличению кода. Это раз. Во-вторых конечный результат что в первой предложенной мной конструкции, что во второй - один и тот же - число 0xc180 (или -16000). Ну и в-третьих. Зачем мне смотреть что-то в симуляторе, когда все очевидно. При входе в прерывание мы поместили значение TCNT1 в регистровую пару r22,r23. Легко сосчитать по тактам, что число это будет равно 2. Далее мы вызываем подпрограммы __floatunsisf, __subsf3 и __fixunssfsi. Трассировать мне их лень, но очевидно что выполнение их займет десятки, а скорее сотни тактов CPU. За это время TCNT1 тикнет не один раз. Но мы то прибавляем к первоначальной двоечке. Так понятно?
Re: Счетчик ATMEGA32
Добавлено: Вт сен 30, 2014 10:46:18
urry
Раздутость кода объясняется приведением числа флоат - #define F_CALC 62.5
Поставьте здесь например #define F_OUT (uint16_t)(F_CALC*2)
и оно исчезнет
Если вы не хотите делать симуляцию, чтобы увидеть разницу между + и += , за это вас никто делать не будет.
Удачи типа
Re: Счетчик ATMEGA32
Добавлено: Вт сен 30, 2014 11:18:34
shads
urry писал(а):за это вас никто делать не будет.
Можно уточнить, какой именно смысл вы вложили в эту фразу

...
Re: Счетчик ATMEGA32
Добавлено: Вт сен 30, 2014 11:38:42
vdavid
urry Хорошо. Ответьте мне по-простому. Зачем в этой задаче плавающая точка в ран-тайме? Что касается разницы, то да, она будет но не в пользу Вашего кода. Почему? По-моему я доходчиво объяснил. Насчет симуляции... Совершенно не обязательно пробовать на зуб гранит для того, что бы убедиться что он таки твердый.
Re: Счетчик ATMEGA32
Добавлено: Вт сен 30, 2014 12:09:38
shads
urry писал(а):Код: Выделить всё
#define F_TMR1_CALC (uint16_t)(65536ul - (FIN_TMR1/F_OUT))
эта запись не имеет смысла, число 65536 не влезает в размер uint16_t
urry - "поспешишь - людей насмешишь..." ну ничьо, с кем не бывает

...
vdavid писал(а):urry Хорошо. Ответьте мне по-простому. Зачем в этой задаче плавающая точка в ран-тайме?
urry занят... отвечу за него

- конкретно в данной задаче - НЕ ЗАЧЕМ... и даже если бы она была не в ран тайме, все равно странно.. что она используется...