Translate

Thursday, 30 March 2017

A LCD serial terminal with Teensy

This project uses a serial 40x4 LCD display with a Teensy board to realize a compact serial terminal receiver to be connected to many systems with serial output such as our microcontroller systems and GPS receivers.
The terminal connected to a GPS receiver.

The Teensy board
I used a Teensy 3.1 because it is very powerful, its most important features are:
·        Processor: MK20DX256 32 bit ARM Cortex-M4 72 MHz;
·        Flash Memory: 256k, RAM Memory: 64k, EEPROM: 1k;
·        I/O: 34, TTL 3.3V, 5V tolerant;
·        Analog In (16 bit, 13 effective): 21;
·        UART,I2C,SPI: 3,2,1;

and finally, it is very inexpensive compared to its features. Now it has been replaced by version 3.2, 100% compatible. 
The display
I have adopted a large alphanumeric display 40 columns by 4 rows, a DMC40457 of Optrex Corporation. As can be seen from the following table, the connections of this type of display are very different from the more common 16-column for two rows. Furthermore there is a second enable signal, being necessary two HD44780 chip. The connector has 16 pins, arranged in 2x8.
pin
function
pin
function
1
D7  Data Bus Line
2
D6  Data Bus Line
3
D5  Data Bus Line
4
D4  Data Bus Line
5
D3  Data Bus Line
6
D2  Data Bus Line
7
D1  Data Bus Line
8
D0  Data Bus Line
9
E1 - Enable Signal #1
10
R/W - Read/Write
11
RS Register Select
12
VEE - Power Supply
13
VSS - Power Supply (GND)
14
VCC - Power Supply
15
E2 - Enable Signal #2
16
Not connected
There are also displays with LED backlight, in which case the connector has 18 pin. The backlight will significantly increase the consumption of the display.
To drive the LCD display dual chip, I used the LiquidCrystalFast library by John Raines. It is not, at the time, capable of driving the LCD display 40x4 with a faster 8-bit data bus, then I used the 4-bit data bus (D4..D7) plus 4 control bits (E1, E2, R / W , RS), eight bits configured as outputs. The fields of the table with a yellow background representing the used pins, then 8 bits + 3 for power supply.
The configuration of the display function has the following syntax:

LiquidCrystalFast lcd(RS, RW, E1, E2, D4, D5, D6, D7);

In our case it becomes:

LiquidCrystalFast lcd(21, 4, 2, 6, 17, 18, 19, 20);

If you don’t think of working with long lines you can use smaller displays as a 20x4 with only a single HD44780 chip. In this case you have to make some changes on the LCD wiring and program. You can now use the library LiquidCrystal of the Arduino IDE.

Baud rate selector
To select the baud rate I used three of the four dip switches for a total of eight communication speed. The fourth can be used to select other communication parameters. The following table shows the positions of the first three dip switches and the corresponding baud rates.  Usually the dip switches with the levers in the low position are closed (ON) which corresponds to logic zero.

The power supply
As already said, the Teensy provides the power supply from USB, but I preferred to have more independence from grid power using rechargeable batteries. The simplest and cheapest solution was to use a commercial device which is now very widespread, usually called 'mobile power bank'. It is used to give energy to our smartphone or tablet, when they used batteries and are not close to grid socket. These devices incorporate, in a small volume, one or more rechargeable batteries Lithium Polymer, a battery charger (5V to 4.2V) and a switching power supply step-up to produce the 5V from 3.7V. The internal battery charger uses an external power supply common with micro USB connector, now standard for mobile phones and tablets, while the output 5V are available on a standard USB type A connector
With power from Vin, as in our case, you must include a switch that must be OFF when we insert the USB plug, otherwise you may be trouble to the power supplies or you can burn the small fuse on the Teensy board. On the same tour you can be interrupted with a cutter the thin runway under the card (for more information see the www.pjrc.com/teensy/ site), but no longer will be fed the other components of the system, such as the display, when you using the USB interface.

The wiring diagram

This scheme includes some components that are not used in this project as J2, J4 and J6 connectors, SD interface and the Lithium battery for Teensy RTC. Because all pins on the Teensy connectors are previously engaged, I used for the dip switches some signals from solder pads on the back side of the board. As can be seen in the following figure, I wired four signals (pins 24, 25, 26 and R) to a small connector J7, located on the back of the Teensy board. The following figure shows the wiring diagram of dip switch and pull-up resistors, mounted on the breadboard. The SW2 button is not used in this project.

With minor changes to the wiring diagram and the program you can connect the dip switches to the pins available on Teensy connectors and avoid soldering the wires on the pad. For example, renouncing the SD interface, you can use the pins 9, 10, 11 and 12.

The LCD40 board
For this project a breadboard has been used to securing and connecting all components. The following photo shows the arrangement of the components on the board and the frame used to support all other components.

As already mentioned, some components on the board are not used in this project. This is because I have made a versatile development system with a large alphanumerical LCD, a SD card interface and a real time clock for many applications as data logger for analog signals or for GPS.
The power bank seen in the photo has been replaced because, while being of good quality, disconnects the current after a few seconds since the system consumes too little.

The program
To compile the program I used the Arduino IDE (Version 1.8.1), adding the Teensyduino software add-on  (Version 1:35), for more details visit the website https://www.pjrc.com.
The setup() function, after initializing the I/O read the status of the dip switches to set the baud rate of the terminal, this value that is also printed on the display.
To realize a real serial terminal it would be better to have an automatic scrolling of received lines, so a buffer is necessary. I used a string array of 4x41 characters. A string size of 41 is necessary to represent a line of a maximum of 40 characters because strings have a null character (ASCII code 0) as a terminator.
For the first four lines received, the printing proceeds from line 0 to line 3. Subsequently, each new line is printed on line 3 while the other three previous lines are shifted up. This operation is done in the buffer: before transferring the last line received in the buffer#3, the current content of the buffer#3 is put in buffer#2 and so on until the contents of the buffer#1 is transferred to the buffer# 0. The whole behaves like a multidimensional shift register. After this process all the buffers are printed at one time on LCD.
The libraries for the controlling of the display have a command to run the scroll, but it refers to the line, and it does not work like the one proposed.
If a line exceeds 40 characters, the program truncates it before transferring to the buffer.
To make the system faster, I decided to read a line at a time instead of working on every single character.
As Teensy has more than one UART, unlike Arduino Uno, HWSERIAL should be used in place of Serial for all serial functions and the statement #define HWSERIAL Serial1 must be used to define the UART to be use (1 in our case).
The function HWSERIAL.readStringUntil('\n') reads a line to the terminator, which in our case is a CR / LF.
I used two types of strings: the linestr variable is a String class while the string array is a character arrays type. So I used the  function linestr.toCharArray(displayline[3],41); for the conversion.

Code
/*Serial terminal, print on a 40x4 LCD display,
  the library LiquidCrystalFast is used because it controls
  also display with double enable pins as that used
  Giovanni Carrera - 07/03/2017
*/
// include the library code:
#include <LiquidCrystalFast.h>
// set this to the hardware serial port used
#define HWSERIAL Serial1

const int Button = 22; // push button
const int DipSw1 = 23; // dip switch bit 1
const int DipSw2 = 24; // dip switch bit 2
const int DipSw3 = 25; // dip switch bit 3
const int DipSw4 = 26; // dip switch bit 4
const long baud_rate[9] = {1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
String linestr;
char displayline[4][41];// display buffers 4 rows x 40 characters
int r, i;
boolean ft_flag = true;// first time flag

// initialize the library with the numbers of the interface pins
//LiquidCrystalFast lcd(RS, RW, E1, E2, D4, D5, D6, D7);
LiquidCrystalFast lcd(21, 4, 2, 6, 17, 18, 19, 20);

void setup() {
  pinMode(DipSw1, INPUT); // set dip switch bits to input
  pinMode(DipSw2, INPUT);
  pinMode(DipSw3, INPUT);
  pinMode(DipSw4, INPUT);
  pinMode(Button, INPUT);
  // set up the LCD's number of rows and columns:
  lcd.begin(40, 4);
  // Print a message to the LCD.
  lcd.println("Serial terminal by GCar - 07/03/2017");
  // read dip switches for baud rate coding
  int brcode = digitalRead(DipSw1) + digitalRead(DipSw2) * 2 + digitalRead(DipSw3) * 4;
  lcd.print("Baud rate = ");
  lcd.println(baud_rate[brcode]);
  HWSERIAL.begin(baud_rate[brcode]);// for Teensy
  delay(5000);
  for (r = 0; r <= 3; r++) {
    displayline[r][0] = 0; // clear buffer
  }
  LCDprint(); // clear display
}

void LCDprint() {
  lcd.clear(); // clear diplay
  for (r = 0; r <= 3; r++) {
    lcd.setCursor(0, r); // set the cursor to column 0, line r
    lcd.print(displayline[r]); // print all four lines
  }
}

void loop() {
  r = 0;
  if (HWSERIAL.available() > 0) {
    linestr = HWSERIAL.readStringUntil('\n');
    if (ft_flag == true) {
      linestr.toCharArray(displayline[r], 41);// store line in buffer
      LCDprint();// print all four lines
      r++;
      if (r > 3) {
        r = 0;
        ft_flag = false;
      }
    }
    else {
      for (i = 0; i <= 40; i++) {
        displayline[0][i] = displayline[1][i];// scroll, line#0 = line#1
        displayline[1][i] = displayline[2][i];// scroll, line#1 = line#2
        displayline[2][i] = displayline[3][i];// scroll, line#2 = line#3
      }
      linestr.toCharArray(displayline[3], 41);// store new line in line#3
      LCDprint();// print all four lines
    }
  }
}

Friday, 30 September 2016

An isolated analog output for Arduino Uno

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 “phase­correct 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
1.      “Secrets of Arduino PWM”, Ken Shirriff, https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
2.      “Atmel 8-bit Microcontroller with 4/8/16/32KBytes In-System Programmable Flash”, 8271G–AVR–02/2013


Sunday, 7 August 2016

4-20 mA current output for Arduino Uno

The purpose of this project is to provide a 4-20 mA output from a PWM signal generated by a microcontroller ATmega328 and numerous other chips, such as the PIC. One of the more interesting applications of this circuit would be to replace or to realize a smart sensor with Arduino.

Last year I had designed a circuit suitable only for Arduino Due, this new work makes use of a common Arduino Uno or similar to create a standard 4-20 mA analog output.
Arduino Uno, or systems based on the ATmega328 chip has no a true analog output. The easiest way is to use one of the PWM outputs and filter the signal with a passive RC filter to obtain an analog signal proportional to the duration of the pulses. This expedient creates a considerable noise due to the frequency of the PWM itself. To eliminate the noise I used a second order active low-pass filter, Sallen-key type. The frequency of the Arduino PWM (with 16 MHz clock) on pin 9 is about 490 Hz, so I used a very low cutoff frequency (11 Hz) but with a bandwidth sufficient for the majority of industrial controls.

By connecting the filter directly to the PWM output is obtained a signal which varies from 0 to 5 V which would give an output current of 0 to 20 mA. The pulses duration is programmed with a word of 8 bits, losing 1/5 of the full scale. To improve the current resolution from 20/255 to 16/255, I modified the minimum amplitude of pulses from 0 to 1 volts, giving at the output a 4 to 20mA current. The block diagram is shown in figure 1.

Figure 2 shows the complete diagram of the circuit. To obtain pulses from 1 to 5 volts I had to use a 1 V source realized with U1A and the transistor Q1 that works as a switch. The operational U1B operates as a separator; the filter uses U1C and the voltage / current converter uses U1D and Q2.
The transistor Q1 inverts the PWM signal, so the software must complement the number of PWM duty cycle.

The trimmer pot Rp1 is used to adjust the minimum output current (4 mA) and the Rp2 to adjust the maximum (20 mA). The theoretical value of the emitter resistor is Re = 5/0.02 = 250 W, but that does not take into account the tolerances of the voltage supply of Arduino and of the resistors.
The resistor R8 is used as U1D output current limiter in the situation of absence of load.
A step down converter is a good solution for powering the system because of the 24 V, this value can be varied from 12 to 30 V, depending of the load circuit.
Arduino Uno has a +5 V output pin, It does not recommend using it as a power input          inasmuch this would be in parallel with the internal regulator but it can be powered at +5V using the USB connector, other boards as Arduino Pro Mini, have a +5 V input.

Hardware components
1x Arduino board,
1x Step-down switching converter,
Components list
R1= 27 kW ±5%
R2= 47 kW ±5%
R3= 10 kW ±5%
R4= 27 kW ±1% metal film
R5= 6.2 kW ±1% metal film
R6= 100 kW ±1% metal film
R7= 100 kW ±1% metal film
R8= 1 kW ±5%
R9= 270 W ±1% metal film
R10= 1.8 kW ±1% metal film
Rp1= 1 kW trimmer
Rp2= 10 kW trimmer
C1= 100nF Mylar
C2= 100 nF Mylar
C3= 200 nF Mylar
C4 = 10 MF,50V Electrolytic
C5 = 100 nF Mylar
U1= LM324 quad op amp
Q1 = 2N3904 or eq.
Q2= 2N2219A or eq.
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 200 nF and C2 have selected a value half of C3.  Q1 is a transistor that must have a low Vce(sat.) and Q2 must have a current gain of at least 100 and a Vceo of at least 40V with a minimum power of 500mW.
The operational amplifier U1 must be suitable also for single-rail power supply, such as LM324.
The components layout of my prototype is shown in Figure 3, the resistor on the top is a precision load used for calibration of the system. Q2 has a small heat sink because, with at 20 mA and a low voltage load,  as in this case,  dissipates: (24-3-5) *0.02 = 320 mW. In these circumstances is better to reduce the 24 v.
The test program
To test the system I used an Arduino with an LCD display and a potentiometer connected to analog input A0, as pin PWM I used D9. The program is very simple: read the potentiometer, converts 10 to 8-bit Analog reading and produces the PWM.

// program to test Arduino Uno PWM
// G. Carrera 2 ago 2016

#include <LiquidCrystal.h>

int PWMpin = 9;      // PWM out on digital pin 9
int analogPin = 0;   // potentiometer connected toA0
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 test");// Print a message to the LCD
}

void loop() {
  val = analogRead(analogPin) >> 2;// 10 to 8 bit conversion 
  analogWrite(PWMpin, val);
  lcd.setCursor(0, 1);
  lcd.print(spacestring);
  lcd.setCursor(0, 1);
  lcd.print(val);
  delay(500);
}

I reported on the spreadsheet the PWM values and the measurements in volts made on a precision resistor (150 W ±0.5%) that worked as a load,. The PWM / output current diagram is shown in Figure 4.
The linearity is very good as confirmed by the coefficient of determination R2 = 0.999992.
If you want a positive slope, the value must be complemented to 255 in this mode:
val = 255-val;
In my program, you could generate a new value every 500 milliseconds (2 Hz), but you could reduce this period of up to 100 ms (10 Hz).