Forum: Mikrocontroller und Digitale Elektronik STM32F1: ADC Wandler verhalten sich komisch


von Christian J. (Gast)


Lesenswert?

Moin,

ich blicke nicht ganz durch, warum sich die beiden Kanäle "vertauschen", 
die ich auslese. Einmal einen LDR (Kanal 0, PA0) und einmal einen 
Widerstandsteilerfür die Batteriespannung (Kanal 8, PB0).

Die richtigen Werte kommen nur raus, wenn die eine Routine ihren Wert 
ausliest und direkt danach schonmal den anderen Kanl vorwählt und die 
Sample startet. Stellt man den Code um, dass jede Routine erst ihren 
Kanal wählt, dann startet, dann wartet sind die Ergebnisse vertauscht.

Mit den Samplezeiten habe ich gespielt, je länger man die macht desto 
ruhiger werden die Werte, je kleiner, desto mehr Rauschen ist drauf.

Ich möchte einfach nur ein Multi-Channel, Single Sampling machen. Keine 
Scans usw.

Es scheint so als würde das Anwählen des Kanals Zeit brauchen, dabei 
müsste das doch sofort passieren.

Das hier würde nicht funzen, bei Val steht dann der Wert drin, der an 
dem anderen Kanal anliegt.
1
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);     
2
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
3
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
4
uint16_t val = ADC_GetConversionValue(ADC1);


1
void Init_LDR()
2
{
3
    GPIO_InitTypeDef    GPIO_InitStructure;
4
    ADC_InitTypeDef     ADC_InitStructure;
5
6
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);                       // GPIOA Clock enable
7
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);                       // ADC Clock enable
8
9
    // ADC Clock auf unter 14 Mhz bringen
10
    RCC_ADCCLKConfig(RCC_PCLK2_Div8);
11
12
    /* ADC Pins konfigurieren A0 und B0----------------------------------------*/
13
    GPIO_InitStructure.GPIO_Pin              = LDR_Pin;                        // AN1 Pin (PA0) aktivieren
14
    GPIO_InitStructure.GPIO_Mode             = GPIO_Mode_AIN;                  // Analog Input
15
    GPIO_InitStructure.GPIO_Speed            = GPIO_Speed_50MHz;
16
    GPIO_Init(GPIOA, &GPIO_InitStructure);
17
18
    GPIO_InitStructure.GPIO_Pin              = VOLT_Pin;                     // AN1 Pin (PA0) aktivieren
19
    GPIO_InitStructure.GPIO_Mode             = GPIO_Mode_AIN;                  // Analog Input
20
    GPIO_InitStructure.GPIO_Speed            = GPIO_Speed_50MHz;
21
    GPIO_Init(GPIOB, &GPIO_InitStructure);
22
23
    /* ADC1 configuration ------------------------------------------------------*/
24
    ADC_InitStructure.ADC_Mode               = ADC_Mode_Independent;           // ADC1 werkelt allein
25
    ADC_InitStructure.ADC_ScanConvMode       = DISABLE;                        // Nur 1 Kanal, keine Scans
26
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                        // ständige Wandlungen aus
27
    ADC_InitStructure.ADC_ExternalTrigConv   = ADC_ExternalTrigConv_None;      // Start mit Software, nicht durch Hardware
28
    ADC_InitStructure.ADC_DataAlign          = ADC_DataAlign_Right;            // Bits rechts ausrichten im Half-Word
29
    ADC_InitStructure.ADC_NbrOfChannel       = 1;                              // 1 Kanal sampeln
30
    ADC_Init(ADC1, &ADC_InitStructure);
31
32
    ADC_Cmd(ADC1, ENABLE);
33
34
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_41Cycles5);     // PA0
35
    /* Enable ADC1 reset calibaration register */
36
    ADC_ResetCalibration(ADC1);
37
    /* Check the end of ADC1 reset calibration register */
38
    while(ADC_GetResetCalibrationStatus(ADC1));
39
    /* Start ADC1 calibaration */
40
    ADC_StartCalibration(ADC1);
41
    /* Check the end of ADC1 calibration */
42
    while(ADC_GetCalibrationStatus(ADC1));
43
    /* Keine Triggerung durch Events etc */
44
    ADC_ExternalTrigConvCmd(ADC1, DISABLE);
45
46
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
47
}
48
49
/* Holt einen AD Wert aus dem LDR und triggert neue Wandlung an */
50
uint16_t GetLDRValue()
51
{
52
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
53
    uint16_t val = ADC_GetConversionValue(ADC1);
54
    ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_55Cycles5);     // PB0
55
    /* Nächste Wandlung starten */
56
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
57
    return(val);
58
}
59
60
/* Liest die Batteriespannung aus */
61
uint16_t GetBattValue()
62
{
63
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
64
    uint16_t val = ADC_GetConversionValue(ADC1);
65
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);     // PB0
66
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
67
    return(val);
68
}

von Irgend W. (Firma: egal) (irgendwer)


Lesenswert?

Christian J. schrieb:
> Es scheint so als würde das Anwählen des Kanals Zeit brauchen, dabei
> müsste das doch sofort passieren.

Das umschalten erfolgt auch sofort. Das Umladen der S&H-Stufe aber 
nicht. Jenachdem wie hochohmig deine Quelle ist kann das schon etrwas 
dauern.

Kap. 2.3 und 4.4:

https://www.st.com/resource/en/application_note/cd00004444-understanding-and-minimising-adc-conversion-errors-stmicroelectronics.pdf

Noch viel mehr Infos zum ADC:

https://www.st.com/resource/en/application_note/cd00211314-how-to-get-the-best-adc-accuracy-in-stm32-microcontrollers-stmicroelectronics.pdf

von Christian J. (Gast)


Lesenswert?

Irgend W. schrieb:
> Das umschalten erfolgt auch sofort. Das Umladen der S&H-Stufe aber
> nicht. Jenachdem wie hochohmig deine Quelle ist kann das schon etrwas
> dauern

Danke! War um die Uhrzeit wohl nicht mehr drin :-) Sample & Hold.... da 
ich ohnehin nur 1x Sec messe werde ich die Messungen einfach switchen in 
der Routine, die zusammen gefasst wird zu einer. Läuft ja ohnehin ohne 
die CPU, die dann auch nicht warten muss.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.