ua6em
14.Сентябрь.2025 10:54:04
1
Код, настройки опустим, они стандартные в 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-й строке хотя бы на четверку.
И да, если в первом окне код, а в другом - результат, то они друг другу не соответствуют.
ua6em
14.Сентябрь.2025 13:09:56
3
так в том и дело, что не должны соответствовать, ан нет, естественно:
/*
Состояние битов Режим
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; // разрешить АЦП
}
ua6em
14.Сентябрь.2025 13:57:44
4
А вот если сделать так, то всё пучком:
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
BABOS
14.Сентябрь.2025 16:39:04
5
я думаю проблема в том что вселенная негодует от постоянства
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.
Почему это работает:
Первый запуск : ADC1->CR2 |= ADC_CR2_SWSTART
- запускает преобразование
Первое ожидание : while (!(ADC1->SR & ADC_SR_EOC))
- ждет завершения
Первое чтение : adc[0] = ADC1->DR
- читает результат и автоматически сбрасывает флаг EOC
Второе ожидание : while (!(ADC1->SR & ADC_SR_EOC))
- снова ждет, но…
Второе чтение : adc[1] = ADC1->DR
- читает результат
Магия происходит здесь:
После первого чтения ADC1->DR
флаг EOC
сбрасывается. Но ADC продолжает работать и сразу начинает новое преобразование, потому что:
В режиме single conversion чтение DR
автоматически запускает новое преобразование
Или у вас настроен непрерывный режим где-то в настройках
Почему это плохая практика:
Непредсказуемость : Код работает случайно, а не по design
Потеря синхронизации : Может пропускать измерения
Нет контроля : Не ясно, какое измерение вы читаете
Риск блокировки : Второй while
может зависнуть, если ADC не запущен
ua6em
14.Сентябрь.2025 17:37:52
6
так это не мой косяк, а STM, жаль не говорит твой ИИ с чего это в режиме одиночного измерения запускается новое преобразование
BABOS
14.Сентябрь.2025 17:46:04
7
возьмите на вооружение инструмент хотя бы в виде дип сика ( ЫЫ )
Вы абсолютно правы! Это особенность реализации STM32 , а не ваша ошибка.
Почему в одиночном режиме чтение DR запускает новое преобразование:
Автоматический перезапуск : В некоторых сериях STM32 чтение регистра DR
в single conversion mode может автоматически очищать флаг EOC и неявно запускать новое преобразование
Особенность CR2 регистра : Биты EXTTRIG
и SWSTART
могут оставаться активными
Тактовая синхронизация : 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; // Явный сброс
}
}
с вашими знаниями вы сможете сотворить кучу интересных вещей))) но это не точно)))
ua6em
14.Сентябрь.2025 18:00:35
9
здесь же можно и пин перестроить, как я делал с скетче преобразователя DC-DC на AVR