Связка по SPI на примере контроллеров mega32 и tiny2313
Маленький пример обмена по SPI (режим 0) между ATmega32(подчиненный) и ATtiny2313(мастер) по схеме предложенной автором авриэла для программирования двух контроллеров через один разъем, код компилировался на AVR Studio 4.16.
У ATmega32 (использованная частота - 7.xxxxМГц) SPI аппаратный:
void SPI_SlaveInit(void)
{
/* MISO делаем выходом */
DDRB = (1<<PB6);
PORTB |= (1<<PB4); /* Инициализируем SPI, Порядок битов - от младшего к старшему, разрешаем прерывание по получению байта */
SPCR = (1<<SPE)|(1<<DORD)|(1<<SPIE);
SPDR=0; //данные которые получит мастер
}
ISR(SPI_STC_vect) //обработчик прерывания
{
SPDR+=1; //в следующий обмен данными с мастером вернем полученное число на 1 больше
}
ATtiny2313 (использованная частота - 8МГц) имеет, скажем так, полуаппаратную реализацию SPI (USI), но при используемом соединении она не может ее использовать в режиме мастера, поэтому сделан программный SPI (выводы MISO и MOSI обозначены правильно лишь для программатора и режима слейв, а в режиме мастера все с точностью до наоборот, об этом сказано в документации, но можно просто не обратить внимания):
void PSPI_Init() //настройка порта
{
//PB0 - сигнал /SS для слейва, остальное согласно схеме
PORTB = (1<<PB0)|(1<<PB5); //MOSI и /SS - выставить в 1
DDRB = (1<<PB5)|(1<<PB7)|(1<<PB0);
}
uint8 PSPI_Send(uint8 val) //процедура приемо-передачи
{
uint8 tmp;
PORTB=(val&1)<<PB5; //SCK=0 и отправим бит 0 слейву
val>>=1; //почистим отправленный бит
tmp=PINB; //задержка
tmp=PINB&0x40; //читаем бит
PORTB|=(1<<PB7); //SCK=1
tmp<<=1; //подвинем полученный бит на 7-ю позицию
val|=tmp; //запишем его в переменную
//далее все повторим еще 7 раз
PORTB=(val&1)<<PB5; //1 бит
val>>=1;
tmp=PINB;
tmp=PINB&0x40;
PORTB|=(1<<PB7);
tmp<<=1;
val|=tmp;
PORTB=(val&1)<<PB5; //2 бит
val>>=1;
tmp=PINB;
tmp=PINB&0x40;
PORTB|=(1<<PB7);
tmp<<=1;
val|=tmp;
PORTB=(val&1)<<PB5; //3 бит
val>>=1;
tmp=PINB;
tmp=PINB&0x40;
PORTB|=(1<<PB7);
tmp<<=1;
val|=tmp;
PORTB=(val&1)<<PB5; //4 бит
val>>=1;
tmp=PINB;
tmp=PINB&0x40;
PORTB|=(1<<PB7);
tmp<<=1;
val|=tmp;
PORTB=(val&1)<<PB5; //5 бит
val>>=1;
tmp=PINB;
tmp=PINB&0x40;
PORTB|=(1<<PB7);
tmp<<=1;
val|=tmp;
PORTB=(val&1)<<PB5; //6 бит
val>>=1;
tmp=PINB;
tmp=PINB&0x40;
PORTB|=(1<<PB7);
tmp<<=1;
val|=tmp;
PORTB=(val&1)<<PB5; //7 бит
val>>=1;
tmp=PINB;
tmp=PINB&0x40;
PORTB|=(1<<PB7);
tmp<<=1;
val|=tmp;
tmp=PINB; //Задержка для слейва, что бы он успел записать последний бит
tmp=PINB;
PORTB=(1<<PB0)|(1<<PB5); //MOSI и /SS - выставить в 1
return val; //полученный байт от слейва
}
ПС. Максимальная скорость обмена составляет около 40Кбайт/сек, что довольно неплохо, но можно и лучше, правда - на ассемблере. При организации обмена данными важно не забывать о слейве, он должен успеть подствить новые данные в регистр SPDR до очередной приемо-передачи.
вс, 13/07/2014 - 22:04
Проект эмуляции