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.
我正在构建一个设备来测量功率,并在给定电源下在16x2 LCD上显示。我正在使用上面提到的传感器在ATMega32中通过ADC读取电流和电压。电压传感器连接到PA0,电流传感器连接到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:
我做了一个校准,发现了位值和实际电流/电压之间的关系。根据这些实际值,我的目标是进行离散傅立叶变换,因为如果我只显示实际值,则功率与时间交替。我构造了一个C代码,如下所示:
#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?
但是,这并不显示实际的输出。有没有人能帮我找出哪里出了问题,做个离散傅里叶变换,然后显示真实值?
更多回答
This is beyond me, but... Don't you need more regularity in your sampling intervals, collect N samples, then perform only one DFT calculation on that batch?
这超出了我的能力范围,但是...难道你不需要在你的抽样间隔中有更多的规律性,收集N个样本,然后只对该批次执行一次DFT计算?
I think that you don't need DFT, but RMS (search for RMS). But then, beware that not all the tools used to measure power are "true RMS" (search also for this).
我认为你不需要DFT,而需要RMS(搜索RMS)。但要注意,并不是所有用于测量功率的工具都是“真正的均方根”(也可以搜索这一点)。
Welcome to StackOverflow! Please take the tour to learn how this site works, and read "How to Ask". Specifically, this is not a forum. Then come back and edit your question, what issue you have to implement the algorithm. If you don't know the algorithm, this is the wrong place to ask, I'm afraid. This is a Q&A site for programming, not for math questions.
欢迎来到StackOverflow!请参加导览,了解这个网站的工作原理,并阅读“如何提问”。具体地说,这不是一个论坛。然后回来编辑你的问题,你有什么问题来实现算法。如果你不知道算法,恐怕你不应该问这个问题。这是一个针对编程的问答网站,不是针对数学问题的。
我是一名优秀的程序员,十分优秀!