STM32F030F4 инициализируем ADC

ADC на PA0

Инициализация:
void ADC_Config(void)
{
  ADC_InitTypeDef     ADC_InitStructure;
  GPIO_InitTypeDef    GPIO_InitStructure;

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
  ADC_DeInit(ADC1);
  
  ADC_StructInit(&ADC_InitStructure);
  
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;
  ADC_Init(ADC1, &ADC_InitStructure); 
  
  ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_239_5Cycles);
  ADC_GetCalibrationFactor(ADC1);
  ADC_Cmd(ADC1, ENABLE);     
  
  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY)); 
  
  ADC_StartOfConversion(ADC1);
}


Использование:

ADC_Config();
while(1) {
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
    ADCValue = ADC_GetConversionValue(ADC1);
}


Вместо ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; можно написать ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;, тогда перед каждой оцифровкой надо будет вызывать ADC_StartOfConversion(ADC1);

Заодно есть вопрос. Подключаю PA0 через делитель к +3.3V, гоняю по циклу ADC_GetConversionValue(). Оцифрованые значения имеют разбежку +/-10. Это нормально поведение АЦП или я что-то не так делаю?
  • -1
  • 03 февраля 2016, 22:41
  • aliaksei

Комментарии (34)

RSS свернуть / развернуть
Оцифрованые значения имеют разбежку +/-10
Вполне нормально, пара последних бит в АЦП могут гулять (а могут и «виртуальными» быть), так что вполне приемлемо: все как у людей=))
0
  • avatar
  • kalik
  • 03 февраля 2016, 23:12
Вполне нормально, пара последних бит в АЦП могут гулять

+/-10 — это 5 разрядов АЦП, а не пара последних бит, это много.
0
Не знаю, как вы можете утверждать что это много, если у него не понятно что на схеме творится.
0
Я отвечал на комментарий коллеги kalik , имеется ввиду, что +/-10 это много для того, чтобы просто так списать это на «пара последних бит в АЦП могут гулять»
+1
Согласен с уточнением.
0
Ну может я и переборщил… но сколько там у STM бит в АЦП? 12? + за сколько приближений произойдет приближений(ой преобразований) в пример метод золотого сечения?

значит имеем 2^12= 4096(95) и 10 единиц в загуле? да как тут писали питание может на больше нагулять… или как наводки и т.д. магия всякая околоокультная=))
но я если честно не силен в аналоговоцифровом преобразовании и утверждать не буду на 100 процентов! то с чем сталкивался и на какие грабли влетал… то и травлю… сплетни в общем=))
0
обычно вся эта «оккультщина» убирается грамотной схемотехникой. а то накупят копеечных иип, понаделают из них блоков питания. и потом ищут откуда ноги помехи растут.
0
эх, не дождался, в посте про USART только что написал:)
0
если питание гуляет — все может быть
0
  • avatar
  • xar
  • 04 февраля 2016, 14:13
Не обязательно должно гулять питание. Вход контроллера высокоомный, линия от источника до АКП — отличная антенна.
0
До АЦП, конечно.
0
тоже вариант.
0
По поводу таких снипетов имею сказать следующее. Смысла в них мало, ибо конфигураций ног контроллера бывает хренова туча. Чтобы их все хранить в виде таких снипетов нужно, хранить кучу кода. Значительно проще прописать стандартную последовательность действий, для каждого из которых держать снипет. Как то: включить тактирование порта, сконфигурировать ногу порта, сконфигурировать альтернативную функцию порта, включить тактирование периферии (ЦАП/АЦП/SPI), настроить периферию, настроить прерывания, настроить DMA. Вот в таком виде из них можно собирать любые конфигурации. Можно для пущей важности прописать некоторые справочные данные из даташитов под конкретный контроллер, если на производстве используется только он.
0
Чтобы их все хранить в виде таких снипетов нужно, хранить кучу кода. Значительно проще прописать стандартную последовательность действий

Не согласен. Данный код вполне читаемо написан, и содержит ту самую последовательность действий + готовый пример реализации. В случае необходимости — не вижу проблем с переделыванием это под другие ноги/АЦП.

Не вижу смысла хранить просто текстовое описание действий (лучше сразу нормальный пример кода).
+1
Хоть один коммент видите? Плохо, что их нет.
Далее, вот этот кусок кода
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;

никуда не годится, будет работать только в этом конкретном случае, а в других надо ещё уточнять параметры.

Не вижу смысла хранить просто текстовое описание действий (лучше сразу нормальный пример кода).
А я этого и не говорил. Я сказал, что есть последовательность действий, и для каждого из этих действий отдельный снипет.
0
Далее, вот этот кусок кода

Возможно дело в том, что я работал с SPL и для меня этот код выглядит простым и понятным: мы переводим пин в режим аналогового входа без подтяжки.

Для тех, например, кто предпочитает работать с регистрами напрямую — данный код возможно будет непонятен, но никто не мешает им нагуглить (или написать самому) пример работы с АЦП, который будет понятен им.

ИМХО, хороший (и понятный вам) пример кода лучше чем просто текстовое описание т. к. он несет больше информации (тут вам и последовательность действий, и пример реализации этой последовательности) он протестирован и может выступать шаблоном. То, что нужно будет поменять GPIO_Pin_0 и GPIOC на то, где у вас висит вход АЦП (и сам АЦП опменять на нужный, ну и тактирование при необходимости) по моему и так понятно, но никто не мешает вам добавить комментарий.

Для обучения, да наверное лучше словесное описание. Но если нужна именно памятка для себя на будущее — я предпочту хороший пример реализации.
+1
пример кода лучше чем просто текстовое описание
Вы меня упорно не слышите. Есть последовательность действий, она стандартная. Для каждого шага свой снипет. Всё.
Но если нужна именно памятка для себя на будущее — я предпочту хороший пример реализации.
Пример лучше снабдить комментариями, чтобы через полгода не задавать себе вопрос «что это такое?»… И пример — плохой, я уже показал почему плохой.
0
Ок, коллега, я не вижу смысла особо спорить, ибо это все «на вкус и цвет ...». Для меня пример неплохой (в плане читаемости кода).

Правда, в данном случае, я не уверен, что это правильный пример, т. к. +-10 слишком большой разброс, и я с Вами согласен в том, что мы не знаем что там творится в аналоговой части (возможно проблема именно там, а не в коде).
+2
Пример неплохой. Снипет плохой. Непонятно, что там происходит для новичка, а ему то комменты были бы очень кстати.

Я с вами согласен, разброс большой, да. Думаю мы пришли к общему мнению.
+1
Хоть один коммент видите? Плохо, что их нет.
Честно говоря, я затрудняюсь придумать хорошие комментарии к этому сниппету. Если писать «последовательность действий», то комментарии просто будут повторять то, что уже написано на ЯП. А что там написать, следуя совету «пишите не „как“, а „зачем“ — я затрудняюсь придумать.
Пример неплохой. Снипет плохой. Непонятно, что там происходит для новичка, а ему то комменты были бы очень кстати.
Сниппет как раз вполне нормальный. Просто не надо путать его с примером. Сниппет не для новичка, сниппет для того, чтобы скопипастить его в новый проект и подправить при необходимости.
+1
Сниппет не для новичка
Ну тогда я умываю руки.
0
Не согласен. Мне вот желательно иметь заведомо рабочий код, чтобы знать если что и не работает, то не из-за кривой инициализации. От этого можно дальше развиваться. А профи могут конфигурировать как хотят, этот пост не для них.
0
В какой среде работаете? В IAR? Даже если нет — можно посмотреть состояние регистров настройки периферии… Если вы не профи — это вам не поможет.
0
Ах да, если уж пишите код, пишите номер ноги, порт с которым работаете и корпус, в котором работаете. Завтра вам вместо TQFP-48 дадут LQFP-100 и номер ноги, что будете делать?
0
Очень рекомендую применять принцип «Делай как я», а не «Делай как я сказал». ;)
Вот это
#define PutPixel(x, y) ( screen_field[(127-(x))*8+(63-(y))/8]|=(0x01<<((63-(y))%8)) )

из Вашего кода.
Хрен разберешь что за наборчик магических циферок
А дадут Вам экранчик 96х64, «что будете делать?»
Явно напрашивается что-то типа
#define LCD_DOT_Y   64
#define LCD_DOT_X   128
#define LCD_MAX_Y   (LCD_DOT_Y-1)
#define LCD_MAX_X   (LCD_DOT_X-1)


Еще хочу заметить, что:
1. В эмбеддерстве, обычно, в части железа сами что-то берут, а не дают непонятно кто.
2. Конкретно в примере с @aliaksei нечто подобное будет загромождать ненужными сущностями простейший код.
+2
Хрен разберешь что за наборчик магических циферок
Я не стремился сделать эту часть понятной. Суть метода понятна и без слов.

В эмбеддерстве, обычно, в части железа сами что-то берут, а не дают непонятно кто.
Не понятно, что вы этим хотели сказать.
простейший код
В простейшем коде идёт работа с контроллером тактирования, с контроллером GPIO и с АЦП. Простейший такой код. Каждому новичку понятный. Новичок меняет местами две строки, ибо это не возбраняется, и всё перестаёт работать.

Моя главная мысль: зачем плодить инициализации, почему не научить правильно их создавать самому?
0
Ну выше уже коллеги пояснили, что новичкам в снипетах делать нечего, так что можно вопрос закрыть.
0
Новичок меняет местами две строки, ибо это не возбраняется, и всё перестаёт работать.
«Поменять местами две строки на императивном языке программирования» — хренасе не возбраняется!
+1
Название STM32F030F4 какбы однозначно намекает нам о количестве ног (и об объеме памяти).
0
По поводу таких снипетов имею сказать следующее. Смысла в них мало
Если бы смысла было мало, то ST не стал бы заморачиваться своими примерами SPL.

@aliaksei утаил :) самое главное — где берут такие штучки.

Скачивается SPL на конкретное семейство, далее в папочке \STM32F0xx_StdPeriph_LibV1.4.0\Projects\STM32F0xx_StdPeriph_Examples такого кода под разную периферию в разных режимах сколько хочешь. Ничего выдумывать и хранить лишнего не надо. Только рихтуй под свои конкретные нужды.

В частности в \STM32F0xx_StdPeriph_LibV1.4.0\Projects\STM32F0xx_StdPeriph_Examples\ADC
лежат директории с примерами
ADC_AnalogWatchdog
ADC_BasicExample
ADC_BatteryChargeMonitoring
ADC_DMA
ADC_LowPower

Выбирай подходящее по смыслу и — вперед.
+1
Если бы смысла было мало, то ST не стал бы заморачиваться своими примерами SPL.
ST и не заморачивался. Минимум строк, не значит понимание. А смысл копипастить, если не знаешь что это, весьма призрачный. Можете спорить…
0
Минимум строк, не значит понимание. А смысл копипастить, если не знаешь что это, весьма призрачный.
Смысла спорить на отвлеченные темы не вижу. Совсем.
Если на прочитать Reference manual хотя бы по-диагонали, то ни копипаст ни какие другие снипеты не помогут. ИМХО.
0
Кстати, если ADC на PA0
То тут ошибка
GPIO_Init(GPIOC, &GPIO_InitStructure);
0
  • avatar
  • e_mc2
  • 05 февраля 2016, 12:13
спасиб, исправил
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.