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

 
 
> Проблема с АЦП STM32F100, Проблема при измерении инжектированного и регулярного канала
drum1987
сообщение Feb 27 2013, 18:36
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 255
Регистрация: 3-02-09
Из: Омск
Пользователь №: 44 323



Задача мониторить ток и напряжения.
Камень самый простой f100c4. Соответственно АЦП только 1. Использую 2 канала (0 и 8). 0 канал мерит напряжения (их 8 подаются с мультиплексора). Сигнал на вход АЦП подается с ОУ, поэтому сопротивление источника мало + RC фильтр 100 Ом + 10нФ.

Схема измерения напряжения такая: Дергаю ножкой(подключая этим источник ко входу ОУ), запускаю 2(4, 8, 16) раза регулярное преобразование в прерывании по окончанию (флаг EOC) считываю результат преобразования, вычисляю среднее и ногу опускаю назад. Повторяю для всех ног. Пачка измерений раз в секунду.
Схема измерения тока: Источник подключен всегда, инжектированный канал связан с таймером необходимо 100 измерений в секунду (хочу считать А*ч).

Вроде все ясно и понятно, но есть проблема: когда инжектированный канал прерывается инжектированным, то преобразование регулярного канала не возобновляется при завершении преобразования в инжектированном канале. Изза этого образубтся "провалы" при измерениях.



Как видно из рисунка, значение измеренное при вытеснении инжектированным каналом близко к 0,4 В. (4+0,4)/2=2,2 В. То, что с напряжением на ноге все в порядке говорит осциллограмма:



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

Прилагаю код:
Настройка АЦП:
CODE
/* Enable ADC1 and RCC clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div2);

/* ADC1 configuration ------------------------------------------------------*/
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);


/* ADC1 regular channel0 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);

/* Set injected sequencer length */
ADC_InjectedSequencerLengthConfig(ADC1, 1);

/* ADC1 injected channel Configuration */
ADC_InjectedChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_239Cycles5);

/* ADC1 injected external trigger configuration */
ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_T2_TRGO);

/* Enable JEOC interrupt on ADC1 */
ADC_ITConfig(ADC1, ADC_IT_JEOC, ENABLE);

/* Enable ADC1 EOC interupt */
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);

NVIC_SetPriority (ADC1_IRQn, 1);

/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);

/* Enable ADC1 reset calibaration register */
ADC_ResetCalibration(ADC1);

/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));

/* Start ADC1 calibaration */
ADC_StartCalibration(ADC1);

/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));


/* Start ADC1 Software Conversion */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
ADC_ExternalTrigInjectedConvCmd(ADC1, ENABLE);



Прерывания по АЦП:
Код
void ADC1_IRQHandler(void)
{
  if (ADC_GetFlagStatus(ADC1, ADC_FLAG_JEOC))
  {
        // Get injected channel8 converted value
        int curr = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_2);
        curr = curr * VCC/0xfff;
    
ADC_ClearITPendingBit(ADC1, ADC_IT_JEOC);
  }

  else if (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
  {
ADC1ConvertedValue = ADC_GetConversionValue(ADC1);
/* Clear ADC1 EOC pending interrupt bit */
ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
converted = 1;
  LED_OFF;
    }
}


Вызов преобразования:
Код
long cell_mesure(unsigned int cell_num)
{

    GPIO_HIGH(Mes[cell_num - 1]->port, Mes[cell_num - 1]->pin); // включение измерителя
    converted = 0;    
    LED_ON;
    ADC1->SQR3 = 0;                //загрузить номер канала
              ADC1->CR2 |= ADC_CR2_SWSTART;     //запустить преобразование в регулярном канале  
    while(!converted);
    long voltage = ADC1ConvertedValue;  // измерение №1

    return (voltage);
}


Куда копать?

Сообщение отредактировал IgorKossak - Mar 1 2013, 08:31
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
koyodza
сообщение Feb 27 2013, 20:27
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 213
Регистрация: 28-02-07
Из: Киев
Пользователь №: 25 744



Ранее Вы, видимо, работали с AVR sm.gif
Попробуйте сделать не так, а как более удобно делать на таких МК
То, что Вы делаете сейчас - это чесание пяткой за ухом.
Раз хотите измерять 100 раз в секунду ток, то настройте regular channel на преобразование по таймеру 100 раз в секунду, и пусть по DMA данные складываются в буфер, прерывания от АЦП не нужны, нужны прерывания по половине буфера и по полному буферу.
А когда хотите измерить напряжение, дёргайте ножкой и запускайте программно преобразование для injected channel, полученные данные после преобразования можете обрабатывать по поллингу готовности или по прерыванию от АЦП
Кстати, если измерение напряжения хотите повторять несколько раз, можно настроить цепочку injected каналов (до 4), при этом канал на самом деле может опрашиваться один, но в JDR1..JDR4 будут результаты отдельных преобразований, и готовность АЦП и прерывание получите в конце
Go to the top of the page
 
+Quote Post



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

 


RSS Текстовая версия Сейчас: 25th August 2025 - 20:54
Рейтинг@Mail.ru


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