Hallo Leute,
ich programmiere einen pic18 für die auswertung einer kapazitiven
tastenfeldes.
um einen genauen ergebnis des adc wertes zu haben wollte ich den
mittelwert z.b einer 16 messungen bilden. um anschließend mit dem wert
weiter arbeiten. jedoch habe ich nicht wirklich einen plan wie ich es
mit C bilden kann.
hier nochmal das programm (dies ist mein zweites programm mit einem µc)
ich würde mich für weitere fragen freuen..
danke und gruss
Na ja.
Von EINER Messung wirst du wohl kaum einen Mittelwert machen können. Du
brauchst schon mehrere Messungen.
Ein µC Programm sieht normalerweise grundsätzlich so aus
1
...
2
3
voidmain(void)
4
{
5
6
// Initialisierung und Konfiguration der
7
// benötigten Hardware Teile
8
9
// diverse Variablen auf ihren Startwert setzen
10
// sofern notwendig
11
12
while(1)
13
{
14
15
// in dieser Endlosschliefe befindet sich dann
16
// die eigentliche Logik des Programmes. Also
17
// das was es zu tun hat
18
19
}
20
}
In deinem Code vermisse ich die zentrale Endlosschleife! Dein Code wird
ein einziges mal abgearbeitet und was danach passiert (wenn main() zu
Ende ist), das wissen nur die Götter.
Also: Du brauchst die zentrale Schleife, in der du immer wieder
ADC-Messungen machst. Diese verrechnest du so, dass du einen Mittelwert
bilden kannst. Zb machst du das so, dass du 16 mal misst und die
Einzelergebnisse aufsummierst. Und nach dem 16-mal messen berechnest du
aus dieser Summe deinen gewünschten Mittelwert und lässt dann die
entsprechende Entscheidung treffen (das if). Danach setzt du wieder
deine Variablen wieder auf 0 zurück, damit die nächsten 16 Messungen
wieder frisch aufsummiert werden können.
Dein Programm könnte also zb als Programmskizze so aussehen
Hallo,
Michael danke für den link..jedoch war es mir etwas zu komplex :) wie
gesagt ich mache es zum ersten mal..
karl heinz das ist wirklich genial..so einen beitrag kann ich auf jeden
fall gebrauchen..wie erwähnt dies ist mein zweites programm und daher
habe ich auch mit einigen fehlenden schleifen gerechnet und daher auch
das code reinkopiert..ich werde es mal jetzt so ausprobieren..ich hoffe
das ich es auch dementsprechend einsetzen kann :)
Karl Heinz Buchegger schrieb:> while( 1 )> {>> ... eine ADC Messung vornehmen ...>> SummeMessungen += Ergebnis;
Ich hätte da "SummeMessungen += ADRESH;" geschrieben oder? Ergebnis ist
ja noch das Ergebnis der Addierten Werte / 16.
Mit der genannten Möglichkeit hast du alle 16 Werte einen Mittelwert
über Diese. Es geht aber auch, dass du über die letzten 16 Werte einen
Mittelwert bildest, ist allerdings Rechenzeitintensiver:
Wenn du die wahl hast, würde ich 2^n Messungen mitteln, sprich
1,2,4,8,16 usw. Denn wenn du dadurch Teilst, macht der Compiler einen
Shift draus, die Bits werden also nur verschoben. Wenn du z.B. 10
Messungen hast, muss er "echt" Teilen und es dauert länger.
el pistolero schrieb:> AnzahlMessungen und SummeMessungen müssten ja auch definiert werden !?
Klar müssen sie das. Genauso wie die Initialisierungen. Du bekommst hier
Lösungsansätze aber keine komplett fertigen Codes. Du musst also
überlegen, was für Daten du erwartest.
Für mein Beispiel z.B.:
In Summe werden 16 8bit-Zahlen addiert. Eine 8bit-Zahl kann maximal 255
sein. Wenn man also 16mal den Maximalen Wert addieren und in Summe
speichern können soll, dann muss es also mindestens 255*16 fassen
können, also die Zahl 4080. Char hat 8 bit, kann es somit nicht. int
(manchmal auch int_16) hat bei Microcontrollern meist 16bit. Damit
kannst du also die Zahlen von 0 - 65535 speichern (unsigned) oder aber
-32768 bis +32767 (signed). Es ist also egal ob signed oder nicht, doch
eine 16bit Variable muss es sein.
Bei Ergebnis wird die Summe durch 16 geteilt. Durch die Überlegung von
eben heißt also, dass die größte Zahl, die ich haben kann, (also 4080
druch 16) 255 ist. Somit reicht dafür wieder eine 8bit Variable.
el pistolero schrieb:> hallo,>> AnzahlMessungen und SummeMessungen müssten ja auch definiert werden !?
Du brauchst ein C-Buch
Und komm mir jetzt nicht mit der Ausrede, dass das dein 2.tes Programm
wäre. Für dein 2.tes Programm ist das sowieso schon viel zu heftig.
Das erste Programm ist LED ein/LED aus
Das zweite Programm ist LED blinken
Das dritte Programm ist: Taste drücken -> LED geht an, Taste loslassen
LED geht aus.
Das vierte Programm ist ...
Das fünfundvierzigste Programm ist: Auswerten eines kapazitiven
Tastenfelds.
hallo karl heinz,
das erste programm war das ich 12 led zum blinken gebrahct habe :)
und das ist jetzt das zweite programm für eine kapazitive taste..später
muss ich das ganze auf 12 kapazitive tasten erwaitern..daher möchte ich
auch die "Ergebnis" auch 'Glätten' für die Störfaktoren...
das code sieht folgendermaßen aus!
wenn ich if(Ergebnis <= 0x00C8) in der zeile breakpoint setzte(mplabx)
und debugge und eine zeile drüber also --> Ergebnis = SummeMessungen /
AnzahlMessungen; mit dem cursor auf "Ergebnis" gehe kann ich den wert
ablesen. Die Ergebnis lautet 0x0000...das darf doch nicht passieren
oder????
#include <stdio.h>
#include <stdlib.h>
#include <p18lf45k22.h>
/* Konfiguration */
#pragma config FOSC = INTIO67 // Interne Oszillator
#pragma config PWRTEN = ON // Power Up Timer
#pragma config BOREN = OFF // Brown of Reset
#pragma config WDTEN = OFF // Watchdog Timer
#pragma config LVP = OFF // Low Voltage ICSP
#pragma config MCLRE = EXTMCLR // externer MCLR
#pragma code
#define Taste1_Abfrage 0b01000101 // ADCON für AN17 der Taste 1
definiert - 0x45
#define LED1_Taste1 LATDbits.LATD2 // Ausgang RD2 wird auf
LED1_Taste1 übergeben
#define GODONE ADCON0bits.GO_DONE
unsigned int Ergebnis;
int SummeMessungen;
int AnzahlMessungen;
void main(void)
{
TRISCbits.TRISC5 = 1; // Taste1 Eingang
TRISDbits.TRISD2 = 0; // LED1 Ausgang
ANSELCbits.ANSC5 = 1; // Analogeingang AN17 für Taste1
ADCON1 = 0x80; // VDD(+3.3V) und VSS(0V) als Referenzspannung
ADCON2 = 0xB1; // Rechtsbündig; 8Tad; FOSC/8 = 500kHz ADC
Taktfrequenz
OSCCON = 0x54; // Register für die Interne Oszillator
while(1)
{
ADCON0 = Taste1_Abfrage;
GODONE = 1;
Ergebnis = ADRESH;
Ergebnis = Ergebnis <<8;
Ergebnis = Ergebnis + ADRESL;
SummeMessungen += Ergebnis;
AnzahlMessungen++;
if(AnzahlMessungen == 16)
{
Ergebnis = SummeMessungen / AnzahlMessungen;
if(Ergebnis <= 0x00C8)
{
LED1_Taste1 = 1;
}
else
{
LED1_Taste1 = 0;
}
SummeMessungen = 0;
AnzahlMessungen = 0;
}
}
}
> Ergebnis = SummeMessungen / AnzahlMessungen;
Und was ist die Summe?
(ANzahl wissen wir, das müsste eigentlich 16 sein)
Dann musst du jetzt eben die Dinge rückwärts verfolgen. Wo kommen, die
Einzelteile her, wie entstehen sie, welche Werte hatten sie dort. Wie
sind diese Dinge wiederrum entstanden, etc. etc. So lange bis du die
Problemstelle gefunden hast, an der die Dinge aus dem Ruder zu laufen
beginnen.
Hallo,
Man kan es ja wie in rn-wissen machen.
Die benutzen einen zirkulären Speicher, der älteste Wert wird durch den
neuesten ersetzt.
Zudem braucht man bei integer-Werten die Summe nicht immer neu zu
berechnen, sondern nur den ältesten abziehen und den neuesten
aufsummieren.
Horst Hahn schrieb:> Man kan es ja wie in rn-wissen machen.
Haben die auch das Rad erfunden?
So ein Ringpuffer ist ein uralter Hut aus dem letzten Jahrtausend. Der
findet sich dann als Beispiel für Zeigeroperationen auch in jedem
brauchbaren C-Buch...
Horst Hahn schrieb:> Hallo,>> Man kan es ja wie in rn-wissen machen.> Die benutzen einen zirkulären Speicher, der älteste Wert wird durch den> neuesten ersetzt.
Gemach, gemach.
Er hat noch ganz andere Probleme.
Lass ihn erst mal gehen lernen, ehe du ihm die Diretissima durch die
Dolomiten zeigst.
Jetzt soll er erst mal den Fehler in der ADC Abfrage suchen, den er
unabsichtlich eingebaut hat.
hallo,
der code was von dem hersteller vorgegeben ist sieht folgendermaßen aus!
ich muss es für die obere single button anwendung i.wie umschreiben! und
anschließend eine mittelwert der ergebnis bilden. die vorschläge für die
mittelwert bildung sehen brauchbar aus. jedoch muss die auswertung erst
einmal funktionieren...
// Port initialization
ANSEL = 0b01010000; // A/D-clock 2uS, all pins are digital
PORTA = 0b00000000;// all pins are low (output)
TRISA = 0b00001000; // everything is output,except RA3 (MCLR)
// Reading the sensor
TRISA |= 0b00000001; // sensor 1 pin becomes input (RA0)
ADCON0 = 0b10000001; // select A/D-channel 0 (CVD happens here)
GODONE = 1; // start the conversion
TRISA &= 0b11111110; // sensor 1 pin becomes output again
el pistolero schrieb:> hallo,>> der code was von dem hersteller vorgegeben ist sieht folgendermaßen aus!> ich muss es für die obere single button anwendung i.wie umschreiben! und> anschließend eine mittelwert der ergebnis bilden. die vorschläge für die> mittelwert bildung sehen brauchbar aus. jedoch muss die auswertung erst> einmal funktionieren...
Nö.
Du musst nur verstehen was da eigenlich passiert und den Code korrekt
kopieren. Vergleich dein erstes Posting mit deinem letzten und such nach
den Unterschieden. Und dann überleg, was dieser Unterschied wohl für
Auswirkungen haben wird.
Lothar Miller schrieb:> So ein Ringpuffer ist ein uralter Hut aus dem letzten Jahrtausend. Der> findet sich dann als Beispiel für Zeigeroperationen auch in jedem> brauchbaren C-Buch...
Nachteil vom Ringpuffer ist der je nach Mittelungsbreite nicht
unerhebliche Speicherbedarf. Normalerweise tut's ein IIR-Filter, z.B.
1
Summe := Summe + Messwert - Mittel
2
Mittel := Summe / 16
Das benötigt nur einen zusätzlichen Speicher für den Summenwert.
Hallo nochmals an alle,
ich habe das problem was ich mit dem "Ergebnis = 0x0000" hatte bereits
gelöst. es funktioniert soweit sehr gut. sodass ich mit 12 tasten, 12
leds zum leuchten bringe.
als nächstes werde ich wie oben erwähnt eine mittelwert der adc werte
bilden. jedoch weiss ich nicht wie ich es am besten machen könnte. die
oben genannten ideen konnte ich hier nicht einbauen bzw wusste nicht wie
ich es machen soll !? :)
für weitere hilfen bin ich euch sehr dankbar
hier das code
ADCON2 habe ich TOSC = 125kHz(4MHz/32) Kondensatorladezeit = 8TAD(64us)
kann ich hier auch anders takten? z.B TOSC = 500kHz und
Kondensatorladezeit(acquisition time)= 2TAD(4us) ???????????
1
voidmain(void)
2
{
3
4
Initialisierung();// Initialisierung wird fortgesetzt
5
6
do
7
{
8
9
Taste1();
10
Taste2();
11
12
}while(1);
13
14
}
15
16
17
voidVreferenz(void)
18
{
19
// In dieser Funktion wird der Sample&Hold Kondensator aufgeladen //
Hallo nochmals,
ich habe eine Gleitende Mittelwert gebildet! Mit dem C-Code(siehe
Anhang) die auf der Seite RN-WISSEN ist.
Ich habe es auch zum laufen gebracht, sodass ich die 16 Werte abfangen
kann.
Weiss jetzt leider nicht wie ich es mit der unteren if Anweisung bzw mit
dem Schwellwert Regeln könnte !? Die LED soll ja leuchten beim Betätigen
auf die Taste, dass heißt beim Betätigen auf die Taste wird die Spannung
geringer(also unter 0x0160).Das Problem ist: Die Spannung fällt auch
Automatisch darunter wenn sich die z.B. die Temperatur verändert!
Meine Frage ist, wie kann ich eine Tastenbetätigung erkennen, wenn sich
die Temperatur verändert ???
el pistolero schrieb:> if(Ergebnis <= 0x0160) // Schwellwert>> {>> LED2 = 1; // LED geht an>> }>> else>> {>> LED2 = 0; // LED geht aus>> }
el pistolero schrieb:> Meine Frage ist, wie kann ich eine Tastenbetätigung erkennen, wenn sich> die Temperatur verändert ???
...gleitender Mittelwert als Langzeitwert....damit folgst du langsam dem
Drift durch die Temperaturänderung und kompensierst diesen....
pompete schrieb:> ...gleitender Mittelwert als Langzeitwert....damit folgst du langsam dem>> Drift durch die Temperaturänderung und kompensierst diesen....
Kann mir das einer etwas Ausführlicher erklären !? :)
Mfg
el pistolero schrieb:> pompete schrieb:>> ...gleitender Mittelwert als Langzeitwert....damit folgst du langsam dem>>>> Drift durch die Temperaturänderung und kompensierst diesen....>> Kann mir das einer etwas Ausführlicher erklären !? :)
Temperaturänderungen sind selten instantan.
Soll heißen: die geschehen langsam!
Drückst du aber auf die Taste, dann ist das ein schneller Vorgang.
d.h. dein Schwellwert, den du zur UNterscheidung benutzt kann nicht eine
fixe Zahl sein, sondern ist zb ein laaaaaaaanger Mittelwert aus der
Vergangenheit.
Denk dir was aus! Das ist doch der halbe Spass in der Programmierung -
sich was ausdenken, es implementieren und nachsehen ob man richtig
gedacht hat.
Karl Heinz Buchegger schrieb:> Temperaturänderungen sind selten instantan.>> Soll heißen: die geschehen langsam!>>>> Drückst du aber auf die Taste, dann ist das ein schneller Vorgang
Ist Logisch! Was könnt ihr mir für den dynamischen Schwellwert
empfehlen? Bzw wie kann ich es implementieren?
Den Gleitenden Mittelwert habe ich als "Ausgang" implementiert!
if(Ausgang < Schwellwert) ... ?
vorher war es ja so gewesen!
el pistolero schrieb:>> if(Ergebnis <= 0x0160) // Ergebnis->ADCwert und 0x0160->Schwellwert>>>>>> {>>>>>> LED2 = 1; // LED geht an>>>>>> }>>>>>> else>>>>>> {>>>>>> LED2 = 0; // LED geht aus>>>>>> }
Hallo,
es ist mir was eingefallen ! kann das vllcht so funktionieren ?
for(AnzahlMessungen=0; AnzahlMessungen < SIZE_OF_AVG; AnzahlMessungen++)
//Gleitende Mittelwertbildung der ADC Werte
{
Vreferenz();
TRISCbits.TRISC5 = 1; // Taste1 als Eingang gewählt
ADCON0 = Taste1_Abfrage; // AN17 Eingang
Ergebnis = Ergb(); //
TRISCbits.TRISC5 = 0; // Taste1 wieder als Ausgang bzw.
// hier werden die Ergebnisse summiert
NeuWertSchreiben(&zeigerAvgFilter, Ergebnis);
}
// hier ist der gefilterten wert also Ausgang
Ausgang = BerechneAusgangswert(&zeigerAvgFilter);
if( Ergebnis <= Ausgang) /*Ergebnis aktueller wert!? Ausgang ist
Gleitender Mittelwert */
{
LED = ON;
}
else
{
/* LED = OFF;
}
Ein durchlauf des Programmes dauert ca 50us, das heißt wenn ich eine
Gleitende Mittelwertbildung von 60s haben möchte, muss ich das ganze
60s/50us= 1.200.000 mal laufen lassen.
Wenn der aktuelle Wert des ADC Wandler, kleiner als der Gleitende
Mittelwert ist wird eine Tastendruck erkannt!? Ist dasselbe was ihr da
meint????
Oder was schlägt ihr mir da vor?
Gruss
Ich finde:
Schön langsam wirds Zeit, dass du selbst auch irgendwas tust.
2 Mittelwerte:
Einer der laaange Messwertintervalle in der Vergangenheit zusammenfasst.
Der reagiert auf Veränderungen in der Temperatur. Die Veränderung durch
einen Tastendruck wird hingegen diesen Mittelwert nicht sonderlich
verändern.
Einer der nur die letzten Paar Messwerte zusammenfasst und nur das
Schwanken am Pin etwas begradigen soll.
Der reagiert zwar auch auf die Temperatur aber er reagiert auch auf
einen Tastendruck.
In 0-stellung sind beide MIttelwerte gleich oder nahezu gleich. Bei
Temperaturänderungen (die langsam erfolgen) folgen beide Mittelwerte
mehr oder weniger parallel dieser Änderung. Bei einem Tastendruck
hingegen, reagiert der kurze MIttelwert sofort und die beiden
Mittelwerte laufen auch sofort extrem auseinander.
Soweit die Idee, mit der ich es probieren würde.
Karl Heinz Buchegger schrieb:> Ich finde:> Schön langsam wirds Zeit, dass du selbst auch irgendwas tust.el pistolero schrieb:> Hallo Karl,>> danke für deine Antwort..
...wie gut das es den Karl Heinz gibt, ihm geht die puste irgendwie nie
aus ;-)