Я пытаюсь измерить напряжение, используемое лампой, которая контролируется с помощью TRIA C с помощью STM32F100 mcu
На скриншоте с осциллографа желтый след - это сигнал, который я хотел бы измерить , Синяя кривая - это сигнал, который достигает контакта MC * AD C.
Если я отсоединяю провод и выполняю измерения непосредственно на MCU AD * Вывод 1028 *. Я вижу, что каждый раз, когда канал AD C активен, вывод MCU выдает чуть менее 2 В на выводе.
Я пытался запустить тест на плате STM32 VLDiscovery, и там происходит то же самое, когда канал AD C активен, вывод выводит напряжение на pin.
Кто-нибудь знает, что здесь происходит, и как мне измерить небольшой сигнал (~ 35 мВ) на STM32, чтобы MCU не испортил мой сигнал?
Вот соответствующий код
/*
* 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;
}
}