Ср дек 07, 2022 12:34:13
uint8_t messCount = 0; // счетчик кол-во измерений АЦП
uint8_t analogPin = 3; // номер входа АЦП
uint8_t recMUX = 0; // переменная для сохранения исходного значения регистра ADMUX
uint16_t voltADCTmp = 0; // вр. перем. для получения ср. ариф. АЦП
uint32_t voltage = 0; // напряжение
uint32_t amperage = 0; // ток
uint32_t wattage = 0; // мощность
uint16_t uRef = 26300; // опорное напряжение для мега8а (внутренний ИОН) x10000
uint8_t rSh = 10; // сопротивление токового шунта x100
uint8_t kUr = 83; // отношение напряжений входного делителя x1000
uint16_t voltADCRes[3];
voltage = voltADCRes[2] * uRef / 1024 * 100 / kUr; // получаем напряжение типа XX.XXX
Ср дек 07, 2022 12:49:11
/ 1024 * 100
voltage = voltADCRes[2] * uRef / 1024 * 100 / kUr; // получаем напряжение типа XX.XXX
voltage = (uint32_t)voltADCRes[2] * uRef * 100 / 1024 / kUr;
Ср дек 07, 2022 12:51:54
Ср дек 07, 2022 13:39:58
Ср дек 07, 2022 14:28:40
Ср дек 07, 2022 14:41:33
Ср дек 07, 2022 14:55:45
Ср дек 07, 2022 15:03:46
Ср дек 07, 2022 15:14:46
voltage = voltADCRes[2];
amperage = voltage * uRef;
wattage = amperage / 1024 * 100 / kUr;
Ср дек 07, 2022 15:28:58
mir0tv0rec писал(а):uint32_t voltage = 0; // напряжение
mir0tv0rec писал(а):получаем напряжение типа XX.XXX
Ср дек 07, 2022 15:34:57
Ср дек 07, 2022 16:11:32
mir0tv0rec писал(а):Объясните, почему так не работает: voltage = voltADCRes[2] * uRef;
а так работает:
voltage = voltADCRes[2];
voltage = voltage * uRef;
veso74 писал(а):можете для теста преобразовать в всех местах:
voltage = (uint32_t)voltADCRes[2] * (uint32_t)uRef / 1024UL * 100UL / (uint32_t)kUr;
Ср дек 07, 2022 19:38:54
Чт дек 08, 2022 00:09:08
//==================
#ifndef METER_H
#define METER_H
#include "meter.h"
#include "main_def_func.h"
//==================
//==================
#define METER_TCNT TCNT0
#define METER_TIMSK TIMSK
#define METER_OCIE OCIE0
#define METER_OCR OCR0
#define METER_TCCR TCCR0
#define METER_CS0 CS00
#define METER_CS1 CS01
#define METER_CS2 CS02
#define METER_OCR_VAL 25
//==================
//==================
#define V_REF 5.00
#define ADC_RES 1023.0
#define K_1 1.089
#define K_2 1.061
#define K_3 1.033
//==================
//==================
#define SAMPLES 400
//==================
//==================
enum
{
PHASE_A, //фаза A
PHASE_B, //фаза B
PHASE_C, //фаза C
PHASE_Usm,
};
//==================
//==================
void meter_timer_init (void);
void meter_timer_off (void);
void meter_init (void);
void meter_off (void);
u16 read_adc (u08 channel);
void set_proc_meter_on (void);
void set_proc_meter_off (void);
void proc_meter (void);
u32 calc_adc_result (u32 sqr_summ);
bool get_measure_complete (void);
//==================
#endif
//==================
#include "meter.h"
//==================
//==================
bool adc_complete;
static u08 phase;
static u16 sample;
static u32 phase_a_summ_sqr;
static u32 phase_b_summ_sqr;
static u32 phase_c_summ_sqr;
static bool measure_complete;
//==================
//==================
#pragma vector = TIMER0_COMP_vect
__interrupt void meter_timer_comp (void)
{
u16 adc = 0;
u16 temp = 0;
u32 a = 0;
METER_OCR += METER_OCR_VAL;
adc = read_adc (PHASE_Usm);
temp = adc;
adc = read_adc (phase);
if (adc >= temp)
adc -= temp;
else
adc = (temp - adc);
a = (long) (adc * adc);
switch (phase)
{
case PHASE_A:
phase_a_summ_sqr += a;
phase = PHASE_B;
break;
case PHASE_B:
phase_b_summ_sqr += a;
phase = PHASE_C;
break;
case PHASE_C:
phase_c_summ_sqr += a;
phase = PHASE_A;
if (++sample > SAMPLES)
{
meter_off ();
measure_complete = true;
}
break;
}
}
//==================
//==================
#pragma inline = forced
void meter_timer_init (void)
{
METER_TCNT = 0;
METER_OCR = METER_OCR_VAL;
set_bit (METER_TIMSK, METER_OCIE);
set_bit (SFIOR, PSR10);
METER_TCCR |= ((1<<METER_CS1) | (1<<METER_CS0));
}
//----------
#pragma inline = forced
void meter_timer_off (void)
{
METER_TCCR = 0;
clr_bit (METER_TIMSK, METER_OCIE);
METER_TCNT = 0;
METER_OCR = 0;
}
//==================
//==================
//#pragma inline = forced
u16 read_adc (u08 channel)
{
ADMUX = ((0<<REFS1) | (0<<REFS0) | (0<<ADLAR) | channel);
set_bit (ADCSRA, ADSC);
while (1)
{
__enable_interrupt ();
sleep_mode_enable ();
if (adc_complete)
{
adc_complete = false;
break;
}
}
return ADC;
}
//==================
//==================
#pragma vector = ADC_vect
__interrupt void adc_interrupt_handler (void)
{
adc_complete = true;
}
//==================
//==================
void meter_init (void)
{
phase = PHASE_A;
phase_a_summ_sqr = 0;
phase_b_summ_sqr = 0;
phase_c_summ_sqr = 0;
sample = 0;
measure_complete = false;
meter_timer_init ();
}
//----------
#pragma inline = forced
void meter_off (void)
{
// ADCSRA = 0;
// ADMUX = 0;
meter_timer_off ();
}
//==================
//==================
static u08 _proc_meter;
void set_proc_meter_on (void)
{
ACSR = (1<<ACD);
ADCSRA = ((1<<ADEN) | (0<<ADSC) | (0<<ADATE) | (1<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (0<<ADPS1) | (0<<ADPS0));
_proc_meter = 1;
}
//----------
void set_proc_meter_off (void)
{
meter_off ();
_proc_meter = 0;
}
//----------
void proc_meter (void)
{
switch (_proc_meter)
{
case 0:
break;
case 1:
meter_init ();
_proc_meter = 2;
break;
case 2:
if (get_measure_complete ())
{
phase = PHASE_A;
_proc_meter = 3;
}
break;
case 3:
switch (phase)
{
case PHASE_A:
set_i_ph_a (calc_adc_result (phase_a_summ_sqr));
phase = PHASE_B;
break;
case PHASE_B:
set_i_ph_b (calc_adc_result (phase_b_summ_sqr));
phase = PHASE_C;
break;
case PHASE_C:
set_i_ph_c (calc_adc_result (phase_c_summ_sqr));
Set_Event (EV_ID_MEASURE_I_ABC_COMPLETE, USER_EVENT);
_proc_meter = 1;
break;
}
break;
}
}
//==================
//==================
u32 calc_adc_result (u32 sqr_summ)
{
float a;
u16 temp;
sqr_summ /= sample;
a = sqrt (sqr_summ);
temp = (int) a;
a = (float) a * (V_REF / ADC_RES);
if (temp <= 50)
a = (float) a * K_1;
if (temp > 50 && temp < 100)
a = (float) a * K_2;
if (temp >= 100)
a = (float) a * K_3;
a = a * 10000;
return (long) a;
}
//==================
//==================
bool get_measure_complete (void)
{
if (measure_complete == true)
{
measure_complete = false;
return true;
}
else
return false;
}
//==================
Чт дек 08, 2022 09:03:56
Чт дек 08, 2022 09:12:00
#define ADC_RESOLUTION 1024
#define V_REF 955L
#define ADC2MV(adc) (adc) * V_REF / ADC_RESOLUTION
Чт дек 08, 2022 10:33:16
Чт дек 08, 2022 11:35:36
void ReadADC()
{
uint16_t result = ADCL | ADCH << 8; // Получаем 10-битный результат
if (ADC_read)
{
// 10 измерений для исключения скачков
if (messCount < 10)
{
voltADCTmp += result; // аккумулируем показания АЦП канала
messCount++; // инкрементируем счетчик кол-во снятых показаний
}// end if
else
{
voltADCRes[analogPin-3] = voltADCTmp / messCount; // усредняем результат, присваиваем значения с АЦП ячейкам массива
voltADCTmp = 0; // обнуляем
messCount = 0; // обнуляем
analogPin++; // Перебираем входные пины по кругу (А3...А5 - их может быть больше)
if (analogPin > 5)
{
voltage = voltADCRes[2];
voltage = voltage * uRef / 1024 * 100 / kUr; // получаем напряжение типа XX.XXX
uint16_t resultTmp = voltage % 1000; // получаем тысячные
//округляем до сотых
if (resultTmp % 10 < 5) resultTmp = resultTmp / 10; // если тысячные меньше 5 - просто делим на 10
else if (resultTmp < 995) resultTmp = resultTmp / 10 + 1; // если тысяные меньше 945 и тысячные больше 4, округляем сотые в большуюю сторону
else
{ // если > 995
resultTmp = 0; // обнуляем сотые
voltage += 1000; // увеличиваем целые
}//end else
voltage = voltage / 1000 * 100 + resultTmp; // приводим в виду XXXX (2 знака целые, 2 знака сотые)
// если напряжение после ОУ вышло из диапазона опорного (напряжение на шунте больше ~0.5V)
if (voltADCRes[1] >= 1023)
{
amperage = voltADCRes[0];
amperage = amperage * uRef / 1024 / rSh; // ток берем до ОУ
}//end if
// если напряжение после ОУ в диапазоне опорного
else
{
amperage = voltADCRes[1];
amperage = amperage * uRef * 10 / 1024 / kOA / rSh; // ток берем с выхода ОУ (ку ОУ рассчитываем относительно друго входа без усиления)
//amperage = amperage * uRef / 1024 / (voltADCRes[1] / voltADCRes[0]) / rSh; // ток берем с выхода ОУ (ку ОУ рассчитываем относительно друго входа без усиления)
}//end else
resultTmp = amperage % 1000; // получаем тысячные
//округляем до сотых
if (resultTmp % 10 < 5) resultTmp = resultTmp / 10; // если тысячные меньше 5 - просто делим на 10
else if (resultTmp < 995) resultTmp = resultTmp / 10 + 1; // если тысяные меньше 945 и тысячные больше 4, округляем сотые в большуюю сторону
else
{ // если > 995
resultTmp = 0; // обнуляем сотые
amperage += 1000; // увеличиваем целые
}//end else
amperage = amperage / 1000 * 100 + resultTmp; // приводим в виду XXXX (2 знака целые, 2 знака сотые)
//if (uSw_1 && uSw_2 > uSw_1 && uSw_3 > uSw_2) SwitchRel(); // не переключаем реле, поку не установлены пороги переключения
analogPin = 3; // Все нужные перебрали...возвращаемся к первому
resultReady = true;
}//end if
ADMUX = recMUX | (analogPin & 0x07); // Устанавливаем новый вход для преобразования
ADC_read = false; // Устанавливаем флаг смены входного пина - следующее прерывание пропускаем
}// end else
}// end if (ADC_read)
else ADC_read = true; // Первый раз пропускаем считывание и устанавливаем флаг на чтение в следующий раз
}// end void ReadADC()
Чт дек 08, 2022 11:42:53
каждой переменной дать собственное имя, и тогда массив не нужен будет вообще.mir0tv0rec писал(а):Как нужно будет понять. с какого входа, куда данные сохранять...
Чт дек 08, 2022 11:49:07