This project uses the
Arduino PWM Uno or other systems to realize a fully isolated analog output with
a range of 0-5 volts or more, changing only the reference voltage.
Introduction
This project completes the series of my
articles about the Arduino analog I/O with the aim to use it as a controller of
small automation systems.
In control systems of the industrial plants it
is always advisable to isolate both the inputs and the outputs coming from the
field. This prevents disturbances caused by power surges, lightning strikes or
other EMI sources and also by ground potential differences.
Arduino Uno, or systems based on the ATmega328
chip has no a true analog output, but it may be realized using a PWM output averaged
with a low-pass filter.
The use of an averaged PWM signal with 8-bit
setting is not comparable with a real DAC, but in the insulation case presents
undoubted advantages of simplicity since it is sufficient to use an optocoupler
for isolating the PWM digital signal. Recently I designed another circuit to
generate a 4-20 mA current with Arduino, that experience gave me the idea for
this new project.
The
Arduino PWM
Arduino Uno has several pins (3, 5, 6, 9, 10, and
11) that can be configured for PWM output. For this project I used pin 9
because the others were used by various devices (LCD, SD and RTC) in my Arduino
system.
The PWM signal on pins D9 and D10 is generated
by Timer# 1 of ATmega328. It has a prescaler which divides by 1, 8, 64, 256, 1024,
controlled by the three least significant bits of the register TCCR1B. The
default value of the prescaler set by the Arduino IDE is equal to Np= 64 (TCCR1B,
bits 2-0= 110), which provides an output frequency:
PWM frequency =
CPUClock/(2´Np´TOP) =
16000000/(2´64´255)= 490.196 Hz
Where the TOP value is he maximum Timer/Counter
value.
The following table shows the frequencies
generated by Timer# 1 of an Arduino Uno (Atmega 328) on pins 9 and 10,
with a 16 MHz clock and in “phasecorrect PWM” mode. In this
mode, the timer counts from 0 to 255 and then back
down to 0.
Prescaler divider (Np)
|
Prescaler code
|
PWM frequency
|
1
|
B001
|
31372.549
|
8
|
B010
|
3921.569
|
64
|
B011
|
490.196
|
256
|
B100
|
122.549
|
1024
|
B101
|
30.637
|
The prescaler code must be put in the three
least significant bits of the register TCCR1B – Timer/Counter1 Control Register
B. For example, to generate a PWM of 3921 Hz, the following instruction must be
inserted in the setup function:
TCCR1B = TCCR1B & B11111000 | B00000010;// set
timer 1 prescaler to 8
Using a common optocoupler with a
phototransistor, as 4N25, the frequency is limited because of the high
transition times, so I used a faster optocoupler with photodiode and with an open
collector output, such as the 6N136.
To eliminate the output noise I utilized a
second order active low-pass filter, Sallen-key type, with a cut-off frequency
of about 11.2 Hz. The isolation is achieved with an optocoupler, of course you
must use for this circuit a power supply different from the one used for
Arduino. If the insulation is not required, things become even simpler and
connect the filter to the PWM output, in this case not even need the reference
source U2.
The circuit diagram, shown in Figure 1, is
quite simple. I recommend using for U1 a double operational amplifier suitable
for single-rail power supply, such as LM358.
The LM358 chip must be powered with a voltage
higher than 7 V (and lower than 32) to have in output a maximum voltage of 5V
and also the regulator has a 2 V dropout.
The advantage of the open collector of the
optocoupler is that you can easily obtain a different output range, for
example, using a 10V reference voltage and R2=10 kohm the output range became 0-10V. In
this case the LM78L05 must be replaced with a LM317 with an appropriate
circuitry.
In figure 2 you can see the arrangement of the
components of my prototype.
Hardware components
1x Arduino board,
Components list
R1= 330 ohm ±5%
|
R2= 5.1 kohm ±5%
|
R3= 100kohm ±5%
|
R4= 100 kohm ±1% metal film
|
C1= 100nF ceramic
|
C2 = 10 MF,50V Electrolytic
|
C3= 200 nF Mylar ±2%
|
C4 = 100 nF Mylar ±2%
|
U1= LM358 dual op amp
|
U2= LM78L05 regulator
|
OPT1= 6N136
|
The capacitors used for the filter must be
measured with a capacimeter, for my prototype I selected for C3 some 220 nF
capacitors to search for a value that approached 200nF and C4 have selected a
value half of C3.
The test on the circuit
The Figure 3 shows the results of the linear
regression on the 14 measurements points made on my prototype. The test
conditions are:
·
PWM
frequency = 490.196 Hz;
·
Vin
= 12V;
·
Vref
= 5.00 V
The standard error is about 6.1 mV, so the
results are very good at the default PWM frequency.
I also tested the system with a frequency of 3921.569
Hz, but with a standard error of 39 mV. The largest errors are found for high duty cycle values, in this area
the pulses are narrow and the rise time is high and this phenomenon creates
non-linearity. The period is: T = 1/3921.569 = 255 µs. The more narrow pulse
has a duration of about 1 µs, approximately the same value as the rise time of
the pulses, the cause of non-linearity is due just to this phenomenon. Using
the default frequency of 490.196 Hz, the minimum pulse has a duration eight
times larger, so it greatly improves the linearity.
The program list
To test the system I used an Arduino Uno with
a LCD display and the analog input A0 connected to a potentiometer to vary the
duty cycle of the PWM.
//
program to test Arduino Uno PWM at 3.9 kHz
// G. Carrera 30 sett 2016
#include <LiquidCrystal.h>
int
PWMpin = 9; // PWM out on digital
pin 9
int
analogPin = 0; // potentiometer
connected to A0
int
val = 0; // variable to store the
read value
char
spacestring[17] =" ";
//
initialize the library with the numbers of the interface pins
LiquidCrystal
lcd(7, 6, 5, 4, 3, 2);
void
setup() {
pinMode(PWMpin,
OUTPUT); // sets the pin as output
lcd.begin(16, 2);// set up number of columns
and rows
lcd.setCursor(0, 0);// set the cursor to
column 0, line 0
lcd.print("Stalker PWM");// Print a
message to the LCD
// set timer 1 prescaler to 8 for PWM
frequency of 3921.57 Hz
//TCCR1B = TCCR1B & B11111000 |
B00000010;
}
void
loop() {
val = analogRead(analogPin) >>
2;// read the potentiometer as 8 bit
analogWrite(PWMpin, val);
val =
255-val;// complement
lcd.setCursor(0, 1);
lcd.print(spacestring);
lcd.setCursor(0, 1);
lcd.print(val);
delay(500);
}
References
2. “Atmel 8-bit
Microcontroller with 4/8/16/32KBytes In-System Programmable Flash”, 8271G–AVR–02/2013
It is through research that new theories, concepts and solutions to life problems are generated. I appreciate the blogger for disclosing that he has passion in electronic projects. This has really stirred up my spirit in the research work. Content Keyword Review
ReplyDeleteI was doing an online research on How to Write an Evaluation Essay before I landed on this magnificent page and I have found interesting and intriguing article that has been written in a unique manner. Thanks so much for sharing this article with us. We are anticipation more articles.
ReplyDeleteLiquid Level Sensor can be used to identify the level of substances that can flow. There are various types of liquid level sensor used to detect the point level of a liquid. Some types use a magnetic float, which rise and fall with the liquid in the container.
ReplyDeleteThanks For Sharing Great Information, Keep It Up Share Again & Again Great Post. 3D Rendering Services in India, 3D Walkthrough Company, Architectural Rendering, Architectural Rendering Services, 3D Architectural Walkthrough Services
ReplyDeleteThanks!!!!!!!!!
Thank you very much for this great article and information. It is very useful to me, please provide more information or a good article like this again.
ReplyDeleteArduino
Question:
ReplyDeleteI'm thinking of perhaps using this for a MC3PHAC-circuit as a means to regulate speed as it has (2) analog 0-5V inputs for speed and acceleration.
Now, my main concern is that this output mustn't exceed 5V, and I was wondering what the tolerances are with the currently supplied values?
I noticed that R2 was responsible for the voltage, as you mention 10k was appropriate for 10V, and this example for 5V uses 5,1k, which is almost half. I'm not much for analog electronics since it involves a lot of mathematics, a subject that doesn't agree with me, so to speak.
Therefore, I'm curious (at the time writing this), since I don't have these components on hand, it should be as simple as putting a potentiometer instead of R2 to limit the maximum voltage I think, but I'm also thinking one could be used on the output, after R3 towards ground to further limit the maximum voltage. But I don't know how that would affect the OP-amp U1b.
Thoughts on this?
The maximum output voltage depends on the voltage tolerance of the 7805 regulator which is +/- 0.5V. A potentiometer must not be put in place of R2 and the filter resistors that determine the cutoff frequency must not be modified. You can modify the maximum voltage by adding a resistor between pin 3 of U1A and ground: for example 51 kohm reduces the maximum voltage by about 1/10. The best solution is to control the MC3PHAC chip via serial.
DeleteOk.
DeleteWell, I looked at the datasheet for the MC3PHAC, and found it very difficult to handle the serial interface.
I have made an PCB, which I'm currently unsure about, as I added a couple of digital potentiometers, both with opto-couplers.
They are to be operated on the SPI bus.
I'm not certain that these opto-couplers (PC817) are fast enough to handle this bus.
This is my 2:nd version, but I'm not feeling 100% about this, so I'm looking to possibly making a third PCB,
and this seemed like a good idea to skip the potentiometer.
One of the reasons I wanted to limit the output voltage was that I want to limit the maximum output to
around 4V. so that I don't max the motor since that has a maximum input of 195V at 310Hz.
Current configuration has resistors to limit this.
I have tried this circuit and it was working, until I found a flaw in the design which made it dangerous to use,
so I had to redo the design.
There are a few things that I'm not satisfied with on the new design, so I'm thinking of making a third version,
as I said.
I worked on the current one for about 5 months, and I sort of rushed the last of the design as I approached my
own set deadline, so a couple of things was messed up.
Managed to connect a bunch of Triacs all wrong, have a couple of IC's crammed into spaces where they
don't belong among high voltage and a couple of more things.
When I'll do this I don't know, so I'm looking for alternatives at the moment.
I have to re-order a bunch of stuff, so I'm saving myself until I have a proper design that I feel
pleased with.
The (re)build is a washing machine that was a give-away due to water damage, so that's the reason for the odd voltage specs for the motor.
I saw there is an application note (AN2202) to control the mc3phac chip with PC via serial interface, download from this site: https: //www.nxp.com/docs/en/application-note/AN2202.pdf
DeleteThe PC817 optocoupler is not good for the SPI bus as it has a phototransistor which is slower. A photodiode optocoupler is needed to achieve smaller rise / fall times. You could use an Arduino connected directly to digital potentiometers and connected via serial with the optocouplers to your controller.
Hmm... Just as I feared.
DeleteYes, I've seen that datasheet. Only thing it did for me was to further confuse me and feeling reluctant to ever use that serial communication.
I think that perhaps this could be a solution to my opto-couplers:
setClockDivider()
as described in this example:
https://www.arduino.cc/en/Reference/SPISetClockDivider
It doesn't say exactly what frequencies or so, but it would suggest that 16 MHz divided by 128 would land me around 125 Khz if my bad math got it right, and should work I think.
But, again, if I'm to use this schematic in another version of this PCB of mine, I don't have to bother with the SPI-bus.
ReplyDeleteIt would, however, be very nice if I could get the existing one to work while I start to work on an upgrade.
cool post, man! If you want to know more about Arduino Mega, check this article. Thats awesome
ReplyDeleteHi, I used this solution to get regulated 0-10V by PWM. I have these parameters: Vin=22V, Vref=10V, C3=220nF, C4=104nF, R2=10k as you proposed. I tried it without Arduino on the optocoupler input, I used a laboratory power source 0-5V. On the output I got these values:
ReplyDeleteVopto > Vout
0,0 > 9,84
1,2 > 9,82
1,5 > 8,00
2,0 > 3,53
2,5 > 0,27
3,0 > 0,23
5,0 > 0,19
It means that there would be 0V when PWM=125 (2,5V) and full 10V when PWM is 0. Please, can you tell me what to change to get linear regretion PWM 0 > 0Vout up to PWM 256 > 10Vout? Why I have it inversely, is it ok?
Thanks, Tom
hi, I don't understand what you did. Did you remove the Arduino that generates the PWM pulses and complemented the output and put a 0-5V DC voltage generator? If you want to generate an output voltage of 0 to 10 volts, just replace the regulator 7805 with a 10V one and change the R2 from 5.1 to 10 kohm and, of course, use Arduino or similar to generate the pulses.
DeleteHi, yes, to be sure I won't destroy the Arduino, I used the DC voltage generator 0-5V. It has different behavior with the PWM pulses? I thought that I can test it by simulating PMW by the voltage generator. Ok, I will try it. Thanks, Tom
ReplyDeleteHi, a PWM signal is completely different from the DC generator in that it generates pulses of fixed amplitude and variable duration. Your Arduino won't get damaged if you follow my circuit.
DeleteYes, it's working properly, thank you.
DeleteHi Giovanni. I want to follow your circuit design to send a 0-5.7v analogue signal from an arduino pwm --> 4n25 --> motor controller. The controller currently supplies 5.7v to a variable resistor (pot) and I want to replicate the pot/wiper. So I have a source voltage of 5.7v I can use to supply the 4n25 and other components (opamp?) to achieve the same outcome that you have. Can you help?
ReplyDeleteHi Chris, you can use my circuit, replacing the LM7805 with an LM317 (adjustable regulator), a couple of resistors and a trimmer to get the voltage you want (see datasheet). Of course you have to remove the motor governor potentiometer. A simpler solution is to use a "digital potentiometer" type MCP41100 or similar with the library and examples you can find on the net. But this simpler solution is not galvanically isolated because it uses an interface SPI bus with Arduino.
DeleteI have a LM317 on hand. My question is do I only need this because the opamp loses 2v? I also have digital pots but these require multiple signals (from Arduino) to control which means multiple octo couplers. Your circuit was simpler and in essence doing what the analogue pot was doing - providing a 0-5.7v analogue signal.
ReplyDeleteI am clueless with designing circuits so could you adjust your circuit for me that would work? Any help appreciated.
There are no problems with opamps if you use a Vi voltage of at least 12 volts. I don't want to change my scheme, but the changes are simple. Replace the 7805 with an LM317. Connect a 220 ohm resistor between its output Vo (pin 2) and ADJ (pin 1), connect a 620 ohm resistor in series to a 220 ohm trimmer (slider and one end) between ADJ and ground. Download the datasheet and see its pinout for connections. Capacitors C1 and C2 are unchanged.
ReplyDeleteThe theoretical output should vary between 4.8 and 6 volts, by varying the trimmer. Calibrate at 5.7 volts, using a voltmeter.
Thanks Giovanni. Quick question, if I want want the output to default to 0v (input circuit off or no power), how do I wire/change the circuit? At the moment if I remove the input, it defaults to 5.7v.
DeleteYou could probably put a pull-up or down resistor on the input. Not sure if it's positive or negative flank, or depending on which input you're referring to, you also could experiment with an old 4066 logic circuit and either find some point in the circuit that holds a voltage around 5V (I believe the logic circuit accepts up to 12V or possibly more) and connect that to the gate for the internal switch. Not sure how signal integrity would hold up, but it's otherwise a neat way to switch signal sources. You could also control that via Arduino if you want extra control.
DeleteI have not yet tried this circuit myself. I've put my project on ice since just before Christmas, so I've had little thoughts about it lately, but it's still on the table, so to speak.
If you don't want to use Arduino, you can use a 4-5 kHz astable oscillator (for example with a NE555) that generates pulses of variable duration (PWM). You get zero output if you put R1 at 5V. The optocoupler is inverting, if you put it at zero, the output is high and if you put it at 5V the output is zero, but to have the intermediate values you must have PWM pulses, because the circuit is not linear, it works as a switch.
Delete