Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F103C8T6, АЦП, DMA и таймер
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
hd44780
Привет всем.
Пытаюсь оцифровать этим процом переменку из розетки (т.е. просто сделать вольтметр).
Перед тем как попасть в проц, переменка проходит через обычный транс от БП (для развязки), потенциометр для подгонки по диапазон, поднимается на 1.5в вверх, чтобы измерять обе полуволны, а не одну.
О том, зачем так сложно, прошу не задумываться, это часть более сложной конструкции.

Виртуальная земля и синусоида из розетки цифруются АЦП проца+таймер+DMA. Эта связка отлажена и работает.

АЦП запускаю по Timer 2 CC2 event:
Код
    // ADC1 configuration ------------------------------------------------------
    ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;            // -> CR1 | 0x00060000
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;    // T2, канал 2 --> CR2
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 2;            // --> ADCx->SQR1
    ADC_Init ( ADC1, &ADC_InitStructure );


Настройка таймера TIM2, CCR2:
Код
   /* TIM2 configuration ------------------------------------------------------*/
   // Time Base configuration
   // TIM2 - APB1, 72MHz
   // Ft = Fapb1/(PSC+1) = 72E6/(PSC+1) = 72E6/1800=40000
   TIM_TimeBaseStructInit ( &TIM_TimeBaseStructure );
   TIM_TimeBaseStructure.TIM_Period = 20-1;               // -> ARR - До этого значения считает таймер
   TIM_TimeBaseStructure.TIM_Prescaler = 1800-1;               // -> PSC - делитель частоты шины, Ft = 40kHz
   TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;            //
   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
   TIM_TimeBaseInit ( TIM2, &TIM_TimeBaseStructure );

   // TIM1 channel1 configuration in PWM mode
   TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
   TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
   TIM_OCInitStructure.TIM_Pulse = 10;                     // CCR2
   TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
   TIM_OC2Init ( TIM2, &TIM_OCInitStructure );


DMA не привожу, там проблем вроде не заметил.
Проблема только лишь в том, что я планировал получить в буфере не 2 периода частоты 50 Гц, а 20 biggrin.gif График из экселя приложил.

по моим подсчётам частота запуска АЦП должна быть 40кГц/AAR = 40kHz/2 = 2КГц, но в буфере я вижу 2 периода входной частоты 50 Гц.
Буфер - 1000 значений.
Почему 2, я понять не могу. 2кГц = 2000 значений в секунду, в буфере 1000 значений за 0.5 сек. Это должно быть 500ms/20ms=25 периодов.
Почему у меня их 2? В чём я ошибаюсь?
Что самое интересное, что ради экперимента я пытался пихать в ARR и PSC разные числа - по фигу совершенно, там всегда 2 периода!

Сижу над этим уже 3 дня, не могу понять crying.gif smile3046.gif
В эррате ничего путного не нашёл.

Спасибо.

PS. Про странную форму графика с какими-то разрывами я уж молчу.
Сергей Борщ
Что с тактированием АЦП? Может вы его тактируете настолько медленно, а длительность выборки сделали настолько большой, что АЦП просто не успевает сделать требуемое количество преобразований?
Шаманъ
А что второй канал второго таймера от которого АЦП запускается никак конфигурировать не нужно? Или здесь не вся инициализация? АЦП то запускается не по переполнению таймера, а по событию от второго канала захвата/сравнения.
Timmy
Советую сделать для начала без DMA, по прерыванию EOC, и включить останов таймера при входе в отладчик, так гораздо понятнее станет, что происходит.
А, я не знаток Хала, но вы вроде врубили Continuous mode, поэтому АЦП после запуска всегда будет дубасить на максимальной скорости, игнорируя таймер.
uriy
Цитата
А, я не знаток Хала, но вы вроде врубили Continuous mode, поэтому АЦП после запуска всегда будет дубасить на максимальной скорости, игнорируя таймер.
:-) Это не HAL это SPL. Но написали вы похоже верно. У меня в ADC+TIM+DMA указано ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
Чтобы узнать реальную частоту таймера я включал прерывания от него и там дергал GPIO.
Еще когда разбирался в работе DMA по точкам останова были непонятные для меня вещи. Причина их была похоже в том что таймер или DMA не сразу останавливались или вовсе не останавливались. В итоге пока данные в дебаггере обновлялись в буфере DMA уже были нащелканы новые данные.
Еще заметил отличие. У меня ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; Сейчас понятия не имею что это значит. У меня было 16 входов АЦП.
Timmy
Цитата(uriy @ Feb 17 2017, 08:05) *
Еще заметил отличие. У меня ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; Сейчас понятия не имею что это значит. У меня было 16 входов АЦП.
Действительно, ТСу тоже надо поставить Independent, это значит, что два АЦП будут работать независимо.
Шаманъ
Цитата(uriy @ Feb 17 2017, 08:05) *
Чтобы узнать реальную частоту таймера я включал прерывания от него и там дергал GPIO.

Логичнее вывести сигнал напрямую без всяких прерываний через блок сравнения 2, который собственно и запускает АЦП, правда вывести можно не на любой вывод.

Цитата(Timmy @ Feb 17 2017, 08:35) *
Действительно, ТСу тоже надо поставить Independent, это значит, что два АЦП будут работать независимо.

Подозреваю, что два АЦП используются для одновременного измерения напряжения и тока, потом считается мощность sm.gif Насколько это корректно сделано не подскажу, ибо всеми этими HALами, SPLами не пользуюсь - напрямую с регистрами проще и понятнее все выходит.
Tanya
Цитата(hd44780 @ Feb 16 2017, 19:31) *
Сижу над этим уже 3 дня, не могу понять crying.gif smile3046.gif
PS. Про странную форму графика с какими-то разрывами я уж молчу.


Таймер запускает АЦП, который работает до заполнения массива по ДМА уже со своей тактовой частотой, которую Вы должны были выбрать сами. Можно еще время выборки менять...
Если ДМА работает по кругу, то легко объяснить Ваш чудный график.
Что Вы хотели-то?
hd44780
вот это
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
полностью решило проблему, в буфере сразу появилась куча периодов.
Видимо я загнался, глядя в кучу примеров rolleyes.gif .

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; - по-моему не надо, у меня ж регулярная группа каналов.

Цитата(Шаманъ @ Feb 17 2017, 09:41) *
Подозреваю, что два АЦП используются для одновременного измерения напряжения и тока, потом считается мощность sm.gif Насколько это корректно сделано не подскажу, ибо всеми этими HALами, SPLами не пользуюсь - напрямую с регистрами проще и понятнее все выходит.

Да, совершенно верно. У меня ещё 2 канала тока есть в схеме - всего 4 канала АЦП. Я их просто пока не опрашивал вообще. Чтобы не усложнять картину.
на SPL писал, т.к. подсматривал конфигурацию в старых некубовых примерах от ST.
Может и натравлю на них второй АЦП, не знаю как получится.

Сейчас ими и буду заниматься.

Спасибо всем большое.
Tanya
Цитата(hd44780 @ Feb 17 2017, 13:12) *
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; - по-моему не надо, у меня ж регулярная группа каналов.

Да, совершенно верно. У меня ещё 2 канала тока есть в схеме - всего 4 канала АЦП. Я их просто пока не опрашивал вообще. Чтобы не усложнять картину.
на SPL писал, т.к. подсматривал конфигурацию в старых некубовых примерах от ST.
Может и натравлю на них второй АЦП, не знаю как получится.

ADC_Mode_Independent - это нужно или не нужно - Вам решать. Там есть такая мода - два АЦП срабатывают почти одновременно с регулируемой задержкой (минимум - полтакта). И ДМА может сразу писать это в один массив.
hd44780
Цитата(Tanya @ Feb 17 2017, 13:29) *
ADC_Mode_Independent - это нужно или не нужно - Вам решать. Там есть такая мода - два АЦП срабатывают почти одновременно с регулируемой задержкой (минимум - полтакта). И ДМА может сразу писать это в один массив.


Да, спасибо, если я решу ток вторым АЦП измерять, это очень пригодится.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.