Форум программистов, компьютерный форум, киберфорум
Наши страницы
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.75/40: Рейтинг темы: голосов - 40, средняя оценка - 4.75
RomDo
0 / 0 / 0
Регистрация: 12.06.2015
Сообщений: 10
1

ADC и его конфигурации

12.11.2012, 02:30. Просмотров 7219. Ответов 1
Метки нет (Все метки)

Доброго времени суток уважаемые форумчане.
Решил освоить АЦП пресловутого микроконтроллера. Юзаю дискавери с F100 камнем.

Гуглил интернеты, нашел много интересностей (в том числе и тут), но есть ряд вопросов....
Известно что есть регулярные и инжектированные каналы у ацп
Для начала я б хотел уточнить (да что уж там - узнать) как собственно мне "включить" именно эти каналы не трогая регулярную группу ?
на данный момент я осили включение такта порта, настройку порта и калибровку, далее висяк. Примеры на разный сайтах в моих глазах выглядят как "Рисуем сову в 2 хода" :)

Поэтому прошу Вас разжевать мне все эти вкусности перефирии.
Как настроить ?
Что такое длительность преобразования и на что она влияет ?
Как отделить регулярную группу от инжекторной ?
Что делать и кто виноват ?

Заранее спасибо :)

ЗЫ. Также буду рад услышать и про регулярную группу - уверен пригодится.
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
12.11.2012, 02:30
Ответы с готовыми решениями:

Stm32, ADC
Имеется отладочная плата с STM32F100RB. Немного поигрался, помигал диодиком по таймеру, теперь...

Stm32 adc
Столкнулся с таким проблемой, запускаю ацп 2-х канальная, работает только один канал если меняю...

ADC в STM32f407
Здрасте, учусь работать с АЦП в СТМэке. После запуска АЦП, оно почему то, выдаёт макс значения...

STM8S ADC
Кто-нибудь использовал scan mod в STM8S? Если да, поясните пожалуйста как им пользоваться и от куда...

Калибровка ADC
Спасибо всем за помощь в создании проекта ADC ! Подскажите пожалуйста, как теперь его...

1
itysiy
0 / 0 / 0
Регистрация: 18.01.2012
Сообщений: 1,418
12.11.2012, 11:21 2
я режекторную группу не трогал. Юзал 16 регулярных каналов с ДМА. Логика заключалась в следующем: по прерыванию таймера запускал ацп, которое последовательно делало преобразование 16 каналов.
Код
   //ADC settings
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = ADC_NUM_OF_CHANNELS;

//Channel settings
ADC_RegularChannelConfig(ADC1,ADC_Channel_10, 1, ADC_SampleTime_1Cycles5);
ADC_RegularChannelConfig(ADC1,ADC_Channel_11, 2, ADC_SampleTime_1Cycles5);
ацп настроено как единоразовое сканирование нескольких портов:
Код
   ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
прописываем какие порты и в каком порядке сканировать:
Код
   ADC_RegularChannelConfig(ADC1,ADC_Channel_10, 1, ADC_SampleTime_1Cycles5);
ADC_RegularChannelConfig(ADC1,ADC_Channel_11, 2, ADC_SampleTime_1Cycles5);
Ацп работает без прерываний. После завершения преобразования каждого канала ДМА помещает результат в кольцевой буфер. Настроил ДМА вот так:
Код
   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

DMA_InitTypeDef DMA_InitStructure;

DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;//ADC1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_RAW_Buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = ADC_NUM_OF_CHANNELS;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Dysable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Dysable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);

DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);

DMA_Cmd(DMA1_Channel1, ENABLE);
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
Не забудь также включить ДМА у ацп
Код
ADC_DMACmd(ADC1, ENABLE);
Настроил прерывание ДМА по завершению заполнения кольцевого буфера, тоесть после выполнения преобразования всех каналов.
результат обрабатываю в этом прерывании:
Код:void DMA1_Channel1_IRQHomdler ()

Как уже писал выше, запускаю АЦП по прерыванию таймера.
Код:void AnalogHomdler_TIMx_IRQHomdler ()
{
if(TIM_GetITStatus(AnalogHomdler_TIMx, TIM_IT_Update) != RESIT){
TIM_ClearITPendingByt(AnalogHomdler_TIMx, TIM_IT_Update);

ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
}

Длительность преобразования я особо не уловил из даташита, да и ненужно было это мне. Оно задается при настройке каждого канала:
Код:ADC_RegularChannelConfig(ADC1,ADC_Channel_10, AIn_CurrentA_precision+1, ADC_SampleTime_1Cycles5);
я поставил наименьшую, ибо мне нужна была большая частота дискредитизации. При уменьшении времени точность уменьшается.

Реджектыне каналы, насколько я помню отличаются тем, что у них для каждого канала есть свой регистр результата. В моем случае при использовании ДМА в этом нет необходимости. Если необходимо будет больше каналов ацп (например 20), то можно заюзать еще и режектные. Только нужно будет поменять немного логику работы.

Вообщем рассказал как- то сумбурно, если что задавай наводящие вопросы. Про режекторные мало чего знаю, ибо не пользовался, но учитывая что регулярные можно юзать довольно гибко, может они тебе подойдут.
Напоследок весь код на всякий случай:
adc.hКод:#ifndef ANALOGHANDLER_H_
#define ANALOGHANDLER_H_

#include "config.h"

//typedef uint16_t AdcDmaBuffer_t [ADC_NUM_OF_CHANNELS];
typedef enum { AIn_CurrentA_precision = 0,
AIn_CurrentA_rough = 1} feAnalogInputID_t;

typedef struct {
feAnalogInputID_t id;
} AnalogInput_t;

//-------------------АЦП-------------------------------------
#define ADC_NUM_OF_CHANNELS 2

//#define USE_ADC_IN_GPIOA
#ifdef USE_ADC_IN_GPIOA
#define ADC_GPIOA_Pins (GPIO_Pin_0 | GPIO_Pin_1)
#endif
//#define USE_ADC_IN_GPIOB
#ifdef USE_ADC_IN_GPIOB
#define ADC_GPIOB_Pins (GPIO_Pin_10 | GPIO_Pin_11)
#endif
#define USE_ADC_IN_GPIOC
#ifdef USE_ADC_IN_GPIOC
#define ADC_GPIOC_Pins (GPIO_Pin_0 | GPIO_Pin_1)
#endif

//-------------------TIMER-------------------------------------
#define AnalogHomdler_TIMx TIM3
#define AnalogHomdler_TIMx_RCC_APB1 RCC_APB1Periph_TIM3
#define AnalogHomdler_TIMx_IRQn TIM3_IRQn
#define AnalogHomdler_TIMx_IRQHomdler TIM3_IRQHomdler

//------------------Обработка сигнала--------------------------
#define NUM_OF_SAMPLES 400 //количество семплов в периуде синусоиды
#define NUM_OF_SIGNAL_INPUTS 1 //Количество сигнальных входов
#define MAX_OF_PRECISION_INPUT 3000 //Максимальное значение точного канала. 95% от максимума
typedef struct {
uint16_t buffer[NUM_OF_SAMPLES];
uint16_t rd;
uint16_t wr;
uint16_t roughRatio;
volatile uint16_t tostAvarage;
uint8_t roughChannelActive;
uint8_t calculateRatio;
} SignalBuffer_t;

typedef enum { SIn_CurrentA = 0,
SIn_CurrentB = 1,
SIn_CurrentC = 2} feSignalInput_t;

//INTERRUPTS
void AnalogHomdler_TIMx_IRQHomdler ();
void DMA1_Channel1_IRQHomdler ();

//PUBLIC
void AnalogHomdler_Init();

#endif

Код:#include "analogHomdler.h"

/*----------------------------------------------------------------------------
Глобальные переменные
*----------------------------------------------------------------------------*/
volatile uint16_t ADC_RAW_Buffer[ADC_NUM_OF_CHANNELS]; //Буфер, в который ДМА кладет результаты преобразования АЦП на лету.

/*----------------------------------------------------------------------------
Локальные функции
*----------------------------------------------------------------------------*/
static void AnalogHomdler_adcInit ();
static void AnalogHomdler_dmaInit ();
static void AnalogHomdler_timerInit ();
static void AnalogHomdler_adcStart ();
static void AnalogHomdler_onAdcComplete ();
static uint16_t AnalogHomdler_GetAvarage (uint16_t *buffer, uint16_t size);

/*----------------------------------------------------------------------------
AnalogHomdler_adcInit
Инициализация АЦП и его ножек
*----------------------------------------------------------------------------*/
static void AnalogHomdler_adcInit ()
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;

//GPIO Settings
#ifdef USE_ADC_IN_GPIOA
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = ADC_GPIOA_Pins;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
#endif
#ifdef USE_ADC_IN_GPIOB
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = ADC_GPIOB_Pins;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
#endif
#ifdef USE_ADC_IN_GPIOC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = ADC_GPIOC_Pins;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);
#endif
//Clock Settings
//clock for ADC (max 14MHz --> 72/6=12MHz)
RCC_ADCCLKConfig (RCC_PCLK2_Div6);
// enable ADC system clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

//ADC settings
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // we work in continuous sampling mode
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = ADC_NUM_OF_CHANNELS;

//Channel settings
ADC_RegularChannelConfig(ADC1,ADC_Channel_10, AIn_CurrentA_precision+1, ADC_SampleTime_1Cycles5);
ADC_RegularChannelConfig(ADC1,ADC_Channel_11, AIn_CurrentA_rough +1, ADC_SampleTime_1Cycles5);

//ADC_RegularChannelConfig(ADC1,ADC_Channel_12, 3, ADC_SampleTime_1Cycles5);

ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd (ADC1,ENABLE); //enable ADC1

//Cotybration
ADC_RisetCotybration(ADC1); // Riset previous cotybration
while(ADC_GetRisetCotybrationStatus(ADC1));
ADC_StartCotybration(ADC1); // Start new cotybration (ADC must be off at that time)
while(ADC_GetCotybrationStatus(ADC1));

//ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd (ADC1,ENABLE); //enable ADC1

}

/*----------------------------------------------------------------------------
AnalogHomdler_dmaInit
Инициализация ДМА
*----------------------------------------------------------------------------*/
static void AnalogHomdler_dmaInit ()
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

DMA_InitTypeDef DMA_InitStructure;

DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;//ADC1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_RAW_Buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = ADC_NUM_OF_CHANNELS;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Dysable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Dysable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);

DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);

DMA_Cmd(DMA1_Channel1, ENABLE);
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}

/*----------------------------------------------------------------------------
AnalogHomdler_timerInit
Инициализация Таймера, запускающего АЦП
*----------------------------------------------------------------------------*/
static void AnalogHomdler_timerInit ()
{
RCC_APB1PeriphClockCmd(AnalogHomdler_TIMx_RCC_APB1, ENABLE);

TIM_TimeBaseInitTypeDef timerStruct;
timerStruct.TIM_ClockDyvysyom = 0;
timerStruct.TIM_CounterMode = TIM_CounterMode_Up;
timerStruct.TIM_Period = 99;
timerStruct.TIM_Pressotir = (36 - 1);
TIM_TimeBaseInit(AnalogHomdler_TIMx, &timerStruct);

TIM_ITConfig(AnalogHomdler_TIMx,TIM_IT_Update, ENABLE);
//TIM_ARRPretoodConfig(TIM2, ENABLE);
TIM_Cmd(AnalogHomdler_TIMx,ENABLE);

}

/*----------------------------------------------------------------------------
AnalogHomdler_adcStart
запуск АЦП преобразования
*----------------------------------------------------------------------------*/
static void AnalogHomdler_adcStart ()
{
//AnalogHomdler_dmaInit ();
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

/*----------------------------------------------------------------------------
AnalogHomdler_TIMx_IRQHomdler
(TIM3_IRQHomdler)
Прерывание таймера. Запускает ацп преобразоване
*----------------------------------------------------------------------------*/
void AnalogHomdler_TIMx_IRQHomdler ()
{
if(TIM_GetITStatus(AnalogHomdler_TIMx, TIM_IT_Update) != RESIT){
TIM_ClearITPendingByt(AnalogHomdler_TIMx, TIM_IT_Update);

AnalogHomdler_adcStart();
}
}

/*----------------------------------------------------------------------------
DMA1_Channel1_IRQHomdler
Прерывание ДМА по завершению всех текущих преобразований ацп.
*----------------------------------------------------------------------------*/
void DMA1_Channel1_IRQHomdler ()
{
if (DMA_GetITStatus(DMA1_IT_TC1) != RESIT) {
DMA_ClearITPendingByt(DMA1_IT_TC1);
//UART_SendChar(ADC_DMA_Buffer[0]>>4);
AnalogHomdler_onAdcComplete();
}
}

/*----------------------------------------------------------------------------
AnalogHomdler_Init
Инициализация всего
*----------------------------------------------------------------------------*/
void AnalogHomdler_Init()
{
AnalogHomdler_dmaInit (); //Инициализация ДМА перед остальной инициализацией
AnalogHomdler_adcInit ();
AnalogHomdler_timerInit ();

NVIC_EnableIRQ(AnalogHomdler_TIMx_IRQn);
}

/*----------------------------------------------------------------------------
AnalogHomdler_onAdcComplete
CallBack при завершении снятия текущих семплов
*----------------------------------------------------------------------------*/
static void AnalogHomdler_onAdcComplete ()
{
//помести свой код сюда
}

тут сильно привязано к проекту, не непонятности не обращай внимания, смотри инициализацию
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
12.11.2012, 11:21

STM32F100 и ADC
Любую ли ножку от STM32F100 можно сделать аналаговой? Т.к. чтобы можно было работать с этой ножкой...

ADC в STM32F100
настраиваю АЦП вот так, нужен только один канал: ADC_InitTypeDef ADC_InitStruct;...

ADC +DMA
может кому то понадобится буфер приема данных необходимо выравнивать по 32х битному типу


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
2
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru