Uploaded by virajnh8

Smart Energy Meter

Major Project- II (EE499)
Project Report Submitted
Viraj N H - 13EE251
Suchith J N - 13EE147
G Rohit - 13EE215
Shreyas R - 13EE245
Bhargav D R - 13EE109
Under the Guidance of
Dr. Manjunatha Sharma K.
(​DEC 2016 - APRIL 2017)
by the B.Tech. Student
We hereby declare that the Project Work entitled “Smart Energy Meter”
which is being submitted to the National Institute of Technology
Karnataka, Surathkal for the award of the Degree of Bachelor of
Technology in Electrical and Electronics Engineering is a bonafide report
of the work carried out by us. The material contained in this Project
Work Report has not been submitted to any University or Institution for
the award of any degree.
Register Number
Name of the Student
Bhargav D R
Suchith J N
G Rohit
Shreyas R
Viraj N H
Department of Electrical and Electronics Engineering
Place: NITK Surathkal
This is to certify that the B.Tech Project Work Report entitled “Smart
Energy Meter” submitted by :
Register Number
Name of the Student
Bhargav D R
Suchith J N
G Rohit
Shreyas R
Viraj N H
as the record of the work carried out by them, is accepted as the ​B.Tech
Project Work Report submission​ in partial fulfilment of the requirements
for the award of degree of ​Bachelor of Technology​ in Electrical and
Electronics Engineering
Dr. Manjunatha Sharma K
(​Signature with Date​)
Chairman - DUGC
(​Signature with Date and Seal​)
The Energy Meter is considered to the point of revenue collection for the
utilities so it is necessary for them to make it fair and accurate so that both
customers and Utility organization is good with the economics. The Smart
Energy meter does both the job and meets the today’s demand of luxury and
economy since no one is required to make the billing by locally getting to the
load point.
In our project we are making a detailed design and construction of smart
meter to measure the single phase quantities. The meter can measure
Energy, Power, Frequency, Power factor, Voltage and Current and then it is
The first step of our project begins with the process diagram which gives the
general idea of the next process to be done. The process diagram is then put
in a circuit (Implemented) and then the results are monitored then the errors
are noted down from each section, then the troubleshooting of each section
is carried to make the results accurate.
The final stage if the project is Implementing the final circuit after
troubleshooting with the errors to get the better results.
Table of Contents
About Smart Meter
1.1. Introduction
1.2. Overview
1.3. History
1.4. Purpose
Preliminary Design Stage
2.1. Preliminary Block Diagram
2.2. Concepts
2.2.1. Hall effect
2.2.2. Opamp 741 Circuit
2.2.3. Passive RC filter
2.2.4. UART
2.2.5. S/N ratio
2.3. Microcontroller
2.3.1. Hardware
2.3.2. Software
2.4. Board computer
2.5. GPIO
2.6. Software
3. Implementation
3.1. Sensor Circuit
3.1.1. Hall effect Voltage Sensor (LV25-P)
3.1.2. Hall effect Current Sensor (LA55-P)
3.1.3. Linearity Test
28 Voltage sensor linearity test
28 Current sensor linearity test
3.1.4. Sensors rigged on the PCB
3.2. Level Shifter with Filter Circuit
3.3. Microcontroller
3.4. LCD Display (HD44780)
3.5. Software
3.5.1. GPIO API
3.5.2. LCD API
3.5.3. Driver
39 Initilization
39 Receive and process sub-component
40 Display sub-component
42 Communication sub-component
3.5.4. Server software
3.6. Complete Circuit Diagram
4. Troubleshooting
4.1. Hardware
4.1.1. Soldering
4.1.2. Noise from the Level Shifter
4.1.3. Communication Error
4.1.4. Sampling reference
4.2. Software
4.2.1. GPIO troubleshooting
4.2.2. LCD troubleshooting
4.2.3. Driver troubleshooting
52 Splitting the work among different cores
52 Long critical section in Display module
52 Handling blocking accept() function
53 Serial Communication settings
54 Detecting valid zero crossings
4.3. Final Circuit Diagram
5. Results
5.1. Sensor Output
5.2. Level shifter with filter output
5.3. LCD Display output
5.4. Remote Device output
5.5. Conclusion
6. Future improvements
6.1. Hardware
6.2. Software
7. Application (s)
7.1. Automatic Billing
7.2. Alerting System
8. References
1. About Smart Meter
Fig. 1
1.1. Introduction
A smart meter is an electronic device that records consumption of electric energy in
intervals of an hour or less and communicates that information at least daily back to the
utility for monitoring and billing. Smart meters enable two-way communication between
the meter and the central system. Unlike home energy monitors, smart meters can gather
data for remote reporting. Such an advanced metering infrastructure (AMI) differs from
traditional automatic meter reading (AMR) in that it enables two-way communications with
the meter.
1.2. Overview
The term Smart Meter often refers to an electricity meter, but it also may mean a device
measuring natural gas or water consumption.
Similar meters, usually referred to as interval or time-of-use meters, have existed for years,
but "Smart Meters" usually involve real-time or near real-time sensors, power outage
notification, and power quality monitoring. These additional features are more than simple
automated meter reading (AMR). They are similar in many respects to Advanced Metering
Infrastructure (AMI) meters. Interval and time-of-use meters historically have been installed
to measure commercial and industrial customers, but may not have automatic reading.
Research by Which?, the UK consumer group, showed that as many as one in three confuse
smart meters with energy monitors, also known as in-home display monitors. The roll-out
of smart meters is one strategy for energy savings. While energy suppliers in the UK could
save around £300 million a year from their introduction, consumer benefits will depend on
people actively changing their energy use. For example, time of use tariffs offering lower
rates at off-peak times, and selling electricity back to the grid with net metering, may also
benefit consumers.
The installed base of smart meters in Europe at the end of 2008 was about 39 million units,
according to analyst firm Berg Insight. Globally, Pike Research found that smart meter
shipments were 17.4 million units for the first quarter of 2011. Visiongain has determined
that the value of the global smart meter market will reach $7bn in 2012.
Smart meters may be part of a smart grid, but alone, they do not constitute a smart grid.
1.3. History
In 1972, Theodore George "Ted" Paraskevakos, while working with Boeing in Huntsville,
Alabama, developed a sensor monitoring system that used digital transmission for security,
fire, and medical alarm systems as well as meter reading capabilities. This technology was a
spin-off of the automatic telephone line identification system, now known as Caller ID.
In 1974, Paraskevakos was awarded a U.S. patent for this technology. In 1977, he launched
Metretek, Inc., which developed and produced the first fully automated, commercially
available remote meter reading and load management system. Since this system was
developed pre-Internet, Metretek utilized the IBM series 1 mini-computer. For this
approach, Paraskevakos and Metretek were awarded multiple patents.
1.4. Purpose
Since the inception of electricity deregulation and market-driven pricing throughout the
world, utilities have been looking for a means to match consumption with generation.
Traditional electrical and gas meters only measure total consumption, and so provide no
information of when the energy was consumed at each metered site. Smart meters provide
a way of measuring this site-specific information, allowing utility companies to introduce
different prices for consumption based on the time of day and the season.
Utility companies propose that from a consumer perspective, smart metering offers
potential benefits to householders. These include, a) an end to estimated bills, which are a
major source of complaints for many customers b) a tool to help consumers better manage
their energy purchases - stating that smart meters with a display outside their homes could
provide up-to-date information on gas and electricity consumption and in doing so help
people to manage their energy use and reduce their energy bills. Electricity pricing usually
peaks at certain predictable times of the day and the season. In particular, if generation is
constrained, prices can rise if power from other jurisdictions or more costly generation is
brought online. Proponents assert that billing customers at a higher rate for peak times will
encourage consumers to adjust their consumption habits to be more responsive to market
prices and assert further, that regulatory and market design agencies hope these "price
signals" could delay the construction of additional generation or at least the purchase of
energy from higher priced sources, thereby controlling the steady and rapid increase of
electricity prices. There are some concerns, however, that low income and vulnerable
consumers may not benefit from intraday time-of-use tariffs.
An academic study based on existing trials showed that homeowners' electricity
consumption on average is reduced by approximately 3-5%.
The ability to connect/disconnect service and read meter consumption remotely are major
labor savings for the utility and can result in large layoffs of meter readers.
2. Preliminary Design stage
In this stage the preliminary design of the processes diagram is carried out and the circuit is
rigged up to test in the real time load and the data is tabulated to make the necessary
changes in the next stage of design after troubleshooting.
2.1. Preliminary Block Diagram
Fig. 2.1
2.2. Concepts
The fundamentals required to carry the preliminary processes to the implementation stage
in selection of the appropriate hardware and the technique to condition the signal that is
available from the sensors with increasing S/N ratio and attain better accuracy. Since the
signal is always weak and are easily distorted by small amount of noise, getting better S/N
ratio till the signal is sampled is the primary goal and this involves taking care of all the
hardware and its behaviour to the external environment. Then applying some signal
processing techniques to increase the S/N ratio.
2.2.1. Hall effect
Fig. 2.2.1
The Hall effect is the production of a voltage difference (the Hall voltage) across an
electrical conductor, transverse to an electric current in the conductor and to an applied
magnetic field perpendicular to the current.
The Hall coefficient is defined as the ratio of the induced electric field to the product of the
current density and the applied magnetic field. It is a characteristic of the material from
which the conductor is made, since its value depends on the type, number, and properties
of the charge carriers that constitute the current.
2.2.2. Opamp 741 Circuit
Fig. 2.2.2
The 741 IC (integrated Circuit) which is commonly called as Opamp (operational amplifier) is
used here to level shift the circuit and to provide the high input impedance for the signal
from the sensor which reduces the loading on the sensor circuit. This IC has a great noise
cancellation effect when negative feedback is applied and this greatly improves the signal
to noise ratio.
2.2.3. Passive RC filter
This is first order RC passive filter circuit, with different settings for Resistor and Capacitor
the filtering of the frequency takes place, but it also comes with the reduction in amplitude
of the input voltage so deciding the V​out​/V​in​ ration is important.
Calculation to get a desired 3dB frequency​ :
At 3dB frequency |V​out​/V​in​ | = 1/sqrt(2)
V​out​/V​in​ = X​C​/(X​C​ + R)
Here X​C​ = 1/(2*pi*f*C);
After substituting we get,
V​out​/V​in​ = 1/(1+2*pi*f*C*R)
|V​out​/V​in​| = 1/sqrt(1+ 2*pi*f*C*R)
At 3dB frequency
From (1) => 1+2*pi*f*C*R = 2
=> f = 1/(2*pi*R*C)
This is the cutoff frequency and the voltage reduction from this point is 20dB/decade (on
logarithmic scale)
2.2.4. UART
UART stands for Universal Asynchronous Receiver Transmitter, in UART communication,
two UARTs communicate directly with each other. The transmitting UART converts parallel
data from a controlling device like a CPU into serial form, transmits it in serial to the
receiving UART, which then converts the serial data back into parallel data for the receiving
device. Only two wires are needed to transmit data between two UARTs. Data flows from
the Tx pin of the transmitting UART to the Rx pin of the receiving UART:
UARTs transmit data asynchronously, which means there is no clock signal to synchronize
the output of bits from the transmitting UART to the sampling of bits by the receiving UART.
Instead of a clock signal, the transmitting UART adds start and stop bits to the data packet
being transferred. These bits define the beginning and end of the data packet so the
receiving UART knows when to start reading the bits.
When the receiving UART detects a start bit, it starts to read the incoming bits at a specific
frequency known as the baud rate. Baud rate is a measure of the speed of data transfer,
expressed in bits per second (bps). Both UARTs must operate at about the same baud rate.
The baud rate between the transmitting and receiving UARTs can only differ by about 10%
before the timing of bits gets too far off.
Both UARTs must also must be configured to transmit and receive the same data packet
How UART works?
UART transmits/receives the data through the data bus. The data bus is used to send data
to the UART by another device like a CPU, memory, or microcontroller. Data is transferred
from the data bus to the transmitting UART in parallel form. After the transmitting UART
gets the parallel data from the data bus, it adds a start bit, a parity bit, and a stop bit,
creating the data packet. Next, the data packet is output serially, bit by bit at the Tx pin. The
receiving UART reads the data packet bit by bit at its Rx pin. The receiving UART then
converts the data back into parallel form and removes the start bit, parity bit, and stop bits.
Finally, the receiving UART transfers the data packet in parallel to the data bus on the
receiving end.
UART transmitted data is organized into ​packets​. Each packet contains 1 start bit, 5 to 9 data
bits (depending on the UART), an optional ​parity​ bit, and 1 or 2 stop bits
The UART data transmission line is normally held at a high voltage level when it’s not
transmitting data. To start the transfer of data, the transmitting UART pulls the transmission line
from high to low for one clock cycle. When the receiving UART detects the high to low voltage
transition, it begins reading the bits in the data frame at the frequency of the baud rate.
The data frame contains the actual data being transferred. It can be 5 bits up to 8 bits long if a
parity bit is used. If no parity bit is used, the data frame can be 9 bits long. In most cases, the
data is sent with the least significant bit first.
Parity describes the evenness or oddness of a number. The parity bit is a way for the receiving
UART to tell if any data has changed during transmission. Bits can be changed by
electromagnetic radiation, mismatched baud rates, or long distance data transfers. After the
receiving UART reads the data frame, it counts the number of bits with a value of 1 and checks
if the total is an even or odd number. If the parity bit is a 0 (even parity), the 1 bits in the data
frame should total to an even number. If the parity bit is a 1 (odd parity), the 1 bits in the data
frame should total to an odd number. When the parity bit matches the data, the UART knows
that the transmission was free of errors. But if the parity bit is a 0, and the total is odd; or the
parity bit is a 1, and the total is even, the UART knows that bits in the data frame have changed.
To signal the end of the data packet, the sending UART drives the data transmission line from a
low voltage to a high voltage for at least two bit durations.
1. The transmitting UART receives data in parallel from the data bus
2. The transmitting UART adds the start bit, parity bit, and the stop bit(s) to the data frame
3. The entire packet is sent serially from the transmitting UART to the receiving UART. The
receiving UART samples the data line at the pre-configured baud rate
4. The receiving UART discards the start bit, parity bit, and stop bit from the data frame
5. The receiving UART converts the serial data back into parallel and transfers it to the data bus
on the receiving end
2.2.5. S/N ratio
In analog and digital communications, signal-to-noise ratio, often written S/N or SNR, is a
measure of signal strength relative to background noise. The ratio is usually measured in
decibels (dB) using a signal-to-noise ratio formula. If the incoming signal strength in
microvolts is Vs, and the noise level, also in microvolts, is Vn, then the signal-to-noise ratio,
S/N, in decibels is given by the formula: S/N = 20 log10(Vs/Vn).
If Vs = Vn, then S/N = 0. In this situation, the signal borders on unreadable, because the
noise level severely competes with it. In digital communications, this will probably cause a
reduction in data speed because of frequent errors that require the source (transmitting)
computer or terminal to resend some packets of data.
Ideally, Vs is greater than Vn, so a high signal-to-noise ratio is positive. As an example,
suppose that Vs = 10.0 microvolts and Vn = 1.00 microvolt. Then:
S/N = 20 log10(10.0) = 20.0 dB
This results in the signal being clearly readable. If the signal is much weaker but still above
the noise -- say, 1.30 microvolts -- then:
S/N = 20 log10(1.30) = 2.28 dB
This is a marginal situation. There might be some error in reading the signal of
fundamental frequency.
This ratio is very important because we are here interested only in fundamental frequency
quantity measurement, so if other frequency components gets into the system then the
noise in the system increases which reduces the S/N ratio.
2.3. Microcontroller
2.3.1. Hardware
MSP430F5529LP :
is a 16 bit microcontroller which can be clocked up to 25MHz of
frequency with its internal DCO (Digitally controlled oscillator). Its has FLL (Frequency
locked loop) technology to control the DCO frequency and set it a particular value. This has
a 12 bit one sampling core to perform ADC (Analog to Digital Conversion) with 16 channels.
The FET (Flash emulator tool) which bridges between MSP430F5529 microcontroller with
computer supports USB 2.0 and a maximum baud rate of 115200.
Arduino Uno (Atmega328P) : Arduino Uno is a microcontroller board based on the
ATmega328P. It has 14 digital input/output pins (of which 6 can be used as PWM outputs), 6
analog inputs, a 16MHz quartz crystal, a USB connection, a power jack, an ICSP header and
a reset button. It contains everything needed to support the microcontroller; simply
connect it to a computer with a USB cable or power it with a AC-to-DC adapter or battery to
get started.. You can tinker with your UNO without worrying too much about doing
something wrong, worst case scenario you can replace the chip for a few dollars and start
over again. It can support up to 115200 baud rate but can go up to 460800 baud rate with
added excess error of around 15-20%.
2.3.2. Software
MSP430F5529LP​: Code composer studio (CCS) is the open source IDE (Integrated
development Environment) by Texas Instruments Inc. helps in programming the device
through the USB serial port which uses Embedded C language. The alternative option of
Energia is available to program the device with some compromise in the access to all the
hardware available in the device but with the user friendly libraries.
Arduino Uno (Atmega 328P)​: Arduino v1.6 is the latest open source IDE available to program
the device which has a user friendly libraries, programming is based on the C language.
2.4. Board computer
Fig. 2.4
PINE A64 is Single Board Computer powered by Quad-Core ARM Cortex A53 64-Bit
Processor. It provides PI-2 Bus, Euler Bus and many others peripheral devices interface for
makers to integrate with sensors and devices. Various Operating System (OS) are made
available by open source community such Mainline Kernel, Linux Distro, Android, Remix OS,
Windows IoT and many more to come.
It has the following features
1.2 Ghz Quad-Core ARM Cortex A53 64-Bit Processor. Executes both 64 and 32 Bit
for scalable high performance.
Dual I/O expansion slots
Dual Core Mali 400 MP2 Graphics card
512MB DDR3 Memory
Integrated Display engine with HDMI 1.4a
10/100Mbps Ethernet Port
We have used Ubuntu 16.04 which is a Linux based Operating System with MATE desktop
2.5. GPIO
GPIO stands for General Purpose Input Output. Pine-64 has 28 GPIO ports.
Because of “everything is a file” view in Linux based systems, GPIO ports are represented as
files and they can be read from or written to using File based I/O techniques which are
quite common. Before using a GPIO port, it has to be initialized.
Here is a small shell script we used to turn a GPIO pin specified by <PORT-NO> to high.
# echo <PORT-NO> > /sys/class/gpio/export
# echo “out” > /sys/class/gpio/gpio<PORT-NO>/direction
# echo “1” > /sys/class/gpio/gpio<PORT-NO>/value
The first line registers the GPIO pin specified by PORT-NO with the system. The second line
specifies that the port is an output port. The third line sets the value at the GPIO port to be
high. Replacing “0” in place of “1” would turn it low. An LED is connected to the GPIO pin
and it glows when the value is high.
2.6. Software
Sampler ​is responsible for getting samples of voltage and current and formatting the data.
Each sample obtained is broken down into 4 bytes and sent to the driver. Sampler is either
MSP430 or Arduino.
Display ​is responsible for showing the values like Energy, Current and Voltage (RMS),
Power, Frequency, Power factor. Values are displayed in LCD.
Server ​is where all data from the board computer goes. There is also a remote terminal
through which one can connect to the device and ask for instantaneous values. This
program runs in a remote computer.
Fig. 2.6
Driver is a software component which controls and coordinates various functionalities of
the system. This software runs in the board computer. It contains three sub-components.
1. Data processor module: ​Receive voltage and current data and check for errors.
Then process it to compute power, frequency, energy etc.
2. LCD module: ​It is responsible for controlling the LCD. It is tasked with displaying
instantaneous values on the LCD screen.
3. Communication module: ​It is responsible for communicating with the server. It
sends instantaneous data to the remote server through the network. (Currently we
are using intranet)
3. Implementation
With the help of the concepts from ​section 2.2. We implement each section of the Process
as shown in the block diagram in ​section 2.1. By the selection of the appropriate
components and devices to meet the desired requirement of Indian standards for
Advanced Metering Infrastructure (AMI).
3.1. Sensor CIrcuit
Here the hall effect sensors are used to step down and sense the values. Both voltage and
current sensor gives current as the output parameter and input is also the current. So it is
required to setup the proper circuit to get the voltage signals out of that current.
3.1.1. Hall effect Voltage Sensor (LV25-P)
Required Parameter
Required Rating
Rating of the sensor
Voltage in rms
Output voltage in rms
25mA*190ohm = 4.75V
Since the rating of the sensor is above the required value it is selected for our project.
The sensor requires +12V and -12V supply for the operation. The selection of the value of
the resistor is done with the help of the data sheet and it is recommended that the
resistance must be within a range of 30 to 190 ohm.
Calculation of the resistor values (R​M​ , R​1)​ ​:
I​PN​ = V​IN​/R​1
V​IN​ = 250V, R​1​ is chosen such a way that I​PN​ <10mA, so let R​1​ = 36kohm
I​PN​ = 6.94mA
Conversion ratio from the datasheet is 2500:1000
I​S​ = 2500*I​PN​/1000 = 17.36mA
Required voltage for the sampler is 2.5 p-p
So R​M​ = 2.5/(sqrt(2)*2*17.36mA) = 50.91 ohm
So R​M​ < 50.91 ohm, so we have chosen R​M​ = 47ohm
Circuit Diagram
3.1.2. Hall effect Current Sensor
Required Parameter
Required Rating
Rating of the sensor
Input Current in rms
Output voltage in rms
25mA*100ohm = 2.5V
Since the rating of the sensor is above the required value it is selected for our project.
The sensor requires +12V and -12V supply for the operation. The selection of the value of
the resistor is done with the help of the data sheet and it is recommended that the
resistance must be within a range of 10 to 100 ohm.
Calculation of the resistor value (R​M​ )​:
Conversion ratio from the datasheet is 1:1000
I​PN​ = 30A
I​S​ = 30A/1000 = 30mA
Required voltage for the sampler is 2.5 p-p
So R​M​ = 2.5/(sqrt(2)*2*30mA) = 29.46 ohm
So R​M​ < 29.46 ohm, so we have chosen R​M​ = 22ohm
Circuit Diagram
3.1.3. Linearity Test
This is a test to find out the transfer function linearity in RMS values. In this test the Sensor
Output voltage in RMS is plotted against source voltage (V​S​) for voltage sensor and load
current for current sensor(I​S​) Voltage sensor linearity test
1. This is for measuring resistance R​M​ = 47Ω , R​1​ = 47kΩ
Fig. (a)
From this we can say that the transducer is linear for R​M​ = 47Ω , slope = 1/397.4983 V/V
2. This is for measuring resistance R​M​ = 120Ω , R​1​ = 47kΩ
Fig (b)
From this we can say that the transducer is linear for R​M​ = 120Ω , slope = 1/150.3799 V/V Current sensor linearity test
1. This is for measuring resistance R​M​ = 22Ω
Fig. (a)
From this we can say that the transducer is linear for R​M​ = 22Ω , slope = 1/46.2529 V/A
2. This is for measuring resistance R​M​ = 47Ω
Fig. (b)
From this we can say that the transducer is linear for R​M​ = 47Ω , slope = 1/21.9865 V/A
3.1.4. Sensors rigged on the PCB
Fig. 3.1.4
3.2. Level Shifter with Filter circuit
This circuit gives the shift in the voltage of the sinusoidal signal received from the sensors
and makes it positive and every instant, this is required for the microcontroller since
microcontroller cannot sample the negative signals. Here the opamp (741) is employed for
this task which has a better noise cancellation in negative feedback and provides high input
impedance which reduces the load on sensors more about this is in ​section 2.2.2.
The reference voltage of 1.25V is set using a 7805 voltage regulator IC followed by a
potential divider circuit and this circuit is powered by a 9V DC transistor battery.
Circuit Diagram​:
FIg. 3.2.1
Potential divider (PD)​:
V​ref​ = (1/(1/R+1/R+1/R))/(R + (1/(1/R+1/R+1/R)))*V​7805​ = ¾ *V​7805​ = ¾*5V = 1.25V
Circuit Diagram​:
Fig. 3.2.2
Calculation of R1, R2, R3, R4​:
Grounding signal in, (non inverting amplifier configuration)
V​o1​ = (1+R2/R1)*(R3*V​ref​)/(R3+R4) ----- (1)
Grounding V​ref​ (non inverting amplifier configuration)
V​o2​ = (1+R2/R1)*(R4*V​signal​)/(R3+R4) ----- (2)
Output, V​o​ = V​o1​ + V​o2
From (1) and (2)
V​o​ = (1+R2/R1)*(R3*V​ref​ + R4*V​signal​)/(R3+R4)
Setting R1=R2=R3=R4=R
V​o​ = V​ref​ + V​signal\-*
Let the value of R = 10Kohm
Now the circuit with shift the voltage of the signal by V​ref
This level shifted circuit will have high frequency signals because of the component noise
and other noise from the sensor which are other than the fundamental frequency so in
order to extract only the fundamental frequency (approx.) we need to use a Low pass filter
circuit this will help to increase S/N ratio.
From the ​section 2.2.3. We need to calculate the value of R and C required to get the
desired 3dB frequency.
Desired 3db frequency must be above 50Hz,
Let’s say the resistance R = 10Kohm and now to get a frequency above 50Hz what must be
the value of capacitor C​req
C​req​ = 1/(2*pi*f*R) = 3.18e-7F
This closest value of capacitor available below C​req (since C is inversely proportional to f) is
C​standard​ = 0.1uF
f​3dB​ ​ = 1/(2*pi*C​standard​*R) = 159.15Hz
This value is close enough to 50Hz so its chosen.
The rigged up circuit on PCB:
Fig. 3.2.3
3.3. Microcontroller
The Microcontroller we used here is the Arduino Uno board with Atmega328P chip which
has a 10 bit ADC (Analog to digital converter), with 6 ADC pins to sample the analog signal
at a specified rate. Atmega328P has 28 pins out of which 14 are GPIO pins. It has 6 PWM
pins which generates the analog waveforms of specified period.
This purpose we are using it is to sample the signals from the sensor and then
communicate these values with the Pine64 board through USB 2.0 serial port at a specified
baud rate this communication protocol is called ​UART​.
Data from the arduino sending format:
Since the arduino has a 10 bit ADC, we cannot send all the 10 bits at once through the serial
channel so we have divided the data as shown below with adding identification bits for bit 7
and bit 6 in the stage 3.
Fig. 3.3
Reason for selection of UART:
1. It is easy to setup and communicate.
2. Changing the data transmission rate is much easier in Arduino
3. It can communicate with just 2 connected data lines between the device (Here
between Arduino and Pine64)
4. The Arduino Uno board has a driver with hardware which interface with the Pine64
USB 2.0 so the data can be transmitted just by a USB cable which is used to power
the Arduino.
1. Only one byte of data can be sent at a time.
2. Higher data transmission rates typically above 115200 bits/sec increases errors in
communication drastically.
3.4. LCD Display (HD44780)
The Hitachi HD44780 LCD controller is an alphanumeric dot matrix liquid crystal display
(LCD) controller developed by Hitachi that was commonly used during the MCS-51 era. It
was made commercially available around year 1987. The character set of the controller
includes ASCII characters, Japanese Kana characters, and some symbols in two 28 character
lines. Using an extension driver, the device can display up to 80 characters.
Fig. 3.4
The Hitachi HD44780 LCD controller is limited to monochrome text displays and is often
used in copiers, fax machines, laser printers, industrial test equipment, networking
equipment, such as routers and storage devices.
Compatible LCD screens are manufactured in several standard configurations. Common
sizes are one row of eight characters (8x1), and 16×2, 20×2 and 20×4 formats. Larger
custom sizes are made with 32, 40 and 80 characters and with 1, 2, 4 or 8 lines. The most
commonly manufactured larger configuration is 40x4. Characters, which requires two
individually addressable HD44780 controllers with expansion chips as a single HD44780
chip can only address up to 80 characters. A common smaller size is 16×2, and this size is
readily available as surplus stock for hobbyist and prototyping work.
Character LCDs use a 16 contact interface, commonly using pins or card edge connections
on 0.1 inch (2.54 mm) centers. Those without backlights may have only 14 pins, omitting
the two pins powering the light. This interface was designed to be easily hooked up to the
MCS-51 XRAM interface, using only two address pins, which allowed displaying text on LCD
using simple MOVX commands, offering cost effective option for adding text display to
The pinout is as follows:
1. Ground
2. VCC (+3.3 to +5V)
3. Contrast adjustment (VO)
4. Register Select (RS). RS=0: Command, RS=1: Data
5. Read/Write (R/W). R/W=0: Write, R/W=1: Read
6. Clock (Enable). Falling edge triggered
7. Bit 0 (Not used in 4-bit operation)
8. Bit 1 (Not used in 4-bit operation)
9. Bit 2 (Not used in 4-bit operation)
10. Bit 3 (Not used in 4-bit operation)
11. Bit 4
12. Bit 5
13. Bit 6
14. Bit 7
15. Backlight Anode (+) (If applicable)
16. Backlight Cathode (-) (If applicable)
The nominal operating voltage for LED backlights is 5V at full brightness, with dimming at
lower voltages dependent on the details such as LED color. Non-LED backlights often
require higher voltages.
Mode Selection
Selecting 4-bit or 8-bit mode requires careful selection of commands. There are two
primary considerations. First, with D3-D0 unconnected, these lines will always appear low
(0b0000) to the HD44780 when it is in 8-bit mode. Second, the LCD may initially be in one of
three states:
(State1) 8-bit mode
(State2) 4-bit mode, waiting for the first set of 4 bits
(State3) 4-bit mode, waiting for the second set of 4 bits
State3 may occur, for example, if a prior control was aborted after sending only the first 4
bits of a command while the LCD was in 4-bit mode.
The following algorithm ensures that the LCD is in the desired mode:
1. Set D7-D4 to 0b0011, and toggle the enable bit.
1. If in State1, the LCD will see the command as 0b0011_0000, and thus remain in
8-bit mode (State1).
2. If in State2, the LCD will simply latch the value 0b0011 into bits 7-4 and then move
to State3.
3. If in State3, the LCD will latch the value 0b0011 into bits 3-0, and then execute a
random command based on the (unknown to us) values in bits 7-4, after which it will
either be in State1 (if the unknown bits happened to be 0b0011), or State2 (if the
unknown bits were anything else).
2. Repeat the above, setting D7-D4 to 0b0011 and toggling the enable bit again.
1. If in State1, the LCD will remain in 8-bit mode (State1) just as above.
2. If in State2, it will latch the value into bits 7-4 and move to State3, just as above.
3. If in State3, the LCD will latch the value into bits 3-0 just as above and execute a
command. However, the command will no longer be random, but will be the 0b0011
that was latched from State2 in the previous iteration. Thus, the LCD will switch to
8-bit mode and change to State1.
3. The LCD is now in either State1 or State 3. Repeat the previous step one more time.
1. If in State1, the LCD will remain in 8-bit mode (and thus State1).
2. The LCD can no longer be in State2 at this point.
3. If in State3, the LCD will latch the value into bits 3-0 and execute a command,
which will be the 0b0011 that was latched from State2 in the previous iteration, thus
switching the LCD to 8-bit mode and State1.
4. Now that the LCD is definitely in 8-bit mode, it can be switched to 4-bit mode if
desired. To do so, set D7-D4 to 0b0010 and toggle the enable bit. This will leave the
LCD in 4-bit mode, configured for a single line and 5x8 fonts.
5. Issue any desired additional Function Set commands to specify the number of lines
and the font to use, being sure to use the appropriate value for bit 4 so as to remain
in the desired mode (0 for 4-bit and 1 for 8-bit).
Once in 4-bit mode, character and control data are transferred as pairs of 4-bit
"nibbles" on the upper data pins, D7-D4. The four most significant bits (7-4) must be
written first, followed by the four least significant bits (3-0).
3.5. Software
3.5.1. GPIO API
typedef enum { IN,OUT }
typedef enum { LOW=0, HIGH=1 } PORT_VALUE;
typedef int
typedef struct {
gpio_open(GPIO *gpio, GPIO_PORT port, DIRECTION dir);
gpio_close(GPIO *gpio);
gpio_get_direction(GPIO *port);
gpio_get_port_no(GPIO *port);
gpio_set_direction(GPIO *port, DIRECTION dir);
gpio_set_value(GPIO *port, PORT_VALUE val);
This is the API used to handle GPIO ports.
The functions ​gpio_init() and ​gpio_finalize() are used to export and unexport GPIO port
files in sysfs. Export is needed before using GPIO pins through sysfs. Functions ​gpio_open()
and ​gpio_close() are used to obtain and release handles to a particular GPIO port
respectively. Rest are getters and setters for port direction and value.
3.5.2. LCD API
typedef struct {
GPIO data[8];
GPIO enable;
GPIO rw, rs;
typedef enum { INSTRUCTION=0, DATA=1 } LCD_RSH_MODE;
typedef enum { READ=1, WRITE=0 }
typedef int
void lcd_set_enable(LCD *disp, PORT_VALUE val);
void lcd_set_readwrite(LCD *disp, LCD_RW_MODE val);
void lcd_set_regshift(LCD *disp, LCD_RSH_MODE val);
lcd_send_command(LCD *disp, LCD_COMMAND cmd);
lcd_send_data(LCD *disp, int data);
lcd_send_text(LCD *disp, const char *text, int r, int c);
lcd_init(LCD *lcd, GPIO data[8], GPIO enable, GPIO rw, GPIO rs);
lcd_close(LCD *lcd);
This is the API used to control LCD. Functions ​lcd_init() ​and ​lcd_close() ​are used to acquire
and release GPIO ports required for them. The most important function used here is
lcd_send_text() ​which is used to display the text given row and column. It is used by the
driver sub-component.
3.5.3. Driver
Driver software runs in Pine-64 board. It is the main program which is responsible for
receiving data from the microcontroller, sending data to the server and displaying values in
the meter. It depends on LCD and GPIO API.
Each of the subcomponents run in a different threads which are bound to different cores. A
thread is a unit of computation which shares the same address space as a process.
Basically, it can be thought of as the lightweight process. We have used ​pthread (POSIX
threads) ​library to deal with threads. The Operating System scheduler doesn’t guarantee
that new threads are bound to a particular core. But there are non-standard extensions in
pthread implementation in Linux which allows us to do that (pthread_setaffinity_np). It
allows us to leverage the power of multiple cores in the system. The board we are using has
4 cores and we use 3 of them. One for each subcomponent. This design also allows us to
add more functionality to the program by adding more threads since they execute
independently while not compromising with the performance of the system. Initialization
First GPIO ports, LCD display and Serial ports are initialized. Then additional threads are
created for LCD and Communication sub-components. Once the sub-components start,
they request the scheduler to set bind them to different cores. Then the main loop which
waits for data from sampler starts. From this point of time, three threads will be running on
three different cores. Receive and process sub-component
This component receives data from the sampler. For each record of voltage and current, 4
bytes has to be received. It receives it byte by byte instead of reading all 4 bytes at once
because it is easy to handle errors this way. Once data is received it checks the sequence
number (which is most significant two bits of data). If the sequence number is wrong, then
the whole sample is discarded. The receiver is a finite state machine with 6 states
VOLTAGE_LOW and VOLTAGE_HIGH - Lower and higher bytes of voltage data.
CURRENT_LOW and CURRENT_HIGH - Lower and higher bytes of current data.
ERROR - If there is error in data, then this state is reached.
PROCESS - Data received successfully
If data is received successfully, then the voltage and current bytes are assembled
discarding sequence numbers. It is then converted to the actual value by offsetting effects
of level shifter and sampler.
Computation of RMS values of current and voltage, power, frequency are triggered only at
zero crossings. Zero crossing is detected by comparing the previous and current values of
voltage. Only voltage zero crossing timestamps are recorded. Once certain number of zero
crossings are recorded, computation of RMS values of current, voltage, power, energy,
power factor are triggered. The time interval is the difference between the first and the last
recorded zero crossing. It is needed to compute energy. Frequency is computed as the
reciprocal of the average time for each cycle which again can be computed by zero crossing
It might happen that some zero crossing readings are lost. In order to handle such
situations we compute if enough readings are available, else the readings are completely
discarded. The number of zero crossing readings required to compute each quantity can
be set in code.
Code to compute RMS value of current, voltage, power, power factor and time elapsed
v_rms = sqrt(v_squared_sum/n_samples);
a_rms = sqrt(a_squared_sum/n_samples);
real_pow = p_sum/n_samples;
apparent_pow = v_rms * a_rms;
power_factor = real_pow/apparent_pow;
cycle_time = time_diff(vzstamps[0],vzstamps[vcnt-1]);
V_squared_sum and a_squared_sum are reset after computation. They represent the sum
of square of the voltage and current readings. The variable n_samples represent the
number of samples considered for computing the quantity.
The number of zero crossings considered for computing these quantities is denoted by the
constant N_ZCROSS. Similarly, the number of zero crossings considered to compute
frequency is N_CYCLES. Currently we have set N_ZCROSS to 3 and N_CYCLES to 10.
Code to compute frequency
double compute_frequency(struct timespec fzstamps[], int fcnt) {
double f_acc = 0.0;
int cycles = 0, cur = 2;
while (cur < fcnt) {
f_acc += 1.0/time_diff(fzstamps[cur-2],fzstamps[cur]);
cur += 2;
return f_acc/cycles;
Frequency of one cycle is computed alternating timestamps as shown in line 5 of the code.
Frequency is the average of frequency of all the cycles.
In driver.c, it resides in the function
void receive_and_process_data(int fd) Display sub-component
while (threads.process) {
if (!lcdd.display) continue;
lcd_send_text(&lcdd.disp, lines[cur_line % 5], 1, 0);
lcd_send_text(&lcdd.disp, lines[(cur_line+1) % 5], 2, 0);
lcd_send_text(&lcdd.disp, lines[(cur_line+2) % 5], 3, 0);
lcd_send_text(&lcdd.disp, units[cur_line % 5], 1, 9);
lcd_send_text(&lcdd.disp, units[(cur_line+1) % 5], 2, 9);
lcd_send_text(&lcdd.disp, units[(cur_line+2) % 5], 3, 9);
double quantities[6];
pthread_mutex_lock(&lcdd.lock); {
quantities[5] = lcdd.cur_state.energy;
quantities[0] = lcdd.cur_state.power;
quantities[1] = lcdd.cur_state.v_rms;
quantities[2] = lcdd.cur_state.a_rms;
quantities[3] = lcdd.cur_state.frequency;
quantities[4] = lcdd.cur_state.power_factor;
samples = lcdd.cur_state.n_samples;
failure = lcdd.cur_state.n_errors;
lcdd.cur_state.n_samples = 0;
lcdd.cur_state.n_errors = 0;
lcdd.cur_state.power = 0.0;
lcdd.cur_state.v_rms = 0.0;
lcdd.cur_state.a_rms = 0.0;
lcdd.cur_state.frequency = 0.0;
lcdd.cur_state.power_factor = 0.0;
for (int i = 0; i < 6; ++i)
if (fabs(quantities[i]) < 1e-4) quantities[i] = 0.0;
char line0[21], line1[21], line2[21], line3[21];
printf("Samples received = %llu | %llu\n", samples,failure);
"%.3f", quantities[5]);
format[cur_line], quantities[cur_line]);
format[(cur_line+1) % 5], quantities[(cur_line+1) % 5]);
format[(cur_line+2) % 5], quantities[(cur_line+2) % 5]);
cur_line = (cur_line + 1) % 5;
The code describes the core part of LCD sub-module which sends data to the display.
pthread_mutex_lock() and pthread_mutex_unlock() are used for concurrency control since
lcdd is used by other subcomponents and hence it introduces race conditions. It is
important to keep the critical section (for which mutual exclusion is needed) small since
LCD hardware is slow and keeping the lock for a long time delays operations in other
components and hence affects the performance of the system. Then lcd_send_text() sends
the text to be displayed to the LCD (See Section 3.4.2 - LCD API). The line where cur_line is
incremented allows for scrolling effect in the display. sleep(1) suspends execution for 1
In driver.c, it resides in the function
void* lcd_routine(void *d) Communication sub-component
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
int bytes = read(connfd, request, sizeof(request));
if (bytes < 0) {
fprintf(stderr, "Failed to read client request\n");
parse_request(connfd, request,sendBuff, sizeof(sendBuff));
bytes = write(connfd, sendBuff, strlen(sendBuff)+1);
if (bytes < 0) {
fprintf(stderr, "Failed to respond\n");
The code describes the process of handling requests. We have used Linux Sockets API to
implement this functionality. First it accepts the client connection. Then it reads the
request. The request is then parsed, that is it tries to make sense out of it. Once it is done,
appropriate response is written back and the connection is closed.
In driver.c, this code resides in the function
void* server_comm_routine(void *data)
3.5.4. Server software
Server offers a terminal to query the device. Presently, get-all command gets the RMS value
of Voltage, Current, Power, Energy, Frequency, Power factor of the system at the instant of
querying. Presently, the IP of the device has to be specified for establishing connection.
Communication is done through the intranet.
It uses TCP/IP connection. The output of the command is sent to the device as raw bytes as
opposed to well formatted ones like HTTP response. It is chosen for simplicity. Right now,
the request and the response are not encrypted.
3.6. Complete Circuit Diagram
FIg. 3.5
4. Troubleshooting
It is important that once the design is implemented and tested on the real time load there
will be some amount of mismatch that exists between the desired results and the obtained
but if it is not in a specified boundary then troubleshooting becomes necessary so there by
troubleshooting of the system takes the major role in getting the desired results. Here we
have got the major troubleshooting both from the software section of the project and the
4.1. Hardware
This part includes the sensor circuit, level shifter circuit, RC filter circuit and the
Microcontroller circuit. The Hardware part troubleshooting becomes most crucial of the
fact that the samples of current and voltage must be given accurately to the
computer(Pine64) for computation, the main objective of this part is increasing S/N ratio.
Since the signal level we are working with is very low (<2.5V peak-peak) that it can be easily
distorted by small amount of Noise in the circuit.
4.1.1. Soldering
Soldering of the components to the PCB (Printed Circuit board) created lots of problems
because of high amount of wax and partially insulated leads of the components this
created some resistance between nodes.
These are some of the Problems in nodes troubleshooted:
1. Negative supply and the voltage sensor lead
2. Positive supply node
3. Measuring terminal Node of both voltage sensor and current sensor
These were the major issues troubleshooted which increased S/N ratio. Then there were
many nodes which was exposed this caused the noise to get in the circuit which had major
impact on S/N ratio.
4.1.2. Noise from the Level Shifter
The Level shifter circuit which we have used is the opamp based and it is a laboratory
based 741 IC which has its own internal component noise since it is designed in a negative
feedback loop which reduced the noise at the output.
Since the signal strength from the sensor is very weak this can get distorted by small
amount of noise so these is a much needed filter to extract the component of frequency
which we are interested (50Hz). Initially the filter circuit was designed to eliminate the
frequency above 150Hz just to keep the 3 harmonics, in the initial stage of design on testing
with the load from the single phase supply the 3rd harmonic was around 40% of the
fundamental which was distorting the signal, we have troubleshooted this by replacing the
capacitor of filter circuit with 0.22㎌ which changed the 3dB frequency from
159.15Hz to 72.34Hz so thereby eliminating the 3rd harmonics.
4.1.3. Communication Error
The Arduino Uno board which was included with Atmega328P does the sampling of the
signals from Voltage sensor and Current sensor and send these data according the format
as in ​section 3.3. to the Pine64 computer through the USB 2.0. This communication uses
the ​UART communication protocol to send the data with a specified baud rate of 230400
bits/sec when the data is received on the computer the missing of the serial identification
of first two bit (identification bits for Voltage and Current data for the lower and higher
byte) was found and the error constituted to around 15% at this baud rate and because of
this error there was lots of nonlinearity started arising in the data computed so the
troubleshooting became necessary to increase the accuracy.
The ​Arduino Uno board is replaced with the ​MSP430F5529LP which has an error of around
-0.8% to 0% according to datasheet at the baud rate of 115200 bits/sec. This baud rate is
good enough to serve our requirement with the reduction in the error which increases the
linearity of the data received.
Number of good samples received:
Arduino Uno
~15% (2 bits) linearly
~50%(8 bits) @230400
-0.8% to 0% (8
bits) @115200
-0.8% to 0%
Good sam/sec
Around 1800
1998 to 2000
1840 to 2000
From the above table it is clear that MSP430 has a better communicating ability than
Arduino and this suits well with our Project.
MSP430F5529 code:
#include "driverlib.h"
#include "msp430.h"
void adcConfigure(void);
void UART_setup(void);
void send_serial(int data);
int conv1 (int x, short int voltage);
void clock_set(void);
#define MCLK_FREQ_KHZ 16000
#define FLLREF_KHZ 32
// MCLK = Master Clock (CPU)
// Reference frequency FLL
// Ratio used to set DCO
void main(void) {
// Stop the Watchdog timer
//initialize the MCLK = SMCLK = 16MHz and ACLK to 32768Hz
int sensorValue_Voltage=0, sensorValue_Current=0;
// Configuring ADC12_A
// setting serial communication protocol UART
while(1) {
ADC12CTL0 &= ~ADC12SC;
while(ADC12CTL1 & ADC12BUSY)
sensorValue_Voltage = ADC12MEM0&0x0FFF;
sensorValue_Current = ADC12MEM1&0x0FFF;
//Enabling the ADC
//->P6.1 -> MEM0
//->P6.3 -> MEM1
//converting into required format and sending the data
void adcConfigure(void) {
//disabling the REFMSTR register
P6SEL |= BIT1 + BIT3;
//selecting P6.1 and P6.3 as ADC pins
void UART_setup(void) {
P4SEL |= 0x30;
//selecting P4.4, P4.5 as UART RX/TX pins
//put state machine in a reset mode UCA1CTL1
|= UCSSEL_2;
//selecting the clock source here its SMCLK UCA1BR0 = 138;
//baudrate selection register 0
UCA1BR1 = 0x00;
//baudrate selection register 1
UCA1MCTL = 0x0E;
UCA1CTL0 = 0x00;
//Control register 0
//put USCI in operation mode
void send_serial(int data) {
//busy checking
UCA1TXBUF = data & 0x00FF;
UCA1TXBUF = data>>8;
//function to convert the data to the required format
int conv1 (int x, short int voltage) {
int val = 0;
int loData = x & ((1<<6)-1);
int hiData = (x>>6) & ((1<<6)-1);
val |= loData;
val |= (hiData << 8);
val |= (1<<14);
if (!voltage) {
val |= (1<<7);
val |= (1<<15);
return val;
void clock_set(void) {
PMM_setVCore(PMM_CORE_LEVEL_2); //Set VCore = 2 for 16MHz
// The reference for Frequency Locked Loop
UCS_REFOCLK_SELECT, // Select 32Khz reference osc
// Start the FLL and let it settle
// This becomes the MCLCK and SMCLK automatically
// Setting the SMCLK frequency by selection DCO source
// Set auxiliary clock
4.1.4. Sampling reference
The arduino Uno comes with Atmega328P microcontroller which has 1.1V internal
reference which is stable and the 5V default reference which has variation in it so our
requirement for this project is 2.5V max, now we have only one option to choose. I.e., 5V
unstable reference. This resulted in a lots of errors while sampling the constant signal so it
is taken out from the list. The arduino also supports the external reference option from V​ref
pin, if this option is enabled we can connect external reference so that arduino samples
based on the reference. But this requires a very stable reference, we have used the
potential divider circuit from a 7805 ic to get a reference of 3V but this 7805 ic requires
>7.5V in the input, but the battery had a very unstable voltage whose voltage drops below
7.5V after loading so this created problems in external reference.
The communication issue we had in Arduino Uno is resolved by MSP430F5529 as explained
in ​section 4.1.3. This MSP430 has 2 internal reference which are very stable 1.5V and 2.5V
we have set the 2.5V reference for ADC (Analog to Digital Conversion) module which solved
our issue regarding the sampling reference.
Snippet of code to set 2.5V reference for ADC:
//disabling the REFMSTR register
//setting 2.5V reference
P6SEL |= BIT1 + BIT3;
//selecting P6.1 and P6.3 as ADC pins
4.2. Software
There can be many points of failure in software. First of all, the GPIO pins might be busy
and when it is the case, the application couldn’t issue commands if the other process
accessing it has exclusive access to it. So the application must either wait or stop.
Another component is LCD display. It is slow compared to the board computer and it might
result in the command/data sent to it being missed because of insufficient delay or it might
miss the pulse sent to change its state which results in it doing nothing.
Then we had to work to keep the data shared between threads to be as minimal as
possible. The section of code to access the shared data must be as small as possible.
Otherwise might become a performance bottleneck.
Serial communication settings must be done carefully. For instance, incorrect baud rate
might result in the driver application seeing lots of errors in communication and hence
lower accuracy. Plus, incorrect settings might lead to end of data reception which is
Finally, the application has to clean up the resources like threads, sockets, file descriptors
allocated to it by the system even if it is forced to terminate because of events external to
the application. We have to handle signals like SIGINT, SIGKILL, SIGTERM to enforce this.
4.2.1. GPIO troubleshooting
In order to work with LCD, we first have to be able to programmatically turn the GPIO pins
on and off. So we executed a set of commands to test it. We tested it with LED connected to
the GPIO pin. When it is high, it glows.
"75" > /sys/class/gpio/export
"out" > /sys/class/gpio/gpio75/direction
1 > /sys/class/gpio/gpio75/value
0 > /sys/class/gpio/gpio75/value
GPIO pins can be dealt with just like any other File. But it has to be registered and the
direction must be set before setting the value of the pin. All this has to be done as root.
Otherwise the operation fails.
We wrote a small shell script which must be run at the start of the system which must be
run to register all GPIO pins.
CODE: exportpins.sh
pins=("227" "226" "362" "71" "233" "76" "64" "65" "66" "361" "229" "230" "69"
"73" "80" "32" "33" "72" "77" "78" "79" "67" "231" "360" "68" "70" "74" "75")
for i in "${pins[@]}"; do
echo $i > /sys/class/gpio/export
echo 'All pins initialized'
4.2.2. LCD troubleshooting
Since LCD hardware is slower compared to the board computer, it is important to add
some delays in order to make the program work properly. That is what lcd_busycheck()
function does in disp.c file. The LCD hardware is positive edge triggered and there must
also be simulate a little pulse.
static void lcd_trigger_device(LCD *disp) {
lcd_set_enable(disp, LOW);
nanosleep(&trigger_delay, NULL);
lcd_set_enable(disp, HIGH);
nanosleep(&trigger_delay, NULL);
lcd_set_enable(disp, LOW);
static void lcd_busycheck(LCD *disp) {
nanosleep(&busycheck_delay, NULL);
Once it was done, we also needed to add some additional delay after issuing clear screen
command to the display. So we added a two microsecond delay. We arrived at the figure
after experimenting with it.
4.2.3. Driver troubleshooting Splitting the work among different cores
Creating a new thread doesn’t guarantee that it is running on a core which is different from
that of the current thread. It depends on OS scheduler. But it is necessary for the
application to do that in order to achieve high performance. OS Scheduler is not
dependable. Hence we had to force it.
int attach_thread_to_core(int core_id) {
int max_cores = sysconf(_SC_NPROCESSORS_ONLN);
if (core_id < 0 || core_id >= max_cores)
return EINVAL;
cpu_set_t cpuset;
CPU_SET(core_id, &cpuset);
pthread_t thread = pthread_self();
return pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset);
This piece of code explicitly requests the scheduler to bind the current thread (the thread
which called it) to bind to the specified core. This is done by the function
pthread_setaffinity_np(). This solves our problem at the cost of portability of the code to a
platform other than Linux. It isn’t important anyways. Long critical section in Display module
As mentioned in section 4.2.2, LCD hardware is slow and when the thread running Display
component holds a mutex for a long time, it affects the performance of other components,
mainly Receive and process sub-component which is vital to process the data received from
the sampler. LCD display has delays in terms of microseconds and milliseconds. Holding
mutex for that long is unacceptable from the viewpoint of performance.
So we copied the values we needed to display to other variables in the critical section,
release the mutex and then work on displaying thereby allowing other sub-components to
proceed executing their critical sections. The piece of code shown above solved the
problem. Handling blocking accept() function
The driver program has to be terminated properly. Otherwise, there might be sockets used
by the communication sub-component which are not closed. They cause problem when the
program is run in the future. The problem is that the accept() function in Sockets API is
blocking. So on interrupt, this thread doesn’t finish and hence doesn’t let the application
clean up resources and terminate.
The sockets have to be manually closed by issuing SIGKILL (it can be done by kill command
in Linux) to stopped processes.
How to solve this issue? The listening socket in the component changes when there is an
incoming connection request. So we have to monitor the descriptor corresponding to the
listening socket for change. Here is a piece of code that does that.
int poll_status = poll(&poll_listenfd, 1, 2000);
if (poll_status == -1) { perror("ERROR"); continue; }
if (poll_status == 0) continue;
This ensures that accept() is not reached unless there is a new incoming connection
request. poll() is a Linux system call for monitoring the file descriptor. Another option was
the use the libevent library for faster performance. But for our purposes, it is an overkill
and makes the application bigger and adds a dependency.
53 Serial communication settings
Earlier we mentioned that communication through serial port is just like File I/O because of
“everything is a file” philosophy. But how does the system know the settings like baud rate?
The solution is the termios structure.
int set_tty_attributes(int fd) {
struct termios options;
tcgetattr(fd, &options);
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
options.c_iflag |= IGNBRK;
options.c_iflag &= ~(BRKINT|IMAXBEL|IXON);
options.c_oflag &= ~(OPOST|ONLCR);
options.c_lflag &= ~(ICANON|IEXTEN|ECHO|ECHOE);
options.c_lflag &= ~(ECHOK|ECHOCTL|ECHOKE|NOFLSH);
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 10;
return tcsetattr(fd,TCSANOW,&options);
This piece of code solves the problem. In this case baud rate is set to 115200. In case there
is any problem in serial communication this is the place to look. Some of it is standard
UART settings. Detecting valid zero crossings
Detecting zero crossing is easy because we have access to the current value and the
previous value. But there are transmission errors and we might miss some zero crossings.
So we have to detect if there are any zero crossings which are missing because they affect
the accuracy of frequency, power factor and energy computation a lot.
inline bool is_valid_zero_crossing(struct timespec prev, struct timespec cur) {
return time_diff(prev,cur) >= ZCROSS_DELTA_MIN &&
time_diff(prev,cur) <= ZCROSS_DELTA_MAX;
This piece of code solves the problem. Since we have the rough idea of frequency, we can
compute the time between zero crossings roughly assuming some error margin in
value might lead to many valid zero crossings to be flagged invalid and hence it must be set
carefully. It is set experimentally starting with very low ZCROSS_DELTA_MIN and very high
ZCROSS_DELTA_MAX and narrowing down the range of values for better accuracy. But it is
not the only parameter affecting accuracy of computations.
4.3. Final Circuit Diagram
Fig. 4.3
5. Results
The ​Final circuit Diagram is tested and the results obtained are tabulated. The output from
each and every section of the circuit is taken and analysed to check if the required
conditions on the accuracy is met to put the meter on use. The results below are shown for
different loading conditions so the values will not match.
5.1. Sensor Output
This section gives the results from the sensors, these results are captured by a DSO (Digital
Storage Oscilloscope) and the results are verified with the expected results.
Voltage sensor:
Fig. 5.1.1
The voltage applied is 95V (single phase 50Hz)
Voltage sensor conversion constant is 398 (as measured in ​section​)
Voltage (rms)
Expected Result
Obtained Result
95/398 = 0.2387
340/1000/20.5 = 0.2404
Current sensor:
Fig. 5.1.2
Current drawn by the load is 10.1A
Current sensor constant is 46 (measured in ​section​)
Voltage (rms)
Expected Result
Obtained result
10.1/46 = 0.2196
320/1000/20.5 = 0.2263
5.2. Level shifter with filter output
This circuit gives a rise to the sensor voltage with the filtering action, the filter will not allow
any frequency above 72Hz, so only the fundamental frequency of the voltage/current is
obtained which makes the computations noise free and easy algorithm to make
Voltage signal (yellow)l:
Fig. 5.2.1
Current signal (green):
FIg. 5.2.2
We can see from the above figures that the V​avg​ = 1.20V, and our expected is 1.25V but it is
close enough for the algorithm to detect the zero crossings.
5.3. LCD Display output
This displays the values of the parameters computed using the voltage and current data
locally in the LCD display.
Parameters that are displayed:
1. Energy in KWh
2. Power in KW
3. Voltage in Volt (V)
4. Current in Ampere (A)
5. Power factor
6. Frequency (Hz)
Fig. 5.3
5.4. Remote Device output
The results which are displayed locally can be communicated to the remote device with
TCP/IP protocol. Here we have connected the Meter to the NITK-NET through its wifi
module and the remote receiver is also connected to the NITK-NET, the data is received by
the remote receiver after a command called ‘get_all(1)’ is sent.
Fig. 5.4
5.5. Conclusion
The results obtained has a satisfactory outcome even though the error is not within the
standard limits but it is still a good enough outcome in the laboratory level. The ​Section 6​ of
this report gives a brief idea about the future improvements that has to be included so as
to get the errors under the limits and meet the standard.
This design used for this Smart meter design is good enough for the residential energy
measurement because there are nothing about the harmonics involved in this circuit is
mentioned and the range of its operation is also limited to 250V which is a single phase.
6. Future improvements
This will help the project to get its next step of improvement both in Hardware and
software to meet the desired standards and used in real time metering of the residential or
any single phase energy reading with automated billing for the consumed energy and also
the alert in the remote device about the consumption.
6.1. Hardware
1. The grade of the components used must be increased to get a better reliability of
the circuit and it also makes the circuit less sensitive to external environment.The
noise levels of the components majorly 741 IC is reduced.
2. The filter circuit must be replaced with the Narrow bandpass filter (40Hz-60Hz) so
that the lower frequency noise will be eliminated, it is recommended to use the
Active filter so that the signal strength can be increased or maintained at the same
3. The quality of the printed circuit board must be good which reduces the noise levels
of the circuit.
4. The hard wiring must be firmly soldered to avoid any resistance in the nodes.
5. The sensors could be added with more protection just to make sure that the
measuring quantities are within the limits if not stop measuring and give a alert to
say that quantity is above the rating.
6. The cable length of communication between MSP430 and Pine64 must be reduced
to increase the transmission accuracy at higher bitrates.
7. The reference generator which is a 7805 IC with a potential divider circuit and
voltage output from this entirely depends on the battery potential and the loading
on the circuit, this could be replaced with a DC-DC converter based on frequency
control with automatically controls the output voltage at a constant level (1.25V).
And this stable reference is much more necessary.
6.2. Software
1. Improvements in recording zero crossing detection timestamp. It has to be done
accurately using techniques like interpolation.
2. Improvements in error handling using signal processing techniques (adaptive filters
etc). Guessing the values of missing samples using interpolation techniques help to
improve the accuracy of various quantities computed.
3. More commands can be supported from the device.
4. Creation of a central database to gather data from various smart meter devices for
further analysis and better decision making.
5. Adding security features to the device to avoid tampering.
6. A graphical frontend on the server end for people in the company. Dashboard and
other visualizations help them to get a picture of the system easily.
7. A frontend for users - either a website or a smartphone application which allows
them to view the usage the power consumption at the moment, helps them to pay
bills online, submit query to the company and so on.
8. A rich data repository for data analysts to slice and dice data based on the
consumption and optimize the power supply and quality based on it.
7. Application(s)
The Smart Energy Meters are the revolution in the field of Automation, this gets everything
in the palm, with a user friendly interface to manage the energy consumption remotely.
7.1. Automatic Billing
Fig. 7.1
The data that is measured by the smart meter is sent to the remote server through a
gateway where it takes the account of the energy readings and puts it to the database then
this information is used for the billing on monthly basis.
7.2. Alerting system
The Smart Meter can alert the user about the Energy usage, the maximum power
consumption in a day or the tripping of the circuit breaker because of some fault in the
load side and these can be easily communicated with the remote device and give an alert
on the current situation.
8. References
1. Ramakanth A. Gayakwad “Op-Amps and Linear Integrated Circuits - 4​th​ Edition”
2. “​www.circuitbasics.com​”- About Universal Asynchronous Receiver transmitter
3. “​www.ti.com​”- Documentations related to MSP430F5529LP Programming
4. Pthread tutorial - ​https://computing.llnl.gov/tutorials/pthreads
5. Pthread documentation -
6. C sockets documentation https://www.gnu.org/software/libc/manual/html_node/Sockets.html
7. poll() documentation - ​http://man7.org/linux/man-pages/man2/poll.2.html
8. “​www.arduino.cc​” - Documentations related to Arduino Uno Programming