I'm writing program in CodeVisionAVR for a reciever and transmitter part of a project. the transmitter MCU(ATmega32) is actually the data logger using MQ9 and BMP280 and it sends the chunks of data using usart to a reciever atmega32 and then it saves it in AT24C512 eeprom then reads the data and displays the entire chunk on the lcd2x16.
reciever:
#include <mega32.h>
#include <delay.h>
#include <twi.h>
// Alphanumeric LCD functions
#include <alcd.h>
// Define constants for EEPROM size and chunk size
#define EEPROM_SIZE 524288 // 512 KB
#define CHUNK_SIZE 17
// Declare your global variables here
unsigned char ch;
unsigned int j=0;
unsigned int currentWriteAddress = 0;
unsigned char receivedData[20]; // Buffer to store received data
volatile unsigned int dataIndex = 0; // Index for the buffer
volatile unsigned char dataReady = 0;
unsigned char bufferSize=17;
unsigned char at24c512_buff[130];
unsigned char read_buff[20];
// Standard Input/Output functions
#include <stdio.h>
void at24c512_write(unsigned char device_addr, unsigned int data_addr, unsigned char *buffer, unsigned char count);
void at24c512_read(unsigned char device_addr, unsigned int data_addr, unsigned char *buffer, unsigned char count);
void at24c512_read_last_chunks(unsigned char *buffer, unsigned char count);
void usart_init()
{
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: Off
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=(1<<RXCIE) | (1<<RXEN);
UCSRC=(1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
UBRRH=0x00;
UBRRL=0x33;
#asm("sei")
}
// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
ch = UDR; // Read the received character
if (ch == '\n') // Check for end of data
{
//receivedData[dataIndex] = '\0'; // Null-terminate the string
dataReady = 1; // Set the data ready flag
dataIndex = 0; // Reset the index for the next data
}
else
{
if (dataIndex < sizeof(receivedData) - 1) // Check for buffer overflow
{
receivedData[dataIndex++] = ch; // Store the character in the buffer
}
}
}
void main(void)
{
// Declare your local variables here
unsigned char lastChunks[2 * CHUNK_SIZE];
usart_init();
// Alphanumeric LCD initialization
// Connections are specified in the
// Project|Configure|C Compiler|Libraries|Alphanumeric LCD menu:
// RS - PORTB Bit 0
// RD - PORTB Bit 1
// EN - PORTB Bit 2
// D4 - PORTB Bit 4
// D5 - PORTB Bit 5
// D6 - PORTB Bit 6
// D7 - PORTB Bit 7
// Characters/line: 16
lcd_init(16);
twi_master_init(100); //I2C clock is set to 100kHz
while (1)
{
if (dataReady)
{
unsigned int writeAddress = currentWriteAddress;
at24c512_write(0x00, writeAddress, receivedData, bufferSize);
currentWriteAddress = (currentWriteAddress + CHUNK_SIZE) % EEPROM_SIZE;
delay_ms(100);
at24c512_read_last_chunks(lastChunks, 2 * CHUNK_SIZE);
//at24c512_read(0x00, writeAddress, read_buff, bufferSize);
// Clear the buffer
for (j = 0; j < sizeof(receivedData); j++)
{
receivedData[j] = '\0';
}
lcd_gotoxy(0, 0);
lcd_putsf("Last 2 chunks of recieved data:");
delay_ms(1000);
lcd_clear();
lcd_gotoxy(0, 0);
lcd_puts(lastChunks); // Display the received data
dataReady = 0; // Reset the data ready flag
delay_ms(2000);
lcd_clear();
}
}
}
void at24c512_write(unsigned char device_addr,
unsigned int data_addr,
unsigned char *buffer,
unsigned char count)
{
unsigned char i;
device_addr += 0x50;
at24c512_buff[0] = (data_addr&0xFF00)>>8;
at24c512_buff[1] = (data_addr&0x00FF);
for(i=0;i<count;i++) at24c512_buff[i+2] = buffer[i];
twi_master_trans(device_addr, at24c512_buff, count+2, 0, 0);
}
void at24c512_read(unsigned char device_addr,
unsigned int data_addr,
unsigned char *buffer,
unsigned char count)
{
device_addr += 0x50;
at24c512_buff[0] = (data_addr&0xFF00)>>8;
at24c512_buff[1] = (data_addr&0x00FF);
twi_master_trans(device_addr, at24c512_buff, 2, buffer, count);
}
void at24c512_read_last_chunks(unsigned char *buffer, unsigned char count)
{
// Calculate the read address for the last chunk of data
unsigned int readAddress = (currentWriteAddress - CHUNK_SIZE) % EEPROM_SIZE;
// Read the last chunk of data from the EEPROM
at24c512_read(0x00, readAddress, buffer, count);
}
transmitter:
#include <mega32.h>
#include <delay.h>
#include <stdio.h>
#include <stdlib.h>
// I2C Bus functions
#include <i2c.h>
// Alphanumeric LCD functions
#include <alcd.h>
#define BMP280_I2C_ADDRESS 0xEC
#include <BMP280_Lib.c>
char lcd[16];
int32_t temperature;
uint32_t pressure;
float i;
int MQ9;
// Voltage Reference: AREF pin
#define ADC_VREF_TYPE ((0<<REFS1) | (0<<REFS0) | (0<<ADLAR))
// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | ADC_VREF_TYPE;
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=(1<<ADSC);
// Wait for the AD conversion to complete
while ((ADCSRA & (1<<ADIF))==0);
ADCSRA|=(1<<ADIF);
return ADCW;
}
void adc_init(unsigned char prescaler)
{
// ADC initialization
// ADC Clock frequency: 1000.000 kHz
// ADC Voltage Reference: AREF pin
// ADC Auto Trigger Source: ADC Stopped
ADMUX = ADC_VREF_TYPE;
ADCSRA = (1 << ADEN) | (0 << ADSC) | (0 << ADATE) | (0 << ADIF) | (0 << ADIE);
//default MCU clock frequency is considered 8MHz.
//for 1000.000 kHz ADC frequency, prescaler 64 is used with ADPS registers.
switch (prescaler)
{
case 2:
ADCSRA |= (0 << ADPS2) | (0 << ADPS1) | (1 << ADPS0);
break;
case 4:
ADCSRA |= (0 << ADPS2) | (1 << ADPS1) | (0 << ADPS0);
break;
case 8:
ADCSRA |= (0 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
break;
case 16:
ADCSRA |= (1 << ADPS2) | (0 << ADPS1) | (0 << ADPS0);
break;
case 32:
ADCSRA |= (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0);
break;
case 64:
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0);
break;
case 128:
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
break;
default:
// Default to prescaler 64
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0);
break;
}
SFIOR = (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0);
}
void usart_init()
{
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: Off
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0;
UCSRB= (1<<TXEN) ;
UCSRC=(1<<URSEL)| (1<<UCSZ1) | (1<<UCSZ0);
UBRRH=0x00;
UBRRL=0x33;
}
void main(void)
{
// Declare your local variables here
// Input/Output Ports initialization
// Port A initialization
DDRA= (0<<DDA0);
PORTA= (0<<PORTA0);
// Bit-Banged I2C Bus initialization
// I2C Port: PORTC
// I2C SDA bit: 1
// I2C SCL bit: 0
// Bit Rate: 100 kHz
// Note: I2C settings are specified in the
// Project|Configure|C Compiler|Libraries|I2C menu.
i2c_init();
// Alphanumeric LCD initialization
// Connections are specified in the
// Project|Configure|C Compiler|Libraries|Alphanumeric LCD menu:
// RS - PORTB Bit 0
// RD - PORTB Bit 1
// EN - PORTB Bit 2
// D4 - PORTB Bit 4
// D5 - PORTB Bit 5
// D6 - PORTB Bit 6
// D7 - PORTB Bit 7
// Characters/line: 16
lcd_init(16);
adc_init(64);
usart_init();
// initialize the BMP280 sensor
if(BMP280_begin() == 0)
{ // connection error or device address wrong!
lcd_gotoxy(0, 0);
putsf("Connection error!");
}
while (1)
{
// Read temperature (in hundredths C) and pressure (in Pa)
// values from BMP280 sensor
BMP280_readTemperature(&temperature); // read temperature
BMP280_readPressure(&pressure); // read pressure
i=read_adc(0);
MQ9=(i*100)/1023 ;
// print data on the LCD screen
// 1: print temperature
// 2: print pressure
lcd_gotoxy(0, 0);
if(temperature < 0)
{
putchar('-');
temperature = abs(temperature);
}
else
sprintf(lcd, "%02u.%02u,%04u.%02u,%d", temperature / 100, temperature % 100, pressure / 100, pressure % 100, MQ9);
puts(lcd);
delay_ms(2000); // wait 2 seconds
}
}
but I want to modify the code in this way:
for the transmitter; it should send each chunk of data every 20 milliseconds.
and for the reciever; the timer must get activated using interrupt every 5 seconds. then we should put a flag in the timer which is gonna be checked in the if without delay part whether it has been set to one or not.
if it was, the data in the eeprom is gonna be read and it gonna be sent through usart and the previous data in eeprom must be deleted.
then the address index of the eeprom will be set to zero again.
finally the interrupt on the reciever's usart must get activated.
note that there is a higher priority for the timer's interrupt.
I constantly get errors writing this and simulating it in Proteus.