PIC16F886 resetet sich selbstständig beim ADC auslesen

Gast #5736176
Lesenswert?

Moin Leute,

leider habe ich ein Problem mit meinem PIC. Dieser resetet sich 
automatisch, sobald ich
1
return ((ADRESH<<8)+ADRESL);
 ausführe. Leider finde ich keine wirkliche Ursache dafür. Kann mir 
jemand helfen?

Vielen Dank.
1
#pragma config FOSC = XT        // Oscillator Selection bits (XT oscillator)
2
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
3
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
4
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
5
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) 
6
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit 
7
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits 
8
#pragma config CP = OFF         // Flash Program Memory Code Protection bit 
9
 
10
#define _XTAL_FREQ 8000000  
11
#include "xc.h"
12

13
int result;
14

15
void InitPWM(){
16
    
17
    CCP1CON = 0b00001100;
18
    CCP2CON = 0b00111100;
19
    PSTRCON = 0b00000100;
20
    CCPR1L = 40;
21
    CCPR1H = 0x00;
22
}
23

24
void InitTMR2(){
25
    
26
    T2CON=0b01111100; 
27
    PR2=100;            //100 us
28
    TMR2=0;
29
    TMR2IF = 0;
30
    TMR2ON = 1;
31
}
32

33
void InitADC()
34
{
35
  ADCON0 = 0x11000000;
36
  ADCON1 = 0b10000000; 
37
  ADCON0bits.ADON = 1;
38
  __delay_ms(10);
39
}
40

41

42

43
int ADC_Read(unsigned char channel)
44
{
45
  __delay_ms(2); 
46
  GO_nDONE = 1; 
47
  while(GO_nDONE); 
48
  return ((ADRESH<<8)+ADRESL); 
49
}
50

51
int main(void) {
52
    
53
    OSCCON = 0x66; //Interner Oszi
54
    
55
    int dc = 0;
56
    int a = 0;
57
    
58
    TRISA = PORTA = TRISB = PORTB = TRISC = PORTB =0x00;
59
    ANSEL = 0x01;
60
    
61
    TRISBbits.TRISB1=0;
62
    PORTBbits.RB1=0;
63
    
64
    TRISAbits.TRISA0=1;
65
    PORTAbits.RA0=1;
66
    
67
    TRISCbits.TRISC2=0;
68
    PORTCbits.RC2=0;
69
    TRISCbits.TRISC3=0;
70
    PORTCbits.RC3=0;
71
    TRISCbits.TRISC4=0;
72
    PORTCbits.RC4=0;
73
    
74
    TRISAbits.TRISA1=0;
75
    PORTAbits.RA1=0;
76
    TRISAbits.TRISA2=0;
77
    PORTAbits.RA2=0;
78
    TRISAbits.TRISA5=0;
79
    PORTAbits.RA5=0;
80
    
81
    INTCON = 0;
82
    PIE1   = 0;
83
    PIE2   = 0;
84
    
85
    InitTMR2();
86
    InitPWM();
87
    InitADC();
88
    
89
    while(1){
90
        
91
        PORTCbits.RC4 = 1;
92
        PORTAbits.RA2 = 1;
93

94
        result = ADC_Read(0); //Analog Channel 0
95
        
96
        for (dc = 0; dc < 17; dc++) 
97
        {
98
            CCPR1L = dc;
99
            CCPR2L = 17-dc;
100
            __delay_ms(100);
101
        }
102

103
        for (dc = 16; dc > 0; dc--) 
104
        {
105
            CCPR1L = dc;
106
            CCPR2L = 17-dc;
107
            __delay_ms(100);
108
}
109
        
110
}
#5736224
Lesenswert?

ThinkPic schrieb:
> leider habe ich ein Problem mit meinem PIC. Dieser resetet sich
> automatisch, sobald ich
1
return ((ADRESH<<8)+ADRESL);
> ausführe.

Das scheint mir eh irgendwie falsch. Was soll das denn tun?
Hast du schon mal return ADRES; getestet? Könnte funktionieren.

Woher weißt du, dass es genau an dieser Zeile liegt? Debugger?

(ADRESH<<8 gibt vermutlich immer 0, warum das einen Reset auslösen 
solle, weiß ich allerdings auch nicht)
Gast #5736315
Lesenswert?

ThinkPic schrieb:
> int ADC_Read(unsigned char channel)
..
> return ((ADRESH<<8)+ADRESL);

Solche Konstrukte würde ich lieber sein lassen. Der Compiler muss für 
den return Wert vor dem Interrupt Speicher reservieren. Ob es das macht?

1
global Irgend_nTyp InterrupReturnValue;
2

3
void InterruptRoutine(Irgend_nTyp Irgend_nVarname) {
4

5
   InterrupReturnValue = RegisterXY
6

7
}

Funzt bei mir zuverlässig.
Gast #5736838
Lesenswert?

Moin,

ich bin mir nicht sicher, ob es direkt an der Zeile liegt. Im Debugger 
lande ich danach immer direkt wieder an den Anfang der Main.

Leider scheint der ADC aktuell gar nicht zu funktionieren. Ich bekomme 
immer als return 0x0000. Auch wenn ich
1
result = ((ADRESH<<8)+ADRESL); //Returns Result
 mache.

Ist meine ADC Konfiguration falsch? Möchte VDD als Ref verwenden und A0 
als Input.
Gast #5736839
Lesenswert?

Volker S. schrieb:
> ThinkPic schrieb:
>> leider habe ich ein Problem mit meinem PIC. Dieser resetet sich
>> automatisch, sobald ichreturn ((ADRESH<<8)+ADRESL);> ausführe.
>
> Das scheint mir eh irgendwie falsch. Was soll das denn tun?
> Hast du schon mal return ADRES; getestet? Könnte funktionieren.
>
> Woher weißt du, dass es genau an dieser Zeile liegt? Debugger?
>
> (ADRESH<<8 gibt vermutlich immer 0, warum das einen Reset auslösen
> solle, weiß ich allerdings auch nicht)

Return ADRES funktioniert nicht. Kennt der Compiler nicht.
#5736961
Lesenswert?

HyperMario schrieb:
> Weil es kein ADRES Register gibt.

Oft hat aber jemand dem Compiler gesagt, was es bedeutet.
#define ADRES *(uint_16t*)(&ADRESL) oder so ähnlich

Das geht beim 16F886 leider nicht, weil die Register nicht 
dementsprechend liegen. Bei den neueren funktioniert es vermutlich 
immer.

@ThinkPIC
setz doch mal einen Breakpoint auf den Resetvector, bzw. den 
Interruptvector (im Program Memory View) und schau, ob er vielleicht 
dahin springt.

Oder setz den Breakpoint auf das return, und geh dann im Single Step 
weiter.
(single step auch im Program Memory View)

Wenn das (ADRESH<<8) später immer 0 liefert, dann probier 
((uint16_t)ADRESH)<<8)
#5737075
Lesenswert?

Peter D. schrieb:
> ThinkPic schrieb:
>> GO_nDONE = 1;
>>   while(GO_nDONE);
>
> Vermutlich wird GO_nDONE niemals auf 0 gesetzt, d.h. Endlosschleife und
> irgendwann schlägt der Watchdogreset zu.

Würde ich auch schätzen.

ThinkPic schrieb:
> int ADC_Read(unsigned char channel)
> {
>   __delay_ms(2);
>   GO_nDONE = 1;
>   while(GO_nDONE);
>   return ((ADRESH<<8)+ADRESL);
> }

Finde ich sowieso etwas speziell. Normalerweise startet man doch eine 
Messung über ein ADC Flag und wartet bis der ADC ein Done Flag setzt. 
Oder das ganze ist im Freilauf. Aber selber irgendwelche Flags 
erfinden...
#5737076
Lesenswert?

Peter D. schrieb:
> Vermutlich wird GO_nDONE niemals auf 0 gesetzt, d.h. Endlosschleife und
> irgendwann schlägt der Watchdogreset zu.

ThinkPic schrieb:
> #pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT
> disabled)


Wenn der ADC richtig konfiguriert wurde, dann geht GO_nDONE nach 
erfolgter Wandlung wieder auf 0

ThinkPic schrieb:
> ADCON0 = 0x11000000;

Weiß zwar nicht, warum eine falsche Konfiguration einen RESET auslösen 
sollte, aber mach mal trotzdem das x zu einem b ;-)



Patrick B. schrieb:
> Aber selber irgendwelche Flags erfinden...

Wie kommst du jetzt darauf? Noch nie PICs programmiert?



####################################################################
Ich bin weiterhin für Debuggen!

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