Главная » Статьи » Уроки по программированию stm32fxxx » Уроки по программированию stm32f4xx

Урок 6: Работа с АЦП

Основные особенности АЦП

Микроконтроллер stm32f1xx имеет на борту 3 12-ти разрядных АЦП. Каждое АЦП может быть подключено к любому из 16-ти аналоговых входов. Более того, каждое из АЦП может сканировать эти входы, снимая с них данные в заданном пользователем порядке.
По окончании преобразования АЦП может выдать прерывание. Вообще АЦП может выдать одно из трёх прерываний: Об окончании преобразования обычного (регулярного) канала, об окончании преобразования по инжекторному каналу и событие по Watchdog.
В режиме сканирования прерывание об окончании преобразования выдаётся только по завершении всего сканирования. И при использовании регулярных каналов, в которых данные записываются всегда в один и тот же регистр, вы будете получать результаты только последнего преобразования.
Что бы этого не происходило, в микроконтроллере предусмотрено наличие так называемых инжекторных каналом, имеющих в своём наличии 4 разных регистра для записи данных. Т.е. если вам надо сканировать не более 4-х каналов, то результаты преобразований вы не потеряете. Т.к. каждый канал будет писать данные в свой регистр.
Для параллельного снятия данных сразу по нескольким каналам, предусмотрена возможность одновременного запуска нескольких АЦП. Данный режим получил название Dual Mode.

Подключение АЦП

Прежде всего рассмотрим подключение АЦП. Для чего нужна каждая ножка показано в таблице 1.

Таблица 1


Из перечисленных ножек интересны -Vоп и +Vоп. Они определяют диапазон напряжений, воспринимаемых АЦП. Если подключить -Vоп к земле, а +Vоп к питанию, то АЦП сможет оцифровать аналоговые сигналы во всём диапазоне от 0, до питания. Т.к. питания МК составляет 3,3В, а разрядность АЦП равна 12-ти, т.е. мы имеем 2^12=4096 уровней квантовая, шум АЦП составит 3,3/4096=0,8 мВ.

Виды АЦП

В микроконтроллере существует 2 вида каналов АЦП: регулярные и инжекторные. Эти 2 канала настраиваются независимо. Но работать может только один из них для каждого канала. Основным различием этих каналов является то, что для хранения данных, получаемых с помощью регулярного канала используется только один регистр. Это не плохо, если вам надо снять за один раз данные только с одного канала для каждого АЦП. Но, если Вам надо производить сканирование данных, то все снятые данные будут записываться с один и тот же регистр. Т.о. при чтении данных в прерывании по окончании преобразования Вы будете получать только последние снятые данные. Эту проблему призваны исправить инжекторные каналы. У них предусмотрены 4 регистра для хранения данных. Т.е. Вы сможете хранить данные с 4-х каналов сканирования. Недостатком инжекторных каналов является несколько более сложная система настройки, в которой надо описать данные, с какого канала в какой регистр будут записаны.

Настройка регулярного канала

Рассмотрим настройку регулярного канала АЦП. Настроим АЦП на ножке А4. Прежде всего, надо узнать какие АЦП имеют доступ к этой ножке и какие каналы на неё выведены. В частности это 4-й канал первого АЦП.
Как обычно используем стандартную схему:
1) Включить тактирование порта
2) Настроить вывод
3) Включить тактирование АЦП
4) Настроить АЦП
5) Включить нужные прерывания
6) Включить глобальные прерывания
7) Включить АЦП

При настройке порта главное в режиме задать аналоговый режим.
Настройка вывода в аналоговом режиме

GPIO_InitTypeDef GPIO_Init_user;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

GPIO_Init_user.GPIO_Pin = GPIO_Pin_4;
GPIO_Init_user.GPIO_Mode = GPIO_Mode_AN;
GPIO_Init_user.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init_user.GPIO_OType = GPIO_OType_PP;
GPIO_Init_user.GPIO_PuPd = GPIO_PuPd_NOPULL;

GPIO_Init(GPIOA, & GPIO_Init_user);


Включаем тактирование АЦП:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

Настраиваем АЦП:
Настройка регулярного канала АЦП

ADC_InitTypeDef ADC_InitType;

ADC_InitType.ADC_ContinuousConvMode = DISABLE;
ADC_InitType.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitType.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_InitType.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitType.ADC_NbrOfConversion = 1;
ADC_InitType.ADC_Resolution = ADC_Resolution_12b;
ADC_InitType.ADC_ScanConvMode = DISABLE;

ADC_Init(ADC1, &ADC_InitType);


Рассмотрим настройки подробнее:
ContinuousConvMode – Этот режим, если включен, запускает следующее преобразование сразу по окончании предыдущего. Так можно добиться максимальной скорости работы АЦП. В нашем случае это не надо и данная функция отключена.
DataAlign – выравнивание данных в 2-хбайтном слове. Есть 2 варианта. ADC_DataAlign_Right при котором данные выравниваются по правому краю, а неиспользуемые биты при этом равны нулю. Т.е. мы получаем обычные числа в 2-х байтах от 0 до 8192. При ADC_DataAlign_Left данные выравниваются по левому краю. Т.е. фактически для 12-ти битного преобразования они увеличиваются в 16 раз. Это может быть использовано например при передаче их через SPI, поддерживающий 12-ти битную передачу данных. Если настроить SPI на передачу начиная со старшего разряда. ExternalTrigConvEdge – настраивает запуск преобразования по какому либо событию, например переполнению таймера. В нашем случае не требуется.
ExternalTrigConv – Устанавливает какие именно события запустят АЦП. Т.к. триггер отключен, то эта функция не используется.
NbrOfConversion – число каналов, которые будет сканировать МК. Сюда записывается требуемое значение, а ниже, если это число больше 1 и ADC_ ScanConvMode=ENABLE, описывается какие каналы и в какой последовательности они будут сканироваться
ScanConvMode – Этот параметр определяет будет ли АЦП сканировать несколько каналов. Если этот режим включен, то АЦП будет последовательно оцифровывать данные с заданных каналов в заданной последовательности. И каналы и последовательность легко можно задать. Но возникает небольшая проблема со снятием данных.

Настраиваем конкретный канал. В нашем случае это всего один канал, потому настройка будет выглядеть так:

ADC_RegularChannelConfig(ADC1,ADC_Channel_4,1, DC_SampleTime_56Cycles);

Из параметров тут:
ADC1 – номер настраиваемого АЦП.
ADC_Channel_4 задаёт снимаемый канал.
1 – так называемый rank. Показывает в каком порядке этот канал будет оцифровываться. В нашем случае канал один, потому и rank=1.
DC_SampleTime_56Cycles – задаёт за какое время будет произведена оцифровка. Чем медленнее, тем точнее.

Теперь осталось настроить прерывания и включить:

NVIC_EnableIRQ(ADC_IRQn);
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);

ADC_Cmd(ADC1, ENABLE);

На этом настройка закончена.

Чтобы запустить преобразование, используйте функцию:

ADC_SoftwareStartConv(ADC1);

По окончании преобразования программа попадёт в функцию прерывания:

void ADC_IRQHandler(void)
{
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
ADC_result = ADC_GetConversionValue(ADC1);
}

Сбрасываем флаг и считываем результат преобразования.
Можно скачать пример работы от сюда.
Категория: Уроки по программированию stm32f4xx | Добавил: Korvin (11.11.2013)
Просмотров: 12911 | Комментарии: 2 | Рейтинг: 3.0/5
Всего комментариев: 2
1 Евгений  
0
во первых спасибо за статью
ну во вторых есть вопрос в приложенном примере есть строка

sprintf(str, "V=%d mv", ADC_result);

как я понял она переменной str присваивает показание АЦП красиво но не понятно.

2 Korvin  
0
Это работа данной функции. Она записывает в массив строку и вместо %d вставляет значение ADC_Result. Так можно переделывать тип интеджер в строковый.

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]