Forum: Mikrocontroller und Digitale Elektronik Interrupt mit PIC18F27J13


von Salade P. (Gast)


Lesenswert?

Hallo Leute,
ich bin ganz neu bei diesem forum. Ich wollte einen Interrupt mit dem 
PIC18F27J13 programmieren aber ich bekomme fehlermeldungen. Ich möchte 
daten über SPI senden wenn ein Interrupt da ist aber davor sollten der 
Akkumulator Status und BSR vorher geretet werden. Das Programm habe ich 
wie folgt geschrieben:

#define    USE_OR_MASKS

#include <stdio.h>
#include <stdlib.h>
#include <pconfig.h>
#include <xc.h>
#include <plib/adc.h>
#include "adc.h"
#include <plib/spi.h>
#include "spi.h"
#include <pic18f27j13.h>

#pragma config CONFIG1L = 0x2C
#pragma config CONFIG1H = 0x4
#pragma config CONFIG2L = 0x0A
#pragma config CONFIG2H = 0xF
#pragma config CONFIG3L = 0xFF
#pragma config CONFIG3H = 0x8
#pragma config CONFIG4L = 0xFF
#pragma config CONFIG4H = 0x3
unsigned char W_TEMP = 0x00;
unsigned char STATUS_TEMP = 0x00;
unsigned char BSR_TEMP = 0x00;
unsigned char DATA_TO_SPI2[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00 };

void high_isr(void);
/*asm(" W_TEMP      SET    0h");
asm(" BSR_TEMP      SET    0h");
asm(" STATUS_TEMP     SET    0h");
*/
#pragma code high_vector = 0x08
void interrupt_at_high_vector(void)
{
_asm
goto high_isr
_endasm
}

#pragma code
#pragma interrupt high_isr
void high_isr(void)
{
_asm{
  MOVWF _W_TEMP
  MOVFF STATUS, _STATUS_TEMP
  MOVFF BSR, _BSR_TEMP ;
}
for(unsigned int n=0; n<2; ++n)
{
if(INTCONbits.TMR0IF && INTCONbits.TMR0IE)
{
getsSPI2(info, 1);
INTCONbits.TMR0IF = 0;
INTCONbits.TMR0IE = 0;
if((info[0] & 0x60) == 0x20)
{
if(INTCONbits.TMR0IF && INTCONbits.TMR0IE)
{
WriteSPI2(DATA_TO_SPI2[(n + 2*((info & 0x18) >> 3))]);
while(PIR3bits.SSP2IF != 1);
INTCONbits.TMR0IF = 0;
INTCONbits.TMR0IE = 0;
}
}
}
}

_asm{
MOVFF _BSR_TEMP, BSR
MOVF _W_TEMP, W
MOVFF _STATUS_TEMP, STATUS
}
}

Das sind die Fehlermeldungen.

Build C:\interrupt for device 18F27J13
Using driver C:\Program Files\Microchip\xc8\v1.12\bin\xc8.exe

Make: The target "C:\interrupt.p1" is out of date.
Executing: "C:\Program Files\Microchip\xc8\v1.12\bin\xc8.exe" --pass1 
C:\interrupt.c -q --chip=18F27J13 -P --runtime=default --opt=default 
-N-1 -D__DEBUG=1 -g --asmlist "--errformat=Error   [%n] %f; %l.%c %s" 
"--msgformat=Advisory[%n] %s" "--warnformat=Warning [%n] %f; %l.%c %s"
Warning [335] C:\interrupt.c; 36.1 unknown pragma "code"
Error   [195] C:\\interrupt.c; 39.1 expression syntax
Error   [312] C:interrupt.c; 42.1 ";" expected
Warning [335] C:\interrupt.c; 44.1 unknown pragma "code"
Warning [335] C:\interrupt.c; 45.1 unknown pragma "interrupt"
Error   [195] C:\interrupt.c; 48.1 expression syntax
Error   [285] C:\interrupt.c; 53.1 no identifier in declaration
Warning [374] C:\interrupt.c; 53.1 missing basic type; int assumed
Error   [314] C:\interrupt.c; 53.1 ";" expected
Warning [374] C:\interrupt.c; 53.24 missing basic type; int assumed
Error   [314] C:\interrupt.c; 53.24 ";" expected
Error   [285] C:\interrupt.c; 53.28 no identifier in declaration
Warning [374] C:\interrupt.c; 53.28 missing basic type; int assumed
Error   [314] C:\interrupt.c; 53.28 ";" expected
Warning [374] C:\interrupt.c; 58.11 missing basic type; int assumed
Error   [984] C:\interrupt.c; 58.11 type redeclared
Error   [1098] C:\interrupt.c; 58.11 conflicting declarations for 
variable "INTCONbits" (C:\Program 
Files\Microchip\xc8\v1.12\include\pic18f27j13.h:15907)
(908) exit status = 1

********** Build failed! **********


kann mir jemandem Helfen? Ich brauche dringend bitte Hilfe.
Danke

von B. S. (bestucki)


Lesenswert?

Im Manual zum XC8 Compiler steht, wie man Interrupts verwendet. Ist 
glaube ich nicht so, wie du das gelöst hast (hab jetzt nicht 
nachgeschaut). In den Fehlermeldungen steht ja schon, dass er einige 
pragmas nicht kennt.

Noch ein Tipp: Wenn du globale Variablen in Interruptfunktionen 
verwendest, deklariere sie als volatile.

von Salade P. (Gast)


Lesenswert?

Hallo,
danke für deine Antwort hab nachgeschaut und hat viel geholfen.
Aber wenn ich die variable als volatile deklariere bekomme ich folgenden 
Fehlermeldungen:

Warning [359] C:\code.c; 63.14 illegal conversion between pointer types
pointer to volatile unsigned char -> pointer to unsigned char

von Salade P. (Gast)


Lesenswert?

ich brauche glaube ich zwei interrupts:
eins der mir meldet, dass der Master das read command gesendet hat weil 
der Master verschiedene Daten senden kann und zwar jeder Zeit,
eins der das Laufen des gesamten Programms unterbricht und die daten 
über SPI senden. ich habe dann die interrupts so geschrieben:

volatile unsigned char info[1] = { 0x00 };
volatile unsigned char data_send[4] = { 0xAB, 0x48, 0x69, 0x00};

void interrupt isrmssp2(void)
{
if(PIR3bits.SSP2IF &&  PIE3bits.SSP2IE)
{
getsSPI2(info, 1);
if(((unsigned char)info[0] & 0x60) == 0x20)
{
TMR0IF = 1;
TMR0IE = 1;
return;
}
}
}

void interrupt isr(void)
{
if(TMR0IF && TMR0IE)
{
TMR0IF = 0;
putsSPI2((unsigned char *)data_send);
return;
}
}

void main()
{
RCONbits.IPEN = 0;
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;
T0CONbits.T08BIT = 0;
T0CONbits.T0CS = 0;
T0CONbits.PSA = 0;
T0CONbits.TMR0ON = 1;
INTCON2bits.INTEDG0 = 1;
INTCONbits.GIE = 1;
}

aber wenn ich die empfangenen Daten des Masters anschaue, dann sind sie 
falsch. Was mache ich bitte da falsch?

von B. S. (bestucki)


Lesenswert?

Ist das dein gesamtes Programm? Ich weiss nicht was passiert, wenn das 
main verlassen wird. Also besser noch eine Endlosschleife einfügen.

Geht er in die richtige Interruptroutine rein, wenn der Master Daten 
sendet? Du sagst, die Daten sind falsch. Was erwartest du und was kommt 
raus? Wie stellst du die empfangenden Daten dar?


Es erscheint mir auch komisch, dass du das Timer0 Interrupt manuell 
auslöst. Evt. geht dort etwas schief.

salade Poisson schrieb:
> TMR0IF = 1;
> TMR0IE = 1;

Müsste wohl heissen:
INTCONbits.TMR0IF = 1;
INTCONbits.TMR0IE = 1;

von Salade P. (Gast)


Lesenswert?

Das Programm das ich geschrieben habe sieht so aus:
#define    USE_OR_MASKS

#include <stdio.h>
#include <stdlib.h>
#include<pconfig.h>
#include <xc.h>
#include <plib/spi.h>
#include "spi.h"
#include <pic18f27j13.h>
#include <math.h>

#pragma config CONFIG1L = 0x2C
#pragma config CONFIG1H = 0x4
#pragma config CONFIG2L = 0x0A
#pragma config CONFIG2H = 0xF
#pragma config CONFIG3H = 0x8
#pragma config CONFIG4L = 0xFF
#pragma config CONFIG4H = 0x3

unsigned char count = 0x00;
unsigned char data_rcv[1] = { 0x00 };
unsigned char data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xAA, 0xAB, 
0xCD, 0xFA, 0xBD, 0xE5 };

void Set_SPI(void)
{
unsigned char sync_mode_SPI = 0;
unsigned char bus_mode_SPI = 0;
unsigned char smp_mode_SPI = 0;
RPINR21 = 7;
RPINR22 = 6;
RPINR23 = 8;
RPOR5 = 10;

ANCON1bits.PCFG8 = 1;
ANCON1bits.PCFG9 = 1;
TRISBbits.TRISB2 = 0;
TRISBbits.TRISB3 = 1;
TRISBbits.TRISB4 = 1;
TRISBbits.TRISB5 = 1;
sync_mode_SPI = SLV_SSON;
bus_mode_SPI = MODE_01;
smp_mode_SPI = SMPMID;
OpenSPI2(sync_mode_SPI, bus_mode_SPI, smp_mode_SPI);
}

void initPIC (void)
{
OSCCONbits.SCS = 0b11;
OSCCONbits.IRCF = 0b110;
RCONbits.IPEN = 0;
INTCONbits.PEIE = 1;
T0CONbits.T08BIT = 1;
T0CONbits.T0CS = 0;
T0CONbits.PSA = 0;
T0CONbits.T0PS = 0b111;
INTCON2bits.INTEDG0 = 1;
INTCONbits.GIE = 1;
INTCONbits.GIE = 1;
T0CONbits.TMR0ON = 1;
PIE3bits.SSP2IE = 1;
}


void interrupt int(void)
{
if(INTCONbits.TMR0IF && INTCONbits.TMR0IE)
{
TMR0IF = 0;
WriteSPI2(data[(unsigned int)count]);
while(PIR3bits.SSP2IF != 1);
if(count == 11)
{
count = 0;
}
else{
count++;
}
return;
}
}

void interrupt isr(void)
{
if(PIR3bits.SSP2IF && PIE3bits.SSP2IE)
{
getsSPI2(data_rcv, 1);
PIR3bits.SSP2IF = 0;
if(data_rcv[0] == 0x20)
{
INTCONbits.TMR0IE = 1;
return;
}
}
}

void main (void)
{
Set_SPI();
initPIC();
for(;;)
{
;
}
}

und der master bekommt immer die selbe daten. Die Funktion mit dem 
interrupt int funktioniert schön weil wenn ich das count incrementiere 
und dann data[count] am Master sende, dann bekomme ich die soll-daten 
aber wenn ich das wie oben schreibe dann sendet der Master immer 0xFE
Er geht eigentlich nicht in die funktion isr rein. hast du ne Idee 
warum?

von Salade P. (Gast)


Lesenswert?

hallo,
wie kann ich merken dass daten über SPI liegen? brauche ich dafür einen 
Interrupt zu programmieren der ausgelöst wird wenn daten über SPI 
liegen?

von Der Rächer der Transistormorde (Gast)


Lesenswert?

salade Poisson schrieb:
> brauche ich dafür einen
> Interrupt zu programmieren der ausgelöst wird wenn daten über SPI
> liegen?

Da gibt es irgendwo ein Bit in einem Register. Das wird gesetzt wenn 
Daten über die SPI angekommen sind. Ist der entsprechende Interrupt 
freigegeben wird er dann auch ausgelöst. Du kannst ihn aber auch sperren 
und per Programm abfragen.

Generell ist es beim PIC alle Interrupts zu einer Adresse springen (die 
zweite mal weggelassen). Beim Interrupt wird dann die Funktion die dort 
beginnt ausgeführt. Alle freigegebenen Interrupts abzuarbeiten und die 
Flags zurückzusetzen ist dann dein Job.

von Salade P. (Gast)


Lesenswert?

Hallo,
ich hab so ein problem:
ich wollte mein temperaturmesssystem kalibirieren. ich habe es gemacht 
aber das problem ist wenn ich keine Daten über SPI empfange oder sende 
dann funktioniert die Kalibrierung, aber wenn ich daten über SPI 
empfange dann funktioniert die Kalibrierung nicht mehr. Ich brauche dann 
eine neue Kalibrierung. Die SPI beeinflusst dann mein Ergebnis. Weiß 
jemand der Grund dafüR

von Erich (Gast)


Lesenswert?

Deine Fragen oder Probleme sind wohl nur zu lösen, wenn du auch die 
komplette Beschaltung deines uC veröffentlichst, insbesondere die SPI 
Signale und alle dort angeschlossenen Komponenten.
Vermutlich kommt sich was irgendwie "in die Quere".
Evt. solltest du die Funktionalitäten SPI erstmal ohne Interrupt-Nutzung 
herstellen. Ob für SPI der Interruptfunktionalität überhaupt sinnvoll 
ist kann man erst sehen wenn man das komplette System sieht, und auch 
die Datenraten bzw. Clockraten bekannt sind.
Für sporadische oder langsame (< 10 Hz) Abfrage eines Temperatursensors 
würde ich das nicht über Interrupt machen.
Gruss

von Salade P. (Gast)


Lesenswert?

Hallo
war mein Fehler. Hatte falsche Daten gesendet deshalb hatte er falsche
Rechnungen durchgeführt. Meine frage ist wie kann ich mit dem Interrupt
daten Auslesen und sie in einem Puffer schreiben? Ich lese Daten aus
aber ich habe den Eindruck dass er Sie nicht speicher. Ich hab es wie
folgt gemacht:

unsigned char info[1] = { 0x00 };
unsigned char data_rcv[5] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; //{ 0x67,
0x68, 0x77, 0x7F, 0x00 };
unsigned char data_send[11] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00 };

void interrupt isr5(void)
{
if(PIR3bits.SSP2IF && PIE3bits.SSP2IE)
{
getsSPI2(info, 1);
switch(info[0] & 0x78)
{
case 0x60:
data_rcv[0] = info[0];
break;

case 0x68:
data_rcv[1] = info[0];
break;

case 0x70:
data_rcv[2] = info[0];
break;

case 0x78:
data_rcv[3] = info[0];
break;

default:
break;
}

if((( info[0] & 0x60 ) == 0x40 ))
{
switch(((info[0] >> 3 ) & 0x03))
{
case 0x00:
data[1] = data_send[0];
data[0] = data_send[1];
break;

case 0x01:
data[1] = data_send[2];
data[0] = data_send[3];
break;

case 0x02:
data[1] = data_send[4];
data[0] = data_send[5];
break;

case 0x03:
data[1] = data_send[6];
data[0] = data_send[7];
break;

default:
data[1] = data_send[8];
data[0] = data_send[9];
break;
}
putsSPI2(data);
info[0] = 0x00;
}
return;
}
}
zum sehen ob der slave die Daten empfängt hab ich folgendes main
geschrieben:

void main (void)
{
float temp = 14450.0;
unsigned char nun = 0x00;
unsigned char configdata[5] = { 0x00, 0x00, 0x00, 0x00, 0x00 };

Set_SPI(2);
initPIC();
SSP2BUF =0;
RCONbits.IPEN = 0;
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;
PIR3bits.SSP2IF = 0;
IPR3bits.SSP2IP = 1;
PIE3bits.SSP2IE = 1;
for(unsigned int i=0; i<4; ++i)
{
num = ( data_rcv[i] >> 3 ) & 0x03;
switch(num)
{
case 0x00:
temp = temp / 2;
data_send[0] = ( signed int ) ( temp / 256 );
data_send[1] = ( signed int )temp%256;
break;

case 0x01:
temp = temp / 3;
data_send[2] = ( signed int ) ( temp / 256 );
data_send[3] = ( signed int ) temp%256;
break;

case 0x02:
temp = temp / 4;
data_send[4] = ( signed int ) ( temp / 256) ;
data_send[5] = ( signed int ) temp%256;
break;

case 0x03:
temp = temp / 5;
data_send[7] = ( signed int )Temperature%256;
break;

default:
temp = temp / 6;
data_send[8] =  ( signed int ) ( temp / 256 );
data_send[9] = ( signed int )temp%256;
break;
}
}
}
}while(1)
continue;
}
Wenn ich data mit Null initialisiere dann führt er keine Rechnung aus
und er sendet nur dummi daten an Master. Aber wenn ich den mit gultigen
Informationen initialisiere dann macht er die Rechnungen und er sendet
die Daten an Master wenn gefordert.

ich brauche die Daten vom Master auszulesen weill ich Sie Später für die
Berechnung verwenden soll. Weißt du woran es liegt

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.