/*
Able to use PROGMEM by using #include avr/pgmspace.h
See https://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html#ga73084a8bbde259ffae72980354b3f027
for details.
CM 10/15/24: This sketch is working well.
- Create a huminoid looking robot with the 8x8 display as its head. The body could
encorperate the ATtiny85, maybe a pulsing LED for a heart?
*/
#include <avr/pgmspace.h> // used with 'PROGMEM'
#include"data_bytes.h" // MAX7219 animation arrays
uint8_t position = 0;
static uint8_t MAX7219_state[8] = {0,0,0,0,0,0,0,0}; // used with MAX7219_set_pixel
unsigned int randNum_row;
unsigned int randNum_col;
uint8_t pixel = 0;
void setup() {
MAX7219_init();
/*
if analog input pin (pin number) is unconnected, random analog noise will cause the call to randomSeed() to generate
different seed numbers each time the sketch runs. randomSeed() will then shuffle the random function.
*/
randomSeed(analogRead(A0)); // Pin PB5 = ADC0
}
void loop() {
/*
MAX7219_clear_display();
// ---------------------------------------------
// Display a static 8x8 image from a 1D array
display_byte_array(smiley);
delay(1000);
// MAX7219_clear_display();
// ---------------------------------------------
// Displays a static 8x8 image from one row of a 2D array
display_byte_2D_array(dogface, 0);
delay(200);
display_byte_2D_array(dogface, 1);
delay(200);
display_byte_2D_array(dogface, 0);
delay(200);
display_byte_2D_array(dogface, 1);
delay(200);
display_byte_2D_array(dogface, 0);
delay(200);
display_byte_2D_array(dogface, 1);
delay(200);
display_byte_2D_array(dogface, 0);
delay(200);
display_byte_2D_array(dogface, 1);
delay(200);
// ---------------------------------------------
// Displays scrolling 'invader' array, with delay (array name)
scrolling_2D_array_with_delay(invader1);
delay(1000);
// ---------------------------------------------
// Displays scrolling 'invader' array, with delay (array name)
scrolling_2D_array_with_delay(invader2);
delay(1000);
// ---------------------------------------------
// Displays scrolling array, (array name, number of rows)
scrolling_2D_array(LSU, 28);
delay(1000); // delay until next function is run
MAX7219_clear_display();
scrolling_2D_array(running_man_LR, 21);
delay(1000); // delay until next function is run
MAX7219_clear_display();
scrolling_2D_array(dancing_man_RL, 45);
delay(1000); // delay until next function is run
MAX7219_clear_display();
scrolling_2D_array(heart, 57);
delay(1000); // delay until next function is run
// ---------------------------------------------
MAX7219_clear_display();
// Display one pixel, (row 0 to 7, column 0 to 7, ON = 1)
MAX7219_set_pixel(7, 0, 1);
delay(1000);
MAX7219_clear_display();
// ---------------------------------------------
// displays random pixels. Time of while loop is set in function
// with '100' equaling 1 second. delay(10) x 100 = 1000ms
random_pixels(500);
delay(1000); // delay until next function is run
// ---------------------------------------------
*/
}
// = = = = = = = = = = = FUNCTIONS = = = = = = = = = = = = =
void MAX7219_init() {
// PB0 -> DIN, PB1 -> CS, PB2 -> CLK
DDRB |= (1 << PB0) | (1 << PB1) | (1 << PB2); // Set pins as outputs
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MAX7219_write(0x09, 0); // Decode-Mode Register: No decode for digits 7–0
MAX7219_write(0x0A, 8); // Intensity Register: Format 0 to 16
MAX7219_write(0x0B, 7); // Scan-Limit Register: Display digits 0 1 2 3 4 5 6 7
MAX7219_write(0x0C, 1); // Shutdown Register: Normal Operation, turn on MAX7219
}
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
void SPI_send(uint8_t data) { // variable 'data' is used in 'command_byte' and 'data_byte'
for (uint8_t i = 0; i < 8; i++) { // try uint8_t i = 8; i >= 1; i-- (no difference) // Loop 8 times to shift out MSB first, of byte to MAX7219
PORTB &= ~(1 << PB2); // Set CLK to LOW
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if (data & 0b10000000) { // Mask the MSB 0x80 of the data
PORTB |= (1 << PB0); // Set DIN to HIGH if MSB = 1
}
else (PORTB &= ~(1 << PB0)); // Set DIN to LOW if MSB = 0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PORTB |= (1 << PB2); // Set CLK to HIGH
data = data << 1; // Shift data to left 1 bit
}
}
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Write to a row, 1 through 8
void MAX7219_write(uint8_t command_byte, uint8_t data_byte) {
PORTB &= ~(1 << PB1); // CS set LOW to enable MAX7219
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SPI_send(command_byte); // Send command byte
SPI_send(data_byte); // Send data byte
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PORTB |= (1 << PB1); // CS set HIGH to disable MAX7219
}
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
void MAX7219_clear_display() {
uint8_t i;
for (i = 0; i < 8; i++) {
MAX7219_write(i + 1, 0);
}
}
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Display one pixel, (row 0 to 7, column 0 to 7, ON = 1)
void MAX7219_set_pixel(uint8_t row, uint8_t col, bool value) {
uint8_t data;
if (row > 7 || col > 7)
return;
data = 1 << col;
if (value) {
MAX7219_state[row] |= data;
}
else {
MAX7219_state[row] &= ~data;
}
MAX7219_write(row + 1, MAX7219_state[row]);
}
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Display a static 8x8 image from a 1D array
void display_byte_array(uint8_t image[8]) {
uint8_t i;
for (i = 0; i < 8; i++) {
MAX7219_write(i + 1, image[i]); // Write to rows 1 through 8
}
}
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Displays a static 8x8 image from one row of a 2D array
void display_byte_2D_array(uint8_t image[][8], uint8_t num) {
uint8_t i;
for (i = 0; i < 8; i++) {
// MAX7219_write(i + 1, image[num][i]); // Use without PROGMEM
MAX7219_write(i + 1, pgm_read_byte(&image[num][i])); // Use with PROGMEM
}
}
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Displays scrolling 'invader' array, with delay (array name)
void scrolling_2D_array_with_delay(uint8_t image[][8]) {
for (uint8_t j = 0; j < 21; j++) {
if (j == 9 || j == 10 || j == 11 || j == 12) {
delay(250);
}
else {
delay(100);
}
for (uint8_t i = 0; i < 8; i++) {
// MAX7219_write(i + 1, image[j][i]); // Use without PROGMEM
MAX7219_write(i + 1, pgm_read_byte(&image[j][i])); // Use with PROGMEM
}
}
}
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Displays scrolling array, (array name, number of rows)
void scrolling_2D_array(uint8_t image[][8], uint8_t num) {
for (uint8_t j = 0; j < num; j++) {
delay(180);
for (uint8_t i = 0; i < 8; i++) {
//MAX7219_write(i + 1, image[j][i]); // Use without PROGMEM
MAX7219_write(i + 1, pgm_read_byte(&image[j][i])); // Use with PROGMEM
}
}
}
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// displays random pixels. Time of while loop is set in function
// with '100' equaling 1 second. delay(10) x 100 = 1000ms
void random_pixels(uint16_t count) {
uint16_t num = 0;
while (num < count) {
randNum_row = random(8);
randNum_col = random(8);
MAX7219_set_pixel(randNum_row, randNum_col, ++pixel & 0x01);
delay(10);
num = num + 1;
}
}
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =