Sunday, September 24, 2023

PIC16F84A DS18B20 1-Wire Temperature Sensor And Character LCD Using XC8

A simple 8-bit PIC16F84A micro-controller can do a lot of stuff as it has only 1kB of ROM, 68 bytes of RAM, 64 bytes of EEPROM two digital I/O port, one timer, etc. Some electronic engineer make an LC meter or a frequency meter with a dozen of components using this small embedded controller. Using the Assembly language is suitable for this micro-controller because it has a little RAM and SFR. Furthermore it has only 35 Assembly instructions to use.

PIC16F84A DS18B20 1-Wire Temperature Sensor And Character LCD Using XC8
Simulating Program At Start Up

In this example I use this micro-controller with a 16x2 character LCD, a DS18B20 digital thermometer, switches, relay, etc. It could be a temperature controlled DC or AC switch. We can use it control an AC fan on and off. However I could find an AC lamp in Proteus. So I replace with a DC/AC lamp.

PIC16F84A DS18B20 1-Wire Temperature Sensor And Character LCD Using XC8
PIC16F84A In P-DIP Package

I use a free version of XC8 v2.36 in MPLABX IDE v1.51 to make its firmware. It does not have restriction but without technical support and code optimization. It should be effective as the program that was written using Assembly language.

A preset temperature value is stored in EEPROM. It's adjustable. It's read once when the program start. Whenever we adjust the preset temperature it will change its value in EEPROM. The current value in program is also updated.

The main program loop continuously get the temperature data from DS18B20, check whether there's a switch pressing.

  1.  
  2. #include<xc.h>
  3.  
  4. #define _XTAL_FREQ 4000000
  5.  
  6.  
  7. // PIC16F84A Configuration Bit Settings
  8.  
  9. // CONFIG
  10. #pragma config FOSC = XT // Oscillator Selection bits (XT oscillator)
  11. #pragma config WDTE = ON // Watchdog Timer (WDT enabled)
  12. #pragma config PWRTE = OFF // Power-up Timer Enable bit (Power-up Timer is disabled)
  13. #pragma config CP = OFF // Code Protection bit (Code protection disabled)
  14.  
  15. #define DQ RA4
  16. #define DQ_DIR TRISA4
  17.  
  18. unsigned char ow_reset(void){
  19. unsigned char presence;
  20. DQ_DIR=0;
  21. DQ=0;
  22. __delay_us(480);
  23. DQ=1;
  24. __delay_us(70);
  25. DQ_DIR=1;
  26. presence=DQ;
  27. __delay_us(425);
  28. return presence;
  29. }
  30.  
  31. unsigned char readBit(void){
  32. DQ_DIR=0;
  33. DQ=0;
  34. DQ_DIR=1;
  35. __delay_us(15);
  36. return DQ;
  37. }
  38.  
  39. void writeBit(char bitVal){
  40. DQ_DIR=0;
  41. DQ=0;
  42. if(bitVal==1) DQ=1;
  43. __delay_us(104);
  44. DQ=1;
  45. }
  46.  
  47. unsigned char readByte(void){
  48. unsigned char i;
  49. unsigned char value=0;
  50. for(i=0;i<8;i++){
  51. if(readBit()) value|=0x01<<i;
  52. __delay_us(96);
  53. }
  54. return value;
  55. }
  56.  
  57. void writeByte(char val){
  58. unsigned char i;
  59. unsigned char temp;
  60. for(i=0;i<8;i++){
  61. temp=val>>i;
  62. temp&=0x01;
  63. writeBit(temp);
  64. }
  65. __delay_us(104);
  66. }
  67.  
  68. __EEPROM_DATA(0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07);
  69. __EEPROM_DATA(0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71);
  70.  
  71. void main(void){
  72. unsigned char LSB,MSB;
  73. unsigned char get[9];
  74. unsigned int temp;
  75. /*PORT B AND A AS OUTPUT*/
  76. PORTB=0x00;
  77. TRISB=0x00;
  78. PORTA=0x00;
  79. TRISA=0x00;
  80. //Select Internal Timer Clock Source
  81. OPTION_REGbits.T0CS=0;
  82. //Assign The Prescaler To WDT
  83. OPTION_REGbits.PSA=1;
  84. //Select 1:128 Prescaler
  85. OPTION_REGbits.PS=0x07;
  86. //Clear Watch Dog Timer
  87. CLRWDT();
  88. //Initiate A First 1-Wire Read
  89. ow_reset();
  90. writeByte(0xCC);
  91. writeByte(0x44);
  92. __delay_us(104);
  93. ow_reset();
  94. writeByte(0xCC);
  95. writeByte(0xBE);
  96. for(int i=0;i<9;i++) get[i]=readByte();
  97.  
  98. __delay_ms(1000);
  99. CLRWDT();
  100. while(1){
  101. ow_reset();
  102. writeByte(0xCC);
  103. writeByte(0x44);
  104. __delay_us(104);
  105. ow_reset();
  106. writeByte(0xCC);
  107. writeByte(0xBE);
  108. for(int i=0;i<9;i++) get[i]=readByte();
  109.  
  110. MSB=get[1];
  111. LSB=get[0];
  112. temp=(MSB<<8)+LSB;
  113. temp>>=4;
  114. LSB=0x0F&LSB;
  115. if(LSB^0x08) LSB=0;
  116. else LSB=5;
  117. //temp&=0x00FF;
  118. //PORTB=temp;
  119. __delay_ms(10);
  120.  
  121. PORTA=0x00;
  122. PORTB=eeprom_read(temp/100);
  123. if(temp>=100) RA0=1;
  124. __delay_ms(5);
  125.  
  126. PORTA=0x00;
  127. PORTB=eeprom_read((temp%100)/10);
  128. if(temp>=10) RA1=1;
  129. __delay_ms(5);
  130.  
  131. PORTA=0x00;
  132. PORTB=eeprom_read(temp%10)|0x80;
  133. RA2=1;
  134. __delay_ms(5);
  135.  
  136. PORTA=0x00;
  137. PORTB=eeprom_read(LSB);
  138. RA3=1;
  139. __delay_ms(5);
  140. CLRWDT();
  141. }
  142. }
  143.  
  144.  

 

It requires 90.9% of program space, and 63.2% of data space. I added a Watch Dog Timer (WDT) reset to keep track of operation of program. Once it's halted ,the WDT will reset the software. 

PIC16F84A DS18B20 1-Wire Temperature Sensor And Character LCD Using XC8
Resource Usage Of PIC16F84A
If we need a larger multiplexing seven-segment display we can use this once. We can customize the size of color of the display.

PIC16F84A DS18B20 1-Wire Temperature Sensor And Character LCD Using XC8
Temperature Reaches The Preset Value, The Output Relay On

PIC16F84A DS18B20 1-Wire Temperature Sensor And Character LCD Using XC8
Press SW4 To Show EEPROM Preset Value

PIC16F84A DS18B20 1-Wire Temperature Sensor And Character LCD Using XC8
Press SW3 To Increase Its Preset Value

PIC16F84A DS18B20 1-Wire Temperature Sensor And Character LCD Using XC8
Press SW4 To Decrease Its Preset Value


This small project could be use in some areas. I don't have hardware experiment or PCB design for this project because my PIC16F84A was burned a long time ago. Click here to download source file for this project.

Saturday, September 23, 2023

PIC16F84A DS18B20 1-Wire Temperature Reading And Multiplexing Display Example Using XC8

Device Overview

The DS18B20 is a digital thermometer that able to convert the temperature from -55 to +125 degree Celsius. The controller communicates with this temperature sensor using a 1-Wire bus. So this device requires only three wires including GND, VCC, and data line. Furthermore it can use data line to power  the device eliminating the VCC. 

PIC16F84A DS18B20 1-Wire Temperature Reading And Multiplexing Display Example Using XC8
DS18B20 Pin Configuration


PIC16F84A DS18B20 1-Wire Temperature Reading And Multiplexing Display Example Using XC8
DS18B20 In TO-92 Package

 A TO-92 package is a typical package for hardware experiment.

PIC16F84A DS18B20 1-Wire Temperature Reading And Multiplexing Display Example Using XC8
A Typical Connection Between Microprocessor And DS18B20
 
PIC16F84A DS18B20 1-Wire Temperature Reading And Multiplexing Display Example Using XC8
Using Multiple Devices Over A 1-Wire Bus
It has its own 64-bit ROM unique ID allowing the controller interface to multiple DS18B20 devices over a 1-Wire bus.  

PIC16F84A DS18B20 1-Wire Temperature Reading And Multiplexing Display Example Using XC8
DS18B20 64-Bit ROM Area

 

If there is only one DS18B20 over a 1-Wire bus, it just need to skip ROM search. The controller just need issue a skip ROM, convert, and read scratch pad command. 

PIC16F84A DS18B20 1-Wire Temperature Reading And Multiplexing Display Example Using XC8
DS18B20 Memory Map
PIC16F84A DS18B20 1-Wire Temperature Reading And Multiplexing Display Example Using XC8
DS18B20 Temperature Data Format

Scratchpad contains 9 bytes of data. Converted temperature consists of two bytes, BYTE 0 and BYTE 1 of device's scratch-pad. It contains sign, decimal temperature data, and fraction in degree Celsius.

To interface with this 1-Wire device, the micro-controller have to prepare a correct timing for its I/O as follow.

PIC16F84A DS18B20 1-Wire Temperature Reading And Multiplexing Display Example Using XC8
DS18B20 Initialization Timing

 
PIC16F84A DS18B20 1-Wire Temperature Reading And Multiplexing Display Example Using XC8
DS18B20 Read/Write Time Slot
This device has two command categories, ROM Commands and Function Commands. ROM commands are not use as the micro-controller just need to get the temperature from a single thermometer on 1-wire bus. 

DS18B20 ROM Commands

  1. Search ROM [F0h]
  2. Read ROM [33h]
  3. Match ROM [55h]
  4. Skip ROM [CCh]
  5. Alarm Search [ECh]

DS18B20 Function Commands

  1. Convert Temperature [44h]
  2. Write Scratchpad [4Eh]
  3. Read Scracthpad [BEh]
  4. Copy Scratchpad [48h]
  5. Recall EEPROM [B8h]
  6. Read Power Supply [B4h]
For full explanation for these command please read the device's data sheet.

XC8 Programming

I use the MPLABX IDE 1.51 with XC8 v2.36 C compiler for PIC micro-controller. I need to write about five C functions to interact with this device. These C functions I followed an application note published by ANALOG DEVICES, "Interfacing the DS18X20/DS1822 1-Wire® Temperature Sensor in a Microcontroller Environment". This example use the 8051 micro-controller.

PIC16F84A DS18B20 1-Wire Temperature Reading And Multiplexing Display Example Using XC8
Simulating Program In Proteus

PIC16F84A DS18B20 1-Wire Temperature Reading And Multiplexing Display Example Using XC8
Multiplexing Seven-Segment Display

 
PIC16F84A DS18B20 1-Wire Temperature Reading And Multiplexing Display Example Using XC8
PIC16F84A In P-DIP Package From Microchip Website


In this example I use a simple 8-bit micro-controller PIC16F84A to get the temperature from this device. The output device is a simple 4-digit common cathode multiplexing display. For the first conversion time, the thermometer yield 85 degree Celsius but I skip this data.

  1.  
  2. #include<xc.h>
  3.  
  4.  
  5. // PIC16F84A Configuration Bit Settings
  6.  
  7. // CONFIG
  8. #pragma config FOSC = XT // Oscillator Selection bits (XT oscillator)
  9. #pragma config WDTE = OFF // Watchdog Timer (WDT disabled)
  10. #pragma config PWRTE = OFF // Power-up Timer Enable bit (Power-up Timer is disabled)
  11. #pragma config CP = OFF // Code Protection bit (Code protection disabled)
  12.  
  13.  
  14. #define _XTAL_FREQ 4000000
  15.  
  16. #define DQ RA4
  17. #define DQ_DIR TRISA4
  18.  
  19. unsigned char ow_reset(void){
  20. unsigned char presence;
  21. DQ_DIR=0;
  22. DQ=0;
  23. __delay_us(480);
  24. DQ=1;
  25. __delay_us(70);
  26. DQ_DIR=1;
  27. presence=DQ;
  28. __delay_us(425);
  29. return presence;
  30. }
  31.  
  32. unsigned char readBit(void){
  33. DQ_DIR=0;
  34. DQ=0;
  35. DQ_DIR=1;
  36. __delay_us(15);
  37. return DQ;
  38. }
  39.  
  40. void writeBit(char bitVal){
  41. DQ_DIR=0;
  42. DQ=0;
  43. if(bitVal==1) DQ=1;
  44. __delay_us(104);
  45. DQ=1;
  46. }
  47.  
  48. unsigned char readByte(void){
  49. unsigned char i;
  50. unsigned char value=0;
  51. for(i=0;i<8;i++){
  52. if(readBit()) value|=0x01<<i;
  53. __delay_us(96);
  54. }
  55. return value;
  56. }
  57.  
  58. void writeByte(char val){
  59. unsigned char i;
  60. unsigned char temp;
  61. for(i=0;i<8;i++){
  62. temp=val>>i;
  63. temp&=0x01;
  64. writeBit(temp);
  65. }
  66. __delay_us(104);
  67. }
  68.  
  69.  
  70. void main(void){
  71. unsigned char LSB,MSB;
  72. unsigned char get[9];
  73. unsigned int temp;
  74. //unsigned char ssd[16]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
  75. unsigned char ssd[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
  76. PORTB=0x00;
  77. TRISB=0x00;
  78. PORTA=0x00;
  79. TRISA=0x00;
  80. ow_reset();
  81. writeByte(0xCC);
  82. writeByte(0x44);
  83. __delay_us(104);
  84. ow_reset();
  85. writeByte(0xCC);
  86. writeByte(0xBE);
  87. for(int i=0;i<9;i++) get[i]=readByte();
  88.  
  89. __delay_ms(800);
  90. while(1){
  91. ow_reset();
  92. writeByte(0xCC);
  93. writeByte(0x44);
  94. __delay_us(104);
  95. ow_reset();
  96. writeByte(0xCC);
  97. writeByte(0xBE);
  98. for(int i=0;i<9;i++) get[i]=readByte();
  99. MSB=get[1];
  100. LSB=get[0];
  101. temp=(MSB<<8)+LSB;
  102. temp>>=4;
  103. LSB=0x0F&LSB;
  104. if(LSB^0x08) LSB=0;
  105. else LSB=5;
  106. //temp&=0x00FF;
  107. //PORTB=temp;
  108. __delay_ms(10);
  109.  
  110. PORTA=0x00;
  111. PORTB=ssd[temp/100];
  112. if(temp/100) RA0=1;
  113. __delay_ms(5);
  114.  
  115. PORTA=0x00;
  116. PORTB=ssd[(temp%100)/10];
  117. RA1=1;
  118. __delay_ms(5);
  119.  
  120. PORTA=0x00;
  121. PORTB=ssd[temp%10]|0x80;
  122. RA2=1;
  123. __delay_ms(5);
  124.  
  125. PORTA=0x00;
  126. PORTB=ssd[LSB];
  127. RA3=1;
  128. __delay_ms(5);
  129.  
  130. }
  131. }
  132.  

This program uses half of device program space and about 80% of device data space. Click here to download its source file.

PIC16F84A DS18B20 1-Wire Temperature Reading And Multiplexing Display Example Using XC8
RAM ROM Usage In PIC16F84A

CCS PICC provide a touch sensor library similar to the DS18B20. MikroC also has a 1-Wire library for its supported devices. Arduino has a lot of libraries for various type of sensors including this device.


Search This Blog

Labels

25AA010A (1) 8051 (7) 93AA46B (1) ADC (30) Analog Comparator (1) Arduino (15) ARM (6) AT89C52 (7) ATMega32 (56) AVR (57) CCS PICC (28) DAC (1) DHT11 (2) Display (105) Distance Sensor (3) DS18B20 (3) dsPIC (2) dsPIC30F1010 (2) EEPROM (5) Environment Sensor (4) esp8266 (1) I2C (29) Input/Output (67) Interrupt (19) Keil (5) Keypad (10) LCD (47) Master/Slave (1) MAX7221 (1) MCP23017 (5) MCP23S17 (4) Meter (3) MikroC (2) Motor (15) MPLABX (71) Nokia 5110 LCD (3) OLED (2) One-Wire (6) Oscillator (8) PCB (6) PCD8544 (3) PCF8574 (5) PIC (107) PIC12F (2) PIC16F628A (2) PIC16F630 (1) PIC16F716 (3) PIC16F818 (10) PIC16F818/819 (2) PIC16F84A (15) PIC16F876A (1) PIC16F877A (9) PIC16F88 (1) PIC16F887 (60) PIC18 (19) PIC18F1220 (4) PIC18F2550 (3) PIC18F4550 (12) PWM (11) RTC (8) Sensor (10) SH1106 (1) Shift Register (11) Shift Registers (3) SPI (24) STM32 (6) STM32 Blue Pill (6) STM32CubeIDE (6) STM32F103C8T6 (6) SysTick (3) temperature sensor (11) Thermometer (21) Timer/Counter (31) TM1637 (2) UART (7) Ultrasonic (4) Voltmeter (7) WDT (1) XC16 (2) XC8 (94)