#include <Arduino.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define CS_LOW() PORTB &= ~(1 << PB0)
#define CS_HIGH() PORTB |= (1 << PB0)
#define SD_BLOCK_SIZE 512
volatile bool writeDataFlag = false;
void setup() {
Serial.begin(9600); // Initialize Serial for debugging
init_port();
init_lcd();
adc_init();
SPI_Init();
timer1_init();
sei(); // Enable global interrupts
// Read ADC and calculate temperature
uint16_t adc_value = adc_read();
float temperature = convertToCelsius(adc_value);
// Convert temperature to string
char temperature_buffer[10];
int temperature_int = (int)(temperature * 10.0 + 0.5);
sprintf(temperature_buffer, "%d.%d", temperature_int / 10, temperature_int % 10);
// Display temperature on LCD
write_string("Temp: ");
write_string(temperature_buffer);
write_string("C");
// Output to Serial Monitor
Serial.print("Temperature: ");
Serial.print(temperature_buffer);
Serial.println(" C");
}
void loop() {
if (writeDataFlag) {
// Ensure the flag is processed once per interrupt
writeDataFlag = false;
// Read ADC value and convert to temperature
uint16_t adc_value = adc_read();
float temperature = convertToCelsius(adc_value);
// Format the temperature data
char buffer[50];
int temp_int = (int)(temperature * 10 + 0.5);
sprintf(buffer, "%d.%d", temp_int / 10, temp_int % 10);
// Simulate writing to SD card by printing to Serial Monitor
Serial.print("Writing to SD card: ");
Serial.println(buffer);
}
}
void write_string(char *ptr) {
while (*ptr != 0) {
write_data(*ptr);
ptr++;
}
}
void init_port() {
volatile char *portf_dir = (volatile char *)0x21;
volatile char *portk_dir = (volatile char *)0x107;
volatile char *portf = (volatile char *)0x30;
*portf_dir = 0xFF; // Set PORTF as output for data
*portk_dir = 0x03; // Set PORTK as output for control
*portf = 0x00; // Initialize PORTF to 0
}
void outdata(char out_data) {
volatile char *portf_data = (volatile char *)0x22;
*portf_data = out_data;
}
void outcontrol(char out_data) {
volatile char *portk_data = (volatile char *)0x108;
*portk_data = out_data;
}
void init_lcd(void) {
_delay_ms(20); // Wait for LCD to power up
outdata(0x38); // Function set: 8-bit mode, 2 lines, 5x8 dots
lcd_control_write();
_delay_ms(5);
outdata(0x0F); // Display on, cursor on, blinking on
lcd_control_write();
_delay_ms(5);
outdata(0x01); // Clear display
lcd_control_write();
_delay_ms(5);
outdata(0x06); // Entry mode set: increment cursor, no display shift
lcd_control_write();
_delay_ms(5);
}
void write_data(char wr_data) {
outdata(wr_data);
outcontrol(0x02); // RS = 1, E = 0
_delay_us(50); // Enable pulse width
outcontrol(0x03); // E = 1
_delay_us(50); // Enable pulse width
outcontrol(0x02); // E = 0
_delay_ms(2); // Wait for command execution
}
void lcd_control_write(void) {
outcontrol(0x01); // RS = 0, E = 0
_delay_us(50); // Enable pulse width
outcontrol(0x00); // E = 1
_delay_us(50); // Enable pulse width
outcontrol(0x01); // E = 0
_delay_ms(2); // Wait for command execution
}
void adc_init(void) {
ADCSRA = 0x87; // ADC enable, prescaler of 128
ADMUX = 0x40; // AVcc reference, ADC0 input
}
uint16_t adc_read(void) {
ADCSRA |= (1 << ADSC); // Start conversion
while (ADCSRA & (1 << ADSC)); // Wait for conversion to complete
return ADC;
}
float convertToCelsius(uint16_t analogValue) {
float cel = 1 / (log(1 / (1023. / analogValue - 1)) / 3950 + 1 / 298.15) - 273.15;
return cel;
}
void SPI_Init(void) {
DDRB |= (1 << PB2) | (1 << PB1) | (1 << PB0); // MOSI, SCK, SS as output
DDRB &= ~(1 << PB3); // MISO as input
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable, master mode, clock rate fck/128
SPSR &= ~(1 << SPI2X); // SPI2X = 0
}
uint8_t SPI_TransmitReceive(uint8_t data) {
SPDR = data;
while (!(SPSR & (1 << SPIF))); // Wait for transmission to complete
return SPDR;
}
uint8_t SD_SendCommand(uint8_t cmd, uint32_t arg) {
uint8_t response, i;
SPI_TransmitReceive(cmd | 0x40); // Send command
SPI_TransmitReceive(arg >> 24);
SPI_TransmitReceive(arg >> 16);
SPI_TransmitReceive(arg >> 8);
SPI_TransmitReceive(arg);
SPI_TransmitReceive(0x95); // CRC for CMD0
for (i = 0; i < 8; i++) {
response = SPI_TransmitReceive(0xFF);
if (response != 0xFF) break;
}
return response;
}
uint8_t SD_Init(void) {
uint8_t response, i;
CS_HIGH();
for (i = 0; i < 10; i++) SPI_TransmitReceive(0xFF);
CS_LOW();
response = SD_SendCommand(0, 0); // CMD0
CS_HIGH();
if (response != 0x01) return 1;
while (response != 0x00) {
CS_LOW();
response = SD_SendCommand(1, 0); // CMD1
CS_HIGH();
}
return 0;
}
uint8_t SD_WriteBlock(uint32_t block, const uint8_t* data) {
uint8_t response;
uint16_t i;
block *= SD_BLOCK_SIZE;
CS_LOW();
response = SD_SendCommand(24, block); // CMD24
if (response != 0x00) {
CS_HIGH();
return 1;
}
SPI_TransmitReceive(0xFE);
for (i = 0; i < SD_BLOCK_SIZE; i++) {
SPI_TransmitReceive(data[i]);
}
SPI_TransmitReceive(0xFF); // Dummy CRC
SPI_TransmitReceive(0xFF); // Dummy CRC
response = SPI_TransmitReceive(0xFF);
if ((response & 0x1F) != 0x05) {
CS_HIGH();
return 1;
}
while (SPI_TransmitReceive(0xFF) == 0x00); // Wait for data programming
CS_HIGH();
return 0;
}
void timer1_init(void) {
TCCR1A = 0x00;
TCCR1B = 0x0C; // CTC mode, prescaler 256
TCNT1 = 0x00;
OCR1A = 625000000000000000000000; // Compare match value for 1Hz (assuming 16MHz clock)
TIMSK1 = 0x02; // Enable Timer1 compare interrupt
}
ISR(TIMER1_COMPA_vect) {
writeDataFlag = true; // Set the flag to true when interrupt occurs
}