Обсуждаем контроллеры компании Atmel.
Ответить

Atmega8. Не работает SPI

Вс мар 24, 2024 14:12:38

Изучаю SPI. Начинающий. Использую МК atmega8. Написал простенький код для того чтобы пересылать значение переменой counter от одного МК к другому.

Как должно работать:
При начале каждой передачи первый МК(далее-master) зажигает ненадолго свой светодиод (на PORTC.4). Потом передает по SPI переменную counter=2 во второй МК (далее-slave), который принимает переменную counter=2 и зажигает соответственно 2 светодиода.
В протеусе все работает нормально.
Изображение Изображение
По итогу получается: собрал все на макетке и при включении master 1 раз включает светодиод, после чего он светится примерно на 50% от того уровня, какой был при включении, и не гаснет вообще (как будто цикл while не выполняется до конца либо выполняется 1 раз). А slave вообще не реагирует никак.

Пробовал убрать связь по SPI между master и slave (в коде закомментил все, что отвечает за SPI) и менял программу просто чтобы каждый МК отдельно помигал своими светодиодами, чтобы исключить неисправность светодиодов и портов МК и все нормально работало. Но как только я возвращал в код все, что связано с SPI, То опять ничего не работало (как было ранее).
Товарищи, не подскажете в чем может быть проблема? Вроде уже и master со slaave менял местами (и на схеме и прошивки) и результат все тот же

Код master:
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define SS 2
#define MOSI 3
#define MISO 4
#define SCK 5

int counter=2;

void SPI_master_settings(void) //настройки SPI_Master
{

DDRB|=(1<<MOSI)|(1<<SCK)|(1<<SS);
PORTB|=(1<<SS); //этот пин надо установить раньше настроек регистра контроля т.е. раньше команды SPCR|=(1<<MSTR); уже не помню почему
DDRB&=~(1<<MISO);

SPCR|=(1<<SPIE);//SPCR-регистр контроля SPI.
//Ставим SPIE=1 (разрешаем прерывания по линии SPI). Когда произошел обмен данными и мастер получил все 8 бит, то сработает прерывание и флаг SPIF становится=1
SPCR|=(1<<SPE);//SPI ENABLE. Ставим этот бит=1, чтобы разрешить работу SPI
SPCR|=(1<<MSTR); //если MSTR=1, МК работает как master

//нам нужен предделитель частоты МК F/16: SPI2X=0 SPR1=0 SPR0=1
SPSR&=~(1<<SPI2X); // мы не удваиваем частоту работы SPI
SPCR&=~(1<<SPR1);
SPCR|=(1<<SPR0);

SPCR|=(1<<CPOL); //мы используем импульсы отрицательной полярности согласно табл 48 (даташит atmega8 стр.126)
SPCR|=(1<<CPHA);//работаем по заднему фронту импульса
SPCR&=~(1<<DORD); //сперва передаются старшие биты(MSB), а потом младшие (LSB) . Если =0, то наоборот
}

ISR(SPI_STC_vect)
{
while(~SPSR&(1<<SPIF)) //ждем когда данные передадутся и флаг SPIF станет =1 и мы выйдем из цикла
;
PORTB|=(1<<SS);
}

int main(void)
{

SPI_master_settings();
sei();
DDRC|=(1<<4);//светодиод
PORTC&=~(1<<4);

while (1)
{
PORTC|=(1<<4);//мигаем светодиодом
_delay_ms(300);
PORTC&=~(1<<4);
_delay_ms(300);

PORTB&=~(1<<SS);
SPDR=counter;
_delay_ms(300);
}
}


Код slave:
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define SS 2
#define MOSI 3
#define MISO 4
#define SCK 5

int counter=0;

void SPI_slave_settings(void) //настройки SPI_SLAVE
{
DDRB&=~((1<<MOSI)|(1<<SCK));
DDRB|=(1<<MISO);

SPCR|=(1<<SPIE);//SPCR-регистр контроля SPI.
SPCR|=(1<<SPE);//SPI ENABLE. Ставим этот бит=1, чтобы разрешить работу SPI
SPCR&=~(1<<MSTR); //ставим MSTR=0, чтобы МК работал как slave (если =1 то как master)

SPCR|=(1<<CPOL); //мы используем импульсы отрицательной полярности согласно табл 48 (даташит atmega8 стр.126)
SPCR|=(1<<CPHA);//работаем по заднему фронту импульса
SPCR&=~(1<<DORD); //сперва передаются старшие биты(MSB), а потом младшие (LSB) . Если =0, то наоборот

DDRB&=~(1<<SS);
PORTB|=(1<<SS); //подтягиваем к единице
}

ISR(SPI_STC_vect)
{
while(~SPSR&(1<<SPIF)) //ждем завершения обмена данными
;
counter=SPDR;//присваиваем переменной counter значение полученное по SPI и сохраненное в регистре данных SPI (SPDR)
}


int main(void)
{
DDRC|=(1<<5)|(1<<4);//светодиоды
PORTC&=~((1<<5)|(1<<4));
DDRB|=(1<<7)|(1<<6);//светодиоды
PORTB&=~((1<<7)|(1<<6));
SPI_slave_settings();
sei();

while (1)
{
if(counter>4)
{
PORTC|=(1<<5);
PORTC&=~(1<<4);
PORTB|=(1<<6);
PORTB&=~(1<<7);
}

if(counter==0)
{
PORTC&=~((1<<5)|(1<<4));
PORTB&=~((1<<7)|(1<<6));
}

if(counter==1)
{
PORTC|=(1<<4);
PORTC&=~(1<<5);
PORTB&=~((1<<7)|(1<<6));
}

if(counter==2) //при передаче COUNTER=2 должно работать вот это
{
PORTC|=(1<<5)|(1<<4);
PORTB&=~((1<<7)|(1<<6));
}

if(counter==3)
{
PORTC|=(1<<5)|(1<<4);
PORTB|=(1<<6);
PORTB&=~(1<<7);
}

if(counter==4)
{
PORTC|=(1<<5)|(1<<4);
PORTB|=(1<<7)|(1<<6);
}
}
}

Re: Atmega8. Не работает SPI

Вс мар 24, 2024 20:40:52

категорически нельзя в схеме использовать вывод SS в схеме, ни для мастера, ни для слэйва. соответственно, нельзя соединять эти выводы между обоими МК.
мастер настраивается так:
PORTB = 0
DDRB = (1<<SCK) + (1<<MOSI) + (1<<SS)
SS устанавливается выходом, но нем устанавливается ноль.
SPCR = (1<<SPIE) + (1<<SPE) + (1<<MSTR) + (нужное значение битов предделителя)
SPSR устанавливается в зависимости от необходимости в двойной скорости.

слэйв настраивается так:
у слэйва вывод SS нужно подключить на "землю" - подать ноль, тогда у него SPI автоматически активируется.
а порт В у слейва нужно установить только MISO на выход.
SPCR = (1<<SPIE) + (1<<SPE) + (нужное значение битов предделителя)
SPSR устанавливается в зависимости от необходимости в двойной скорости.

Re: Atmega8. Не работает SPI

Пн мар 25, 2024 08:45:37

ТС, ты бы код сначала научился вставлять правильно. А то и отвечать не хочется...
Starichok51, чего это?
SS мастера на выход и выводи в него что хош. И SS мастера не обязательно должен быть выходом - может и входом, но с 1-цей.

Re: Atmega8. Не работает SPI

Вт мар 26, 2024 08:29:27

я сказал в меру своих знаний.
я сделал собственный последовательный программатор, и там у меня работа мастера. поэтому я рассказал, как у меня настроен мастер.
а для программатора настройку слэва ("пациента") делать не надо. поэтому про настройку слэва я просто высказал своё мнение.

Re: Atmega8. Не работает SPI

Вт мар 26, 2024 15:29:34

категорически нельзя в схеме использовать вывод SS в схеме, ни для мастера, ни для слэйва. соответственно, нельзя соединять эти выводы между обоими МК.
мастер настраивается так:
PORTB = 0
DDRB = (1<<SCK) + (1<<MOSI) + (1<<SS)
SS устанавливается выходом, но нем устанавливается ноль.
SPCR = (1<<SPIE) + (1<<SPE) + (1<<MSTR) + (нужное значение битов предделителя)
SPSR устанавливается в зависимости от необходимости в двойной скорости.

слэйв настраивается так:
у слэйва вывод SS нужно подключить на "землю" - подать ноль, тогда у него SPI автоматически активируется.
а порт В у слейва нужно установить только MISO на выход.
SPCR = (1<<SPIE) + (1<<SPE) + (нужное значение битов предделителя)
SPSR устанавливается в зависимости от необходимости в двойной скорости.


_____
1) В мастере: вывод SS теперь ни к чему не подключен. Провод между SS у master и SS slave убрал
Я хочу использовать импульсы отрицательной полярности. Потому поставил MOSI, SCK, SS в единицу по умолчанию. SS хочу ставить в ноль только для передачи, а потом снова в единицу.
DDRB|=(1<<MOSI)|(1<<SCK)|(1<<SS);
PORTB|=(1<<MOSI)|(1<<SCK)|(1<<SS);
Добавил в master в функцию прерывания по SPI одно мигание сигнальным светодиодом до окончания передачи данных и одно мигание после каждой передачи данных:
ISR(SPI_STC_vect)
{
PORTC|=(1<<4);//первое мигание сигнальным светодиодом
_delay_ms(100);
PORTC&=~(1<<4);
_delay_ms(100);
while(~SPSR&(1<<SPIF)) //ждем когда данные передадутся и флаг SPIF станет =1 и мы выйдем из цикла
;
PORTB|=(1<<SS);

PORTC|=(1<<4);//второе мигание сигнальным светодиодом
_delay_ms(100);
PORTC&=~(1<<4);
_delay_ms(100);
}
2) В slave прописал MOSI, SCK как входы, MISO как выход (по умолчанию подтянут к единице, т.к. импульсы отрицательной полярности):
DDRB&=~((1<<MOSI)|(1<<SCK));
DDRB|=(1<<MISO);
PORTB|=(1<<MISO);
Все остальные настройки master и slave уже были прописаны так, как вы и написали.
Вывод SS в slave проводом подключил к нулю.
В симуляции в proteus все прекрасно работает, но на макетке тот самый сигнальный светодиод, подключенный к master, делает первое мигание, НО не делает второе мигание.
Т.е. почему то сама передача либо не начинается вообще, либо не завершается. Не пойму почему. Такое ощущение, что master не может выйти из цикла while(~SPSR&(1<<SPIF)).
При этом slave включает свой первый светодиод, подключенный к PORTC.4. (что соответствует что slave получил переменную counter=1. Потом этот светодиод продолжает гореть и ничего не меняется. Т.е. получается master один раз все-таки передает данные, а потом перестает?

p.S. как правильно код на форуме вставлять?

Re: Atmega8. Не работает SPI

Вт мар 26, 2024 19:57:01

при ответе вверху есть тэг [code].

Re: Atmega8. Не работает SPI

Ср мар 27, 2024 18:09:42

[uquote="Starichok51",url="/forum/viewtopic.php?p=4560271#p4560271"]при ответе вверху есть тэг
Код:
.[/uquote]
Теперь схема выглядит так.
[url=https://img.radiokot.ru/files/154442/medium/3eoro7ny97.jpg]
Задумка такова, что в master есть переменная counter, которая поочередно в двух циклах for меняется от 0 до 4 и обратно. Значение этой переменной передается по SPI в slave. Причем  в функции прерывания ISR(SPI_STC_vect) master один раз мигает светодиодом D9 при начале отправки по SPI, и 1 раз после отправки. Slave получает по SPI переменную counter и через stitch зажигает светодиоды D5-D8 (число горящих светодиодов равно переменной counter). В симуляции все мигает как надо, но в реале на макетке  1 раз мигнет светодиод D9 и больше ничего не происходит. Как будто в master прерывание по SPI  с чем то конфликтует, хотя у меня других прерываний нет.

Код master:
[code]
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define SS 2
#define MOSI 3
#define MISO 4
#define SCK 5

int counter=0;

void SPI_master_settings(void) //настройки  SPI_Master
{   
   DDRB|=(1<<MOSI)|(1<<SCK)|(1<<SS);
   DDRB&=~(1<<MISO);
   PORTB|=(1<<MOSI)|(1<<SCK)|(1<<SS);
   
   SPCR|=(1<<SPIE);[color=#800000]// разрешаем прерывания по SPI[/color]
   SPCR|=(1<<SPE);// разрешаем работу SPI
   SPCR|=(1<<MSTR); // МК работает как master
   SPSR&=~(1<<SPI2X); //без удвоения частоты
   SPCR&=~(1<<SPR1);
   SPCR|=(1<<SPR0);
   SPCR|=(1<<CPOL); // импульсы отрицательной полярности
   SPCR|=(1<<CPHA);//работаем по заднему фронту импульса
   SPCR&=~(1<<DORD); //сперва передаются старшие биты(MSB
}

ISR(SPI_STC_vect)
{
   PORTC|=(1<<4); //первый раз мигаем светодиодом D9
   _delay_ms(100);
   PORTC&=~(1<<4);
   _delay_ms(100);

   while(~SPSR&(1<<SPIF)) //ждем окончания передачи
   ;
   PORTB|=(1<<SS);
   
   PORTC|=(1<<4); //второй раз мигаем светодиодом D9
   _delay_ms(100);
   PORTC&=~(1<<4);
   _delay_ms(100);
}

int main(void)

   SPI_master_settings();
   sei();
   DDRC|=(1<<4);//светодиод D9
   PORTC&=~(1<<4);   
    while (1)
    {   
      for (int i=0;i<5;i++)
      {
         counter++;
         if(counter>4)
         {counter=4;}
            
         if(counter<0)
         {counter=0;}
         
         
         PORTB&=~(1<<SS);
         SPDR=counter;
         
         _delay_ms(100);   
      }
      
      for (int i=0;i<4;i++)
      {
         counter--;
         if(counter>4)
         {counter=3;}
            
         if(counter<0)
         {counter=0;}
            
         
         PORTB&=~(1<<SS);
         SPDR=counter;
         
         _delay_ms(100);   
      }
    }
}
[/code]
Код slave:
[code]
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define SS 2
#define MOSI 3
#define MISO 4
#define SCK 5

int counter=0;

void SPI_slave_settings(void) //настройки  SPI_SLAVE
{
   DDRB&=~((1<<MOSI)|(1<<SCK));
   DDRB|=(1<<MISO);
   PORTB|=(1<<MISO);
   
   SPCR|=(1<<SPIE); //разрешаем прерывания по линии SPI
   SPCR|=(1<<SPE);// разрешаем работу SPI
   SPCR&=~(1<<MSTR); // МК работает как slave   
   SPCR|=(1<<CPOL); //мы используем импульсы отрицательной полярности   SPCR|=(1<<CPHA);//работаем по заднему фронту импульса
   SPCR&=~(1<<DORD); //сперва передаются старшие биты(MSB   
   DDRB&=~(1<<SS);
   PORTB&=~(1<<SS);
}
ISR(SPI_STC_vect)
{
   while(~SPSR&(1<<SPIF)) //ждем завершения обмена данными
   ;
   counter=SPDR;//присваиваем переменной counter значение полученное по SPI
}

int main(void)
{
   DDRC|=(1<<5)|(1<<4);//светодиоды D5, D6
   PORTC&=~((1<<5)|(1<<4));
   DDRB|=(1<<7)|(1<<6);//светодиоды D7, D8
   PORTB&=~((1<<7)|(1<<6));
   
   SPI_slave_settings();
   sei();

    while (1)
    {      
      switch(counter) //мигаем светодиодами
      {
         case 0:PORTC&=~((1<<5)|(1<<4));PORTB&=~((1<<7)|(1<<6));break;
         case 1:PORTC|=(1<<4);PORTC&=~(1<<5);PORTB&=~((1<<7)|(1<<6));break;
         case 2:PORTC|=(1<<5)|(1<<4);PORTB&=~((1<<7)|(1<<6));;break;
         case 3:PORTC|=(1<<5)|(1<<4);PORTB|=(1<<6);PORTB&=~(1<<7);break;
         case 4:PORTC|=(1<<5)|(1<<4);PORTB|=(1<<6)|(1<<7);break;
      }
    }
}

Re: Atmega8. Не работает SPI

Вт апр 09, 2024 19:23:34

Методом проб и ошибок я частично решил проблему.
Если не использовать прерывания, то цифры 1,2,3,4 нормально передаются от master к slave. Если использовать прерывания, то как будто slave принимает цифры в другом порядке: 1,3,2,4. Собственно мой вопрос почему?
Теперь подробнее.
Не стал использовать прерывания для передачи данных по SPI (поначалу), а передавал их вручную внутри main. В сами настройки SPI для master и slave почти в самом начале добавил обнуление регистров SPCR=0; SPSR=0;SPDR=0;, а остальные настройки оставил прежними. Т При монтаже не занулял SS в slave, а все-таки между master и slave я соединил между собой проводами все выводы, ответственные за SPI. И у меня нормально пошла передача цифр "0","1","2","3","4".
Вот код для master:
Код:
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define SS 2
#define MOSI 3
#define MISO 4
#define SCK 5

void SPI_master_settings(void) //настройки  SPI_Master
{
   DDRB|=(1<<MOSI)|(1<<SCK)|(1<<SS);
   PORTB|=(1<<SS);
   DDRB&=~(1<<MISO);
   PORTB|=(1<<MOSI)|(1<<SCK)|(1<<SS);
   SPCR=0;
   SPSR=0;
   SPDR=0;
   SPCR|=(1<<SPIE);//разрешаем прерывания по линии SPI
   SPCR|=(1<<SPE);//разрешаем работу SPI
   SPCR|=(1<<MSTR); // МК работает как master

   SPSR&=~(1<<SPI2X); //без удвоения частоты
   SPCR&=~(1<<SPR1);//нам нужен предделитель частоты МК clk/16:
   SPCR|=(1<<SPR0);

   SPCR|=(1<<CPOL); //используем импульсы отрицательной полярности
   SPCR|=(1<<CPHA);//работаем по заднему фронту импульса
   SPCR&=~(1<<DORD); //сперва передаются старшие биты
}
int main(void)
{
   SPI_master_settings();
        for (int i=0;i<5;i++)
      {   
         PORTB&=~(1<<SS);
         SPDR=i;
                       while(!(SPSR&(1<<SPIF))) ; //Дождаться окончания передачи
             PORTB |=(1<<SS);
         _delay_ms(100);      
      }
}

Аналогично для слейва прием данных я сделал в main без использования прерываний. Полученные по SPI цифры "0","1","2","3","4" я присваивал переменной counter, а в цикле for я зажигал соответствующий светодиод.
Вот код slave:
Код:
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define SS 2
#define MOSI 3
#define MISO 4
#define SCK 5

void SPI_slave_settings(void) //настройки  SPI_SLAVE
{
   
   DDRB&=~((1<<MOSI)|(1<<SCK));
   DDRB|=(1<<MISO);
   PORTB|=(1<<MISO);
   SPCR=0;
   SPSR=0;
   SPDR=0;
   SPCR|=(1<<SPIE);
   SPCR|=(1<<SPE);
   SPCR&=~(1<<MSTR); //МК работает как slave   
   SPCR|=(1<<CPOL);
   SPCR|=(1<<CPHA);
   SPCR&=~(1<<DORD);
   
   DDRB&=~(1<<SS);
   PORTB&=~(1<<SS);
}
int main(void)
{
    DDRC|=(1<<5)|(1<<4);// 1й и 2йсветодиоды
   PORTC&=~((1<<5)|(1<<4));
   DDRB|=(1<<7)|(1<<6);// 3й и 4й светодиоды
   PORTB&=~((1<<7)|(1<<6));
   _delay_ms(50);
   SPI_slave_settings();
    while (1)
    {
        while(~SPSR&(1<<SPIF)) //ждем завершения обмена данными
      ;
      counter=SPDR;//получили цифру от master

        switch(counter)
      {
         case 0:PORTC&=~((1<<5)|(1<<4));PORTB&=~((1<<7)|(1<<6));break; //светодиоды погашены
         case 1:PORTC|=(1<<4);PORTC&=~(1<<5);PORTB&=~((1<<7)|(1<<6));break; //зажигаем 1й светодиод
         case 2:PORTC|=(1<<5);PORTC&=~(1<<4);PORTB&=~((1<<7)|(1<<6));;break; //зажигаем 2й светодиод
         case 3:PORTB|=(1<<6);PORTB&=~(1<<7);PORTC&=~((1<<5)|(1<<4));break; //зажигаем 3й светодиод
         case 4:PORTB|=(1<<7);PORTB&=~(1<<6);PORTC&=~((1<<5)|(1<<4));break; //зажигаем 4й светодиод
      }
    }
}

Все хорошо работает и последовательно загораются 1й, 2й , 3й , 4й светодиоды.
НО хочется использовать прерывания (вроде это круче, чем вручную в main). Для этого изменил main. При этом у меня со строкой sei() вообще передача не шла на макетке (а в протеусе норм). Но когда я sei() убрал, то передача по SPI заработала(ПОЧЕМУ??? ведь должно быть наоборот ибо sei разрешает прерывания). НО slave зажигает светодиоды в следующем порядке: 1й, 3й, 2й, 4й , хотя master как и прежде передает цифры в порядке 1,2,3,4.
Код master с прерываниями:
Код:
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define SS 2
#define MOSI 3
#define MISO 4
#define SCK 5

void SPI_master_settings(void) //настройки  SPI_Master
{
   DDRB|=(1<<MOSI)|(1<<SCK)|(1<<SS);
   PORTB|=(1<<SS);
   DDRB&=~(1<<MISO);
   PORTB|=(1<<MOSI)|(1<<SCK)|(1<<SS);
   SPCR=0;
   SPSR=0;
   SPDR=0;
   SPCR|=(1<<SPIE);//разрешаем прерывания по линии SPI
   SPCR|=(1<<SPE);//разрешаем работу SPI
   SPCR|=(1<<MSTR); // МК работает как master

   SPSR&=~(1<<SPI2X); //без удвоения частоты
   SPCR&=~(1<<SPR1);//нам нужен предделитель частоты МК clk/16:
   SPCR|=(1<<SPR0);

   SPCR|=(1<<CPOL); //используем импульсы отрицательной полярности
   SPCR|=(1<<CPHA);//работаем по заднему фронту импульса
   SPCR&=~(1<<DORD); //сперва передаются старшие биты
}

ISR(SPI_STC_vect)
{
   while(~SPSR&(1<<SPIF)) //ждем когда данные передадутся и флаг SPIF станет =1 и мы выйдем из цикла
   ;
   PORTB|=(1<<SS);
}

int main(void)
{
   
   SPI_master_settings();
    while (1)
   {   
      for (int i=0;i<5;i++) //по очереди отправляем цифры  0,1,2,3,4 в slave
      {
         PORTB&=~(1<<SS);
         SPDR=i;
         _delay_ms(100);            
      }   
   }
}

Вот код slave с прерываниями:
Код:
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define SS 2
#define MOSI 3
#define MISO 4
#define SCK 5
int counter=0;

void SPI_slave_settings(void) //настройки  SPI_SLAVE
{
   DDRB&=~((1<<MOSI)|(1<<SCK));
   DDRB|=(1<<MISO);
   PORTB|=(1<<MISO);
   SPCR=0;
   SPSR=0;
   SPDR=0;      
   SPCR|=(1<<SPIE);
   SPCR|=(1<<SPE);
   SPCR&=~(1<<MSTR);   
   //мы не выбираем частоты работы SPI для slave, т.к. он подчиняется master    
   SPCR|=(1<<CPOL);
   SPCR|=(1<<CPHA);
   SPCR&=~(1<<DORD);
   DDRB&=~(1<<SS);
   PORTB&=~(1<<SS);
}

ISR(SPI_STC_vect)
{
   while(~SPSR&(1<<SPIF)) //ждем завершения обмена данными
   ;
   counter=SPDR;//присваиваем переменной counter значение полученное по SPI и сохраненное в регистре данных SPI (SPDR)
}


int main(void)

   DDRC|=(1<<5)|(1<<4);// 1й и 2йсветодиоды
   PORTC&=~((1<<5)|(1<<4));
   DDRB|=(1<<7)|(1<<6);// 3й и 4й светодиоды
   PORTB&=~((1<<7)|(1<<6));
   _delay_ms(50);   
 
   SPI_slave_settings();   
   sei();
   while (1)
    {
      switch(counter)
      {
         case 0:PORTC&=~((1<<5)|(1<<4));PORTB&=~((1<<7)|(1<<6));break; //светодиоды погашены
         case 1:PORTC|=(1<<4);PORTC&=~(1<<5);PORTB&=~((1<<7)|(1<<6));break; //зажигаем 1й светодиод
         case 2:PORTC|=(1<<5);PORTC&=~(1<<4);PORTB&=~((1<<7)|(1<<6));;break; //зажигаем 2й светодиод
         case 3:PORTB|=(1<<6);PORTB&=~(1<<7);PORTC&=~((1<<5)|(1<<4));break; //зажигаем 3й светодиод
         case 4:PORTB|=(1<<7);PORTB&=~(1<<6);PORTC&=~((1<<5)|(1<<4));break; //зажигаем 4й светодиод
      }
      _delay_ms(100);
    }
}
Ответить