Смешение выхода операционного усилителя для блюпила

Потребовалось бюпилом измерить постоянное напряжение ±5 вольт. Спаял схему на одном операционнике напряжение сместилось, но не так как задумывалось. Поиск в сети дал интересный документ от Ti. https://images.shoutwiki.com/mindworks/8/81/SLOA097.pdf
Полный расчёт резисторов для схемы смещения уровня и коэффициента усиления на одном операционнике. Результат порадовал - при входном напряжении ±5 вольт выходное 0-3.3 вольт. Ну и лайф хак - операционнику нужно ±питание. На блюпиле запитал от +5, напряжение смещения от 3.3, а -5 от преобразователя +5 > -5 такого https://aliexpress.ru/item/1005004109272585.html
В блюпил загрузил программу. Усредняет по 50 токам за 20мс двумя чередующимися буферами и выдаёт в компорт. При подключении к входу батарейки показания скачут на единичку в последнем знаке.

Спойлер
#include <Arduino.h>
#include <HardwareTimer.h>

#define ADC_PIN PA1
#define LED_PIN PC13
#define SAMPLE_RATE 50000
#define BUFFER_SIZE 2000

// Буфер для DMA должен быть выровнен
__attribute__((aligned(4))) volatile uint16_t adcBuffer[BUFFER_SIZE];
volatile bool dataReady = false;
volatile uint16_t* currentHalf = nullptr;

void processData(volatile uint16_t* data, uint16_t length) {
  uint32_t sum = 0;
  for(uint16_t i = 0; i < length; i++) {
    sum += data[i];
  }
  Serial.printf("%.3f %d\n", millis()/1000.0f, sum/length);
}

extern "C" {
void DMA1_Channel1_IRQHandler(void) {
  if (DMA1->ISR & DMA_ISR_HTIF1) {
    DMA1->IFCR = DMA_IFCR_CHTIF1;
    currentHalf = adcBuffer;
    dataReady = true;
  }
  else if (DMA1->ISR & DMA_ISR_TCIF1) {
    DMA1->IFCR = DMA_IFCR_CTCIF1;
    currentHalf = adcBuffer + BUFFER_SIZE/2;
    dataReady = true;
  }
}
}

void setupADC_DMA() {
  // 1. Включение тактирования
  RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
  RCC->AHBENR |= RCC_AHBENR_DMA1EN;

  // 2. Калибровка АЦП
  ADC1->CR2 |= ADC_CR2_ADON;
  delay(1);
  ADC1->CR2 |= ADC_CR2_CAL;
  while(ADC1->CR2 & ADC_CR2_CAL);

  // 3. Настройка АЦП
  ADC1->SQR1 = 0;
  ADC1->SQR3 = 1;
  ADC1->SMPR2 = 7 << 3;
  ADC1->CR2 |= ADC_CR2_CONT | ADC_CR2_DMA;

  // 4. Настройка DMA
  DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
  DMA1_Channel1->CMAR = (uint32_t)adcBuffer;
  DMA1_Channel1->CNDTR = BUFFER_SIZE;
  DMA1_Channel1->CCR = DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 |
                      DMA_CCR_CIRC | DMA_CCR_HTIE | DMA_CCR_TCIE | DMA_CCR_EN;

  // 5. Настройка прерываний
  NVIC_EnableIRQ(DMA1_Channel1_IRQn);
  NVIC_SetPriority(DMA1_Channel1_IRQn, 0);

  // 6. Запуск АЦП
  ADC1->CR2 |= ADC_CR2_ADON;
  delay(1);
  ADC1->CR2 |= ADC_CR2_SWSTART;
}

void setup() {
  pinMode(LED_PIN, OUTPUT);
  pinMode(ADC_PIN, INPUT_ANALOG);
  
  Serial.begin(115200);
  while(!Serial);

  setupADC_DMA();
  Serial.println("System initialized");
}

void loop() {
  static uint32_t lastBlinkTime = 0;
  
  // Мигание светодиодом 1 Гц
  if(millis() - lastBlinkTime >= 1000) {
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
    lastBlinkTime = millis();
  }

  // Обработка данных
  if(dataReady && currentHalf) {
    processData(currentHalf, BUFFER_SIZE/2);
    dataReady = false;
  }
}  
2 лайка

Вот спасибо! Такого раньше не видел – очень понравился!

В отзывах пишут что это просто повышайка. Так это или речь про другой модуль?

А в 1 раз повысить - не «повышайка» разве?)

5 умножить на 1 равно 5 → не повышайка))
Ник пишет, что из положительного напряжения делает отрицательное. Вот я про што

В описании -Модуль MC34063A обратного напряжения Ah robot 3,6В-36В при питании 5В даёт точно от -3. Крутил до -6 мне больше не надо было, но запас крутилки был.

1 лайк

Не в 1 а в -1. Но можно и до -7 докрутить. А можно и до -0.6 раз. Отрицательная повышайка короче.

1 лайк

Повышайка Мёбиуса! :smile: