ECG Patiënt Simulator - The Software.


The software of the ECG Patient Simulator was initially developed using an Arduino UNO R3 board to eventually run on a self-made PCB with the “escape” version of the microcontroller, namely an Atmega328 with the Arduino boot loader and the Arduino code. The purpose of the self-made PCB is to make the overall design as compact as possible.

In the following description, an input or output will be called with both the I/O connection as we find it on the Arduino UNO board and also with the physical pin number of the Atmega328 in Plastic DIL 28-pin version. The Arduino UNO naming is used in the software because the compiler of the Arduino IDE (Integrated Development Environment) is also using this naming.

In order to get an idea of ​​the software, I will first go through the functionalities of this device. Then I will briefly run through the different sections and functions of the code in sequence. For a more detailed description of the constants, variables and functions I would like to refer to the detailed commentary in the Arduino Sketch. The Arduino IDE can be downloaded for free from the Arduino website: in case you would like to review or edit this sketch.

The Arduino IDE (Integrated Development Environment)

The Arduino UNO R3

ATMEGA328 Escape Kit

Controls and Functions:

The ECG Patient Simulator has two push buttons: An "ON / +" push button and a "-" push button. The "ON / +" push button has several functions. The device can be turned on or off with this button or this button can be used to increase the heart rhythm or to set the output amplitude. This push button, SW1A in the schematic, is read by the microcontroller via Digital I/O 3 of the Arduino UNO or Pin 5 of the Atmega328.

The "-" pushbutton on the ECG Patient Simulator is used to decrease the heart rhythm, to set the output amplitude and together with the "ON / +" pushbutton, it can initiate a longer auto-power-off time, when turning on the simulator. The "-" button, SW2A in the schematic, is connected to Digital I/O 2 of the Arduino UNO or Pin 4 of the Atmega328.

When the ECG Patient Simulator turns on, it will start with a heart rate of 60 Bpm and a start-up tone will sound through the speaker. The speaker is connected to Digital I/O 6 of the Arduino UNO or Pin 12 of the Atmega328 via a MOSFET. With the "ON / +" and "-" keys, heart rhythms of 30, 60, 90, 120, 150, 180, 210 or 240 BPM can be selected.

The ECG signal:

The ECG signal is produced in a PWM format (Pulse width modulated) at the Digital I/O 9 of the Arduino UNO or Pin 15 of the Atmega328. The base frequency of the PWM signal is 490.20Hz on the Arduino UNO. To keep the values ​​of the capacitors in the low pass filters small, this frequency has been increased to 31372.55Hz by adjusting Timer 1 of the microcontroller.

The PQRST complex of the ECG is made up out of 300 sample values ​​that are stored in the constant array EcgWaveForm []. These sample values ​​are sequentially written to the PWM output Digital I/O 9 at intervals that vary depending on the selected heart rate. This makes it possible to shorten the total time of the PQRST complex at higher heart rates  and stretching it at lower hear rates. The flat line between the complexes is one constant value.

Arduino UNO to Atmega328P Pin Conversion.

The Power Supply:

The programmed energy saver will turn off the circuit after 5 minutes of operation. This shutdown function is controlled by Digital I/O 5 of the Arduino UNO or Pin 11 of the Atmega328 and is active high. That is, the Atmega328 will continue to power itself and the rest of the circuit as long as this output is high and an input voltage is present.

The user can of course anytime switch off the device by pressing the "ON / +" button for about 3 seconds. A closing tone will sound and the microcontroller will switch the device off. 

It is possible to increase the time before the simulator automatically switches off to 30 minutes by pressing and holding the "-" button while pressing the "ON / +" button to switch the device on. Depending on the state of Dip Switch 2, connected to Digital I/O 13 of the Arduino UNO or Pin 19 of the Atmega328, a different start-up tone will sound when the 30 minute auto-power-off is activated.

Heart rate indication and sounds:

At the speed of the heart rhythm an LED will light up. It is connected to Digital I/O 17 of the Arduino UNO or Pin 11 of the Atmega328. Making this output low, will light up the LED. A short beep will also sound at the same heart rhythm when Dip Switch 1 is ON. Dip Switch 1 is connected to Digital I/O 18 of the Arduino UNO or Pin 12 of the Atmega328. When Dip Switch 1 is off, there will be no rhythm beep but a short high-pitched beep will sound every 15 seconds (AttentionBeep) to draw the user's attention to the simulator as long as it is on.

The battery voltage of the ECG Patient simulator is continuously measured via Analog I/O A0 of the Arduino UNO or Pin 23 of the Atmega328. Depending on the condition of the battery, the beep at heart rate will vary in pitch. When the battery voltage is higher than 7.2Vdc, the frequency of the beep will be 900Hz. With a battery voltage between 7.2Vdc and 6.7Vdc, the frequency of the beep tone is 200Hz. With a battery voltage between 6.7Vdc and 6.3Vdc, the beep frequency is only 80Hz. This low beep indicates that the battery needs to be replaced.
The start-up tone also varies as the battery condition weakens. As long as the battery voltage is higher than 6.7Vdc, a normal start-up tone will sound. These are 4 consecutive tones with increasing frequency. If the battery is between 6.7Vdc and 6.3Vdc and the ECG simulator is being switched on, a warning tone will sound instead of the normal start-up tone. The warning tone consists of 4 short consecutive low-pitch beeps. When switching on the device with a battery voltage lower than 6.3Vdc, the same warning tone sounds immediately followed by the shutdown tone (4 consecutive tones with descending frequency) and the simulator then switches itself off again.

When turning on the ECG Patient Simulator with a poor battery, it can still be switched on in an emergency. In this case, if the warning tone sounds, followed by the shutdown tone, and the user holds the "ON / +" button anyway, then, after about 5 seconds, the simulator can still be used for 5 minutes. The simulator will switch itself off afterwards.


Adjusting the amplitude of the ECG signal:

The signal coming from the simulator is fed back to the microcontroller via Analog I/O A1 of the Arduino UNO or Pin 24 of the Atmega328. This makes it possible to adjust the level (amplitude) of the output signal equally for all heart rhythms. The reason why this should be done is described in the Hardware section of this project.
At first time using the simulator, it is recommended to adjust the amplitude of the delivered ECG signal to an amplitude that you prefer most. The typical amplitude of an ECG signal on lead II is 1mVpp to 1.5mVpp. To adjust, connect the device to an ECG Monitor and press and hold the "On / +" push button for about 15 seconds after you heard the start up tone. When A high-pitched beep is sound you can release the "ON / +" key. The simulator will now start with its highest heart rate of 240 Bpm. By short pressing the "ON / +" button or the "-" button the generated amplitude (WantedAmplitude) can be increased or decreased respectively.  Keeping pressed the "ON / +" pushbutton, for about 3 seconds during adjustment, will switch off the simulator and the new amplitude setting will not be saved.

If, during this adjustment, neither button is pressed for 30 seconds, the simulator will adjust the amplitudes for all heart rhythms in descending order. This may take some time because only one measurement/adjustment is done per heartbeat, at the highest level of the ECG wave. As a result, the higher heart rhythms will be adjusted faster than the lower heart rhythms. Completion of an adjustment will be indicated by a short, high pitch tone for each heart rhythm after which the next lower heart rhythm will be adjusted. Each measurement is converted by the software to an attenuation factor (AttenuationXXXBpm) that is applied to the generated output signal to match the “WantedAmplitude”.

As soon as all heart rhythms have been adjusted, all attenuation factors and the “WantedAmplitude” are stored in the EEPROM, after which the shut-off sound is played and the simulator switches off itself. When switching on the simulator, these attenuation values ​​will be transferred from the EEPROM back to their respective AttenuationXXXBpm values ​​to ensure that the same amplitude of the ECG is produced for each heart rhythm.

Holding down the "ON / +" pushbutton, for about 3 seconds during this automatic procedure, will turn off the simulator and the newly adjusted amplitudes will not be saved.

Various goodies:

The microcontroller-output, Digital I/O 6, that controls the speaker via a MOSFET, can instead be used to connect a relay or something else if you would like. You can also program another function for the DIP-switches if you want.

In the loop() section of the program you can notice that the millis() and micros() functions of the Arduino are used a lot. This provides a multitasking effect to enable, for example, operating the push buttons while the ECG waveform is being generated.


So far, the most important operations of the software have been discussed.

Next is a brief overview of the code.

The Code in brief.

Hereafter, we will step through the program and briefly explain the most important sections of the code.


The code starts with initializing the EEPROM.h Library. This is the only library that our program is using. The EEPROM.h library allows us to use a part of the 1K EEPROM, embedded in the Arduino UNO, to store the values ​​of the amplitude adjustments permanently.

Constants and Variables. 

In the first big section, all constants and variables are declared. The most important variable is undoubtedly the EcgWaveForm[]. This array contains the 300 amplitude samples ​​of the ECG signal. These amplitude values ​​use the full 8-Bit (0-255) range, that we can send to a PWM output of the Arduino UNO. In this section we can also find the array with the musical start-up sound that plays when you select a 30 minute auto power-off time (StartupSound1[]).

Setup() section.

After the declarations we hop into the setup() section. This section starts with defining the inputs and outputs, next are the initialization of the timers (millis and micros) for the multitasking, and then moves on to the control of the startup modes. First will be checked whether an auto power-off time of 30 minutes has been selected and eventually the simulator starts with the musical start-up sound. Next the battery is checked and the corresponding startup beeps are set. Also, the calibration values, if they exist, ​​are read from the EEPROM. Then the default heart rate of 60Bpm is selected. The last task in the setup() section checks if the amplitude calibration has to be started.  This happens when the SW1A pushbutton is held for 15 seconds after the startup sound has played.

The Loop() section.

The loop() section mainly contains the triggers for various functions, and so generating a multitasking effect.

The first and most important trigger (EcgPeriod) starts a new ECG waveform at the rate of the selected heart rhythm. This trigger opens a time window during a full PQRST complex of the ECG.

During this time window, the second trigger (SampleWriteInterval) keeps track of the moment for the next sample value to be written to the PWM output. The interval of this second trigger allows stretching or shrinking the total time of a PQRST complex according to the selected heart rhythm.

A third trigger (CheckButtonInterval) checks whether the push buttons are pressed or released. The job of this trigger is not only the recurrent testing of the switches, but also de-bounces the push buttons. At this moment there will also be checked whether the "ON" button has been pressed for a longer period, allowing the user to turn off the ECG Patient Simulator.

Then the LED is turned on and off at the appropriate moment.

If, at start-up, was chosen to adjust the amplitude of the waveform, (CalibrationTriggerTime), the next routine, starting with "if_ (SettingAmplitude == true)", will make sure that, with the "-" and the "ON / +" push-buttons, the desired peak-to-peak level of the ECG wave can be adjusted.

The next thing is to check whether the heart rate beep has been switched off with DIP Switch 1 and generate an attention beep accordingly (CurrentAttentionBeepTime).

Next, measure the battery voltage (CheckBatteryVoltage()) and finally see if the time has come to switch off the ECG Patient Simulator automatically (AutoPowerOffTime).

This is the end of the main routine and this loop() section will be started all over again.


Behind the loop() section you can find the programmed functions that will be called from within the loop() section or the setup() section.

It starts with the "WriteEcg" function. This is the most comprehensive function of the entire program. In this function the ECG samples, with the correct attenuation, are sent to the PWM-pin of the microcontroller. Here is kept track if the end of the PQRST complex has been reached.  This is where the amplitude will be adjusted too. The automatic calibration is also performed in this function. All of these tasks are initialized by choices made in the setup() or the loop() section of the program. The commentary in the sketch will undoubtedly provide more explanation.

After the "WriteEcg" function, there is the "CheckBatteryVoltage" function. In this function, the pitch of the beep tone is adjusted, according to the state of the battery.

In the next "ReadButtons" function is tested whether a push button has been pressed or released and will the time, that the "ON" button is held, be recorded, to be able to switch off the circuit.

In the "UpdateNewAttenuationValue" function, the attenuation that was adjusted during the automatic calibration, is stored in the correct attenuation factor (AttenuationXXXBpm) per heart rhythm.

The "DefineSampleWriteInterval" function sets the heart rate trigger and sets the time between writing the samples. The attenuation factor per heart rhythm is also selected here.

Increasing or decreasing the heart rhythm is done by pressing the "ON / +" or the "-" key, which starts the "SwitchHeartBeat" function. This causes the heart rhythm to change to the next, or to the previous value.

The "PlayStartupSound" and the "PlayShutdownSound" functions play the corresponding sounds while the "CheckPowerOff" function will check if the circuit should be turned off by holding the "ON / +" button long enough.

"SoundWarningBeep" plays the alarm sound.

The last two functions "WriteSettingsToEeprom" and "ReadSettingsFromEeprom" will write or read the amplitude and attenuation factors to or from the EEPROM respectively.


This is pretty much the summary of the code.
In the Arduino sketch a more detailed commentary is provided for each part of the program. You can consult this sketch via the Arduino IDE if you want to learn more.

Programming the Atmega328.

As I mentioned before, the software was developed in the Arduino IDE. It is very nice, especially during the development phase, that the software can instantly be transferred from the IDE to the Arduino via a USB cable for diagnosting.
I used an Arduino UNO with an Atmega328 microcontroller in a 28-Pin DIL housing, so the programmed microcontroller can be transferred from the Arduino UNO to the self-made PCB because both boards are equipped with the same 28-Pin IC socket. 

And that's all there is to it.

In order not to be left with an "empty" Arduino board, I bought the Atmega328 with a preprogrammed Arduino boot loader at Conrad and put it back onto my Arduino UNO board. Good to go again! This Atmega328 with boot loader was sold as a package together with a low profile 16MHz crystal. You can order the blank Atmega328 and flash it yourself with the boot loader via an existing Arduino. This will be a bit cheaper, but will require a little more effort.



The full Arduino Sketch can be downloaded under the Downloads Tab of this project at the top of this page.

It is likely that the software can be optimized and written more efficiently by an experienced programmer. Be my guest, because that is exactly the intention of the STEAM Reactor Makerspace and it's published projects. It is not only our goal to stimulate the replication of the projects, but we also want to stimulate your own creativity and the sharing of knowledge.

I had a great time writing this program and could go on eternally.

At a certain moment you have to say "Ok, this is where I will stop programming and continue with the hardware or the housing". This will also leave some room for extra functions that may come up while using the device.


And at the end, I am very happy with the result !


Happy coding.
Johan Smets

image/svg+xmlOpen Source Licenses HardwareSoftwareDocumentationCERN-OHL-S-2.0-or-laterGPL-3.0-or-laterCC-BY-SA-4.0

This ECG Patient Simulator project is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.