Skip to content

Commit e78e6e1

Browse files
authored
Add files via upload
1 parent abac01a commit e78e6e1

11 files changed

Lines changed: 932 additions & 0 deletions

File tree

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#include "i2c.h"
2+
#include "HT16K33.h"
3+
4+
HT16K33::HT16K33(uint8_t _addr) {
5+
i2c_addr=_addr;
6+
}
7+
8+
void HT16K33::init() {
9+
i2cInit();
10+
clearDisplay();
11+
sendCommand(0x21);
12+
sendCommand(0x81);
13+
setBrightness(INITIAL_BRIGHTNESS);
14+
}
15+
16+
void HT16K33::sendCommand(uint8_t c) {
17+
writeRegister(i2c_addr, c);
18+
}
19+
20+
void HT16K33::setBrightness(uint8_t b) {
21+
brightness=b;
22+
sendCommand(0xE0 | brightness);
23+
}
24+
25+
void HT16K33::increaseBrightness() {
26+
if (brightness<MAX_BRIGHTNESS) {
27+
brightness++;
28+
setBrightness(brightness);
29+
}
30+
}
31+
32+
void HT16K33::decreaseBrightness() {
33+
if (brightness>MIN_BRIGHTNESS) {
34+
brightness--;
35+
setBrightness(brightness);
36+
}
37+
}
38+
39+
void HT16K33::storeToBuffer(uint8_t* matrix) {
40+
for (uint8_t i=0;i<16;i++) buffer[i]=matrix[i];
41+
}
42+
43+
void HT16K33::refreshDisplay() {
44+
uint16_t transposedBuffer[8];
45+
for (uint8_t i=0;i<8;i++) {
46+
uint16_t val=0;
47+
for (uint8_t j=0;j<16;j++) {
48+
uint8_t bitVal=(buffer[j]>>i)&1;
49+
uint8_t shiftVal=j;
50+
val+=(bitVal<<shiftVal);
51+
}
52+
transposedBuffer[i]=val;
53+
}
54+
writeRegisters(i2c_addr, DISP_REGISTER, 8, transposedBuffer);
55+
}
56+
57+
void HT16K33::clearDisplay() {
58+
uint16_t zero[8] = {0};
59+
writeRegisters(i2c_addr, DISP_REGISTER, 8, zero);
60+
}
61+
62+
void HT16K33::readButtons() {
63+
previousButtonState = currentButtonState;
64+
currentButtonState = readRegister(i2c_addr, KEYS_REGISTER);
65+
66+
for (uint8_t i=0;i<8;i++) {
67+
if ( !((previousButtonState>>i)&1) && ((currentButtonState>>i)&1) ) buttonFirstPress|=_BV(i);
68+
else buttonFirstPress&=~_BV(i);
69+
70+
if ( ((previousButtonState>>i)&1) && ((currentButtonState>>i)&1) ) {
71+
if (buttonHoldTime[i]<0xFFFF) buttonHoldTime[i]+=1;
72+
}
73+
else buttonHoldTime[i]=0;
74+
}
75+
}
76+
77+
bool HT16K33::getButtonFirstPress(uint8_t i) {
78+
return (buttonFirstPress>>i)&1;
79+
}
80+
81+
uint16_t HT16K33::getButtonHoldTime(uint8_t i) {
82+
return buttonHoldTime[i];
83+
}
84+
85+
bool HT16K33::allowToMove(uint8_t i, uint16_t time, uint8_t rate) {
86+
// if first press, or hold time >time (time/50=sec) and %rate=0 (to reduce the rate)
87+
return (getButtonFirstPress(i) || (getButtonHoldTime(i)>time && getButtonHoldTime(i)%rate==0));
88+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include "Arduino.h"
2+
3+
#define DISP_REGISTER 0x00
4+
#define KEYS_REGISTER 0x40
5+
#define MAX_BRIGHTNESS 12
6+
#define MIN_BRIGHTNESS 0
7+
#define INITIAL_BRIGHTNESS 1
8+
9+
class HT16K33 {
10+
private:
11+
uint8_t i2c_addr;
12+
uint8_t brightness;
13+
uint8_t buffer[16];
14+
15+
// all four variables are updated in readButtons()
16+
uint8_t previousButtonState; // stored in MSB First format: B7, ... , B0
17+
uint8_t currentButtonState; // stored in MSB First format: B7, ... , B0
18+
uint8_t buttonFirstPress; // stored in MSB First format: B7, ... , B0
19+
uint16_t buttonHoldTime[8]; // stored in LSB First format: B0, ... , B7
20+
21+
uint16_t* transposeMatrix(uint8_t* matrix);
22+
void sendCommand(uint8_t c);
23+
void setBrightness(uint8_t b);
24+
25+
public:
26+
HT16K33(uint8_t _addr);
27+
void init();
28+
void increaseBrightness();
29+
void decreaseBrightness();
30+
31+
void storeToBuffer(uint8_t* matrix);
32+
void refreshDisplay();
33+
void clearDisplay();
34+
void readButtons(); // only reads the first byte of the key scan register becasue only the first 7 keys are used on this device
35+
bool getButtonFirstPress(uint8_t i);
36+
uint16_t getButtonHoldTime(uint8_t i);
37+
bool allowToMove(uint8_t i, uint16_t time, uint8_t rate);
38+
};
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
const uint8_t tetrisBoot[16]={
2+
B00000000,
3+
B00000000,
4+
B00001000,
5+
B00001100,
6+
B00000100,
7+
B00000000,
8+
B00000000,
9+
B00100000,
10+
B11100000,
11+
B11111010,
12+
B10111110,
13+
B11011110,
14+
B01111111,
15+
B11111101,
16+
B11011111,
17+
B10110111
18+
};
19+
20+
const uint8_t snakeBoot[16]={
21+
B00000000,
22+
B00000000,
23+
B00000100,
24+
B00000000,
25+
B00000000,
26+
B00000000,
27+
B00000100,
28+
B00000100,
29+
B00000100,
30+
B01111100,
31+
B01000000,
32+
B01000000,
33+
B01100000,
34+
B00100000,
35+
B00100000,
36+
B00100000
37+
};
38+
39+
const uint8_t paintBoot[16]={
40+
B01100000,
41+
B11000000,
42+
B10000010,
43+
B00001010,
44+
B00011110,
45+
B00110110,
46+
B01100011,
47+
B11000001,
48+
B01010101,
49+
B01010001,
50+
B01111111,
51+
B00101000,
52+
B11101111,
53+
B00000000,
54+
B11011011,
55+
B00000000
56+
};
57+
58+
uint8_t option=1;
59+
60+
void changeMode(){
61+
mode = option;
62+
}
63+
64+
uint8_t* getMenu(){
65+
switch(option) {
66+
case 1:
67+
return (uint8_t*)tetrisBoot;
68+
case 2:
69+
return (uint8_t*)snakeBoot;
70+
case 3:
71+
return (uint8_t*)paintBoot;
72+
}
73+
return 0;
74+
}
75+
76+
void changeOption(int8_t i){
77+
int8_t temp = option+i;
78+
if (temp<1 || temp>3) return;
79+
option=temp;
80+
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#include "HT16K33.h"
2+
#include "Tetris.h"
3+
#include "Snake.h"
4+
#include "Paint.h"
5+
6+
// ADC clock configurations
7+
#define ADPS_16 _BV(ADPS2)
8+
#define ADPS_32 _BV(ADPS2)|_BV(ADPS0)
9+
#define ADPS_128 _BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0)
10+
11+
// Buttons: bits 0-6 in the first byte of the key-scan matrix
12+
#define LEFT 6
13+
#define SELECT 1
14+
#define DOWN 2
15+
#define UP 5
16+
#define RIGHT 0
17+
#define BRIGHTNESS_UP 4
18+
#define BRIGHTNESS_DOWN 3
19+
20+
// Objects
21+
HT16K33 ht(0x70); // I2C address of the HT16K33 IC
22+
Tetris tetris;
23+
Snake snake;
24+
Paint paint(3,3); // initilize cursor position to (3,3)
25+
26+
// Mode: 0-Undecided; 1-Tetris; 2-Snake; 3-Paint
27+
uint8_t mode=0;
28+
29+
// Interrupt Variables
30+
uint8_t interruptCounter2Hz = 0;
31+
32+
ISR(TIMER1_OVF_vect){
33+
// things that need to be done at 50Hz
34+
ht.readButtons();
35+
processButtons();
36+
switch(mode) {
37+
case 0:
38+
ht.storeToBuffer(getMenu());
39+
break;
40+
case 1:
41+
ht.storeToBuffer(tetris.getActiveBoard());
42+
break;
43+
case 2:
44+
ht.storeToBuffer(snake.getActiveBoard());
45+
break;
46+
case 3:
47+
ht.storeToBuffer(paint.getActiveCanvas());
48+
}
49+
ht.refreshDisplay();
50+
51+
// things that happen less frequently
52+
interruptCounter2Hz++;
53+
if (interruptCounter2Hz==25) {
54+
interruptCounter2Hz=0;
55+
paint.flashCursor();
56+
}
57+
}
58+
59+
void processButtons() {
60+
// These two buttons are fixed
61+
if (ht.allowToMove(BRIGHTNESS_DOWN,25,6) && ht.getButtonHoldTime(SELECT)==0) ht.decreaseBrightness();
62+
if (ht.allowToMove(BRIGHTNESS_UP,25,6) && ht.getButtonHoldTime(SELECT)==0) ht.increaseBrightness();
63+
64+
// change to the previous/next program by pressing holding select and press the brightness control buttons
65+
if (mode!=0 && ht.getButtonHoldTime(SELECT)>10) {
66+
if (ht.getButtonFirstPress(BRIGHTNESS_UP)) {
67+
changeOption(-1);
68+
changeMode();
69+
}
70+
else if (ht.getButtonFirstPress(BRIGHTNESS_DOWN)){
71+
changeOption(1);
72+
changeMode();
73+
}
74+
}
75+
76+
// control for different programs
77+
switch(mode) {
78+
case 0:
79+
if (ht.getButtonFirstPress(LEFT)) changeOption(-1);
80+
if (ht.getButtonFirstPress(RIGHT)) changeOption(1);
81+
if (ht.getButtonFirstPress(SELECT)) changeMode();
82+
break;
83+
case 1:
84+
if (tetris.gameRunning) {
85+
if (ht.allowToMove(UP,100,4)) tetris.rotatePiece();
86+
if (ht.allowToMove(DOWN,15,2)) tetris.movePiece(0,1);
87+
if (ht.allowToMove(LEFT,15,2)) tetris.movePiece(-1,0);
88+
if (ht.allowToMove(RIGHT,15,2)) tetris.movePiece(1,0);
89+
if (ht.getButtonFirstPress(SELECT)) tetris.dropPiece();
90+
}
91+
else {
92+
if (ht.getButtonFirstPress(SELECT)) tetris.init();
93+
}
94+
break;
95+
case 2:
96+
if (snake.gameRunning) {
97+
if (ht.getButtonFirstPress(UP)) snake.changeDirection(0,-1);
98+
if (ht.getButtonFirstPress(DOWN)) snake.changeDirection(0,1);
99+
if (ht.getButtonFirstPress(LEFT)) snake.changeDirection(-1,0);
100+
if (ht.getButtonFirstPress(RIGHT)) snake.changeDirection(1,0);
101+
}
102+
else {
103+
if (ht.getButtonFirstPress(SELECT)) snake.init();
104+
}
105+
break;
106+
case 3:
107+
if (ht.allowToMove(UP,25,2)) paint.moveCursor(0,-1);
108+
if (ht.allowToMove(DOWN,25,2)) paint.moveCursor(0,1);
109+
if (ht.allowToMove(LEFT,25,2)) paint.moveCursor(-1,0);
110+
if (ht.allowToMove(RIGHT,25,2)) paint.moveCursor(1,0);
111+
if (ht.getButtonFirstPress(SELECT)) paint.draw();
112+
if (ht.getButtonHoldTime(SELECT)==150) paint.clearCanvas();
113+
}
114+
}
115+
116+
void setup(){
117+
// Set randomSeed; the first few random() are not used because they never change
118+
randomSeed(analogRead(A0));
119+
for (uint8_t i=0;i<4;i++) random();
120+
121+
// Initiate objects
122+
Serial.begin(115200);
123+
ht.init();
124+
tetris.init();
125+
snake.init();
126+
127+
//ADC: 16MHz/16=1MHz
128+
ADCSRA &= ~ADPS_128; // clean out ADPS
129+
ADCSRA |= ADPS_32; // set Division Factor
130+
131+
// Timer1 overflow interrupt setup
132+
TCNT1 = 0; // reset the counter
133+
ICR1 = 19999; // top value of the counter (16*10^6Hz/2000000*20000us/8-1) -> 1/20000us = 50Hz
134+
TCCR1A = 0; // clear TCCR1A (not used)
135+
TCCR1B = _BV(WGM13) | _BV(CS11); // mode 8(PWM), set prescalar=8;
136+
TIMSK1 = _BV(TOIE1); // Enable Overflow Interrupt
137+
}
138+
139+
void loop(){
140+
// For both the tetris and snake, they have a function called "run" as the main game loop.
141+
// For the paint program, all the actions are handled in the timer interrupt, so there is nothing to do in the main loop
142+
switch(mode) {
143+
case 0:
144+
break;
145+
case 1:
146+
tetris.run(); break;
147+
case 2:
148+
snake.run(); break;
149+
case 3:
150+
;
151+
}
152+
}

0 commit comments

Comments
 (0)