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

Atmega8 OCR1A и OCR1B 2 шим канала

Добавлено: Пт ноя 18, 2016 18:49:46
BIOS23
всем привет! Ознакомившись с ардуиной и немного попрактиковавшись плавно перешел игры с Атмега8 и Аттини13. Дается очень тяжело, но шаг за шагом разобрался с АЦП и прочими мелочами. Вот сейчас мучаю таймера. И есть моменты которые очень хотелось бы обсудить с более опытными людьми.
Можно ли реализовать 2 независимых ШИМа на таймере1. Что бы OCR1A и OCR1B выдавали 2 каждый свой независимый шим?
вот на данный момент настройки регистров, но когда я управляю каждыйм каналом то они как то непонятно зависимы друг от друга.

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


	/*** Настройка Таймера для PWM ***/	
TCCR1A |= (1 << COM1A1)|(0 << COM1A0) // Установим биты COM1A1-COM1A0:0b10, означает сброс вывода канала A при сравнении
		| (1 << COM1B1)|(0 << COM1B0)
		| (0 << WGM11)|(1 << WGM10); // Установим биты WGM13-10:0b1110, согласно таблице это
TCCR1B |= (0 << WGM13)|(1 << WGM12) // будет режим - FAST PWM, где верхний предел счета задается битом ICR1
       |(0 << CS12)|(0 << CS11)|(1 << CS10); // Битами CS12-10:0b001 задаем источник тактового сигнала для таймера МК, включен без делителя
	   
TCNT1 = 0x00; // начальная установка счетчика
ICR1 = 0xFF; // задаем период ШИМ, здесь у нас число 255,
OCR1A = 0x00; // начальный коэффициент заполнения ШИМ
OCR1B = 0x00; // начальный коэффициент заполнения ШИМ


Re: Atmega8 OCR1A и OCR1B 2 шим канала

Добавлено: Пт ноя 18, 2016 20:35:04
Starichok51
BIOS23 писал(а): | (0 << WGM11)|(1 << WGM10); // Установим биты WGM13-10:0b1110, согласно таблице это
TCCR1B |= (0 << WGM13)|(1 << WGM12) // будет режим - FAST PWM, где верхний предел счета задается битом ICR1
на самом деле, ты установил WGM13-10:0b0101 (режим №5, Fast PWM, 8-bit).
а зачем тебе понадобилось управлять с помощью регистра (а не бита) ICR1?
регистр ICR1 считает от аналогового компаратора. это тебе нужно?
BIOS23 писал(а):ICR1 = 0xFF; // задаем период ШИМ, здесь у нас число 255
ты загружаешь всего 8 бит. вот, ограничься заданным тобой режимом №5...

Re: Atmega8 OCR1A и OCR1B 2 шим канала

Добавлено: Пт ноя 18, 2016 23:32:34
BIOS23
сделал вот так (режим 5)

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

TCCR1A |= (1 << COM1A1)|(0 << COM1A0) // Установим биты COM1A1-COM1A0:0b10, означает сброс вывода канала A при сравнении
		| (1 << COM1B1)|(0 << COM1B0)
		| (0 << WGM11)|(1 << WGM10); // Установим биты WGM13-10:0b1110, согласно таблице это
TCCR1B |= (0 << WGM13)|(1 << WGM12) // будет режим - FAST PWM, где верхний предел счета задается битом ICR1
       |(0 << CS12)|(0 << CS11)|(1 << CS10); // Битами CS12-10:0b001 задаем источник тактового сигнала для таймера МК, включен без делителя
но всеравно если я изменяю значение OCR1A то на OCR1B тоже происходит влияние

чтото мне подсказывает что не получится на 1м таймере сделать 2 независимых ШИМ канала, потмоу что TCNT1 у них общий как я понял, или я нифига не понял, придется использовать таймер 1 и таймер2

Добавлено after 1 hour 47 minutes 51 second:
изследовав некоторые моменты.
Я получаю значение с АЦП (2 потенциометра работают в роле делителей и подают напряжение на 2 ножки контроллера), каждый потенциометр управляет заполнением шима каждого канала.

вот настройки АЦП:

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

	ADCSRA |= (1 << ADEN) // Включение АЦП
            |(1 << ADPS2) |(0 << ADPS1)|(1 << ADPS0);    // предделитель преобразователя на 32 , частота 62 КГц
	ADMUX |= (0 << REFS1) | (1 << REFS0); // опорное напряжение внешнее с кондером 0,1uF

и функция работы с ножками

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


unsigned int ReadADC(unsigned int ch) // принимает на вход вариант номера пина
{
	unsigned char setADMUX = ADMUX;
	setADMUX &= ~((1 << MUX3)|(1 << MUX2)|(1 << MUX1)|(1 << MUX0)); // ADC0 про дефоулту 
	switch(ch)
	{
		case 1: setADMUX |= (0 << MUX3)|(0 << MUX2)|(0 << MUX1)|(1 << MUX0); break; // PС1 ADC1 номер пина адц
		case 2: setADMUX |= (0 << MUX3)|(0 << MUX2)|(1 << MUX1)|(0 << MUX0); break; // PС2 ADC2 номер пина адц
		case 3: setADMUX |= (0 << MUX3)|(0 << MUX2)|(1 << MUX1)|(1 << MUX0); break; // PС3 ADC3 номер пина адц
		case 4: setADMUX |= (0 << MUX3)|(1 << MUX2)|(0 << MUX1)|(0 << MUX0); break; // PС4 ADC4 номер пина адц
		case 5: setADMUX |= (0 << MUX3)|(1 << MUX2)|(0 << MUX1)|(1 << MUX0); break; // PС5 ADC5 номер пина адц
		default: break;
	}	
	
	ADMUX = setADMUX;
	_delay_us(10);	
	int tmp = 0;
	for(int i = 0; i<40; i++) // усредняем скачки напряжения
	{
		ADCSRA |= (1 << ADSC);    // Начинаем преобразование
		while ((ADCSRA &(1 << ADCSRA))== 0); // Ждем флага окончания преобразования  
		tmp += ADC;  // Считываем  ADC
	}		
		return tmp/40; 
}

и вот так я заполняю шим:

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

	OCR1A =ReadADC(0)/4; 
	OCR1B =ReadADC(1)/4;

проблема оказывается в АПЦ, почемуто значение с одной ножки АЦП управляют частично каждым каналом, в чем беда, как так может быть, может кто увидет баг ?

Re: Atmega8 OCR1A и OCR1B 2 шим канала

Добавлено: Сб ноя 19, 2016 00:05:51
mrFox
что подразумевается под влиянием
если нужно, чтоб сигналы на выходах A и B не пересекались
то А настраивается - включение при 0, выключение при совпадении
В настраивается - выключение при 0, включение при совпадении
в OCRA даем значение valA
в OCRB даем значение 0xFF-valB
при valA + valB < 0xFF
пересечения сигналов не будел

Re: Atmega8 OCR1A и OCR1B 2 шим канала

Добавлено: Сб ноя 19, 2016 01:15:08
BIOS23
сейчас попробую ваш вариант, но я пробовал таймер1 А канал и таймер2, то у меня оба потенциометра влияли на оба шима одновременно, очень странно, я начал подозревать ацп, так как оттуда получаю значения.

Добавлено after 37 minutes 33 seconds:
TCCR1A |= (1 << COM1A1)|(0 << COM1A0)
| (1 << COM1B1)|(1 << COM1B0)
| (0 << WGM11)|(1 << WGM10);



OCR1A = ReadADC(0)/4;

OCR1B = 255 - ReadADC(1)/4;

не работает, я уже немогу, как тольк оне пробовал,и условие valA + valB < 0xFF тыкал , они зависимы друг от друга.

Re: Atmega8 OCR1A и OCR1B 2 шим канала

Добавлено: Сб ноя 19, 2016 07:46:56
Starichok51
BIOS23 писал(а):while ((ADCSRA &(1 << ADCSRA))== 0); // Ждем флага окончания преобразования
что за фигню ты тут написал?
тебе нужно проверять бит ADSC, а ты записал еще раз название всего регистра. потому и не работает нормально программа.
надо быть внимательным, чтобы потом не задавать "глупых" вопросов.

вот тут http://radiokot.ru/forum/viewtopic.php?f=11&t=134419 моя тема, где прекрасно работают оба ШИМ с настройкой "включение при 0, выключение при совпадении".
и никакого взаимного влияния или "пересечения" каналов нет и не должно быть.
у меня выбран режим Fast PWM, 10-bit (0111, №7). но в данном случае другой номер режим значения не имеет.
при обработке ШИМ я записываю в регистры сравнения разные величины:
; вычисляю "выход" первого канала и вывожу его
out OCR1AH, R21
out OCR1AL, R20 ; выводим "выходной сигнал" ШИМ в регистры сравнения таймера1
и
; вычисляю "выход" второго канала и вывожу его
out OCR1BH, R21
out OCR1BL, R20 ; выводим "выходной сигнал" ШИМ в регистры сравнения таймера1
и никакого взаимного влияния нет.

Re: Atmega8 OCR1A и OCR1B 2 шим канала

Добавлено: Сб ноя 19, 2016 11:23:57
BIOS23
АЦП писал по уроку из ютуба, там дядька так рассказывал, звучало убедительно. )))
спс за ответ, сейчас буду пробовать.

Добавлено after 2 hours 18 minutes 43 seconds:
еще интересный момент: я беру опорные 5 вольт со входа ref, но значение ацп получаю 1023 при 4х вольтах

Re: Atmega8 OCR1A и OCR1B 2 шим канала

Добавлено: Сб ноя 19, 2016 12:07:51
Starichok51
не видя схемы твоего изделия, я не знаю, откуда и как ты берешь опорное...
я "на слово" не верю, так как ты сначала писал, что берешь (задаешь) опору с AVCC (ADMUX |= (0 << REFS1) | (1 << REFS0); // опорное напряжение внешнее с кондером 0,1uF), а теперь появилось какое-то буквосочетание "ref", которого в описании контроллера просто нет.
в описании есть вход "AREF".
и строка
ADMUX |= (0 << REFS1) | (1 << REFS0); // опорное напряжение внешнее с кондером 0,1uF
означает именно то, что опора берется с AVCC, а на вход AREF вешается конденсатор.
да, я, естественно, понял, что ты именно это и хотел сказать, но выражаться нужно абсолютно точно и однозначно. иначе твои неточные слова могут привести к непониманию и ты других людей можешь ввести в заблуждение.
учись выражать свои мысли так, чтобы люди тебя понимали с одного раза, а не пытались уточнить, что ты там имел в виду...
BIOS23 писал(а):но значение ацп получаю 1023 при 4х вольтах
ну что тут можно посоветовать? бери в руки мультиметр и измеряй напряжение питания и измеряй напряжение на входе AVCC. скорее всего, до AVCC доходит всего 4 Вольта, а не 5 Вольт...

Re: Atmega8 OCR1A и OCR1B 2 шим канала

Добавлено: Сб ноя 19, 2016 19:40:23
BIOS23
ну конечно же я мерял мультиметром напряжение на ножке AREF. 5вольт!
по поводу того что было опорное с конденсатором, это было в начале, я уже поменял на просто со входа. Я уже что только не пробовал, по этому могут быть такие путаницы.
За неточные выражения прошу прощения, я сам считаю себя педантичным человеком и предпочитаю выражатся четко и используя правильные термины, просто уже сил нету мучать Атмегу ну и пошел в ход чтото типа сленга. :)

вот светодиод загорается на 100 ШИМ при 4х вольтах на входе ADC0 когда я даю напряжение с потенциометра. дальше когда докручиваю потенциометр после 4х вольт шим сбрасуется на 0 и идет опять по нарастающей примерно до 3ти заполнения на 5ти вольтах. переполнения типа происходит.

и вот так я пробовал тестить :

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


		if(ReadADC(0)>1023)
			OCR1A = 255;
		else
			OCR1A = 0;

на OCR1A вешал светодиод и он загорается при 4х вольтах (потенциометр недокручен до конца)

Добавлено after 2 hours 14 minutes 44 seconds:
всем огромное спасибо, я разобрался в своих проблемах.
Проблема с АЦП решилась, сотый раз перечитывая код я нашел ошибку. Вот в функции вычисления АЦП:

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

unsigned int ReadADC(unsigned int ch) // принимает на вход вариант номера пина
{
	unsigned char setADMUX = ADMUX;
	setADMUX &= ~((1 << MUX3)|(1 << MUX2)|(1 << MUX1)|(1 << MUX0)); // ADC0 про дефоулту 
	switch(ch)
	{
		case 1: setADMUX |= (0 << MUX3)|(0 << MUX2)|(0 << MUX1)|(1 << MUX0); break; // PС1 ADC1 номер пина адц
		case 2: setADMUX |= (0 << MUX3)|(0 << MUX2)|(1 << MUX1)|(0 << MUX0); break; // PС2 ADC2 номер пина адц
		case 3: setADMUX |= (0 << MUX3)|(0 << MUX2)|(1 << MUX1)|(1 << MUX0); break; // PС3 ADC3 номер пина адц
		case 4: setADMUX |= (0 << MUX3)|(1 << MUX2)|(0 << MUX1)|(0 << MUX0); break; // PС4 ADC4 номер пина адц
		case 5: setADMUX |= (0 << MUX3)|(1 << MUX2)|(0 << MUX1)|(1 << MUX0); break; // PС5 ADC5 номер пина адц
		default: break;
	}	
	
	ADMUX = setADMUX;
	_delay_us(10);	
	int tmp = 0;
	for(int i = 0; i<40; i++) // усредняем скачки напряжения
	{
		ADCSRA |= (1 << ADSC);    // Начинаем преобразование
		while ((ADCSRA &(1 << ADSC))== 0); // Ждем флага окончания преобразования  
		
		tmp += ADC;  // Считываем  ADC
	}		
		return tmp/40; 
}
проблема в переполнении типа int в переменной tmp.
дело в том что в цыкле 40 раз я сумирую результат, и если значение АЦП близится к 1000 (5 вольт) то 1000*40 мы получаем 40000, но тип инт 32тыс с хвостиком, и соответственно у нас при переполненни типа получается.
изменил количество итераций на 20, теперь все в порядке. Можно было бы и сделать тип другой у tmp например unsigned int.

также и решилась вторая проблема с зависимостью значений в регистрах OCR1A и OCR1B. сделал вот так

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

	//// Настройка Таймера1 для PWM ////
TCCR1A |= (1 << COM1A1)|(0 << COM1A0) // не инвертированый PWM
		| (1 << COM1B1)|(1 << COM1B0)  //  инвертированый PWM
		| (0 << WGM11)|(1 << WGM10); // Установим биты WGM13-10:0b1110, согласно таблице это
TCCR1B |= (0 << WGM13)|(1 << WGM12) // будет режим - FAST PWM, где верхний предел счета задается битом ICR1
       |(0 << CS12)|(0 << CS11)|(1 << CS10); // Битами CS12-10:0b001 задаем источник тактового сигнала для таймера МК, включен без делителя
[code]

и в мейни в цыкле дергаю ацп и заношу значения в регистры сравнения
[code]

		OCR1A = ReadADC(0)/4;
		OCR1B = ReadADC(1)/4;
все клево, все работает.