/* Использование семисегментного индикатора с общим катодом и сдвиговым регистром по протоколу SPI */

#include <avr/io.h>         //подключаем библиотеки
#include <util/delay.h>

#define SPI_DDR     DDRB    //назначаем имя для изменеия направления на порту B
#define SPI_PORT    PORTB   //назначаем имя для используемого порта
#define SPI_SS      PB4     //назначаем имя выхода SS
#define SPI_MOSI    PB5     //назначаем имя выхода MOSI
#define SPI_MISO    PB6     //назначаем имя выхода MISO
#define SPI_SCK     PB7     //назначаем имя выхода SCK

char d[18] ={               //кодирование знаков для семисегментного индикатора
    0x7E,  //0
    0x30,  //1
    0x6D,  //2
    0x79,  //3
    0x33,  //4
    0x5B,  //5
    0x5F,  //6
    0x70,  //7
    0x7F,  //8
    0x7B,  //9
    0x77,  //a
    0x1F,  //b
    0x4E,  //c
    0x3D,  //d
    0x4F,  //e
    0x47,  //f
    0x80,   //.
    0x00   //пусто
};

void spi(unsigned char cmd, unsigned char data)                //Функция передачи двух пакетов по 8 бит по протоколу SPI
{
	unsigned char i=0; 
/*    SPI_PORT &= ~(1<<SPI_SS);                       //сбрасываем SS в 0
    SPDR = cmd;                                     //отправляем данные по SPI адрес
    while(!(SPSR&(1<<SPIF)));                       //ждем окончания отправки
    SPDR = data;                                    //отправляем данные по SPI данные
    while(!(SPSR&(1<<SPIF)));                       //ждем окончания отправки
    SPI_PORT |= (1<<SPI_SS);                        //устанавливаем SS в 1
*/
	SPI_PORT &= ~(1<<SPI_SS);                      //сбрасываем SS в 0
	
	_delay_us(10);
	for (i=0; i<8; i++)
       {
		if( (cmd>>(7-i))&0x01 ) SPI_PORT |= (1<<SPI_MOSI); else SPI_PORT &= ~(1<<SPI_MOSI);		//SPI_MOSI = (cmd>>(7-i))&0x01
        _delay_us(10);        
		SPI_PORT |= (1<<SPI_SCK);					//SPI_SCK=1;
        _delay_us(30);
        SPI_PORT &= ~(1<<SPI_SCK);					//SPI_SCK=0;
        _delay_us(20);
       }
	for (i=0; i<8; i++)
       {
        if( (data>>(7-i))&0x01 ) SPI_PORT |= (1<<SPI_MOSI); else SPI_PORT &= ~(1<<SPI_MOSI);		//SPI_MOSI = (cmd>>(7-i))&0x01
        _delay_us(10);
        SPI_PORT |= (1<<SPI_SCK);					//SPI_SCK=1;
        _delay_us(30);
        SPI_PORT &= ~(1<<SPI_SCK);					//SPI_SCK=0;
        _delay_us(20);
       }
	SPI_PORT |= (1<<SPI_SS);                        //устанавливаем SS в 1
	_delay_us(20);	
	
}





void clrdig (void)          //Функция очистки индикаторов
{
    spi(0x01,d[17]);
    spi(0x02,d[17]);
    spi(0x03,d[17]);
    spi(0x04,d[17]);
    spi(0x05,d[17]);

}

int main(void)
{

   SPI_DDR = (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS);    //настраиваем MOSI, SCK, SS как выходы
   SPI_PORT |= (1<<SPI_SS);                              //устанавливаем SS в 1
   //SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0);       //через регистр SPCR настраиваеи аппаратное SPI

   //Инициализация MAX7221

    spi(0x0C,0x00);     //Отключение индикаторов
    spi(0x09,0x00);     //Отключение декодирования
    spi(0x0A,0x0A);     //Интенсивность свечения индикаторов
    spi(0x0B,0x04);     //Количество индикаторов начиная с 0
    spi(0x0F,0x00);     //Отключение теста индикаторов
    spi(0x0C,0x01);     //Включение индикаторов

    clrdig();           //Очистка всех индикаторов

int i=0;                //Переменная перебора выводимых символов
int j=1;                //Переменная осчета номера индикатора

    while(1){           //Бесконечный цикл

        spi(j,d[i]);    //Вывод на индикатор j символа i

        _delay_ms(1000);    //Задержка выполнения 1000мс

        i++;
        if(i>17)i=0;
        j++;
        if(j>5)j=1;

    }

    return 0;
}
