|
AVR и дифф сигналы, как правильно измерить? |
|
|
|
Oct 25 2007, 10:41
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(ivainc1789 @ Oct 24 2007, 12:50)  Собрал простую схемку и измерил мультиметром VC9808+ разность ADC4-ADC3=-7mV. Далее попробовал измерить разность напряжений делителей двумя способами: измерить сигналы как single ended и differential с внутренним усилителем с Ку=1. Первый способ стабильно дает правильный результат в 7 милливольт (по модулю). А со вторым проблемы, АЦП возвращает чаще всего 0x3FF, что "в переводе с биполярного режима" равно -1. Получить -7 никак не удается даже произведя 10 измерений и взяв среднее. Где может быть ошибка? Разрешение в Bipolar Differential Conversion уменьшается в два раза, так что вы должны получить -3, а не -7. Ошибка у вас в том, что тип AdcSumma беззнаковая переменная, а результат из регистра ADC вы читаете, как знаковый. Сделайте AdcSumma знаковой и будет вам щастье.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Oct 25 2007, 16:17
|

Профессионал
    
Группа: Свой
Сообщений: 1 175
Регистрация: 5-01-05
Пользователь №: 1 807

|
Цитата(=GM= @ Oct 25 2007, 14:41)  Разрешение в Bipolar Differential Conversion уменьшается в два раза, так что вы должны получить -3, а не -7. Затупил  ... А я все думаю, почему в макете все дифф измерения ровно в два раза меньше чем ожидается. Большое спасибо, что нашли время ответить. Вот только с ошибкой усилителя есть вопрос (ADC возвращает ADCe == +3 для (ADC3-ADC3)*20). Правильно ли будет ее вычесть из результата так: Result = 2*((ADC4-ADC3)*20 - ADCe)? Да, в коде ошибка, спасибо... Осознал!
|
|
|
|
|
Oct 25 2007, 22:46
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(ivainc1789 @ Oct 25 2007, 16:17)  Затупил  ... А я все думаю, почему в макете все дифф измерения ровно в два раза меньше чем ожидается. Большое спасибо, что нашли время ответить. Вот только с ошибкой усилителя есть вопрос (ADC возвращает ADCe == +3 для (ADC3-ADC3)*20). Правильно ли будет ее вычесть из результата так: Result = 2*((ADC4-ADC3)*20 - ADCe)? Да, в коде ошибка, спасибо... Осознал! Ну, если считать, что смещение линейно, то Result = 2*(ADC4-ADC3) - ADCe/10.0
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Oct 26 2007, 09:29
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(ivainc1789 @ Oct 26 2007, 04:57)  Разве не так: 2*((ADC4-ADC3) - ADCe)/10.0 Ну вы ж вроде меряли ADC4-ADC3 при Ку=1, а ADCe с Ку=20. (Замечу в скобках, если вы подставите ваши данные в вашу формулу, 2*((ADC4-ADC3) - ADCe)/10.0, то получите (2*(-3)-3)/10=-0.9, что явно неверно, должно быть в районе 6..7)
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Oct 26 2007, 21:25
|

Профессионал
    
Группа: Свой
Сообщений: 1 175
Регистрация: 5-01-05
Пользователь №: 1 807

|
Код модифицировал так: Код signed int AdcResult; __C_task void main (void) { unsigned char i; signed long AdcSumma=0; signed int tmp1; ADCSRA = BIN(10010110); // 125kHz,Fosc=8MHz ADCSRB = BIN(10000000); // bipolar mode DIDR0 = BIN(11111111); // digital inputs disable DIDR1 = BIN(11110000); ADMUX = BIN(10010011); // (ADC4-ADC3)*1 Delay(500*ms);// wait for ADC stable for(i=0;i<10;i++){// get 10 conversions SETBIT(ADCSRA,ADSC);while(CHKBIT(ADCSRA,ADSC)); tmp1 = ADC; if (CHKBIT(tmp1,9))tmp1|= 0xFC00; AdcSumma += tmp1; } AdcResult = AdcSumma/10; while(1); } Результаты измерений в целом: (ADC3-ADC3)*20=ADCe=+3; (ADC4-ADC3)*1=-1; Смотрел через EEPROM все 10 значений как unsigned int - там большинство результатов 0x3FF, реже 0x000. Округление конечного результата при делении на 10 дает существенную ошибку. Если смотреть на формулу Result = 2*(ADC4-ADC3) - ADCe/10.0 то искомого результата (-3) чуть-чуть не получается... Если следовать общей формуле биполярного режима ADC = (ADC4-ADC3)*512*GAIN/Vref, то уверенно должно возвращаться (-3.2). Вижу необходимость переходить к float. Верно ли?
|
|
|
|
|
Oct 27 2007, 08:03
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(ivainc1789 @ Oct 26 2007, 23:25)  AdcResult = AdcSumma/10; ... Округление конечного результата при делении на 10 дает существенную ошибку. Вижу необходимость переходить к float. Верно ли? Смотря какая ошибка устроит. "простое" деление в С происходит с отбрасыванием остатка, а не с округлением к ближайшему. Надо так (тут предполагаем, что N положительно, что справедливо при усреднении) Код averaged_A = (A < 0 ? A - N/2 : A + N/2 ) / N; // или более по-паскальному if( A < 0 ) averaged_A = (A - N/2) / N; else averaged_A = (A + N/2) / N; Это уменьшает ошибку и может оказаться достаточно. Можно также воспользоваться числами с фиксированной точкой, например, 13.3 (13 бит до точки, три после, дискретность представления числа 1/8). Тогда при простом суммировании восьми отсчётов с АЦП в 16-битной целочисленной переменной мы получаем их среднее значение в формате 13.3 без никаких делений  , и ещё остаётся запас разрядности "сверху", от переполнения, так как отсчёты АЦП 10-битные. Далее взяв очередной отсчёт и умножив его на 8 (сдвинув влево на 3) мы отнимаем от него то "среднее" и получаем отклонение от среднего в том же формате 13.3 Суммировение чисел с фиксированной точкой между собой производится так же, как и целых (толи 13.3, толи 16.0 - какая разница, главное помнить положение точки). Множатся и делятся на целые тоже "обычно", просто запас точности есть. Вопросы возникают при умножении и делении чисел с фиксированной точкой между собой, так как при умножении (13.3) * (13.3) выходит (25.6) и нужно сдвинуть на 3 бита вправо, чтобы опять вышло .3 Но можно и к плавающей перейти, особенно если в 16 бит точно не лезет и в алгоритме много умножений или делений не на константу - эти операции у AVR что с long, что с float работает с приблизительно одинаковой скоростью (точнее, медленностью), так как 32-битной целочисленной арифметики у него всё равно нет, работа с отличается отсутствием необходимости в выравниваниях/нормировках для long и меньшей длиной мантиссы для float.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Oct 27 2007, 14:04
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(ivainc1789 @ Oct 26 2007, 21:25)  Код signed int AdcResult; . . . . . for(i=0;i<10;i++) { SETBIT(ADCSRA,ADSC);while(CHKBIT(ADCSRA,ADSC)); tmp1 = ADC; if (CHKBIT(tmp1,9)) tmp1|=0xFC00; AdcSumma += tmp1; } AdcResult = AdcSumma/10; while(1); } Оператор if(CHKBIT(tmp1,9)) tmp1|=0xFC00; здесь использовать нельзя, уберите. Понятно и ёжику, что для усреднения надо сложить 10 результатов измерений, неважно положительные они или отрицательные, и поделить на 10, а вы вдруг хотите сделать все слагаемые положительными. С какого припрыгу? Цитата(ivainc1789 @ Oct 26 2007, 21:25)  Смотрел через EEPROM все 10 значений как unsigned int - там большинство результатов 0x3FF, реже 0x000 Ничего не понимаю. Если у вас -7 мВ на входе, то код должен быть равен -3 или 0хFFFD. Цитата(ivainc1789 @ Oct 26 2007, 21:25)  Вижу необходимость переходить к float. Верно ли? А что это вам даст? Сначала получите reasonable значения в целых числах. Вообще, для получения хорошей точности надо бы слабые диффсигналы мерять с Ку=20 или даже Ку=32, потом поделить на 20 или 32, заодно учесть смещение. А смещение, кстати, лучше мерять непосредственно перед измерением диффсигнала.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Oct 27 2007, 17:16
|

Профессионал
    
Группа: Свой
Сообщений: 1 175
Регистрация: 5-01-05
Пользователь №: 1 807

|
Цитата(=GM= @ Oct 27 2007, 18:04)  Оператор if(CHKBIT(tmp1,9)) tmp1|=0xFC00; здесь использовать нельзя, уберите. а вы вдруг хотите сделать все слагаемые положительными. С какого припрыгу? Данная операция является попыткой перейти от знакового 10 р. значения ADC к обычному знаковому int путем размножения знака влево... Не ВСЕ слагаемые делаются положительными, как вы говорите, а только 10р. отрицательные становятся 16р. отрицательными... Цитата Ничего не понимаю. Если у вас -7 мВ на входе, то код должен быть равен -3 или 0хFFFD. В том то и дело, что результат получен (-1=0xFFFF) и то, если принять меры к обеспечению округления не отбрасыванием остатка а до ближайшего целого, т. к. в выборке из 10-ти значений ВСЕГДА присутствует один 0x0000, остальные 0xFFFF. Отчего такая ошибка сказать затруднительно, особенно на фоне вполне корректного измерения single ended. Цитата А что это вам даст? Сначала получите reasonable значения в целых числах. Согласен. Только вот вариантов источника ошибки больше не видится. АЦП работает на корректной частоте, настройки вроде все верные, меняем только значение ADMUX. Single ended результат подтверждает показания мультиметра, что доказывает исправность входных цепей.... Цитата А смещение, кстати, лучше мерять непосредственно перед измерением диффсигнала. Согласен, но помимо смещения есть еще погрешность резисторов в делителях. Например, у меня в зарядном устройстве измеряется сигнал на токоизмерительном резисторе, делители подключены к нему. Для учета этой ошибки нужно подать одинаковое напряжение на сами делители, и это требует "откл" тока токоизмерительного резистора, а это может быть недопустимо. Поэтому такая ошибка измеряется только на старте программы один раз...
|
|
|
|
|
Oct 27 2007, 18:46
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(ivainc1789 @ Oct 27 2007, 17:16)  Согласен, но помимо смещения есть еще погрешность резисторов в делителях. Например, у меня в зарядном устройстве измеряется сигнал на токоизмерительном резисторе, делители подключены к нему. Для учета этой ошибки нужно подать одинаковое напряжение на сами делители, и это требует "откл" тока токоизмерительного резистора, а это может быть недопустимо. Поэтому такая ошибка измеряется только на старте программы один раз... Погрешность резисторов это отдельная песня, не надо бежать впереди паровоза. Начинать надо с ошибки смещения. Для её учёта при измерении диффсигналов надо измерить смещение, выбрав один и тот же канал, и непосредственно после этого измерить диффсигнал, затем вычесть смещение из полученного значения. Вообще, снимите график зависимости кода АЦП от диффсигнала, и всё увидите.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|