![]() |
|
|
#1 |
|
Junior Member
Регистрация: 12.02.2015
Сообщений: 18
Вес репутации: 0 ![]() |
Всем доброго времени суток!
Не совсем хорошо понимаю значение "Открытый проект умного дома" - должен ли я только опубликовать исходный код или есть ещё какие требования? Техподдержку оказывать по этому проекту не смогу ввиду того что являюсь программистом уровня "Хеллоу Ворлд!" и основная часть кода пишется по наитию. Но в любом случае - идею и основную часть кода позаимствовал у andr128 (за что ему огромное спасибо!) из темы http://cyber-place.ru/showthread.php?t=623, а раз этот проект является открытым - поэтому считаю нужным выложить и свой код. Итак: В последнее время по счетам за электроэнергию стали приходить большие счета и решил я создать небольшую систему для сбора данных по количеству потребляемой электроэнергии для того чтобы проанализировать: куда идёт бОльшая часть эл.энергии и как можно этот расход оптимизировать. После долгих размышлений решил остановиться на следующей схеме: роутер с OpenWRT служит как веб-сервер а также собирает информацию с модбас-слейва - ардуино, которая собирает информацию о потреблении эл.энергии с помощью датчиков тока. Немного о железе: Роутер: D-Link DIR-320 (hw B1) с прошивкой OpenWRT Attitude Adjustment 12.09 Контроллер: Ардуино Мега 2560 Датчики тока: ACS712-20A Во время ремонта в квартире была заменена проводка и сейчас практически на каждую группу розеток идёт свой кабель что позволило установить все датчики в одном месте - в распред. щитке в квартире. В общем у меня 14 автоматов: 1 вводной и 13 - на группы потребителей. Поэтому были закуплены датчики тока ACS712-20A в кол-ве 15 штук (2-резерв). Выбор контроллера пал на Ардуино Мега 2560, т.к. у неё достаточное кол-во аналоговых входов и, тем более, она уже была в наличии. Скетч для Меги: Код:
#include <TimerOne.h> //использует Timer1
#include <SimpleModbusSlave.h>
//////////////////////// Modbus slave ///////////////////////
// Using the enum instruction allows for an easy method for adding and
// removing registers. Doing it this way saves you #defining the size
// of your slaves register array each time you want to add more registers
// and at a glimpse informs you of your slaves register layout.
//////////////// registers of your slave ///////////////////
enum
{
// just add or remove registers and your good to go...
// The first register starts at address 0
mb_A0,
mb_A1,
mb_A2,
mb_A3,
mb_A4,
mb_A5,
mb_A6,
mb_A7,
mb_A8,
mb_A9,
mb_A10,
mb_A11,
mb_A12,
mb_A13,
mb_A14,
mb_A15,
HOLDING_REGS_SIZE // leave this one
// total number of registers for function 3 and 16 share the same register array
// i.e. the same address space
};
unsigned int holdingRegs[HOLDING_REGS_SIZE]; // function 3 and 16 register array
////////////////////////////////////////////////////////////
//================================================================
// http://habrahabr.ru/post/141442/
#define FASTADC 1
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
//================================================================
const int k=100;
int cycles=15; // Кол-во обрабатываемых аналоговых входов
int ai_count=cycles, ai_mid_cnt=cycles; // Счетчики циклов 'for'
volatile long Counter=0; // счетчик периодов
volatile int CurA[16]; // Ток текущий
volatile int A[16]; // Аналоговый вход
volatile int CurMaxA[16]; // Ток маскимальный
volatile int CurMinA[16]; // Ток минимальный
volatile long CurMaxCalcA[16]; // Ток маскимальный за весь период
volatile long CurMinCalcA[16]; // Ток минимальный за весь период
float CurMidCalcA[16]; // Ток средний (среднеквадратичное от CurA0calcMax и CurA0calcMin)
volatile int c, v;
// ---------------------
float Current_A[16];
void setup()
{
// Serial.begin(57600);//поднимаем соединение для передачи на терминал
////////////////////// Modbus slave ///////////////////////
modbus_configure(&Serial, 57600, SERIAL_8N1, 1, 2, HOLDING_REGS_SIZE, holdingRegs);
//////////////////////////////////////////////////////////
//================================================================
// http://habrahabr.ru/post/141442/
#if FASTADC
// set prescale to 16
sbi(ADCSRA,ADPS2) ;
cbi(ADCSRA,ADPS1) ;
cbi(ADCSRA,ADPS0) ;
#endif
//================================================================
Timer1.initialize(400); // Интервал срабатывания таймера в мкс
Timer1.attachInterrupt(current_meter); //будет вызываться каждый раз при отсчете заданного времени
}
//********************обработчики прерываний*******************************
void current_meter() //прерывания таймера
{
Counter++; //счетчик периодов
// for (ai_count=0; ai_count < cycles; ai_count++)
// {
// CurA[ai_count] = analogRead(A[ai_count])-512;
// CurMaxA[ai_count] = max(CurA[ai_count],CurMaxA[ai_count]);
// CurMinA[ai_count] = min(CurA[ai_count],CurMinA[ai_count]);
// }
CurA[0] = analogRead(A0)-512;
CurMaxA[0] = max(CurA[0],CurMaxA[0]);
CurMinA[0] = min(CurA[0],CurMinA[0]);
CurA[1] = analogRead(A1)-512;
CurMaxA[1] = max(CurA[1],CurMaxA[1]);
CurMinA[1] = min(CurA[1],CurMinA[1]);
CurA[2] = analogRead(A2)-512;
CurMaxA[2] = max(CurA[2],CurMaxA[2]);
CurMinA[2] = min(CurA[2],CurMinA[2]);
CurA[3] = analogRead(A3)-512;
CurMaxA[3] = max(CurA[3],CurMaxA[3]);
CurMinA[3] = min(CurA[3],CurMinA[3]);
CurA[4] = analogRead(A4)-512;
CurMaxA[4] = max(CurA[4],CurMaxA[4]);
CurMinA[4] = min(CurA[4],CurMinA[4]);
CurA[5] = analogRead(A5)-512;
CurMaxA[5] = max(CurA[5],CurMaxA[5]);
CurMinA[5] = min(CurA[5],CurMinA[5]);
CurA[6] = analogRead(A6)-512;
CurMaxA[6] = max(CurA[6],CurMaxA[6]);
CurMinA[6] = min(CurA[6],CurMinA[6]);
CurA[7] = analogRead(A7)-512;
CurMaxA[7] = max(CurA[7],CurMaxA[7]);
CurMinA[7] = min(CurA[7],CurMinA[7]);
CurA[8] = analogRead(A8)-512;
CurMaxA[8] = max(CurA[8],CurMaxA[8]);
CurMinA[8] = min(CurA[8],CurMinA[8]);
CurA[9] = analogRead(A9)-512;
CurMaxA[9] = max(CurA[9],CurMaxA[9]);
CurMinA[9] = min(CurA[9],CurMinA[9]);
CurA[10] = analogRead(A10)-512;
CurMaxA[10] = max(CurA[10],CurMaxA[10]);
CurMinA[10] = min(CurA[10],CurMinA[10]);
CurA[11] = analogRead(A11)-512;
CurMaxA[11] = max(CurA[11],CurMaxA[11]);
CurMinA[11] = min(CurA[11],CurMinA[11]);
CurA[12] = analogRead(A12)-512;
CurMaxA[12] = max(CurA[12],CurMaxA[12]);
CurMinA[12] = min(CurA[12],CurMinA[12]);
CurA[13] = analogRead(A13)-512;
CurMaxA[13] = max(CurA[13],CurMaxA[13]);
CurMinA[13] = min(CurA[13],CurMinA[13]);
// CurA[14] = analogRead(A14)-512;
// CurMaxA[14] = max(CurA[14],CurMaxA[14]);
// CurMinA[14] = min(CurA[14],CurMinA[14]);
if(Counter==k)
{
Counter=0; //обнуляем счетчик
// for (ai_count=0; ai_count < cycles; ai_count++)
// {
// CurMaxCalcA[ai_count]=CurMaxA[ai_count];
// CurMinCalcA[ai_count]=CurMinA[ai_count];
// CurMaxA[ai_count]=0;
// CurMinA[ai_count]=0;
// }
CurMaxCalcA[0]=CurMaxA[0];
CurMinCalcA[0]=CurMinA[0];
CurMaxA[0]=0;
CurMinA[0]=0;
CurMaxCalcA[1]=CurMaxA[1];
CurMinCalcA[1]=CurMinA[1];
CurMaxA[1]=0;
CurMinA[1]=0;
CurMaxCalcA[2]=CurMaxA[2];
CurMinCalcA[2]=CurMinA[2];
CurMaxA[2]=0;
CurMinA[2]=0;
CurMaxCalcA[3]=CurMaxA[3];
CurMinCalcA[3]=CurMinA[3];
CurMaxA[3]=0;
CurMinA[3]=0;
CurMaxCalcA[4]=CurMaxA[4];
CurMinCalcA[4]=CurMinA[4];
CurMaxA[4]=0;
CurMinA[4]=0;
CurMaxCalcA[5]=CurMaxA[5];
CurMinCalcA[5]=CurMinA[5];
CurMaxA[5]=0;
CurMinA[5]=0;
CurMaxCalcA[6]=CurMaxA[6];
CurMinCalcA[6]=CurMinA[6];
CurMaxA[6]=0;
CurMinA[6]=0;
CurMaxCalcA[7]=CurMaxA[7];
CurMinCalcA[7]=CurMinA[7];
CurMaxA[7]=0;
CurMinA[7]=0;
CurMaxCalcA[8]=CurMaxA[8];
CurMinCalcA[8]=CurMinA[8];
CurMaxA[8]=0;
CurMinA[8]=0;
CurMaxCalcA[9]=CurMaxA[9];
CurMinCalcA[9]=CurMinA[9];
CurMaxA[9]=0;
CurMinA[9]=0;
CurMaxCalcA[10]=CurMaxA[10];
CurMinCalcA[10]=CurMinA[10];
CurMaxA[10]=0;
CurMinA[10]=0;
CurMaxCalcA[11]=CurMaxA[11];
CurMinCalcA[11]=CurMinA[11];
CurMaxA[11]=0;
CurMinA[11]=0;
CurMaxCalcA[12]=CurMaxA[12];
CurMinCalcA[12]=CurMinA[12];
CurMaxA[12]=0;
CurMinA[12]=0;
CurMaxCalcA[13]=CurMaxA[13];
CurMinCalcA[13]=CurMinA[13];
CurMaxA[13]=0;
CurMinA[13]=0;
// CurMaxCalcA[14]=CurMaxA[14];
// CurMinCalcA[14]=CurMinA[14];
// CurMaxA[14]=0;
// CurMinA[14]=0;
}
}
//*************************************************************************
void loop()
{
// for (ai_mid_cnt=0; ai_mid_cnt < cycles; ai_mid_cnt++)
// {
// CurMidCalcA[ai_mid_cnt] = sqrt((sq(CurMaxCalcA[ai_mid_cnt])+sq(CurMinCalcA[ai_mid_cnt]))/2);
CurMidCalcA[0] = sqrt((sq(CurMaxCalcA[0])+sq(CurMinCalcA[0]))/2);
CurMidCalcA[1] = sqrt((sq(CurMaxCalcA[1])+sq(CurMinCalcA[1]))/2);
CurMidCalcA[2] = sqrt((sq(CurMaxCalcA[2])+sq(CurMinCalcA[2]))/2);
CurMidCalcA[3] = sqrt((sq(CurMaxCalcA[3])+sq(CurMinCalcA[3]))/2);
CurMidCalcA[4] = sqrt((sq(CurMaxCalcA[4])+sq(CurMinCalcA[4]))/2);
CurMidCalcA[5] = sqrt((sq(CurMaxCalcA[5])+sq(CurMinCalcA[5]))/2);
CurMidCalcA[6] = sqrt((sq(CurMaxCalcA[6])+sq(CurMinCalcA[6]))/2);
CurMidCalcA[7] = sqrt((sq(CurMaxCalcA[7])+sq(CurMinCalcA[7]))/2);
CurMidCalcA[8] = sqrt((sq(CurMaxCalcA[8])+sq(CurMinCalcA[8]))/2);
CurMidCalcA[9] = sqrt((sq(CurMaxCalcA[9])+sq(CurMinCalcA[9]))/2);
CurMidCalcA[10] = sqrt((sq(CurMaxCalcA[10])+sq(CurMinCalcA[10]))/2);
CurMidCalcA[11] = sqrt((sq(CurMaxCalcA[11])+sq(CurMinCalcA[11]))/2);
CurMidCalcA[12] = sqrt((sq(CurMaxCalcA[12])+sq(CurMinCalcA[12]))/2);
CurMidCalcA[13] = sqrt((sq(CurMaxCalcA[13])+sq(CurMinCalcA[13]))/2);
// CurMidCalcA[14] = sqrt((sq(CurMaxCalcA[14])+sq(CurMinCalcA[14]))/2);
/*
Измеряем максимальный и минимальный пики синусоиды. Затем находим их среднеквадратичное значение.
пик = sqrt( ( (пик мин)^2 + (пик макс)^2 )/2 ) [маш.ед.]
Далее это значение (в машинных единицах - 0-1023) переводим в напряжение:
напряж. = (пик / 1023)*5 [Вольт]
Чувствительность ACS712-20 равна 100 милиВольт/Ампер = 0,1В/А (см. даташит на ACS), отсюда:
ток ампл. = напряж. / Чувствит. = напряж / 0,1 = напряж * 10 [Ампер]
Ток средний - это ток ампл., поделенный на корень из 2:
ток средний = ток ампл. / sqrt(2) = ток ампл. * 0,707 [Ампер]
Итого:
Ток = 0,707*ток ампл. = 0,707 * напряж / чувствит. = 0,707 * напряж. * 10 = 7,07 * напряж. =
= 7,07 * пик * 5 / 1023 = 35,35 * пик / 1023
*/
// Current_A[ai_mid_cnt] = 35.35 * CurMidCalcA[ai_mid_cnt] / 1023.0;
Current_A[0] = 35.35 * CurMidCalcA[0] / 1023.0;
Current_A[1] = 35.35 * CurMidCalcA[1] / 1023.0;
Current_A[2] = 35.35 * CurMidCalcA[2] / 1023.0;
Current_A[3] = 35.35 * CurMidCalcA[3] / 1023.0;
Current_A[4] = 35.35 * CurMidCalcA[4] / 1023.0;
Current_A[5] = 35.35 * CurMidCalcA[5] / 1023.0;
Current_A[6] = 35.35 * CurMidCalcA[6] / 1023.0;
Current_A[7] = 35.35 * CurMidCalcA[7] / 1023.0;
Current_A[8] = 35.35 * CurMidCalcA[8] / 1023.0;
Current_A[9] = 35.35 * CurMidCalcA[9] / 1023.0;
Current_A[10] = 35.35 * CurMidCalcA[10] / 1023.0;
Current_A[11] = 35.35 * CurMidCalcA[11] / 1023.0;
Current_A[12] = 35.35 * CurMidCalcA[12] / 1023.0;
Current_A[13] = 35.35 * CurMidCalcA[13] / 1023.0;
// Current_A[14] = 35.35 * CurMidCalcA[14] / 1023.0;
// }
//////////////////////// Modbus slave ///////////////////////
holdingRegs[mb_A0] = int(Current_A[1]*1000); // update data to be read by the master
holdingRegs[mb_A1] = int(Current_A[2]*1000); // update data to be read by the master
holdingRegs[mb_A2] = int(Current_A[3]*1000); // update data to be read by the master
holdingRegs[mb_A3] = int(Current_A[4]*1000); // update data to be read by the master
holdingRegs[mb_A4] = int(Current_A[5]*1000); // update data to be read by the master
holdingRegs[mb_A5] = int(Current_A[6]*1000); // update data to be read by the master
holdingRegs[mb_A6] = int(Current_A[7]*1000); // update data to be read by the master
holdingRegs[mb_A7] = int(Current_A[8]*1000); // update data to be read by the master
holdingRegs[mb_A8] = int(Current_A[9]*1000); // update data to be read by the master
holdingRegs[mb_A9] = int(Current_A[10]*1000); // update data to be read by the master
holdingRegs[mb_A10] = int(Current_A[11]*1000); // update data to be read by the master
holdingRegs[mb_A11] = int(Current_A[12]*1000); // update data to be read by the master
holdingRegs[mb_A12] = int(Current_A[13]*1000); // update data to be read by the master
// holdingRegs[mb_A13] = int(Current_A[13]*1000); // update data to be read by the master
// holdingRegs[mb_A14] = int(Current_A[14]*1000); // update data to be read by the master
holdingRegs[mb_A15] = int(analogRead(A15)*1000.0*5.0/1023.0); // update data to be read by the master
// holdingRegs[mb_A15] = analogRead(A15); // update data to be read by the master
modbus_update();
////////////////////////////////////////////////////////////
}
![]() В ходе пусконаладки Меги столкнулся с недостатком аппаратных ресурсов - прерывания нужно вызывать достаточно часто и обработка 13-ти аналоговых входов также занимает время. Поэтому пришлось увеличить частоту работы АЦП понизив делитель. |
|
|
|
| Здесь присутствуют: 1 (пользователей: 0 , гостей: 1) | |
| Опции темы | Поиск в этой теме |
| Опции просмотра | |
|
|