![]() |
![]() |
#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-ти аналоговых входов также занимает время. Поэтому пришлось увеличить частоту работы АЦП понизив делитель. |
![]() |
![]() |
Здесь присутствуют: 2 (пользователей: 0 , гостей: 2) | |
|
|