#define F_CPU 16000000UL
#include <inttypes.h>
#include <avr/io.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define SPI_PORT PORTB
#define SPI_DDR DDRB
#define SPI_SS 2
#define SPI_MOSI 3
#define SPI_MISO 4
#define SPI_SCK 5
#define BUTTON (PINB & (1 << PINB0)) //Pin B0
#define NUMBEROFSCREENS 3
//SCL - PB5 - Pin 13
//MOSI - PB4 - Pin 11
//SS - PB2 - Pin 10
void initSPI0(void)
{
/* Set SS, MOSI and SCK output, all others input */
SPI_DDR = (1<<SPI_SS) | (1<<SPI_MOSI) | (1<<SPI_SCK);
/* Enable SPI, Master, set clock rate fck/128 */
SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR1) | (1<<SPR0);
}
void SPI_Master_Transceiver(uint16_t data)
{
SPI_PORT &= ~(1<<SPI_SS); // Pull Slave_Select low
SPDR = data >> 8; // Start transmission of first byte
while( !(SPSR & (1<<SPIF)) );// Wait for transmission complete
SPDR = (uint8_t)data; // Start transmission of second byte
while( !(SPSR & (1<<SPIF)) );// Wait for transmission complete
SPI_PORT |= (1<<SPI_SS); // Pull Slave Select High
}
uint8_t display[24];
/*
uint8_t display[24] = {//agp
0b00000000,
0b00111100,
0b01100110,
0b01100110,
0b01111110,
0b01100110,
0b01100110,
0b01100110,
0B00000000,
0B00111100,
0B01000010,
0B01000000,
0B01001110,
0B01000010,
0B01000010,
0B00111100,
0B0000000,
0B1111000,
0B1000100,
0B1000100,
0B1111000,
0B1000000,
0B1000000,
0B1000000};
*/
uint8_t smile[] = {
0,0,0,0,0,0,0,0,
0b00111100,
0b01111110,
0b11011011,
0b11111111,
0b11011011,
0b01111110,
0b00111100,
0,0,0,0,0,0,0,0};
uint8_t frown[] = {
0,0,0,0,0,0,0,0,
0b00111100,
0b01111110,
0b11011011,
0b11111111,
0b11000011,
0b01111101,
0b00111100,
0,0,0,0,0,0,0,0};
void updateMatrix() //function to put what's in display[] on the LED display
{
//loop through each row, then send it to the matrixes
for (char i=0;i<8;i++)
{
unsigned long long column;//a place to store the column of the matrix that we're currently working with
for (char j=(sizeof display)-1;j >= 0;j--)//Have j count down not up to reverse the row before it's sent
{
column = column << 1; //shift left 1
column = column | ((display[j] >> i) & 1);//put the ith bit of display[j] in the lsb of row
}
//column is done, now send it over SPI
SPI_PORT &= ~(1<<SPI_SS); // Pull Slave_Select low
for (char k=0;k<NUMBEROFSCREENS;k++)//repeat based on number of matrices attached
{
SPDR = i+1;//send column number to be updated
while( !(SPSR & (1<<SPIF)) );// Wait for transmission complete
SPDR = column >> 8*k;//send the first bit of "row" (8*0), then the second (8*1), etc.
while( !(SPSR & (1<<SPIF)) );// Wait for transmission complete
}
SPI_PORT |= (1<<SPI_SS); // Pull Slave Select High
}
}
void setup()
{
//initalizations
Serial.begin(9600);
initSPI0();
updateMatrix();
DDRB &= ~(1 << DDB0);//set pin B0 (the pushbutton) as an input
}
char row = 23;
unsigned int currentRow = 0b1111000000;
char isGoingRight = 1;
char oneShotFlag = 0;
char restartFlag = 0;
void loop()
{
if (BUTTON)
{
if (!oneShotFlag)//one-shot handling
{
if (row != 23)//hande the case where the first row just gets placed
{
//AND current row with the one below
display[row] = display[row+1] & display[row];
updateMatrix();//send to display
}
if (!display[row] || !row)//handle winning + loosing
{
for (char i=0;i<6;i++)//flash screen
{
for (char j=0;j < (sizeof display);j++) display[j] = ~display[j];//invert display
updateMatrix();//send to display
_delay_ms(500);
}
//frown or smile
if (!display[row]) for (char i=0;i < (sizeof display);i++) display[i] = frown[i]; //handle loosing
else for (char i=0;i < (sizeof display);i++) display[i] = smile[i]; //handle winning
updateMatrix();//send to display
_delay_ms(5000000000000000);
restartFlag = 1;//set flag to restart the game
}
if (!restartFlag)
{
//count how many ones there are in the row so the length of the cursor in the next row will be the same
char countOfOnes = 0;
for (char i=0;i<8;i++) if ((display[row]>>i)&1) countOfOnes++;
row--;//move up one row
//find where the stack is so we can put the cursor there
char whereToPutCursor = 4;
for (char i=0;i<8;i++) if (((int)pow(2,countOfOnes)>>i)&1) whereToPutCursor++;
//(int)pow(2,countOfOnes) -> create int with countOfOnes 1s
//shift by whereToPutCursor so it's above the previous row
currentRow = (int)pow(2,countOfOnes) << whereToPutCursor;
}
else //need to reset everything
{
memset(display, 0, sizeof(display));//blank display
row = 23;
currentRow = 0b1111000000;
isGoingRight = 1;
restartFlag = 0;
}
}
oneShotFlag=1;//one-shot handling
}
else oneShotFlag=0;//one-shot handling
//if lsb or msb is 1, need to switch directions
if ((currentRow & 0b10) || (currentRow & 0b0100000000000000)) isGoingRight = !isGoingRight;
//shift left or right, depending
if (isGoingRight) currentRow = currentRow >> 1;
else currentRow = currentRow << 1;
display[row] = (uint8_t)(currentRow >> 4);//update array
updateMatrix();//send to display
_delay_ms(100);
}