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

Обсуждаем контроллеры компании Atmel.
Ответить
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Сообщение ibiza11 »

:))) тут подсказки ТС не нужны) только протоколы, прерывания и код!
Ставим плюсы: )
Реклама
Встал на лапы
Аватара пользователя
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Сообщение dem66 »

Уже разобрался. Получаеся примерно такой код:

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

#define F_CPU 10000000UL

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

ISR(TIMER1_OVF_vect)
{

	TCNT1 = 64456;
	
	if( PINB & ( 1 << PB0 ) ) {
		PORTB &= ~( 1 << PB0 );
	}else {
		PORTB |= ( 1 << PB0 );
	}
}

void SetupTIMER1(void)
{
	TCCR1B = (1<<CS10);
    
	TIMSK |= (1<<TOIE1);

	//TCNT1 = 64456;
}

int main(void)
{
	DDRB = ( 1 << PB0 );
	
	SetupTIMER1();
	sei();
	
	while(1)
	{
	}
}
Теперь подскажите что делать с TCNT1? Сейчас же получается статическое значение, а если я получу новое значение по USART то как мне его туда впихнуть?

Начальное же значение указывается в функции ISR(TIMER1_OVF_vect)

И как запустить два таймера? Чтото не получается :(

ibiza11, тихо там
Это не хвост, это антенна
Реклама
Встал на лапы
Аватара пользователя
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Сообщение dem66 »

Так всетаки как должен выглядеть код с двумя таймерами? У меня никак не поучается настроить два, перестают работать оба
Это не хвост, это антенна
Мучитель микросхем
Аватара пользователя
Сообщения: 462
Зарегистрирован: Пн фев 22, 2010 09:12:34

Сообщение ArtDen »

Ты лучше объясни что вообще хочешь получить. Пока просто никто не понял как должен выглядеть твой конечный результат.
http://ufa-darts.ru/ - приходи играть в дартс в Уфе
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
YS
Друг Кота
Аватара пользователя
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05

Сообщение YS »

Да не, ТС же писал:
Нужно получить вот такую осцилограмму
Изображение
Я тут подумал, а может ну их нафиг, контроллеры? :) Вот, два корпуса стандартной логики:

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

Сообщение codenamehawk »

YS писал(а): Я тут подумал, а может ну их нафиг, контроллеры? :) Вот, два корпуса стандартной логики:
А перестройка частоты через уарт?
Реклама
Вымогатель припоя
Сообщения: 547
Зарегистрирован: Вт фев 09, 2010 17:52:26

Сообщение codenamehawk »

TCNT1 = 64456;

замените на

TCNT1 = peremennaja_v_kotoruju_ja_budu_zadavat_znachenija_chastoty;

Для второго таймера

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

ISR(TIMER2_OVF_vect)
{

   TCNT2 = время_задержки;//это место где нет импульсов, ну или длина пачки импульсов
   
   if( пауза == 0)
 {
      TCCR1B = 0;//запретить работу первого таймера
      пауза=1;
   }else 
  {
    TCCR1B = (1<<CS10);
    пауза=0;//разрешить работу первого таймера
   }
}
как-то так
Последний раз редактировалось codenamehawk Ср янв 30, 2013 16:41:50, всего редактировалось 1 раз.
Вымогатель припоя
Сообщения: 547
Зарегистрирован: Вт фев 09, 2010 17:52:26

Сообщение codenamehawk »

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

Сообщение dem66 »

Ну на логике я бы и сам мог сделать, ну и всякие там TL494, NE555, но к сожалению такой вариант не проходит :(

Пытаюсь вручную расчитывать нужное количество тиков.

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

#define F_CPU 10000000UL
#define TCNT1_1MS (F_CPU/1024)

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

ISR(TIMER1_OVF_vect)
{

   //TCNT1 = 50000;
   TCNT1 = 0x4E2;
   
   if( PINB & ( 1 << PB0 ) ) {
      PORTB &= ~( 1 << PB0 );
   }else {
      PORTB |= ( 1 << PB0 );
   }
}

void SetupTIMER1(void)
{
   //TCCR1B = (1<<CS12);
   TCCR1B = 0x05;
    
   TCNT1 = 0x4E2;

   //TCNT1 = 64456;
   //TIMSK = (1<<TOIE1);
   TIMSK |= 1;
}

int main(void)
{
   DDRB = ( 1 << PB0 );
   
   SetupTIMER1();
   sei();
   
   while(1)
   {
   }
}
Timer0 = 10MHz/1024=15625 Гц
Частотапереполнения = 15625 / 256 = 61,0352 Гц.

10000000/1024=9765.625 Гц = 9,765Khz

Частотапереполнения = 9765.625/256 = 38.146972656 Гц.

время одного "переполнения" = 1 / 38.146972656 = 0.0262144 сек

время одного тика таймера = 0.0262144 / 65536 = 0.0000004 сек

Чтобы получить 0.0005 c (2Khz) необходимо чтобы таймер тикнул 0.0005 / 0.0000004 = 1250 раз.
1250 в 16-тиричной системе это 4E2 = 0x4E2

Чтото я не понимаю как эти данные привязать к таймеру :(

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

Сообщение zero648 »

Делаем частоту 2000 Гц с помощью Timer0, CLK=10.000.000 Гц:
1 - 10000000/2000=5000 ;
2 - 5000/64=78,125 ; не подходит, нужно целое число;
3 - 5000/8=625 ; уже лучше, но больше 1 байта;
4 - делаем собственный прескалер в прерывании Timer0 overflow 625/125=5, берем переменную или регистр, который не трогаем нигде, загружаем в него 5 и при каждом прерывании Timer0 уменьшаем на единицу, когда переменная станет =0, снова загружаем в переменную 5 и выполняем само прерывание. При каждом входе в прерывание обновляем TCNT0=256-125=131.
Встал на лапы
Аватара пользователя
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Сообщение dem66 »

zero648 писал(а):загружаем в него 5 и при каждом прерывании Timer0 уменьшаем на единицу
Чтото непонятно :(

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

Сообщение zero648 »

dem66 писал(а):Чтото непонятно :(

А как быть с TCCR0 и TIMSK??
Это прописываем в инициализации:
TCCR0=0x02 - прескалер 1:8;
TIMSK=0x01 - прерывание по переполнению таймера 0
Вымогатель припоя
Сообщения: 547
Зарегистрирован: Вт фев 09, 2010 17:52:26

Сообщение codenamehawk »

dem66 писал(а): Чтобы получить 0.0005 c (2Khz) необходимо чтобы таймер тикнул 0.0005 / 0.0000004 = 1250 раз.
1250 в 16-тиричной системе это 4E2 = 0x4E2
Если подсчитали количество импульсов правильно, то необходимо от числа 0xFFFF отнять ваш результат 0x4E2 и присвоить результат TCNT1
(объясню на пальцах
как только вы присвоили TCNT1= 0x4E2 он сразу же начинает тикать с этого значения.
прерывание по переполнению наступит после 0xFFFF
сколько тиков пройдет до прерывания подсчитать можете?)


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

Сообщение dem66 »

codenamehawk писал(а):то необходимо от числа 0xFFFF отнять ваш результат 0x4E2
извиняюсь, забыл.

zero648, сделал как вы писали и получилось 4,9Khz

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

ISR(TIMER0_OVF_vect)
{

  TCNT0 = 131;
   
   if(PINB & (1 << PB0)){
      PORTB &= ~(1 << PB0);
   }else {
      PORTB |= (1 << PB0);
   }
}

void SetupTIMER0(void)
{
   TCCR0 = 0x02;
   TCNT0 = 131;
   TIMSK = 0x01;
}
Но при работе видны какието задержки на осцилограмме, немного подтормаживает, и виртуальный осцилограф в протеусе на сразу показывает частоту.

Сейчас вот пытаюсь оптимизировать, делаю вот так:

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

int status;
int b;

ISR(TIMER0_OVF_vect)
{

  TCNT0 = 131;
   
   if(status){
      b = 0;
   }else {
      b = 1;
   }
}

void SetupTIMER0(void)
{
   TCCR0 = 0x02;   
   TCNT0 = 131;
   TIMSK = 0x01;
}

int main(void)
{
   DDRB = ( 1 << PB0 );
   
   SetupTIMER0();
   sei();
   
   while(1)
   {
	   status = (PINB & (1 << PB0));
	   
	   if(b==1){
		 PORTB |= (1 << PB0);
	   }else{
		  PORTB &= ~(1 << PB0);
	   }
   }
}
А оно вобще перестало работать.
Сейчас if(status) всегда получается FALSE
Это не хвост, это антенна
Вымогатель припоя
Сообщения: 547
Зарегистрирован: Вт фев 09, 2010 17:52:26

Сообщение codenamehawk »

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

Сообщение vitalik_1984 »

что это за оптимизация такая? те же самые действия, только еще и используя переменную, которая может лежать вне РОН, а чаще всего так и есть.
теперь представим себе примерно ассемблер
загрузили число,
сравнили с константой,
если равно переход к метка
порт в 1
переход к метка 2
метка :порт в 0
метка 2

а в начальном варианте :
определили пин
если равно переход к метка
порт в 1
переход к метка 2
метка :порт в 0
метка 2

хорошо сэкономили?

можно вообще вот так:
PORTB ^= (1 << PB0);

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

Сообщение zero648 »

dem66 писал(а):zero648, сделал как вы писали и получилось 4,9Khz
Во-первых не вижу самодельного прескалера, во-вторых у Вас меняется состояние PORTB.0 каждый раз при выполнении обработчика прерывания, поэтому для полного периода в обработчик нужно зайти два раза, а значит частоту входа нужно увеличить в 2 раза, чтобы получить нужную частоту сигнала, и в третьих есть небольшой нюанс, при использовании переполнения таймера нужно учитывать время входа в обработчик, так что TCNT0=131 это как бы базовая расчетная величина и её нужно корректировать по ходу процесса.

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

ISR(TIMER0_OVF_vect)
{

  TCNT0 = 131;
   
   if(PINB & (1 << PB0)){
      PORTB &= ~(1 << PB0);
   }else {
      PORTB |= (1 << PB0);
   }
}

void SetupTIMER0(void)
{
   TCCR0 = 0x02;
   TCNT0 = 131;
   TIMSK = 0x01;
}
Теперь пересчитаем все это дело для частоты входа в обработчик 2000x2=4000Гц
10000000/4000=2500
2500=250*10, получается TCNT0 будет теперь 256-250 и плюс учтем время входа в обработчик, 11 тактов на вход плюс 1 такт на загрузку регистра TCNT0, самодельный прескалер будет 10, таймер тикает без аппаратного прескалера, т.е. 10МГц.
При таких настройках у меня все четко получается:
Изображение
Встал на лапы
Аватара пользователя
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Сообщение dem66 »

Прескалер это OCR0 или TCCR0?

И что это у вас за proteus такой?
Это не хвост, это антенна
Вымогатель припоя
Сообщения: 547
Зарегистрирован: Вт фев 09, 2010 17:52:26

Сообщение codenamehawk »

zero648 писал(а): получается TCNT0 будет теперь 256-250 и плюс учтем время входа в обработчик, 11 тактов на вход плюс 1 такт на загрузку регистра TCNT0,
ИМХО можно не учитывать эти "11 тактов на вход плюс 1 такт на загрузку регистра TCNT0"
Прерывания и так происходят каждые 1/4000 сек , а дополнительные такты просто сместят сигнал немного правее, не меняя его ширины (длительности).
Встал на лапы
Аватара пользователя
Сообщения: 141
Зарегистрирован: Ср окт 26, 2011 13:38:13

Сообщение dem66 »

Вы меня точно запутали.
Так ктото обяснит про прескалер?

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

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