Хочу передавать задавать в master значение переменной counter от 0 до 3 и передавать её по SPI в slave и чтобы slave через I2C отображал её значение на OLED дисплее SSD1306. Для этого соединил MOSI, MISO, SCK, SS между собой между master и slave. Код писал в двух вариантах: первый работает, а второй почему то нет.
Первый вариант: Подключил к master три кнопки к портам PORTC.1, PORTC.2, PORTC.3, при нажатии на которые переменная counter будет принимать значение 1,2 и 3 соответственно. И всё нормально работает: slave весь OLED-дисплей заполняет этими цифрами как надо.
Вот первый вариант кода для master:
Код: Выделить всё
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)| (1<<SPE)| (1<<MSTR) ;
SPCR|=(1<<SPE);//разрешаем работу SPI
SPCR|=(1<<MSTR); // МК работает как master
SPSR&=~(1<<SPI2X); //без удвоения частоты
SPCR&=~(1<<SPR1);//нам нужен предделитель частоты МК clk/16:
SPCR|=(1<<SPR0);
SPCR|=(1<<CPOL) |(1<<CPHA); // импульс отрицательной полярности, задний фронт
SPCR&=~(1<<DORD); //сперва передаются старшие биты
}
int main()
{
SPI_master_settings();
DDRC&=~((1<<3)|(1<<2)|(1<<1));//кнопки
PORTC|=(1<<3)|(1<<2)|(1<<1);
if (~PINC&(1<<1)) //задаем значение 1
{
SPDR = 1;
PORTB &= ~(1<<SS);
while(!(SPSR&(1<<SPIF))) ; //Дождаться окончания передачи
PORTB |=(1<<PB2); //Установить "1" на линии SS
}
if (~PINC&(1<<2)) //задаем значение 2
{
SPDR = 2;
PORTB &= ~(1<<SS);
while(!(SPSR&(1<<SPIF))) ; //Дождаться окончания передачи
PORTB |=(1<<PB2); //Установить "1" на линии SS
}
if (~PINC&(1<<3)) //задаем значение 3
{
SPDR = 3;
PORTB &= ~(1<<SS);
while(!(SPSR&(1<<SPIF))) ; //Дождаться окончания передачи
PORTB |=(1<<PB2); //Установить "1" на линии SS
}
}
Код: Выделить всё
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);
}
ISR(SPI_STC_vect) //по прерыванию получаем от master значение counter
{
while(~SPSR&(1<<SPIF)) //ждем завершения обмена данными
;
counter=SPDR;//присваиваем переменной counter значение полученное по SPI и сохраненное в регистре данных SPI (SPDR)
}
int main(void)
{
sei();
SPI_slave_settings();
_delay_ms(50);
//тут должен располагаться код для инициализации и очистки OLED дисплея. Я его не пишу, чтобы сообщение не было слишком большим. Потому перехожу сразу к while
while (1)
{
switch(counter) // выводим значение counter на OLED-дисплей
{
case 0:
print_char('0');
break;
case 1:
print_char('1');
break;
case 2:
print_char('2');
break;
case 3:
print_char('3');
break;
}
}
Вот второй вариант кода main для master:
Код: Выделить всё
int main(void)
{
SPI_master_settings();
DDRC&=~((1<<3)|(1<<2)|(1<<1));//кнопки
PORTC|=(1<<3)|(1<<2)|(1<<1);
while (1)
{
for(int i=0;i<4;++i)
{
switch (i)
{
case 0: //отправляем 0
SPDR = 0;
PORTB &= ~(1<<SS);
while(!(SPSR&(1<<SPIF))); //Дождаться окончания передачи
PORTB |=(1<<PB2); //Установить "1" на линии SS
break;
case 1: [color=#40FF00]//отправляем 1
SPDR = 1;
PORTB &= ~(1<<SS);
while(!(SPSR&(1<<SPIF))) ; //Дождаться окончания передачи
PORTB |=(1<<PB2); //Установить "1" на линии SS
break;
case 2: //отправляем 2
SPDR = 2;
PORTB &= ~(1<<SS);
while(!(SPSR&(1<<SPIF))) ; //Дождаться окончания передачи
PORTB |=(1<<PB2); //Установить "1" на линии SS
break;
case 3: //отправляем 3
SPDR = 3;
PORTB &= ~(1<<SS);
while(!(SPSR&(1<<SPIF))) ; //Дождаться окончания передачи
PORTB |=(1<<PB2); //Установить "1" на линии SS
break;
}
_delay_ms(500);
}
}
}
Пробовал убрать OLED-дисплей и подключить к slave три светодиода, чтобы они загорались по очереди в соответствии с переменной counter (т.к. сперва 1й, потом 2й, потом 3й). Но снова неудача и загорались как будто я передавал цифры не 1,2,3 а в порядке 2,1,3


