Страница 1 из 1
stm32f10x - измерение частоты и амплитуды сигнала
Добавлено: Сб мар 05, 2016 11:59:21
kapusta1986
Всем добрый день! Котаны и кошки! )
Имею отладочную плату на базе камня stm32f10x (то бишь дискавери), с сайта (
http://robocraft.ru/blog/ARM/739.html) - код автора заработал сразу. Получилось измерить частоту и ширину импульса. У меня вопрос, может ли стмка измерить амплитуду сигнала?
Ведь нельзя в прерывание таймера засунуть прерывание ADC ?
Отдельно запустил ADC для измерения того же самого сигнала, но он получается какой то устредненный, ровно половину от 3,3 В
Если подать постоянный сигнал, то получаю как положенно 4095 (то бишь 3.3В), а с частотой проблема.... собсвенно вот и вопрос: может ли стмка измерить амплитуду сигнала?
Спасибо!

Re: stm32f10x - измерение частоты и амплитуды сигнала
Добавлено: Вс мар 06, 2016 06:05:20
Z_h_e
kapusta1986 писал(а):Ведь нельзя в прерывание таймера засунуть прерывание ADC ?
Прерывание с более высоким приоритетом прервет выполнение текущего обработчика прерывания.
kapusta1986 писал(а):может ли стмка измерить амплитуду сигнала?
Программно то можно сделать. Я правда с STM еще очень мало игрался.
Re: stm32f10x - измерение частоты и амплитуды сигнала
Добавлено: Вс мар 06, 2016 06:35:22
Neekeetos
kapusta1986 писал(а):Ведь нельзя в прерывание таймера засунуть прерывание ADC ?
А зачем, если настроить триггер ацп на выход канала захвата таймера, то оно будет срабатывать когда пришел фронт/спад, в прерывании таймера можно будет подождать пока закончится преобразование и считать то что намерилось. Там будет еще задержка между самим фронтом входного сигнала и началом работы ацп, она примерно равна длине фильтра канала захвата плюс задержка старта ацп , еще пару тактов , а сам момент для которого сигнал будет измерен будет еще дальше отодвинут во времени - еще и на время выборки ацп, которое кстати лучше увеличить.
Re: stm32f10x - измерение частоты и амплитуды сигнала
Добавлено: Ср мар 16, 2016 07:16:32
kapusta1986
Спасибо Neekeetos, с помощью товарища одного мне удалось собрать код
На низких частотах работает нормально. Из проблем у меня выявилось небольшое отклонение по вольтажу - 4095 значение при 2.8 В
Частоту мерит без проблем
Код: Выделить всё
#include <тут подключите библиотеки необходимые>
void init_gpio(void);
void init_timer(void);
uint16_t uint16_time_diff(uint16_t now, uint16_t before);
volatile uint16_t systick_ms = 0;
volatile uint16_t Tcapture1 = 0, Tcapture2 = 0;
volatile uint8_t T1capture_is_first = 1, T1capture_is_ready = 0;
uint32_t period;
uint32_t adcvalue;
void ADC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
/* PCLK2 is the APB2 clock */
/* ADCCLK = PCLK2/6 = 72/6 = 12MHz*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
/* Enable ADC1 clock so that we can talk to it */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
/* Put everything back to power-on defaults */
ADC_DeInit(ADC1);
/* ADC1 Configuration ----------*/
/* ADC1 and ADC2 operate independently */
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
/* Disable the scan conversion so we do one at a time */
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
/* Don't do contimuous conversions - do them on demand */
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
/* Start conversin by software, not an external trigger */
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
/* Conversions are 12 bit - put them in the lower 12 bits of the result */
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
/* Say how many channels would be used by the sequencer */
ADC_InitStructure.ADC_NbrOfChannel = 1;
/* Now do the setup */
ADC_Init(ADC1, &ADC_InitStructure);
/* 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));
//настройка канала АЦП
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
//настройка прерывания для ацп
NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_EnableIRQ(ADC1_2_IRQn);
}
//прерывание измерит значение и передаст переменной adcvalue
void ADC1_2_IRQHandler(void)
{
//обработали прерывание
if (ADC_GetITStatus(ADC1, ADC_IT_EOC))
{
ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
adcvalue = ADC_GetConversionValue(ADC1);
}
}
int main(void)
{
static uint32_t toggle_ms = 0;
//тут настройте тактирование и прочие параметры
init_gpio();
init_timer();
ADC_Configuration();
//SysTick_Config(SystemCoreClock / 1000);
while (1)
{
if (T1capture_is_ready)
{
NVIC_DisableIRQ(TIM3_IRQn);
T1capture_is_ready = 0;
/* Обрабатываем захваченный период */
period = uint16_time_diff(Tcapture2, Tcapture1);
// ...
NVIC_EnableIRQ(TIM3_IRQn);
}
//тут уже оперируйте со значением амплитуды adcvalue
}
}
void init_gpio(void)
{
GPIO_InitTypeDef gpio_cfg;
GPIO_StructInit(&gpio_cfg);
/* Таймер TIM3, канал 1 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
gpio_cfg.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio_cfg.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOA, &gpio_cfg);
//светодиоды PC9 и PC8
gpio_cfg.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
gpio_cfg.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_cfg.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOC, &gpio_cfg);
}
void init_timer(void)
{
TIM_TimeBaseInitTypeDef timer_base;
TIM_ICInitTypeDef timer_ic1;
TIM_ICInitTypeDef timer_ic2;
/* Подаём такты на TIM3 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/* Настраиваем предделитель так, чтобы таймер считал миллисекунды.
На бо́льших частотах следите, чтобы предделитель не превысил
максимальное значение uint16_t - 0xFFFF (65535) */
TIM_TimeBaseStructInit(&timer_base);
//прескалер для измерения низких частот
timer_base.TIM_Prescaler = 7200 - 1;
TIM_TimeBaseInit(TIM3, &timer_base);
/* Настраиваем захват сигнала:
- канал: 1
- счёт: по нарастанию
- источник: напрямую со входа
- делитель: отключен
- фильтр: отключен */
timer_ic1.TIM_Channel = TIM_Channel_1;
timer_ic1.TIM_ICPolarity = TIM_ICPolarity_Rising;
timer_ic1.TIM_ICSelection = TIM_ICSelection_DirectTI;
timer_ic1.TIM_ICPrescaler = TIM_ICPSC_DIV1;
timer_ic1.TIM_ICFilter = 0;
TIM_ICInit(TIM3, &timer_ic1);
timer_ic2.TIM_Channel = TIM_Channel_2;
timer_ic2.TIM_ICPolarity = TIM_ICPolarity_Falling;
timer_ic2.TIM_ICSelection = TIM_ICSelection_DirectTI;
timer_ic2.TIM_ICPrescaler = TIM_ICPSC_DIV1;
timer_ic2.TIM_ICFilter = 0;
TIM_ICInit(TIM3, &timer_ic2);
/* Разрешаем таймеру генерировать прерывание по захвату */
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);
TIM_ITConfig(TIM3, TIM_IT_CC2, ENABLE);
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
/* Включаем таймер */
TIM_Cmd(TIM3, ENABLE);
/* Разрешаем прерывания таймера TIM3 */
NVIC_EnableIRQ(TIM3_IRQn);
}
void TIM3_IRQHandler(void)
{
//если сработало прерывание по фронту
if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
{
/* Даём знать, что обработали прерывание */
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
// /* Запоминаем предыдущее измерение и считываем текущее */
/* время будет как разность этих двух значении */
Tcapture1 = Tcapture2;
Tcapture2 = TIM_GetCapture1(TIM3);
// /* Для корректной обработки нужно минимум два измерения */
if (!T1capture_is_first)
T1capture_is_ready = 1;
T1capture_is_first = 0;
//одновременно будем считать, что здесь высокий уровень сигнала, а значит можно измерить амплитуду
//запускаем конвертацию АЦП
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
//
/* Тут как-нибудь обрабатываем событие over-capture, если провороним */
if (TIM_GetFlagStatus(TIM3, TIM_FLAG_CC1OF) != RESET)
{
TIM_ClearFlag(TIM3, TIM_FLAG_CC1OF);
// ...
}
}
}
void SysTick_Handler(void)
{
++systick_ms;
}
uint16_t uint16_time_diff(uint16_t now, uint16_t before)
{
return (now >= before) ? (now - before) : (UINT16_MAX - before + now);
}
Re: stm32f10x - измерение частоты и амплитуды сигнала
Добавлено: Ср мар 16, 2016 08:06:32
kapusta1986
А зачем, если настроить триггер ацп на выход канала захвата таймера, то оно будет срабатывать когда пришел фронт/спад,
А как это сделать?
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_CC1; //частота у меня приходит на Т3 таймер
ADC_ExternalTrigConvCmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
включил
Но не фурычит... ((( что я делаю не так?
Re: stm32f10x - измерение частоты и амплитуды сигнала
Добавлено: Ср мар 16, 2016 18:43:16
Neekeetos
kapusta1986 писал(а):ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_CC1; //частота у меня приходит на Т3 таймер
ADC_ExternalTrigConvCmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
Не пользуюсь SPL именно из за этого бреда. У ацп в ф10х просто нету внешнего триггера т3-сс1, вот например картинка из мануала
видно что для того чтобы работал сс1 нужно включить TIM3_TRGO, а на самом таймере выбрать выход триггера чтобы он дублировал сс1.
Re: stm32f10x - измерение частоты и амплитуды сигнала
Добавлено: Ср мар 16, 2016 20:16:24
fagci
Делаю осциллограф, посмотреть можно тут
http://www.youtube.com/watch?v=5nLQ-VqMv-gтам же ссылка на исходники.
Ветка ADC, пока не сливаю, ибо сыро=)
Re: stm32f10x - измерение частоты и амплитуды сигнала
Добавлено: Чт мар 17, 2016 04:38:45
kapusta1986
Спасибо!

Neekeetos , Z_h_e
Буду думать теперь, писать, пробовать, отлаживать...
fagci - исходник ADC как у Вас сделан? Вы можете без кода вкратце рассказать как у вас идут измерения в этом проекте?
Re: stm32f10x - измерение частоты и амплитуды сигнала
Добавлено: Пт мар 18, 2016 23:56:57
fagci
Есть ADC, к нему прицеплен DMA с размером буфера равным ширине экрана в ландшафте. DMA кольцевой, по окончанию генерится прерывание, в котором устанавливается флаг наличия данных.
Сам ADC делает замеры по внешнему триггеру - таймеру, настроенному на частоту, которая просчитана с учётом частоты на деление.
В основном цикле проверяется, сработало ли прерывание по заполнению ДМА буфера и дальше рисуется с учётом того, что максимум 4096 по амплитуде, далее масштабируется.
Пока захвата rising/спада нет, но хочется реализовать.