Szenario
Ich habe einen ATMega168 mit einem externen 10-MHz-Quarz. Das Sicherungsbit DIV/8 ist nicht gesetzt. Der Prozessor übernimmt die Ausgänge von 4 Quadratur-Drehgebern. Ihre Drehrichtungsinformation wird mit Hilfe von Pinwechsel-Interrupts und den Pinzuständen dekodiert. Die Rotationsinformationen werden in Steuercodes umgewandelt und über SPI an einen anderen Prozessor gesendet, der einige Motorantriebe übernimmt.
Problem
In dem aufgelisteten Code werden die Drehrichtungsinformationen wie vorgesehen decodiert und in Steuercodes umgewandelt und in Hardware verifiziert. Die SPI-Übertragung startet nicht. Betrachtet man die SPI-Pins am Oszilloskop, bleibt der !SS-Pin hoch und SCK und MOSI bleiben niedrig.
Außer mir haben sich zwei andere Personen diesen Code angesehen. Ich weiß, dass ich etwas Einfaches übersehen muss. Warum startet die Übertragung nicht?
/*Ports:
D.7..D.0 - 4x quadrature rotary encoders, triggering pin change interrupts
B.5 - SCK (SPI clock line)
B.3 - MOSI(SPI data line)
B.2 - !SS (SPI chip select)
This module interfaces with the rotary encoders, converts their
rotation to control commands, and transfers these commands over
the serial peripheral interface to the motor controller.
*/
#define LASER_X_L 28
#define LASER_X_R 56
#define LASER_Y_D 84
#define LASER_Y_U 112
#define MIRROR_X_L 140
#define MIRROR_X_R 168
#define MIRROR_Y_D 196
#define MIRROR_Y_U 224
#define NOTHING 0
#include <avr/io.h>
#include <avr/interrupt.h>
void initPorts(void); //set up function for GPIO ports
void initExtInt(void); //set up function for external interrupts
void initSPI(void); //set up function for SPI
int main(void)
{
initPorts(); //call port set up function
initExtInt(); //call interrupt set up function
initSPI(); //call SPI set up function
while(1)
{
}
}
void initPorts(void)
{
DDRB = 0b00101100; //set SPI pins as outputs, unused pins as inputs
PORTB = 0b11010011; //pull unused pins high
DDRD = 0x00; //rotary encoder pins as inputs
PORTD = 0x00; //pull ups off
}
void initExtInt(void)
{
sei(); //global interrupt enable
PCICR = 0x04; //enable Port D pin change interrupts
PCMSK2 = 0xFF; //enable pin change interrupt on all Port D pins
}
void initSPI(void)
{
SPCR = 0b01010001; //SPI interrupt disabled, SPI enabled, MSB trasmitted first,
//master, rising edge triggered, sample then set up, fosc/8
SPSR = SPSR | 0x01; //2x clock speed for fosc/8
}
ISR(PCINT2_vect)
{
unsigned char reg = PCMSK2; //read pin change mask register into intermediate register
unsigned char send;
//laser x - left
if(((reg & 0x80) > 0) && ((PIND & 0x40) > 0))
{
send = LASER_X_L;
}
//laser x - right
else if(((reg & 0x40) > 0) && ((PIND & 0x80) > 0))
{
send = LASER_X_R;
}
//laser y - down
else if(((reg & 0x20) > 0) && ((PIND & 0x10) > 0))
{
send = LASER_Y_D;
}
//laser y - up
else if(((reg & 0x10) > 0) && ((PIND & 0x20) > 0))
{
send = LASER_Y_U;
}
//mirror x - left
else if(((reg & 0x08) > 0) && ((PIND & 0x04) > 0))
{
send = MIRROR_X_L;
}
//mirror x - right
else if(((reg & 0x04) > 0) && ((PIND & 0x08) > 0))
{
send = MIRROR_X_R;
}
//mirror y - down
else if(((reg & 0x02) > 0) && ((PIND & 0x01) > 0))
{
send = MIRROR_Y_D;
}
//mirror y - up
else if(((reg & 0x01) > 0) && ((PIND & 0x02) > 0))
{
send = MIRROR_Y_U;
}
else
{
send = NOTHING;
}
if(send != NOTHING)
{
SPDR = send; //start transmission
}
}
Endlich die Lösung für dieses Problem gefunden.
Zunächst musste die SPI-Setup-Funktion angepasst werden.
void initSPI(void)
{
PRR = 0b11111011; //turn power saving on for all peripherals other than SPI
SPCR = 0b11111001; //SPI interrupt enabled, SPI enabled, MSB trasmitted last,
//master, falling edge triggered, set up then sample, fosc/8
SPSR = 0x01; //2x clock speed for fosc/8
}
Außerdem verarbeitet der Prozessor den !SS-Pin im Mastermodus nicht. Es muss zu Beginn der Übertragung niedrig eingestellt und danach manuell wieder hoch gesetzt werden.
if(send != NOTHING)
{
PORTB = PORTB & 0b11111011;
SPDR = send; //start transmission
while(!(SPSR & (1<<SPIF))); //wait for transmission to finish
PORTB = PORTB & 0b11111111;
}
Lundin
Lundin
Matt Jung
Matt Jung
Matt Jung
Lundin
Lundin
W5VO