реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Измерение напряжения с помощью АЦП, 16 битное SD16_A
chainikru
сообщение Apr 9 2012, 10:58
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 24
Регистрация: 5-12-11
Пользователь №: 68 682



Добрый день. Хочу поставить индикатор на регулятор мощности, для этого я хочу дополнить регулятор MSP430F2013 на аналоговые входы которого я буду подавать уменьшенный сигнал и измеряя напряжение с помощью АЦП выводить его значение в процентах. Для этого сделал для отлатки устройство с регулируемым напряжением до 0.59 вольт . Как я понял для написания пограммы надо сделать таблицу соответствия напряжения его цифрвому коду в АЦП .
Вот моя программа для этой цели где результат преобразования напряжения хранится в ChA0results:
#include <msp430x20x3.h>

/* Arrays to store SD16 conversion results */
/* NOTE: arrays need to be global to */
/* prevent removal by compiler */
static unsigned int ChA0results = 0x00;

static unsigned int ch_counter=0;

void main(void)
{

volatile unsigned int i; // Use volatile to prevent removal
// by compiler optimization

WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
BCSCTL2 |= DIVS_3; // SMCLK/8

SD16CTL = SD16REFON + SD16SSEL_1; // 1.2V ref, SMCLK
SD16INCTL0 = SD16INCH0; // Set channel A0+/-
SD16CCTL0 |= SD16SNGL + SD16UNI + SD16IE;
// Single conv, 256OSR, unipolar,
// enable interrupt
SD16INCTL0 |= SD16INTDLY_0; // Interrupt on 4th sample
SD16AE = SD16AE0; // P1.0 A0+, A0- = VSS

for (i = 0; i < 0x3600; i++); // Delay for 1.2V ref startup

while(1)
{
SD16CCTL0 |= SD16SC; // Set bit to start conversion
_BIS_SR(LPM0_bits + GIE); // Enter LPM0
}
}

#pragma vector = SD16_VECTOR
__interrupt void SD16ISR(void)
{
switch (SD16IV)
{ case 2: // SD16MEM Overflow
break;

case 4: // SD16MEM0 IFG

switch(ch_counter)
{
case 0:
ChA0results = SD16MEM0; // Save CH0 results (clears IFG)
SD16AE &= ~SD16AE0; // Disable external input A0+, A0
SD16INCTL0 &= ~SD16INCH_0; // Disable channel A0+/-
ch_counter++;

SD16AE = SD16AE0; // Reset external input to A0+/-
SD16INCTL0 = SD16INCH_0; // Reset channel observed
break;
}

_BIC_SR_IRQ(LPM0_bits); // Exit LPM0

}
}
Но у меня проблема с недопонимание работы этого АЦП. Я подаю напряжение на канал A0 и вижу результат на SD16MEM0 он его благополучно заносит в ChA0results. Но эти значени при каждом перезапуске программы разные. Подскажите пожалуйста как решить эту проблему и составить таблицу:для
0.59В-"результат преобразования" , 0.531В- , 0.472В- , 0.413В- , 0.354В- , 0.295В- , 0.236В- , 0.177В- , 0.118В- , 0.059В.
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Apr 9 2012, 11:56
Сообщение #2


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



А зачем таблицу?
Намного проще тупо пересчитывать.
Одно действие - умножение кода на коэффициент пересчета


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
chainikru
сообщение Apr 9 2012, 13:38
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 24
Регистрация: 5-12-11
Пользователь №: 68 682



Цитата(MrYuran @ Apr 9 2012, 15:56) *
А зачем таблицу?
Намного проще тупо пересчитывать.
Одно действие - умножение кода на коэффициент пересчета

А как или что вы имеете в виду под словом пересчитать? я ведь не знаю какой код будет на выходе АЦП при подаче того или иного значения напряжения. Ну а таблицу я не имею ввиду как таковую, я просто хочу знать какой код будет соответствовать тому или иному напряжению.
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Apr 9 2012, 14:07
Сообщение #4


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(chainikru @ Apr 9 2012, 17:38) *
А как или что вы имеете в виду под словом пересчитать? я ведь не знаю какой код будет на выходе АЦП при подаче того или иного значения напряжения.

А зачем его знать - пусть машина думает.
Полная шкала АЦП соответствует напряжению опоры.
То есть, если опора, скажем, Vref=1.5В, то Vin = Vref * (Code/0xFFFF)
Ну, ещё могут быть нюанс в зависимости от режима АЦП (дополнительные коэффициенты, смещение шкалы, изменение разрядности итд.)


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
chainikru
сообщение Apr 9 2012, 14:38
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 24
Регистрация: 5-12-11
Пользователь №: 68 682



Цитата(MrYuran @ Apr 9 2012, 18:07) *
А зачем его знать - пусть машина думает.
Полная шкала АЦП соответствует напряжению опоры.
То есть, если опора, скажем, Vref=1.5В, то Vin = Vref * (Code/0xFFFF)
Ну, ещё могут быть нюанс в зависимости от режима АЦП (дополнительные коэффициенты, смещение шкалы, изменение разрядности итд.)

А под значение Code что взять? Ну а хочу я это использовать примерно так:
#pragma vector = SD16_VECTOR
__interrupt void SD16ISR(void)
{
if (SD16MEM0 < 0x3FFF) // SD16MEM0 > 0.3V?, clears IFG
P1OUT &= ~0x01;
else
P1OUT |= 0x01;
}
но при нужных значениях будет гореть не 1 светодиод, а соответствующее значение на индикаторе

Сообщение отредактировал chainikru - Apr 9 2012, 14:41
Go to the top of the page
 
+Quote Post
hash20
сообщение Apr 9 2012, 20:45
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 24
Регистрация: 24-01-12
Пользователь №: 69 858



Mr.Yuran верно сказал !!! Vin = Vref * (Code/0xFFFF) добавлю! Vin = Vref * (Code/0xFFFF)*k (k - коэфициент деления вашего делителя)

Тоесть напряжение необходимо подвать через делитель напряжения (на двух резисторах) коэфициент выбираеться так, что-бы при макисмальном измеряемом напряжении напряжение на соответств входе АЦП не превышал опорное напряжение (и категорически не более напряжения питания контроллера). Рекомендую поставить стабилитрон между 0V и входом АЦП (внимание на токи низковольтных стабилитронов), есть так-же вриант с защитными диодами...

Дальше... какая точность измерения нужна??? Встроенные АЦП чесно говоря какашечные(не у всех моделей MSP... ставьте акцент на сигма-дельта АЦП)... долбит как минимум 2-3 младших разряда (зависит от схемотехники)

Варианты решения:
1: Использование фильтра ( в большинстве случаев достаточно среднего значения 10-15 замеров или классическая RC цепочка).
2: Использование таблицы (массива значений) соответствующей требуемой точности измерения (пример: значения от 0x00 до 0x05 соответствуют 0.1В, от 0x06 до 0x0B соответств 0,2В и.т.д.)
3: Использование внешних прецезионных АЦП (фильтр всё равно нужен).

Советы:
1. Если производите измерение на индуктивной нагрузке уделите этому соответствующие меры защиты !!!!! (сапрессоры или пассивный/активный баласт... всё зависит от мощности нагрузки).
2. АЦП заводите в режим n-канального циклического измерения (замер получаем по прерыванию, вычисление фильтра и индикацию в теле main{}).
3. Не забываем о конденсаторах в непосредственной близости к контроллеру (цепи АVcc, Ref+,Ref-)
4. Вместо фильтра иногда! можно применить сдвиг (>>x) вправо. Каждый сдвиг уменьшает разрядность АЦП на x. (для уменьшения колбасни младших разрядов)
5. Для измерения слабых сигналов используем инструментальный операционный усилитель.... (кстати ОУ в любом случае лучше использовать пусть накрайняк ОУ сгорит, аля контроллер дороже.... хотя ОУ и контроллеры бывают разные sm.gif )

Всё пифо кончилось..... ушел спать....


Go to the top of the page
 
+Quote Post
chainikru
сообщение Apr 9 2012, 21:28
Сообщение #7


Участник
*

Группа: Участник
Сообщений: 24
Регистрация: 5-12-11
Пользователь №: 68 682



Цитата(hash20 @ Apr 10 2012, 00:45) *
Mr.Yuran верно сказал !!! Vin = Vref * (Code/0xFFFF) добавлю! Vin = Vref * (Code/0xFFFF)*k (k - коэфициент деления вашего делителя)
2: Использование таблицы (массива значений) соответствующей требуемой точности измерения (пример: значения от 0x00 до 0x05 соответствуют 0.1В, от 0x06 до 0x0B соответств 0,2В и.т.д.)

Вот я и хочу использовать массив значений, но я думал что для каждого напряжения есть только одно значение. Для начала хочу написать программу для измерения постоянного напряжения (питание подаю с обычной батареи через резистры и меняю его значение переменным резистром) чтобы потм переделать под переменное.
И вот для этого мне надо знать значения соответствующие 0.59В- , 0.531В- , 0.472В- , 0.413В- , 0.354В- , 0.295В- , 0.236В- , 0.177В- , 0.118В- , 0.059В на SD16MEM0, чтоб выводить на сколько процентов работает прибор. Но когда я начинаю измерять у меня значения на SD16MEM0 всегда получаются разные это нормально?
А по формуле я не уверен что все понял. Что вы имеете ввиду под словом Code хотя я предполагаю что Code это код получаемый на SD16MEM0 Vref- опорное напряжение Vin-напряжение код которого я хочу получть. Правильно ли я вас понял? И может ли к примеру 0.413В соответствовать несколько значений на SD16MEM0, если да сколько измерений посоветуете, и в программе для одного напряжения задавать среднее значение или сразу группу значений?

Сообщение отредактировал chainikru - Apr 9 2012, 21:29
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Apr 10 2012, 04:53
Сообщение #8


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(chainikru @ Apr 10 2012, 01:28) *
Но когда я начинаю измерять у меня значения на SD16MEM0 всегда получаются разные это нормально?

Нормально.
Я, кажется, понял.
Вам надо просто несколько фиксированных уровней?
Так это ещё проще.
Забиваете формулу в макрос, и даже считать ничего не придется в рантайме. Константы сосчитаются на этапе компиляции.

Что-то типа:
Код
#define V_REF    1500ul // опора в мВ
#define MAX_SCALE    0xffff // вся шкала АЦП
#define V_1    590 // V1 в мВ
#define V_2    531 // V2 в мВ
#define V_3    472 // V3 в мВ
...
#define CODE(v)    (V_REF * v / MAX_SCALE)      // макрос пересчета мВ в код АЦП

...

if (SD16MEM0 < CODE(V_1))
{  }


Чтобы меньше дрожало, можно усреднять по нескольким отсчетам, тем более что АЦП в МСП-шках поддерживает множественный запуск. То есть, за один запуск можно получить подряд несколько отсчетов, а потом их усреднить.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
chainikru
сообщение Apr 10 2012, 09:33
Сообщение #9


Участник
*

Группа: Участник
Сообщений: 24
Регистрация: 5-12-11
Пользователь №: 68 682



Цитата(MrYuran @ Apr 10 2012, 08:53) *
Нормально.
Я, кажется, понял.
Вам надо просто несколько фиксированных уровней?
Так это ещё проще.
Забиваете формулу в макрос, и даже считать ничего не придется в рантайме. Константы сосчитаются на этапе компиляции.


Вы имеете ввиду написать чтото наподобие этого (но так что то не хочет работать) ?

Код
#include  <msp430x20x3.h>

#define V_REF    1200ul     // опора в мВ
#define MAX_SCALE    0xffff // вся шкала АЦП
#define V_10   590          // V10 в  мВ
#define V_9    531          // V9 в мВ
#define V_8    472          // V8 в мВ
#define V_7    413          // V7 в мВ
#define V_6    354          // V6 в мВ
#define V_5    295          // V5 в мВ
#define V_4    236          // V4 в мВ
#define V_3    177          // V3 в мВ
#define V_2    118          // V2 в мВ
#define V_1    59           // V1 в мВ
#define V_0    0            // V0 в мВ
#define CODE(v)   (V_REF * v / MAX_SCALE)// макросы пересчета мВ в код АЦП

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
  P1DIR |= 0x01;                            // Set P1.0 to output direction
  SD16CTL = SD16REFON + SD16SSEL_1;         // 1.2V ref, SMCLK
  SD16INCTL0 = SD16INCH_1;                  // A1+/-
  SD16CCTL0 =  SD16UNI + SD16IE;            // 256OSR, unipolar, interrupt enable
  SD16AE = SD16AE2;                         // P1.1 A1+, A1- = VSS
  SD16CCTL0 |= SD16SC;                      // Set bit to start conversion

  _BIS_SR(LPM0_bits + GIE);
}


#pragma vector = SD16_VECTOR
__interrupt void SD16ISR(void)
{
if (SD16MEM0 < CODE(V_6))  P1OUT &= ~0x01;
  else
    P1OUT |= 0x01;
  
/*   P1OUT|= 0x08 + 0x10+0x40 + 0x80;
   P2OUT|= 0x80;
   if (CODE(V_8)< SD16MEM0 < CODE(V_9))
   P1OUT|= 0x04 + 0x08 + 0x10 + 0x20 + 0x80;
   P2OUT|= 0x80;
if (CODE(V_7)< SD16MEM0 < CODE(V_8))
   P1OUT|= 0x04 + 0x08 + 0x10 + 0x20 + 0x40 + 0x80;;
   P2OUT|= 0x80;  
if (CODE(V_6)< SD16MEM0 < CODE(V_7))
   P1OUT|= 0x04 + 0x08 + 0x10 + 0x80;  
if (CODE(V_5)< SD16MEM0 < CODE(V_6))
   P1OUT|= 0x04 + 0x10 + 0x20 + 0x40 + 0x80;
   P2OUT|= 0x80;  
if (CODE(V_4)< SD16MEM0 < CODE(V_5))
   P1OUT|= 0x04 + 0x10 + 0x20 + 0x80;
   P2OUT|= 0x80;
if (CODE(V_3)< SD16MEM0 < CODE(V_4))
   P1OUT|= 0x08 + 0x10+0x80;
   P2OUT|= 0x80;  
if (CODE(V_2)< SD16MEM0 < CODE(V_3))
   P1OUT|= 0x04 + 0x08 + 0x10 + 0x20;
   P2OUT|= 0x80;  
if (CODE(V_1)< SD16MEM0 < CODE(V_2))
   P1OUT|= 0x04 + 0x08 + 0x20 + 0x40;
   P2OUT|= 0x80;    
if (CODE(V_0)< SD16MEM0 < CODE(V_1))
   P1OUT|= 0x08 + 0x10;
if (SD16MEM0 < CODE(V_0))
   P1OUT|= 0x04 + 0x08 + 0x10 + 0x20 + 0x40 + 0x80;
   P2OUT|= 0x80;  */  
  
     _BIC_SR_IRQ(LPM0_bits);                // Exit LPM0    
}
    
}


в if (SD16MEM0 < CODE(V_6)) P1OUT &= ~0x01;
else
P1OUT |= 0x01; светодиод горит даже при отсутствии напряжения хотя елси вместо CODE(V_6) написать 0x7FFF //SD16MEM0 > 0.3V?, clears IFG то покра немерее яркость светодида меняется при изменении напряжения (почти выключается)

Сообщение отредактировал chainikru - Apr 10 2012, 10:07
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 27th July 2025 - 23:52
Рейтинг@Mail.ru


Страница сгенерированна за 0.01433 секунд с 7
ELECTRONIX ©2004-2016