Нужна консультация по чтению значения аналогового входа

Подаю напряжение 0 вольт на аналоговый вход PA0. Значение ацп =0. Подаю напряжение 3.3 вольта. Значение ацп меняется от 4088 до 4091. Подаю половину напряжения питания. Значение ацп меняется от 2100 до 2102. Пока все нормально. Вывожу информацию на ЖК экран каждые 0.1 секунду. Подаю напряжение снова 0 вольт. Значение ацп становится равным случайному значению (например 95) и отображается неизменным около 1 минуты. При этом на экран выводится значение миллисекунд и это значение меняется. Потом случайным образом меняется и снова постоянное значение около 1 минуты. Но если подать на вход напряжение 3.3 вольта то начинает отображать правильно в диапазоне 4088 до 4091. В чем может быть проблема.

Если подаещь на вход напряжение через делитель на основе переменного резистора, то поменяй резистор.

аналоговый вход подключаю проводом напрямую либо к земле либо к питанию 3.3 вольта. Переменного резистора в схеме нет. Если бы было чтение то на экране бы отображалось значение в каком либо диапазоне. Например от 95 до 96. А тут число не меняется. Например 1 минуту отображается 95 потом 50 секунд 507 потом снова 95.

  1. А не забыл ли уважаемый сэр указать, на каком камне он все это пробует?
  2. Если это ESP, то проблемы его АЦП на краях широко известны
1 лайк

Камень stm32g431. Для проверки использую такой код.

//---Ver------------------------------------------------------------//
#include <LiquidCrystal.h>                                          //
LiquidCrystal lcd (PB11,PB10,PB2,PB1,PB0,PC4,PA7,PA6,PA3,PA2);      //
//------------------------------------------------------------------//
uint16_t adc_value = 0;                                             //
ADC_HandleTypeDef AdcHandle;                                        //
//------------------------------------------------------------------//
void setup()                                                        //
{                                                                   //
  //---Настройка тактирования АЦП через HAL-------------------------//
  __HAL_RCC_ADC12_CLK_ENABLE();                                     //
  __HAL_RCC_GPIOA_CLK_ENABLE();                                     //
  //---Настройка PA0 как аналоговый вход----------------------------//
  GPIO_InitTypeDef GPIO_InitStruct = {0};                           // 
  GPIO_InitStruct.Pin = GPIO_PIN_0;                                 //
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;                          //
  GPIO_InitStruct.Pull = GPIO_NOPULL;                               //
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);                           //
  //---Полная инициализация ADC-------------------------------------//
  AdcHandle.Instance = ADC1;                                        //
  AdcHandle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;         //
  AdcHandle.Init.Resolution = ADC_RESOLUTION_12B;                   //
  AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;                   //
  AdcHandle.Init.ScanConvMode = ADC_SCAN_DISABLE;                   //
  AdcHandle.Init.EOCSelection = ADC_EOC_SINGLE_CONV;                //
  AdcHandle.Init.LowPowerAutoWait = DISABLE;                        //
  AdcHandle.Init.ContinuousConvMode = ENABLE;                       //
  AdcHandle.Init.NbrOfConversion = 1;                               //
  AdcHandle.Init.DiscontinuousConvMode = DISABLE;                   //
  AdcHandle.Init.NbrOfDiscConversion = 0;                           //
  AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START;             //
  AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;//
  AdcHandle.Init.DMAContinuousRequests = DISABLE;                   //
  HAL_ADC_Init(&AdcHandle);                                         //
  //---Калибровка АЦП-----------------------------------------------//
  HAL_ADCEx_Calibration_Start(&AdcHandle, ADC_SINGLE_ENDED);        //
  HAL_Delay(10);                                                    //
  //---Настройка канала ADC-----------------------------------------//
  ADC_ChannelConfTypeDef sConfig = {0};                             //
  sConfig.Channel = ADC_CHANNEL_1;                                  //
  sConfig.Rank = ADC_REGULAR_RANK_1;                                //
  sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;                //
  sConfig.SingleDiff = ADC_SINGLE_ENDED;                            // 
  sConfig.OffsetNumber = ADC_OFFSET_NONE;                           // 
  sConfig.Offset = 0;                                               //
  HAL_ADC_ConfigChannel(&AdcHandle, &sConfig);                      //
  //---ЗАПУСК АЦП в непрерывном режиме------------------------------//
  HAL_ADC_Start(&AdcHandle);                                        //
  //---Инициализация LCD экрана-------------------------------------//
  lcd.begin(20, 4);                                                 //
  //----------------------------------------------------------------//
}                                                                   //
//------------------------------------------------------------------//
void loop()                                                         //
{                                                                   //
  __HAL_ADC_CLEAR_FLAG(&AdcHandle, ADC_FLAG_EOC | ADC_FLAG_EOS);    //
  __HAL_ADC_CLEAR_FLAG(&AdcHandle, ADC_FLAG_OVR);                   //
  if (HAL_ADC_PollForConversion(&AdcHandle, 100) == HAL_OK) {       // 
    adc_value = HAL_ADC_GetValue(&AdcHandle);}                      //
  lcd.setCursor(0, 0); lcd.print("MILLIS = "); lcd.print(millis()); //
  lcd.setCursor(0, 1); lcd.print("ADC PA0 = "); lcd.print(adc_value);//
  delay(100);                                                       //
}                                                                   //
//------------------------------------------------------------------//

А почему не HAL_ADC_Start(&AdcHandle); ??
Зачем «магия с регистрами»?

Вот, доходчиво:

https://narodstream.ru/stm-urok-16-hal-adc-regular-channel/

Сначала пробовал стандартный способ чтения аналогового пина средствами Arduino ide. Но у меня почему то были большие помехи. Подаю на вход половину напряжения питания через 2 резистора по 1 ком и значение ацп меняются вместо 1 - 2 младших разряда на целых несколько десятков разрядов. Думал что слишком большая частота преобразования ацп и поэтому решил добавить делитель через регистры. Проблема с помехами убралась но появилась новая проблема.

Ссылку сейчас посмотрю. Может получится убрать ошибку. Просто у меня ацп тактируется от шины ABP1 которая работает на частоте 160 мгц. А этого для ацп слишком много. Я думал что помехи из за высокой частоты тактирования ацп.

Посмотрел ссылку. Поскольку там указана максимальная частота работы 84 мгц то это похоже на плату stm32f401. ацп на 401 чипе у меня прекрасно работает. К чипу 401 притензий нет.

Может контакт просто хреновый? Пропаивать контакты пробовал?

Если бы был плохой контакт то я бы увидел сигнал помехи, которая меняется. А у меня помеха считалась а потом 1 минуту отображается не меняя значение. Это не похоже на плохой контакт.

Попробуй для начала увеличить Делей до 500мс. А потом вместо 56 и 57 строки это:


HAL_ADC_Start(&AdcHandle);

И если помогло второе - снижай Делей постепенно…

1 лайк

Похоже проблема решилась. Код не менял. Решил плавно уменьшать напряжение на входе ацп. Сделал равным 2 единицам. Все отображается. (то есть значение меняется между 2 и 3 каждую 0.1 секунду) Сделал 0 опять не отображается. Сделал несколько долей миливольта. и у меня стало отображаться между 0 и 1. Только обратил внимание что меняется число в левом разряде. А 3 цифры справа остались мусором от предыдущего измерения. Я их не стер и остаток старого значения я принял за новое число.

Сделал очистку экрана и все заработало.

lcd.clear();
  lcd.setCursor(0, 0); lcd.print("MILLIS = "); lcd.print(millis()); //
  lcd.setCursor(0, 1); lcd.print("ADC PA0 = "); lcd.print(adc_value);//

1 лайк

А развели то аж как бермудский треугольник

Хех, у меня тоже подобное было, не помню уже что выводил. Просто в конце вывода добавил пробелы и всё ОК стало.

2 лайка

надо видимо заглянуть в даташит и посмотреть какая максимальная частота тактирования допустима для ADC и привести в соответствие, открою страшную тайну даже для F103 (14 мегагерц) делители не позволяют установить эту частоту точно если APB2 72 мегагерца и надо в конфигураторе настроить на 56, тогда при делителе на 4 получим цацу
И таки да она для G431 всего 3.6 мегагерца (((

Витя, переключи галетник на катушке обратно, разговор совсем не о шинах, частотах и делителях.

1 лайк

был не прав, 3.6 это мегасэмплы, частота шины ADC 60 мегагерц

Зачем вообще метод clear() нужен… мы же не мелом на школьной доске пишем…

byte posCursor = 0;
lcd.setCursor(0, 0);
 posCursor =  lcd.print("MILLIS = "); 
 posCursor += lcd.print(millis()); 
while( posCursor < 20)  posCursor += lcd.print(' '); //пишем пробелы до конца строки