PIC16F1705 ADC Samples

OP #7460537
Lesenswert?

Hallo Leute,

mir ist kein wirklich gutes Subjekt eingefallen, daher habe ich es mal sehr allgemein formuliert. Ihr wisst sicher, dass ich als Newbie etwas Probleme habe, das was ich will auch in Worte/Begrifflichkeiten zu fassen, die µC-kompatibel sind. Daher finde ich es auch schwer mir Antworten zu ergooglen (klar, wenn schon die Frage schlecht formuliert ist :-)

Was will ich ?

Ich möchte für einen Zeitabschnitt/Periode (nehmen wir hier mal 1msec) analoge Werte via ADC sampeln. Die werden aufaddiert und dann der Mittelwert für diese Periode berechnet. Die Anzahl der Samples sei erst mal egal, Hauptsache ist, dass die Periode (relativ) exakt eingehalten wird.

Da es bei µC keinen Systemzeit/etc gibt wäre ein (grober Algorithmus ungefähr folgender :

1 Starte einen Timer/Zähler

2 Lese die Werte aus dem ADC ein

3 Wenn der Zähler abgelaufen ist : Mittelwertberechnung und dann etwas Programmlogik.

4 Zurück zu 1

Für euch sicher kein Problem mir dieses Vorgehen etwas genauer zu beschreiben, bzw C-Codefragmente, Tutorials oder ähnliches als Hilfe beizusteuern ?

Viele Grüße Harry

#7460555
Lesenswert?

Hallo Du könntest dich an dein Problem herantasten. So machen das im Allgemeinen alle. Zuerst mal ein ADC-programm zum Laufen bringen, dann einen Timer und dann beides verbinden. Weiss nicht, ob dein PIC vom MCC unterstützt wird, sonst kannst du da schon mal die Basis-Funktionen bekommen. Arbeitest du mit MPLAB X und dem XC8?

Und das hier gibzs auch noch: https://github.com/sowd/pic16F1715_Analog_to_UART

Gruß

OP #7460565
Lesenswert?

Franko P. schrieb:

Hallo Du könntest dich an dein Problem herantasten. So machen das im Allgemeinen alle. Zuerst mal ein ADC-programm zum Laufen bringen, dann einen Timer und dann beides verbinden. Weiss nicht, ob dein PIC vom MCC unterstützt wird, sonst kannst du da schon mal die Basis-Funktionen bekommen. Arbeitest du mit MPLAB X und dem XC8?

Gruß

Klar, aber manchmal möchte ich mich etwas schneller herantasten. ADC habe ich soweit fertig, dass ausgelesen werden kann.

Der PIC wird von MCC unterstützt, Basis ist da, Begriffe wie FOSC FOSV4 etc finde ich verwirrend ....
Im Moment scheint mir folgender Link zur Timerprogrammierung vielversprechend: https://deepbluembedded.com/timer-modules/

Ein allgemeines Problem bei der Suche nach Tutorials ist, dass viele schon irgendwie outdatet sind und man das erst merkt, wenn man viel Zeit verbraten hat.

Komme ich mit der "The general formula for Timer1 Module .." zum Ziel eine Periode von 1msec zu implementieren ?

Viele Grüße

#7460569
Lesenswert?

Bei Samples ist es durchaus sinnvoll nur solche zu beachten, die auch für deinen PIC sind. Leider ist Microchip nicht kompatibel zu sich...

"Komme ich mit der "The general formula for Timer1 Module .." zum Ziel eine Periode von 1msec zu implementieren ?"

sagt mir nix. Wo steht das?

#7461331
Lesenswert?

Hallo,

man muss versuchen das Grundprinzip zu verstehen, weil das Prinzip ist immer gleich. Leider finde ich auch für andere PICs keine Timer AppNote. Aber 3 Anleitungen auf Youtube. Ob die qualitativ gut sind weiß ich nicht, wäre jedenfalls ein Anfang.

https://www.youtube.com/watch?v=I3x519D9NC0 https://www.youtube.com/watch?v=pAs9Up6Ap2M https://www.youtube.com/watch?v=vD2jqWxuGEM

Auch wenn die sich nicht explizit auf deinen µC Typ beziehen kann man das adaptieren. Die Registernamen sollten gleich bzw. ähnlich sein. Mit einmal Timer Kapitel lesen im Manual sollte eine Anpassung möglich sein. Du musst verstehen was die warum machen und notfalls die gleiche Funktionalität in den Registern zusammensuchen. Also versteife dich nicht so sehr auf die Register- und Bitnamen.

OP #7461359
Lesenswert?

Veit D. schrieb:

Hallo,

man muss versuchen das Grundprinzip zu verstehen, weil das Prinzip ist immer gleich. Leider finde ich auch für andere PICs keine Timer AppNote. Aber 3 Anleitungen auf Youtube. Ob die qualitativ gut sind weiß ich nicht, wäre jedenfalls ein Anfang.

https://www.youtube.com/watch?v=I3x519D9NC0 https://www.youtube.com/watch?v=pAs9Up6Ap2M https://www.youtube.com/watch?v=vD2jqWxuGEM

Auch wenn die sich nicht explizit auf deinen µC Typ beziehen kann man das adaptieren. Die Registernamen sollten gleich bzw. ähnlich sein. Mit einmal Timer Kapitel lesen im Manual sollte eine Anpassung möglich sein. Du musst verstehen was die warum machen und notfalls die gleiche Funktionalität in den Registern zusammensuchen. Also versteife dich nicht so sehr auf die Register- und Bitnamen.

Danke für die Links. Wie (fast immer) behandelt man in den Tutorials die Erzeugung eines "genauen" delays. Ich habe aber nach so etwas wie "Solange 1msec noch nicht vorbei ist" gesucht, denn in delays mit beliebigen Schleifen wird einfach nur "sinnlos" Zeit verbraten. Im Grunde genommen implementiere ich eine primitive Nebenläufigkeit mittels Zeitscheiben. Also so etwas wie:

1
wiederhole unendlich
2
{
3
  Eine Periode Task1
4
  Eine Periode Task2
5
  ...
6
  Eine Periode TaskN
7
}

Mit Hilfe von MCC habe ich nun folgendes gemacht:

o es wird eine Flagvariable instantiert, die mir zeigen soll, wenn eine Periode (hier: 1msec) abgelaufen ist:

1
volatile bool periodFinished = false;

o Timer0 wird so konfiguriert , dass er nach 1msec einen Interrupt auslöst

1
void TMR0_Initialize(void)
2
{
3
    // Set TMR0 to the options selected in the User Interface
4
  
5
    // PSA not_assigned; PS 1:2; TMRSE Increment_hi_lo; mask the nWPUEN and INTEDG bits
6
    OPTION_REG = (uint8_t)((OPTION_REG & 0xC0) | (0xD8 & 0x3F)); 
7
  
8
    // TMR0 131; 
9
    TMR0 = 0x83;
10
  
11
    // Load the TMR value to reload variable
12
    timer0ReloadVal= 131;
13

14
    // Clear Interrupt flag before enabling the interrupt
15
    INTCONbits.TMR0IF = 0;
16

17
    // Enabling TMR0 interrupt
18
    INTCONbits.TMR0IE = 1;
19

20
    periodFinished = false;
21
    // Set Default Interrupt Handler
22
    TMR0_SetInterruptHandler(TMR0_DefaultInterruptHandler);
23
}

o in der zugeordneten ISR wird ein Flag auf true gesetzt, wenn die msec vorbei ist.

1
void TMR0_DefaultInterruptHandler(void){
2
  periodFinished = true;
3
}

Jedes mal, wenn ich im main einen Programmzweig habe, der genau eine Periode dauern soll wird davor der Timer neu initialisiert und dann solange der Zweig abgearbeitet, bis die Periode vorbei ist

1
while (!periodFinished)
2
{  
3
// TuwasSinvolles};
4
}

Was ich noch nicht gut gelöst habe ist, dass ich jedes mal den Timer neu initialisiere. Mir wäre eine startTimer und eine stopTimer-Function lieber.

Also:

o Initialisieren des Timers am Anfang von main()

Schleife :

a) Aufruf von startTimer wenn eine Periode Arbeit anliegt

b) Arbeiten bis Periode vorbei : (periodFinished == true)

c) danach kann der Timer erst mal ruhen : stopTimer

d) zurück zu a)

So könnte ein startTimer stopTimer aussehen:

1
void startTimer()
2
{
3
  periodFinished = false;
4
  Irgendwie den Timer starten
5
}
6

7
void stopTimer()
8
{
9
  Irgendwie den Timer stopen/einfrieren deaktivieren
10
}

Wenn mir jemand einen Tipp geben könnte, wie ich start/stopTimer implementiere wäre ich sehr dankbar.

Der verwendete µC ist übrigens ein PIC16F1705

Danke und Grüße

#7461402
Lesenswert?

Ich weiss nicht, warum du dich so gegen das Lesen des datenblattes sperrst. Dieser PIC z.B. hat für mich eine Besonderheit, da der Timer0 nicht gestoppt oder gestartet werden kann. Der Timer 1 schon. T1CONbits.TMR1ON = 1; startet den Timer. Aber wenn du so eine Abneigung gegen Datnblätter hast, wäre Arduino oder ein anderer Compiler, wo es für alle Funktionen eine Funktion in einer C-Bibliothek gibt, besser für dich geeignet.

Gruß

OP #7461411
Lesenswert?

Franko P. schrieb:

Ich weiss nicht, warum du dich so gegen das Lesen des datenblattes sperrst. Dieser PIC z.B. hat für mich eine Besonderheit, da der Timer0 nicht gestoppt oder gestartet werden kann. Der Timer 1 schon. T1CONbits.TMR1ON = 1; startet den Timer. Aber wenn du so eine Abneigung gegen Datnblätter hast, wäre Arduino oder ein anderer Compiler, wo es für alle Funktionen eine Funktion in einer C-Bibliothek gibt, besser für dich geeignet.

Gruß

Ich sperre mich nicht, ich decodiere vdie Datenblätter nicht exakt genug. :-) Danke für den Hinweis

#7461418
Lesenswert?

Harry R. schrieb:

Hauptsache ist, dass die Periode (relativ) exakt eingehalten wird.

Nun, das ist kein Problem, da die ADCs mit konstantem Takt laufen. Du läßt also den ADC durchlaufen, zählst die Anzahl der ADC-Interrupts mit und hast damit eine konstante Periode. In den ADC-Interrupts addierst Du die Ergebnisse auf und teilst sie z.B. alle 256 Wandlungen /256, d.h. schmeißt das untere Byte der Summe weg.

#7461426
Lesenswert?

Mir scheint bisher das ganze recht wenig zielgerichtet.

Im Datenblatt 20.2.5 AUTO-CONVERSION TRIGGER sind unter anderem die Timer 2,4,6 sowie die beiden CCP Module gelistet, welche bei einem Match (Timer == Periode, bzw. Compare) den ADC automatisch periodisch starten können.

Wenn der ADC fertig ist löst er, sofern entsprechend konfiguriert, einen Interrupt aus und man kann den Wert abspeichern bzw. aufaddieren Dabei zählt man einfach mit, wie viele Werte man schon hat, berechnet bei entsprechender Anzahl den Mittelwert...

#7461427
Lesenswert?

Hallo, wenn dein PIC von MCC unterstützt wird, dann benutze doch einfach die generierten Funktionen:

Hier ein Beispiel vom PIC32MZ:

1
void TMR4_Initialize(void);
2
void TMR4_Start(void);
3
void TMR4_Stop(void);
4
void TMR4_PeriodSet(uint16_t period);
5
uint16_t TMR4_PeriodGet(void);
6
uint16_t TMR4_CounterGet(void);
7
uint32_t TMR4_FrequencyGet(void);
8
void TMR4_InterruptEnable(void);
9
void TMR4_InterruptDisable(void);
10
void TMR4_CallbackRegister( TMR_CALLBACK callback_fn, uintptr_t context );
OP #7461436
Lesenswert?

Volker S. schrieb:

Mir scheint bisher das ganze recht wenig zielgerichtet.

Im Datenblatt 20.2.5 AUTO-CONVERSION TRIGGER sind unter anderem die Timer 2,4,6 sowie die beiden CCP Module gelistet, welche bei einem Match (Timer == Periode, bzw. Compare) den ADC automatisch periodisch starten können.

Wenn der ADC fertig ist löst er, sofern entsprechend konfiguriert, einen Interrupt aus und man kann den Wert abspeichern bzw. aufaddieren Dabei zählt man einfach mit, wie viele Werte man schon hat, berechnet bei entsprechender Anzahl den Mittelwert...

Das liest sich wie ein gutes Verfahren, ich werde es bei einer Optimierung des Programms ausprobieren. Im Moment liegt mein Focus darauf zu testen, ob meine Idee funktionieren könnte, es ist (noch) unoptimiert und relativ geradeaus implementiert.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren