Например TDA7294

Форум РадиоКот • Просмотр темы - Atmega8. Не работает SPI
Форум РадиоКот
Здесь можно немножко помяукать :)





Текущее время: Сб апр 27, 2024 14:50:52

Часовой пояс: UTC + 3 часа


ПРЯМО СЕЙЧАС:



Начать новую тему Ответить на тему  [ Сообщений: 8 ] 
Автор Сообщение
Не в сети
 Заголовок сообщения: Atmega8. Не работает SPI
СообщениеДобавлено: Вс мар 24, 2024 14:12:38 
Родился

Зарегистрирован: Сб окт 07, 2023 21:34:17
Сообщений: 15
Рейтинг сообщения: 0
Изучаю 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 
Модератор
Аватар пользователя

Карма: 153
Рейтинг сообщений: 2808
Зарегистрирован: Сб авг 14, 2010 15:05:51
Сообщений: 18103
Откуда: г. Озерск, Челябинская обл.
Рейтинг сообщения: 0
Медали: 1
Лучший человек Форума 2017 (1)
категорически нельзя в схеме использовать вывод 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 
Держит паяльник хвостом

Карма: 10
Рейтинг сообщений: 99
Зарегистрирован: Вт июн 07, 2011 08:03:18
Сообщений: 968
Рейтинг сообщения: 0
ТС, ты бы код сначала научился вставлять правильно. А то и отвечать не хочется...
Starichok51, чего это?
SS мастера на выход и выводи в него что хош. И SS мастера не обязательно должен быть выходом - может и входом, но с 1-цей.


Вернуться наверх
 
PCBWay - всего $5 за 10 печатных плат, первый заказ для новых клиентов БЕСПЛАТЕН

Сборка печатных плат от $30 + БЕСПЛАТНАЯ доставка по всему миру + трафарет

Онлайн просмотровщик Gerber-файлов от PCBWay + Услуги 3D печати
Не в сети
 Заголовок сообщения: Re: Atmega8. Не работает SPI
СообщениеДобавлено: Вт мар 26, 2024 08:29:27 
Модератор
Аватар пользователя

Карма: 153
Рейтинг сообщений: 2808
Зарегистрирован: Сб авг 14, 2010 15:05:51
Сообщений: 18103
Откуда: г. Озерск, Челябинская обл.
Рейтинг сообщения: 0
Медали: 1
Лучший человек Форума 2017 (1)
я сказал в меру своих знаний.
я сделал собственный последовательный программатор, и там у меня работа мастера. поэтому я рассказал, как у меня настроен мастер.
а для программатора настройку слэва ("пациента") делать не надо. поэтому про настройку слэва я просто высказал своё мнение.

_________________
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.


Вернуться наверх
 
Выбираем схему BMS для заряда литий-железофосфатных (LiFePO4) аккумуляторов

Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.

Подробнее>>
Не в сети
 Заголовок сообщения: Re: Atmega8. Не работает SPI
СообщениеДобавлено: Вт мар 26, 2024 15:29:34 
Родился

Зарегистрирован: Сб окт 07, 2023 21:34:17
Сообщений: 15
Рейтинг сообщения: 0
категорически нельзя в схеме использовать вывод 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. как правильно код на форуме вставлять?


Вернуться наверх
 
Новый аккумулятор EVE серии PLM для GSM-трекеров, работающих в жёстких условиях (до -40°С)

Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре. Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.

Подробнее>>
Не в сети
 Заголовок сообщения: Re: Atmega8. Не работает SPI
СообщениеДобавлено: Вт мар 26, 2024 19:57:01 
Модератор
Аватар пользователя

Карма: 153
Рейтинг сообщений: 2808
Зарегистрирован: Сб авг 14, 2010 15:05:51
Сообщений: 18103
Откуда: г. Озерск, Челябинская обл.
Рейтинг сообщения: 0
Медали: 1
Лучший человек Форума 2017 (1)
при ответе вверху есть тэг [code].

_________________
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Atmega8. Не работает SPI
СообщениеДобавлено: Ср мар 27, 2024 18:09:42 
Родился

Зарегистрирован: Сб окт 07, 2023 21:34:17
Сообщений: 15
Рейтинг сообщения: 0
[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 
Родился

Зарегистрирован: Сб окт 07, 2023 21:34:17
Сообщений: 15
Рейтинг сообщения: 0
Методом проб и ошибок я частично решил проблему.
Если не использовать прерывания, то цифры 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);
    }
}


Вернуться наверх
 
Показать сообщения за:  Сортировать по:  Вернуться наверх
Начать новую тему Ответить на тему  [ Сообщений: 8 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 25


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB
Extended by Karma MOD © 2007—2012 m157y
Extended by Topic Tags MOD © 2012 m157y