Обсуждаем контроллеры компании Atmel.
Ответить

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

Вт мар 02, 2021 19:20:46

как ты можешь сравнивать OCR1B, если у тебя там записан НОЛЬ, и это значение нигде не изменяется?
и что такое PWR, тоже не понятно.
OCR1A тоже нигде не изменяется и OCR1A задает частоту ШИМ.
изменяется только сам счетчик таймера TCNT1.
а вот где задается длительность импульса, чтобы получить 40% периода, я что-то нигде не увидел.

ну да че т я тут лиху дал... убрал для вас 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кГц... и вот там то бегущее среднее хорошо работает... и я пока не увидел наглядности кода вашей идеи,чтобы так переделывать... извените! а так мне сложно судить.... и с прерываниями я не реализую дальнейшие задумки, мне так видится.

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

Вт мар 02, 2021 19:31:42

тогда делай, как тебе видится.

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

Вт мар 02, 2021 19:36:06

тогда делай, как тебе видится.

:kill: расстрелять тебя надо!

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

Вт мар 02, 2021 19:52:56

я тебе полезные советы давал, а ты меня расстрелять ...

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

Вт мар 02, 2021 20:21:22

Эмм... наверное не очень решение, но что в лоб пришло в голову - после среднего или медианного фильтра отсечь сэмплы выше оного и фильтрануть аналогично только оставшиеся?

А есди всё-таки вернуться к изначальному вопросу ТС именно по фильтру сигнала, почему бы всё-таки так не сделать? Вот мы высчитали среднее AVG на N сэмплов. Берем из этих семплов только те, которые < AVG и считаем их среднее, оно и будет для ШИМ в общем то лежать по нижней границы амплитуды сигнала. Не?

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

Вт мар 02, 2021 20:29:41

neid, к примеру смотри
СпойлерИзображение
Пытался на сколько возможно воспроизвести в протеусе, может шумов добавить надо было, ну да ладно, для наглядности и так сойдет.

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

Ср мар 03, 2021 12:39:14

Dimon456, Идею то я понял, мне б в своем реализовать коде, на примере моего кода что именно не правильно? хотите сказать по переполнению настроить таймер
Код:
if(OCR1B>0 && OCR1B<PWR) {adc_max_pwr=read_adc(0);} //т.е. когда период ШИМ Toff то меряем напругу без фильтрации

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

Ср мар 03, 2021 12:46:21

с этим условием измерение может повторяться многократно, пока условие выполняется.
и это не Димон, а я предлагал сделать прерывание по переполнению.
тогда в прерывании измерение будет сделано однократно. и измерение будет происходить каждый период ШИМ.

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

Ср мар 03, 2021 13:11:20

с этим условием измерение может повторяться многократно, пока условие выполняется.
и это не Димон, а я предлагал сделать прерывание по переполнению.

Хорошо это вы так предлагали! Нормально, что многократно, пусть пока во время периода ШИМ, идет время отключенного состояния сигнала Toff измеряем не один раз, а многократно. Вопрос в другом почему это условие не отрабатывает( какого ему пинка не хватает? или чего я не понимаю или не знаю?
Вложения
pwm-kw.jpg
(19.25 KiB) Скачиваний: 166

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

Ср мар 03, 2021 14:37:02

ты не показывал полный текст программы. я не могу знать, почему это условие у тебя не работает.
может, тебе и нравится многократное измерение, но последнее запущенное измерение может попасть на самое начало импульса, и будет искажение результата.
а зачем тебе многократное измерение во время паузы?
даже однократно у тебя будет 1000 измерений за 1 секунду, с частотой ШИМ.
а 1000 измерений за секунду - это и так до хрена, столько даже и не обязательно.

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

Ср мар 03, 2021 15:27:48

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

Вот это
Код:
#define IGLA   400                //Импульс 40.0%
константное выражение, такое выражения обрабатывается во время компиляции, а не при выполнении программы, как вы собираетесь менять это константное выражение во время выполнения программы?

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

Ср мар 03, 2021 16:00:07

а может ему и не надо его менять?

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

Ср мар 03, 2021 16:23:09

А я вот не хочу отвечать даже! вообще не о том речь!
А на 5 страниц мы ее сами растянем.
Жду вас на пятой странице!

константное выражение, такое выражения обрабатывается во время компиляции, а не при выполнении программы, как вы собираетесь менять это константное выражение во время выполнения программы?

а это вообще так важно сейчас узнать?!)))

Добавлено after 7 minutes 13 seconds:
ты не показывал полный текст программы. я не могу знать, почему это условие у тебя не работает.
может, тебе и нравится многократное измерение, но последнее запущенное измерение может попасть на самое начало импульса, и будет искажение результата.
а зачем тебе многократное измерение во время паузы?
даже однократно у тебя будет 1000 измерений за 1 секунду, с частотой ШИМ.
а 1000 измерений за секунду - это и так до хрена, столько даже и не обязательно.

лучше объясните как узнать частоту опроса ацп, что в самом начале темы мелькало от вас?

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

Ср мар 03, 2021 16:33:40

чтобы узнать частоту опроса, нужно видеть полный текст программы.
и даже видя полный текст, если у тебя опрос не привязан к таймеру, а крутится в майне, то не известно, как быстро идет это верчение в майне.
а если ты сделаешь опрос в прерывании по переполнению ШИМ, то частота опроса будет в точности равна частоте ШИМ.

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

Ср мар 03, 2021 19:19:54

чтобы узнать частоту опроса, нужно видеть полный текст программы.


Код:
удалил по причине невнимательности Starichok51
Последний раз редактировалось neid Ср мар 03, 2021 21:26:55, всего редактировалось 3 раз(а).

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

Ср мар 03, 2021 20:55:53

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

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

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

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

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

Ср мар 03, 2021 21:23:39

зачем тебе параметр "К", если он в вычислениях явно не упоминается?

ранее писал же это коэффициент для бегущее среднее
зачем в прерывании каждый раз вычислять PWR=(PERIOD_kHz*(1000-IGLA))*0.001,
если IGLA - константа на время компиляции, и PWR можно вычислить один раз при объявлении параметра PWR?

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

и на последок пример кода покажите как измерять АЦП по прерыванию когда ШИМ 1кГц, для обучения! А то слов много, а дела с вас двоих - ни шиша! вот и поучимся у нормальных программистов!

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

Чт мар 04, 2021 06:32:19

и в чем заключалась моя невнимательность, которая послужила причиной удаления исходника?
я самоучка в программировании, у меня тоже нет специального образования.
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);

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

Чт мар 04, 2021 09:05:31

А что целиком код был? Жаль, не видал.
Я то же не программист, у меня образование 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 года, мне уже лень что либо делать.

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

Чт мар 04, 2021 09:52:09

Dimon456 писал(а):А что целиком код был?
да, был. но он обиделся на меня за мои комментарии к коду и удалил код.
Ответить