Фильтр АЦП atmega 8 по нижней границе

Обсуждаем контроллеры компании Atmel.
Ответить
Прорезались зубы
Сообщения: 228
Зарегистрирован: Пн окт 04, 2010 11:55:41

Сообщение neid »

[uquote="Starichok51",url="/forum/viewtopic.php?p=3990412#p3990412"]как ты можешь сравнивать OCR1B, если у тебя там записан НОЛЬ, и это значение нигде не изменяется?
и что такое PWR, тоже не понятно.
OCR1A тоже нигде не изменяется и OCR1A задает частоту ШИМ.
изменяется только сам счетчик таймера TCNT1.
а вот где задается длительность импульса, чтобы получить 40% периода, я что-то нигде не увидел.[/uquote]
ну да че т я тут лиху дал... убрал для вас PWR и все лишнее, но раз надо, добавил опять... по этому и сравниваю с 0 и PWR

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

#define PERIOD_kHz 7999     //настроим Т1 на 1мс (1 кГц) = 8000000/1000Гц=8000-1=7999
#define IGLA   400                //Импульс 40.0%
int PWR;

//*******Timer1 output compare A interrupt service routine***********************
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
timer++;                                                        //таймер шим 1кГц                                                     
PWR=(PERIOD_kHz*(1000-IGLA))*0.001;   
OCR1B=PWR;    //т.к С ИНВЕРСИЕЙ - считаем так
} // end Timer1
//**********************************************************************

и настройки таймера1 не буду писать
таймер так настроен не спроста, будет пару идей еще реализовано, например 35Гц/1кГц... и вот там то бегущее среднее хорошо работает... и я пока не увидел наглядности кода вашей идеи,чтобы так переделывать... извените! а так мне сложно судить.... и с прерываниями я не реализую дальнейшие задумки, мне так видится.
Реклама
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

тогда делай, как тебе видится.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Реклама
Прорезались зубы
Сообщения: 228
Зарегистрирован: Пн окт 04, 2010 11:55:41

Сообщение neid »

[uquote="Starichok51",url="/forum/viewtopic.php?p=3990441#p3990441"]тогда делай, как тебе видится.[/uquote]
:kill: расстрелять тебя надо!
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

я тебе полезные советы давал, а ты меня расстрелять ...
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Реклама
Эиком - электронные компоненты и радиодетали
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

[uquote="NStorm",url="/forum/viewtopic.php?p=3990015#p3990015"]Эмм... наверное не очень решение, но что в лоб пришло в голову - после среднего или медианного фильтра отсечь сэмплы выше оного и фильтрануть аналогично только оставшиеся?[/uquote]
А есди всё-таки вернуться к изначальному вопросу ТС именно по фильтру сигнала, почему бы всё-таки так не сделать? Вот мы высчитали среднее AVG на N сэмплов. Берем из этих семплов только те, которые < AVG и считаем их среднее, оно и будет для ШИМ в общем то лежать по нижней границы амплитуды сигнала. Не?
Реклама
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

neid, к примеру смотри
СпойлерИзображение
Пытался на сколько возможно воспроизвести в протеусе, может шумов добавить надо было, ну да ладно, для наглядности и так сойдет.
Реклама
Прорезались зубы
Сообщения: 228
Зарегистрирован: Пн окт 04, 2010 11:55:41

Сообщение neid »

Dimon456, Идею то я понял, мне б в своем реализовать коде, на примере моего кода что именно не правильно? хотите сказать по переполнению настроить таймер

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

if(OCR1B>0 && OCR1B<PWR) {adc_max_pwr=read_adc(0);} //т.е. когда период ШИМ Toff то меряем напругу без фильтрации
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

с этим условием измерение может повторяться многократно, пока условие выполняется.
и это не Димон, а я предлагал сделать прерывание по переполнению.
тогда в прерывании измерение будет сделано однократно. и измерение будет происходить каждый период ШИМ.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Прорезались зубы
Сообщения: 228
Зарегистрирован: Пн окт 04, 2010 11:55:41

Сообщение neid »

[uquote="Starichok51",url="/forum/viewtopic.php?p=3990829#p3990829"]с этим условием измерение может повторяться многократно, пока условие выполняется.
и это не Димон, а я предлагал сделать прерывание по переполнению.[/uquote]
Хорошо это вы так предлагали! Нормально, что многократно, пусть пока во время периода ШИМ, идет время отключенного состояния сигнала Toff измеряем не один раз, а многократно. Вопрос в другом почему это условие не отрабатывает( какого ему пинка не хватает? или чего я не понимаю или не знаю?
Вложения
pwm-kw.jpg
(19.25 КБ) 189 скачиваний
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

ты не показывал полный текст программы. я не могу знать, почему это условие у тебя не работает.
может, тебе и нравится многократное измерение, но последнее запущенное измерение может попасть на самое начало импульса, и будет искажение результата.
а зачем тебе многократное измерение во время паузы?
даже однократно у тебя будет 1000 измерений за 1 секунду, с частотой ШИМ.
а 1000 измерений за секунду - это и так до хрена, столько даже и не обязательно.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

neid писал(а):Вопрос в другом почему это условие не отрабатывает( какого ему пинка не хватает? или чего я не понимаю или не знаю?
А я вот не хочу отвечать даже! вообще не о том речь!
А на 5 страниц мы ее сами растянем.

Вот это

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

#define IGLA   400                //Импульс 40.0%
константное выражение, такое выражения обрабатывается во время компиляции, а не при выполнении программы, как вы собираетесь менять это константное выражение во время выполнения программы?
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

а может ему и не надо его менять?
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Прорезались зубы
Сообщения: 228
Зарегистрирован: Пн окт 04, 2010 11:55:41

Сообщение neid »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3990939#p3990939"]А я вот не хочу отвечать даже! вообще не о том речь!
А на 5 страниц мы ее сами растянем.[/uquote] Жду вас на пятой странице!

[uquote="Dimon456",url="/forum/viewtopic.php?p=3990939#p3990939"]константное выражение, такое выражения обрабатывается во время компиляции, а не при выполнении программы, как вы собираетесь менять это константное выражение во время выполнения программы?[/uquote]
а это вообще так важно сейчас узнать?!)))

Добавлено after 7 minutes 13 seconds:
[uquote="Starichok51",url="/forum/viewtopic.php?p=3990890#p3990890"]ты не показывал полный текст программы. я не могу знать, почему это условие у тебя не работает.
может, тебе и нравится многократное измерение, но последнее запущенное измерение может попасть на самое начало импульса, и будет искажение результата.
а зачем тебе многократное измерение во время паузы?
даже однократно у тебя будет 1000 измерений за 1 секунду, с частотой ШИМ.
а 1000 измерений за секунду - это и так до хрена, столько даже и не обязательно.[/uquote]
лучше объясните как узнать частоту опроса ацп, что в самом начале темы мелькало от вас?
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

чтобы узнать частоту опроса, нужно видеть полный текст программы.
и даже видя полный текст, если у тебя опрос не привязан к таймеру, а крутится в майне, то не известно, как быстро идет это верчение в майне.
а если ты сделаешь опрос в прерывании по переполнению ШИМ, то частота опроса будет в точности равна частоте ШИМ.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Прорезались зубы
Сообщения: 228
Зарегистрирован: Пн окт 04, 2010 11:55:41

Сообщение neid »

[uquote="Starichok51",url="/forum/viewtopic.php?p=3990983#p3990983"]чтобы узнать частоту опроса, нужно видеть полный текст программы.[/uquote]

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

удалил по причине невнимательности Starichok51
Последний раз редактировалось neid Ср мар 03, 2021 21:26:55, всего редактировалось 3 раза.
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

зачем тебе параметр "К", если он в вычислениях явно не упоминается?
зачем в прерывании каждый раз вычислять
PWR=(PERIOD_kHz*(1000-IGLA))*0.001,
если IGLA - константа на время компиляции, и PWR можно вычислить один раз при объявлении параметра PWR?
зачем тебе параметр newTime, если он внутри функции никак не изменяется? в вычислениях можно прямо использовать переменную timer2.

да, по тексту время "вращения" в цикле while не определить. это время вполне может оказаться меньше одного периода ШИМ (1 мс).

нормальные программисты создают систему реального времени.
это значит, что все действия в программе синхронизированы таймером.
а без привязки к реальному времени, как это сделано у тебя, это не грамотно с профессиональной точки зрения.
только с привязкой к реальному времени можно точно задать, сколько раз в секунду будет крутится цикл while.

привязку к реальному времени можно сделать прерыванием по переполнению таймера ШИМ (уже который раз тебе это говорю).
прерывание по переполнению устанавливает признак (назовем его флаг), что это прерывание произошло.
цикл while в самом своем начале "топчется" на месте, проверяя этот твой флаг.
как только флаг появился, сбрасываем этот флаг и делаем все действия, которые у тебя перечислены в цикле while.
только в этом случае мы можем четко сказать, что измерения делаются 1000 раз в секунду (период ШИМ 1 мс).
и еще можем сказать, что измерения будут сделаны именно тогда, когда импульса нет. то есть, когда нет никакой "помехи" для корректного измерения.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Прорезались зубы
Сообщения: 228
Зарегистрирован: Пн окт 04, 2010 11:55:41

Сообщение neid »

[uquote="Starichok51",url="/forum/viewtopic.php?p=3991167#p3991167"]зачем тебе параметр "К", если он в вычислениях явно не упоминается?[/uquote]
ранее писал же это коэффициент для бегущее среднее
[uquote="Starichok51",url="/forum/viewtopic.php?p=3991167#p3991167"]зачем в прерывании каждый раз вычислять PWR=(PERIOD_kHz*(1000-IGLA))*0.001,
если IGLA - константа на время компиляции, и PWR можно вычислить один раз при объявлении параметра PWR?[/uquote]
за этим, тоже обсуждали if(OCR1B>0 && OCR1B<PWR) {adc_max_pwr=read_adc(0);} //т.е. когда период ШИМ Toff то меряем напругу без фильтрации
[uquote="Starichok51",url="/forum/viewtopic.php?p=3991167#p3991167"]зачем тебе параметр newTime, если он внутри функции никак не изменяется? в вычислениях можно прямо использовать переменную timer2.[/uquote] можно, пока мне так удобней
НА МНОГИЕ ВАШИ ЗАЧЕМ, ОТВЕТ БЫЛ - Я ТОЛЬКО НАЧИНАЮ ПРОГРАММИРОВАТЬ, Я НЕ НОРМАЛЬНЫЙ ПРОГРАММИСТ, У МЕНЯ НЕТ ОБРАЗОВАНИЯ ПРОГРАММИСТА! МЕНЯ НИ КТО НЕ УЧИЛ РАНЕЕ! ЗАМЕНИТЕ СЛОВО ЗАЧЕМ НА СЛОВО СЛЕДОВАЛО БЫ! НАДЕЮСЬ УСЛЫШАЛ! ВООБЩЕ ЭТО ПЕРВАЯ ПРОГРАММА!

и на последок пример кода покажите как измерять АЦП по прерыванию когда ШИМ 1кГц, для обучения! А то слов много, а дела с вас двоих - ни шиша! вот и поучимся у нормальных программистов!
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

и в чем заключалась моя невнимательность, которая послужила причиной удаления исходника?
я самоучка в программировании, у меня тоже нет специального образования.
neid писал(а):ранее писал же это коэффициент для бегущее среднее
ну писал, и что из этого? если он нигде в вычислениях не участвует в явном виде, то он не нужен.
neid писал(а):за этим, тоже обсуждали if(OCR1B>0 && OCR1B<PWR)
ну обсуждали, и что из этого? если PWR - постоянная величина, которую можно вычислить один раз, то не нужно вычислять ее бессчетное число раз в прерывании
neid писал(а):пока мне так удобней
если удобнее, ну и ладно.
я пишу только на ассемблере, поэтому на Си пример тебе сделать не могу.
хотя я тебе описал словами очень подробно, что нужно сделать. а тебе остается добавить прерывание по переполнению и объявить флаг наступления этого прерывания.
если уж ты сумел так написать свою первую программу, то добавить в нее еще чуточку не должно составлять проблему.

Добавлено after 8 hours 39 minutes 12 seconds:
вот, попробовал изложить на Си то, что я предлагал сделать:

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

// тут все твои ранее сделанные объявления
// объявляем переменную-флаг
byte overflow_yes = 0;

// добавляем прерывание по переполнению
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
	overflow_yes = 0;
}

// тут все твои ранее орисанные функции

void main(void)
{
// тут все твоя ранее сделанная инициальзация

// настройки таймера несколько изменяем
// чтобы прерывания не наступили сразу же после запуска таймера, сначала устанавливаем все регистры
// и только потом настраиваем режим и делаем пуск таймера
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x1F; // 1F3F(7999) - 1кГц - 1.0000 ms
OCR1AL=0x3F;
OCR1BH=0x00;
OCR1BL=0x00;
TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (1<<COM1B1) | (1<<COM1B0) | (1<<WGM11) | (1<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (1<<WGM13) | (1<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10);
TIMSK=(1<<OCIE1A) | (1<<TOIE1);
// и теперь разрешаем прерывания
sei;

	while(1)
	{
		while (overflow_yes == 0)	// пока прерывание не наступило,
			;				// "топчемся на месте" и ничего не делаем
		overflow_yes = 0;		// прерывание наступило - сбрасываем флаг
		// тут всё ранее написанное "тело" цикла while(1)
	}
}
поскольку я для МК на Си не пишу, мог что-нибудь неправильно написать. например, мог не правильно записать объявление переменной-флага overflow_yes.
мог не правильно записать и название прерывания по переполнению.

попутно еще замечу, что нет смысла задвигать биты, которые равны нулю.
достаточно задвинуть только те биты, которые равны единице.
вот так:
TCCR1A=(1<<COM1B1) | (1<<COM1B0) | (1<<WGM11) | (1<<WGM10);
TCCR1B=(1<<WGM13) | (1<<WGM12) | (1<<CS10);
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

А что целиком код был? Жаль, не видал.
Я то же не программист, у меня образование 5 классов церковно-приходской, и вообще не понимаю в этих "иероглифах", какой-то "птичий язык".
Ну да ладно, мой код.
СпойлерИ так задача - запускать АЦП между импульсами ШИМ.

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

volatile uint16_t rezultat2;

// глубина буфера усреднения. чем больше, тем сильнее фильтрация и медленнее работа
// очень хорошо, если число кратно степени двойки (т.е. 1, 2, 4, 8, 16, 32, 64 и т.д.)
#define AVERAGE_DEPTH	8	
// функция получает результат очередного замера и возвращает отфильтрованное значение
__inline static uint16_t get_average (uint16_t val){
  static uint16_t buf[AVERAGE_DEPTH];
  static uint8_t cur;
  uint32_t sum = 0;

  buf[cur++] = val;
  if(cur >= AVERAGE_DEPTH) cur = 0;

  for(uint8_t i=0; i < AVERAGE_DEPTH; i++) sum += buf[i];

  return sum / AVERAGE_DEPTH;
}


// Timer1 output compare A interrupt service routine
ISR(TIMER1_COMPA_vect)
{
// Start the AD conversion
ADCSRA|=(1<<ADSC);
while ((ADCSRA & (1<<ADIF))==0);
ADCSRA|=(1<<ADIF);
 rezultat2 = get_average(ADCW);
 
 timer++;        //таймер шим 1кГц	
}

// Voltage Reference: AVCC pin
#define ADC_VREF_TYPE ((0<<REFS1) | (1<<REFS0) | (0<<ADLAR))

#define PERIOD_kHz 7999UL     //настроим Т1 на 1мс (1 кГц) = 8000000/1000Гц=8000-1=7999
#define IGLA   400                //Импульс 40.0%

int main()
{

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 8000,000 kHz
// Mode: Fast PWM top=ICR1
// OC1A output: Disconnected
// OC1B output: Inverted PWM
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer Period: 1 ms
// Output Pulse(s):
// OC1B Period: 1 ms Width: ... ms
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (1<<COM1B1) | (1<<COM1B0) | (1<<WGM11) | (0<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (1<<WGM13) | (1<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10);

TCNT1=0;

ICR1=0x1F3F;	// 1F3F(7999) - 1кГц - 1.0000 ms

OCR1A=0;

OCR1B = (PERIOD_kHz*(1000-IGLA))*0.001;	// 40%

// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=(0<<ICIE1) | (0<<OCIE1B) | (1<<OCIE1A) | (0<<TOIE1);

// ADC initialization
// ADC Clock frequency: 125,000 kHz
// ADC Voltage Reference: AVCC pin
// ADC Auto Trigger Source: ADC Stopped
// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
// ADC4: On, ADC5: On
DIDR0=(0<<ADC5D) | (0<<ADC4D) | (0<<ADC3D) | (0<<ADC2D) | (0<<ADC1D) | (0<<ADC0D);
ADMUX= 0 | ADC_VREF_TYPE;
ADCSRA=(1<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0);
ADCSRB=(0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);

sei();
   
while (1)
      {
      // Place your code here
      }
 }
Комментарии к коду:
Режим ШИМ Fast PWM top=ICR1
По какой то причине, а может и к лучшему режим выхода ШИМ OC1B output: Inverted PWM
значит ШИМ заполняется, скажем так, с конца а не сначала.
Соответственно когда TCNT1 будет равен 0 ШИМ будет выключен,
отсюда формируем прерывание Compare A Match Interrupt по совпадению OCR1A=0

И запускаем модуль АЦП, хорошо что один канал надо всего измерять.
От точки входа в прерывание, даже не от точки входа, а от момента когда произошло переключение ШИМ с высокого на низкий уровень, до функции get_average(ADCW) проходит ~110us, судя по измерениям в протеусе, значит %заполнения ШИМ не должен превышать 88%, в противном случае ШИМ перекроет измерение АЦП, и оно будет не корректным.

Размер кода в прерывании максимально минимизирован благодаря __inline функции.
После расчета rezultat2 = get_average(ADCW) пожалуйста вставляете что хотите, к примеру timer++.

Функция get_average работает с целыми числами, а не с типом float.

Писал левой ногой, могу ошибаться, в железе не проверял, это АКБ тащит надо, ключ какой-то делать, и вообще мне 52 года, мне уже лень что либо делать.
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

Dimon456 писал(а):А что целиком код был?
да, был. но он обиделся на меня за мои комментарии к коду и удалил код.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Ответить

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