-diese Library dient zum betreiben der AD-Wandler im Single-Conversation-Mode
-die ADC-Pins die benutzt werden sollen, müssen im H-File deklariert und im C-File den entsprechenden Port-Pins zugeordnet werden.
-es kann auch eine Mittelwertbildung von dem Messwert durchgeführt werden
(die Messdauer steigt dann natürlich entsprechend an)
-es gibt zwei identische Libs einmal für ADC1 und einmal für ADC2
(sie unterscheiden sich nur in den verwendeten Variabelnnamen)
Hier eine Auswertung über die Genauigkeit :
Spannungswert über einen 100k Poti (ohne externen Kondensator)
100.000 Messungen und dann Anzeige der Min- und Max- AD-Werte
(ADC mit 12Bit, URef = 3V, 1 Digit ca 730 uV)
1 2 3 4 5 6 7 8 | Ohne Mittelwerte : 814 - 1144 = +/- 165 2 Mittelwerte : 974 - 1132 = +/- 79 4 Mittelwerte : 990 - 1114 = +/- 62 8 Mittelwerte : 1014 - 1101 = +/- 43 16 Mittelwerte : 1036 - 1086 = +/- 25 32 Mittelwerte : 1043 - 1077 = +/- 17 64 Mittelwerte : 1052 - 1068 = +/- 8 128 Mittelwerte : 1054 - 1066 = +/- 6 |
-im Beispiel wurden 3 Pins als Analog-IN definiert und per ADC1 gemessen
1 | PA3, PC4, PC5 |
Voraussetzungen :
1 2 | Benutzte Module der CooCox-IDE : GPIO, ADC Benutzte Librarys : keine |
Enumerationen (für ADC1) :
1 2 3 4 5 | typedef enum { ADC_PA3 = 0, // PA3 ADC_PC4 = 1, // PC4 ADC_PC5 = 2 // PC5 }ADC1s_NAME_t; |
:
1 2 3 4 5 6 7 8 9 10 | typedef enum { MW_NONE =0, // keine Mittelwerte MW_2, // 2 Mittelwerte MW_4, // 4 Mittelwerte MW_8, // 8 Mittelwerte MW_16, // 16 Mittelwerte MW_32, // 32 Mittelwerte MW_64, // 64 Mittelwerte MW_128 // 128 Mittelwerte }ADC1s_MW_t; |
Funktionen (für ADC1) :
1 2 3 | void UB_ADC1_SINGLE_Init(void); // zum init des ADC1 uint16_t UB_ADC1_SINGLE_Read(ADC1s_NAME_t adc_name); // zum auslesen eines ADC direkt uint16_t UB_ADC1_SINGLE_Read_MW(ADC1s_NAME_t adc_name); // zum auslesen eines ADC mit Mittelwertbildung |
Beispiel :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | //-------------------------------------------------------------- // File : main.c // Datum : 17.02.2013 // Version : 1.0 // Autor : UB // EMail : mc-4u(@)t-online.de // Web : www.mikrocontroller-4u.de // CPU : STM32F4 // IDE : CooCox CoIDE 1.7.0 // Module : CMSIS_BOOT, M4_CMSIS_CORE // Funktion : Demo der ADC-Single-Library // Hinweis : Diese zwei Files muessen auf 8MHz stehen // "cmsis_boot/stm32f4xx.h" // "cmsis_boot/system_stm32f4xx.c" //-------------------------------------------------------------- #include "main.h" #include "stm32_ub_adc1_single.h" #include "stm32_ub_led.h" int main(void) { uint16_t adc_wert; SystemInit(); // Quarz Einstellungen aktivieren UB_ADC1_SINGLE_Init(); // Init vom ADC1 UB_Led_Init(); // Init der LEDs while(1) { // ADC-Kanal an PA3 messen und 3 LEDs entsprechend schalten adc_wert=UB_ADC1_SINGLE_Read_MW(ADC_PA3); if(adc_wert>1024) UB_Led_On(LED_GREEN); else UB_Led_Off(LED_GREEN); if(adc_wert>2048) UB_Led_On(LED_ORANGE); else UB_Led_Off(LED_ORANGE); if(adc_wert>3072) UB_Led_On(LED_RED); else UB_Led_Off(LED_RED); // ADC-Kanal an PC4 messen und die Blaue LED entsprechend schalten adc_wert=UB_ADC1_SINGLE_Read_MW(ADC_PC4); if(adc_wert>2048) UB_Led_On(LED_BLUE); else UB_Led_Off(LED_BLUE); } } |
Beschreibung :
1 2 3 4 5 6 7 8 9 | Funktion : -ADC1 wird im Single-Conversation Mode initialisiert -es wird die Analog-Spannung an PA3 und PC4 gemessen (in der LIB definiert) -die 4 LEDs werden ja nach Spannungswert entweder ein- oder ausgeschaltet Librarys die für das Beispiel benutzt werden : -stm32_ub_adc1_single -stm32_ub_led |
Hier die Library zum Download :
Hier der komplette CooCox-Projektordner zum Download :
Hallo,
Zwei kurze Fragen
Wo wird denn der Referenzwert für die ADC-Spannung angegeben?
Und wie hoch ist die maximale Spannung die an einen Pin angelegt werden kann?
solche sachen (und andere) stehen im Datenblatt.
Hast du recht
Sorry
Irgendwie habe ich das mit den enums nicht verstanden…
adc_wert=UB_ADC1_SINGLE_Read_MW(ADC_PA3); ruft einen Wert ab
wie muss es aussehen um den Aufruf mit Mittelwert zu machen?
die Funktion “UB_ADC1_SINGLE_Read_MW” mittelt den ADC-Wert schon. Die direktmessung wäre die Funktion “UB_ADC1_SINGLE_Read”
im ADC C-File wird ganz zu Anfang in einer Liste eingetragen wieviele Mittelwerte benutzt werden sollen…das kannst du event. noch anpassen.
in der Demo steht da z.B. für ADC_PA3 “MW_32″ drinn …also wird der Mittelwert aus 32 Messwerten gebildet.
von Blindheit geschlagen gewesen
Danke
Danke für die lib, die macht das alles noch ein wenig handlicher.
Gerade habe ich aber ein Weilchen gebraucht, wo der Fehler lag, weil zwei Werte, die nacheinander gesampled wurden immer identisch waren. Die Lösung liegt in einem
#ifdef __cplusplus
extern “C” {
#endif
… tolle LIB
#ifdef __cplusplus
}
#endif
, da ich C++ programmiere.
Eventuell könnte man das in den Standard-Lib-Rahmen aufnehmen
Gruß
x_X
es steht dir frei diese Änderung in allen Librarys zu machen…ich brauch die nicht, da ich in “C” programmiere
wenn ich zwei kanäle nacheinander abfrage, scheint es ein übersprechen zwischen den kanälen zu geben… ist dieses phänomen bekannt?
ich wende es so an:
tester[7] = ((float) UB_ADC1_SINGLE_Read_MW(ADC_PC4)) / 4096.0f;
tester[8] = ((float) UB_ADC1_SINGLE_Read_MW(ADC_PA3)) / 4096.0f;
config:
ADC1s_t ADC1s[] = {
//NAME ,PORT , PIN , CLOCK , Kanal , Mittelwerte
{ADC_PC4,GPIOC,GPIO_Pin_4,RCC_AHB1Periph_GPIOC,ADC_Channel_14,MW_32}, // ADC an PC4 = ADC12_IN14
{ADC_PA3,GPIOA,GPIO_Pin_3,RCC_AHB1Periph_GPIOA,ADC_Channel_3 ,MW_32}, // ADC an PA3 = ADC123_IN3
};
ist an den beiden Pins auch was angeschlossen ? bei einem offenen Eingang kann ein übersprechen auftauchen aber sobald an allen Eingängen ein niederohmiges Signal hängt dürfte das nicht mehr sein.
Niederohmig ist vielleicht Defintionsfrage:
Es sind 10k Potis an 3 V und GND, deren Mittelabgriffe am ADC anliegen.
Wenn ich keine Mittelwertbildung mache, ist der erste Wert, den ich am zweiten ADC-Pin auslese quasi identisch mit dem des anderen Pins… Durch die mehrfache Auslesung bei der MW-Bildung wirds halt besser…
bin mir nicht sicher ob der erste Wert nach dem Umschalten vom MUX verworfen werden sollte … müsste ich mal ausprobieren.
ich bin gerade an den ADC-Libs für den STM32F429 und da ist es auch so. Wenn ein Eingang offen ist, zeigt er den gleichen Wert an wie der andere ADC mit Poti. Aber sobald an beiden ein Poti angeschlossen ist (5k || 100nF) zeigen Sie jeweils den Wert an den Sie sollen. Der Werte schwanken allerdings stark, man muß schon 64-Mittelwerte benutzen wenn man 12bit Auflösung will.
Hast du mal das zuletzt ausgelesene Poti auf null gestellt, und dann am zweiten gedreht? Wenn ich das erste auf 100% stelle, ist der andere wert oberhalb von null.
Also das geht bei mir. Aber ich komme nicht auf 0 sondern nur auf 1..3 runter (unabhängig vom anderen Kanal). Wenn dir 11bit (oder 10bit) Auflösung reichen, kannst du das Ergebnis ja nochmal durch 2 bzw 4 Teilen…dann wird das ganze vielleicht besser.
Die 100 nF parallel zum Mittelabgriff scheinen der Einzige Unterschied zu sein. Das werde ich bei Gelegenheit mal testen.
Gibt es das Lib auch für ADC3?
Es empfiehlt sich, unmittelbar nach
ADC_InitTypeDef ADC_InitStructure;
die Funktion
ADC_StructInit (&ADC_InitStructure);
aufzurufen. Sonst kann es passieren, dass
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
nur einmal korrekt funktioniert und bei weiteren Aufrufen in einer Endlosschleife hängt.
Der Grund ist, dass nicht alle Member von ADC_InitStructure in der Initialisierung vollständig beschrieben werden. Je nach Inhalt, der auf dem Stack herumliegt, tritt dann dieses Problem auf. Nachdem ich genau dieses Problem hatte, habe ich im Internet recherchiert. Dabei ist dann aufgefallen, dass viele Beispielcodes hier genau dieses Problem haben.
Beispiel-Link:
http://www.mikrocontroller.net/topic/273743
danke für den Hinweis. Werd ich beim nächsten update einfügen.
Hallo,
ichv ersuche mit dem STM32E407 mehrere analoge Eingänge zu programmieren, bekomme aber nur den Eingang “PC0″,was dem Pin “A0″ entspricht als analogen Eingang hin.
Die Eingänge PF6 bis PF10 als die restelichen A1-A5 wollen bei mir nicht laufen. Aus was muss ich achten, wenn ich diese implementieren möchte, habe in den Datenblättern nichts brauchbares für mich gefunden.
Danke
Gruß Phil
sry,
habe es nach intensiverem Nachdenken hinbekommen
Hallo,
ich versuche nun anstatt Spannungssignale, Stromewerte mittels Stromsensoren einzulesen, doch dies funktioniert bei mir nicht.
Wie muss ich dabei vorgehen? Auf was muss ich achten?
Und ist dies überhaupt möglich, Werte von Stromsensoren auszulesen?
Viele Grüße und Danke
Flori
was ist den ein “Stromsensor” ?
falls es kein shunt ist, sondern ein IC empfehle
ich das datenblatt zum sensor zu lesen…da stehen nützliche infos drin.
z.B. wie er auszulesen ist und worauf man achten muss.
Ich meine, ich habe ein Stromsignal, welches ich direkt an den ADC Eingang anschließe (wo ich sonst Spannungssignale messe), aber ich bekomme keine Stromwerte angezeigt. muss ich zusätzlich Hardware kaufen, um Stromwerte einlesen zu können?
der ADC misst Spannungen und keine Ströme.
Und ein “Strom” fließt auch nicht irgendwie aus einem Sensor raus. Schreib doch einfach um was für einen Sensor es sich handelt (die Bezeichnung) sonst ist das hier nur ein Ratespiel und für Ratespiele bin ich zu alt.