HOME  > >  ARDUINO MAIN PAGE > >  HINTS AND HOW-TOs > >  NuELEC DATALOG  t.o.c.

Up to five Dallas 1-Wire temperature sensors

on an Arduino


This tutorial shows you how to access two or more Dallas 1-Wire digital temperature sensors, DS18B20s. Don't be scared by the "DS"... yes, this is a chip from Dallas's 1-wire family , but you don't have to deal with some of the fancier opportunities offered by the 1-Wire chips. You don't need the general Arduino 1-Wire library.

This is a shell, intended for expansion.

It reads a number of temperature (tture) sensors. And presents the values on the serial monitor.

But you wouldn't go to all this trouble just to read some sensors. You'd want to do something with those readings.

The place you add your code is marked in what is presented here.

(If you just want to capture the tture readings, an SD card makes a great choice, and recording what would otherwise go to the serial monitor is very easy if you spend a LITTLE money ($20), and very, very easy, and cheap ($5), with just a LITTLE work!)


Stop press, June 2019:

The same kind reader mentioned below sent some MORE code, 6/19. (If you find it useful... "pay it forward", support the Australian charity of Kind Reader's choice: Very Special Kids, if you want to show appreciation for the reader's kindness to us all. (On its website, Very Special Kids says that its mission is to support families of children with life-threatening conditions.))

This page is becoming a mish-mash... apologies! But I can at least give you a way to download the 6/19 version of the code. It uses one pin per temperature sensor. (I've simply put the .ino file online. Let me know if you have trouble downloading. As is usual for the Arduino IDE, you'll have to put it ("ar3ne1tt2-MultTture19609.ino") in a folder named "ar3ne1tt2-MultTture19609". You can, of course, assign your own name... but folder and .ino must agree.


Earlier stop press:

A helpful letter from a reader showed me places where this is wrong.

I believe the code that was here until 22 Feb 19 "worked"... I don't put things on the web without trying them (unless explicitly flagged as "off the top of my head")... but...

But the code shouldn't have worked! There were problems in how some timing issues that need paying attention to when using the Dallas DS18xx temperature sensing chips were being dealt with!

Also, even if it works, for it to be USEFUL, you need to know some things. (And it could still be written better. A user won't see different behavior, but the code will be written better... and achieve the same result in a different way. "Written better" is IMPORTANT, even when there are no functional changes.)

The timing issues

When you work with the Dallas chips, it goes like this:

Sigh. Sorry.

(By the way: Dallas calls the first part of "take reading" part as "doing a conversion"... the temperature around the sensor is "converted" into some numbers inside the sensor.)

The flow of the program as it was didn't need a complete rethink, but it did need some re-working.

The code does compile... but has not had further testing.. I have not hooked an Arduino with that code up to some chips, seen reading pour forth. But, "it should work". I hope that will be your experience, especially after I failed you and previously published BAD code... which did, I'm sure, "work". I just can't see how.

If you feel you want to ease into this subject more gently, I have a "How to connect one DS18B20 to an Arduino" essay for you.

There's also my more general introduction, an overview of using 1-Wire chips



In the "solution" on this page, we are taking the "simple/ expensive" route: We will be using a separate data line for each of the sensors we want to read. To put that a different way: We won't be using the power of the 1-Wire chips to co-exist on a little "network" of their own. (Such networks are called "MicroLans" (a trademarked term, which is helpful for Google searching!)

Know this: The program has to run for a bit (about 10 seconds) before you will have "good numbers" for five sensors. This is due to something in the nature of the Dallas temperature sensing chips that I will try to explain soon.

Those chips are worth the trouble, by the way!

The "answers", i.e. the readings from the sensors, will be in the elements of TReading. The first sensor reading is in TReading[0]. (They're also in other places, which we will come to in a moment.)

There's a "trick" you need to know about: If the sensor was exposed to, say, 12.7 degrees C, then in TReading[x] you will find 127. The temperatures are stored in tenths of Centigrade degree. (This avoids the hassle of dealing with floating point numbers.)

Ummm. Unless they are stored in CENTI degrees. TReading[x] might be holding 1274 to represent 12.74 degrees C. I'm a little confused on that point at the moment... and there may be flaws in the code, as a result. Let me know what you see, if you find the time and energy to bring this code to some hardware!

The "other places"... besides having nice simple integers in TReading[x], the ttures, in nice everyday ordinary degrees C, along with their nasty fractional parts, are in fT_c100[x].

And, to make printing the values easy, the integer part is in Whole[x] and the part to the right of the decimal point is, as an integer, in Fract[x]. (To go with Whole and Frac, there's something in SignBit[2] to say if the combined Whole+Frac positive degrees, or negative degrees. (I think the "something" will be a 0 or a 1, with 0 meaning the temperature was below zero. It will be something like that. Maybe the other way around.)

Other variables

There are some "trivial" arrays which may be useful to you, especially in presenting the data...

If sensor "2" returned 12.7 degrees C, then TReading[2] has 127 in it. Fine. That's going to be "the best" place to look for most things. But also, you'll have 12 in Whole[2], 7 in Fract[2], and something in SignBit[2] to say if that's positive 12.7 degrees, or negative 12.7 degrees. (I think the "something" will be a 0 or a 1, with 0 meaning the temperature was below zero. It will be something like that. Maybe the other way around.) (Whole[] will hold the absolute value of the tture, be it +ve or -ve.)


The heart of it all...

It might not look like it, but "all" you need to understand of the code farther down the page is....

void loop(){
   digitalWrite(13,!digitalRead(13));//To Pulse LED, to show prgm is running

   readTturePt1(tture[bWhichSensor]);//N.B.: Values passed back in globals

   delay(1900);//This is "wait for conversion" (see webpage)
   readTturePt2(tture[bWhichSensor]);//N.B.: Values passed back in globals
   delay(50);

   printTture();//N.B.: Takes values from globals.
   Serial.print("   ");

   if(bWhichSensor == 0){
      Serial.print("\n");//Start new line
   }

   bWhichSensor++;
   if(bWhichSensor == kTtureSensorMaxIndex+1){
      bWhichSensor = 0;
        }

/*"YOUR STUFF GOES HERE... if, for instance, you
making a fire alarm system, this is where you
put "if tture is too high, ring alarm bell".

-------------------
If you take steps to ensure that at least 1.9
seconds pass between the calls of...
      readTturePt1
    ... and...
      readTturePt2

 ... then, as long as you leave the pin associated
 with the sensor alone, you can "do things"
 during the time the system is waiting for the
 conversion to complete.
*/

}//end of loop()

Okay... the above and a few extra details is all you need to understand. We'll come back to the above in a moment. The details are....

At the head of the code (after user's needs tweakings), we have:

const byte kTtureSensorMaxIndex=4;//Make this 4 if you
  //want to use 5 sensors

//CARE This next one is a little tricky...
//If kTtureSensorMaxIndex = 4, then you need FIVE
//  numbers in the following array. They will
//  define which pins the temperature sensing
//  chips should go on.
//The number of numbers in the { }s must be
//  exactly kTtureSensorMaxIndex+1
//  (Arrays are zero based.)

//The following...
// const byte kTtureSensorMaxIndex=2;
// int tture[kTtureSensorMaxIndex] = {3,4,5};
//Would set the program up to deal with three
// temperature sensors. They would have to be
// on the pins for the GPIO lines 3, 4 and 5.

//kTtureSensorMaxIndex is set a little higher up
//   the page.

int tture[kTtureSensorMaxIndex+1] = {3,4,5,6,7};
//In the declaration, the number in [] is the COUNT
//  of array elements... not the index of the last.
//(The index of the last will be one less than the
//  count, as the first element of the array is
//  tture[0], by "name".

This tells the program which pins of the Arduino will be connected to the temperature sensors.

----
Then there's....

int TReading[kTtureSensorMaxIndex], SignBit[kTtureSensorMaxIndex],
        Whole[kTtureSensorMaxIndex],Fract[kTtureSensorMaxIndex];

float fTc_100[kTtureSensorMaxIndex];

... to create places to put the answers. (No rocket science there.)

----
And in the setup() function:

   for (bLoopCounter = 0;
     bLoopCounter <= kTtureSensorMaxIndex;
     bLoopCounter++)
   {
      pinMode(tture[bLoopCounter], INPUT);
      digitalWrite(tture[bLoopCounter], LOW);//Disable internal pull-up.
   }

Again... These are just routine configuration commands. Writing to an input might seem strange. We are making sure that the internal pull-up resistor which could be on the input is not connected, this time.

Everything else in the code is either basic, basic, general stuff, or "black box" stuff that you put in and leave alone, as is.

Details of what is in "loop()"...

I've done a Bad Thing in order to keep the code simple. I've used global variables: HighByte, LowByte, etc.

A particularly "bad" global variable is "bWhichSensor".

The way the program works is that it reads each temperature sensor in turn. And "bWhichSensor" keeps track of which sensor's turn it is.

It starts of at zero, due the way it was declared.

It goes 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1,...

... because of the bit of code at the bottom of loop().

The command "readTturePt1(xx)" tells the Arduino to go off and do the first step for checking one of the sensors. (Which sensor is checked is determined by what "xx" is.)

Then we must wait. (That's the way the 1-Wire chips work.)

Then, with "readTturePt2(xx)", we collect the raw numbers that the sensor now has ready for us, and put the relevant data into the various global variables concerned.

Then you can "printTture(xx)" to get the just fetched temperature displayed via the serial monitor.

That use of global variables is "poor programming"... but it works. It is a Bad Idea because it is easy for bugs to creep in and hide in such opaque programming. But The Right Way To Do It requires that you understand a complex data type, and I want this essay accessible to many readers.

That's really pretty well "it"!

Details of how to connect the sensor... really easy... and details of what goes on inside the "black box" parts of the program are covered in detail in my page about reading just one DS18B20.

Code for reading five DS18B20's on an Arduino....

Here is the code for reading five DS18B20's on an Arduino. (The number of sensors you can read is easily changed... just change the value in kTtureSensorMaxIndex.

New version, 23 Feb 19. The following HAS NOT BEEN TESTED, but it DOES COMPILE. I think it "should" work, and would commend it to you.

/*ReadDS18B20mk19222*/

 const String sPrgmName="ReadDS18B20mk19222";
 const String sVers="23 Feb 19";

 /*See...
  http://sheepdogguides.com/arduino/ar3ne1tt2.htm
  ... for explanation of this code.

The approach taken here is straightforward, but inefficient.

A serious problem arose 23 Feb 19 in working on this code
  in the Arduino compiler at a time when I couldn't do more
  that see if it compiles without complaint.
The problem was that parts of what I had suggested that
  this returns the temperature readings (tture) (in the
  elements of the array "TReading" in TENTHS of degree C...
  and other parts said the values were in HUNDREDTHS of degree C
There are further notes about this in the relevant place.

-------------------------------------------------------------
Started life as code adapted from nuelectronics.com demo

-------------------------------------------------------------
If for what you are doing, you need a more responsive system,
change the programming slightly...

   Send a "start conversion" to ALL of the sensors,
     one after the other. (Call readTturePt1 to send that)
   Wait 1.9 seconds.
   Read the ttures discovered, from ALL of the sensors,
     one after the other. (Call readTturePt2 to send that)


====================
OLD REMS---vers: 6 Jly 14- Modified by Brian (twice!) for 5 sensors,
better responsiveness. Derived from vers 18 July 2010
Started end of term eve WG/TA/LE/EW/JGB
*/

const byte pLED=13;//Set this to the line on which
//you will have an LED, tied to ground, through
//a resistor. (Such a resistor is available on the
//board for many Arduinos.)

const byte kTtureSensorMaxIndex=4;//Make this 4 if you
  //want to use 5 sensors

//CARE This next one is a little tricky...
//If kTtureSensorMaxIndex = 4, then you need FIVE
//  numbers in the following array. They will
//  define which pins the temperature sensing
//  chips should go on.
//The number of numbers in the { }s must be
//  exactly kTtureSensorMaxIndex+1
//  (Arrays are zero based.)

//The following...
// const byte kTtureSensorMaxIndex=2;
// int tture[kTtureSensorMaxIndex] = {3,4,5};
//Would set the program up to deal with three
// temperature sensors. They would have to be
// on the pins for the GPIO lines 3, 4 and 5.

//kTtureSensorMaxIndex is set a little higher up
//   the page.
int tture[kTtureSensorMaxIndex+1] = {3,4,5,6,7};
//In the declaration, the number in [] is the COUNT
//  of array elements... not the index of the last.
//(The index of the last will be one less than the
//  count, as the first element of the array is
//  tture[0], by "name".

byte bLoopCounter = 0;//used for misc loop counters.
    //Values in bLoopCounter do not need to persist
    //  in places not nearby where it is set.
    //In older versions of this code, "x" was used
    //  as bLoopCounter is now used.
    //It was made global only because having a
    //  variable for this sort of task is often useful.

byte bWhichSensor = 0;//This variable was called "count"
  //in earlier versions of this code.

//Following globals used to communicate results back
//from readTturePt1, Pt2, and to send data to printTture...

//See webpage for what they hold.

int TReading[kTtureSensorMaxIndex], SignBit[kTtureSensorMaxIndex],
        Whole[kTtureSensorMaxIndex],Fract[kTtureSensorMaxIndex];
//Whole[] holds the ABSOLUTE VALUE of the integer part
//  of the reading. E.g. for either 12.7 r -12.7, Whole
//  holds 12. (SignBit[] tells you if it is +ve or -ve.)

float fTc_100[kTtureSensorMaxIndex];

//----------------------------------------------------------
void setup() {
   //For each tture sensor: Do a pinMode and a digitalWrite
   for (bLoopCounter = 0;
     bLoopCounter <= kTtureSensorMaxIndex;
     bLoopCounter++)
   {
      pinMode(tture[bLoopCounter], INPUT);
      digitalWrite(tture[bLoopCounter], LOW);//Disable internal pull-up.
   }

   pinMode(pLED,OUTPUT);//Just so it can "pulse" to show Arduino
   // is working

   Serial.begin(9600);
   delay(300);//Wait for newly restarted system to stabilize
   Serial.println(sPrgmName);
   Serial.println(sVers);
   Serial.println();
   Serial.println("See http://sheepdogguides.com/arduino/ar3ne1tt2.htm");

   Serial.println("Temperature measurement, Multiple Dallas DSxxxx sensors");
   Serial.println("The 'S' value at the start of each line identifies the sensor reading was from.");
   Serial.println();
}//end of setup()

/*=========================================
The loop() subroutine:
It completes in just under 2 seconds.
Each pass fully reads one sensor, and adds a line
   to the serial monitor display.
The first pass processes sensor 0, the next
   sensor 1, and so on to sensor kTtureSensorMaxIndex.
After that, the next pass goes back, reads sensor0
   again. And thus the big cycle proceeds.

There is at least a second's "dead time" which,
   with careful coding, could be used for other
   things.
Even without clever coding, this is the place
*/

void loop(){
   digitalWrite(13,!digitalRead(13));//To Pulse LED, to show prgm is running

   readTturePt1(tture[bWhichSensor]);//N.B.: Values passed back in globals

   delay(1900);//This is "wait for conversion" (see webpage)
   readTturePt2(tture[bWhichSensor]);//N.B.: Values passed back in globals
   delay(50);

   printTture();//N.B.: Takes values from globals.
   Serial.print("   ");

   if(bWhichSensor == 0){
      Serial.print("\n");//Start new line
   }

   bWhichSensor++;
   if(bWhichSensor == kTtureSensorMaxIndex+1){
      bWhichSensor = 0;
        }

/*"YOUR STUFF GOES HERE... if, for instance, you
making a fire alarm system, this is where you
put "if tture is too high, ring alarm bell".

-----------------------------
If you take steps to ensure that at least 1.9
seconds pass between the calls of...
       readTturePt1
     ... and...
       readTturePt2

 ... then, as long as you leave the pin associated
 with the sensor alone, you can "do things"
 during the time the system is waiting for the
 conversion to complete.
*/

}//end of loop()

/*Everything below here... just copy it into your program "as is".

That "should work". (There may, alaa, be a problem in readTturePt2.
   See notes there.)

You are only likely to need to use readTture(pin) and printTture()
   directly. Others are subordinate to those.

These routines access the following global variables...
   int TReading[], SignBit[], fTc_100[], Whole[], Fract[];
   */

void OneWireReset(int Pin) // reset.  Should improve to act as a presence pulse
{
   digitalWrite(Pin, LOW);
   pinMode(Pin, OUTPUT); // bring low for 500 us
   delayMicroseconds(500);
   pinMode(Pin, INPUT);
   delayMicroseconds(500);
}//end  OneWireReset()

void OneWireOutByte(int Pin, byte d) // output byte d (least sig bit first).
{
   byte n;
   for(n=8; n!=0; n--)
   {
      if ((d & 0x01) == 1)  // test least sig bit
      {
         digitalWrite(Pin, LOW);
         pinMode(Pin, OUTPUT);
         delayMicroseconds(5);
         pinMode(Pin, INPUT);
         delayMicroseconds(60);
      }

      else
      {
         digitalWrite(Pin, LOW);
         pinMode(Pin, OUTPUT);
         delayMicroseconds(60);
         pinMode(Pin, INPUT);
      }

      d=d>>1; // now the next bit is in
                     // the least sig bit position.
   }
}//end OneWireOutByte

byte OneWireInByte(int Pin) // read byte, least sig byte first
{
   byte d, b;

   d=0;/*This critical line added 04 Oct 16
    I hate to think how many derivatives of
      this code exist elsewhere on my web pages
      which have NOT HAD this. You may "get away"
      with not setting d to zero here... but it
      is A Very Bad Idea to trust to "hidden"
      initializations!
    The matter was brought to my attention by
      a kind reader who was THINKING OF YOU!!!
    If YOU spot an error, please write in, bring
      it to my attention, to save the next person
      grief.*/

   for (bLoopCounter=0; bLoopCounter<8; bLoopCounter++)
     {
      digitalWrite(Pin, LOW);
      pinMode(Pin, OUTPUT);
      delayMicroseconds(5);
      pinMode(Pin, INPUT);
      delayMicroseconds(5);
      b = digitalRead(Pin);
      delayMicroseconds(50);
      d = (d >> 1) | (b<<7); // shift d to right and
         //insert b in most sig bit position
     }
   return(d);
}//end OneWireInByte()

void readTturePt1(byte Pin){
   /*This part starts the sensor doing a conversion,
       i.e. taking a reading, and storing result inside
       itself.
     This must be given time to complete. The time necessary
       is affected by how sensor is powered, and exact
       sensor time. 1.8 seconds (yes, nearly 1/30th of a minute!)
       should, off the top of my head, be enough, worst case.
     Other things can be happening while this is being
       "given time"... just don't disturb the chip.

     Pass WHICH pin you want to read in "Pin"
     Returns values in... (See global declarations)*/

   OneWireReset(Pin);
   OneWireOutByte(Pin, 0xcc);
   OneWireOutByte(Pin, 0x44); // request temperature conversion,
        //  maintain strong pullup while that is done.

}//end readTturePt1


void readTturePt2(byte Pin){
   /*This part starts asks the sensor for the reading
       it took "a moment ago", arising from the call
       of readTturePt1

     (This should have a "check that CheckSum isn't
       reporting a problem" added to it... or else
       a readTturePt3 should be added to do that.
       Not "necessary", but A Very Good Idea!)

     Pass the pin connected to the sensor you want
       to read in "Pin"
     Returns values in... (See global declarations)*/

int HighByte,LowByte;

   OneWireReset(Pin);
   OneWireOutByte(Pin, 0xcc);
   OneWireOutByte(Pin, 0xbe);

   LowByte = OneWireInByte(Pin);
   HighByte = OneWireInByte(Pin);

   //At this point, we SHOULD have the two bytes returned by the sensor safely
   //  captured in LowByte and HighByte.

   //Now we turn to combining them into a temperature reading in
   //  more usual units.

   //My work got confused... does this return the tture in
   //  TReading in TENTHS of degree C or HUNDRETHS of degree C?
   //The code down to "end of dubious section"... is quite suspect.
   //Remember, if you have to work on it, that some DS18xx chips encode
   //  the temperatures slightly differently than others. Sigh.
   //I'm not SURE which chip this encoding is right for...
   //I think it is the DS18B20 (and others using the same
   //data format.)

   TReading[bWhichSensor] = (HighByte << 8) + LowByte;
   SignBit[bWhichSensor] = TReading[bWhichSensor] & 0x8000;  // test most sig bit

   if (SignBit[bWhichSensor]) // negative

   {
      TReading[bWhichSensor] = (TReading[bWhichSensor] ^ 0xffff) + 1; // 2's comp
   }

   //At this point, we SHOULD have the two bytes returned by the sensor safely
   fTc_100[bWhichSensor] = (6.0 * TReading[bWhichSensor]) + TReading[bWhichSensor] / 4.0;
   //multiply by (100 * 0.0625) or 6.25

   Whole[bWhichSensor] = fTc_100[bWhichSensor] / 100.0;  // separate off the whole
      //number and fractional portions

   //Now remove the negative sign from negative values in Whole...
   if  (Whole[bWhichSensor]<0) {Whole[bWhichSensor]= Whole[bWhichSensor]*-1;};

   Fract[bWhichSensor] = round((fTc_100[bWhichSensor]-Whole[bWhichSensor])* 100);
}//end readTturePt2

void printTture(){//Uses values from global variables.

   //See global declarations.
   //N.B.: No new line inside printTture

   //First, provide ID of sensor to output...

    Serial.print("S");
    Serial.print(bWhichSensor);

   if (Whole[bWhichSensor] < 10)//To line up decimal points
   //This assumes that no tture will be < -99.9 or > +99.0
   //As these are in degrees C, that seems reasonable.
   //And if a very high tture is measured, it will only
   //slightly disturb the contents of the serial monitor.
   {
      Serial.print(" ");
   }

   if (SignBit[bWhichSensor]) // If it is negative
     {
       Serial.print("-");
     }//no ; here
    else
     {
        Serial.print("");
   };//end of if... then... else...

   Serial.print(Whole[bWhichSensor]);//Print the part of the reading
     //which falls on the LEFT of the decimal point
   Serial.print(".");

   if (Fract[bWhichSensor] < 10)
   {
      Serial.print("0");
   }

   Serial.print(Fract[bWhichSensor]);//Print the part of the reading
     //which falls on the RIGHT of the decimal point

}//end of printTture()

I hope the above Just Works for you. Do please write and "complain", if not, as you may be saving the next person hassle you have had.

The history of the code above...

Quite a while ago (at 7/14), I posted a starting point, probably derived from demos from Nuelectronics.

A kind reader sent in an improved version. Said kind reader is a supporter of the Australian charity Very Special Kids, if you want to show appreciation for the reader's kindness to us all. (On its website, Very Special Kids says that its mission is to support families of children with life-threatening conditions.)

The kind reader's version of the code, which went into what remains here, was for more temperature sensors, and improved the responsiveness of the program over my original. (You now can revise it to use few or many sensors.)

Subsequently, 2/19, another kind reader wrote, and brought further issues to my attention. Several hours later, the above was there for you. If YOU spot things, please contact me (Details below). Save the next person the questions that arose for you!

Hardware

Each sensor will connect to a separate data line. The sensor will also have to connect to ground. If it suits your circumstances, I would also eschew "parasitic powering"... but it should work, if you need it.

You will need to supply an external pull-up resistor on the data line. Getting the right value is a bit of a black art... consult other pages for details. Some will tell you "the right value", and if it works for you, great! But don't be surprised if you have to fiddle a bit to get good results. The good news: The chips will tell you if a reading is "bad". (One of the reasons a digital sensor is so much better than something analog!)

The End

That's pretty well it for "how to read one or more temperature sensors with a microprocessor, e.g. Arduino".

Back in the Bad Old Days when programming was Hard Work, I did quite a lot with Dallas 1-Wire chips. They have quite fantastic capabilities, of which the above code doesn't avail itself at all. If you are interested in learning more about 1-Wire chip programming, in a context probably more relevant to users of "big" computers, I offer you my tutorials about programming for the Dallas Semiconductor 1-Wire (tm) chips, as used on a MicroLan (tm). Those tutorials are written for Delphi (language) programmers, but they contain much information that would apply to other language environments. I also maintain pages which introduce MicroLans and explain the hardware.

NEW code, 22 Feb 19...

If you have things that derive from earlier versions: A few variables have been given better names. "Count" became bWhichSensor. X became bLoopCounter. Tc_100[] not only had an "f" pre-pended, but it also underwent a critically necessary change of data type from "int" to "float".



(Footer)

Going back to Arduinos (and away from Dallas 1-Wire), see also...

The Arduino programming course from Sheepdog Guides:

I have written a series of essays which try to help you become a better Arduino programmer and engineer... but, for the best result, you will have to buckle down and work your way through them in sequence. The collection of "How To's" this page comes from can be accessed in whatever order you like.



Feel free to use this information in programming courses, etc, but a credit of the source would be appreciated. If you simply copy the pages to other web pages you will do your readers a disservice: Your copies won't stay current. Far better to link to these pages, and then your readers see up-to-date versions. For those who care- thank you- I have posted a page with more information on what copyright waivers I extend, and suggestions for those who wish to put this material on CDs, etc.





Editorial Philosophy

See the discussion near the bottom of the "top level" page covering the bulk of my Arduino contributions. There is information there, too, about things like "May I copy your material?", and the system of file names I am trying to work to.


   Search this site or the web        powered by FreeFind
 
  Site search Web search
Site Map    What's New    Search

The search engine is not intelligent. It merely seeks the words you specify. It will not do anything sensible with "What does the 'could not compile' error mean?" It will just return references to pages with "what", "does", "could", "not".... etc.
In addition to the information about the nuelectronics data shield of which this page is part, I have other sites with material you might find useful.....

Tutorials about the free database which is part of the free Open Office.
Sequenced set of tutorials on Pascal programming and electronics interfacing.
Some pages for programmers.
Using the parallel port of a Windows computer.

If you visit 1&1's site from here, it helps me. They host my website, and I wouldn't put this link up for them if I wasn't happy with their service... although I was less than pleased the other day to have what I was doing interrupted by a telephone call from their sales team, trying to get me to extend my involvement. Sigh. Hardly a rare event, but I'd thought 1&1 were a bit classier that some of the people who have my telephone number.



Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows PC) please visit my freeware and shareware page, download something, and circulate it for me? Links on your page to this page would also be appreciated!

Click here to visit editor's Sheepdog Software (tm) freeware, shareware pages.


And if you liked that, or want different things, here are some more pages from the editor of these tutorials....

Click here to visit the homepage of my biggest site.

Click here to visit the homepage of Sheepdogsoftware.co.uk. Apologies if the "?Frmar3ne1tt2" I added to that link causes your browser problems. Please let me know, if so?

Click here to visit editor's pages about using computers in Sensing and Control, e.g. weather logging.



To email this page's editor, Tom Boyd.... Editor's email address. Suggestions welcomed!


Valid HTML 4.01 Transitional Page has been tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org. Mostly passes.

AND passes... Valid CSS!


Why does this page cause a script to run? Because of the Google panels, and the code for the search button. Why do I mention the script? Be sure you know all you need to about spyware.

....... P a g e . . . E n d s .....