Я то же не программист, у меня образование 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%, в противном случае ШИМ перекроет измерение АЦП, и оно будет не корректным.[/uquote]
Привет! Изучаю таймеры. вот тут нарыл эту тему, мне в отличии от автора нужно не измерять напряжение когда ШИМ периода 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, но задача остается для меня не решенной как это реализовать?



