Created
June 6, 2017 16:28
-
-
Save stas-dovgodko/29dbfb5ac737b2b22b6c96d8dc8fe00c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <SoftwareSerial.h> | |
| #include <SPFD5408_Adafruit_GFX.h> // Core graphics library | |
| #include <SPFD5408_Adafruit_TFTLCD.h> // Hardware-specific library | |
| #include <SPFD5408_TouchScreen.h> // Touch library | |
| #include <math.h> | |
| #include "EmonLib.h" | |
| #include <TimerOne.h> | |
| #include <stdint.h> // needed for uint8_t | |
| SoftwareSerial ESPserial(19, 18); // RX | TX | |
| #ifndef READVCC_CALIBRATION_CONST | |
| #define READVCC_CALIBRATION_CONST 1126400L | |
| #endif | |
| #if defined(__arm__) | |
| #define ADC_BITS 12 | |
| #else | |
| #define ADC_BITS 10 | |
| #endif | |
| #define ADC_COUNTS (1<<ADC_BITS) | |
| #define VOLTAGE_CALIBARTION 450 | |
| #define VOLTAGE_PHASE_SHIFT 1.28 | |
| #define CURRENCY_CALIBARION 29.0 // 30A | |
| int points = 100; | |
| volatile int data[100][10]; // points from sensors buffer | |
| volatile int sdata[100][10]; // points to process | |
| double rms[10]; | |
| double trms[10]; | |
| int v[100]; | |
| int width; | |
| int height; | |
| volatile int point = 0; | |
| volatile bool xloop = false; | |
| volatile long vcc; | |
| // LCD Pin | |
| #define LCD_CS A3 | |
| #define LCD_CD A2 | |
| #define LCD_WR A1 | |
| #define LCD_RD A0 | |
| #define LCD_RESET A4 // Optional : otherwise connect to Arduino's reset pin | |
| // Assign human-readable names to some common 16-bit color values: | |
| #define BLACK 0x0000 | |
| #define BLUE 0x001F | |
| #define RED 0xF800 | |
| #define GREEN 0x07E0 | |
| #define CYAN 0x07FF | |
| #define MAGENTA 0xF81F | |
| #define YELLOW 0xFFE0 | |
| #define WHITE 0xFFFF | |
| #define SCREEN_DASHBOARD 1 | |
| #define SCREEN_VOLTAGE_A 2 | |
| #define SCREEN_VOLTAGE_B 3 | |
| #define SCREEN_VOLTAGE_C 4 | |
| // Init LCD | |
| Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET); | |
| void setup(void) { | |
| tft.reset(); | |
| tft.begin(0x9341); | |
| tft.setRotation(1); // Need for the Mega, please changed for your choice or rotation initial | |
| width = tft.width() - 1; | |
| height = tft.height() - 1; | |
| tft.fillScreen(WHITE); | |
| ESPserial.begin(9600); | |
| Serial.begin(115200); // setup serial | |
| cli(); | |
| TCCR1A = 0;// set entire TCCR0A register to 0 | |
| TCCR1B = 0;// same for TCCR0B | |
| TCNT1 = 0;//initialize counter value to 0 | |
| // set compare match register for 200khz increments | |
| OCR1A = 20;// = (16*10^6) / (200000*64) - 1 (must be <256) | |
| // turn on CTC mode | |
| TCCR1B |= (1 << WGM12); | |
| // Set CS01 and CS00 bits for 64 prescaler | |
| TCCR1B |= (1 << CS11) | (1 << CS10); | |
| // enable timer compare interrupt | |
| TIMSK1 |= (1 << OCIE1A); | |
| ADMUX = 0b01000110; // 01000110 | |
| ADCSRA = 0b10101111; | |
| //ADCSRA=(1<<ADEN)|(1<<ADATE)|(1<<ADPS2)|(1<<ADPS1)|(0<<ADPS1); | |
| ADCSRA &= ~(bit (ADPS0) | bit (ADPS1) | bit (ADPS2)); // clear prescaler bits | |
| // sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles] | |
| // for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles | |
| //ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // 128 prescaler for 19.2 KHz | |
| //ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0); // 64 prescaler for 19.2 KHz | |
| ADCSRA |= (1 << ADPS2) | (1 << ADPS0); // 32 prescaler for 38.5 KHz | |
| //ADCSRA |= (1 << ADPS2); // 16 prescaler for 76.9 KHz | |
| //ADCSRA |= (1 << ADPS1) | (1 << ADPS0); // 8 prescaler for 153.8 KHz | |
| ADCSRA |= (1 << ADATE); // enable auto trigger | |
| ADCSRA |= (1 << ADIE); // enable interrupts when measurement complete | |
| ADCSRA |= (1 << ADEN); // enable ADC | |
| ADCSRA |= (1 << ADSC); // start ADC measurements | |
| ADCSRB= 0b01000000; | |
| //bitWrite(ADCSRA, 6, 1); // Запускаем преобразование установкой бита 6 (=ADSC) в ADCSRA | |
| //ADCSRB=(1<<ADTS1)|(1<<ADTS0); // Timer/Counter0 Compare Match A | |
| sei(); // устанавливаем флаг прерывания | |
| mux(0); | |
| } | |
| float FK = 0.1; | |
| double offset; | |
| void loop() | |
| { | |
| String cmd; | |
| if (xloop) { | |
| // magic with static data. Data locked for modifications | |
| for(int c=0;c<10;c++) { | |
| int sample; | |
| double sqv = 0,sum = 0,tsum = 0;; | |
| double lastFiltered = 0,filtered = 0; //Filtered_ is the raw analog value minus the DC offset | |
| short acc_x_raw, acc_x, acc_xf; | |
| int b; double alfa=0.05; | |
| // low filter | |
| /*for(b=1; b<points; b++) | |
| { | |
| sdata[b][c]=sdata[b-1][c]*alfa+sdata[b][c]*(1.-alfa); | |
| }*/ | |
| for (b=0; b<points; b++) { | |
| lastFiltered = filtered; | |
| sample = sdata[b][c]; | |
| if (c == 0) { | |
| //offset+= ((sample - offset)/1024); | |
| filtered = sample - offset; | |
| v[b] = filtered; | |
| } else { | |
| filtered = sample - 512; | |
| } | |
| tsum += abs(filtered); | |
| sqv = filtered * filtered; //1) square voltage values | |
| sum += sqv; | |
| } | |
| double V_RATIO = VOLTAGE_CALIBARTION *((vcc/1000.0) / (ADC_COUNTS)); | |
| rms[c] = V_RATIO * sqrt(sum / points); | |
| trms[c] = V_RATIO * 1.11 * (tsum / points); | |
| if (c == 0) { | |
| cmd = "mqtt-publish test/rms_" + String(c) + " "+ String(rms[c]); | |
| ESPserial.println(cmd); | |
| cmd = "mqtt-publish test/trms_" + String(c) + " "+ String(trms[c]); | |
| ESPserial.println(cmd); | |
| } | |
| } | |
| graph(); | |
| delay(500); | |
| xloop = false; // release lock | |
| } | |
| } | |
| volatile int value; | |
| volatile int locked; | |
| ISR(ADC_vect) | |
| { | |
| /*static unsigned long atime; unsigned long new_time; static int c = 0; static long c1 = 0; | |
| new_time = micros(); | |
| if (atime > 0) { | |
| c1 += (new_time - atime); | |
| if (++c > 1000) { | |
| Serial.println(c1 / 1000); | |
| c = 0; c1 = 0; | |
| } | |
| } | |
| atime = new_time;*/ | |
| value = ADC; | |
| if (locked < 255) locked++; | |
| } | |
| ISR(TIMER1_COMPA_vect) | |
| { | |
| if (locked > 2) { // delay to MUX | |
| /*static unsigned long atime; unsigned long new_time; static int c = 0; static long c1 = 0; | |
| new_time = micros(); | |
| if (atime > 0) { | |
| c1 += (new_time - atime); | |
| if (++c > 1000) { | |
| //Serial.println(c1 / 1000); | |
| c = 0; c1 = 0; | |
| } | |
| } | |
| atime = new_time;*/ | |
| locked= 0; | |
| static uint8_t n=0; static uint8_t p=0; | |
| uint8_t next_n = n+1; | |
| if (next_n > 10) next_n = 0; | |
| mux(next_n); // switch to next MUX | |
| if (n == 0) { | |
| // VCC | |
| offset = 512;//value; | |
| vcc = READVCC_CALIBRATION_CONST / value; | |
| } else { | |
| data[p][n-1] = value; | |
| if ((next_n == 0) && ++p >= points) { | |
| p = 0; | |
| if (!xloop) { | |
| memcpy( sdata, data, points * 2 * 10 ); | |
| xloop = true; | |
| } | |
| } | |
| } | |
| n = next_n; | |
| } | |
| } | |
| void mux(uint8_t n) | |
| { | |
| locked = 0; | |
| switch(n) { | |
| case 0: // VCC | |
| #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined (__AVR_ATmega328P__) | |
| ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); | |
| #elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) | |
| ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); | |
| #elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB1286__) | |
| ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); | |
| ADCSRB &= ~_BV(MUX5); // Without this the function always returns -1 on the ATmega2560 http://openenergymonitor.org/emon/node/2253#comment-11432 | |
| #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) | |
| ADMUX = _BV(MUX5) | _BV(MUX0); | |
| #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) | |
| ADMUX = _BV(MUX3) | _BV(MUX2); | |
| #endif | |
| break; | |
| case 1: | |
| case 2: | |
| case 3: | |
| // V(n) | |
| ADMUX = 0b01000110; | |
| break; | |
| case 4: | |
| case 5: | |
| case 6: | |
| case 7: | |
| case 8: | |
| case 9: | |
| case 10: | |
| // A(n) | |
| ADMUX = 0b01001001; | |
| break; | |
| } | |
| locked = 0; | |
| } | |
| void graph() | |
| { | |
| tft.setTextColor(BLACK); | |
| tft.setTextSize(3); | |
| tft.fillScreen(WHITE); | |
| graphV(); | |
| //graphA(); | |
| //Serial.println(vcc); | |
| } | |
| void graphV() | |
| { | |
| int s = 0; int b=0; | |
| int vmin = 1000; int vmax = 0; int vv = 0; int pc = 0; | |
| for (b=0; b<points; b++) { | |
| vv = v[b]; | |
| //if (vv > 0) { | |
| vmin = min(vv, vmin); | |
| vmax = max(vv, vmax); | |
| s += vv; pc++; | |
| //} | |
| } | |
| int vavg = s / pc; | |
| //int vv = 0; | |
| //int vmin = -300; int vmax = 300; | |
| int pw = ((width - 15 - 30)*100/points); vv = 0; int x = 0; int y = 0; int prevx = 0; int prevy = 0; | |
| for (b=0; b<points; b++) { | |
| vv = map(v[b], vmin, vmax, 0, 200); | |
| x = (b*pw)/100 + 1; y = vv; | |
| //tft.drawRect(x, y, 1, 1, RED); | |
| tft.drawLine(prevx, prevy, x, y, BLACK); | |
| prevx = x; prevy = y; | |
| } | |
| tft.fillRect(width - 42, 45, 40, 65, WHITE); | |
| tft.setCursor(width - 40, 45); | |
| tft.setTextSize(2); | |
| tft.println(vmax); | |
| tft.setCursor(width - 40, 69); | |
| tft.println(rms[0]); | |
| tft.setCursor(width - 40, 92); | |
| tft.setTextSize(2); | |
| tft.println(trms[0]); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment