0% found this document useful (0 votes)
123 views61 pages

Ncube Brian T Final Year Project

hmi design

Uploaded by

Brian Ncube
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
123 views61 pages

Ncube Brian T Final Year Project

hmi design

Uploaded by

Brian Ncube
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 61

UNIVERSITY OF ZIMBABWE

FACULTY OF ENGINEERING
DEPARTMENT OF ELECTRICAL ENGINEERING

DESIGN OF A HUMAN MACHINE INTERFACE


FOR A SMART GRID TIED INVERTER

LEVEL 4 PROJECT
Submitted in partial fulfilment of
BSc (HONOURS) DEGREE IN ELECTRICAL ENGINEERING
By
Brian Takudzwa Ncube (R137000W)
[email protected]
Supervised by
Dr. T Marisa
DECLARATION

In presenting this project report, I agree that permission for the copying of this project report
for scholarly purposes may be granted by the head of the department or by his or her
representatives. Copying or publication of this report for financial gain shall not be allowed
without my written permission.

Department of Electrical Engineering


The University of Zimbabwe
P.O Box MP 167
Mount Pleasant
Harare
Zimbabwe

Date…………………………………………..

Signature……………………………….....

i
ABSTRACT
In this design of the HMI. The human machine interface is defined and ISO standards relating
to HMI design are discussed. The STM32 Cortex-M3 microcontroller is used as the ‘brains’ of
the system. The designer reviews the microcontroller’s peripherals specific to the design. The
design process is laid out and C code is given at the end to show the implementation of the
design.

ii
ACKNOWLEDGEMENTS
I would like to recognise and show gratitude to my supervisor Dr T Marisa for his guidance,
support and patience throughout my project.
Great appreciation goes to my parents Mr and Mrs Ncube and my brothers Larrack, Tendai and
Lamont Jr. for their support, love and encouragement during the completion of this project.
Above all, I thank the Almighty GOD for the grace that He has given me. It is my belief that
this project has helped me grow professionally and in the pursuance of my studies.

iii
Contents
DECLARATION ........................................................................................................................ i

ABSTRACT ...............................................................................................................................ii

ACKNOWLEDGEMENTS ..................................................................................................... iii

Contents ..................................................................................................................................... 1

List of figures ............................................................................................................................. 3

Chapter 1 .................................................................................................................................... 4

1.1 Introduction ...................................................................................................................... 4

1.2 Aim .................................................................................................................................. 4

1.3 Objectives ........................................................................................................................ 4

1.4 Justification ...................................................................................................................... 5

1.5 Concept ............................................................................................................................ 5

Chapter 2 .................................................................................................................................... 6

LITERATURE REVIEW .......................................................................................................... 6

2.0 Human Machine Interface (HMI) ............................................................................... 6

2.0.1 ISO 9421 .............................................................................................................. 6

2.1 STM32 Microcontroller .............................................................................................. 6

2.1.1 Controller Area Network (CAN) .............................................................................. 7

2.3 Analogue-to-Digital Converter (ADC) .......................................................................... 10

2.2.1 ADC Modes ............................................................................................................ 10

2.2.2 ADC with DMA ...................................................................................................... 11

2.4 Timers and Pulse Width Modulation ............................................................................. 11

2.4.1 Pulse Width Modulation (PWM) ............................................................................ 11

2.4.2 Sinusoidal PWM ..................................................................................................... 12

Chapter 3 .................................................................................................................................. 13

DESIGN & IMPLEMENTATION .......................................................................................... 13

1
3.0 Graphical User Interface (GUI)................................................................................. 13

3.0.1 GUI Layout ............................................................................................................. 14

3.0.2 Calibrating the Touch Panel.................................................................................... 17

3.1 Sensor-HMI Network..................................................................................................... 17

3.2 Inverter-HMI Network ................................................................................................... 18

Chapter 4 .................................................................................................................................. 19

4.1 Conclusion ..................................................................................................................... 19

4.2 Recommendations .......................................................................................................... 19

4.3 Further Work .................................................................................................................. 19

4.3.1 Expansion of CAN network .................................................................................... 19

4.3.2 Battery charger ........................................................................................................ 19

4.3.3 Inverter Control ....................................................................................................... 20

REFERENCES ........................................................................................................................ 21

APPENDIX .............................................................................................................................. 23

I – HMI home screen and subsequent screens ..................................................................... 23

II – Touch panel calibration ................................................................................................. 31

III– Touch Sense .................................................................................................................. 42

IV – HMI CAN configuration.............................................................................................. 47

V – Inverter ADC................................................................................................................. 52

VI – Timer 1 PWM .............................................................................................................. 56

2
List of figures
Figure 1: Design concept ........................................................................................................... 5
Figure 2: Cortex-M3 peripherals ............................................................................................... 7
Figure 3: STM32 CAN block diagram ...................................................................................... 7
Figure 4: Controller Area Network structure ............................................................................. 8
Figure 5: Structure of the data frame ......................................................................................... 8
Figure 6: Successive approximation ADC ............................................................................... 10
Figure 7: Analogue to Digital Converter ................................................................................. 10
Figure 8: DMA data transfer .................................................................................................... 11
Figure 9: Three PWM signals for different CCRx values ....................................................... 12
Figure 10: Flow chart for GUI ................................................................................................. 13
Figure 11: Home Screen .......................................................................................................... 14
Figure 12: Inverter selection screen (left) and Screen showing Inverter_1 parameters (right)15
Figure 13: Graph displaying generation statistics .................................................................... 15
Figure 14: Grid ......................................................................................................................... 16
Figure 15: Power Usage ........................................................................................................... 16
Figure 16: Battery .................................................................................................................... 17
Figure 17: Inverter-HMI CAN connection .............................................................................. 18

3
Chapter 1
1.1 Introduction
Technology has advanced quickly in the past decades. Factories are becoming more automated,
households have more appliances that run on electricity and more personal electronic gadgets
are available to the consumers. Due to this increase the demand for electricity has also
drastically increased. Zimbabwe has also been part of this technological revolution and the
country faces a problem of not being able to meet the public energy demand (Longman, 2015).

A large portion of the country’s energy demand is being met by fossil fuel based energy
generation as well as imports from neighbouring countries. Burning of fossil fuels to produce
energy has adverse effects to the environment, is expensive to maintain and the fossil fuel
resources are dwindling (uSwitch, 2016). Importing energy is also costly for the country and
contributing to the high cost of energy for the consumers. The country is in need of more energy
from renewable sources. Renewable energy sources are infinite and do not emit substances that
are detrimental to the environment. The most abundant renewable energy source is the sun and
solar photovoltaic (PV) cells can be used to convert the energy of the sun into cheap clean
electricity.
Solar PV cells produce direct current (DC), but many household appliances require alternating
current (AC) to operate, therefore an inverter is required to convert DC into usable AC. An
even more advanced form of inverter is the grid tied inverter (GTI). This enables excess energy
produced from the solar panels to be fed into the national grid.

1.2 Aim
 To design a Human Machine Interface (HMI) to service multiple grid tie inverters

1.3 Objectives
 Create an inverter-HMI communication link
 Set up an inverter-sensor network
 Display current operating conditions for individual inverter
 Show inverter output over time graphically
 Display grid parameters

4
 Show battery voltage

1.4 Justification
Solar panels and hence inverters are generally mounted on rooftops of households or in an open
field in the case of a solar farm. It is then necessary to enable the user to monitor the
performance of individual solar panels. The HMI helps the user to do this from a centralised
location and not having to inspect each individual inverter.

1.5 Concept
The HMI and inverters will be implemented in a scheme as shown below:
BATTERY
CHARGER

INVERTER #1 SENSORS

CAN BUS
HMI

INVERTER #n SENSORS

BATTERY
CHARGER

Figure 1: Design concept

Sensors will be used to measure grid parameters which will allow the output of the GTI to
match these parameters so that it can supply power to the grid. Other sensors will be used to
measure the parameters of the P.V. array such as its output voltage and the temperature of the
panels. Control Area Network (CAN) will be used for communication of the sensors with the
Human Machine Interface (HMI). Operating conditions and grid conditions among other
statistics will be displayed on the HMI.

5
Chapter 2

LITERATURE REVIEW
2.0 Human Machine Interface (HMI)
An HMI is a software application that presents information to a user or operator on the state of
processes in a device and also accepts parameters to execute the operator’s control instructions
(International Engineering Consortium, 2000). Like any other product, HMIs have certain
standards they have to meet. One such standard is the ISO9421.

2.0.1 ISO 9421


The standard outlines three quality aspects to be factored in in the design of Human Machine
Interfaces (ISO, 2010):
1. Effectiveness
 The product should do what the users require.
 Does it do the right thing?
2. Efficiency
 Level of user friendliness.
 Improvement of productivity/effort ratio.
 Tasks carried out the right way.
3. Satisfaction
 Do users express satisfaction with the product?
 Whether or not the new product reduces stress.
 End users should have a more satisfying job experience.

2.1 STM32 Microcontroller


The HMI and inverter use the STM32 CortexM3 microcontroller as the central processing unit.
The STM32 is a family of 32-bit Advanced RISC Machine (ARM) microcontrollers from
STMicroelectronics. The internals of each microcontroller consist of the processor core, static
RAM and flash memories, a debugging interface and various peripherals depending on the line
of microcontroller (STMicroelectronics, 2016).

6
Figure 2: Cortex-M3 peripherals

2.1.1 Controller Area Network (CAN)


One of the peripherals as shown in Figure 2 is the controller area network (CAN). This is a
serial communication protocol whereby all nodes are connected to a single BUS. It allows
microcontrollers and devices (sensors, actuators, etc.) to communicate with each other. The
STM32 CAN block diagram is shown below for the connectivity line series:

Figure 3: STM32 CAN block diagram

2.1.1.1 Features of CAN


 Message priority assignment and guaranteed maximum latency times
 Error detection and signalling
 Automatic retransmission of corrupted messages
 Multi-master access to the bus

7
 Automatic switching off of defective nodes
 Excellent noise immunity

2.1.1.2 How CAN works


The CAN bus is made up of a twisted pair of cables. Each node connects from this twisted pair.

Figure 4: Controller Area Network structure

A CAN message is sent without a specific address instead messages use unique identifiers. The
identifier is also used to define the priority of the message in the event multiple nodes require
to transmit in the bus. Before a node can transmit a message, the messages pass through the
CAN controller which ‘constructs’ the transmission message. When the transmitter receives
bus allocation all the other nodes turn to receivers. Each node then reads the identifier to
determine whether it need the message or not by filtering. If it is required, it is sent to the
receiver FIFO where it is read otherwise it is discarded (Boys, 2009).

2.1.1.3 Message Frame Formats


The CAN protocol has multiple message frames, depending on their content and function.
 Data Frame – contains data information from the source to possible receivers

Figure 5: Structure of the data frame

 Remote Frame – used to request transmission of a message with a given identifier


from a remote node. It has the same format as a data frame but with the following
characteristics:
- the identifier field indicates the identifier of the requested message
- data field is always empty

8
- DLC field indicates data length of the requested message

 Error Frame – this is not a real frame. It is a result of error signalling and recovery.
 Overload Frame – a special version of an error frame. The error and overload frames
are of fixed form (Natale, 2008)
2.1.1.4 Error management
The CAN protocol can automatically detect and signal error and perform self-diagnostics. This
makes it an extremely robust protocol. Error management consists of error detection, error
signalling and fault confinement (Dandahwa, 2016).
Five different error checking detection mechanisms are implemented, three at message level
and two at bit level. Messages that fail any of the mechanisms will not be accepted and will
result in transmission of an error frame. The message level mechanisms are Cyclic Redundancy
Check (CRC), Frame check and ACK errors. For CRC, check bits are sent at the end of
transmission, these are retested at the receiver, a disagreement of these bits signifies a CRC
check. Frame check looks at the structure of the bit fields in the message and compares them
with an expected fixed format. Received frames are acknowledged by recipients by positive
acknowledgement, if the transmitter does not receive acknowledgement transmission errors
may have been detected by the recipients. Bit level mechanisms are monitoring and bit stuffing.
Monitoring is based on the ability of the transmitter to monitor each transmitted bit. Bit stuffing
ensures that a stream of recessive bits is not mistaken for an error frame or the seven-bit inter-
frame space that signifies the end of a message by inserting a complementary bit whenever five
consecutive equal bits are sent (BOSCH, 1991).
Errors a signalled by the transmission of the error flag. This prevent reception of erroneous
messages. The CAN protocol has a mechanism that differentiates short disturbances and
permanent failures so as to achieve fault confinement. A node operating with defects can be
categorised in any of three states, these are error active, error passive and buss off (Natale,
2008).
 Error active – node takes part in bus transmission and signals active error flags
 Error passive – error signalling limited to passive error flags but can still take part in
bus transmission
 Bus off – node is likely corrupted and cannot have any influence on the bus

9
2.3 Analogue-to-Digital Converter (ADC)
STM32 microcontroller are fitted with a 12-bit successive approximation ADC. Successive
approximation ADC operates as follows. To begin conversion, hardware control captures a
sample of the input voltage (Vain). The captured input (Vsamp) is captured and the controller
generates a sequence of digital approximations D(vest) and checks each by converting the
approximation to an analogue signal which is then compared to the sampled input. When the
best approximation is found, the value is loaded into the ADC data register (ADCDR) (Brown,

2012).
Figure 6: Successive approximation ADC

2.2.1 ADC Modes


STM32 ADC supports multiple analogue inputs as shown below:

Figure 7: Analogue to Digital Converter

The ADC can be configured to operate either in single or continuous conversion. For single
conversion, once an internal or external trigger occurs it converts the channel once and stores

10
the value in the ADCDR. For continuous conversion, a new conversion is started as soon as
the conversion is completed. Scan conversion means the ADC converts a group of channels at
once and stores the values in the ADCDR, scan conversion can be single or continuous
(STMicroelectronics, 2015).

2.2.2 ADC with DMA


ADC has a single register. In continuous conversion mode, this register is continuously written
to when a single conversion is completed. Therefore, to ensure that data is not lost Direct
Memory Access (DMA) is used. DMA relieves the processor the task of transferring memory
blocks between memory and peripherals (Brown, 2012). DMA also preserves ADC converted
values from being over written in the ADCDR.

Figure 8: DMA data transfer

2.4 Timers and Pulse Width Modulation


STM32 microcontrollers use timers to generate signals of different frequencies and pulse width
modulated signals. Each timer is equipped with multiple channels to enable different signals to
be outputted using a single timer (STMicroelectronics, 2015).

2.4.1 Pulse Width Modulation (PWM)


For PWM the timer is set to run at a certain frequency by setting a prescaler value, the prescaler
value divides the reference clock to a different value for the timer. For example, in a
microcontroller running at 24MHz a prescaler of 1 (two values 0 and 1) means the timer is
running at 24/2 = 12MHz. The auto-reload (ARR) value sets the frequency of the PWM signal.
Compare and Capture (CCRx) sets the duty cycle, where x represents the output channel of the
timer (Harrison, 2016). An example of how PWM works for a 3-channel output is shown in
Figure 9.

11
Figure 9: Three PWM signals for different CCRx values

2.4.2 Sinusoidal PWM


Implementation of sinusoidal PWM (SPWM) is identical to PWM. The CCR values are derived
from a sine table which represents digital values of the sine wave. When an interrupt occurs
the CCR value is updated to the next value in the sine table by the interrupt service routine
(Harrison, 2016).

12
Chapter 3

DESIGN & IMPLEMENTATION


3.0 Graphical User Interface (GUI)
The GUI was designed using Micrium’s µC/GUI. It features multiple graphical libraries,
string/value output routines and touchscreen support among other things. The flow chart for
the GUI is shown in Figure 10 below.

INVERTER # GRAPH

SOLAR

HOME
GRID BATTERY
SCREEN

POWER
USAGE

Figure 10: Flow chart for GUI

13
3.0.1 GUI Layout
3.0.1.1 Home screen

Figure 11: Home Screen

The Home Screen is setup as shown in Figure 11, the user can select either of the four on screen
buttons to view the specifics of operation of the system. The buttons are: ‘Solar’, ‘Power
Usage’, ‘Grid’ and ‘Battery’.
3.0.1.2 Solar
Selecting the button ‘Solar’ opens a window for selection of individual inverters. On this screen
the total power being produced by the inverters in the system is shown. The user can select an
inverter to view its individual operating conditions. A further option ‘History’ is available to
enable the user to view the output of the inverter over a period of twelve hours (Figure 12).

14
Figure 12: Inverter selection screen (left) and Screen showing Inverter_1 parameters (right)

Figure 13: Graph displaying generation statistics

15
3.0.1.3 Grid
‘Grid’ shows power drawn from the grid and power being injected to the grid.

Figure 14: Grid

3.0.1.4 Power Usage


The ‘Power Usage’ button shows the current household demand and how much of it is being
met by the inverters and by the grid.

Figure 15: Power Usage

16
3.0.1.5 Battery
The ‘Battery’ button is applicable to systems incorporating a battery bank. The actual value of
the voltage as well as the percentage of the full charge is shown.

Figure 16: Battery

3.0.2 Calibrating the Touch Panel


The touch panel is mapped using x and y coordinates. These are used to determine the position
of a touch event when the user touches the panel. To calibrate the screen the controller requires
at least 3 touch events to calibrate the screen. This is implemented using the
TouchPanel_Calibrate() (see Appendix II) method. This method draws three crosses on the
screen with one cross appearing when the user touches the preceding one. Each cross is drawn
at a certain position predetermined in the software. Upon touch of the cross on the screen the
controller corrects any deviation of the touch position from the predetermined positon and then
updates the calibration matrix. Once the process is done three times the processor can
accurately detect a touch event on any of the coordinates on the touch panel.

3.1 Sensor-HMI Network


The sensors are not connected directly to the HMI but via the microcontroller of the inverter.
This means that the analogue signals of the sensors are processed by the inverter and the
processed information sent to the HMI. The inverter is therefore connected to five sensors for
input current and voltage, output current and voltage and temperature. These are continuously
converted to digital format using the STM32’s scan mode. The processed signals are used for

17
the control of the inverter’s operation for example alteration of the PWM duty cycle to control
the output of the boost converter. These also are used to calculation input and output powers
of the inverter for display on the HMI.
To achieve near real time data on the operating conditions of the inverter. The ADC is run in
continuous scan conversion mode. The converted values are stored in an array which is
processed by the inverter to implement control measures and the same array is sent to the HMI
via CAN for processing and display.

3.2 Inverter-HMI Network


The HMI is connected to the inverter via CAN, this establishes the inverter-HMI network and
completes the sensor-HMI network. In the configuration of the CAN the HMI is set as the
master and the inverter the slave.

Figure 17: Inverter-HMI CAN connection

18
Chapter 4
4.1 Conclusion
The HMI for a grid tie inverter with minimum requirements has been realised. The design can
be implemented as a low-cost HMI solution for monitoring not just grid tie inverters but also
off-grid inverters in domestic and industrial settings.
The student has been able to gain practical knowledge in design and troubleshooting of the
product. Embedded system concepts have been reinforced after working with STM32
microcontroller. The student is more proficient in programming STM32 microcontrollers in C
and also being able to debug code. The inverter part of the project enabled the student to have
a deeper appreciation of power electronics technologies and design techniques. It has been
realised that calculation and simulation results do not directly translate into a working physical
product but repetitive testing may result in design parameters different from those acquired
during simulation.

4.2 Recommendations
 Engagement with authorities to come up with structures to promote investment in grid
tie technology domestically and industrially
 Upgrade of the current utility grid by the authorities to be able to handle erratic power
supplied by solar system
 Setting up of payment methods for people and organisations supplying power to the
utility grid

4.3 Further Work


4.3.1 Expansion of CAN network
The design focused on a only three inverters and particularly tested with one inverter however
in can be expanded to up to 512 inverters per HMI

4.3.2 Battery charger


Without the inclusion of the battery charger in the system battery voltage statistics cannot be
displayed at the time of submission of the project.

19
4.3.3 Inverter Control
To enable the user not to just view inverter parameters but also enable them to switch the
inverters ON and OFF.

20
REFERENCES
[1] BOSCH, 1991. CAN Specification, Stuttgart: Robert Bosch GmbH.
[2] Boys, R., 2009. CAN Primer: Creating your own Network, San Jose: ARM, Ltd.
[3] Brown, G., 2012. Discovering the STM32 Microcontroller, s.l.: s.n.
[4] Charaborty, S., 2013. Design of a Transformer-less Grid-Tie Photovoltaic Inverter Using
Dual-stage Buck and Boost Converters, Bangladesh: Independent University.
[5] Cullen, R. A., 2015. www.blueskyenergyinc.com. [Online]
[Accessed 14 October 2016].
[6] Dandahwa, N., 2016. The Controller Area Network, Harare: University of Zimbabwe .
[7] Harrison, P., 2016. PWM basics on the STM32 general purpose timers. [Online]
Available at: http://www.micromouseonline.com/2016/02/06/pwm-basics-on-the-stm32-
general-purpose-timers/
[Accessed 8 Feruary 2017].
[8] International Engineering Consortium, 2000. The Human-Machine Interface. [Online]
Available at: http://www.iec.org
[Accessed 6 February 2017].
[9] ISO, 2010. Ergonomics of human–system-Part 210: Human-centred design for interactive
systems, Geneva: International Organisation for Standardization.
[10]Longman, N., 2015. Zimbabwe's energy crisis. [Online]
Available at: http://www.africanbusinessreview.co.za/technology/2102/Zimbabwe%27s-
energy-crisis
[Accessed 12 May 2017].
[11] Natale, M. D., 2008. Understanding and using the Controller Area, s.l.: s.n.
Shahryiar, S., 2015. STM32 Analogue-to-Digital Converter (ADC). [Online]
Available at: http://embedded-lab.com/blog/stm32-adc-2/
[Accessed 25 January 2017].
[12] STMicroelectronics, 2015. Reference Manual (RM0008) : STM32F101xx,
STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx advanced ARM®-based
32-bit MCUs, s.l.: ST.
[13] STMicroelectronics, 2016. STM32 32-bit ARM Cortex MCUs. [Online]
Available at: http://www.st.com/en/microcontrollers/stm32-32-bit-arm-cortex-mcus
[Accessed 12 December 2016].

21
[14] uSwitch, 2016. Renewable energy facts. [Online]
Available at: https://www.uswitch.com/solar-panels/guides/renewable-energy-facts/#step3
[Accessed 9 October 2016].

22
APPENDIX
I – HMI home screen and subsequent screens
The code below shows methods to create the home screen and it objects and also methods to
initialise subsequent screens. When a new screen is selected objects on the current screen are
cleared before the new screen can be drawn, for example ClearHome () clears the buttons on
the home screen.
#include "BUTTON.h"
#include "EDIT.h"

//Defines
BUTTON_Handle hButton, hB1, hB2, hB3, hB4, hB5, hB6, hB7,hB8, hB9, hB0, hB10;
EDIT_Handle hE1, hE2, hE3, hE4, hE5, hE6, hE7, hE8, hE9;
/*******************************************************************************
* Function Name : Home Screen
* Description : Screen shown when HMI is turned on
*******************************************************************************/
void Home (void) {

//BUTTON_Handle hButton, hB1, hB2, hB3;


//EDIT_Handle hE1;

hE1 = EDIT_CreateEx(35, 15, 253, 20,0, WM_CF_SHOW,0, GUI_ID_EDIT0,100);


EDIT_SetTextAlign(hE1, GUI_TA_HCENTER | GUI_TA_TOP);
EDIT_SetText(hE1, "CLICK A BUTTON TO VIEW");
EDIT_SetFont(hE1, &GUI_Font8x15B_ASCII);

hButton = BUTTON_CreateEx(21, 51, 90, 50, 0, WM_CF_SHOW, 0, GUI_ID_BUTTON0);


/* Set text and font */
BUTTON_SetText(hButton, "Solar");
BUTTON_SetFont(hButton, &GUI_Font8x15B_ASCII);

hB1 = BUTTON_CreateEx(205, 51, 90, 50, 0, WM_CF_SHOW, 0, GUI_ID_BUTTON1);


/* Set text and font */
BUTTON_SetText(hB1, "PowerUsage");
BUTTON_SetFont(hB1, &GUI_Font8x15B_ASCII);

hB2 = BUTTON_CreateEx(21, 135, 90, 50, 0, WM_CF_SHOW, 0, GUI_ID_BUTTON2);


/* Set text and font */
BUTTON_SetText(hB2, "Grid");
BUTTON_SetFont(hB2, &GUI_Font8x15B_ASCII);

23
hB3 = BUTTON_CreateEx(205, 135, 90, 50, 0, WM_CF_SHOW, 0, GUI_ID_BUTTON3);
/* Set text and font */
BUTTON_SetText(hB3, "Battery");
BUTTON_SetFont(hB3, &GUI_Font8x15B_ASCII);

GUI_Exec();

while(1){
DelayMil(50);
SenseHome();
}
}

/*******************************************************************************
* Function Name : Solar
*
* Description : CLICK button "Solar" to display
*******************************************************************************/
void Solar (void){

// BUTTON_Handle hB4, hB5, hB6, hB7;


// EDIT_Handle hE2;

hE2 = EDIT_CreateEx(73, 21, 155, 20,0, WM_CF_SHOW,0,


GUI_ID_EDIT1,100);
EDIT_SetTextAlign(hE2, GUI_TA_HCENTER | GUI_TA_TOP);
EDIT_SetText(hE2, "Total Power in = ");
EDIT_SetFont(hE2, &GUI_Font8x15B_ASCII);

hB4 = BUTTON_CreateEx(82, 66, 135, 20, 0, WM_CF_SHOW, 0, GUI_ID_BUTTON4);


/* Set text and font */
BUTTON_SetText(hB4, "Inverter_1");
BUTTON_SetFont(hB4, &GUI_Font8x15B_ASCII);

hB5 = BUTTON_CreateEx(82, 103, 135, 20, 0, WM_CF_SHOW, 0,


GUI_ID_BUTTON5);
/* Set text and font */
BUTTON_SetText(hB5, "Inverter_2");
BUTTON_SetFont(hB5, &GUI_Font8x15B_ASCII);

24
hB6 = BUTTON_CreateEx(82, 146, 135, 20, 0, WM_CF_SHOW, 0,
GUI_ID_BUTTON6);
/* Set text and font */
BUTTON_SetText(hB6, "Inverter_3");
BUTTON_SetFont(hB6, &GUI_Font8x15B_ASCII);

hB7 = BUTTON_CreateEx(230, 197, 80, 20, 0, WM_CF_SHOW, 0,


GUI_ID_BUTTON7);
/* Set text and font */
BUTTON_SetText(hB7, "Back");
BUTTON_SetFont(hB7, &GUI_Font8x15B_ASCII);

GUI_Exec();

while(1){
DelayMil(50);
SenseSolar();
}
}

/*******************************************************************************
* Function Name : Grid
*
* Description : CLICK button "Grid" to display
*******************************************************************************/
void Grid (void){

// BUTTON_Handle hB8, hB9;


// EDIT_Handle hE3, hE4;

hE3 = EDIT_CreateEx(50, 56, 190, 30,0, WM_CF_SHOW,0,


GUI_ID_EDIT2,100);
EDIT_SetTextAlign(hE3, GUI_TA_HCENTER | GUI_TA_VCENTER);
EDIT_SetText(hE3, "Grid Power in = ");
EDIT_SetFont(hE3, &GUI_Font8x15B_ASCII);

hE4 = EDIT_CreateEx(50, 128, 190, 30,0, WM_CF_SHOW,0,


GUI_ID_EDIT3,100);
EDIT_SetTextAlign(hE3, GUI_TA_HCENTER | GUI_TA_VCENTER);
EDIT_SetText(hE3, "Grid Power out = ");
EDIT_SetFont(hE3, &GUI_Font8x15B_ASCII);

25
hB8 = BUTTON_CreateEx(33, 195, 80, 20, 0, WM_CF_SHOW, 0,
GUI_ID_BUTTON8);
/* Set text and font */
BUTTON_SetText(hB8, "History");
BUTTON_SetFont(hB8, &GUI_Font8x15B_ASCII);

hB9 = BUTTON_CreateEx(191, 195, 80, 20, 0, WM_CF_SHOW, 0,


GUI_ID_BUTTON9);
/* Set text and font */
BUTTON_SetText(hB9, "Back");
BUTTON_SetFont(hB9, &GUI_Font8x15B_ASCII);

GUI_Exec();

while(1){
DelayMil(50);
SenseGrid();
}

/*******************************************************************************
* Function Name : Battery
*
* Description : CLICK button "Battery" to display
*******************************************************************************/
void Battery (void){

/*BUTTON_Handle hB0;
EDIT_Handle hE5, hE6;*/

hE5 = EDIT_CreateEx(77, 45, 160, 30,0, WM_CF_SHOW,0,


GUI_ID_EDIT4,100);
EDIT_SetTextAlign(hE5, GUI_TA_HCENTER | GUI_TA_VCENTER);
EDIT_SetText(hE5, "Battery voltage = ");
EDIT_SetFont(hE5, &GUI_Font8x15B_ASCII);

hE6 = EDIT_CreateEx(78, 105, 160, 30,0, WM_CF_SHOW,0,


GUI_ID_EDIT5,100);
EDIT_SetTextAlign(hE6, GUI_TA_HCENTER | GUI_TA_VCENTER);
EDIT_SetText(hE6, "100%");
EDIT_SetFont(hE6, &GUI_Font8x15B_ASCII);

26
hB0 = BUTTON_CreateEx(216, 208, 80, 20, 0, WM_CF_SHOW, 0,
GUI_ID_BUTTON0);
/* Set text and font */
BUTTON_SetText(hB0, "Back");
BUTTON_SetFont(hB0, &GUI_Font8x15B_ASCII);

GUI_Exec();

while(1){
DelayMil(50);
SenseBattery();
}

/*******************************************************************************
* Function Name : Battery
*
* Description : CLICK button "Battery" to display
*******************************************************************************/
void PowerUsage (void){

// BUTTON_Handle hB10;
// EDIT_Handle hE7, hE8, hE9;

hE7 = EDIT_CreateEx(60, 30, 190, 30,0, WM_CF_SHOW,0,


GUI_ID_EDIT6,100);
EDIT_SetTextAlign(hE7, GUI_TA_HCENTER | GUI_TA_VCENTER);
EDIT_SetText(hE7, "Demand = ");
EDIT_SetFont(hE7, &GUI_Font8x15B_ASCII);

hE8 = EDIT_CreateEx(60, 90, 190, 30,0, WM_CF_SHOW,0,


GUI_ID_EDIT7,100);
EDIT_SetTextAlign(hE8, GUI_TA_HCENTER | GUI_TA_VCENTER);
EDIT_SetText(hE8, "Grid in ");
EDIT_SetFont(hE8, &GUI_Font8x15B_ASCII);

hE9 = EDIT_CreateEx(60, 150, 190, 30,0, WM_CF_SHOW,0,


GUI_ID_EDIT8,100);
EDIT_SetTextAlign(hE9, GUI_TA_HCENTER | GUI_TA_VCENTER);
EDIT_SetText(hE9, "Solar in");
EDIT_SetFont(hE9, &GUI_Font8x15B_ASCII);

27
hB10 = BUTTON_CreateEx(221, 212, 80, 20, 0, WM_CF_SHOW, 0,
GUI_ID_BUTTON0);
/* Set text and font */
BUTTON_SetText(hB10, "Back");
BUTTON_SetFont(hB10, &GUI_Font8x15B_ASCII);

GUI_Exec();

while(1){
DelayMil(50);
SensePowerUsage();
}

void Inverter_1(void){
CAN1_Val_Tx = 10;
TxMessage.Data[0] = CAN1_Val_Tx>>8;
TxMessage.Data[1] = CAN1_Val_Tx;
CanWriteData1(CAN1,&TxMessage);

hB7 = BUTTON_CreateEx(230, 197, 80, 20, 0, WM_CF_SHOW, 0, GUI_ID_BUTTON7);


/* Set text and font */
BUTTON_SetText(hB7, "Back");
BUTTON_SetFont(hB7, &GUI_Font8x15B_ASCII);

GUI_Exec();

while(1){
if (CAN1_RxRdy==ENABLE){
CAN1_RxRdy=DISABLE;

float Power = CurrentOut * Vout;

CurrentIn=CAN1_Val_Rx;
CurrentIn = (CurrentIn/4096)*3.3;

GUI_SetFont(&GUI_Font8x16);
GUI_SetColor(GUI_BLACK);
GUI_SetTextMode(GUI_TM_TRANS);
GUI_DispStringHCenterAt("Inverter_1 Power(W): ",140,40);
GUI_DispFloatMin(CurrentIn,2);
GUI_DispStringHCenterAt("Voltage(V): " ,140,80);

28
GUI_DispFloatMin(24,2);
GUI_DispStringHCenterAt("Temperature(degrees): ",140,120);
GUI_DispFloatMin(30,2);

}
//DelayMil(50);
SenseInverter_1();
}
}

void Inverter_2(void){
hB7 = BUTTON_CreateEx(230, 197, 80, 20, 0, WM_CF_SHOW, 0, GUI_ID_BUTTON7);
/* Set text and font */
BUTTON_SetText(hB7, "Back");
BUTTON_SetFont(hB7, &GUI_Font8x15B_ASCII);

GUI_Exec();

while(1){
DelayMil(50);
SenseInverter_2();
}
}

void Inverter_3(void){
hB7 = BUTTON_CreateEx(230, 197, 80, 20, 0, WM_CF_SHOW, 0, GUI_ID_BUTTON7);
/* Set text and font */
BUTTON_SetText(hB7, "Back");
BUTTON_SetFont(hB7, &GUI_Font8x15B_ASCII);

GUI_Exec();

while(1){
DelayMil(50);
SenseInverter_3();
}
}

/*******************************************************************************
* Function Name : Methods to delete widgets
* Description : To avoid overlay of screens
*******************************************************************************/
void ClearHome (void) {
BUTTON_Delete(hB1);

29
BUTTON_Delete(hB2);
BUTTON_Delete(hB3);
BUTTON_Delete(hButton);
EDIT_Delete(hE1);

void ClearSolar (void){


BUTTON_Delete(hB4);
BUTTON_Delete(hB5);
BUTTON_Delete(hB6);
BUTTON_Delete(hB7);
EDIT_Delete(hE2);
}

void ClearGrid (void){


BUTTON_Delete(hB8);
BUTTON_Delete(hB9);
EDIT_Delete(hE3);
EDIT_Delete(hE4);
}

void ClearBattery (void){


BUTTON_Delete(hB0);
EDIT_Delete(hE5);
EDIT_Delete(hE6);
}

void ClearPowerUsage (void){


BUTTON_Delete(hB10);
EDIT_Delete(hE7);
EDIT_Delete(hE8);
EDIT_Delete(hE9);
}

void ClearInverter_1(void){
BUTTON_Delete(hB7);
}
void ClearInverter_2(void){
BUTTON_Delete(hB7);
}
void ClearInverter_3(void){
BUTTON_Delete(hB7);
}

30
II – Touch panel calibration
TouchPanel.c from WaveShare used to calibrate the touch panel
/********************************************************************************
*
* File : TouchPanel.c
* Version : V1.0
* By :
*
* (c) Copyright 2005-2011, WaveShare
* http://www.waveshare.net
* All Rights Reserved
*
*********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "TouchPanel.h"
#include "systick.h"
#include "LCD.h"

/* Private variables ---------------------------------------------------------*/


Matrix matrix ;
Coordinate display ;

/*******************************************************************************
* Function Name : ADS7843_SPI_Init
*******************************************************************************/
static void ADS7843_SPI_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
/* DISABLE SPI3 */
SPI_Cmd(SPI3, DISABLE);
/* SPI3 Config -------------------------------------------------------------*/
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;

31
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI3, &SPI_InitStructure);
/* Enable SPI3 */
SPI_Cmd(SPI3, ENABLE);
}

/*******************************************************************************
* Function Name : TP_Init
*******************************************************************************/
void TP_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD |
RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SPI3, ENABLE);

/* Configure SPI3 pins: SCK, MISO and MOSI ---------------------------------*/


GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStruct);

/* TP_CS */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStruct);

/* TP_IRQ */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStruct);

TP_CS(1);
ADS7843_SPI_Init();
}

32
/*******************************************************************************
* Function Name : DelayUS
*******************************************************************************/
static void DelayUS(vu32 cnt)
{
uint16_t i;
for(i = 0;i<cnt;i++)
{
uint8_t us = 12;
while (us--)
{
;
}
}
}

/*******************************************************************************
* Function Name : WR_CMD
* Input : - cmd:
*******************************************************************************/
static void WR_CMD (uint8_t cmd)
{
/* Wait for SPI3 Tx buffer empty */
while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);
/* Send SPI3 data */
SPI_I2S_SendData(SPI3,cmd);
/* Wait for SPI3 data reception */
while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) == RESET);
/* Read SPI3 received data */
SPI_I2S_ReceiveData(SPI3);
}
/*******************************************************************************
* Function Name : RD_AD
*******************************************************************************/
static int RD_AD(void)
{
unsigned short buf,temp;
/* Wait for SPI3 Tx buffer empty */
while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);

33
/* Send SPI3 data */
SPI_I2S_SendData(SPI3,0x0000);
/* Wait for SPI3 data reception */
while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) == RESET);
/* Read SPI3 received data */
temp=SPI_I2S_ReceiveData(SPI3);
buf=temp<<8;
DelayUS(1);
while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);
/* Send SPI3 data */
SPI_I2S_SendData(SPI3,0x0000);
/* Wait for SPI3 data reception */
while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) == RESET);
/* Read SPI3 received data */
temp=SPI_I2S_ReceiveData(SPI3);
buf |= temp;
buf>>=3;
buf&=0xfff;
return buf;
}

/*******************************************************************************
* Function Name : Read_X
* Description : Read ADS7843 ADC X
*******************************************************************************/
int Read_X(void)
{
int i;
TP_CS(0);
DelayUS(1);
WR_CMD(CHX);
DelayUS(1);
i=RD_AD();
TP_CS(1);
return i;
}

/*******************************************************************************

34
* Function Name : Read_Y
*******************************************************************************/
int Read_Y(void)
{
int i;
TP_CS(0);
DelayUS(1);
WR_CMD(CHY);
DelayUS(1);
i=RD_AD();
TP_CS(1);
return i;
}

/*******************************************************************************
* Function Name : TP_GetAdXY
* Description : Read ADS7843
*******************************************************************************/
void TP_GetAdXY(int *x,int *y)
{
int adx,ady;
adx=Read_X();
DelayUS(1);
ady=Read_Y();
*x=adx;
*y=ady;
}

/*******************************************************************************
* Function Name : TP_DrawPoint
* Input : - Xpos: Row Coordinate
* - Ypos: Line Coordinate
*******************************************************************************/
void TP_DrawPoint(uint16_t Xpos,uint16_t Ypos)
{
LCD_SetPoint(Xpos,Ypos,Blue); /* Center point */
LCD_SetPoint(Xpos+1,Ypos,Blue);
LCD_SetPoint(Xpos,Ypos+1,Blue);
LCD_SetPoint(Xpos+1,Ypos+1,Blue);

35
}

/*******************************************************************************
* Function Name : DrawCross
* Input : - Xpos: Row Coordinate
* - Ypos: Line Coordinate
*******************************************************************************/
void DrawCross(uint16_t Xpos,uint16_t Ypos)
{
LCD_DrawLine(Xpos-15,Ypos,Xpos-2,Ypos,Red);
LCD_DrawLine(Xpos+2,Ypos,Xpos+15,Ypos,Red);
LCD_DrawLine(Xpos,Ypos-15,Xpos,Ypos-2,Red);
LCD_DrawLine(Xpos,Ypos+2,Xpos,Ypos+15,Red);

LCD_DrawLine(Xpos-15,Ypos+15,Xpos-7,Ypos+15,RGB565CONVERT(184,158,131));
LCD_DrawLine(Xpos-15,Ypos+7,Xpos-15,Ypos+15,RGB565CONVERT(184,158,131));

LCD_DrawLine(Xpos-15,Ypos-15,Xpos-7,Ypos-15,RGB565CONVERT(184,158,131));
LCD_DrawLine(Xpos-15,Ypos-7,Xpos-15,Ypos-15,RGB565CONVERT(184,158,131));

LCD_DrawLine(Xpos+7,Ypos+15,Xpos+15,Ypos+15,RGB565CONVERT(184,158,131));
LCD_DrawLine(Xpos+15,Ypos+7,Xpos+15,Ypos+15,RGB565CONVERT(184,158,131));

LCD_DrawLine(Xpos+7,Ypos-15,Xpos+15,Ypos-15,RGB565CONVERT(184,158,131));
LCD_DrawLine(Xpos+15,Ypos-15,Xpos+15,Ypos-7,RGB565CONVERT(184,158,131));

/*******************************************************************************
* Function Name : Read_Ads7846
* Description : Get TouchPanel X Y
*******************************************************************************/
Coordinate *Read_Ads7846(void)
{
static Coordinate screen;
int m0,m1,m2,TP_X[1],TP_Y[1],temp[3];
uint8_t count=0;
int buffer[2][9]={{0},{0}};

do

36
{
TP_GetAdXY(TP_X,TP_Y);
buffer[0][count]=TP_X[0];
buffer[1][count]=TP_Y[0];
count++;
}
while(!TP_INT_IN&& count<9); /* TP_INT_IN */
if(count==9) /* Average X Y */
{
/* Average X */
temp[0]=(buffer[0][0]+buffer[0][1]+buffer[0][2])/3;
temp[1]=(buffer[0][3]+buffer[0][4]+buffer[0][5])/3;
temp[2]=(buffer[0][6]+buffer[0][7]+buffer[0][8])/3;

m0=temp[0]-temp[1];
m1=temp[1]-temp[2];
m2=temp[2]-temp[0];

m0=m0>0?m0:(-m0);
m1=m1>0?m1:(-m1);
m2=m2>0?m2:(-m2);

if( m0>THRESHOLD && m1>THRESHOLD && m2>THRESHOLD ) return 0;

if(m0<m1)
{
if(m2<m0)
screen.x=(temp[0]+temp[2])/2;
else
screen.x=(temp[0]+temp[1])/2;
}
else if(m2<m1)
screen.x=(temp[0]+temp[2])/2;
else
screen.x=(temp[1]+temp[2])/2;

/* Average Y */
temp[0]=(buffer[1][0]+buffer[1][1]+buffer[1][2])/3;
temp[1]=(buffer[1][3]+buffer[1][4]+buffer[1][5])/3;
temp[2]=(buffer[1][6]+buffer[1][7]+buffer[1][8])/3;

37
m0=temp[0]-temp[1];
m1=temp[1]-temp[2];
m2=temp[2]-temp[0];
m0=m0>0?m0:(-m0);
m1=m1>0?m1:(-m1);
m2=m2>0?m2:(-m2);
if(m0>THRESHOLD&&m1>THRESHOLD&&m2>THRESHOLD) return 0;

if(m0<m1)
{
if(m2<m0)
screen.y=(temp[0]+temp[2])/2;
else
screen.y=(temp[0]+temp[1])/2;
}
else if(m2<m1)
screen.y=(temp[0]+temp[2])/2;
else
screen.y=(temp[1]+temp[2])/2;

return &screen;
}
return 0;
}

/*******************************************************************************
* Function Name : setCalibrationMatrix
* Description : Calculate K A B C D E F
*******************************************************************************/
FunctionalState setCalibrationMatrix( Coordinate * displayPtr,
Coordinate * screenPtr,
Matrix * matrixPtr)
{
FunctionalState retTHRESHOLD = ENABLE ;
matrixPtr->Divider = ((screenPtr[0].x - screenPtr[2].x) * (screenPtr[1].y -
screenPtr[2].y)) -
((screenPtr[1].x - screenPtr[2].x) * (screenPtr[0].y -
screenPtr[2].y)) ;
if( matrixPtr->Divider == 0 )

38
{
retTHRESHOLD = DISABLE;
}
else
{
matrixPtr->An = ((displayPtr[0].x - displayPtr[2].x) * (screenPtr[1].y -
screenPtr[2].y)) -
((displayPtr[1].x - displayPtr[2].x) * (screenPtr[0].y -
screenPtr[2].y)) ;
matrixPtr->Bn = ((screenPtr[0].x - screenPtr[2].x) * (displayPtr[1].x -
displayPtr[2].x)) -
((displayPtr[0].x - displayPtr[2].x) * (screenPtr[1].x -
screenPtr[2].x)) ;
matrixPtr->Cn = (screenPtr[2].x * displayPtr[1].x - screenPtr[1].x *
displayPtr[2].x) * screenPtr[0].y +
(screenPtr[0].x * displayPtr[2].x - screenPtr[2].x *
displayPtr[0].x) * screenPtr[1].y +
(screenPtr[1].x * displayPtr[0].x - screenPtr[0].x *
displayPtr[1].x) * screenPtr[2].y ;
matrixPtr->Dn = ((displayPtr[0].y - displayPtr[2].y) * (screenPtr[1].y -
screenPtr[2].y)) -
((displayPtr[1].y - displayPtr[2].y) * (screenPtr[0].y -
screenPtr[2].y)) ;
matrixPtr->En = ((screenPtr[0].x - screenPtr[2].x) * (displayPtr[1].y -
displayPtr[2].y)) -
((displayPtr[0].y - displayPtr[2].y) * (screenPtr[1].x -
screenPtr[2].x)) ;
matrixPtr->Fn = (screenPtr[2].x * displayPtr[1].y - screenPtr[1].x *
displayPtr[2].y) * screenPtr[0].y +
(screenPtr[0].x * displayPtr[2].y - screenPtr[2].x *
displayPtr[0].y) * screenPtr[1].y +
(screenPtr[1].x * displayPtr[0].y - screenPtr[0].x *
displayPtr[1].y) * screenPtr[2].y ;
}
return( retTHRESHOLD ) ;
}

/*******************************************************************************

39
* Function Name : getDisplayPoint
*******************************************************************************/
FunctionalState getDisplayPoint(Coordinate * displayPtr,
Coordinate * screenPtr,
Matrix * matrixPtr )
{
FunctionalState retTHRESHOLD =ENABLE ;

if( matrixPtr->Divider != 0 )
{
/* XD = AX+BY+C */
displayPtr->x = ( (matrixPtr->An * screenPtr->x) +
(matrixPtr->Bn * screenPtr->y) +
matrixPtr->Cn
) / matrixPtr->Divider ;
/* YD = DX+EY+F */
displayPtr->y = ( (matrixPtr->Dn * screenPtr->x) +
(matrixPtr->En * screenPtr->y) +
matrixPtr->Fn
) / matrixPtr->Divider ;
}
else
{
retTHRESHOLD = DISABLE;
}
return(retTHRESHOLD);
}

/*******************************************************************************
* Function Name : TouchPanel_Calibrate
*******************************************************************************/
void TouchPanel_Calibrate(void)
{
uint8_t i;
Coordinate * Ptr;

for(i=0;i<3;i++)
{
LCD_Clear(White);
GUI_Text(50,150,"Touch cross hair to calibrate",Cyan,White);

40
delay_ms(100);
DrawCross(DisplaySample[i].x,DisplaySample[i].y);
do
{
Ptr=Read_Ads7846();
}
while( Ptr == (void*)0 );
ScreenSample[i].x= Ptr->x; ScreenSample[i].y= Ptr->y;
}
setCalibrationMatrix( &DisplaySample[0],&ScreenSample[0],&matrix );
LCD_Clear(Black);
}

41
III– Touch Sense
The GUI uses polling to determine touch events and hence respond accordingly. The polling
methods for each screen are as follows:
void SenseHome(void);
void SenseHome (void) {
GUI_PID_STATE _State;
screenPtr=Read_Ads7846();
if (screenPtr != (void*)0) { //If there is a touch event
getDisplayPoint(displayPtr, screenPtr, matrixPtr );

//Button 'Solar'
if ((displayPtr->x >= 21) && (displayPtr->y >= 51) && (displayPtr->x <= 111) &&
(displayPtr->y <= 101)) {
ClearHome();
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
Solar();}

//Button 'Power Usage'


else if ((displayPtr->x >= 205) && (displayPtr->y >= 51) && (displayPtr->x <= 295) &&
(displayPtr->y <= 101)) {
ClearHome();
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
PowerUsage(); }

//Button 'Grid'
else if ((displayPtr->x >= 21) && (displayPtr->y >= 135) && (displayPtr->x <= 111) &&
(displayPtr->y <= 185)) {
ClearHome();
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
Grid(); }

//Button 'Battery'
else if ((displayPtr->x >= 205) && (displayPtr->y >= 135) && (displayPtr->x <= 295) &&
(displayPtr->y <= 185)) {
ClearHome();
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
Battery(); }
else{
ClearHome();

42
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
Home();
}

}
}

/******************************************************************************************
*************************************************/
void SenseSolar(void);

void SenseSolar(void){
GUI_PID_STATE _State;
screenPtr=Read_Ads7846();
if (screenPtr != (void*)0) { //If there is a touch event
getDisplayPoint(displayPtr, screenPtr, matrixPtr );

//Button 'Inverter_1'
if ((displayPtr->x >= 82) && (displayPtr->y >= 66) && (displayPtr->x <= 217) &&
(displayPtr->y <= 86)) {
ClearSolar();
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
Inverter_1();
/*show inverter_1 stats*/}

//Button 'Inverter_2'
else if ((displayPtr->x >= 82) && (displayPtr->y >= 103) && (displayPtr->x <= 217) &&
(displayPtr->y <= 123)) {
ClearSolar();
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
Inverter_2();
/*show inverter_2 stats*/}

//Button 'Inverter_3'
else if ((displayPtr->x >= 82) && (displayPtr->y >= 146) && (displayPtr->x <= 217) &&
(displayPtr->y <= 166)) {
ClearSolar();
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
Inverter_3();
/*show inverter_3 stats*/}

43
//Button 'back'
else if ((displayPtr->x >= 230) && (displayPtr->y >= 197) && (displayPtr->x <= 310) &&
(displayPtr->y <= 217)) {
ClearSolar();
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
Home();}

}
}
/******************************************************************************************
*****************************************************/

void SenseGrid(void);

void SenseGrid(void){
GUI_PID_STATE _State;
screenPtr=Read_Ads7846();
if (screenPtr != (void*)0) { //If there is a touch event
getDisplayPoint(displayPtr, screenPtr, matrixPtr );

//Button 'History'
if ((displayPtr->x >= 33) && (displayPtr->y >= 195) && (displayPtr->x <= 113) &&
(displayPtr->y <= 215)) {
ClearGrid();
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
/*show graph of grid power in and out over time*/}
}
//Button 'Back'
else if ((displayPtr->x >= 191) && (displayPtr->y >= 195) && (displayPtr->x <= 271) &&
(displayPtr->y <= 215)) {
ClearGrid();
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
Home();}
}
/******************************************************************************************
****************************************************/

44
void SenseBattery(void);

void SenseBattery(void){
GUI_PID_STATE _State;
screenPtr=Read_Ads7846();
if (screenPtr != (void*)0) { //If there is a touch event
getDisplayPoint(displayPtr, screenPtr, matrixPtr );

//Button 'Back'
if ((displayPtr->x >= 216) && (displayPtr->y >= 208) && (displayPtr->x <= 296) &&
(displayPtr->y <= 228)) {
ClearBattery();
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
Home();}
}

}
/******************************************************************************************
******************************************************/

void SensePowerUsage(void);

void SensePowerUsage(void){
GUI_PID_STATE _State;
screenPtr=Read_Ads7846();
if (screenPtr != (void*)0) { //If there is a touch event
getDisplayPoint(displayPtr, screenPtr, matrixPtr );

//Button 'Back'
if ((displayPtr->x >= 221) && (displayPtr->y >= 212) && (displayPtr->x <= 301) &&
(displayPtr->y <= 232)) {
ClearPowerUsage();
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
Home();}
}

void SenseInverter_1(void){
GUI_PID_STATE _State;
screenPtr=Read_Ads7846();
if (screenPtr != (void*)0) { //If there is a touch event

45
getDisplayPoint(displayPtr, screenPtr, matrixPtr );

//Button 'back'
if ((displayPtr->x >= 230) && (displayPtr->y >= 197) && (displayPtr->x <= 310) &&
(displayPtr->y <= 217)) {
ClearInverter_1();
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
Solar();}
}

void SenseInverter_2(void){
GUI_PID_STATE _State;
screenPtr=Read_Ads7846();
if (screenPtr != (void*)0) { //If there is a touch event
getDisplayPoint(displayPtr, screenPtr, matrixPtr );

//Button 'back'
if ((displayPtr->x >= 230) && (displayPtr->y >= 197) && (displayPtr->x <= 310) &&
(displayPtr->y <= 217)) {
ClearInverter_2();
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
Solar();}
}

void SenseInverter_3(void){
GUI_PID_STATE _State;
screenPtr=Read_Ads7846();
if (screenPtr != (void*)0) { //If there is a touch event
getDisplayPoint(displayPtr, screenPtr, matrixPtr );
//Button 'back'
if ((displayPtr->x >= 230) && (displayPtr->y >= 197) && (displayPtr->x <= 310) &&
(displayPtr->y <= 217)) {
ClearInverter_3();
GUI_Clear();
GUI_SetBkColor(GUI_CYAN);
Solar();}
}
}

46
IV – HMI CAN configuration
#include "stm32f10x.h"
#include "stm32f10x_can.h"
#include "stm32f10x_rcc.h"
#include "systick.h"
#include "stdlib.h"
#include "stdio.h"

/* PRIVATE VALUES---------------------------------*/
uint8_t CAN1_RxRdy,CAN2_RxRdy;
uint16_t CAN1_Val_Rx;
uint16_t CAN1_Val_Tx,CAN2_Val_Tx,CAN2_Val_Rx;
CanTxMsg TxMessage;

/*******************************************************************************
* Function Name : Can_Mode_Init
* Description : Initialize CAN-BUS, GPIOs and Interrupts
* Input : none
* Output : None
* Attention : Baud rate =Fpclk1/((tsjw+tbs1+tbs2)*brp)
*******************************************************************************/
void CAN_Mode_Init(void) {

GPIO_InitTypeDef GPIO_InitStructure;
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;

//CAN 1 Config
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO ,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
//Enable CAN1 clock

//Configure CAN1 RX pin

47
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);

// Configure CAN1 pin: TX


GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);

//Remap CAN1 GPIOs


GPIO_PinRemapConfig(GPIO_Remap2_CAN1 , ENABLE);

//Struct init
CAN_StructInit(&CAN_InitStructure);

//The CAN unit set


CAN_InitStructure.CAN_TTCM=DISABLE;
//Non time trigger communication mode //
CAN_InitStructure.CAN_ABOM=DISABLE;
//The software automatically offline management //
CAN_InitStructure.CAN_AWUM=DISABLE;
//Sleep mode wake by software (clear CAN-> MCR SLEEP)//
CAN_InitStructure.CAN_NART=ENABLE; //Disable
automatic transfer message //
CAN_InitStructure.CAN_RFLM=DISABLE;
//The message is not locked, the new cover the old //
CAN_InitStructure.CAN_TXFP=ENABLE;
//Priority is determined by the message identifier //
CAN_InitStructure.CAN_Mode= CAN_Mode_Normal;

//Set the baud rate //450 Kbps for 36M clock


CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
//Re synchronization jump width (Tsjw) for tsjw+1 time units
CAN_SJW_1tq CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq
CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;
//Tbs1=tbs1+1 time units CAN_BS1_1tq ~CAN_BS1_16tq

48
CAN_InitStructure.CAN_BS2=CAN_BS1_7tq;
//Tbs2=tbs2+1 time units CAN_BS2_1tq ~ CAN_BS2_8tq
CAN_InitStructure.CAN_Prescaler=5;
//The frequency factor (Fdiv) is brp+1 //
CAN_Init(CAN1, &CAN_InitStructure);
//Iinitialization of CAN1

//CAN1 Filter Config.


CAN_FilterInitStructure.CAN_FilterNumber=1;
//Filter 0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;
////The 32 bit ID
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;
//The 32 bit MASK
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;
//Filter 0 is related to the FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
//Active filter 0
CAN_FilterInit(&CAN_FilterInitStructure);
//Filter initialization

//CAN interrupt config


CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
//The FIFO0 message to register interrupt enable
}

void NVIC_ConfigCAN (void){


NVIC_InitTypeDef NVIC_InitStructure;
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;

49
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // The
main priority 1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //
Time priority 0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}

/*******************************************************************************
* Function Name : CanWriteData
* Description : Can Write Date to CAN-BUS
* Input : None
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
void CanWriteData1( CAN_TypeDef* CANx ,CanTxMsg *TxMessage )
{
/* transmit */
TxMessage->StdId = 0xA5; //specifies standard identifier ,must be less than
0x7FF
TxMessage->ExtId = 0x00; // specifies extended identifier
TxMessage->RTR = CAN_RTR_DATA; // set to data frame
TxMessage->IDE = CAN_ID_STD; //use standard identifier
TxMessage->DLC = 8; //data length 8 bytes

CAN_Transmit(CANx,TxMessage); //Initiates the transmission of a message


}

/*******************************************************************************
* Function Name : CAN1_RX0_IRQHandler
* Description : This function handles CAN1 RX0 interrupts
* Input : None
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
void CAN1_RX0_IRQHandler(void)

50
{
CanRxMsg RxMessage;
CAN_Receive(CAN1,CAN_FIFO0, &RxMessage);

CAN1_Val_Rx = RxMessage.Data[0] <<8 ;


CAN1_Val_Rx += RxMessage.Data[1];
CAN1_RxRdy = ENABLE;
}

51
V – Inverter ADC
Six channels converted in continuous scan mode and the result stored in memory using DMA:
#include "stm32f10x_lib.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_adc.h"

#define ADC1_DR ((unsigned int)0x4001244C)


volatile unsigned short int ADC_values[6]={0,0,0,0,0,0};
volatile unsigned short int finalADC_values[6]={0,0,0,0,0,0};
vu16 CurrentIn,CurrentOut,PanelV,Stage1V,Vout,Temp;

/*
* channel 1 (PA2) = input ACS712 (CurrentIn)
* channel 2 (PA3) = output ACS712 (CurrentOut)
* channel 3 (PA4) = solar panel input voltage (PanelV)
* channel 4 (PA5) = boost stage 1 voltage (Stage1V)
* channel 5 (PA6) = inverter output voltage (Vout)
* channel 6 (PA7) = inverter temperature (Temp)
*
*/

void ADC_GPIO_Config1(void){
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);

//Configure ADC pins (PA2-> Channel 2 to PA7 -> Channel 7 ) as analog inputs
GPIO_StructInit(&GPIO_InitStructure); // Reset init structure
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3| GPIO_Pin_4| GPIO_Pin_5|
GPIO_Pin_6| GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void NVIC_ConfigADC (void) {


NVIC_InitTypeDef NVIC_InitStructure;

/* Configure and enable ADC interrupt */


NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQChannel;

52
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}

void ADC_Config1(void){
ADC_GPIO_Config1();
NVIC_ConfigADC();

ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;

RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC1, ENABLE);


RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA, ENABLE);

/* DMA1 channel1 configuration ----------------------------------------------*/


DMA_DeInit(DMA_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr =ADC1_DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (unsigned int)ADC_values;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 6;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA_Channel1, &DMA_InitStructure);

/* Enable DMA channel1 */


DMA_Cmd(DMA_Channel1, ENABLE);

/* ADC1 configuration ------------------------------------------------------*/


ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

53
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 6;
ADC_Init(ADC1, &ADC_InitStructure);

/* ADC1 regular channels configuration */


ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 2, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 3, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 4, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 5, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 6, ADC_SampleTime_55Cycles5);

/* Enable ADC1 DMA */


ADC_DMACmd(ADC1, ENABLE);

/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);

/* Enable ADC1 reset calibration register */


ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));

/* Start ADC1 calibration */


ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));

/* Start ADC1 Software Conversion */


ADC_SoftwareStartConvCmd(ADC1, ENABLE);

54
/*******************************************************************************
* Function Name : SortADC
* Description : This function reads ADC values and seperates the array
*******************************************************************************/
void SortADC (void){
CurrentIn = ADC_values[0];
CurrentOut = ADC_values[1];
PanelV = ADC_values[2];
Stage1V = ADC_values[3];
Vout = ADC_values[4];
Temp = ADC_values[5]; }

55
VI – Timer 1 PWM
Timer 1 is used to generate a 25kHz PWM signal with 75% duty cycle.
#include "stm32f10x_lib.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_tim1.h"

TIM1_TimeBaseInitTypeDef TIM1_TimeBaseStructure;
TIM1_OCInitTypeDef TIM1_OCInitStructure;
unsigned int CCR1Val = 1079;
unsigned int PrescalerValue = 0;

void TIM1_PWM (void){


GPIO_ConfigPWM();

TIM1_TimeBaseStructure.TIM1_Period=1439;
TIM1_TimeBaseStructure.TIM1_Prescaler = 1;
TIM1_TimeBaseStructure.TIM1_ClockDivision = 0;
TIM1_TimeBaseStructure.TIM1_RepetitionCounter = 0;
TIM1_TimeBaseStructure.TIM1_CounterMode = TIM_CounterMode_Up;

TIM1_TimeBaseInit(&TIM1_TimeBaseStructure);

/* PWM1 Mode configuration: Channel1 */


TIM1_OCInitStructure.TIM1_OCMode = TIM1_OCMode_PWM1;
TIM1_OCInitStructure.TIM1_OutputState = TIM1_OutputState_Enable;
TIM1_OCInitStructure.TIM1_OutputNState = TIM1_OutputNState_Enable;
TIM1_OCInitStructure.TIM1_Pulse = CCR1Val;
TIM1_OCInitStructure.TIM1_OCPolarity = TIM1_OCPolarity_High;
TIM1_OCInitStructure.TIM1_OCNPolarity = TIM1_OCNPolarity_High;
TIM1_OCInitStructure.TIM1_OCIdleState = TIM1_OCIdleState_Set;
TIM1_OCInitStructure.TIM1_OCNIdleState = TIM1_OCNIdleState_Set;
TIM1_OC1Init(&TIM1_OCInitStructure);

TIM1_OC1PreloadConfig(TIM1_OCPreload_Enable);

TIM1_ARRPreloadConfig(ENABLE);

/* TIM1 enable counter */

56
TIM1_Cmd(ENABLE);

/* TIM1 Main Output Enable */


TIM1_CtrlPWMOutputs(ENABLE);
}

void GPIO_ConfigPWM (void) {


GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1| RCC_APB2Periph_GPIOA
|RCC_APB2Periph_AFIO, ENABLE);

/* GPIOE Configuration: TIM1 Channel1 as alternate function push-pull */


GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

57

You might also like