More to come!
Here is a schematic of the external hardware:
Figure 1: External Hardware |
======================================================
ARDUINO SKETCH FOLLOWS BELOW
======================================================
A few changes:
I added the means to change the brightness and scroll-rate using external analog signals. Two ordinary pots wired between 0 and +5V (variable voltage divider), with the wiper going to the respective analog pin is all you need. These parts are not shown in the above schematic.
The code for both is present, however, only the Brightness Control is activated. The scroll rate code is currently commented out, with a fixed scroll rate of 8 char/sec. Please find the relevant section of code (shown below) in the sketch, and follow the directions.
/* ---------------------------------------------------------------------
To use an external analog signal controls scroll rate, 4 to 20 char/sec:
t1Preset = map(analogRead(scrollSpeed),0,1023,250,50);
(Comment out the line above, "t1Preset = 125;"
------------------------------------------------------------------------*/
/*
DHT22 SCROLLING TEMPERATURE AND HUMIDITY DISPLAY
---------------------------------------------
Author: EasternStarGeek, Johnson City, TN
Date: 27 August, 2011
---------------------------------------------
This sketch reads a DHT22 Temperature and Humidity Sensor and displays the
readings on a 3-digit, 7-segment display.
The three readings scroll by, "Marquee" fashion: Temperature in Degrees F, Temp. in Deg. C, and Percent relative Humidity.
Normal Display Format:
(+/-)XXX.y *F (+/-)XXX.y *C XX.XH
(If the senor returns invalid data, all values will show "-999.9")
Readings repeat in between display updates.
Hardware:
Controller: Adafruit DC Boarduino
Sensor: DHT22
- 10K, 1/4W Resistor
Display:
- 7-Segment LED, 3-Digit, Common Cathode
- 74HC595 Shift Register
- 220 ohm, 1/4W resistors (8)
- 2N2222 Digit Drivers (3)
- 10K, 1/4W Resistors (3)
For a complete schematic of th external hardware, please see details in my blog:
http://easternstargeek.blogspot.com/2011/08/dht22-temperaturehumidity-sensor.html
This software uses the Adafruit DHT Sensor Library:
https://github.com/adafruit/DHT-sensor-library
*/
// Include Library:
#include "DHT.h" // DHT Sensor Library
// Hardware Connections to I/O Pins:
#define DHTPIN A0 //DHT22 Data Pin
// Note: The sensor data is digital. Any I/O Pin can be used.
const int dataPin = 11; // 74HC595 Shift Register Data, IC Pin 14
const int clockPin = 12; // 74HC595 Shift Register Data Clock, IC Pin 11
const int latchPin = 8; // 74HC595 Shift Register Latch Clock, IC Pin 12
// Arduino pins for Digit Driver Transistors: 1(MSD), 2, 3(LSD)
const int digitEnable[3] = {
2,3,4}; // Array holding pin numbers for Digit Driver transistors
const int brightLevel = A5; // Analog pin for Brightness Control
const int scrollSpeed = A4; // Analog pin for Scroll Rate Control
// Global Declarations:
#define DHTTYPE DHT22 // DHT 22 (AM2302)
DHT dht(DHTPIN, DHTTYPE); // Declare Sensor Class
// Lookup Table containing all segment patterns used in this project:
// Character Set:
// 0,1,2,3,4,5,6,7,8,9,<null>,H,t,C,F, -, _, =, <deg symbol>
// Mapping of Display Segments by bit: (MSB) dp,g,f,e,d,c,b,a (LSB)
const byte LUT_Chars[20] = {
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,
0x00,0x76,0x78,0x39,0x71,0x40,0x08,0x48,0x63};
// Proxies for non-numeric characters:
const int chr_nul = 10; // Pointer to pattern for null (blank) character
const int chr_H = 11; // Pointer to pattern for 'H'
const int chr_t = 12; // Pointer to pattern for 't'
const int chr_C = 13; // Pointer to patterrn for 'C'
const int chr_F = 14; // Pointer to pattern for 'F'
const int chr_min = 15; // Pointer to pattern for dash (minus sign)
const int chr_usc = 16; // Pointer to pattern for underscore
const int chr_equ = 17; // Pointer to pattern for equal sign
const int chr_deg = 18; // Pointer to pattern for degree symbol
int valLength; // Length of returned numerical substring after conversion
int numFieldChars[5]; // Global array hilding converted numerical subsrting
int CharBuffer[3]; // Buffer holding segment patterns for currently displayed digits
int Brightness = 255; // Brightness Level, 1 to 255
unsigned int T_On; // LED ON Time // For display brightness control
unsigned int T_Off; // LED OFF Time // For display brighness control
int pointerScroll; // Index to Character Buffer (1=MSD, 3=LSD)
int SCR = 10; // Sequence Control Register, used w/ Switch/Case
int DisplayLine[47]; //Array holding segment patterns
// for the entire string to be displayed, pre-scroll
int pointerDL;
float h; //Raw sensor data, Percent Relative Humidity
float tc; //Raw sensor data, Temperature, Degrees Celsius
/* Timers:
This project uses a Timer Services that run on every scan, making use of the millis()
function. This allows the code to scan continuously with minimal wait-states
*/
// Declare Timer 1 Variables
boolean t1Bit; // Timer 1 Control Bit
boolean t1Edge; // Timer 1 Edge Bit
long t1Preset; // Timer 1 Preset
long t1Temp; // Timer 1 Temporary Value
long t1Remain; // Timer 1 Word
// End Timer 1 Variables
void setup() {
Serial.begin(9600);
dht.begin(); // Initialize Sensor Functions
// I/O Pin Modes::
pinMode (dataPin, OUTPUT);
pinMode (clockPin, OUTPUT);
pinMode (latchPin, OUTPUT);
for (int i=0; i<3; i++) {
pinMode(digitEnable[i], OUTPUT);
}
pinMode (brightLevel, INPUT);
pinMode (scrollSpeed, INPUT);
}
void loop()
{
// Switch/Case used to control delayed sequential processes without wait-states
switch (SCR)
{
case 10:
// ======== Get Raw Sensor Data ==============================
h = dht.readHumidity(); //Get the Humidity Data
tc = dht.readTemperature(); // Temperature in deg C (Float)
// check if returned sensor data is invalid, put in dummy data so
// that all temp and humidity values will read "-999.9"
if (isnan(h) || isnan(tc))
{
h = -999.9;
tc = -999.9;
}
// ======== Build the Display String ============================
/* Containing the 7-segment patterns for the entire
assembled message, pre-scroll:
*/
pointerDL = 0; // Initialize the Display Line Pointer
// Start the Display Line with three null characters
for (int n=0; n<4; n++) { // Add four blanks to the Display Line
DisplayLine[pointerDL] = LUT_Chars[chr_nul];
pointerDL +=1; // Increment the Pointer
}
//Convert the Temperature Data into Fahrenheit, and convert it to a 7-segment pattern:
valLength = float_to_SevenSegment((tc * 1.8)+ 32);
// Copy the Temperature Substring to the Display Line
for (int i=0; i < valLength; i++) {
DisplayLine[pointerDL + i] = numFieldChars[i];
}
pointerDL += valLength;
// Add the Degree Symbol character, the 'F' character, and three null (blank) characters
DisplayLine[pointerDL] = LUT_Chars[chr_deg];
pointerDL +=1; // Increment the Pointer
DisplayLine[pointerDL] = LUT_Chars[chr_F];
pointerDL +=1; // Increment the Pointer
for (int n=0; n<4; n++) { // Add four blanks to the Display Line
DisplayLine[pointerDL] = LUT_Chars[chr_nul];
pointerDL +=1; // Increment the Pointer
}
// Convert the Celsius Temperature to a 7-segment pattern:
valLength = float_to_SevenSegment(tc);
for (int i=0; i < valLength; i++) {
DisplayLine[pointerDL + i] = numFieldChars[i];
}
pointerDL += valLength;
// Add the Degree Symbol character, the 'C' character, and three null (blank) characters
DisplayLine[pointerDL] = LUT_Chars[chr_deg];
pointerDL +=1; // Increment the Pointer
DisplayLine[pointerDL] = LUT_Chars[chr_C];
pointerDL +=1; // Increment the Pointer
for (int n=0; n<4; n++) { // Add four blanks to the Display Line
DisplayLine[pointerDL] = LUT_Chars[chr_nul];
pointerDL +=1; // Increment the Pointer
}
//Get the Humidity Data, and convert it to a 7-segment pattern:
valLength = float_to_SevenSegment(h);
// Copy the Humidity Substring to the Display Line
for (int i=0; i < valLength; i++) {
DisplayLine[pointerDL + i] = numFieldChars[i];
}
pointerDL += valLength;
// Add the 'H' character and three null (blank) characters
DisplayLine[pointerDL] = LUT_Chars[chr_H];
pointerDL +=1; // Increment the Pointer
for (int n=0; n<3; n++) { // Add three blanks to the Display Line
DisplayLine[pointerDL] = LUT_Chars[chr_nul];
pointerDL +=1; // Increment the Pointer
}
/* Diagnostics:
Serial.print("Humidity: ");
Serial.print(h);
Serial.print(" % ");
Serial.print("Temp: ");
Serial.print(tc);
Serial.print(" *C ");
Serial.print((tc * 1.8)+ 32);
Serial.println(" *F");
// Print out contents of Display "String"
for (int j=0; j<pointerDL; j++)
{
Serial.print(DisplayLine[j],HEX);
Serial.print(" ");
}
Serial.println();
*/
pointerScroll = 0; // Initialize the Marquee Pointer
SCR = 20;
break;
// ======= Scroll the 3-character Display over the Display Line =========
case 20:
// Update the contents of the three LED Digits
if (pointerScroll <= (pointerDL - 3))
{
CharBuffer[0] = DisplayLine[pointerScroll];
CharBuffer[1] = DisplayLine[pointerScroll + 1];
CharBuffer[2] = DisplayLine[pointerScroll + 2];
pointerScroll +=1;
// Set Timer to 125mS for scroll delay
t1Preset = 125;
/* ---------------------------------------------------------------------
To use an external analog signal controls scroll rate, 4 to 20 char/sec:
t1Preset = map(analogRead(scrollSpeed),0,1023,250,50);
(Comment out the line above, "t1Preset = 125;"
------------------------------------------------------------------------*/
t1Bit = 1;
SCR = 30;
}
else
{
SCR = 10; // Get another Reading
}
break;
case 30:
if (!t1Bit) // When Timer expires, scroll the next character
SCR = 20;
break;
} // End of Switch/Case statement for SCR
// ################################################################
// ################################################################
// ###################################################
// ################## SERVICES #######################
// ###################################################
// Multiplex 3-digit 7-segment display
/* Here is a line of code that allows you to control the
display brightness with an external analog voltage: */
Brightness = map(analogRead(brightLevel),0,1023,1,255);
// If not using this feature, substitute a number between 1 and 255
Brightness = constrain (Brightness,1,255); // Traps bad Brightness Level Data
T_On = Brightness * 20;
T_Off = (256 - Brightness) * 20;
// Scan the three digits once
for (int i=0; i < 3; i++)
{
// Transmit Segment Data for current digit to the Shift Register:
digitalWrite(latchPin, LOW);
shiftOut (dataPin, clockPin, MSBFIRST, CharBuffer[i]); // Shift out Byte
digitalWrite(latchPin, HIGH);
// Energize Digit Driver for current Digit
digitalWrite(digitEnable[i], HIGH);
// Leave energized, according to Brighness Level
delayMicroseconds(T_On);
// Blank Digit Outputs according to Brighness Level
digitalWrite(digitEnable[0], LOW);
digitalWrite(digitEnable[1], LOW);
digitalWrite(digitEnable[2], LOW);
delayMicroseconds(T_Off);
}
// ### END Display Multiplexing ###
// ********** Pulse Timer Service **********
/* This timer runs as a service, allowing delayed sequences to be built without hanging-up
the rest of the project code
When the sequence wants to use the timer, it must specify the Time Delay (t1Preset)in milliseconds,
and then set the Timer Bit (t1Bit = HIGH).
From that point forward, the Timer Service will keep track of the elapsed time (via the millis() function).
When the time interval expires, the Timer Service will reset the Timer Bit (t1Bit) which can be checked by
code running elsewhere.
*/
// arm the timer
if (t1Bit && !t1Edge)
{
t1Edge = HIGH;
t1Temp = millis();
t1Remain = t1Preset;
}
// decrement the Timer Word as long as the timer is active
if ( t1Edge )
{
t1Remain = t1Remain - abs(millis() - t1Temp);
t1Temp = millis();
}
// check for timer expiration (Timer can also be cancelled by forcing t1Bit to LOW)
if ( (t1Remain <= 0) || !t1Bit )
{
t1Bit = LOW;
t1Edge = LOW;
t1Remain = 0;
}
// *** END Pulse Timer 1 ***
} // Loop Procedure End
// #######################################################################
// #######################################################################
/*
*****************
*** FUNCTIONS ***
*****************
*/
/* CONVERT FLOATING POINT VALUE TO 7-SEGMENT CHARACTER ARRAY
Display Format: -999.9 TO 999.9, with one fixed decimal place
Return Value = "String Length"
(The "string" is a series of 1-byte segment patterns, not an actual ASCII string)
Notes:
a. The decimal point does not occupy a character position, but
is incorporated into the units digit.
b. Numbers between -0.9 and 0.9 are always displayed with a leading zero.
c. Over/under range values are displayed as "999.9" or "-999.9" respectively
*/
int float_to_SevenSegment (float inputVal) {
// Declare local function variables
int numFieldVal[5];
// Constrain input value
inputVal = constrain (inputVal, -999.9, 999.9);
// Convert constrained Float to Word * 10, display as 1 Fixed decimal place
int inputInt = word(inputVal*10);
// Clear Array
for (int i=0; i<5; i++) {
numFieldVal[i] = chr_nul;
}
int charPos = 0; //Initialize Character Position Pointer
// Is Input Value Negative?
if (inputVal < 0)
{
inputInt = inputInt * -1; // Negate Input Integer
numFieldVal[charPos] = chr_min; // Insert a Minus Sign
charPos +=1; // Increment the Character Position Counter
}
// Round-off Integer value
if ((inputVal*10) - inputInt >= 0.5)
inputInt +=1;
// if Input value is less than 100.0
if (inputInt < 1000)
{
// if Input is less than 10.0
if (inputInt < 100)
{
numFieldVal[charPos] = inputInt /10 ;
numFieldVal[charPos+1] = inputInt % 10;
charPos +=2; // Increment the Character Poaition Output by 2
}
// if Input is greater than 10.0
else
{
numFieldVal[charPos] = inputInt / 100;
numFieldVal[charPos+1] = (inputInt - numFieldVal[charPos]*100)/10 ;
numFieldVal[charPos+2] = (inputInt - numFieldVal[charPos]*100) % 10;
charPos +=3; // Increment the Character Poaition Output by 3
}
}
// if Input is greater than or equal to 100.0
else
{
numFieldVal[charPos] = (inputInt) / 1000;
numFieldVal[charPos+1] = (inputInt - numFieldVal[charPos]*1000) /100 ;
numFieldVal[charPos+2] = (inputInt - numFieldVal[charPos]*1000 - numFieldVal[charPos+1]*100)/10 ;
numFieldVal[charPos+3] = (inputInt - numFieldVal[charPos]*1000 - numFieldVal[charPos+1]*100)%10 ;
charPos +=4; // Increment the Character Poaition Output by 4
}
// Fetch the Segment Patterns
for (int i=0; i<=charPos; i++) {
numFieldChars[i] = LUT_Chars[numFieldVal[i]];
if (i == charPos-2) //is the current digit the units digit?
numFieldChars[i] += 0x80; //set bit 7 (dp)
}
return charPos;
}