Monday, October 11, 2010

PIC 16F88 Digital Thermometer Light Meter and resistance ohm meter.

My original idea for this project was simply to try and interface the WINTEK WD-C2401P lcd panel to the pic (see my previous post). I figured it would be fun to add a couple of ADC readings to display something useful on the lcd. 

Theory of Operation:

PORTB on the PIC is used as the data port for the LCD. The Enable, Register Select and Reset are tied to PORTA. Once the LCD is initialized, the PIC reads the ADC values from the thermistor, CDS cell and resistor (if connected) via a voltage divider. The voltage divider translates any change in resistance from the sensors into changes in voltage. The Vout is calculated as 
Vdd*(R2/R2+R1). ) So any change in R1 (the sensor's resistance) will result in a change in the output voltage. In order to translate this into the ADC value, a 10 bit ADC resolution microcontroller will have 1024 (2 to the power of 10) possible steps. So if the controller is operating on 5V then each step will increment the voltage by 5/1024 = 0.004882813V every increment. So the value in the ADC will be the voltage input at the ADC divided by 0.004882813. This allows for an accurate calculation of the resistance of the sensor. In order to translate the resistance to useful human readable form, its necessary to calibrate the sensors using real life instruments and extrapolating the values to the resistance offered. Since the display does not have any backlight, an LED is connected to PORTA4 to turn on whenever the light falls below a certain threshold. 

PIC 16F88
78L05 Voltage regulator
C1 - 1uf capacitor
R1,R3,R4 - 10K Ohm
R2 - 1K Ohm
R5 - 120 Ohm
CDS Cell
Wintek WD-C2401P LCD display

Circuit Diagram:

Designed by Mindfront Technologies for    
The complete kit is available at

Tuesday, September 28, 2010

ADC Conversions on Microchip

In order to correctly perform an ADC it is important to ensure there is enough time between enabling the ADC module to performing a conversion. Here is a code sample for PIC 16F88

#define TEMP 0x00 //AN0
#define LIGHT 0x08 //AN1

ANSEL |= 0x03; //Select AN0-1 as analog
TRISA |= 0x03; //Select RA0-1 as input
ADCON0 =0x00; //Configure A/D params

unsigned int GetA2DLevel(unsigned char channel)
unsigned int adc_result=0;
ADCON1 =0b10000000; //Configure A/D params
ADCON0 =0b11000001 | channel; //Set the channel and start A/D module
__delay_us(20); //Delay required to ensure module is operating properly
ADCON0 |= 0x04; //Start Conversion
while(ADCON0 & 0x04); //Wait for conversion
adc_result = ADRESH;
adc_result = (adc_result<<8)|ADRESL;
ADCON0 =0x00;

return adc_result;


Wednesday, July 21, 2010

Interfacing Wintek WD-C2401P LCD with Microchip PIC

 Wintek WD-C2401P LCD panel is a 24x1 character display. The code for using the LCD was written for microchip PIC 16F88 but should work with all other micro controllers.

Pinout for the WD-C2401P

Pin #NameFunction
1VssGround ( 0v)
2Vdd+5 volts
3ResetWhen this pin is low it resets the LCD. You can either tie this pin to a pin on your microcontroller so you can reset the LCD before initializtion, or just tie it high. I had a couple of times where I couldn't init the LCD without first resetting it, so I'd recommend putting it under micro control, or some other powerup controller. The reset low time should be at least 10ms. The time after reset before you start commanding the LCD should also be at least 10 ms.
4RSRegister Select. This pin determines whether the data you're about to write is a command or a data byte. Commands do interesting stuff to the LCD, like set the number of lines or contrast. Data is what actually gets put on the screen, or in the custom character registers. High means Data, Low means command
5Read/WriteSet this pin high to read from the display. Set this pin low to write to it. If you don't need to update the display super fast you can save an I/O line by just tying it to ground. Wait at least a millisecond between each command and data, though, since you can't query the busy status without read capability.
6EEnable. This line works to clock in data and commands. See the protocol section below.
7DB0Least Significant Data Bit

 Details of soldering the pins are available at


#define E_LO  PORTA &= ~0x80;  //RA7
#define E_HI  PORTA |=0x80
#define RS_HI  PORTA |=0x40 //RA6
#define RS_LO  PORTA &= ~0x40
#define RESET_LO PORTA &= ~0x04
#define RESET_HI PORTA |= 0x04

#define DELAY10MS __delay_ms(10)
#define DELAY1MS __delay_ms(1)
#define DELAY5MS __delay_ms(5)
#define DELAY20MS __delay_ms(20)
#define DELAY90MS __delay_ms(90)
#define DELAY0_5MS __delay_us(500)
#define DELAY5US __delay_us(5)

void LCDInitialize();
void LCDWriteChar(char c);
void LCDClockByte(char c); //Called internally do not use
void LCDClearScreen();
void LCDWriteString(char *s);
void LCDResetChar(); //Return back to first address


#include "lcd_wintek_wdc2401p.h"

void LCDInitialize()

 //Initialize Sequence
 LCDClockByte(0x1C); //Turn on the lcd driver power
 LCDClockByte(0x14); //Turn on the character display
 LCDClockByte(0x28); //Set two display lines (The hd66717 considers
     //12 characters to be a line. Our 24 character display is
     //actually two 12-character lines right next to each other).    
 LCDClockByte(0x4F); //Set to darkest contrast
 LCDClockByte(0xE0); //Set the data address to the first character

void LCDClockByte(char c)
 LCD_DATA = c;

void LCDWriteChar(char c)
void LCDResetChar()

void LCDWriteString( char *s)
 unsigned char c,i,end_flag=0;
 for(i=0;i< 24;i++) {
  c = (s[i] == 0x00)?'-':s[i];
  if(s[i] == 0x00 || end_flag == 1){
   c = ' ';
   end_flag = 1;
  } else {
   c = s[i];

void LCDClearScreen()

main.c: (Sample Usage)
#include "lcd_wintek_wdc2401p.h"
main() {
 //Make sure you setup the pins on the micro controller for output
       // and designate the pins properly in the include file. 
 char s[]="abcdefghijklmnop";

Monday, April 19, 2010

Zilog Microcontroller General Purpose Frequency Counter with 7 segment display

This circuit is a frequency counter circuit original designed  to be used with a Geiger Counter.This circuit uses an 8 bit 8F0423 Zilog microcontroller to act as a frequency counter. The input to the circuit is driven through an optocoupler to isolate the source circuit. The output is displayed on a 3 digit seven segment display. There are 2 push buttons, one for reset and another to select between counter and frequency mode. Counter mode simply measures the counts whereas the frequency mode measures the counts per minute. The counter can accurately measure input up to 999,999, but only the 3 most significant digits are displayed. For example to display 19,832, 198 is displayed on the seven segment display and the x100 LED comes on. The overflow LED is used to indicate when the count has exceeded 999,999. It is fairly simple to add additional digits but for the purpose of my measurement the 3 most significant digits were sufficient. 

Technical Details:

The output from the optocoupler is connected to pin 11 of the microcontroller with a pull up resistor. A pull up resistor is used to ensure that there is a proper logic on the microcontroller input even when the output from the optocoupler is floating. An interrupt service routine (ISR) is triggered every time there is a transition on the port (from low logic to high logic and vice versa). The ISR keeps track of the count. Timer 1 is configured as a timer to indicate when a full minute is elapsed. This allows for the calculation of the number of transitions per minute. The 2 pins which say "To Geiger LED" take the input from any source.
Driving the seven segment display:
There are 7 LEDs per digit and to display 3 digits it will normally take 7x3 = 21 pins. This is beyond the packaging of most microcontrollers and a waste of resources. Instead a technique called multiplexing is used. Each digit on the display is turned on and off so rapidly that it gives an illusion that they are all on at the same time. This is due to the persistence of vision experienced by the eye. Timer 0 is configured to timeout every 1 ms and updates the seven segment display.
Your browser may not support display of this image.

Mode and reset buttons:
The mode and reset buttons are driven by their own ISRs to interrupt every time they are pushed down.  The internal pull up resistor is enabled on the pins connected to push button switches. This is to ensure there is always a clear logic level even when the push button is off (floating). 

Designed by Mindfront Technologies for  
The complete kit is available at

Monday, April 5, 2010

PIC 16F88 Microcontroller PIC based Tengu

Tengu derives its name from a mythical Japanese creature known for getting into mischief. Our Tengu, however is more earthly in nature.  It responds to voice and sounds and takes on different facial features depending on the intensity of the sound. If no sound is heard for some time, it changes from a happy face to a sad face and then goes to sleep. Gently blowing on his face wakes him back up to his usual happy self. 

The Technical Details:
The project is based on a Microchip PIC 16F88 which is part of their mid range of microcontrollers. The sound is amplified through a pre-amp circuit based on 2N3904 and fed to the RB7/AN6 (pin 13) of the pic microcontroller. The A/D converter on the microcontroller is used to convert the analog signal from the pre-amp. The LED Matrix is directly driven by the pic. In order to be able to display the entire smiley, the LED dot matrix is multiplexed in such a way that only one row out of the seven is active at any given time. However the rows are turned on and off so rapidly, the human eye sees it as a full picture. This effect is called the persistence of vision. In order to achieve multiplexing, timer 0 on the pic is running at approximately 1 ms timeouts to switch the row that is being displayed on the LED Matrix. Timer 1 is configured as a general purpose timer used to keep track of the time since any noise over the threshold was heard. This is used to change the smiley from a happy to a sad one. The code is written in C using MPLAB and Hi-Tech C compiler ver 9.80.

Parts List:
  • PIC Microchip 16F88
  • 7x5 LED Dot Matrix Display
  • 5 x 160 Ohm resistor
  • 2 x 10K Ohm resistor
  • 1 x 100K Ohm Resistor
  • 2N3904 NPN Transistor
  • Electret Mic
  • 1 x 0.1 uf capacitor
  • 1uf capacitor
  • 78L05 5v voltage regulator
Circuit Diagram 
Eagle Schematic available here

The gain I was getting on the amp circuit above was only moderate. I changed the circuit to use a LM386 based on Jose Pino's circuit and got a much better gain. The circuit diagram is below. The 10K potentiometer is used to adjust the sensitivity of the mic while the 100K potentiometer is used to adjust the gain. 

Designed by Mindfront Technologies for  
The complete kit is available at

Here is the video of the project in action:

YDLidar (lidar) X4 API in golang

YDLidar X4 This is a demo of the YDLidar using a golang API. The software supplied with the device only contains the drivers in C++ an...