|
|
|
|
Добрый день Вот решил сделать блок питания с управлением на МК Возникли проблемы с АЦП, а именно: Не могу настроить его так чтобы он мерил многократно, а не 1 раз Работаю в CVAVR, симулирую в ПРОТЕУСЕ Делаю так: interrupt [ADC_INT] void adc_isr(void){ Vizm=ADCW; Vpr = (float) Vizm; //переводим формат данных из целочисленно в фиксированную арифметику Vpr = Vpr * 0.03128; //умножаем на множитель масштаба(измерение до 32В) Vdec = (int) Vpr; //выделяем целую часть; Vpr = Vpr - (float) Vdec;//выделяем милливольты Vpr = Vpr * 1000; //избавляемся от целой части Vmili = (int) Vpr; //переводим милливольты в вольты } Дальше преобразовываю в BCD и вывожу на LED.(ADCSRA=0b11011111; ADMUX=0b11000000 Но он делает преобразование 1 раз и останавливается. Если установить ADFR=1, то в протеусе на индикаторе кракозябры (может на железе будет нормально?) Как заставить делать преобразование многократно?
|
|
|
Я бы не делал все эти вычисления в прерывании. При FR=1 прерывание будет вызываться постоянно. Либо выносить вычисления из прерывания, либо вручную запускать преобразование по окончании вычислений (хуже).
|
|
|
Не только лучше вынести вычисления из прерывания, но и не полениться усреднить показания - АЦП практически никогда два одинаковых показания Вам не даст. Обычно 16..32 выборок достаточно, чтобы цифры не скакали. |
|
|
Да но если я выношу измерение за прерывание то начинает показывать крякозябрики: interrupt [ADC_INT] void adc_isr(void){ adc_data=ADCW; } ..... void main(void) { ADMUX=0b11000000; ADCSRA=0b11011111; #asm("sei") while(1) { Vizm=adc_data ; Vpr = (float) Vizm; Vpr = Vpr * 0.03128; Vdec = (int) Vpr; Vpr = Vpr - (float) Vdec; Vpr = Vpr * 1000; Vmili = (int) Vpr; Помогите пожалуйста разобраться |
|
|
Сдаётся мне, что дело не в АЦП. Если даже АЦП работает неверно, то отображались бы просто не те цифры, а никак не "кракозябрики" Давайте кусок кода где вывод. |
|
|
Вывод на LED: ADMUX=0b11000000; ADCSRA=0b11011111; // Global enable interrupts #asm("sei") while(1){ if (Vdec>=10) { Vdec=(Vdec-10); tis++; } else { sot=Vdec;} ; //Преобразование BCD if (Vmili>=100) { Vmili=(Vmili-100); des++; } if (Vmili>=10) { Vmili=(Vmili-10); ed++; } if (r==2) { PORTD.7=0;}; switch (razrad[r]) { case 1 : PORTD=digits[ed]; break; case 2: PORTD=digits[des]; break; case 4: PORTD=digits[sot]; break; case 8: PORTD=digits[tis]; break; }; Вроде потому-что АЦП мереет намного больше раз в секунду чем выводится на индикатор? Как по грамотному организовать вывод? |
|
|
А где переключение разряда? Ну и желательно делать это не постоянно, а с заданной частотой. Поместите вывод в таймерное прерывание например. Что касается кода... shemmer: if (Vdec>=10) { Vdec=(Vdec-10); tis++; } else { sot=Vdec;} ; //Преобразование BCD , то это некорректный код. Если Vdec больше 10, то переменной sot не присваивается никакого значения. Если Vdec больше 20, то тоже неверный результат... Надо примерно так:
sot = Vdec;
while (sot >= 10)
{
tis++;
sot -= 10;
}
Аналогично с Vmili. ЗЫ. И форматируйте текст получше, сложно читать. |
|
|
1. razrad[r] - это бегущая единица? 2. if (r==2) {PORTD.7=0;}; нужно перенести за switch. 2. Не совсем понятно - кусок расчета Vizm, Vpr и прочее - он в этом же цикле while? Если он - в прерывании, на дисплее действительно будет полный бред. |
|
|
Да razrad[r] это бегущая еденица Вольтмер у меня на 32 вольта Поясняю: int Vizm; float Vpr; int Vdec, Vmilli; Vizm = ADCW; Vpr = (float) Vizm; //переводим формат данных из целочисленно в фиксированную арифметику Vpr = Vpr * 0.03128; //умножаем на множитель масштаба: Vdec = (int) Vpr; //выделяем целую часть; Vpr = Vpr - (float) Vdec; //выделяем милливольты Vpr = Vpr * 1000; //избавляемся от целой части Vmilli = (int) Vpr; //переводим милливольты в вольты Теперь в Vdec число в вольтах, а в Vmili миливольты Теперь если этот расчет поместить в прерывание АЦП то все правильно работает но 1 раз и останавоивается Если выношу из прерывания показывает не весть что. Как заставить мерить всегда и правильно? |
|
|
Вычисления нужно в любом случае выносить из обработчика, потому что Вы потом все эти данные начинаете преобразовывать. Простейший пример: 1. Во время выполнения оператора if (Vdec>=10) {Vdec=(Vdec-10); tis++; }, например, между Vdec=(Vdec-10) и tis++; возникает прерывание от АЦП - почему бы и нет 2. В обработчике прерываний выполняется, в том числе, Vdec = (int) Vpr; 3. Теперь мы возвращаемся в основную программу, и теперь наш Vdec содержит уже совсем не то значение, которое было до момента возникновения прерывания. Запросто можно и 20 сотен в числе насчитать С разделяемыми ресурсами работать нужно очень аккуратно. Вариантов решения здесь два - либо выносить вычисления из обработчика, либо внутри цикла в основной программе запрещать прерывания, на время, пока не сформируете правильно все свои ed, des, sot и т.д. Насчет "останавливается" - попробуйте в обработчике руками сбросить флаг прерывания от АЦП. Он, по идее, должен сбрасываться сам, но кашу маслом не испортишь. Частенько помогает. Можете также перед выходом из обработчика перепрограммировать регистр управления АЦП.
|
|
|
|
|