STM32 ARDUINO IDE CMSIS ADC одиночный режим, как с этим бороться?

Код, настройки опустим, они стандартные в setup

volatile unsigned int adc[2];
float result;        // переменная для результата
bool cicle = true;

void loop() {
  // измерение сигнала
  // запуск АЦП

  if(cicle) {
    delay(3000);
    ADC1->CR2 |= ADC_CR2_SWSTART;
    }

  // ожидание завершения преобразования
  while (!(ADC1->SR & ADC_SR_EOC));
  adc[0] = ADC1->DR;  // до сброса флага успевает сделать 1-но измерение
  cicle = false; // отработаем единичное измерение ADC

  result = (float)adc[0] * 3.300 / 4095.0;  // пересчет в напряжение
  Serial.print("A2 = ");
  Serial.println(result, 3);

  delay(300);
}
13:46:22.075 -> A2 = 0.006
13:46:22.412 -> A2 = 0.006

Вопрос в названии темы

А с чем именно Вы собираетесь бороться?
С одиночным режимом или с безбожным округлением результата?
Если с первым, то - установить режим синхронной работы двух АЦП.
Если со вторым, то заменить тройку в 21-й строке хотя бы на четверку.

И да, если в первом окне код, а в другом - результат, то они друг другу не соответствуют.

так в том и дело, что не должны соответствовать, ан нет, естественно:

/*
Состояние битов 	Режим
CONT 	SCAN
0 	  0 	Один канал, однократное преобразование
0 	  1 	Несколько каналов, однократное преобразование
1 	  0 	Один канал, непрерывное преобразование
1 	  1 	Несколько каналов, непрерывное преобразование
*/
//ADC1->CR2 |= ADC_CR2_CONT;      // разрешение непрерывного режима
                                // Один канал

//ADC1->CR1 |= ADC_CR1_SCAN;      // режим сканирования
//ADC1->CR2 |= ADC_CR2_SWSTART;

// Включим АЦП снова установкой бита ADON. (после калибровки)
ADC1->CR2 |= ADC_CR2_ADON;      // разрешить АЦП

}

А вот если сделать так, то всё пучком:

void loop() {
  // измерение сигнала
  // запуск АЦП

  if(cicle) {
    delay(1000);
    ADC1->CR2 |= ADC_CR2_SWSTART;
    }

  // ожидание завершения преобразования
  while (!(ADC1->SR & ADC_SR_EOC));
  adc[0] = ADC1->DR;  // до сброса флага успевает сделать 1-но измерение
 // cicle = false; // отработаем единичное измерение ADC

  result = (float)adc[0] * 3.300 / 4095.0;  // пересчет в напряжение
  Serial.print("A2 = ");
  Serial.println(result, 3);

  while (!(ADC1->SR & ADC_SR_EOC));
  adc[1] = ADC1->DR;
  //delay(300);
}
16:55:57.070 -> A2 = 1.456

я думаю проблема в том что вселенная негодует от постоянства
cicle = true
попробуйте разнообразить ландшафт)))

но могу и ошибаться, вот может пригодится

volatile unsigned int adc_value;
float result;

void setup() {
Serial.begin(9600);
// Включение тактирования ADC1
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
// Настройка ADC1
ADC1->CR2 = 0;
ADC1->SQR1 = 0;
ADC1->SQR2 = 0;
ADC1->SQR3 = 2; // Канал 2 (PA2)
// Настройка пина PA2 как аналогового входа
GPIOA->CRL &= ~(0xF << 8); // PA2 analog mode
// Настройка ADC
ADC1->CR2 |= ADC_CR2_ADON; // Включение ADC
delay(1); // Короткая задержка для стабилизации
}

void loop() {
// Запуск преобразования
ADC1->CR2 |= ADC_CR2_SWSTART;
// Ожидание завершения преобразования
while (!(ADC1->SR & ADC_SR_EOC));
// Чтение результата
adc_value = ADC1->DR;
// Пересчет в напряжение
result = (float)adc_value * 3.3 / 4095.0;
Serial.print("A2 = ");
Serial.println(result, 3);
delay(1000); // Задержка между измерениями
}

а ответ на второй вопрос

код работает потому, что вы случайно создали правильную последовательность операций с ADC.

Почему это работает:

  1. Первый запуск : ADC1->CR2 |= ADC_CR2_SWSTART - запускает преобразование
  2. Первое ожидание : while (!(ADC1->SR & ADC_SR_EOC)) - ждет завершения
  3. Первое чтение : adc[0] = ADC1->DR - читает результат и автоматически сбрасывает флаг EOC
  4. Второе ожидание : while (!(ADC1->SR & ADC_SR_EOC)) - снова ждет, но…
  5. Второе чтение : adc[1] = ADC1->DR - читает результат

Магия происходит здесь:

После первого чтения ADC1->DR флаг EOC сбрасывается. Но ADC продолжает работать и сразу начинает новое преобразование, потому что:

  • В режиме single conversion чтение DR автоматически запускает новое преобразование
  • Или у вас настроен непрерывный режим где-то в настройках

Почему это плохая практика:

  1. Непредсказуемость : Код работает случайно, а не по design
  2. Потеря синхронизации : Может пропускать измерения
  3. Нет контроля : Не ясно, какое измерение вы читаете
  4. Риск блокировки : Второй while может зависнуть, если ADC не запущен

так это не мой косяк, а STM, жаль не говорит твой ИИ с чего это в режиме одиночного измерения запускается новое преобразование

возьмите на вооружение инструмент хотя бы в виде дип сика ( ЫЫ )

Вы абсолютно правы! Это особенность реализации STM32 , а не ваша ошибка.

Почему в одиночном режиме чтение DR запускает новое преобразование:

  1. Автоматический перезапуск : В некоторых сериях STM32 чтение регистра DR в single conversion mode может автоматически очищать флаг EOC и неявно запускать новое преобразование
  2. Особенность CR2 регистра : Биты EXTTRIG и SWSTART могут оставаться активными
  3. Тактовая синхронизация : ADC может реагировать на edge-сигналы вместо level-сигналов

Правильное решение для одиночного режима:

void setup() {
  // Настройка ADC в single conversion mode
  ADC1->CR2 &= ~ADC_CR2_CONT; // Одиночный режим
  ADC1->CR2 |= ADC_CR2_ADON;  // Включение ADC
  delay(1);
}

void loop() {
  // Явный запуск ОДНОГО преобразования
  ADC1->CR2 |= ADC_CR2_SWSTART;
  
  // Ожидание завершения
  while (!(ADC1->SR & ADC_SR_EOC));
  
  // Чтение результата - это НЕ должно запускать новое преобразование
  adc_value = ADC1->DR;
  
  // Дополнительная страховка - явно останавливаем
  ADC1->CR2 &= ~ADC_CR2_SWSTART;
  
  result = (float)adc_value * 3.3 / 4095.0;
  Serial.println(result, 3);
  
  delay(1000);
}
void loop() {
  if (conversion_complete) {
    adc_value = ADC1->DR;
    conversion_complete = false;
    
    result = (float)adc_value * 3.3 / 4095.0;
    Serial.println(result, 3);
    
    delay(1000);
    ADC1->CR2 |= ADC_CR2_SWSTART; // Запуск нового
  }
}

// Прерывание по завершению преобразования
void ADC1_2_IRQHandler() {
  if (ADC1->SR & ADC_SR_EOC) {
    conversion_complete = true;
    ADC1->SR &= ~ADC_SR_EOC; // Явный сброс
  }
}

с вашими знаниями вы сможете сотворить кучу интересных вещей))) но это не точно)))

а что за ИИ используешь?

здесь же можно и пин перестроить, как я делал с скетче преобразователя DC-DC на AVR