Forum: Mikrocontroller und Digitale Elektronik SPI funktioniert nicht


von Helge S. (freestila)


Lesenswert?

Hallo zusammen,

ich versuche mich gerade an SPI. Dabei nutze ich einen Arduino Mega als 
Master und einen Atmega8 als Slave.

SS, SCK, MISO und MOSI sind angeschlossen. der Slave-code lautet
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/signal.h>
4
#ifndef F_CPU
5
#define F_CPU    16000000
6
#endif
7
#include <util/delay.h>
8
9
 
10
 //FUSE ATMEGA 8 16Mhz: hfsue C9, Lfuse FF
11
 
12
 volatile unsigned char data;
13
 unsigned char status;
14
   unsigned char receive(void){
15
     //warten
16
  //   SPDR = 1;
17
     while(!(SPSR & (1<<SPIF)));
18
     //im Sendepuffer steht jetzt empfangenes Byte
19
     return SPDR;
20
   }
21
   
22
   ISR (SIG_SPI) {
23
   //  PORTC ^= ( 1 << PC1 ); 
24
   if (status == 1){
25
     PORTC &=~(1<<PC1);
26
     status  = 0;
27
   } else {
28
     PORTC |=(1<<PC1);
29
     status  = 1;
30
   }       
31
     //data = SPDR;
32
     data = receive();
33
     if (data == '1'){  PORTC |= (1 << PC0) ;}    //LEDs an
34
   //  if (data == '0')  PORTC &= ~(1 << PC0) ;      //LEDs aus
35
   else {  PORTC &= ~(1 << PC0) ;}
36
   }
37
 
38
39
 void slave_init (void) {
40
  // DDRB |= _BV(PB4);              //MISO als Ausgang, der Rest als Eingang
41
  DDRB  |= ( 1 << PB4 );    
42
  // SPCR = _BV(SPE) | _BV(SPIE);        //Aktivierung des SPI + Interrupt
43
  //Einstellungen des SPI-Control Register
44
45
  SPCR = (1<<SPE)   // SPE=1 (Freigabe der SPI-Schnittstelle)
46
  |(0<<DORD) // DORD=0: Data Order MSB
47
  |(0<<MSTR)  //MSTR=1 (ATMega als Master definiert)
48
  |(0<<CPOL)   //SPI-Modus CPOL=0 und CPHA=1 (gesendete Bits werden bei fallender Flanke des SPI-Clocks SCK übernommen)
49
  |(0<<CPHA)   //SPI-Modus CPOL=0 und CPHA=1 (gesendete Bits werden bei fallender Flanke des SPI-Clocks SCK übernommen)
50
  //|(1<<SPR0);  //Übertragungsfrequenz der Daen wir auf fosc / 16 eingestellt
51
  |(1<<SPIE); // Interrupt aktivieren
52
   status = 1;                //Status löschen
53
54
55
//PD3 / Int1 als Interrupt für Slave select
56
57
 }
58
  
59
60
 
61
62
63
 int main (void) {
64
//return blink();
65
   DDRD = 0xff;
66
  
67
68
    DDRB |= ( 1 << PB0 );        // PB0 an PORTB als Ausgang setzen
69
    DDRC |= ( 1 << PC0 );        // PB0 an PORTB als Ausgang setzen
70
    DDRC |= ( 1 << PC1 );        // PB0 an PORTB als Ausgang setzen
71
     slave_init ();
72
     sei();
73
  //   
74
    
75
      PORTC |= (1 << PC1) ;
76
     PORTC |= (1 << PC0) ;
77
    // return blink();
78
  while( 1 ) {                // Endlosschleife
79
  PORTB ^= ( 1 << PB0 );  // Toggle PB0 z.B. angeschlossene LED
80
  _delay_ms(1000);        // Eine Sekunde +/-1/10000 Sekunde warten...
81
  }  
82
   return 0;
83
 }

Auf Arduino-Seite sende ich entweder eine 0 oder eine 1.

Leider klappt es nicht ganz. Ich muss merhmals eine 0 senden, dann erst 
geht pc0 aus. und erst ein oder zwei sendungen später wechselt PC1. 
Irgendwas stimmt da also nicht.
Auch das SS funktioniert nicht 100%. Ich hab SS direkt auf ground 
gesetzt, dann hat es am betsen funktioniert.

Hat einer eine Idee?

Der Arduino code ist:
1
//  50 (MISO), 51 (MOSI), 52 (SCK), and 53 (SS). 
2
//The full code is in library example file Quick_tour.ino
3
#include <Wire.h>
4
#include <LCD.h>
5
#include <LiquidCrystal.h>
6
#include <buttons.h>
7
#include <MENWIZ.h>
8
#include <EEPROM.h>
9
#include <SPI.h>
10
11
int  adc_key_val[5] ={30, 150, 360, 535, 760 };
12
//int button_codes[5]={MW_BTR,MW_BTU,MW_BTD,MW_BTL,MW_BTC};
13
int button_codes[5]={MW_BTR,MW_BTU,MW_BTD,MW_BTE,MW_BTC};
14
int NUM_KEYS = 5;
15
int adc_key_in;
16
int key=-1;
17
int oldkey=-1;
18
19
const int slaveSelectPin = 53;
20
21
menwiz tree;
22
// create lcd obj using LiquidCrystal lib
23
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
24
25
int  list,sp=110;
26
int  mem;
27
 
28
void setup(){
29
  _menu *r,*s1,*s2;
30
mem=tree.freeRam();
31
  Serial.begin(9600);    
32
    Serial.println("ASCII Table ~ Character Map"); 
33
  tree.begin(&lcd,16,2); //declare lcd object and screen size to menwiz lib
34
35
  r=tree.addMenu(MW_ROOT,NULL,F("Einstellungen"));
36
    s1=tree.addMenu(MW_SUBMENU,r, F("Node 1"));
37
      s2=tree.addMenu(MW_VAR,s1, F("Node3"));
38
        s2->addVar(MW_LIST,&list);
39
        s2->addItem(MW_LIST, F("Option1"));
40
        s2->addItem(MW_LIST, F("Option2"));
41
        s2->addItem(MW_LIST, F("Option3"));
42
      s2=tree.addMenu(MW_VAR,s1, F("Node4"));
43
        s2->addVar(MW_AUTO_INT,&sp,0,120,10);  
44
    s1=tree.addMenu(MW_VAR,r, F("Sende an"));
45
      s1->addVar(MW_ACTION,sendeAn);
46
      s1=tree.addMenu(MW_VAR,r, F("Sende aus"));
47
      s1->addVar(MW_ACTION,sendeAus);
48
       tree.addUsrNav(&getPressedButton);
49
       tree.addUsrScreen(&menuMainCallBack, 5000);
50
         tree.addSplash((char *) tree.sbuf, 5000);
51
       
52
       sprintf(tree.sbuf,"Free mem. :%d\n.Used mem  :%d",tree.freeRam(),mem-tree.freeRam()); 
53
        // set the slaveSelectPin as an output:
54
  pinMode (slaveSelectPin, OUTPUT);
55
56
  // initialize SPI:
57
  SPI.begin(); 
58
    SPI.setBitOrder(MSBFIRST); 
59
SPI.setDataMode(1);
60
SPI.setClockDivider(SPI_CLOCK_DIV16);
61
  }
62
  
63
  int sendValue(int value){
64
    
65
     // take the SS pin low to select the chip:
66
  digitalWrite(slaveSelectPin,LOW);
67
  SPI.transfer(value);
68
  // take the SS pin high to de-select the chip:
69
  digitalWrite(slaveSelectPin,HIGH); 
70
}
71
72
void menuMainCallBack(){
73
 sprintf(tree.sbuf,"Uptime (s): %ld\nFree mem  : %d\n\n",millis()/1000,(int)tree.freeRam());
74
  tree.drawUsrScreen(tree.sbuf);
75
  
76
  
77
}
78
79
void loop(){
80
  tree.draw(); 
81
  }
82
83
void sendeAn(){
84
  Serial.println("Action an");
85
  sendValue(1);
86
  }
87
void sendeAus(){
88
  Serial.println("Action aus");
89
  sendValue(0);
90
  }
91
  
92
int getPressedButton(){
93
  
94
  adc_key_in = analogRead(0);    // read the value from the sensor  
95
  key = get_key(adc_key_in);            // convert into key press
96
  
97
  if (key != oldkey)            // if keypress is detected
98
  {
99
    delay(50);    // wait for debounce time
100
    adc_key_in = analogRead(0);    // read the value from the sensor  
101
    key = get_key(adc_key_in);            // convert into key press
102
    if (key != oldkey)        
103
    {      
104
      oldkey = key;
105
      if (key >=0){
106
        Serial.println("Pressed Button ");
107
        Serial.println(key);
108
        Serial.println(": ");
109
        Serial.println(button_codes[key]); 
110
      return button_codes[key];
111
     }
112
     
113
    }
114
  }
115
  return MW_BTNULL;
116
117
  
118
  
119
}
120
121
  
122
  
123
// Convert ADC value to key number
124
int get_key(unsigned int input)
125
{
126
  int k;
127
    
128
  for (k = 0; k < NUM_KEYS; k++)
129
  {
130
    if (input < adc_key_val[k])
131
    {
132
           
133
    return k;
134
        }
135
  }
136
    
137
    if (k >= NUM_KEYS)
138
        k = -1;     // No valid key pressed
139
    
140
    return k;
141
}

von Stefan F. (sfrings)


Lesenswert?

Benutze als Master oder Slave ein Gerät, dass sich bisher bewährt hat.

Du probierts gerade zwei neue Programme und hast daher nichteinmal eine 
Ahnung, welches der beiden fehlerhaft ist.

Hast Du einen Hardwarefehler ausschließen können? Wenn nicht, würde ich 
mich erstmal darum kümmern. Und dann als zweiten Schritt ein bekanntest 
funktionierendes Bauteil verwenden, z.B. einen einfachen A/D Wandler 
oder ein Schieberegister.

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.