Генератор на Atmega8 (микросекунды) большие погрешности

Обсуждаем контроллеры компании Atmel.
Ответить
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2482
Зарегистрирован: Пт авг 27, 2010 05:57:06
Откуда: Тюмень

Сообщение vitalik_1984 »

Прескалер в переводе с английского означает предделитель.
В прикладном программировании бывают аппаратные делители это которые есть или нет в каждом Мк по своему.
И еще есть программный делитель.
Это когда действие происходит не каждый раз при проходе подпрограммы, а только после обнуления какой то специальной переменной.
пример алгоритма деления на 5:
начало
если переменная равна нулю,
  • выполняем действие
    загружаем в переменную число 5
если не равна нулю,
  • отнимаем из переменой 1

идем в начало.
Последний раз редактировалось vitalik_1984 Чт янв 31, 2013 19:59:18, всего редактировалось 1 раз.
Контактная информация:
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

Сообщение zero648 »

dem66 писал(а):Прескалер это OCR0 или TCCR0?
Регистр TCCR0=0x01 - аппаратный прескалер 1:1, т.е. на тактовой частоте МК.
У ATmega8 нет регистра OCR0.
Протеус - ISIS Professional rev. 7.7 SP2 (сборка 9089)
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

Сообщение zero648 »

codenamehawk писал(а):ИМХО можно не учитывать эти "11 тактов на вход плюс 1 такт на загрузку регистра TCNT0"
Прерывания и так происходят каждые 1/4000 сек , а дополнительные такты просто сместят сигнал немного правее, не меняя его ширины (длительности).
Позвольте с Вами не согласиться коллега, это справедливо только для Compare match, а тут мы вмешиваемся в счетчик TCNT0 и изменяем его? поэтому все критично.

codenamehawk, так сказать, СПЕШАЛ ФОР Ю!
Изображение
YS
Друг Кота
Аватара пользователя
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05

Сообщение YS »

Ох. Ну почитайте что ли мой туториал на эту тему...
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Вымогатель припоя
Сообщения: 547
Зарегистрирован: Вт фев 09, 2010 17:52:26

Сообщение codenamehawk »

Не обратил внимание на на ручной прескаллер.
Реклама
Встал на лапы
Аватара пользователя
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Сообщение dem66 »

Кажись разобрался с таймером. Использую предделитель 1

Код: Выделить всё

#define F_CPU 10000000UL

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

int status;
int b;

ISR(TIMER1_OVF_vect)
{

  TCNT1 = 60560;

   PORTB ^= (1 << PB0);
}

void SetupTIMER0(void)
{

   //TCCR1B = (1<<CS12)|(0<<CS11)|(1<<CS10); // настраиваем делитель 1024
   //TCCR1B = (1<<CS12)|(0<<CS11)|(0<<CS10); // настраиваем делитель 256
   //TCCR1B = (0<<CS12)|(1<<CS11)|(1<<CS10); // настраиваем делитель 64
   TCCR1B = (0<<CS12)|(0<<CS11)|(1<<CS10); // настраиваем делитель 1

   TIMSK |= (1<<TOIE1);  // разрешить прерывание по переполнению таймера счетчика
   
   TCNT1 = 60560;
}

int main(void)
{
   DDRB = (1 << PB0);
   
   SetupTIMER0();
   sei();
   
   while(1)
   {
	   
   }
}
Допустим на частоту 1Khz

Делитель = 1
Частота таймера счетчика = Тактовая частота/Делитель = 10000000/1 = 10000000 Гц
Длительность периода( тика ) = (1/10000000) = (0.0000001 / 0.000001) = 0.1мкс
10000000/2000 = 5000

Количество тиков = 65536-5000 = 60536

Корекция 60536+24 = 60560

Получилось настроить ровно на 1Khz, тютелька в тютельку)))

-----
5Khz

10000000/10000 = 1000
Количество тиков = 65536-1000=64536
Корекция 64536+22 = 64558
-----
10Khz
10000000/20000 = 500
Количество тиков = 65536-500=65036
Корекция 65036+23 = 65059
-----
20Khz
10000000/40000 = 250
Количество тиков = 65536-250=65286
Корекция 65286+23 = 65309

После 50-ти начинаются большие погрешности но жить можно.

Теперь скажите как реализовать два таймера?
У второго частота будет меньше, буквально до 1Khz, и он будет управлять этим таймером.

А мотет сделать так чтобы эти таймера работали паралельно? Ну какбы на две лапы, или будет нормально если делать управлять из одного таймера другим?
Это не хвост, это антенна
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

Сообщение zero648 »

dem66, Я ж конкретно показывал пример для таймера 0, потому, что так стоял вопрос, но если будешь использовать таймер 1, тогда все намного проще, используй не переполнение, а совпадение, тогда можно не вникать на время входа в прерывание, ну ниче, зато теперь будешь знать как работать с переполнением.
С таймером 1 так вообще шоколадно получится, с любой тактовой, потому, что у нас есть регистр ICR1.
Встал на лапы
Аватара пользователя
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Сообщение dem66 »

А как сделать по совпадению?
Это не хвост, это антенна
Вымогатель припоя
Аватара пользователя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

Сообщение zero648 »

В принципе с таймером 1 и без ICR1 нормально получится. C ICR1 скважность хорошо регулировать с заданным разрешение длины периода.

В общем так, тоже что и раньше но с таймером 1 и по совпадению, делаем частоту сигнала 2кГц на PORTB.0:
Для инициализации таймера:
OCR1A = 2500-1;
TCCR1B = (0b01<<WGM12)|(0b001<<CS10); режим таймера СТС, аппаратный прескалер 1:1
TIMSK = (1<<OCIE1A); Timer1 Compare Match A

В прерывании таймера просто меняем логическое состояние пина PORTB.0.
Последний раз редактировалось zero648 Пт фев 01, 2013 14:15:23, всего редактировалось 2 раза.
Встал на лапы
Аватара пользователя
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Сообщение dem66 »

Ну так как же всетаки будет выглядеть код когда таймер будет работать на совпадение?

Код: Выделить всё

ISR(TIMER1_COMPA_vect)
{

  //TCNT1 = 65476;
  //ICR1 = 0;

   PORTB ^= (1 << PB0);
}

void SetupTIMER0(void)
{

   //TCCR1B = (1<<CS12)|(0<<CS11)|(1<<CS10); // настраиваем делитель 1024
   //TCCR1B = (1<<CS12)|(0<<CS11)|(0<<CS10); // настраиваем делитель 256
   //TCCR1B = (0<<CS12)|(1<<CS11)|(1<<CS10); // настраиваем делитель 64
   TCCR1A = 0x00;
   TCCR1B = (0<<CS12)|(0<<CS11)|(1<<CS10)|(1 << WGM12); // настраиваем делитель 1

   //TIMSK |= (1<<TOIE1);  // разрешить прерывание по переполнению таймера счетчика
  // TIMSK|=(1<<OCIE0);
   //TCNT1 = 65476;
   ICR1 = 65476;
   
   TIMSK |= (1 << OCIE1A);
}
Так вот частота получилась аж 125Khz :))

Как теперь с ним работать? Тут же все по другому
Последний раз редактировалось dem66 Чт янв 31, 2013 23:56:35, всего редактировалось 1 раз.
Это не хвост, это антенна
Вымогатель припоя
Аватара пользователя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

Сообщение zero648 »

Нет, ICR1 пока не будем трогать, потом если посчитаем нужным, читай пост выше.
Встал на лапы
Аватара пользователя
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Сообщение dem66 »

Ок, все запустил, все четко. А как теперь мне для него частоту расчитывать?
Для переполнения я то уже понял как, а как тут?
Это не хвост, это антенна
Вымогатель припоя
Аватара пользователя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

Сообщение zero648 »

dem66 писал(а):Теперь скажите как реализовать два таймера?
У второго частота будет меньше, буквально до 1Khz, и он будет управлять этим таймером.
В чем заключается это управление, что будет меняться, частота, скважность, еще чтото?
Да, кстати, если сигнал снимать с PB1, а не с PB0, тогда обработчик прерывания можно удалть совсем, все будет работать аппаратно, надо только настроить выход РВ1 соответственно.
В данном случае нужно PB1 сделать выходом и режим выхода канала "переключать при совпадении":
TCCR1A = (0b01<<COM1A0); Toggle OC1A/OC1B on Compare Match

В качестве второго счетчика можно использовать второй канал таймера 1, настраивается аналогично, за исключением прескалера, его не трогаем иначе испортим первый канал.
OCR1B = 10000-1;
TIMSK |= (1<<OCIE1B); Timer1 Compare Match B

Частота расчитывается так, вернее значение регистра OCR1:
тактовая частота делим на нужную частоту и минус один.
10000000/1000-1=9999 ; 1 кГц для канала В
Для канала А нужно тактовую предварительно поделить пополам, т.к. полупериоды.
Открыл глаза
Сообщения: 46
Зарегистрирован: Ср янв 16, 2013 06:51:09
Откуда: Сам не знаю...

Сообщение JeysonRou »

dem66 писал(а):Ок, все запустил, все четко. А как теперь мне для него частоту расчитывать?
Для переполнения я то уже понял как, а как тут?
Боже столько демогогий кодовых изза таймера меговского :)))
Не тугодумте народ нафига вы юзаете OSC T1 :dont_know:
Если тебе нужен асинхронный режим сигнала не проще ли задействова Т2 который тебе с одной строчки это все сделает???
А не городить куча хламокода под таймер которому это не пресуще??? :facepalm: :facepalm: :facepalm:
Вымогатель припоя
Аватара пользователя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

Сообщение zero648 »

JeysonRou писал(а):Не тугодумте народ нафига вы юзаете OSC T1 :dont_know:
Интересно :))) , где это видно, причем тут OSC T1?
Встал на лапы
Аватара пользователя
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Сообщение dem66 »

ну вобще то можно использовать и PB1, изначально я думал использовать PB1 и PB2. Под них и плату травил.

Изображение

Типа вот так?

Код: Выделить всё

#define F_CPU 10000000UL

#include <avr/io.h>
#include <avr/interrupt.h>


void SetupTIMER0(void)
{

  OCR1A = 99;
  OCR1B = 499;
   
   TCCR1A = (0b01<<COM1A0); //Toggle OC1A/OC1B on Compare Match
   TCCR1B = (0b01<<WGM12)|(0b001<<CS10); //режим таймера СТС, аппаратный прескалер 1:1

  
   TIMSK = (1<<OCIE1A); //Timer1 Compare Match A
   TIMSK |= (1<<OCIE1B); //Timer1 Compare Match B
}

int main(void)
{
   DDRB = (1 << PB1);
   
   SetupTIMER0();
   sei();
   
   while(1)
   {
	   
   }
}
Поидее должно было быть 50Khz и 10Khz а в результате осцилограф как показывал 50 так и показывает, осцилограмма такой и осталась :(
Вложения
driver.png
(27.45 КБ) 1540 скачиваний
Это не хвост, это антенна
Вымогатель припоя
Аватара пользователя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

Сообщение zero648 »

Во-первых РВ2 на выход надо сделать:
DDRB |= (1 << PB2);
Во-вторых на выходе РВ2 не настроен режим:
TCCR1A |= (0b01<<COM1B0);
Если прерывания не используешь, то убери TIMSK, зачем его трогать.
Встал на лапы
Аватара пользователя
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Сообщение dem66 »

не понимаю :( Раньше говорили о том что б все генерить на одну лапу, теперь уже не две :(

Код: Выделить всё

#define F_CPU 10000000UL

#include <avr/io.h>
#include <avr/interrupt.h>


void SetupTIMER0(void)
{

  OCR1A = 4998;
  OCR1B = 499;
   
   TCCR1A |= (0b01<<COM1B0);

   TCCR1B = (0b01<<WGM12)|(0b001<<CS10); //режим таймера СТС, аппаратный прескалер 1:1
	
}

int main(void)
{
   DDRB = (1 << PB1);
   DDRB |= (1 << PB2);
   
   SetupTIMER0();
   sei();
   
   while(1)
   {
	   
   }
}
Частота 1Khz на лапе PB2
Это не хвост, это антенна
Вымогатель припоя
Аватара пользователя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

Сообщение zero648 »

dem66 писал(а):не понимаю :( Раньше говорили о том что б все генерить на одну лапу, теперь уже не две :(
Как бы объяснить то..., короче, аппаратно в меге так устроено, что канал А выведен на ногу РВ1, а канал В на ногу РВ2, значит, если нужно иметь разную частоту на одной ноге, тогда работайте только с одним каналом А или В.
Частота 1Khz на лапе PB2
А точно не 10кГц? может еще проверите.
Встал на лапы
Аватара пользователя
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Сообщение dem66 »

Точно, почемуто работает только канал A
И кстати proteus такой же как и у вас но почемуто осцилограф другой :(

Изображение

Код: Выделить всё

#define F_CPU 10000000UL

#include <avr/io.h>
#include <avr/interrupt.h>


void SetupTIMER0(void)
{

  OCR1A = 4998;
  OCR1B = 499;
   
   TCCR1A |= (0b01<<COM1B0);

   TCCR1B = (0b01<<WGM12)|(0b001<<CS10); //режим таймера СТС, аппаратный прескалер 1:1
	
}

int main(void)
{
   DDRB = (1 << PB1);
   DDRB |= (1 << PB2);
   
   SetupTIMER0();
   sei();
   
   while(1)
   {
	   
   }
}
Вложения
Снимок-4.png
(226.62 КБ) 1698 скачиваний
Это не хвост, это антенна
Ответить

Вернуться в «AVR»