Пн апр 22, 2024 20:17:42
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;
}
}
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);
}
}
}
Вт апр 23, 2024 12:26:23
SPDR = 1;
PORTB &= ~(1<<SS);
while(!(SPSR&(1<<SPIF))) ; //Дождаться окончания передачи
PORTB |=(1<<PB2); //Установить "1" на линии SS
PORTB &= ~(1<<SS); //Установить "0" на линии SS
SPDR = 1; // Передаём "1"
while(!(SPSR&(1<<SPIF))) ; //Дождаться окончания передачи
PORTB |=(1<<PB2); //Установить "1" на линии SS
ISR(SPI_STC_vect) //по прерыванию получаем от master значение counter
{
while(~SPSR&(1<<SPIF)) //ждем завершения обмена данными
;
counter=SPDR;//присваиваем переменной counter значение полученное по SPI и сохраненное в регистре данных SPI (SPDR)
}
ISR(SPI_STC_vect) //по прерыванию получаем от master значение counter
{
counter=SPDR;//присваиваем переменной counter значение полученное по SPI и сохраненное в регистре данных SPI (SPDR)
}
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); //сперва передаются старшие биты
SPCR=0x50; // 8 МГц/4 = 2 МГц -режим мастер
// 0... .... SPIE разрешение прерывания...
// .1.. .... SPE разрешается работа SPI.
// ..0. .... DORD порядок сдвига данных DORD=0 первым передается старший разряд.
// ...1 .... MSTR (1-мастер, 0-слейв).
// .... 0... CPOL 0 = SCK имеет низкий уровень в состоянии ожидания. (полярность синхро).
// .... .0.. CPHA 0 = установка-задний фронт/выборка передий фронт SCK (фаза синхро).
// .... ..00 SPR1, SPR0 SCK = кварц 8 Мгц/4 = 2 МГц (частота синхро).
// .... ..00 SPR1, SPR0 f/4
// .... ..01 SPR1, SPR0 f/16
// .... ..10 SPR1, SPR0 f/64
// .... ..11 SPR1, SPR0 f/128
SPCR=0x50; // 8 МГц/4 = 2 МГц -режим мастер
Вт апр 23, 2024 16:33:33
Вт апр 23, 2024 20:42:56
, то ждать завершения обмена данными не надо...
поэтому правильно будет так:
согласно даташиту...
сначала надо Установить "0" на линии SS, а потом начинать передачу...
поэтому правильно будет так:
- Код:
PORTB &= ~(1<<SS); //Установить "0" на линии SS
SPDR = 1; // Передаём "1"
while(!(SPSR&(1<<SPIF))) ; //Дождаться окончания передачи
PORTB |=(1<<PB2); //Установить "1" на линии SS
int main(void)
{
SPI_master_settings();
while (1)
{
for (int i=0;i<5;i++)
{
PORTB &= ~(1<<SS);
SPDR = i;
while(!(SPSR&(1<<SPIF))) ; //Дождаться окончания передачи
PORTB |=(1<<PB2); //Установить "1" на линии SS
_delay_ms(300);
}
}
}
if (~PINC&(1<<1))
{
while(~PINC&(1<<1))
;
counter++;
if(counter>4) counter = 0;
PORTB &= ~(1<<SS);
SPDR = counter;
//while(!(SPSR&(1<<SPIF))) ; //Дождаться окончания передачи
//PORTB |=(1<<PB2); //Установить "1" на линии SS
_delay_ms(50);
}
Ср апр 24, 2024 12:33:54
Sharcer писал(а):Пробовал убрать OLED-дисплей и подключить к slave три светодиода, чтобы они загорались по очереди в соответствии с переменной
Ср апр 24, 2024 20:12:54
Sharcer писал(а):Пробовал убрать OLED-дисплей и подключить к 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_master_settings(void) //настройки SPI_Master
{
DDRB|=(1<<MOSI)|(1<<SCK)|(1<<SS);
PORTB|=(1<<SS); //этот пин надо установить раньше настроек регистра контроля т.е. раньше команды SPCR|=(1<<MSTR);
DDRB&=~(1<<MISO);
PORTB|=(1<<MOSI)|(1<<SCK)|(1<<SS);
//PORTB&=~(1<<SS);
SPCR=0;
SPSR=0;
SPDR=0;
SPCR|=(1<<SPIE);//SPCR-регистр контроля SPI.
SPCR|=(1<<SPE);//SPI ENABLE.
SPCR|=(1<<MSTR); // МК работает как master
SPSR&=~(1<<SPI2X); // мы не удваиваем частоту работы SPI
SPCR&=~(1<<SPR1);
SPCR|=(1<<SPR0);
SPCR|=(1<<CPOL); //мы используем импульсы отрицательной полярности согласно
SPCR|=(1<<CPHA);//работаем по заднему фронту импульса
SPCR&=~(1<<DORD); //сперва передаются старшие биты(MSB), а потом младшие (LSB)
}
int main(void)
{
while(1)
{
for (int i=0;i<4;i++)
{
PORTB &= ~(1<<SS);
SPDR = i;
while(!(SPSR&(1<<SPIF))) //Дождаться окончания передачи
;
PORTB |=(1<<SS); //Установить "1" на линии SS
_delay_ms(300);
}
}
}
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h> //для работы с PROGMEM
unsigned int r1_1000, r2_100=0, r3_10=0, r4_1=0;
#define SS 2
#define MOSI 3
#define MISO 4
#define SCK 5
int counter;
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
//мы не выбираем частоты работы SPI для slave, т.к. он подчиняется master
SPCR|=(1<<CPOL); //мы используем импульсы отрицательной полярности
SPCR|=(1<<CPHA);//работаем по заднему фронту импульса
SPCR&=~(1<<DORD);
DDRB&=~(1<<SS);
PORTB&=~(1<<SS);
}
ISR(SPI_STC_vect)
{
counter=SPDR;//присваиваем переменной counter значение полученное по SPI и сохраненное в регистре данных SPI (SPDR)
}
int main(void)
{
sei();
SPI_slave_settings();
DDRC|=(1<<1)|(1<<0);//1-й и 2-й светодиоды
PORTC&=~((1<<5)|(1<<4));
DDRB|=(1<<7)|(1<<6);//3-й и 4-й светодиоды
PORTB&=~((1<<7)|(1<<6));
while (1)
{
switch(counter)
{
case 0:
PORTC&=~((1<<1)|(1<<0));PORTB&=~((1<<7)|(1<<6));
break;
case 1:
PORTC|=(1<<0);PORTC&=~(1<<1);PORTB&=~((1<<7)|(1<<6));
break;
case 2:
PORTC|=(1<<1);PORTC&=~(1<<0);PORTB&=~((1<<7)|(1<<6));
break;
case 3:
PORTB|=(1<<6);PORTB&=~(1<<7);PORTC&=~((1<<1)|(1<<0));
break;
case 4:
PORTB|=(1<<7);PORTB&=~(1<<6);PORTC&=~((1<<1)|(1<<0));
break;
}
}
}
Чт апр 25, 2024 11:48:43
Sharcer писал(а):1) в master передаваемую переменную объявил не в начале программы (там где все define F_CPU и т.д.) , а внутри main
Sharcer писал(а):2) в slave получаемая переменная counter по прежнему объявлена в начале программы (там где все define F_CPU и т.д.) , НО БЕЗ значения по умолчанию (просто "int counter;")