Saturday, February 28, 2015

PDC1211: a 7 segments LCD




Abstract
The PDC1211 is a 7-segments display LCD. In this post we provide a library for dealing with this display. The library is strongly inspired by the classical LiquidCrystal library.

Main Characteristics
Module size (WxH):
95.6 x 32.6 mm
Active area (W x H):
77.4 x 16.8 mm
Viewing angle:
6:00
Driving voltage:
5V
Driving IC:
HT1621
Operating temp.:
-2O°C to 60°C
Storage temp.:
-30°C to 70°C
Manifacturer:
Nanjing Guoxian Electronics Corp

Figure 1. PDC1211: special symbols and pinout.


Introduction
The PDC1211 is a 7 segments LCD which is (was?) used mainly for telephony purposes. It has 12 7-segments digits and 7 special symbols. Figure 1 provides an overall view of the display and the position of the special symbols (numbered 1 to 7 in red). Indeed, more than symbols these seems to be sentences written in Chinese. Since I don't know Chinese, I have no idea of their meaning. Except for the 4th one which I got translated from a Chineese girl that I met in the train: "Local phone (number)". I would be grateful to any of you that could provide a translation for the remaining symbols/sentences.

Encoding a character
Concerning the representation of the digits, the PDC1211 follows the requirements of the HT1211 chip. Figure 2 shows the wiring of the backpane and Figure 3 the wiring of the frontpane. These are useful to compute the code values for the printable characters.


Figure 2. Wiring of the backpane.
Figure 3. Wiring of the frontpne.

Segment 0 of the memory mapping of the HT1621 corresponds to the leftmost digit. As illustrated in Figure 3, two memory segment adresses are used to encode a single character. Segments named a, b, c, d are the least significant bits and e, f, g, h. So to encode a 0 for example, one would set segments b, c, d in the first address and e, f, h in the other. Hence we obtain 0xE (or 0B1110) for the first segment and 0xB for the second. However, it is not recommended to write directly these values to the HT1621 but pass either through the write function or through the standard Print interface (see the dedicated section).

Configuration
Libraries. In order to work this library needs the following libraries installed: both of them can be downloaded from this website.
Pinout. The pins on the module are numbered 1 (leftmost) to 5 (rightmost) and are associated as in Figure 1 where SS is pin 1 and Vcc is the number 5. In our examples, pin 1 is connected to Arduino pin 2, pin 2 to Arduino pin 3 and pin 3 to Arduino pin 4.

Installing the library
As all Arduino's additional libraries, PDC1211 has to be installed in your local Arduino's library directory (look into Preference pane of your Arduino IDE to discover the path) in a directory called PDC1211/src. The documentation can be installed into PDC1211/doc.

Communication protocol
The communication between Arduino and the PDC1211 follows the same protocol as for the HT1621 but here Read/Write signals are on the same pin (RW) (see the documentation here for more details).

The print interface
This library implements the method of the Print interface of LiquidCrystal with all its advantages and all of its drawbacks. Moreover, remark that the type of the value to print is important, for example the following instructions all have the same effect of printing a '0' symbol on the LCD

lcd.print((char)0xBE);
lcd.print('0');
lcd.print("0");

while the following

lcd.print(0xBE);

will print a three character string "190" ie. the integer value of 0xBE.
Finally, since this is a 7 segments display and hence not all characters can be displayed. The set of displayable characters is reduced to: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, b, C, c, d, E, F, H, h, L, N, n, o, P, r, t, U, u, -, . and space.

The examples
The following snippet shows the typical usage of the library

// mandatory include files
#include "HT1621.h"
#include "LiquidCrystal7S.h"
#include "PDC1211.h"
// Pin connections 
#define SS 2
#define RW 3
#define DATA 4
// LCD class instantiation
PDC1211 lcd(SS,RW,DATA);

void setup() { ... lcd.begin(); ... }

void loop() { ... lcd.print("HELLO"); // print something ... }

All the examples shipped with LiquidCrystal library run as well exception made, of course, for those implying unsupported methods (see section next section).

Supported LiquidCrystal methods
Since PDC1211 is a child class of the LiquidCrystal7S class, it supports all of the methods of this class. However, they are a subset of those implemented by the LiquidCrystal library since they are impossible to implement in the context of a 7 segments display. Here is the full list of the unsupported methods:
  • cursor()
  • noCursor()
  • blink()
  • noBlink()
  • createChar()
  • blink()
  • noBlink()
  • createChar()

Downloads
The library consists in only one header and an implementation files:
And here it is the documentation both in pdf and html (zipped) formats:

Enjoy!

Sunday, February 15, 2015

LiquidCrystal7S: a library for 7 segments LCD based on HT1621 chipset




Abstract

This project aims at implementing the same functionalities as the classical LiquidCrystal library for 7 segments LCD based on the HT1621 chipset. The LCD is supposed to communicate with the HT1621 through a 3-wire or a 4-wire serial protocol. Remark that this wants to be a generic driver, hence only the basic features of 7 segments displays are implemented. All the other features such as displaying special characters or fine tuning should be implemented in a child class. Indeed, the driver is not aware of how memory is mapped to the LCD screen.

Configuration

LCD initialization.The display is initialized with 256KHz internal RC clock frequency, 1/3 Bias and 4 Commons. Refer to the manual of class HT1621 on how to change these settings.

Communication protocol. The communication protocol (3-Wire vs. 4-Wire) is chosen at the constructor level. Using the k-parameters constructor selects the k-Wire protocol.

The examples

As usual, here is a small example for testing the library. The sketch initializes the LCD and then writes a line of symbols 0xBE (this corresponds to '0' on my LCD). The sketch assumes a 12 digits LCD, if you has more (or less) digits please modify the range in the for loop.


/**
 * \file LiquidCrystal7S-test.ino
 * \brief Simple test sketch for the LiquidCrystal7S library.
 * \author Enrico Formenti
 * \date 8 february 2015
 * \version 1.0
 * \copyright BSD license, check the License page on the blog for more information. All this text must be
 *  included in any redistribution.
 *  <br><br>
 *  See macduino.blogspot.com for more details.
 */
#include "HT1621.h"
#include "LiquidCrystal7S.h"

// refer to Macduino website for pin connections 
// and their meaning

#define SS 2
#define RW 3
#define DATA 4

LiquidCrystal7S lcd(SS,RW,DATA);

void setup() {
  uint8_t i;
  
  lcd.begin(12, 1);

  // write all zeroes
  for(i=0; i<12; i++)  
    lcd.print((char)0xBE); // remark the cast here
}

void loop() {}

As a second example, here is a sketch which prints a string of three characters 0xBE (a '0' on my LCD).


/**
 * \file LiquidCrystal7S-test.ino
 * \brief Print a string using LiquidCrystal7S library.
 * \author Enrico Formenti
 * \date 8 february 2015
 * \version 1.0
 * \copyright BSD license, check the License page on the blog for more information. All this text must be
 *  included in any redistribution.
 *  <br><br>
 *  See macduino.blogspot.com for more details.
 */
#include "HT1621.h"
#include "LiquidCrystal7S.h"

// refer to Macduino website for pin connections 
// and their meaning

#define SS 2
#define RW 3
#define DATA 4

LiquidCrystal7S lcd(SS,RW,DATA);
const char str[] = {0xBE, 0xBE, 0xBE, 0};

void setup() {
  
  lcd.begin(12, 1);

  // write 3 zeroes
  lcd.print(str); // remark the definition of str here
}

void loop() {}

Downloads

The library consists just in the header and implementations files:
The documentation is provided both in html and pdf formats:

Thursday, February 12, 2015

HC-SR04 : using an ultrasonic module as a motion detector




Abstract

This week we are going to use our preferred ultrasonic sensor as a motion detection module. This is an alternative to the classical PIR sensors (see here) with its pros and contras that we will try to illustrate.

The idea

We are going to use the HC-SR04 to measure some default distance (background distance) B. At regular time frames we are going to measure a new distance, say D. If D is different from A, then this means that there is an obstacle between the sonar and B.

Computing the background distance

We assume that the sensor has been fixed on some support and that for a certain interval of time there are no objects that enter in the scene. From this post, the safe interval of times between two distinct distance measurements is 26ms. Therefore we are going to perform SAMPLESIZE measurements and take the average distance (rounded up) as background distance.


uint16_t SetupDefaultDistance() {
  
  uint64_t averageMillis;
  uint32_t i;

  for(i=0, averageMillis=0; i<SAMPLESIZE; i++) {
    averageMillis += readoutSensor();
    delay(INITDELAYMS);
  }
 
  // return the mean (rounded up)
  return (uint16_t)(averageMillis/SAMPLESIZE); 
}

Configuring the sketch

Using a different ultrasonic module. To configure the sketch for a different ultrasonic module, the just change the definition of INITDELAYMS which is the minimal time between two valid distance measurements. The duration of the trigger signal is configured by changing TRIGLENUS (expressed in microseconds).

Choosing sample size. The duration and precision of the computation of the calibration phase is regulated by the macro SAMPLESIZE which accounts for the number of measurements over which take the mean distance (ie the background distance). Of course, the larger this number the more precise will be the value of the background distance. However, remark that larger sample sizes require greater times to be computed. We think that setting it to 100 is a good trade-off.

Sensibility. As it is well-known, the measurements of our sensor are not perfect. Therefore, if we don't want to trigger alarm just because a measuring error, it is better to setup some tolerance for measurement errors. Tolerance is controlled by the macro TOLERANCE which contains a float number between 0 and 1 which stands for the percentage of errors that we accept. Of course, it is not wise to setup a tolerance which is lower than your sensor precision ;-)

The pinout. The sketch uses digital pins 2 (ECHO signal) and 4 (TRIGGER signal). If one needs to change them, just change the corresponding macro definitions TRIGPIN and ECHOPIN.

The complete sketch


/**
 * \file MotionDetection.ino
 * \brief Motion detection using an HC-SR04
 * \author Enrico Formenti
 * \date 9 february 2015
 * \version 1.0
 * \copyright BSD license, check the License page on the blog for more information. All this text must be
 *  included in any redistribution.
 *  <br><br>
 *  See macduino.blogspot.com for more details.
 */

// the include below is for old versions of the IDE
// #include <Serial.h>

#define SAMPLESIZE 100
#define TOLERANCE .01
#define INITDELAYMS 26
#define TRIGLENUS 10

// trigger pin of HC-SR04
#define TRIGPIN 4 
// echo pin of HC-SR04
#define ECHOPIN 2

uint16_t defaultMS;
uint16_t curMillis;
uint16_t millisTolerance;

uint16_t readoutSensor() {
  // The sensor is triggered by a HIGH pulse of 10us or more.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  digitalWrite(TRIGPIN, LOW);
  delayMicroseconds(3);

  // Start trigger signal

  digitalWrite(TRIGPIN, HIGH);
  delayMicroseconds(TRIGLENUS);
  digitalWrite(TRIGPIN, LOW);
 
  // Read the signal from the sensor: a HIGH pulse whose
  // duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
 
  return pulseIn(ECHOPIN, HIGH);
}

uint16_t SetupDefaultDistance() {
  
  uint64_t averageMillis;
  uint32_t i;

  for(i=0, averageMillis = 0; i<SAMPLESIZE; i++) {
    averageMillis += readoutSensor();
    delay(INITDELAYMS);
  }
 
  // return the mean (rounded up)
  return (uint16_t)(averageMillis/SAMPLESIZE); 
}



void setup() {

  // setup pins
  pinMode(TRIGPIN, OUTPUT);
  pinMode(ECHOPIN, INPUT);

  // init serial communication
  Serial.begin(9600);

  // compute background distance
  Serial.print("Computing defaults...");

  defaultMS = SetupDefaultDistance();
  millisTolerance = (uint16_t)(defaultMS * TOLERANCE);
  
  Serial.println("Done."); 
}

void loop() {
  uint16_t val;
  
  curMillis = readoutSensor();

  if ( curMillis>defaultMS) 
    val = curMillis-defaultMS;
  else
    val = defaultMS - curMillis;
        
  if( val > millisTolerance)
    Serial.println("Motion detected!");
 
  delay(INITDELAYMS);
}

Remark that in the sketch all the distances etc. are expressend in milliseconds since there is no point to transform them into real distance. Indeed, we just want to measure differences!

Detection failures

If an object runs through the sensing cone of the HC-SR04 fast enough, then the sensor may fail to detect it. Indeed, assume that the sensing cone is 30 degrees wide (horizontally) and that an object traverses the cone at some distance d in a direction which is parallel to the sensor as illustrated in Figure 1. The HC-SR04 is positioned at the bottom of the triangle.
Fig. 1. Example of detection failure.
Then, with simple trigonometric calculations we may find that the speed v is given by the formula given in Figure 1, where td is the time that takes the sound wave emitted by the HC-SR04 to travel the distance d. For example, if d=4m then v is about 91 m/s.

HC-SR04 vs. PIR sensor

Each of these two modules has its own precise purpose which is distance measuring for HC-SR04 and motion detection for a PIR sensor. It is pretty clear that a PIR sensor cannot be used for distance measuring; however, an HC-SR04 can be used as a motion detector as it is proved by our previous sketch. Let us try to list advantages and disadvantages.

Advantages
  • Multipurpose: the HC-SR04 can be reverted for measuring distances; then back to motion detection and so on.
  • Configuration: the HC-SR04 can be quickly reconfigured completely via software; while, in general, PIR sensors need manual hardware configuration.
  • Initialization: can be pretty fast on the HC-SR04 (2-3 seconds); while it is a least 10 seconds on most PIR sensors.
Disadvantages
  • Sensing cone: PIR sensors have large sensing cones while the cone of HC-SR04 is very few degrees wide vertically and less than 30 degrees horizontally.
  • Speed: of course, light speed (PIR sensor) is incomparably higher than sound speed (HC-SR04).
  • CPU usage: the HC-SR04 needs to send signals periodically in order to detect motion and this uses CPU of course. On the other hand, PIR sensors are passive sensors, so they need CPU only when a motion is detected (if they are attached to an interrupt).
  • Detection failures: because of its low speed, the HC-SR04 may fail to detect a fast enough moving object (see the dedicated section); while this is nearly impossible for PIR sensors.

See also

HC-SR04: avoiding oversampling errors
HC-SR04: what is the distribution law for the frequencies of values? (Part 2)
HC-SR04: what is the distribution law for the frequencies of values? (Part 1)
HC-SR04 : using multiple ultrasonic modules
Introduction to HC-SR04

Conclusions

Each module is designed for its own purpose. However, turning an HC-SR04 into a motion detector can be useful in some situations.

Enjoy!

Friday, February 6, 2015

HT1621: a seven segments LCD driver




Abstract
This note resumes the main characteristics of the HT1621 chip that are useful to drive 7-segments displays on Arduino boards.

Main Characteristics
Memory:
32x4 bits RAM (i.e. enough for 32x 7-seg displays with dot)
Operating voltage:
2.4V-5.2V
Power Consumption:
<3mA (@5V)
Power Consumption:
<600μA (@5V with no load, LCD on, internal RC oscillator on)
Clock (built-in):
256kHz RC oscillator
Clock (external):
32kHz quartz oscillator or 256kHZ external input
Comm. interface:
3-wire serial interface
Additional features
Comm. interface:
3-wire serial interface
Tone buzzer:
built-in 2kHz or 4kHz tone buzzer
Data accessing:
three accessing modes
Block diagram
Here is the functional block diagram directly extracted from the Holtek datasheet. In the sequel we will describe each of these blocks.

Figure 1. HT1621: functional block diagram.

Sunday, February 1, 2015

FM radio receiver for your Arduino (TEA5767/TEA5768/TEA5757)
(Part 4/4)




Abstract

In this last part we provide a basic front-end for the FM radio and a simple example program. Moreover, we provide full documentation for all the TEA library and their classes.

This project is a simple implementation of a FM Radio player based on the FM module. The radio has a simple front-end consisting of the LCD module and its buttons. The are five possible working modes. For more details on the working modes see the Section "Using the radio".

Building the radio

Just stack the LCD module (more infos here) on your Arduino and connect the FM module as explained here. That's all!

Display and buttons

In all working modes (except for the sub-modes) the information is displayed in a standard format on the LCD. The first line indicates the frequency of the current station being reproduced (approx to 2 decimal digits) and the current working mode. The second line displays the audio level (a number between 0 and 16) and if the reception is stereo or mono. The following figure gives a more visual illustration of the display organisation.
Figure 1. Display organisation in main working modes.

The radio uses 4 out the 5 buttons on the LCD module (the leftmost ones). The leftmost button (button 1) and the its neighbor (button 2) are used as navigation buttons. In standard mode (STD), they are used to search backward (resp. forward) for the next station to reproduce. In recording mode (REC) and in memory mode (MEM), they are used to move backward or forward in the memory array. Button 3 is called mode button and it is used to change the working mode. Button 4 is called action button and it is used to confirm actions for the current working mode. For example, when choosing a memory slot for memorizing the current station in the memory array, if this button is pressed then the frequency of the current station is recorded and the radio returns in STD mode. The following figure illustrates buttons positions.
Figure 2. Buttons of the LCD module.

Warning For lack of space when displaying information on the LCD, some shortcuts are used. For example, btn means "button" and act means "action", etc.

Using the radio

At power on time, the radio is tuned at frequence 87.5 MHz on the US/European FM band, if a station is present then the radio starts reproducing it, otherwise noise is heard. Standard mode (STD) is activated. All entries of the memory array are initialized at 87.5MHz. The backward and forward buttons can be used to select other stations in the band. The search for the next station wraps around the band limits.

Using the mode button, the working mode can be changed. The radio has five operating modes:
  • standard (STD): we just described this.
  • recording (REC): in this mode the user can save the current frequency to memory. The user is prompted to choose a slot in the memory in which to store the frequency of the current station. Once the slot number is chosen, press the action button to confirm selection. Use the forward/backward buttons to navigate in the memory array.
  • memory (MEM): reproduces the station memorized at current position in the memory array. Use the forward/ backward buttons to navigate in the memory array.
  • preselect (PRE): this mode automatically preselects the stations with better reception level (SEARCH_LEV_MEDIUM) and memorize them into the memory array. The scan is started from the current frequency toward the superior band limit and restarts from the inferior band limit if the memory has not been completely filled. The filling of the memory follows a greedy policy. The scan is stopped if after two successive trials no station is found.
  • standby (SBY): sets the radio in standby. Press action button to return in STD mode.

Configuration and fine tuning

Configuring the front-end. The radio class has been kept as simple as possible. In this way its configuration is very simple. All you need to edit it is the file FM_Radio_Config.h and update information about the pins used by the LCD module. You need also to specify the size of the memory array (constant MEMOMAX) that will be used by the radio to store the frequency of your preferred radio stations.

Configuring the FM module. The radio is configured to work with EU/US band limits. If you want to change japanese band limits, then you have to replace EUROPEAN_FM_BAND by JAPANESE_FM_BAND in function TEA576X::begin(). Please check also the working parameters of your FM module (crystal frequency, etc) and configure them accordingly. Remark also that high side injection is selected by default.

Delays. In the reading and write operations (immediately after them) it is often used a delay to allow the operation to finish. The delays are sometimes overestimated to be sure to work with most modules. Maybe the user can change them to adapt more closely to his module and increase the overall performances.

Also in the front-end (FM_Radio.cpp) a number of delays are set. Also those can be change to improve performance or user experience.

Test sketch

The simplicity of the design allows to run our radio with a very simple sketch.

#include <SPI.h>
#include <Wire.h>
#include <LiquidCrystal.h>
#include "FM_Radio.h"
FM_Radio radio;
void setup() {
  radio.begin(LCD_BTN, MEMOMAX);
}
void loop() {
  radio.loop();
}

Documentation

You may download the full documentation about all classes in this article series in the following formats:

See also