12Bit A-D Converter Revisited

The original version of this project dates from 1998. Although it's handy to have and I use it mainly with "clip-on" temperature sensors made from small plastic clothes-pegs with surface mount format LM335 sensors. However, it has some drawbacks:

  • The output is in hexadecimal - fine for computer logging, but not so easy for people to read
  • The output is only terminated with a linefeed character, so the output appears to "staircase" down the screen
  • The output comes at "top-speed", as fast as the 9600Baud connection can handle

What I had been meaning to do was to update the software, while leaving the hardware as it was. To this end, I decided the simplest solution was to rewrite the code in HiTech C, using their free compiler for the 8-bit PIC devices. As it turned out, due partly to a bug I keep running into, where the "mod" (in C it's the percent: % operator) function overwrites crucial variables in low memory. Since I used this function to convert the 12-bit measurements from the ADC into decimal, I found some code that performs this binary to BCD function - however it's written in assembler. This had the added advantage that it's a lot faster. When I was profiling the executable in MPLAB the time taken to do the binary - ASCII conversion in C was about something around 17mSec (with the PICs 1MHz clock). Add on another 7 mSec for my C-written SPI code (see the speech recorder project) and it was taking close to 200mSec to read, convert and transmit a line of 8 readings - one from each channel of the A-D convertor. I felt this was too long, so using the assembler routine to get BCD numbers, and another assembler routine I wrote to perform the SPI function, I was able to get the time to send a line below 100mSec - which allowed me to send 10 lines of data per second - fast enough.

I also chose to add a timer interrupt, that was executed every 10mSec. this gave me a timestamp (which I implemented as 6 BCD digits, rather than binary) The code is clumsier, but faster to convert to ASCII. The timer also allowed me to get lines of output at preset times - rather than starting the next line immediately after the previous one had finished.


I also updated the circuit diagram, which is here. While writing the new version I did come across some timing problems with the bit-banged 9600Baud output. Although I lifted the serial output routine from the original, I did remove a couple of nops from it's delay code, to get the bit timings right.

The new code is here with the assembler routines in here.

Note

During the development I discovered that two of the ADC channels were reporting the same data, and that another channel wasn't showing anything at all. Obviously, I suspected some screw-ups in my software - notably the SPI routine. However, after about 3 days of trying different things, including dumping out the AD7858's status register for every operation, I came to the conclusion that I had a hardware fault in the I.C itself. For this reason, you will find that the lines of code which read and output channel 3 have been commented out - and I now only have a 7-channel device. Putting the old 16C84, with the original code back in the device shows that this, too duplicates 1 channel, so the problem's been there, unnoticed for 10 years. Oh well.