А что целиком код был? Жаль, не видал. Я то же не программист, у меня образование 5 классов церковно-приходской, и вообще не понимаю в этих "иероглифах", какой-то "птичий язык". Ну да ладно, мой код. [spoiler]И так задача - запускать АЦП между импульсами ШИМ.
Код:
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);
// 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%, в противном случае ШИМ перекроет измерение АЦП, и оно будет не корректным.
Привет! Изучаю таймеры. вот тут нарыл эту тему, мне в отличии от автора нужно не измерять напряжение когда ШИМ периода 0, просто флаг ставить правда когда период ШИМ сигнала в 1, а не в 0, и возводить флаг 1. И у меня возникло несколько вопросов, почему вы рекомендуете режим ШИМ Fast PWM top=ICR1, а не Fast PWM top=OCR1A и как сделать это при выходе ШИМ OC1B output: Inverted PWM. Как понять что у нас сейчас в периоде ШИМ сигнала стоит высокий уровень, и сказать об этом флагом? Автор тут что то начудил конечно с if(OCR1B>0 && OCR1B<PWR), ясное дело что OCR1B не увидишь изменения, тут лучше следить за TCNT1. но каким образом? Приходит на мой юный ум что то:
Код:
interrupt [TIM1_COMPA] void timer1_compa_isr(void) { if (TCNT1 > 0 && TCNT1 < PWR) {flag = 0; //в момент когда Toff пднимемн флаг в } else {flag = 1;} }
...но это тоже полная ерись... Вы ему советуете измерять чтобы ШИМ не привышал 88% понято дело почему, в этом периоде сначала идет низкий уровень, и максимум из ~110us на измерение можно выжать 8 измерений на 1ms. А как понять что у нас уже высокий уровень ШИМ ведь период начинается с низкого, и если мы это поняли то поднимает флаг, как только низкий уровень, то опустили флаг? Можно конечно поменять выход на OC1B output: Non Inverted PWM, но задача остается для меня не решенной как это реализовать?
а как прерывание по переполнению, прерывание наступило и что, у меня 50% высокий уровень 50% низкий. От чего мне отталкиваться, или от какой переменной?
1.а за каким хреном понадобился тебе этот флаг? 2.а где и как ты собрался проверять этот флаг? 3.и как ты собрался использовать этот флаг?
1. лично для меня флаг понадобился сделать к примеру 1000 импульсов, или 2000 насчитать... прошел верхний уровень периода ШИМ , счетчик инкрементирую... 2. как и где лучше проверить, это к вам вопрос по реализации, у меня скудно мыслей по этому поводу, но хотел бы научиться могу конечно написать что то такое:
Код:
while(1){ if(flag==1) {cnt++;} }
3. далее отсчитал 2000 импульсов и выключил ШИМ. Но у меня задача стоит научиться считать эти импульсы, в тот момент когда он начался, и понимать тот момент когда он закончился, т.е. как вы говорите жесткая привязка по времени... по переполнению я так понимаю на метод не дает такой полноты понимания?
Как понять что у нас сейчас в периоде ШИМ сигнала стоит высокий уровень, и сказать об этом флагом?
Это не удобно, при высокой частоте ШИМ вы не успеете этот флаг в главном цикле отследить.
т.е. если нужно пульнуть 200 импульсов частотой 1кГц, с заполнение 50% - проще это сделать в цикле for, или программный шим - "ногодрыг", и посчитать успеем заодно. Ну 1кГц частота не большая... мне интересно было сделать это, как то более правильно, рассуждая с точки зрения программирования под AVR, и получить от вас форумчане красивый пример для своей копилки. Вот например соседней теме "ATmega + 12bit ADC очень красивая дискуссия, и самое главное примеры. Особо других мест нет, где учиться))
kote52, если тебе нужно насчитать определенное число импульсов ШИМ, то можно применить прерывание по переполнению таймера, который вырабатывает эту ШИМ. считай в прерывании количество переполнений. насчитаешь нужное число, отключишь ШИМ.
Добавлено after 1 minute 33 seconds: да, и посмотри почту, я там тебе отправил предупреждение о нарушении правил форума. будешь продолжать нарушать- дам бан.
_________________ Мудрость приходит вместе с импотенцией... Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
kote52, считай в прерывании количество переполнений. насчитаешь нужное число, отключишь ШИМ.
Хорошо, я прислушаюсь к вашим словам! А если мне нужно сделать какое либо действие когда высокий уровень, по длительности - это 500us, а не просто считать период равный 1ms, т.е. = 1 переполнению.
если ШИМ выведена в порт, то проверяешь пин этого порта на высокий уровень. или на низкий уровень. только проверять нужно достаточно часто, чтобы попадать несколько раз за один период ШИМ.
_________________ Мудрость приходит вместе с импотенцией... Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Ух, ничего себе тема моя ожила! А меня чуть ли гнобили(( но Dimon456, хочу сказать тогда его метод сработал, так и оставил, доделал ЗУ, уже трудится в сервисе у друга. И kote52, прав, это работает когда в периоде идет Toff(картинку приводил). А вот когда в периоде Ton, так и не добился замера. Поэтому выбирал из замеров, самое минимальное значение и относил его Toff, а что самое мальсимальное из замеров относил Ton.
Я бы для себя хотел прояснить как возможно сделать!
Я, наверное, чего-то пропустил. Но что вызывает вопросы? По прерыванию TIMERx_COMPY для прямого ШИМ попадаете на низкий уровень на выходе, по TIMERx_OVF - на высокий. Для инверсного ШИМ соответственно наоборот. АЦП можно запустить сразу в прерывании таймера, но есть опасность что переходные процессы еще не закончатся - тогда можно запускать по прерыванию второго канала, который настроить со смещением от первого. А можно просто провести серию замеров, первый проигнорировать а остальные усреднить. Но тут надо посчитать сколько замеров АЦП успеет сделать гарантировано, не попав на высокий выходной уровень и сколько ждать от спада ШИМ до начала замера.
По прерыванию TIMERx_COMPY для прямого ШИМ попадаете на низкий уровень на выходе, по TIMERx_OVF - на высокий. Для инверсного ШИМ соответственно наоборот.
Можно хотя бы условно примитивный код, у меня сейчас еще больше вопрос возникло, чем ответов)) то что мы попали, на высокий или низкий уровень - и что? нам надо понимать - что начался высокий уровень и сделать замер к примеру если про ацп речь уж. Это возможно?
А можно просто провести серию замеров, первый проигнорировать а остальные усреднить. Но тут надо посчитать сколько замеров АЦП успеет сделать гарантировано, не попав на высокий выходной уровень и сколько ждать от спада ШИМ до начала замера.
Можно хотя бы условно примитивный код, у меня сейчас еще больше вопрос возникло, чем ответов)) то что мы попали, на высокий или низкий уровень - и что?
А чего вы хотите добиться? Если синхронизироваться с ШИМом - пожалуйста, вот вам два прерывания на начало и конец импульса.
Цитата:
Примерно тож самое написал авто темы neid.
Могу только повторить: скорее всего, я с какого-то момента потерял нить рассуждения. ТС вроде бы хотел измерять по нижнему уровню ШИМа. Значит по TIMERx_COMPy можно запускать преобразование. Ну а там по алгоритму: можно просто выкинуть первое и ограничиться вторым. А можно складывать пока не наступит TIMERx_OVF - тогда посчитать среднее арифметическое из того что успело намериться.
Заголовок сообщения: Re: Фильтр АЦП atmega 8 по нижней границе
Добавлено: Вт авг 24, 2021 11:08:19
Встал на лапы
Зарегистрирован: Пт мар 19, 2021 08:58:45 Сообщений: 120
Рейтинг сообщения:0
Dimon456, Давай те код, буду вникать так! Вообще есть мысли смотреть регистр TIFR1 помойму OCF1A - Флаг прерывания по событию "совпадение А" таймера/счетчика Т
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 25
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения