#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#define RTC_WRITE_MODE_ADDRESS 0xD0
#define RTC_READ_MODE_ADDRESS 0xD1
#define DS1307_SECOND_ADDRESS 0x00
#define DDR_SPI DDRB // Define Data Direction Register for SPI
#define DD_MOSI PB3 // MOSI pin
#define DD_SCK PB5 // SCK pin
#define DD_SS PB2 // SS pin for the MAX7219
#define no_op_address 0x00
#define no_op_data 0x00
void I2C_Init(void);
void I2C_Start(void);
void I2C_Stop(void);
void I2C_Write(uint8_t data);
uint8_t I2C_Read_NACK(void);
volatile uint8_t read_second(void);
void SPI_MasterTransmit(uint8_t cData);
void SPI_MasterInit(void);
void send_7219_matrix(uint8_t address, uint8_t data, uint8_t matrix_no);
void displaySecondsOnMAX7219(uint8_t seconds);
void MAX7219_Init(uint8_t matrix_no);
void initializeAllMAX7219(void);
const uint8_t numbers[10] = {
0b11111100, // 0
0b01100000, // 1
0b11011010, // 2
0b11110010, // 3
0b01100110, // 4
0b10110110, // 5
0b10111110, // 6
0b11100000, // 7
0b11111110, // 8
0b11110110 // 9
};
int main(void) {
I2C_Init(); // Initialize I2C communication
SPI_MasterInit(); // Initialize SPI for MAX7219 communication
initializeAllMAX7219(); // Initialize all MAX7219 modules
while (1) {
// Read seconds from DS1307
uint8_t seconds = read_second();
// Display the seconds on MAX7219 modules
displaySecondsOnMAX7219(seconds);
_delay_ms(1000); // Wait for 1 second before updating the time
}
}
// Initialize SPI in Master mode
void SPI_MasterInit(void) {
DDR_SPI = (1 << DD_MOSI) | (1 << DD_SCK) | (1 << DD_SS); // Set MOSI, SCK, and SS as output
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); // Enable SPI, set as Master, clock rate f/16
}
void SPI_MasterTransmit(uint8_t cData) {
SPDR = cData; // Load data into SPI data register
while (!(SPSR & (1 << SPIF))); // Wait until transmission is complete
}
// Function to send data to a specific MAX7219 module
void send_7219_matrix(uint8_t address, uint8_t data, uint8_t matrix_no) {
PORTB &= ~(1 << DD_SS); // Select MAX7219 by pulling SS low
for (uint8_t i = 1; i <= 6; i++) { // Adjust to target 6 matrices
if (i == matrix_no) {
SPI_MasterTransmit(address); // Send register address for target matrix
SPI_MasterTransmit(data); // Send data for target matrix
} else {
SPI_MasterTransmit(no_op_address); // Send no-operation command to other matrices
SPI_MasterTransmit(no_op_data);
}
}
PORTB |= (1 << DD_SS); // Deselect MAX7219 by pulling SS high
}
// Initialize MAX7219 with specific settings
void MAX7219_Init(uint8_t matrix_no) {
send_7219_matrix(0x09, 0x00, matrix_no); // No decode mode
send_7219_matrix(0x0A, 0x03, matrix_no); // Intensity level
send_7219_matrix(0x0B, 0x07, matrix_no); // Scan limit (all 8 rows)
send_7219_matrix(0x0C, 0x01, matrix_no); // Turn on the display
send_7219_matrix(0x0F, 0x00, matrix_no); // No display test
}
// Initialize all MAX7219 modules
void initializeAllMAX7219(void) {
for (uint8_t i = 1; i <= 6; i++) {
MAX7219_Init(i);
}
}
// Function to display seconds on the MAX7219
void displaySecondsOnMAX7219(uint8_t seconds) {
// Display each digit of the seconds value on different MAX7219
send_7219_matrix(1, numbers[seconds / 10], 5); // Tens of seconds on the 5th matrix
send_7219_matrix(1, numbers[seconds % 10], 6); // Units of seconds on the 6th matrix
}
// I2C Initialization
void I2C_Init(void) {
TWSR = 0x00; // Set prescaler to 1
TWBR = 0x48; // Set bit rate (SCL frequency is 100 kHz with 16 MHz F_CPU)
TWCR = (1 << TWEN); // Enable TWI
}
// I2C Start Condition
void I2C_Start(void) {
TWCR = (1 << TWSTA) | (1 << TWEN) | (1 << TWINT);
while (!(TWCR & (1 << TWINT))); // Wait for TWINT Flag set
}
// I2C Stop Condition
void I2C_Stop(void) {
TWCR = (1 << TWSTO) | (1 << TWEN) | (1 << TWINT);
}
// I2C Write Data
void I2C_Write(uint8_t data) {
TWDR = data;
TWCR = (1 << TWEN) | (1 << TWINT);
while (!(TWCR & (1 << TWINT)));
}
// I2C Read Data with NACK
uint8_t I2C_Read_NACK(void) {
TWCR = (1 << TWEN) | (1 << TWINT);
while (!(TWCR & (1 << TWINT)));
return TWDR;
}
// Read seconds from DS1307
volatile uint8_t read_second(void) {
I2C_Start();
I2C_Write(RTC_WRITE_MODE_ADDRESS);
I2C_Write(DS1307_SECOND_ADDRESS);
I2C_Start();
I2C_Write(RTC_READ_MODE_ADDRESS);
uint8_t seconds = I2C_Read_NACK();
I2C_Stop();
return seconds;
}