www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Frage zu PIC ADC Wandler!


Autor: dewey (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo leute!

ich will mit einem pic16f877 einen servoposition per pc steuern und auch 
einen(bzw später mehrere Analogwerte) einlesen!

bei meiner steuerung funktioniert die servo ansteuerung schon sehr gut!

jetzt möchte ich dazu einen analogwert einlesen! ich habe dazu eine 
interrupt routine programmiert aber irgendwie wird diese isr nicht 
ausgeführt! könnte mir da jemand vielleicht helfen???

hier mal der gesamte programmcode!
#include <16F877a.h>
#device ADC=10      //10bit Auflösung
#use delay (clock=20000000)
#fuses HS, NOWDT, NOPROTECT, NOLVP
#use RS232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#include <stdlib.h>

int8 pos;
int8 zaehler = 0;
int16 ad_wert;
float messwert;  

/*******************************************************/
/*          Timer2 - Interrupt Routine                 */
/*    Aufruf: alle 0,1ms                               */
/*    Funktion: Servoansteuerung                       */
/*    Datum: 14.07.08                                  */
/*******************************************************/
#INT_TIMER2
void timer2overflow()
{
   zaehler++;
   
   if(zaehler == 180)
   {
     zaehler = 0;
     output_high(PIN_C2);
   }
   if(zaehler == pos)
     output_low(PIN_C2);   
}

#INT_AD
void ad_handler()
{
      
      
      ad_wert = read_adc();
      messwert = ad_wert/1023.0 * 5; // AD Wert 0-5V; Betriebsspannung
      printf("\fADWert: %1.4f\n", messwert);

}

void main (void)
{
   char empfangen; 
   
 
   setup_timer_2(T2_DIV_BY_4, 125, 1);
   set_timer2(0);
   
   setup_adc( ADC_CLOCK_INTERNAL );
   setup_adc_ports( ALL_ANALOG );
   set_adc_channel(0);
   enable_interrupts(INT_TIMER2);
   enable_interrupts(INT_AD);
   enable_interrupts(GLOBAL);
    
   while(true)
   {  
      //************************************
      if(kbhit())
         empfangen = getc();
      pos = empfangen - 60; 
      //************************************
      
   }
} 

ich habe aus dem CCSC manuel die interrupt auslösung #INT_AD gefunden!
und in die beschreibung dazu: "Analog to digital conversion complete"
wann löst der interrupt jetzt eigentlich aus?
ich habe mir dass so gedacht, wenn die a/d wandlung fertig ist wird ein 
interrupt ausgelöst! oder??
warum wird dann mein interrupt nie ausgelöst??

hoffe mir kann jemand helfen! danke schon im voraus!

mfg

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok.
1) Shift-Taste benutzen. Groß-/Kleinschreiberegeln aus der Grundschule 
wiederholen.
2) Sätze enden im Deutschen mit einem Punkt ("."). Wann man Ausrufe- 
oder Fragezeichen verwendet, hat man dort ebenfalls gelernt.
3) Ich vermute du brauchst in dem ISR-Handler
ad_wert=read_adc(ADC_READ_ONLY);
und im Hauptprogramm ein (oder mehrere)
 read_adc(ADC_START_ONLY);

Autor: Timmo H. (masterfx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Musst du nicht noch den ADC überhaupt aktivieren, z.B. mit ADON oder so?

Autor: dewey (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok danke. Ich werde es gleich ausprobieren!
Tut mir leid. Ich werde das nächste mal besser darauf achten!

mfg dewey

Autor: dewey (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Timmo: Nein ich muss den ADC nicht extra aktivieren. Das Aktivieren 
erfolgt mit den befehlen :
setup_adc( ADC_CLOCK_INTERNAL );
setup_adc_ports( ALL_ANALOG );


@Ernst Bachmann: Ich habe jetzt das Programm mit den von dir 
vorgeschlagenen Befehlen ergänzt. Doch leider ist das Ergebnis immer 
noch nicht, dass was ich will.
Der AD Wert wird jetzt zwar richtig eingelesen, aber immer nur dann wenn 
ich ein Zeichen vom PC zu meinem PIC sende.
Ich möchte aber, dass der aktuelle AD Wert zu meinem PC gesendet wird, 
ohne dabei ein Zeichen senden zu müssen.

Danke schon im Voraus!

mfg dewey

Autor: unid (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat sich dein Problem gelöst? Sonst poste doch bitte noch einmal deinen 
aktuellen Code.

Autor: dewey (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Leider habe ich das Problem noch nicht lösen können.
Das Problem:
Der AD Wert wird jetzt zwar richtig eingelesen, aber immer nur dann wenn
ich ein Zeichen vom PC zu meinem PIC sende.
Ich möchte aber, dass der aktuelle AD Wert zu meinem PC gesendet wird,
ohne dabei ein Zeichen senden zu müssen.

Hier mal de aktuelle Code. Bin schon langsam am verzweifeln!
#include <16F877a.h>
#device ADC=10      //10bit Auflösung
#use delay (clock=20000000)
#fuses HS, NOWDT, NOPROTECT, NOLVP
#use RS232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#include <stdlib.h>

int8 pos;
int8 zaehler = 0;
int16 ad_wert;
float messwert;  

/*******************************************************/
/*          Timer2 - Interrupt Routine                 */
/*    Aufruf: alle 0,1ms                               */
/*    Funktion: Servoansteuerung                       */
/*    Datum: 14.07.08                                  */
/*******************************************************/
#INT_TIMER2
void timer2overflow()
{
   zaehler++;
   
   if(zaehler == 180)
   {
     zaehler = 0;
     output_high(PIN_C2);
   }
   if(zaehler == pos)
     output_low(PIN_C2);   
}

#INT_AD
void ad_handler()
{
      
      
      ad_wert = read_adc(ADC_READ_ONLY);
      messwert = ad_wert/1023.0 * 5; // AD Wert 0-5V; Betriebsspannung
      printf("\fADWert: %1.4f\n", messwert);

}

void main (void)
{
   char empfangen; 
   
 
   setup_timer_2(T2_DIV_BY_4, 125, 1);
   set_timer2(0);
   
   setup_adc( ADC_CLOCK_INTERNAL );
   setup_adc_ports( ALL_ANALOG );
   set_adc_channel(0);
   enable_interrupts(INT_TIMER2);
   enable_interrupts(INT_AD);
   enable_interrupts(GLOBAL);
    
   while(true)
   {
      read_adc(ADC_START_ONLY);  
      //************************************
      if(kbhit())
         empfangen = getc();
      pos = empfangen - 60; 
      //************************************
      
   }
} 

Danke schon im Voraus!

mfg dewey

Autor: ... ... (docean) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kein printf keine Division und kein float in einer INT Fkt...

Das macht man einfach nicht...( siehe auch dazu ander beiträge von uns 
beiden)

in der isr nur den  ad_wert holen und dann mit einer var. dem main 
mitteilen das da was neues gibt...

Autor: unid (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Du startest bei jedem Durchgang des Mainloops die AD-Wandlung neu, dabei 
wurde die "alte" AD-Wandlung noch gar nicht beendet. Dadurch kann die 
AD-Wandlung nie beendet werden, ausser du empfängst ein Zeichen wodurch 
der Mainloop etwas länger dauert (und die AD-Wandlung genügend Zeit 
hat).

Starte nur eine neue AD-Wandlung, wenn die alte bereits abgeschlossen 
ist.
Etwa so:
   while(true)
   {
      if(adc_done())
         read_adc(ADC_START_ONLY);  
      //************************************
      if(kbhit())
         empfangen = getc();
      pos = empfangen - 60; 
      //************************************
   }

freundliche Grüsse
unid

Autor: dewey (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo,

Ich habe mit dem Befehl adc_done() ein kleines Problem!

Mein Compiler sagt, dass er diesen Befehl nicht kennt!

Liegt das an meiner Compiler Version?

Ich habe PCB version 3.187
         PCM version 3.187
         PCH version 3.187

Danke schon im Voraus!

mfg dewey

Autor: unid (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Keine Ahnung, dass kann ich dir nicht sagen. Probiere es einmal manuell:

Definiere am Anfang:
#bit     AD_GO    = 0x1F.2

Die Abfrage machst du anschliessend so:
if(AD_GO)
  read_adc(ADC_START_ONLY);

mfg

Autor: dewey (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo,

Habe jetzt die Änderungen vorgenommen! Doch leider funktioniert es auch 
nicht!
Die Servos kann ich problemlos steuern! Am PC wird mir nichts angezeigt!
Ich soll ja keine printfs in einer isr verwenden! jetzt ist die Frage 
wie ich es sonst machen soll.

Der Code sieht jetzt folgendermaßen aus und so funktioniert es leider 
auch nicht:
#include <16F877a.h>
#device ADC=10      //10bit Auflösung
#use delay (clock=20000000)
#fuses HS, NOWDT, NOPROTECT, NOLVP
#use RS232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#include <stdlib.h>
#bit     AD_GO    = 0x1F.2

int8 servopos;
int8 zaehler = 0;
char empfangen;
int16 ad_wert=0;
int8 a=0;

#INT_TIMER2
void timer2overflow()
{
   zaehler++;
   if(zaehler == 180)
   {
      zaehler = 0;
      output_b(0x07);    
   }
   if(zaehler == servopos)
   {
      output_low(PIN_B0);
      output_low(PIN_B1);
      output_low(PIN_B2);
   }          
}

#INT_AD
void read_advalue()
{
   ad_wert = read_adc(ADC_READ_ONLY);
   a=1;
}

void main (void)
{
   setup_timer_2(T2_DIV_BY_4, 125, 1);
   set_timer2(0);

   setup_timer_0(RTCC_DIV_32 | RTCC_INTERNAL);
   set_timer0(0);

   setup_adc( ADC_CLOCK_INTERNAL );
   setup_adc_ports( ALL_ANALOG );
   set_adc_channel(0);

   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER2);
   enable_interrupts(INT_AD);
   
   
   while(true)
   {  
      if(AD_GO)
         read_adc(ADC_START_ONLY);  
            
      if(a == 1)
      {
         printf("\fADWert: %ld\n", ad_wert);
         a = 0;
      }
      if(kbhit()) empfangen = getc();
      servopos = (empfangen - 60);  
      
   }
} 

mfg dewey

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.