project design document (pdd) three-phase microprocessor ...nrgalassi.org/eece490b/eece490b spring...
TRANSCRIPT
Project Design Document (PDD)
Three-phase Microprocessor Relay (THMPR)
Author: Wade Archer Date:12-8-18
Revision 1 Date:12-8-18
Revision 2 Date:12-21-18
Revision 3 Date:3-25-19
Revision 4 Date:5-9-19
1.0 Architectural Design (Refer to PA4)
• Delivers warning and current status information via Wi-Fi communication
• Disconnects system from power supply
• Collects sensor readings from supply line
• Uses collected data to make system level decisions
2. Graphically relate the functional elements to the physical elements of the
design:
Functional Elements:
Customer Need Functional Element Physical Element 1. Quick decisions “ uses collected data…” Micro controller
2. Smart “ delivers warning…” RF transceiver 3. safe “ disconnects…” disconnect relay
4. “ collects sensor…” voltage/ current sensor
Architectural Graphic:
2.0 Hardware Design
Current sensors/Hall sensors
− input to the current sensors will be a single-phase AC signal
− the purpose of the sensor is to take measurement of the current present in the
wire of interest
− the output of the current sensor will be an analog voltage signal that correlates to
the what current is there
Current transformers
− the input of the current transformers (CT) will be one of the phases from main
supply
− the purpose of the CT measures the current in the phase while isolating the
THMPR from main power, this will be beneficial in large systems
− the output of the transformer will be fed into one of the inputs of the LM324
operational amplifier (op-amp)
LM324 operational amplifiers
− the input of the op-amp will be a single-phase voltage or current reading of the
three-phase voltage supply
− the purpose of the op-amps will be to create square wave signals for their use in
zero-crossing detection and for frequency measurement of each phase
− the output of the op-amps will be square wave signals that represents either the
present voltage or current in that single phase
XOR gate
− the input of the two input XOR gate will be two square wave signals from two of
the op-amps
− the purpose of the XOR gate is to detect the time difference between the two
signals coming from the op-amps. Essentially it will be detecting the phase
difference between the current and voltage signal
− the output of the XOR gate will be a square wave that will represent the time
delay between the two signals and be fed into the microcontroller
STM32f103c8t6 “blue pill” microcontroller
− the input of the microcontroller will multiple signals -both digital and analog-
that correlate to the collected data of the sensor devices
− the purpose of the microcontroller will be to use the collected data in calculations
that will dictate the functions of the system as whole
− the output of the microcontroller will be multiple digital signals that connect to
different hardware components that will carry out their functions as dictated by
the micro controller
the Disconnect relay
− the inputs of this relay will be an AC signal from the micro controller that will
activate the disconnect relay, and the three single phase supply lines that are
being monitored
− the purpose of the disconnect relay will be to break the circuit connecting the
power supply from the system
− the output of the disconnect is meant to be another three single-phase lines that
would act as supply lines
ESP8266-01 Wi-Fi module
− the input of this system would be a digital signal that it would send to the user’s
PC
− the purpose of this device is to allow the user to be kept updated on the condition
of their power supply if something where to go wrong, or if there is something to
be concerned over
− the output of this system is a signal that can be picked up by the user’s PC
2.1 Theory of operation (required)
the purpose of this product is to act as a safety measure for power supply
systems. Essentially if the product detects an irregularity in the supplies’ current that could cause damage to those systems or bodily harm and will
disconnect the system from its malfunctioning power supply.
it can be described in three steps:
2.2 Schematics (required)
2.3 State Flow Diagrams (as required)
None so far
2.4 Timing Diagrams (as required)
None so far
3.0 Software Design
( blocks described are from the main loop of the program)
Frequency measurement
− input of this will be pulse length measurements from hardware relating to the
signal generated by the op-amp from the phase voltage
− the purpose of this is calculate the frequency of the input phase to ensure a
consistent frequency between all phases
− the output of this block will be frequency measurements of each phase
Overcurrent calc.
− the input of this section will be the output of the sampling section
− the purpose of this section is to make comparison calculations with input data
and the set values. This is done by taking in input data and running it through
calculations focusing on area of interest in power systems, such as power
factor, and comparing that calculated value with normal and acceptable values
− the output of this block will be digital signals that will either activate the
disconnect relay, or be transmitted through the Wi-Fi module
Tell user/Communicate with Wi-Fi Module
− the input of this block will be the fault check flag used elsewhere in the program
− this block will be used to “write” to the user interface, updating information that
would be relevant to the user about the state of the relay using the fault flag to
decide what is sent to user interface
− the output is data describing the current state of the THMPR to the user interface
Power Factor Reading
− the input for this block is the DC signal timing signal output from the zero-
crossing detection circuit
− this function is meant to measure the phase difference between the voltage and
current of that phase and calculate the power factor from it.
− The output of this block will be the calculated power factor measurement of each
phase
3.1 Software Inter-Relationships Block Diagram
(main)
3.2 code of critical software elements //three phase relay test code for Senior project
//Wade Archer
// created: 4-13-19
// last updated: 5-8-19
//Interfacing ESP8266 Wi-Fi with STM32F103C8
//---------------------------------------------------------------
//NOTE: Serial is serial monitor with baud rate(9600)
//NOTE: Serial1 (TX2, RX2)is connected with ESP8266(RX,TX)respectively with baud rate (115200)
String webpage = ""; //String variable to store characters
int i = 0, k = 0, x = 0; //integer variables
//float pf_data; // data to be sent from pf calculation
String readString; //using readString feature to read characters
boolean No_IP = false; //boolean variables
String IP = ""; //String variable to store data
char temp1 = '0'; //character variable
String names = "<p>Wade Archer</p><p>Chico State Senior Design Project</p>"; //String with html
notations
String data = "<p>Data Received Successfully.....</p>"; //String with html
String danger = "<p> Power Source is in the DANGER ZONE.</p>"; // string with html notation
String prblm = "<p> a phase is faultly, tripped relay, reset the THMPR</p>"; // string with html
notation
String safe = "<p> this phase is operating normally</p>";
String space = "<p> <p/>";
int THMPR_flag[] = {0, 0, 0}; // used to tell Send() whats going on with the rest of the relay, one for
each phase
//---------------------------------------------------------------
//Measuring AC Current Using ACS712 hall sensor
//---------------------------------------------------------------
//setting up arrays for all hall sensors
const int sensorIn[3] = {PA4, PB1 , PA0}; // setting input pins
int mVperAmp = 185; // use 185 for 5A, 100 for 20A Module, and 66 for 30A Module
// define variables for calculations
//float Voltage[3];
float VRMS[3];
float AmpsRMS[3];
//---------------------------------------------------------------
// power factor calculation, three phase
//---------------------------------------------------------------
const int pf_in[3] = {PB4, PA12, PA15};// setting up array for input pins from all three phases
float rads = 57.29577951; // 1 radian = approx 57 deg.
float degree = 360; // degrees
float frequency = 60; // frequency of supply for North America
float nano = 1 * pow (10, -6); // Multiplication factor to convert micro seconds into seconds
// Define floats to contain calculations
float pf[3];
float angle[3];
float pf_max[3] = {0, 0, 0};
float angle_max[3] = {0, 0, 0};
int ctr;
//---------------------------------------------------------------
// Powerfeather Relay
//---------------------------------------------------------------
const int Signal[3] = {PB12, PB13, PB14};// signal output pins
//const int Reset[3] = {PA6, 0, 0};// reset pins
//---------------------------------------------------------------
// frequency measurement
//---------------------------------------------------------------
const int freqIn[3] = {PA11, PB8, PB15};
float Freqs[3];
//---------------------------------------------------------------
// fault, frequency, and powerfactor functions
//------------------------o---------------------------------------
void powerfactor() { // this function is used to measure and store the power factor of each phase
uint32_t start_time = millis();
Serial.print(" time since program started: "); Serial.println(start_time);
for (int b = 0; b <= 2; b++) { // Perform a measurement for each phase
for (ctr = 0; ctr <= 3; ctr++) // Perform 4 measurements then reset
{
// 1st line calculates the phase angle in degrees from differentiated time pulse
// Function COS uses radians not Degree's hence conversion made by dividing angle / 57.2958
uint32_t timing = pulseIn(pf_in[b], HIGH, 100000);
angle[b] = ((((pulseIn(pf_in[b], HIGH, 100000)) * nano) * degree) * frequency); // phase difference
(in degrees)= delta_t*360*f, pulseIn's timeout set to 10 sec
// pf[b] = cos(angle[b] / rads);
if (angle[b] > angle_max[b]) // Test if the angle is maximum angle
{
angle_max[b] = angle[b]; // If maximum record in variable "angle_max"
pf_max[b] = cos(angle_max[b] / rads); // Calc PF from "angle_max"
}
}
if (angle_max[b] > 360) // If the calculation is higher than 360
{
angle_max[b] = 0; // assign the 0 to "angle_max"
pf_max[b] = 1; // Assign the Unity PF to "pf_max"
}
else if (angle_max[b] == 0) // If the calculation is higher than 360
{
angle_max[b] = 0; // assign the 0 to "angle_max"
pf_max[b] = 1; // Assign the Unity PF to "pf_max"
}
Serial.print("phase"); Serial.println(b + 1);
Serial.print(" phase shift between I"); Serial.print(b + 1); Serial.print(" and V"); Serial.print(b + 1);
Serial.print(":");
Serial.print(angle_max[b], 2); // Print the result
Serial.print(", ");
Serial.print("power factor: ");
Serial.println(pf_max[b], 2);
angle[b] = 0; // Reset variables for next test
angle_max[b] = 0;
}
}
void getFrequency() {// this function takes in the pin that we would like to measure and returns the
frequency of that phase, it also checks if the phase has been disconnected
int Htime[3] = {0, 0, 0}; //integer for storing high time
int Ltime[3] = {0, 0, 0}; //integer for storing low time
float Ttime[3] = {0, 0, 0}; // integer for storing total time of a cycle
uint32_t start_time = millis();
for (int b = 0; b <= 2; b++) {
Htime[b] = pulseIn(freqIn[b], HIGH); //read high time
Ltime[b] = pulseIn(freqIn[b], LOW); //read low time
Ttime[b] = Htime[b] + Ltime[b];
Freqs[b] = 1000000 / Ttime[b]; //getting frequency with Ttime is in Micro seconds
if (start_time > 1000) { // 1 seconds, setting a "timer" to wait for signals to settle
if ((pulseIn(freqIn[b], HIGH) == 0) || (pulseIn(freqIn[b], LOW) == 0)) { // looks to see if one phase
has been disconnected, if a pulse remains high longer than 1.5 second
// direct pin register manipulation
GPIOB->regs->ODR |= 0b0111000000000000;// setting B12,B13, B14 high, which are my relays
Serial.print(" time in milli seconds since program started, relay has disconnected: ");
Serial.println(start_time);
Serial.print(" lost phase"); Serial.println(b + 1);
THMPR_flag[0] = 1; THMPR_flag[1] = 1; THMPR_flag[2] = 1; // setting flags for webpage
break; // breaking from for loop
}
}
}
}
void flt_check(float Ampsrms[]) { // this function checks the current of the supply phases, deciding if a
fault has occured
uint32_t start_time = millis();
double safei = 0.00; // the accepted current value reference point
double plus = safei + 0.010;
double neg = safei - 0.010; // can reset these variables as needed
double over = safei + 0.005;
double under = safei - 0.005;
for (int b = 0; b <= 2; b++) {
if (Ampsrms[b] >= (under) && Ampsrms[b] < (neg)) { // danger zone (-)
Serial.print("reached: danger zone (-) for phase "); Serial.println(b + 1);
THMPR_flag[b] = 2;
}
else if (Ampsrms[b] > (plus) && Ampsrms[b] <= (over) ) { // danger zone (+)
Serial.print(" reached: danger zone (+) for phase "); Serial.println(b + 1);
THMPR_flag[b] = 2;
}
else if (Ampsrms[b] > (over)) { // over current
Serial.print(" reached overcurrent for phase "); Serial.println(b + 1);
// direct pin register manipulation
GPIOB->regs->ODR |= 0b0111000000000000;// setting B12,B13, B14 high, which are my relays
Serial.print(" time in milli seconds since program started, relay has disconnected: ");
Serial.println(start_time);
THMPR_flag[0] = 1; THMPR_flag[1] = 1; THMPR_flag[2] = 1; // setting flags for webpage
}
else if (Ampsrms[b] < (under)) { // under current
Serial.print(" reached under current for phase "); Serial.println(b + 1);
// direct pin register manipulation
GPIOB->regs->ODR |= 0b0111000000000000;// setting B12,B13, B14 high, which are my relays
THMPR_flag[0] = 1; THMPR_flag[1] = 1; THMPR_flag[2] = 1; // setting flags for web page
}
else { // the current is equal to the safe current
THMPR_flag[b] = 0;
}
}
}
//---------------------------------------------------------------
//wifi functions
//---------------------------------------------------------------
void check4IP(int t1) //A function to check ip of ESP8266
{
Serial.println("checking IP address of ESP8266...");
int t2 = millis();
while (t2 + t1 > millis())
{
while (Serial1.available() > 0)
{
if (Serial1.find("WIFI GOT IP"))
{
No_IP = true;
}
}
}
}
void get_ip() //After cheacking ip ,this is a function to get IP address
{
Serial.println("getting IP address ...");
IP = "";
char ch = 0;
int h = 0;
while (1)
{
Serial1.println("AT+CIFSR"); //GET IP AT COMMAND, the AT command that gets the
IP adress
Serial.println("AT+CIFSR");
h++;
if ( h > 20) {
Serial.print("sent AT+CIFSR, could not get IP, check wifi connection");
break; // break out of while stat
}
while (Serial1.available() > 0)
{
if (Serial1.find("STAIP,")) //This finds the STAIP that is the STATIC IP ADDRESS of
ESP8266
{
delay(1000);
Serial.print("IP Address:");
while (Serial1.available() > 0)
{
ch = Serial1.read(); //Serial1 reads from ESP8266
if (ch == '+')
break;
IP += ch;
}
}
if (ch == '+')
break;
}
if (ch == '+')
break;
delay(1000);
}
Serial.print(IP); //prints IP address in Serial monitor
Serial.print("Port:");
Serial.println(80);
}
void connect_wifi(String cmd, int t) //This function is for connecting ESP8266 with wifi
network by using AT commands
{
int temp = 0, i = 0;
while (1)
{
Serial.println(cmd); //Sends to serial monitor
Serial1.println(cmd); //sends to ESP8266 via serial communication
while (Serial1.available())
{
if (Serial1.find("OK"))
i = 8;
}
delay(t);
if (i > 5)
break;
i++;
}
if (i == 8)
Serial.println("OK");
else
Serial.println("Error");
}
void wifi_init() //This function contains AT commands that passes to connect_wifi()
{
connect_wifi("AT", 100); //Sends AT command with time(Command for
Achknowledgement)
connect_wifi("AT+CWMODE=3", 100); //Sends AT command with time (For setting mode of
Wifi), mode 3 is station and access point
connect_wifi("AT+CWQAP", 100); //Sends AT command with time (for Quit AP)
connect_wifi("AT+RST", 5000); //Sends AT command with time (For RESETTING WIFI)
check4IP(5000);
if (!No_IP)
{
Serial.println("Connecting Wifi....");
connect_wifi("AT+CWJAP=\"DESKTOP-Archer_01\",\"Trialsinspace\"", 7000); // WiFi
username and password here
// Robert's Phone , fuckchina
// Verizon-SM-J327V-9E26\",\"sur3pass
// laptop modile wifi hotspot: DESKTOP-Archer_01 , Trialsinspace
}
else
{
}
Serial.println("Wifi Connected");
get_ip();
connect_wifi("AT+CIPMUX=1", 100); //Sends AT command with time (For creating
multiple connections)
connect_wifi("AT+CIPSERVER=1,80", 100); //Sends AT command with time (For setting
up server with port 80)
}
void sendwebdata(String webPage) //, int pf_max //This function is used to send
webpage datas to the localserver
{
int ii = 0;
while (1)
{
unsigned int l = webPage.length();
Serial.print("AT+CIPSEND=0,");
Serial1.print("AT+CIPSEND=0,");
Serial.println(l + 2);
Serial1.println(l + 2);
delay(100);
Serial.println(webPage); //sends webpage data to serial monitor
// Serial.println(pf_max);
Serial1.println(webPage); //sends webpage data to Serial1 ESP8266
// Serial1.println(pf_max);
while (Serial1.available())
{
break;
// }
if (Serial1.find("OK"))
{
ii = 11;
break;
}
}
if (ii == 11) {
break;
}
// if (y >= 6) {
break;
// }
delay(2000);
break;
}
}
void Send() //This function contains data to be sent to local server
{
webpage = "<h1>3phase Microprocessor Relay</h1><body bgcolor=f0f0f0>";
sendwebdata(webpage);
delay(100);
webpage = names;
sendwebdata(webpage);
delay(100);
Serial.print("Sending: ");
for (int b = 0; b <= 2; b++) {
webpage = space;
sendwebdata(webpage);
delay(100);
webpage += "<p>Phase" + String(b + 1) + "</p>";
sendwebdata(webpage);
delay(100);
switch (THMPR_flag[b]) {
case 1:
Serial.println("relay engaged");
webpage = prblm; // relay engaged, overcurrent present
delay(100);
sendwebdata(webpage);
delay(100);
break; // break from for loop
case 2: // approaching the DANGER ZONE
Serial.println("your in the danger zone");
webpage = danger;
delay(100);
sendwebdata(webpage); // , pf_max[1]
delay(100);
break; // break from for loop
default:
Serial.println("operation is normal");
webpage = safe; //operation is normal
delay(100);
sendwebdata(webpage); // , pf_max[1]
delay(100);
break; // break from for loop
}
}
Serial1.println("AT+CIPCLOSE=0"); //Closes the server connection
}
//---------------------------------------------------------------
//hall sensor functions
//---------------------------------------------------------------
float getVPP(int SensorIn) // this function is used to attain the peak to peak voltage of a phase to be
used later
{
float Result;
int readValue; //value read from the sensor
float adcConv = 0.0008058608058608059; // Volts per step
uint32_t start_time = millis();
//Serial.println("value from ADC: " + String(analogRead(SensorIn)));
float Value = analogRead(SensorIn) - 1700;// reading input and removing offset
if (SensorIn == PB1) {
Value += 60;
}
Result = (Value * adcConv); // convertting the ADC value into volts
//Serial.println("voltage: " + String(Result));
//Serial.println(" voltage in mV: " + String((Result * 10000) / 2, 3));
return (Result * 10000) / 2; // returns result in mV
}
//---------------------------------------------------------------
void setup() {
//wifi
Serial.begin(9600); //begins serial monitor with baud rate 9600
Serial1.begin(115200); //begins serial communication with esp8266 with baud rate 115200
(Change according to your esp8266 module)
wifi_init();
Serial.println("WiFi System Ready..");
// hall sensor
pinMode(sensorIn[0], INPUT);
pinMode(sensorIn[1], INPUT);
pinMode(sensorIn[2], INPUT);
//relay
pinMode(Signal[0], OUTPUT);// make more, for more pins
pinMode(Signal[1], OUTPUT);// make more, for more pins
pinMode(Signal[2], OUTPUT);// make more, for more pins
//pinMode(Reset[0], OUTPUT);
//power factor
pinMode(pf_in[0], INPUT);
pinMode(pf_in[1], INPUT);
pinMode(pf_in[2], INPUT);
// frequency measurement
pinMode(freqIn[0], INPUT);
uint32_t start_time = millis();
}
void loop() {
uint32_t start_time = millis();
for (int b = 0; b <= 2; b++) {
VRMS[b] = getVPP(sensorIn[b]); // copying the array, there are other ways to do this, could
look them up
AmpsRMS[b] = VRMS[b] / mVperAmp; // calculating RMS amperage based upon the type of hall
sensor I'm using
Serial.print(AmpsRMS[b], 2); Serial.print(" Amps RMS, phase"); Serial.println(b + 1);
}
flt_check(AmpsRMS);// sending amps measurement to fault detection, be aware `.20 A offset at
most,from the ac217 hall sensor
getFrequency();
for (int b = 0; b <= 2; b++) {
Serial.print("frequency of phase"); Serial.print(b + 1); Serial.print(": "); Serial.println(Freqs[b]);
}
delay(2000);
//powerfactor();
Serial.println("Please Refresh your Page");
while (Serial1.available())
{
if (Serial1.find("0")) // 0,CONNECT
{
Serial.println("Start Printing");
Send();
Serial.println("Done Printing");
delay(1000);
}
break;
}
while (THMPR_flag[0] == 1 || THMPR_flag[1] == 1 || THMPR_flag[2] == 1) { // relay has been
tripped, waiting for reset
Serial.println("relays have been tripped");
// repeats code for the webpage
Serial.println("Please Refresh your Page");
while (Serial1.available())
{
if (Serial1.find("0"))
{
Serial.println("Start Printing");
Send();
Serial.println("Done Printing");
}
break;
}
delay(1000);
}
}
4.0 Glossary
Word or Acronym Meaning in This Context
Zero cross detection A method to determine the phase difference between two signals
5.0 Appendix – Reference documents and hardware interface details
Code used in microcontroller:
No. URL
Example:
USB 1.x/2.0 standard pinout
Pin
Name
Cable color
Description 1 VBUS Red +5 V
2 D− White Data −
3 D+ Green Data +
4 GND Black Ground