Frage zu PIC ADC Wandler!

Gast #927234
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
#927244
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);
Gast #927270
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
Gast #934564
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
Gast #935430
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
Gast #935886
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
Gast #936002
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
Gast #936062
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

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