I'm constructing a device to measure power and display in a 16x2 LCD in a given power source. I'm using the above mentioned sensors to read current and voltage through ADC in ATMega32. Voltage sensor is connected to PA0 and current sensor to PA1.
I did a calibration and found a relationship between bit value and actual current/voltage. From these actual values, my aim is to do a discrete Fourier transformation as the power gets alternate with the time if I only display the actual values. I have constructed a C code as follows:
#define F_CPU 8000000UL // CPU Frequency to 8MHz
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#define LCD_Dir DDRC
#define LCD_Port PORTC
#define RS PC0
#define EN PC1
#define VOLTAGE_SENSOR_CHANNEL 0
#define CURRENT_SENSOR_CHANNEL 1
#define N 256 // Number of data points
// Sampled voltage and current data
double voltage_data[N];
double current_data[N];
double power_data[N];
// Function to perform DFT on a single frequency component
void dft(double data[], int n, double* result_real, double* result_imag, double frequency) {
*result_real = 0;
*result_imag = 0;
for (int k = 0; k < n; k++) {
double angle = 2.0 * M_PI * frequency * k / n;
*result_real += data[k] * cos(angle);
*result_imag -= data[k] * sin(angle); // Use subtraction here for the imaginary part
}
}
// Function to initialize ADC
void ADC_init(void) {
DDRA = 0x00;
ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
ADMUX |= (1 << REFS0);
}
// Function to read ADC value from a specified channel
uint16_t ADC_read(uint8_t channel) {
ADMUX = (ADMUX & 0xF8) | (channel & 0x07);
ADCSRA |= (1 << ADSC);
while (!(ADCSRA & (1 << ADIF)));
ADCSRA |= (1 << ADIF);
_delay_ms(1);
return ADCW;
}
// Function to convert ADC reading to voltage
double ADC_to_Voltage(uint16_t adcValue) {
double voltage = (adcValue * 2.0457) - 1305.2;
return voltage;
}
// Function to convert ADC reading to current
double ADC_to_Current(uint16_t adcValue) {
double current = (adcValue * 0.056311) - 35.617;
return current;
}
// Function to calculate power using DFT
double calculatePower(double voltage[], double current[], int n, double frequency) {
double voltage_real, voltage_imag;
double current_real, current_imag;
dft(voltage_data, n, &voltage_real, &voltage_imag, frequency);
dft(current_data, n, ¤t_real, ¤t_imag, frequency);
// Calculate real power as the product of the real parts of voltage and current
double real_power = voltage_real * current_real + voltage_imag * current_imag;
return real_power;
}
// Function to send LCD command
void LCD_Command(unsigned char cmnd) {
LCD_Port = (LCD_Port & 0x0F) | (cmnd & 0xF0);
LCD_Port &= ~(1 << RS);
LCD_Port |= (1 << EN);
_delay_us(1);
LCD_Port &= ~(1 << EN);
_delay_us(200);
LCD_Port = (LCD_Port & 0x0F) | (cmnd << 4);
LCD_Port |= (1 << EN);
_delay_us(1);
LCD_Port &= ~(1 << EN);
_delay_ms(2);
}
// LCD data writing function
void LCD_Char(unsigned char data) {
LCD_Port = (LCD_Port & 0x0F) | (data & 0xF0);
LCD_Port |= (1 << RS);
LCD_Port |= (1 << EN);
_delay_us(1);
LCD_Port &= ~(1 << EN);
_delay_us(200);
LCD_Port = (LCD_Port & 0x0F) | (data << 4);
LCD_Port |= (1 << EN);
_delay_us(1);
LCD_Port &= ~(1 << EN);
_delay_ms(2);
}
// LCD Initialization function
void LCD_Init (void) {
LCD_Dir = 0xFF;
_delay_ms(20);
LCD_Command(0x02);
LCD_Command(0x28);
LCD_Command(0x0C);
LCD_Command(0x06);
LCD_Command(0x01);
_delay_ms(2);
}
// Function to display a string on the LCD
void LCD_String(char *str) {
int i;
for (i = 0; str[i] != 0; i++) {
LCD_Char(str[i]);
}
}
// Function to display a string on the LCD with specified position
void LCD_String_xy(char row, char pos, char *str) {
if (row == 0 && pos < 16)
LCD_Command((pos & 0x0F) | 0x80);
else if (row == 1 && pos < 16)
LCD_Command((pos & 0x0F) | 0xC0);
LCD_String(str);
}
void displayPower(double power_val) {
char powerStr[16];
sprintf(powerStr, "Power: %.2f W", power_val);
// Implement a scrolling mechanism here
int len = strlen(powerStr);
int i;
for (i = 0; i <= len; i++) {
LCD_Command(0x01); // Clear display screen
_delay_ms(2);
LCD_String_xy(0, 0, powerStr + i);
_delay_ms(500); // Delay for scrolling speed
}
}
int main(void) {
LCD_Init();
ADC_init();
int data_index = 0;
while (1) {
// Read ADC values from voltage and current sensors
uint16_t voltage_adc = ADC_read(VOLTAGE_SENSOR_CHANNEL);
uint16_t current_adc = ADC_read(CURRENT_SENSOR_CHANNEL);
// Convert ADC readings to voltage and current with calibration
double current = ADC_to_Current(current_adc);
double voltage = ADC_to_Voltage(voltage_adc);
// Store the latest voltage and current values in the data arrays
voltage_data[data_index] = voltage;
current_data[data_index] = current;
// Increment the data index (use a circular buffer implementation if needed)
data_index++;
if (data_index >= N) {
data_index = 0;
}
// Calculate power using DFT
double power = calculatePower(voltage_data, current_data, N, 60.0);
// Store the calculated power value
power_data[data_index] = power;
// Display real power on LCD and scroll through values
displayPower(power_data[data_index]);
_delay_ms(1);
}
return 0;
}
However this does not display the real output. Can someone help me to figure out where I have gone wrong and to do a Discrete Fourier Transformation and display the real values?