Forum: Mikrocontroller und Digitale Elektronik ST Visual Develop STM8 compiler error - was mach ich falsch?


von Max M. (maxmicr)


Lesenswert?

Hallo,

ich versuche gerade den ADC eines STM8 zu aktivieren, aber der Compiler 
liefert bei diesem Code den Fehler
1
13:bad struct/union operand
2
13:ADC_CSR undefined
1
#include <stm8s.h>
2
#include <stm8s_adc1.h>
3
#include <stm8s_adc2.h>
4
5
void delay_ms(uint16_t ms);
6
void initADC();
7
8
void initADC(){
9
  ADC_CR1->ADON=1; //turn ADC on
10
  ADC_CSR->CH |= (1<<3); //Pin D3 (AIN4) as Analog Channel
11
  ADC_CR1->SPSEL |= (1<<4); //Set Prescaler to f/4 (4MHz)
12
}

Wo genau liegt mein Fehler?

von hp-freund (Gast)


Lesenswert?

Habe keine Ahnung vom STM8, aber hast Du einen Blick in die stm8s_adc1.h 
und stm8s_adc2.h geworfen.

von google (Gast)


Lesenswert?

> ADC_CSR->CH

muss das nicht ADC_CR1->CH heißen?

von Max M. (maxmicr)


Lesenswert?

Danke für eure Antworten, aber anscheinend ist die Syntax etwas anders 
(danke an hp-freund für den Hinweis mal in den Header-Dateien 
nachzuschauen). So compiliert es zumindest:
1
void initADC(){
2
  ADC1->CR1 |= ADC1_CR1_ADON; //turn ADC on
3
  ADC1->CSR |= (1<<3); //Pin D3 (AIN4) as Analog Channel
4
  ADC1->CR1 |= (1<<2); //Set Prescaler to f/4 of master (4MHz)
5
}

von google (Gast)


Lesenswert?

google schrieb:
> muss das nicht ADC_CR1->CH heißen?

Nein, Deine Bezeichnung war richtig. Aber CH[0..3] sind vier Bits, in C 
ein Bitfeld. Guck in die zugehörige .h Datei, wie vorher schon 
geschrieben. Dort steht, wie Du es in Assembler ansprechen kannst. (Von 
Assembler hab ich keine Ahnung)

von Max M. (maxmicr)


Lesenswert?

google schrieb:
> Aber CH[0..3] sind vier Bits, in C
> ein Bitfeld.

Soweit ich die Beschreibung des Registers richtig verstehe:

Bits 3:0 CH[3:0]: Channel selection bits
These bits are set and cleared by software. They select the input 
channel to be converted.
0000: Channel AIN0
0001: Channel AIN1
....
1111: Channel AIN15


müsste ich für "AIN4" 0100 schreiben, dann müsste (1<<3) doch stimmen, 
oder?

von google (Gast)


Lesenswert?

Max M. schrieb:
> müsste ich für "AIN4" 0100 schreiben, dann müsste (1<<3) doch stimmen,
> oder?

Ja.


Er macht das zwar in C, aber ist ja nur Bitgeschubse:

http://blog.mark-stevens.co.uk/2012/09/single-scan-adc-on-the-stm8s/

Vielleicht hilft Dir das etwas, er erklärt alles immer recht gut.

von Max M. (maxmicr)


Lesenswert?

google schrieb:
> Vielleicht hilft Dir das etwas, er erklärt alles immer recht gut.

Danke für den Link, aber da ist die Syntax auch anders als in STVD 
(warum eigentlich keine einheitliche Syntax?).

Edit: Noch eine Frage, warum bekomme ich hier den Fehler "missing 
prototype" (bei "initADC();")? Ich hab doch mit
1
uint16_t readAnalogValue();

die Methode ganz brav "vorinitialisiert"?
1
#include <stm8s.h>
2
3
void initADC();
4
void initADC(){
5
  ADC1->CR1 |= ADC1_CR1_ADON; //turn ADC on
6
  ADC1->CSR |= (1<<3); //Pin D3 (AIN4) as Analog Channel
7
  ADC1->CR1 |= (1<<2); //Set Prescaler to f/4 of master (4MHz)
8
}
9
10
uint16_t readAnalogValue();
11
uint16_t readAnalogValue(){
12
  if((ADC1->CSR & (1<<7)) == 1){ //check End of Conversion Bit
13
    uint8_t hRegister = ADC1->DRH;
14
    uint8_t lRegister = ADC1->DRL;
15
    uint16_t completeValue = hRegister << 8 | lRegister;
16
    return completeValue;
17
  }
18
}
19
20
void delay_ms(uint16_t ms);
21
void delay_ms(uint16_t ms){
22
  while(ms--){
23
    uint16_t i;
24
    for(i = 0; i < ms; i++){
25
      nop();
26
    }
27
  }
28
}
29
30
void main()
31
{
32
  initADC();
33
}

von google (Gast)


Lesenswert?

google schrieb:
> Dort steht, wie Du es in Assembler ansprechen kannst. (Von
> Assembler hab ich keine Ahnung)

Ich hab im Titel "ST Visual Develop" gelesen und das unmittelbar mit 
Assembler assoziiert, sorry. Du bist ja in C unterwegs. Welchen Compiler 
nutzt Du?



Laß mal die "Prototypen" vorläufig weg:

> void initADC();
> uint16_t readAnalogValue();
> void delay_ms(uint16_t ms);


Wie es richtig geht und warum man die braucht, steht hier:
http://www.c-howto.de/tutorial-funktionen-funktions-prototypen.html

von Max M. (maxmicr)


Lesenswert?

google schrieb:
> Du bist ja in C unterwegs. Welchen Compiler
> nutzt Du?

Jup, ich nutze den Cosmic C compiler. Den gibts ja seit März '16 
kostenlos ohne Codebeschränkung!

google schrieb:
> Laß mal die "Prototypen" vorläufig weg:

Anscheinend ist da mein Compiler (?) ziemlich pingelig, so 
funktionierts:
1
uint16_t readAnalogValue(void);
2
uint16_t readAnalogValue(){
3
  if((ADC1->CSR & (1<<7)) == 1){ //check End of Conversion Bit
4
    uint8_t hRegister = ADC1->DRH;
5
    uint8_t lRegister = ADC1->DRL;
6
    
7
    uint16_t completeValue = hRegister << 8 | lRegister;
8
    return completeValue;
9
  }
10
}

Anscheinend fehlt noch irgendwas bei der Initialisierung da:
1
if((ADC1->CSR & (1<<7)) == 1)

beim Debuggen nicht "true" ist...

von Max M. (maxmicr)


Lesenswert?

Hm, bin leider immer noch nicht weiter gekommen, das hier ist mein Code:
1
/* MAIN.C file */
2
#include <stm8s.h>
3
4
void initADC(void);
5
void initADC(){
6
  ADC1->CR1 |= (1<<0); //turn ADC on
7
  ADC1->CSR |= (1<<2); //Pin D3 (AIN4) as Analog Channel
8
  ADC1->CR1 |= (1<<5); //Set Prescaler to f/4 of master (4MHz)
9
}
10
11
uint16_t readAnalogValue(void);
12
uint16_t readAnalogValue(){
13
  ADC1->CSR &= ~(1<<7);
14
  ADC1->CR1 |= (1<<0); //Start conversion
15
  if((ADC1->CSR & (1<<7)) == 1){ //check End of Conversion Bit
16
    uint8_t hRegister = ADC1->DRH;
17
    uint8_t lRegister = ADC1->DRL;
18
    
19
    uint16_t completeValue = hRegister << 8 | lRegister;
20
    return completeValue;
21
  }
22
}
23
24
void delay_ms(uint16_t ms);
25
void delay_ms(uint16_t ms){
26
  while(ms--){
27
    uint16_t i;
28
    for(i = 0; i < ms; i++){
29
      nop();
30
    }
31
  }
32
}
33
34
void main()
35
{
36
  GPIOC->DDR|=(1<<7); //PD3 as Output
37
  GPIOC->CR1|=(1<<7); //PD3 as Push Pull
38
  
39
  initADC();
40
  while(1){
41
    uint16_t adc_value = readAnalogValue();
42
    if(adc_value > 0){
43
      GPIOC->ODR |= (1<<7);//turn PD3 on
44
      delay_ms(250);
45
      GPIOC->ODR &= ~(1<<7);//turn PD3 off
46
      delay_ms(250);
47
    }
48
  }
49
}

Beim Debuggen ist der Wert der "adc_value" Variable zu Beginn "256", 
danach aber immer 0.Laut Datenblatt muss ich das erste Bit im CR1 
Register sowohl setzen, um den ADC aufzuwecken als auch um eine 
Umrechnung zu starten. Beides mache ich ja. Wo liegt nun mein Fehler?

von aSma>> (Gast)


Lesenswert?

Servus,
dir fehlt es an elementaren Grundwissen. Man hat dir schon ein Link 
geschickt wie man richtig Prototypen deklariert. Hier ist noch ein Link:
http://openbook.rheinwerk-verlag.de/c_von_a_bis_z/009_c_funktionen_005.htm#mje421cf9136c8c0c1fa1f340719d12e5b
1
 //Prototyp
2
void initADC(void);
3
void delay_ms(uint16_t ms);
4
uint16_t readAnalogValue(void);
5
6
7
//main
8
int main(){
9
10
return 0;
11
}
12
13
14
//funktion1
15
void initADC(void){
16
//inhalt
17
}
18
19
20
//funktion2
21
void delay_ms(uint16_t ms){
22
//inhalt
23
}
24
25
26
//funktion3
27
uint16_t readAnalogValue(void){
28
//inhalt
29
//return x
30
}

Max M. schrieb:
> Beim Debuggen ist der Wert der "adc_value" Variable zu Beginn "256",
> danach aber immer 0.Laut Datenblatt muss ich das erste Bit im CR1
> Register sowohl setzen, um den ADC aufzuwecken als auch um eine
> Umrechnung zu starten. Beides mache ich ja. Wo liegt nun mein Fehler?

Es gibt zich Beispiele. Guck Sie dir an. Debugge erstmal die Register 
durch sind diese auch richtig gesetzt? Vielleicht hast du irgendeine 
clock nicht gesetzt.

mfg

von Max M. (maxmicr)


Lesenswert?

aSma>> schrieb:
> Man hat dir schon ein Link
> geschickt wie man richtig Prototypen deklariert.

Achso, die Reihenfolge des Codes ändert natürlich alles. Das dient 
bestenfalls der Übersichtlichkeit, ändert aber, in meinem Beispiel, 
nichts an der Funktionalität.

aSma>> schrieb:
> Es gibt zich Beispiele. Guck Sie dir an.

Wenn es wirklich so viele gäbe, hätte ich nicht gefragt.

Aber, danke für die Antwort.

von Max M. (maxmicr)


Lesenswert?

Okay, mein Code funktioniert jetzt soweit:
1
/* MAIN.C file */
2
#include <stm8s.h>
3
4
void initADC(void);
5
uint16_t readAnalogValue(void);
6
void delay_ms(uint16_t ms);
7
8
void initADC(){
9
  ADC1->CR1 |= (1<<0); //turn ADC on
10
  ADC1->CSR |= (1<<2); //Pin D3 (AIN4) as Analog Channel
11
  ADC1->CR1 |= (1<<5); //Set Prescaler to f/4 of master (4MHz)
12
}
13
14
uint16_t readAnalogValue(){
15
  ADC1->CSR &= ~(1<<7); //reset End of Conversion Bit
16
  ADC1->CR1 |= (1<<0); //Start conversion
17
  delay_ms(10);
18
  if((ADC1->CSR & (1<<7))){ //check End of Conversion Bit
19
    uint8_t hRegister = ADC1->DRH;
20
    uint8_t lRegister = ADC1->DRL;
21
    
22
    uint16_t completeValue = hRegister << 8 | lRegister;
23
    return completeValue;
24
  }
25
}
26
27
void delay_ms(uint16_t ms){
28
  while(ms--){
29
    uint16_t i;
30
    for(i = 0; i < ms; i++){
31
      nop();
32
    }
33
  }
34
}
35
36
void main()
37
{
38
  GPIOC->DDR|=(1<<7); //PD3 as Output
39
  GPIOC->CR1|=(1<<7); //PD3 as Push Pull
40
  
41
  initADC();
42
  while(1){
43
    uint16_t adc_value = readAnalogValue();
44
45
    if(adc_value > 20){
46
      GPIOC->ODR |= (1<<7);//turn PD3 on
47
      delay_ms(250);
48
      GPIOC->ODR &= ~(1<<7);//turn PD3 off
49
      delay_ms(250);
50
    }
51
  }
52
}

Beim Debuggen werden Werte um die ~3100 angezeigt. Jetzt ist nur die 
Frage, wie ich diesen Wert wieder in die Eingangsspannung umwandel? In 
den Dokumenten finde ich keine Formel, wie der ADC-Wert berechnet wird, 
oder hab ich was übersehen?

von Christopher B. (chrimbo) Benutzerseite


Lesenswert?

Spannung = ADCWert * 5/65536 dann hast du es in Volt

von Max M. (maxmicr)


Lesenswert?

Danke, das kommt hin! Aber woher hattest du diese Formel? Oder aus 
welchen Gegebenheiten erschließt sich die?

von aSma>> (Gast)


Lesenswert?

Max M. schrieb:
> Danke, das kommt hin! Aber woher hattest du diese Formel? Oder aus
> welchen Gegebenheiten erschließt sich die?

Servus,
einfacher Dreisatz Kollega.

Wobei ich der stm8 eher 10bit ADC hat. K.A. steht alles in den 
Datenblätter.

Eine analoge Spannung wird immer durch einen ADC digitalisiert, d.h. es 
werden diskrete Werte von den gemessenen analogen Wert aufgenommen.

Annahme 10bit Auflösung: 2^10-1 ergibt 1023. stm8 hat 5 Volt ADC 
Eingänge.
Klingelt es ?

mfg

von Eric B. (beric)


Lesenswert?

Max M. schrieb:
> müsste ich für "AIN4" 0100 schreiben, dann müsste (1<<3) doch stimmen,
> oder?

Nein. 0100 wäre (1<<2), oder einfach 4.

von Christopher B. (chrimbo) Benutzerseite


Lesenswert?

aSma>> schrieb:
> Wobei ich der stm8 eher 10bit ADC hat. K.A. steht alles in den
> Datenblätter.

Korrekt. Wobei ich jetzt einfach von left aligned ausgegangen bin, weil 
er einen Wert >1023 rausbekommen hat :)

von honk (Gast)


Lesenswert?

ST stellt für den STM8 eine Lib bereit.

Sieht dann so aus und der Käse ist gegessen:

ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_6, 
ADC1_PRESSEL_FCPU_D18, ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT, 
ADC1_SCHMITTTRIG_CHANNEL0, DISABLE);

von Max M. (maxmicr)


Lesenswert?

aSma>> schrieb:
> Annahme 10bit Auflösung: 2^10-1 ergibt 1023. stm8 hat 5 Volt ADC
> Eingänge.
> Klingelt es ?

Ehrlich gesagt nicht. Beim Atmega des Arduino war die Formel für mich 
eingängiger, da die Auflösung, wie du schon sagst, 2^10 beträgt. Von 
daher wäre Vref / 1024 (wie es bei den Atmegas auch ist) sinnvoller. Wie 
man auf 2^16 kommt, ist mir nicht klar.

Eric B. schrieb:
> Nein. 0100 wäre (1<<2), oder einfach 4.

Danke.

honk schrieb:
> Sieht dann so aus und der Käse ist gegessen:

Das sieht jetzt aber auch nicht wesentlich kürzer aus im Vergleich zu 
meiner Init-Funktion.

von Christopher B. (chrimbo) Benutzerseite


Lesenswert?

ADC1->CR2 |= (1<<3)
dann kannst du mit deinen 1024 rechnen. Warum dass so ist musst du aber 
selber herausfinden :-)

von guest (Gast)


Lesenswert?

Max M. schrieb:
> Ehrlich gesagt nicht. Beim Atmega des Arduino war die Formel für mich
> eingängiger, da die Auflösung, wie du schon sagst, 2^10 beträgt. Von
> daher wäre Vref / 1024 (wie es bei den Atmegas auch ist) sinnvoller. Wie
> man auf 2^16 kommt, ist mir nicht klar.

Aber nur wenn das entsprechende Config-Bit 0 ist. Wenn es 1 ist muß man 
auch beim ATmega mit 2^16 rechnen (oder mit 2^8, je nachdem wie man den 
ADC Wert ausliest).

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.