Guión
Tengo un ATMega168 usando un cristal externo de 10 MHz. El bit del fusible DIV/8 no está configurado. El procesador toma las salidas de 4 codificadores rotatorios de cuadratura. Su información de dirección de rotación se decodifica usando interrupciones de cambio de pin y los estados de pin. La información de rotación se convierte en códigos de control y se envía a través de SPI a otro procesador que maneja algunos motores.
Problema
En el código enumerado, la información de la dirección de rotación se descodifica y convierte en códigos de control según lo diseñado, y se ha verificado en el hardware. La transmisión SPI no se inicia. Mirando los pines SPI en el alcance, el pin !SS permanece alto y el SCK y MOSI permanecen bajos.
Otras dos personas han mirado este código además de mí. Sé que tengo que estar pasando por alto algo simple. ¿Por qué no se inicia la transmisión?
/*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
}
}
Finalmente encontré la solución a este problema.
Primero, la función de configuración de SPI necesitaba un ajuste.
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
}
Además, el procesador no maneja el pin !SS en modo maestro. Debe configurarse en un nivel bajo al comienzo de la transmisión y volverse en un nivel alto después de forma manual.
if(send != NOTHING)
{
PORTB = PORTB & 0b11111011;
SPDR = send; //start transmission
while(!(SPSR & (1<<SPIF))); //wait for transmission to finish
PORTB = PORTB & 0b11111111;
}
Lundin
Lundin
mate joven
mate joven
mate joven
Lundin
Lundin
W5VO