Связка по 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