Страница 1 из 5

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

Добавлено: Вс янв 27, 2013 23:43:55
dem66
Доброго времени суток.
Возникла потребность собрать генератор испульсов на Atmega8.

Все работает но дело в том что слишком большие погрешости получаются.
Допустим:

Частота 6Khz
6*1000 = 6000
1/6000 = 0.000166667
0.000166667 * 1000 = 0.166667
0.166667/2 = 0.0833335
0.0833335 * 1000 = 83.3335

Полупериод = 83

Но атмега с этим не согласна и получается частота 7397Hz

Частота 3,102
1/3102 = 0.000322373
0.000322373 * 1000 = 0.322373
0.322373/2 = 0.1611865
0.1611865 * 1000 = 161.1865

Полупериод = 161

Но получается частота 3847Hz

Использую самописную функцию для милисекундных задержек, так как стандартные из <util/delay.h> весят очень много, занимают аж 10Kb.

Кварц 10Mhz

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

#define TIKS_1MS (10000000/64/1000)
#define TIKS_1US (TIKS_1MS/500)

void sleep_us(unsigned long int us)
{
	while(us--){
		TCNT0 = 0;
		while(TCNT0 < TIKS_1US);
	}
}

TCCR0 = (1<<CS02);

sleep_us(83);
На стандартной _delay_us(); погрешности почти нет
---------------------
PS: Пересобрал с опциями avr-gcc -mmcu=atmega8 -g -Os -Werror -lm -mcall-prologues -o firmware.o firmware.c и все ок, получился файлик 1,3Кб.

Теперь другой вопрос, так к нему приделать USART? чтобы можно было управлять частотой с компа.
Пример:

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

void uart_init(void)
{
  UBRRH = 0;
  //UBRRL = 52;
  //UBRRL = (10000000/(16*9600)) – 1;
  UBRRL = 65;
  UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
  UCSRB = (1 << TXEN) | (1 << RXEN) | (1 << RXCIE);
}

unsigned char USART_Receive(void)
{
	while (!(UCSRA & (1<<RXC)));
	return UDR;
}

void USART_Transmit(unsigned char data)
{
	while (!(UCSRA & (1<<UDRE)));
	UDR = data;	        
}


int main(void){
   DDRD = 0xff;		// все выводы порта D сконфигурировать как выходы
   
  uart_init();
   
	while(1)
	{
		USART_Transmit(USART_Receive());
	}
}
Прикрепляю прошивку

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

Добавлено: Пн янв 28, 2013 04:15:09
zero648
В даташите посмотрел, 10МГц для стандартного битрейта без погрешностей никакя скорость не подходит, если только подбирать чтобы была самая маленькая погрешность.

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

Добавлено: Пн янв 28, 2013 04:26:45
vitalik_1984

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

 void sleep_us(unsigned long int us)
{
   while(us--){
      TCNT0 = 0;
      while(TCNT0 < TIKS_1US);
   }
} 
сами подумайте что это у вас за бред написан?
зачем эти (us--)?
Нужно работать с прерыванием таймера, а не так деревянно так у вас получается аналогично с режимом delay_us тупит в цикле , зачем?

Рассчитайте сколько нужно поставить предделитель и сколько нужно тактов до прерывания.

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

Добавлено: Пн янв 28, 2013 13:59:38
dem66
vitalik_1984, в интернете нашел. Обясните тогда как правельно это сделать.

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

Добавлено: Пн янв 28, 2013 14:21:44
ChipKiller
А вот остался вопрос по поводу USART
... встроенного генератора (8 Мгц) вполне хватает для обмена на скорости 19200

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

Добавлено: Пн янв 28, 2013 15:52:55
dem66
Зачем мне встроеный? Мне и с внешним неплохо, я вот только не понимаю как реализовать прием данных в атмеге и вприхивать принятые данные в функцию генерации. Принимает же по одному символу

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

Добавлено: Пн янв 28, 2013 16:07:40
ploop
Принимает же по одному символу
Так придумайте протокол. Маркеры начала/конца посылки, контрольную сумму желательно. Как посылка принята и проверена - забирайте необходимые данные и работайте.

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

Добавлено: Пн янв 28, 2013 16:23:59
dem66
А разве нету готовых решений? :shock: Видел что чтото с прерываниями связано

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

Добавлено: Пн янв 28, 2013 20:32:11
Аlex
Причём тут прерывания ? Вы хоть думаете, перед тем как пишите ? Ну или, хотя бы, погуглили бы незнакомые слова.
Вам толкуют про протокол. Придумайте его себе сами и пользуйтесь на здоровье.

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

Добавлено: Пн янв 28, 2013 20:38:17
ArtDen
вообще-то таймер сам умеет выводами дергать. никаких самописных функций для задержки, которые вносят погрешность, в данном случае не надо. читайте даташит. там все написано.

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

Добавлено: Пн янв 28, 2013 20:40:28
dem66
Я и без вас пректрасно знаю что такое протокол

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

Добавлено: Пн янв 28, 2013 20:48:01
Аlex
dem66 писал(а):Я и без вас пректрасно знаю что такое протокол
Заметно :
Видел что чтото с прерываниями связано
:))

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

Добавлено: Пн янв 28, 2013 21:10:32
YS
Мой вариант Вас случайно не устроит?

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

Добавлено: Пн янв 28, 2013 21:37:05
codenamehawk

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

/*
 * main.c
 *
 *  Created on: 10.12.2011
 *      Author: Marian
 */

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

//main
int main(void)
{
	DDRB  = 1<<PB3;
	PORTB = 1<<PB3;

// Wychodnaja czastota F_OC0 = F_clkIO / (2*N*(1+OCR0))
// gdzie N prescaler (1,8,64,256,1024)
// Przyklad 12000000/2*1*(1+0) = 6000000 Hz

	TCCR0 |= 1 << CS00;							//clock/1    na wychodzie 6 000 000     Hz
//	TCCR0 |= 1 << CS01;							//clock/8    na wychodzie   750 000     Hz
//	TCCR0 |= 1 << CS01 | 1 << CS00;				//clock/64   na wychodzie    93 750     Hz
//	TCCR0 |= 1 << CS02;							//clock/256  na wychodzie    23 437.5   Hz
//	TCCR0 |= 1 << CS02 | 1 << CS00;				//clock/1024 na wychodzie     5 859.375 Hz

	TCCR0 |= 1<<WGM01 | 1<<COM00; //  CTC mode , togle wychod PB3

	OCR0   = 0;
//	OCR0   = 5; 								//OCR0   = 0x05;i dla clock/1 da na wychodzie da 1 000 000 Hz
//	OCR0   = 0x02;								//dla clock/64 da na wychodzie da 31250 Hz
//	OCR0   = 0x21;								//dla F_CPU 12MHz, clock/1, OCR0=21  da na wychodzie da 272727.2727 Hz


	sei();

	while (1)
	{
	}
}
Делал генератор на атмеге 16, кварц 12 Мн, выход на ногу PB3
По уарту передаете по одному символу, загоняете в текстовую переменную нужной длины, дальше преобразование текст в целое и присвоение TCCR0
Дальше тоже самое и с OCR0

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

Добавлено: Пн янв 28, 2013 23:13:15
dem66
Аlex, вы вобще внимательно читали а?
Если вы не вкурсе то принимать можно и с прерываниями

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

//Обработчик прерывания по окончанию приёма байта
ISR( USART_RXC_vect )
{
  unsigned char rxbyte = UDR;
}
И без

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

unsigned char USART_Receive(void)
{
	while (!(UCSRA & (1<<RXC)));
	return UDR;
}
YS, codenamehawk спасибо что откликнулись, буду думать.
YS а можко как то второй канал прилепить, ну он у вас как бы есть но частота у них одинкаовая, мне нужно чтобы на них можно было устанавливать разную частоту.

Нужно получить вот такую осцилограмму
Изображение

Думаю как это сделать, есть несколько вариантов:
1)генерить на две лапы и потом скрещивать дополнительной микрухой. Но какреализовать в атмеге 2 разных потока (походу два таймера с прерываниями) я пока не понял.
2)генерить на одну лапу, код типа этого:

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

int Pulse(timer1, timer2){
	int count;
	
	if(timer1>timer2){
		count = timer1/timer2;
	}else{
		count = timer2/timer1;
	}
		
		int i;
		
		for(i = 0; i<count; i++){
			PORTD |= _BV(PD3);
			_delay_us(timer2);
			PORTD &= ~_BV(PD3);
			if(i!=(count-1)){
				_delay_us(timer2);
			}
		}
	return 1;
}
int main(void){
   DDRD = 0xff;		// все выводы порта D сконфигурировать как выходы
   
   int timer1 = 238;
   int timer2 = 21;
   Pulse(timer1, timer2);
   
	while(1)
	{
		PORTD |= _BV(PD2);	// установить "1" (высокий уровень) на выводе PD1,зажечь светодиод
		
		Pulse(timer1, timer2);
		
		PORTD &= ~_BV(PD2);
		_delay_us(timer1);
	}
}
Подскажите в каком напревлении двигатся. Чтото не понял решения codenamehawk, там сразу куча ошибок посыпалась :(

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

Добавлено: Пн янв 28, 2013 23:33:44
codenamehawk
Используйте два таймера.
Первый таймер в прерывании (по совпадению) сбрасываете счетчик и инвертируете нужную вам ногу.
Второй таймер в прерывании (по совпадению) сбрасываете счетчик и разрешаете-запрещаете работу первого.
(Тут не ясно что вы хотите получить из рисунка мало что понятно, какой диапазон частот ожидаете получить?)

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

Добавлено: Пн янв 28, 2013 23:39:26
dem66
Диапазон частот примерно 1Khz-100Khz, скважность 50%;

Если подскажите как это реализовать то буду очень благодарен.
У меня ваш код не компилируется, вываливается с ошибками на WGM01, COM00 и OCR0.

Компилирую в avr-gcc

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

Добавлено: Пн янв 28, 2013 23:40:18
codenamehawk
dem66 писал(а): Чтото не понял решения codenamehawk, там сразу куча ошибок посыпалась
Если прочитаете внимательно, то это прога для конкретного проца и без ошибок. Компилить надо WinAVR

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

Добавлено: Пн янв 28, 2013 23:41:53
dem66
уже увидел

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

Добавлено: Пн янв 28, 2013 23:49:49
codenamehawk
dem66 писал(а):Диапазон частот примерно 1Khz-100Khz, скважность 50%;

Если подскажите как это реализовать то буду очень благодарен.
У меня ваш код не компилируется, вываливается с ошибками на WGM01, COM00 и OCR0.

Компилирую в avr-gcc
Так мой пост перед вашим и есть подсказка, как вам еще подсказать?