Вывод STM32 AD C устанавливает напряжение на выводе - PullRequest
0 голосов
/ 17 апреля 2020

Я пытаюсь измерить напряжение, используемое лампой, которая контролируется с помощью TRIA C с помощью STM32F100 mcu

На скриншоте с осциллографа желтый след - это сигнал, который я хотел бы измерить , Синяя кривая - это сигнал, который достигает контакта MC * AD C.

enter image description here

Если я отсоединяю провод и выполняю измерения непосредственно на MCU AD * Вывод 1028 *. Я вижу, что каждый раз, когда канал AD C активен, вывод MCU выдает чуть менее 2 В на выводе. enter image description here

Я пытался запустить тест на плате STM32 VLDiscovery, и там происходит то же самое, когда канал AD C активен, вывод выводит напряжение на pin.

Кто-нибудь знает, что здесь происходит, и как мне измерить небольшой сигнал (~ 35 мВ) на STM32, чтобы MCU не испортил мой сигнал?

enter image description here

Вот соответствующий код

    /*  
 *  GPIO setup
*/ 
void initializeGPIO() {

    // Enable GPIO port A, B, C and D
    RCC_APB2ENR_EnableDevice(RCC_APB2ENR_IOPAEN);   
    RCC_APB2ENR_EnableDevice(RCC_APB2ENR_IOPBEN);   
    RCC_APB2ENR_EnableDevice(RCC_APB2ENR_IOPCEN);  
    RCC_APB2ENR_EnableDevice(RCC_APB2ENR_IOPDEN);  

    // Enable alternate functions
    RCC_APB2ENR_EnableDevice(RCC_APB2ENR_AFIOEN);

    // Enable analog to digital conversion
    RCC_APB2ENR_EnableDevice(RCC_APB2ENR_ADC1EN);

…

    // TRIAC control pins
    GPIO_ConfigurePins(GPIOC, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9, GPIO_OUTPUT_PUSH_PULL, GPIO_SPEED_50_MHZ);

    // ADC --------------------------------------------------------------------
    // POWER consumption of heat lamp
    GPIO_ConfigurePins(GPIOC, GPIO_PIN_1, GPIO_ANALOG, GPIO_SPEED_NA); 
    // Mains voltage level detection
    GPIO_ConfigurePins(GPIOA, GPIO_PIN_1, GPIO_ANALOG, GPIO_SPEED_NA); 
    // Internal voltage level detection
    GPIO_ConfigurePins(GPIOA, GPIO_PIN_2, GPIO_ANALOG, GPIO_SPEED_NA); 
}

/*
*  Initialize ADC
*/
void initializeADC(ADC_TypeDef *adc) {
    // Power up ADC
    ADC_EnableAnalogToDigitalConversion(adc);
    ADC_SetSampleRate(adc, 1, ADC_SAMPLE_TIME_13_5);
    ADC_SetSampleRate(adc, 2, ADC_SAMPLE_TIME_13_5);
    ADC_EnableContinuosConversion(adc);
    ADC_EnableExternalTrigger(adc);
    ADC_SetExternalTriggerSelection(adc, ADC_SWSTART);
    ADC_SetSequence(adc, 1, 11);
    ADC_SetSequenceLength(adc, 1);
    SYS_Delay(100);
    if (ADC_Calibrate(adc)) {
        DEBUG_PUTS("ADC Calibration: SUCCESS");
    } else {
        DEBUG_PUTS("ADC Calibration: FAILURE");
    }
    // Start ADC
    ADC_EnableAnalogToDigitalConversion(adc);
}

/*
*  V_out = V_in * (R2/(R1+R2)) => V_in = V_out / (R2/(R1+R2))
*/
float calcVOutFromVoltageDivider(float V_out, float R1, float R2) {
    float V_in = V_out / (R2/(R1+R2));
    return V_in;
}

// FIXME
void ADC_GetTriacPower(ADC_TypeDef *adc) {
    float adcValue = ADC_GetAnalogValue(hADC, 100, (3.3/4095));
    if( adcValue != NULL) {
        data.measuredCurrent = adcValue; // * (0.022 / 1.41) * data.measuredMainsVoltage; 
    } else {
        data.measuredCurrent = -1;
    }
}

void ADC_GetMainsVoltage(ADC_TypeDef *adc) {
    float adcValue = ADC_GetAnalogValue(hADC, 100, (3.3/4095));
    if( adcValue != NULL) {
        data.measuredMainsVoltage = calcVOutFromVoltageDivider(adcValue, 2460, 18) / sqrt(2);
    } else {
        data.measuredMainsVoltage = -1;
    }
}

void ADC_GetInternalVoltage(ADC_TypeDef *adc) {
    float adcValue = ADC_GetAnalogValue(hADC, 100, (3.3/4095));
    if( adcValue != NULL) {
        data.measuredInternalVoltage = calcVOutFromVoltageDivider(adcValue, 30, 10);
    } else {
        data.measuredInternalVoltage = -1;
    }
}

/*
*  Handles power and voltage measurements and the TRIAC tick
*  frequency = (24MHz / 12499+1)/(1+1) = 9.6 KHz
*/
void TIM3_IRQHandler(void) {
    if ((TIM3->SR & TIM_SR_UIF) != 0) {
        if(isRunning) {
            powerAndVoltageMeasurementCounter++;

            uint8_t ticksPerACWave = 192;
            if (settings.expectedMainsFrequency == 50) {
                // 50 Hz mains power. 96 ticks at 4.8Khz
                ticksPerACWave = 192;
            } else if (settings.expectedMainsFrequency == 60) {
                // 60 Hz mains power. 80 ticks at 4.8Khz
                ticksPerACWave = 160;
            }

            uint8_t offset = 4;

            TRIAC_tick(&hTriac, ticksPerACWave/2);

            if (powerAndVoltageMeasurementCounter == (ticksPerACWave/4)+offset) {
                ADC_GetTriacPower(hADC);
                // Next ADC measurement is mains voltage
                ADC_SetSequence(hADC, 1, 1);
            } else if (powerAndVoltageMeasurementCounter == (ticksPerACWave/2)+offset) {
                ADC_GetMainsVoltage(hADC);
                // Next ADC measurement is internal voltage
                ADC_SetSequence(hADC, 1, 2);
            } else if (powerAndVoltageMeasurementCounter == ((ticksPerACWave/4)*3)+offset) {
                ADC_GetInternalVoltage(hADC);
                // Next ADC measurement is TRIAC power
                //ADC_SetSequence(hADC, 1, 0);
                ADC_SetSequence(hADC, 1, 11);
                GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET); // FIXME: DEBUG
            }
        }
        TIM3->SR &= ~TIM_SR_UIF;
    }
}





// ADC.c


bool ADC_Calibrate(ADC_TypeDef *pADC) {
    pADC->CR2 |= ADC_CR2_CAL;
    return WaitFlag((&pADC->CR2), ADC_CR2_CAL, BIT_RESET, 100);
}

/*
*  The ADC can be powered-on by setting the ADON bit in the ADC_CR2 register. When the
*  ADON bit is set for the first time, it wakes up the ADC from Power Down mode.
*  Conversion starts when ADON bit is set for a second time by software after ADC power-up
*  time (tSTAB).
*/
inline void ADC_EnableAnalogToDigitalConversion(ADC_TypeDef *pADC) {
    pADC->CR2 |= ADC_CR2_ADON; 
}

/*
*  The conversion can be stopped, and the ADC put in power down mode by resetting the
*  ADON bit. In this mode the ADC consumes almost no power (only a few µA).
*/
inline void ADC_DisableAnalogToDigitalConversion(ADC_TypeDef *pADC) {
    pADC->CR2 &= ~ADC_CR2_ADON; 
}

/*
*  Enable continuos mode
*/
inline void ADC_EnableContinuosConversion(ADC_TypeDef *pADC) {
    pADC->CR2 |= ADC_CR2_CONT;
}

/*
*  Bit 20 EXTTRIG: External trigger conversion mode for regular channels
*  This bit is set and cleared by software to enable/disable the external trigger used to start
*  conversion of a regular channel group.
*      0: Conversion on external event disabled
*      1: Conversion on external event enabled
*/
inline void ADC_EnableExternalTrigger(ADC_TypeDef *pADC) {
    pADC->CR2 |= ADC_CR2_EXTTRIG;
}

/*
*  Bits 19:17 EXTSEL[2:0]: External event select for regular group
*  These bits select the external event used to trigger the start of conversion of a regular group:
*      000: Timer 1 CC1 event
*      001: Timer 1 CC2 event
*      010: Timer 1 CC3 event
*      011: Timer 2 CC2 event
*      100: Timer 3 TRGO event
*      101: Timer 4 CC4 event
*      110: EXTI line 11
*      111: SWSTART
*/
void ADC_SetExternalTriggerSelection(ADC_TypeDef *pADC, ADC_EXTERNAL_TRIGGER_EVENT event) {
    switch(event) {
        case ADC_TIMER_1_CC1_EVENT :
            pADC->CR2 &= ~(ADC_CR2_EXTSEL_0 | ADC_CR2_EXTSEL_1 | ADC_CR2_EXTSEL_2);
            break;
        case ADC_TIMER_1_CC2_EVENT :
            pADC->CR2 |= ADC_CR2_EXTSEL_0;
            break;
        case ADC_TIMER_1_CC3_EVENT :
            pADC->CR2 |= ADC_CR2_EXTSEL_1;
            break;
        case ADC_TIMER_2_CC2_EVENT :
            pADC->CR2 |= ADC_CR2_EXTSEL_1 | ADC_CR2_EXTSEL_0;
            break;
        case ADC_TIMER_3_TRGO_EVENT :
            pADC->CR2 |= ADC_CR2_EXTSEL_2;
            break;
        case ADC_TIMER_4_CC4_EVENT :
            pADC->CR2 |= ADC_CR2_EXTSEL_2 | ADC_CR2_EXTSEL_0;
            break;
        case ADC_EXTI_LINE_11 :
            pADC->CR2 |= ADC_CR2_EXTSEL_2 | ADC_CR2_EXTSEL_1;
            break;
       case ADC_SWSTART :
            pADC->CR2 |= ADC_CR2_EXTSEL_2 | ADC_CR2_EXTSEL_1 | ADC_CR2_EXTSEL_0;
            break;
    }
}

inline void ADC_DisableScanMode(ADC_TypeDef *pADC) {
    pADC->CR1 &= ~ADC_CR1_SCAN;
}

inline void ADC_EnableScanMode(ADC_TypeDef *pADC) {
    pADC->CR1 |= ADC_CR1_SCAN;
}

/*
*   Enable analog watchdog interrupt 
 */
inline void ADC_EnableAnalogWatchdogInterupt(ADC_TypeDef *pADC) {
    pADC->CR1 |= ADC_CR1_AWDIE;
}

/*
*   Enable interrupt at End Of Conversion
*/
inline void ADC_EnableInteruptAtEndOfConversion(ADC_TypeDef *pADC) {
    pADC->CR1 |= ADC_CR1_EOCIE; 
}

/*
*  Sets the numer of conversions in the regular channel conversion sequence
*  4 bit register field 
 *  uint8_t length : sequence number range 0 - 15 
 */
void ADC_SetSequenceLength(ADC_TypeDef *pADC, uint8_t sequenceLength) {
    uint8_t length = sequenceLength - 1;

    assert(length >= 0 && length <= 15);
    pADC->SQR1 &= ~(0xF << 20);
    pADC->SQR1 |= length << 20;
}

/* 
 *  Sets the sample time specified in the enum ADC_SAMPLE_TIMES
*  uint8_t channel : channel numer. Range 0 - 17
*/
void ADC_SetSampleRate(ADC_TypeDef* pADC, uint8_t channel, ADC_SAMPLE_TIMES sample) {
    uint32_t retVal = 0;
    assert(channel >= 0 && channel <= 17);

    uint32_t mask = 0b111;
    uint8_t shift;

    if (channel < 10) {
        shift = channel*3;
        mask = mask << shift;
        retVal = sample << shift;
        pADC->SMPR2 &= ~mask;
        pADC->SMPR2 |= retVal;
    } else {
        shift = (channel-10)*3;
        mask = mask << shift;
        retVal = sample << shift;
        pADC->SMPR1 &= ~mask;
        pADC->SMPR1 |= retVal;
    }
}

/* 
 *  Sets the channel in the sequence
*  uint8_t seq : sequence number range 1 - 16 
 *  uint8_t channel : channel numer. Range 0 - 17
*/
void ADC_SetSequence(ADC_TypeDef* pADC, uint8_t seq, uint8_t channel) {
    uint32_t retVal = 0;
    assert(channel >= 0 && channel <= 17);
    assert(seq >= 1 && seq <= 16);

    if (seq < 7) {    
        pADC->SQR3 &= ~(0x1F << (seq-1)*5);
        pADC->SQR3 |= channel << (seq-1)*5;
    } else if ( seq < 13) {
        pADC->SQR2 &= ~(0x1F << (seq-7)*5);
        pADC->SQR2 |= channel << (seq-7)*5;
    } else {
        pADC->SQR1 &= ~(0x1F << (seq-13)*5);
        pADC->SQR1 |= channel << (seq-13)*5;
    }
}

float ADC_GetAnalogValue(ADC_TypeDef* pADC, uint32_t timeout, float multiplier ) {
    pADC->CR2 |= ADC_CR2_SWSTART;
    // Wait until EOC flag is reset
    if (WaitFlag((&pADC->SR), ADC_SR_EOC, BIT_SET, timeout)) {
        uint32_t adcVal = pADC->DR;
        float actual = adcVal*multiplier;
        return actual;
    } else {
        return NULL;
    }
}
...