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


von dewey (Gast)


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!
1
#include <16F877a.h>
2
#device ADC=10      //10bit Auflösung
3
#use delay (clock=20000000)
4
#fuses HS, NOWDT, NOPROTECT, NOLVP
5
#use RS232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
6
#include <stdlib.h>
7
8
int8 pos;
9
int8 zaehler = 0;
10
int16 ad_wert;
11
float messwert;  
12
13
/*******************************************************/
14
/*          Timer2 - Interrupt Routine                 */
15
/*    Aufruf: alle 0,1ms                               */
16
/*    Funktion: Servoansteuerung                       */
17
/*    Datum: 14.07.08                                  */
18
/*******************************************************/
19
#INT_TIMER2
20
void timer2overflow()
21
{
22
   zaehler++;
23
   
24
   if(zaehler == 180)
25
   {
26
     zaehler = 0;
27
     output_high(PIN_C2);
28
   }
29
   if(zaehler == pos)
30
     output_low(PIN_C2);   
31
}
32
33
#INT_AD
34
void ad_handler()
35
{
36
      
37
      
38
      ad_wert = read_adc();
39
      messwert = ad_wert/1023.0 * 5; // AD Wert 0-5V; Betriebsspannung
40
      printf("\fADWert: %1.4f\n", messwert);
41
42
}
43
44
void main (void)
45
{
46
   char empfangen; 
47
   
48
 
49
   setup_timer_2(T2_DIV_BY_4, 125, 1);
50
   set_timer2(0);
51
   
52
   setup_adc( ADC_CLOCK_INTERNAL );
53
   setup_adc_ports( ALL_ANALOG );
54
   set_adc_channel(0);
55
   enable_interrupts(INT_TIMER2);
56
   enable_interrupts(INT_AD);
57
   enable_interrupts(GLOBAL);
58
    
59
   while(true)
60
   {  
61
      //************************************
62
      if(kbhit())
63
         empfangen = getc();
64
      pos = empfangen - 60; 
65
      //************************************
66
      
67
   }
68
}

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

von Εrnst B. (ernst)


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
1
ad_wert=read_adc(ADC_READ_ONLY);
und im Hauptprogramm ein (oder mehrere)
1
 read_adc(ADC_START_ONLY);

von Timmo H. (masterfx)


Lesenswert?

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

von dewey (Gast)


Lesenswert?

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

mfg dewey

von dewey (Gast)


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

von unid (Gast)


Lesenswert?

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

von dewey (Gast)


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!
1
#include <16F877a.h>
2
#device ADC=10      //10bit Auflösung
3
#use delay (clock=20000000)
4
#fuses HS, NOWDT, NOPROTECT, NOLVP
5
#use RS232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
6
#include <stdlib.h>
7
8
int8 pos;
9
int8 zaehler = 0;
10
int16 ad_wert;
11
float messwert;  
12
13
/*******************************************************/
14
/*          Timer2 - Interrupt Routine                 */
15
/*    Aufruf: alle 0,1ms                               */
16
/*    Funktion: Servoansteuerung                       */
17
/*    Datum: 14.07.08                                  */
18
/*******************************************************/
19
#INT_TIMER2
20
void timer2overflow()
21
{
22
   zaehler++;
23
   
24
   if(zaehler == 180)
25
   {
26
     zaehler = 0;
27
     output_high(PIN_C2);
28
   }
29
   if(zaehler == pos)
30
     output_low(PIN_C2);   
31
}
32
33
#INT_AD
34
void ad_handler()
35
{
36
      
37
      
38
      ad_wert = read_adc(ADC_READ_ONLY);
39
      messwert = ad_wert/1023.0 * 5; // AD Wert 0-5V; Betriebsspannung
40
      printf("\fADWert: %1.4f\n", messwert);
41
42
}
43
44
void main (void)
45
{
46
   char empfangen; 
47
   
48
 
49
   setup_timer_2(T2_DIV_BY_4, 125, 1);
50
   set_timer2(0);
51
   
52
   setup_adc( ADC_CLOCK_INTERNAL );
53
   setup_adc_ports( ALL_ANALOG );
54
   set_adc_channel(0);
55
   enable_interrupts(INT_TIMER2);
56
   enable_interrupts(INT_AD);
57
   enable_interrupts(GLOBAL);
58
    
59
   while(true)
60
   {
61
      read_adc(ADC_START_ONLY);  
62
      //************************************
63
      if(kbhit())
64
         empfangen = getc();
65
      pos = empfangen - 60; 
66
      //************************************
67
      
68
   }
69
}

Danke schon im Voraus!

mfg dewey

von ... .. (docean) Benutzerseite


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...

von unid (Gast)


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:
1
   while(true)
2
   {
3
      if(adc_done())
4
         read_adc(ADC_START_ONLY);  
5
      //************************************
6
      if(kbhit())
7
         empfangen = getc();
8
      pos = empfangen - 60; 
9
      //************************************
10
   }

freundliche Grüsse
unid

von dewey (Gast)


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

von unid (Gast)


Lesenswert?

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

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

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

mfg

von dewey (Gast)


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:
1
#include <16F877a.h>
2
#device ADC=10      //10bit Auflösung
3
#use delay (clock=20000000)
4
#fuses HS, NOWDT, NOPROTECT, NOLVP
5
#use RS232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
6
#include <stdlib.h>
7
#bit     AD_GO    = 0x1F.2
8
9
int8 servopos;
10
int8 zaehler = 0;
11
char empfangen;
12
int16 ad_wert=0;
13
int8 a=0;
14
15
#INT_TIMER2
16
void timer2overflow()
17
{
18
   zaehler++;
19
   if(zaehler == 180)
20
   {
21
      zaehler = 0;
22
      output_b(0x07);    
23
   }
24
   if(zaehler == servopos)
25
   {
26
      output_low(PIN_B0);
27
      output_low(PIN_B1);
28
      output_low(PIN_B2);
29
   }          
30
}
31
32
#INT_AD
33
void read_advalue()
34
{
35
   ad_wert = read_adc(ADC_READ_ONLY);
36
   a=1;
37
}
38
39
void main (void)
40
{
41
   setup_timer_2(T2_DIV_BY_4, 125, 1);
42
   set_timer2(0);
43
44
   setup_timer_0(RTCC_DIV_32 | RTCC_INTERNAL);
45
   set_timer0(0);
46
47
   setup_adc( ADC_CLOCK_INTERNAL );
48
   setup_adc_ports( ALL_ANALOG );
49
   set_adc_channel(0);
50
51
   enable_interrupts(GLOBAL);
52
   enable_interrupts(INT_TIMER2);
53
   enable_interrupts(INT_AD);
54
   
55
   
56
   while(true)
57
   {  
58
      if(AD_GO)
59
         read_adc(ADC_START_ONLY);  
60
            
61
      if(a == 1)
62
      {
63
         printf("\fADWert: %ld\n", ad_wert);
64
         a = 0;
65
      }
66
      if(kbhit()) empfangen = getc();
67
      servopos = (empfangen - 60);  
68
      
69
   }
70
}

mfg dewey

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.