<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>PIC Projects | Teach Me Microcontrollers!</title>
	<atom:link href="https://www.teachmemicro.com/category/projects/pic-projects/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.teachmemicro.com/category/projects/pic-projects/</link>
	<description>Microcontroller Tutorials and Resources</description>
	<lastBuildDate>Sun, 28 Jun 2026 01:12:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.2</generator>

<image>
	<url>https://www.teachmemicro.com/wp-content/uploads/2019/04/blue-icon-65x65.png</url>
	<title>PIC Projects | Teach Me Microcontrollers!</title>
	<link>https://www.teachmemicro.com/category/projects/pic-projects/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Using a 16x2 Monochrome LCD with the PIC16F84A (Assembly Tutorial)</title>
		<link>https://www.teachmemicro.com/using-a-16x2-monochrome-lcd-with-the-pic16f84a-assembly-tutorial/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=using-a-16x2-monochrome-lcd-with-the-pic16f84a-assembly-tutorial</link>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Wed, 24 Sep 2025 00:48:52 +0000</pubDate>
				<category><![CDATA[PIC Projects]]></category>
		<category><![CDATA[PIC Tutorial]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=9316</guid>

					<description><![CDATA[<p>Introduction A 16x2 monochrome LCD module is a widely used display in microcontroller projects. It can show two lines of text, each up to 16 characters long, making it ideal for simple user interfaces. These LCDs are based on the HD44780 controller (or compatible), which accepts commands and data via an 8-bit or 4-bit parallel &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/using-a-16x2-monochrome-lcd-with-the-pic16f84a-assembly-tutorial/">Using a 16x2 Monochrome LCD with the PIC16F84A (Assembly Tutorial)</a> appeared first on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h3><strong>Introduction</strong></h3>
<p>A 16x2 monochrome LCD module is a widely used display in microcontroller projects. It can show <strong>two lines of text, each up to 16 characters long</strong>, making it ideal for simple user interfaces. These LCDs are based on the <strong>HD44780 controller (or compatible)</strong>, which accepts commands and data via an 8-bit or 4-bit parallel interface.</p>
<p>The LCD works by receiving control signals (RS, R/W, E) and data signals (D0–D7 or D4–D7 for 4-bit mode). In this tutorial, we’ll use <strong>8-bit mode</strong> for simplicity. The PIC16F84A will send initialization commands to the LCD, followed by ASCII characters to be displayed.</p>
<p>Understanding the control lines:</p>
<ul>
<li><strong>RS (Register Select):</strong>
<ul>
<li>0 = Instruction/command (e.g., clear display).</li>
<li>1 = Data (character to display).</li>
</ul>
</li>
<li><strong>R/W (Read/Write):</strong>
<ul>
<li>0 = Write to LCD.</li>
<li>1 = Read from LCD (rarely needed, we’ll keep it  0.</li>
</ul>
</li>
<li><strong>E (Enable):</strong>
<ul>
<li>A high-to-low pulse latches the data/command into the LCD.</li>
</ul>
</li>
</ul>
<p>Once initialized, the LCD can display text by sending ASCII codes as data.</p>
<hr />
<h3><strong>Materials</strong></h3>
<ul>
<li>PIC16F84A microcontroller</li>
<li>16x2 HD44780-based monochrome LCD module</li>
<li>4 MHz crystal oscillator + 2 × 22pF capacitors</li>
<li>10kΩ potentiometer (for LCD contrast adjustment)</li>
<li>Breadboard and jumper wires</li>
<li>5V regulated power supply</li>
</ul>
<hr />
<h3><strong>Code (Assembly for PIC16F84A)</strong></h3>
<p>We’ll walk through the full code, then explain each part.</p>
<h4><strong>Full Program</strong></h4>
<div class="hcb_wrap">
<pre class="prism undefined-numbers lang-plain" data-lang="Plain Text"><pre><code class="language-cpp">;===========================================================
; Program: LCD 16x2 Display with PIC16F84A
;===========================================================

    list p=16F84A
    include &lt;p16f84a.inc&gt;

    __CONFIG _FOSC_HS &amp; _WDTE_OFF &amp; _PWRTE_ON &amp; _CP_OFF

;-------------------------------
; Pin connections
; LCD Data -&gt; PORTB
; RS -&gt; RA0
; RW -&gt; RA1 (tied low, write only)
; EN -&gt; RA2
;-------------------------------

    cblock 0x20
        temp
    endc

;-------------------------------
; Reset vector
;-------------------------------
    org 0x00
    goto main

;-------------------------------
; Subroutines
;-------------------------------
delay_ms
    movlw   d&#039;250&#039;
    movwf   temp
d1  nop
    nop
    decfsz  temp, f
    goto d1
    return

lcd_pulse
    bsf     PORTA,2      ; E=1
    call    delay_ms
    bcf     PORTA,2      ; E=0
    call    delay_ms
    return

lcd_cmd
    bcf     PORTA,0      ; RS=0
    movwf   PORTB        ; Send command
    call    lcd_pulse
    return

lcd_data
    bsf     PORTA,0      ; RS=1
    movwf   PORTB        ; Send data
    call    lcd_pulse
    return

lcd_init
    ; Function Set: 8-bit, 2 line, 5x8 font
    movlw   0x38
    call    lcd_cmd

    ; Display ON, Cursor OFF
    movlw   0x0C
    call    lcd_cmd

    ; Clear display
    movlw   0x01
    call    lcd_cmd

    ; Entry mode: auto-increment
    movlw   0x06
    call    lcd_cmd
    return

;-------------------------------
; Main Program
;-------------------------------
main
    bsf     STATUS, RP0
    movlw   0x00
    movwf   TRISB       ; PORTB = output
    movlw   0xF8
    movwf   TRISA       ; RA0-RA2 output, RA3-RA4 input
    bcf     STATUS, RP0

    call    lcd_init

    ; Write &quot;HELLO&quot;
    movlw   &#039;H&#039;
    call    lcd_data
    movlw   &#039;E&#039;
    call    lcd_data
    movlw   &#039;L&#039;
    call    lcd_data
    movlw   &#039;L&#039;
    call    lcd_data
    movlw   &#039;O&#039;
    call    lcd_data

endless
    goto endless

    end</code></pre></pre>
</div>
<p><strong><a class="sim-btn" href="https://picsimulator.com/?example=lcd-hello" target="_blank" rel="noopener" aria-label="Open LCD Hello example in PICSimulator"><img decoding="async" class="sim-icon" src="https://picsimulator.com/favicon.png" width="20" height="20" style="width: 20px; height: 20px; vertical-align: middle; margin-right: 5px;" data-wp-editing="1" />Simulate this code in PICSimulator</a></strong></p>
<h3>Code Explanation</h3>
<h4><strong>1. Configuration and Setup</strong></h4>
<div class="contain-inline-size rounded-2xl relative bg-token-sidebar-surface-primary">
<div class="hcb_wrap">
<pre class="prism undefined-numbers lang-plain" data-lang="Plain Text"><pre><code class="language-cpp">list p=16F84A
    include &lt;P16F84A.inc&gt;
    __CONFIG _FOSC_HS &amp; _WDTE_OFF &amp; _PWRTE_ON &amp; _CP_OFF</code></pre></pre>
</div>
</div>
<ul>
<li>Sets processor type and includes the register definitions.</li>
<li>Configures the microcontroller for <strong>High-Speed crystal oscillator</strong>, <strong>watchdog timer off</strong>, <strong>power-up timer on</strong>, and <strong>code protection off</strong>.</li>
</ul>
<h4><strong>2. LCD Pin Mapping</strong></h4>
<ul>
<li><strong>PORTB</strong> is used for LCD data (D0–D7).</li>
<li><strong>RA0 = RS</strong>, <strong>RA1 = R/W (grounded)</strong>, <strong>RA2 = E</strong>.</li>
<li>Only writing to the LCD is needed, so R/W is tied to ground.</li>
</ul>
<h4><strong>3. Delay Routine</strong></h4>
<div class="contain-inline-size rounded-2xl relative bg-token-sidebar-surface-primary">
<div class="hcb_wrap">
<pre class="prism undefined-numbers lang-plain" data-lang="Plain Text"><pre><code class="language-cpp">delay_ms
    movlw d&#039;250&#039;
    movwf temp
d1: decfsz temp, f
    goto d1
    return</code></pre></pre>
</div>
</div>
<p>A simple software delay loop to let the LCD process commands.</p>
<h4><strong>4. LCD Enable Pulse</strong></h4>
<div class="contain-inline-size rounded-2xl relative bg-token-sidebar-surface-primary">
<div class="hcb_wrap">
<pre class="prism undefined-numbers lang-plain" data-lang="Plain Text"><pre><code class="language-cpp">lcd_pulse
    bsf PORTA,2   ; E=1
    call delay_ms
    bcf PORTA,2   ; E=0
    call delay_ms
    return</code></pre></pre>
</div>
</div>
<p>The LCD latches commands/data on the <strong>falling edge of E</strong>.</p>
<h4><strong>5. Sending Commands and Data</strong></h4>
<div class="contain-inline-size rounded-2xl relative bg-token-sidebar-surface-primary">
<div class="hcb_wrap">
<pre class="prism undefined-numbers lang-plain" data-lang="Plain Text"><pre><code class="language-cpp">lcd_cmd
    bcf PORTA,0   ; RS=0 (command)
    movwf PORTB
    call lcd_pulse
    return</code></pre></pre>
</div>
</div>
<div class="contain-inline-size rounded-2xl relative bg-token-sidebar-surface-primary">
<div class="hcb_wrap">
<pre class="prism undefined-numbers lang-plain" data-lang="Plain Text"><pre><code class="language-cpp">lcd_data
    bsf PORTA,0   ; RS=1 (data)
    movwf PORTB
    call lcd_pulse
    return</code></pre></pre>
</div>
</div>
<p>These subroutines separate <strong>instructions (clear, cursor)</strong> from <strong>characters (ASCII)</strong>.</p>
<h4><strong>6. LCD Initialization</strong></h4>
<div class="contain-inline-size rounded-2xl relative bg-token-sidebar-surface-primary">
<div class="hcb_wrap">
<pre class="prism undefined-numbers lang-plain" data-lang="Plain Text"><pre><code class="language-cpp">movlw 0x38   ; Function set: 8-bit, 2-line, 5x8 font
movlw 0x0C   ; Display ON, cursor OFF
movlw 0x01   ; Clear display
movlw 0x06   ; Entry mode: auto-increment</code></pre></pre>
</div>
</div>
<p>These commands are required at startup to prepare the LCD.</p>
<h4><strong>7. Writing Text</strong></h4>
<div class="contain-inline-size rounded-2xl relative bg-token-sidebar-surface-primary">
<div class="hcb_wrap">
<pre class="prism undefined-numbers lang-plain" data-lang="Plain Text"><pre><code class="language-cpp">movlw &#039;H&#039;
call lcd_data</code></pre></pre>
</div>
</div>
<p>Each ASCII character is written sequentially to the LCD.</p>
<hr />
<h3><strong>Conclusion</strong></h3>
<p>In this tutorial, we connected a <strong>16x2 monochrome LCD</strong> to a <strong>PIC16F84A microcontroller</strong> using an <strong>8-bit parallel interface</strong>. We wrote initialization and display routines in <strong>assembly</strong>, giving full control of the LCD at a low level.</p>
<p>This project demonstrates how to:</p>
<ul>
<li>Initialize the LCD in 8-bit mode.</li>
<li>Send commands and data separately.</li>
<li>Display custom strings of text.</li>
</ul>
<p>With this foundation, you can extend the program to display sensor data, menu options, or real-time feedback for embedded projects.</p>
<p>The post <a href="https://www.teachmemicro.com/using-a-16x2-monochrome-lcd-with-the-pic16f84a-assembly-tutorial/">Using a 16x2 Monochrome LCD with the PIC16F84A (Assembly Tutorial)</a> appeared first on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Flame Sensor Project: Comprehensive Guide</title>
		<link>https://www.teachmemicro.com/flame-sensor-project-comprehensive-guide/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=flame-sensor-project-comprehensive-guide</link>
					<comments>https://www.teachmemicro.com/flame-sensor-project-comprehensive-guide/#respond</comments>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Thu, 23 Jan 2020 03:22:51 +0000</pubDate>
				<category><![CDATA[Arduino Projects]]></category>
		<category><![CDATA[ESP8266 Projects]]></category>
		<category><![CDATA[PIC Projects]]></category>
		<category><![CDATA[Sensor Tutorial]]></category>
		<category><![CDATA[fire detector]]></category>
		<category><![CDATA[fire sensor]]></category>
		<category><![CDATA[flame sensor for furnace]]></category>
		<category><![CDATA[iot]]></category>
		<category><![CDATA[push notification]]></category>
		<category><![CDATA[pushbullet]]></category>
		<category><![CDATA[pushingbox]]></category>
		<category><![CDATA[sensor]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=4081</guid>

					<description><![CDATA[<p>Flame sensors are found from the simplest gas stoves to huge industrial plants. There are different types of fire sensors -- some cheap, some expensive. Yet they’re all built for one single purpose: detect fire. In this article, I will guide you on how to build a flame sensor with a few extra bucks and &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/flame-sensor-project-comprehensive-guide/">Flame Sensor Project: Comprehensive Guide</a> appeared first on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><span style="font-weight: 400;">Flame sensors are found from the simplest gas stoves to huge industrial plants. There are different types of fire sensors -- some cheap, some expensive. Yet they’re all built for one single purpose: detect fire. In this article, I will guide you on how to build a flame sensor with a few extra bucks and some microcontroller programming knowledge.</span></p>
<p><span id="more-4081"></span></p>
<h3><b>What You’ll Need</b></h3>
<ul>
<li style="font-weight: 400;"><a href="http://s.click.aliexpress.com/e/_shLsn8"><span style="font-weight: 400;">Flame sensor module</span></a></li>
<li style="font-weight: 400;"><span style="font-weight: 400;">Microcontroller (<a href="http://s.click.aliexpress.com/e/_swUr9G">Arduino</a> or <a href="http://s.click.aliexpress.com/e/_sjwNOI">NodeMCU ESP8266</a> or <a href="http://s.click.aliexpress.com/e/_rwLdlk">PIC</a>)</span></li>
<li style="font-weight: 400;"><span style="font-weight: 400;">Power source</span></li>
<li style="font-weight: 400;"><span style="font-weight: 400;">Output device (<a href="http://s.click.aliexpress.com/e/_sJNkJ4">buzzer</a> or smartphone)</span></li>
</ul>
<h3><b>Flame Sensor Module</b></h3>
<p><span style="font-weight: 400;">The star of this project is this flame sensor module:</span></p>
<p><img loading="lazy" decoding="async" class="aligncenter" src="https://lh3.googleusercontent.com/UXqpd7DvjX9XaJgMK5vgvEzS2Xl67oAI2kZ_0juCLcn3UGK7t9laSC6FsKtlTnfCJDP7ATFQFZM8cossm01jBggvcdgcXg0uu7Zv0Y98Zdlnvg6hRWrgQNFQ6L2ZE8B58Y8OjPI8" alt="flame sensor module" width="401" height="401" /></p>
<p id="ureLAlb">This module contains a <a href="https://www.win-source.net/category/sensors-transducers/optical-sensors/optical-sensors-phototransistors">phototransistor</a> and <a href="https://en.wikipedia.org/wiki/Signal_conditioning"><i>signal conditioning</i></a> electronics. A phototransistor conducts more electrical current when exposed to light. Physics taught us that (visible) light comprises of all colors, from red to violet. By coating the phototransistor with black epoxy, it becomes more sensitive to red or even invisible <i>below red</i> or <a href="https://www.merriam-webster.com/dictionary/infra">infra</a>red. Interestingly, flame emits infrared radiation. Thus, when this sensor <i>sees</i> flame, it conducts more current.</p>
<p><a href="https://www.teachmemicro.com/wp-content/uploads/2020/01/flame-sensor-range.jpg"><img loading="lazy" decoding="async" class="aligncenter wp-image-4101 size-large" src="https://www.teachmemicro.com/wp-content/uploads/2020/01/flame-sensor-range-1024x486.jpg" alt="flame sensor range" width="640" height="304" srcset="https://www.teachmemicro.com/wp-content/uploads/2020/01/flame-sensor-range-1024x486.jpg 1024w, https://www.teachmemicro.com/wp-content/uploads/2020/01/flame-sensor-range-300x142.jpg 300w, https://www.teachmemicro.com/wp-content/uploads/2020/01/flame-sensor-range-768x365.jpg 768w, https://www.teachmemicro.com/wp-content/uploads/2020/01/flame-sensor-range.jpg 1089w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a></p>
<p><span style="font-weight: 400;">Microcontrollers read voltage, not current. Thus, the signal conditioning circuit in the module converts the current into levels of voltage that is considered safe for the microcontroller (typically, the maximum voltage should be the supply voltage to the microcontroller).</span></p>
<p><span style="font-weight: 400;">The flame sensor module also contains indicator LEDs. One LED lights up (PWR-LED) when the module is powered up while another lights up (D0-LED) when the sensor detects fire.</span></p>
<p><span style="font-weight: 400;">Moreover, the voltage from the D0 pin falls to zero in the vicinity of fire and rises to the supply voltage when there is none. We use this as a trigger for the microcontroller.</span></p>
<h3><b>Arduino - Flame Sensor Interface</b></h3>
<p><span style="font-weight: 400;">I aim to use three different kinds of microcontroller for this project. First, I’ll show how to build an Arduino flame sensor with a buzzer as indicator.</span></p>
<p><span style="font-weight: 400;">Since the module only provides two values, on and off, we don’t need to use any of the </span><i><span style="font-weight: 400;">analog</span></i><span style="font-weight: 400;"> pins of the Arduino. The wiring diagram below shows that the D0 pin of the module connects to the digital pin 2 of the <a href="https://www.teachmemicro.com/arduino-uno-pinout-diagram/">Arduino UNO</a>:</span></p>
<p><img loading="lazy" decoding="async" class="aligncenter" src="https://lh6.googleusercontent.com/PranlMnwtShfCJ8lP3_YPz9tnJPyhji4pLBnISEus-tZ_0V_Hy3aY6vkLm9fjXCaEVDj8vCSHQ37fpplFfSMCBZPTthgpA34qsKnvCvS3ssqPHwZSWAe0iTB9eUBHm0drPoA82Px" alt="arduino flame sensor" width="1600" height="810" /></p>
<p id="qxiAFCd">Moreover, the VCC or + pin connects to 5V and the G pin is connected to GND. Note that the fire detector module can also run on 3.3V. Finally, the buzzer’s red wire is connected to pin 5 while its black pin is wired to GND. In this project, I am using a buzzer that can run from voltages 3 to 24 V.</p>
<p><span style="font-weight: 400;">The sketch is straightforward:</span></p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">const int sensor_pin = 2;
const int buzzer = 5;

void setup() {
  pinMode(sensor_pin,INPUT_PULLUP);
  pinMode(buzzer,OUTPUT);
}

void loop() {
  if(digitalRead(sensor_pin) == LOW){
    digitalWrite(buzzer,HIGH);
  }else{
    digitalWrite(buzzer,LOW);
  }
}</code></pre></pre>
<p><span style="font-weight: 400;">I gave pins 2 and 5 appropriate aliases:</span></p>
<pre class="lang:arduino decode:true"><pre><code class="language-cpp">const int sensor_pin = 2;
const int buzzer = 5;</code></pre></pre>
<p><span style="font-weight: 400;">Inside <em>setup()</em>, we declare sensor_pin as an input pin while buzzer is an output pin:</span></p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">pinMode(sensor_pin,INPUT_PULLUP);
pinMode(buzzer,OUTPUT);</code></pre></pre>
<p>In <em>loop()</em>, we check if the sensor_pin voltage is zero. If it is, we sound the buzzer. If not, then turn off the buzzer.</p>
<pre class="lang:arduino decode:true"><pre><code class="language-cpp">void loop() {
  if(digitalRead(sensor_pin) == LOW){
    digitalWrite(buzzer,HIGH);
  }else{
    digitalWrite(buzzer,LOW);
  }
}</code></pre></pre>
<p><span style="font-weight: 400;">The fire sensor can detect flame within its 60 degree capture angle. The distance of the flame varies with ambient light. In my tests, the sensor was able to detect a match’s flame from around 5 cm.</span></p>
<h3><b>Using the Flame Sensor with PIC16F877A</b></h3>
<p><span style="font-weight: 400;">The difference here is that we are using a different microcontroller and thus, a different compiler. Nevertheless, the concept is the same: the <a href="https://www.teachmemicro.com/pic16f877a-more-microcontroller-features/">PIC16F877A</a> reads the D0 pin and if its low, fire up the buzzer and so on.</span></p>
<p><span style="font-weight: 400;">Here’s the wiring diagram:</span></p>
<p><img loading="lazy" decoding="async" class="alignnone" src="https://lh4.googleusercontent.com/dUHgVWYPYGKTBkkIi98OV0o0ohNzCquUNk7_t-gBAgCKJnwVBsFRA1-RQi_3v4Ow7o5SrNTauA4MCofZkgznBr7v6YK6oa85DZ1fmmQC3dUe1EENyWSN8JwlgUMkJ4shVRYXh4ql" alt="PIC flame sensor" width="1600" height="843" /></p>
<p id="SpHuJQC">The D0 pin of the fire detector module connects to RB0 while the buzzer’s red wire is connected to RB1.</p>
<p><span style="font-weight: 400;">The C code (XC8) for the circuit above is shown below:</span></p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">#define _XTAL_FREQ 4000000
#include &lt;xc.h&gt;

void main(void) {
    
    TRISBbits.TRISB0 = 1;
    TRISBbits.TRISB1 = 0;
    while(1){
        if(PORTBbits.RB0 == 0){
            PORTBbits.RB1 = 1;
        }else{
            PORTBbits.RB1 = 0;
        }
    }
    return;
}</code></pre></pre>
<p>The pin RB0 is an input pin while RB1 is an output pin. Hence their corresponding TRIS bits should be:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">TRISBbits.TRISB0 = 1; 
TRISBbits.TRISB1 = 0;</code></pre></pre>
<p>We then use simple if-else statements to check if the sensor detects a fire and then turn on or off the buzzer:</p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">while(1){
 if(PORTBbits.RB0 == 0){
    PORTBbits.RB1 = 1; 
 }else{ PORTBbits.RB1 = 0; 
 } 
}</code></pre></pre>
<p>There's no <em>loop()</em> function in XC8 so we create our own infinite loop using the <em>while(1)</em> statement.</p>
<p>That's it for interfacing the flame detector with a PIC microcontroller.</p>
<h3><b>Flame Sensor and ESP8266</b></h3>
<p><span style="font-weight: 400;">Finally we are down to our last microcontroller, the <a href="https://www.teachmemicro.com/category/tutorials/esp8266-tutorial/">ESP8266</a>. Of course, we will be using the flame sensor with the ESP8266 according to the latter’s capabilities. In this version, the user will receive a push notification on his or her smartphone everytime the fire detector is triggered.</span></p>
<p><span style="font-weight: 400;">Here’s the wiring diagram:</span></p>
<p><img loading="lazy" decoding="async" class="aligncenter" src="https://lh6.googleusercontent.com/jPuaGEAok0DvjF24L3ULtL-xCwLtbK6yiYEPgqj7w-BtBtZTVdHNKBFwePp68rLr-ScEfE1tPyygRPoDe5Odc5_ZnkM3hdkdtufbeq2wCUl-6FPlcdaEfoMaAng9-CwgWTGc-EA1" alt="nodemcu esp8266 flame sensor" width="951" height="780" /></p>
<p id="XsNDRWV">This diagram is the simplest since we don’t need the buzzer anymore. Note that I am using a <a href="https://www.teachmemicro.com/nodemcu-pinout/">NodeMCU ESP8266</a> board for this project. If this is your first time using the NodeMCU, please follow the <a href="https://www.teachmemicro.com/intro-nodemcu-arduino/">instructions to program it using the Arduino IDE</a>.</p>
<p><span style="font-weight: 400;">Here is the full sketch:</span></p>
<pre class="lang:arduino decode:true "><pre><code class="language-cpp">/*
 *  This sketch sends push notifications via Pushbullet App through PushingBox.
 *
 *  You need to create a service and scenario at pushingbox.com to acquire
 *  a device ID. Also change lines 12 and 13 to your own WiFi SSID and password
 *
 */
#include &lt;ESP8266WiFi.h&gt;
#include &lt;WiFiClient.h&gt;
#include &lt;ESP8266WebServer.h&gt;

const char* ssid     = &quot;&lt;your WiFi SSID&gt;&quot;;
const char* password = &quot;&lt;your WiFi password&gt;&quot;;

const char* host = &quot;api.pushingbox.com&quot;;
const char* devid = &quot;vADAB279A6A4DA5A&quot;;

const int sensor_pin = 14;

void setup()
{
    pinMode(sensor_pin,INPUT_PULLUP);
    pinMode(buzzer,OUTPUT);
    
    Serial.begin(115200);
    delay(10);

    // We start by connecting to a WiFi network

    Serial.println();
    Serial.println();
    Serial.print(&quot;Connecting to &quot;);
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(&quot;.&quot;);
    }

    Serial.println(&quot;&quot;);
    Serial.println(&quot;WiFi connected&quot;);
    Serial.println(&quot;IP address: &quot;);
    Serial.println(WiFi.localIP());
}

int value = 0;

void loop()
{
    delay(5000);

    if(digitalRead(sensor_pin) == LOW){  //flame sensor triggered

    Serial.print(&quot;connecting to &quot;);
    Serial.println(host);

    // Use WiFiClient class to create TCP connections
    WiFiClient client;
    const int httpPort = 80;
    if (!client.connect(host, httpPort)) {
        Serial.println(&quot;connection failed&quot;);
        return;
    }

    // We now create a URI for the request
    String url = &quot;/pushingbox&quot;;
    url += &quot;?devid=&quot;;
    url += devid;
    
    Serial.print(&quot;Requesting URL: &quot;);
    Serial.println(url);

    // This will send the request to the server
    client.print(String(&quot;GET &quot;) + url + &quot; HTTP/1.1\r\n&quot; +
                 &quot;Host: &quot; + host + &quot;\r\n&quot; +
                 &quot;Connection: close\r\n\r\n&quot;);
    unsigned long timeout = millis();
    while (client.available() == 0) {
        if (millis() - timeout &gt; 5000) {
            Serial.println(&quot;&gt;&gt;&gt; Client Timeout !&quot;);
            client.stop();
            return;
        }
    }

    // Read all the lines of the reply from server and print them to Serial
    while(client.available()) {
        String line = client.readStringUntil(&#039;\r&#039;);
        Serial.print(line);
    }

    Serial.println();
    Serial.println(&quot;closing connection&quot;);
    }else{;}
}</code></pre></pre>
<p><span style="font-weight: 400;">Before uploading this sketch, w</span><span style="font-weight: 400;">e need to configure <strong>Pushingbox</strong> and <strong>Pushbullet</strong> for this project to work. </span></p>
<p><span style="font-weight: 400;">First, go to <a href="http://pushingbox.com">Pushingbox</a> and signup or login to your account. You will then be redirected to the Dashboard page:</span></p>
<p><img decoding="async" class="aligncenter" src="https://lh3.googleusercontent.com/onidtVcEdB_-AD1N1hmd_U--Ugx_GuzftOOyi5w8TTPTqRhUsjVMeRMR6p6JqMimVi-vBtUCL99LkUj_blpx_Gt288EM4MFhF8tVVGvD5QDWhh2Yy0x1mbwSW7YEiX6X6BwbQBPT" /></p>
<p id="rwLevPd">Click the My Services tab and click “Add a service”:</p>
<p><img decoding="async" class="aligncenter" src="https://lh6.googleusercontent.com/7MLzXVKaxj_6xpC78ViRap8_tLodfaUrre6CDgHloPfnRW7EAc8TD2ll4DroYBgl2woBst32iE3uLW6O4W-DiVSCpasPornGV2nGZcF6J_mRErikaVSpIPdp_yre0Diq3sd2xlQ_" /></p>
<p id="WxAnCWK">Next, look for the <strong>Pushbullet</strong> service:</p>
<p><img decoding="async" class="aligncenter" src="https://lh4.googleusercontent.com/e8wWY2MwPV0Z6qqTO94GiIrpeiqaLFLR6i2fonsrNSWcGUEG8TP88ogMw3UXHsepGfd25LoU3Y2ROQGxa3ij6afPtaXdWGuhtrWf4qYVAFy88nmIth50tDN6wEzuzx1PaNeuFpdr" /></p>
<p id="RNORYDo">However, before your press the “Select this service” button, you need to have a Pushbullet account first.</p>
<p><span style="font-weight: 400;">Go to <a href="http://pushbullet.com">Pushbullet</a>:</span></p>
<p><img decoding="async" class="aligncenter" src="https://lh5.googleusercontent.com/B-9xPNHGioDovDHk7N0KuQiLvKsliBGQKHR9YeJErvbV8jZfQT1dmDbVAaTyyS2OhdwS3Mzs5Z4S9LVKkqZNY1Rp04Ih6sVb0qh-48QGJu37MaD6olFSVW674hWg7QZOOEFGO7oS" /></p>
<p id="phKrJrS">Sign up or login to your account. After that, find <i>Settings</i> on the dashboard. There you’ll find your access token:</p>
<p><img decoding="async" class="aligncenter" src="https://lh5.googleusercontent.com/9X0Yh57X6kKZTlxaA4vNpklb_VMOT9zzSohc8NYgA8y39g9zlo9in-szfwCD0b8SITQlbLAlq7jnQGn6AwTF2GIkL2EuZxjvYYfzDGhYj0DRTObwRr1UPxCtkatamWtlFxGNyono" /></p>
<p id="fPFfvEA">Go back to Pushingbox, click add a service again and this time click the “Select this service” button for pushbullet. A window appears:</p>
<p><img decoding="async" class="aligncenter" src="https://lh4.googleusercontent.com/uvIReILZSWdPHVwQvxeOUIQcJdArIZvx4IMd3VLN0HYhesHwkFISfT_kvY7N4nr5GiWaczJ1uoZmoaSYE6O1z_xx37T1_JJV6mIyl9wBlOoMy7Wvfisp5T5EDx6Nv4JYp3X7EVYG" /></p>
<p id="oQUGmGo">Give the configuration a name, paste your Pushbullet token then click submit.</p>
<p><span style="font-weight: 400;">Next, click the My Scenarios tab to add a scenario linked to the service just created:</span></p>
<p><img decoding="async" class="aligncenter" src="https://lh5.googleusercontent.com/s2ggarqvw_j8pYkbsUILpx8OwN4K79FVGl4103dIym8VyTRM-n4uQujiiDbIGxnTTnINR2qycaWjDsuKK7WqFgD_nnxZ8vtPfjINg18MPTJD--iUfR4uMUSOyWEyYghq-CbDjhAZ" /></p>
<p id="uUFvHoo">After creating the scenario, add an action:</p>
<p><img decoding="async" class="aligncenter" src="https://lh6.googleusercontent.com/LtbubUNpaf77sVNZwprFZZu1h772RvoPnsVmjWCFoHCwvCGe_QBUOKW14faxf_dFXKXKoZ_Tx-IuTegm67b9H5a0QXoMgquGU1x0ogRXWZEP6TQuYbOw2Bovxzzsow5srodB2aUw" /></p>
<p id="SqmKfkc">Make sure you select the appropriate scenario:</p>
<p><img decoding="async" class="aligncenter" src="https://lh3.googleusercontent.com/ZMtFdP_6dKMRC6ruvdydLsJjRrRRtxSam_LtvyQcoSoHrgOrDZGCTqCcRgsDSfbqbsTDaea_5ArY3gXzuYVxgBselD9w9DjguWlm9at2bS5ThenE5DhwyB8ufwYROm83hU1XXhZA" /></p>
<p id="BUFdKUn">A window appears; give the action title, push notification message and then click submit.</p>
<p><img decoding="async" class="aligncenter" src="https://lh4.googleusercontent.com/7YccBkESlKjf06DxCvKe_S4v0I_DmhCk8cO48EhPtYrC4igr5ko_39D76FE1iTBOZHXA5kFkzOPMNEt8zwqI_RzkSZaCG-x3Oz2tWm5fCS3bgB2QVV2wLgl1nDE_7Y229s0lY9Ci" /></p>
<p id="ICjEFEN">Finally, copy the d<em>evice ID</em> whose location is shown:</p>
<p><img decoding="async" class="aligncenter" src="https://lh5.googleusercontent.com/tScPkXAptG6vu4v3K3ezYKz_yn-gzTtaDO7AksWWUoISwe1xlsl_8F3aZGzyz8EsmJciGmsKTehxKaEzhmtw_zJUZzOsM8HWRG4HKtlYfG9mDSgZoNmLs0uWOhTF_KG6k6xnt5OD" /></p>
<p id="XcDpIRZ">Now on the sketch, locate line 16 and change the device ID:</p>
<pre class="lang:arduino decode:true"><pre><code class="language-cpp">const char* devid = &quot;vADAB279A6A4DA5A&quot;;</code></pre></pre>
<p><span style="font-weight: 400;">Also, don’t forget to provide your own WiFi’s SSID and password on lines 12 and 13:</span></p>
<pre class="lang:arduino decode:true"><pre><code class="language-cpp">const char* ssid     = &quot;&lt;your WiFi SSID&gt;&quot;;
const char* password = &quot;&lt;your WiFi password&gt;&quot;;</code></pre></pre>
<p><span style="font-weight: 400;">Upload the sketch and you're good to go! Now, install the Pushbullet app on your smartphone and login to your account. Everytime the fire detector is triggered, you will receive a push notification!</span></p>
<h3><b>Conclusion</b></h3>
<p>The flame sensor project here is limited in capture angle and range. However, there's a special module that contains five phototransistors:</p>
<p><a href="https://www.teachmemicro.com/wp-content/uploads/2020/01/multi-flame-sensor.jpg"><img loading="lazy" decoding="async" class="aligncenter wp-image-4104" src="https://www.teachmemicro.com/wp-content/uploads/2020/01/multi-flame-sensor.jpg" alt="wide angle flame sensor" width="562" height="442" srcset="https://www.teachmemicro.com/wp-content/uploads/2020/01/multi-flame-sensor.jpg 905w, https://www.teachmemicro.com/wp-content/uploads/2020/01/multi-flame-sensor-300x236.jpg 300w, https://www.teachmemicro.com/wp-content/uploads/2020/01/multi-flame-sensor-768x603.jpg 768w" sizes="auto, (max-width: 562px) 100vw, 562px" /></a>This 5-way fire detector module has a capture angle of 120°. <a href="http://s.click.aliexpress.com/e/_sKoiI2">Check prices here</a>.</p>
<p id="kaAcODv">Hopefully, this article helps you in any way. For any questions, reactions or suggestions, kindly drop comments below.</p>
<p>The post <a href="https://www.teachmemicro.com/flame-sensor-project-comprehensive-guide/">Flame Sensor Project: Comprehensive Guide</a> appeared first on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.teachmemicro.com/flame-sensor-project-comprehensive-guide/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Catch the Light PIC Game</title>
		<link>https://www.teachmemicro.com/catch-the-light-pic-game/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=catch-the-light-pic-game</link>
					<comments>https://www.teachmemicro.com/catch-the-light-pic-game/#respond</comments>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Fri, 20 Apr 2018 05:36:21 +0000</pubDate>
				<category><![CDATA[PIC Projects]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=2070</guid>

					<description><![CDATA[<p>This project is a simple PIC game where LEDs go on randomly one at a time. The objective is to “catch” the LED that’s on by pressing the corresponding button. For every catch, the score, displayed on a seven segment display, is incremented. The speed of the LEDs increase every time the score goes beyond &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/catch-the-light-pic-game/">Catch the Light PIC Game</a> appeared first on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>This project is a simple PIC game where LEDs go on randomly one at a time. The objective is to “catch” the LED that’s on by pressing the corresponding button. For every catch, the score, displayed on a seven segment display, is incremented. The speed of the LEDs increase every time the score goes beyond multiples of 5 (10, 15, 20).</p>
<p><span id="more-2070"></span></p>
<h3><strong>Introduction</strong></h3>
<p>This a good PIC project for beginners. All that is needed is four LEDs, four buttons and a dual 7 segment display. This project is coded using XC8. Here’s a video of the project simulated on Proteus ISIS:</p>
<p><center><br />
<iframe loading="lazy" width="560" height="315" src="https://www.youtube.com/embed/CYerTL5qGzA" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"></iframe></center><center></center><center></center>Making the LEDs go random is done through the rand() command and using TMR1’s value as seed. Each LED has a corresponding button. If the user presses a button, the RB change interrupt is triggered and then the PORTB (buttons) value is compared to the PORTC (LEDs) values. If a match occurs, the score is incremented.</p>
<h3><strong>Materials Needed</strong></h3>
<ul>
<li><a href="https://www.win-source.net/products/detail/microchip-technology/pic16f877a-i-p.html">PIC16F877A</a></li>
<li>Dual Seven-segment Display - Common Cathode</li>
<li>74LS48</li>
<li>5 x SPST Pushbuttons</li>
<li>4 x LEDs</li>
<li>5 x 10k ohm, 1/4 W Resistors</li>
<li>5 x 200 ohm, 1/4 W Resistors</li>
<li>4 MHz Crystal</li>
<li>2 x 22pF Ceramic Capacitor</li>
</ul>
<h3><strong>Schematic Diagram</strong></h3>
<p><a href="https://www.teachmemicro.com/wp-content/uploads/2018/04/catch_the_light.png"><img loading="lazy" decoding="async" class="size-large wp-image-2073 aligncenter" src="https://www.teachmemicro.com/wp-content/uploads/2018/04/catch_the_light-1024x710.png" alt="Catch the Light! PIC Project Game" width="618" height="428" srcset="https://www.teachmemicro.com/wp-content/uploads/2018/04/catch_the_light-1024x710.png 1024w, https://www.teachmemicro.com/wp-content/uploads/2018/04/catch_the_light-300x208.png 300w, https://www.teachmemicro.com/wp-content/uploads/2018/04/catch_the_light-768x533.png 768w, https://www.teachmemicro.com/wp-content/uploads/2018/04/catch_the_light-110x75.png 110w, https://www.teachmemicro.com/wp-content/uploads/2018/04/catch_the_light-24x17.png 24w, https://www.teachmemicro.com/wp-content/uploads/2018/04/catch_the_light-36x25.png 36w, https://www.teachmemicro.com/wp-content/uploads/2018/04/catch_the_light-48x33.png 48w" sizes="auto, (max-width: 618px) 100vw, 618px" /></a></p>
<p><span style="font-weight: 400;">I wanted to use RB change interrupt for faster reaction time. And since this interrupt triggers via four pins (RB4 to RB7), this project is limited to four buttons and, consequently, four LEDs. More LEDs and more buttons is possible but you can’t use interrupts anymore.</span></p>
<h3><strong>Code</strong></h3>
<pre class="lang:c++ decode:true "><pre><code class="language-cpp">/*
 * File:   catch_the_light.c
 * Author: Roland
 * 
 * Catch the Light Game
 * 
 * 
 * Created on April 19, 2018, 1:02 PM
 */

#pragma config FOSC = XT        // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

#define _XTAL_FREQ 4000000
#include &lt;xc.h&gt;

#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;time.h&gt;

int rand_num;
int old_rand_num;
int score;
int score_tens;
int score_ones;
int shifter;
int delay;

//a function that varies the delay. Because passing variables to __delay_ms() doesn&#039;t work
void someDelay(){
    switch(delay){
        case 500:
            __delay_ms(500);
            break;
        case 200:
            __delay_ms(200);
            break;
        case 100:
            __delay_ms(100);
            break;
        case 50:
            __delay_ms(50);
            break;
    }
    return;
}
void main(void) {
    
    T1CON = 0b00000001;             //turn on TMR1
    INTCON = 0b10101000;            //use global, TMR0 and RB change interrupts
    OPTION_REG = 0b00000100;        //use 1:32 prescale for TMR0
    TRISB = 0xF0;                   //inputs on RB4 to RB7, outputs for RB0 to RB3
    TRISC = 0;                      //all PORTC are outputs
    TRISD = 0;                      //all PORTD are outputs
    
    delay = 500;                    //default delay
   
    loop:
    while(1){
        srand(TMR1);                //use TMR1 value as seed for random
        rand_num = rand() % 9;      //generate random numbers from 0 to 9
        //filter out consecutive numbers, 0 and those that has at least two bits high (011 = 3, 101 = 5, 110 = 6, 111 = 7)
        if(rand_num == old_rand_num || rand_num == 0 || rand_num == 3 || rand_num == 5 || rand_num == 6 || rand_num == 7){ 
            goto loop;
        }
        PORTD = rand_num;           
        old_rand_num = rand_num;    //
        someDelay();                //a function that varies the delay. Because passing variables to __delay_ms() doesn&#039;t work 
    }
    
    return;
}

void interrupt isr(void){
    if(TMR0IF){
         //switch digits for every interrupt. Read about POV for better understanding
            shifter++;        
            switch(shifter){
                case 1:
                    PORTB = 0b11111110;
                    PORTC = score_ones;
                    break;
                case 2:
                    PORTB = 0b11111101;
                    PORTC = score_tens;
                    break;
                case 6:
                    shifter = 0;
                    break;
            }
            TMR0IF = 0;     //manual clearing of interrupt flag
    }
    if(RBIF){
        int dummy = PORTB;          //read PORTB to clear mismatch condition
        int masked = (PORTB &amp; 0xF0) &gt;&gt; 4;   //acquire pressed buttons
        if(~masked == (PORTD + 0xFFF0)){
            score++;
            score_tens = score/10;
            score_ones = score - score_tens*10;
            //adjust speed according to score
            if(score &lt;= 5){ 
                delay = 500;
            }else if(score &gt; 5 &amp;&amp; score &lt;= 10){
                delay = 200;
            }else if(score &gt; 10 &amp;&amp; score &lt;= 20){
                delay = 100;
            }else if(score &gt; 20 &amp;&amp; score &lt;= 30){
                delay = 50;
            }else if(score &gt; 99){
                score = 99;
            }else{
                delay = 500;
            }
        }
        RBIF = 0;
    }
}</code></pre></pre>
<p>&nbsp;</p>
<p>The post <a href="https://www.teachmemicro.com/catch-the-light-pic-game/">Catch the Light PIC Game</a> appeared first on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.teachmemicro.com/catch-the-light-pic-game/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Electronic Queuing System</title>
		<link>https://www.teachmemicro.com/electronic-queuing-system/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=electronic-queuing-system</link>
					<comments>https://www.teachmemicro.com/electronic-queuing-system/#comments</comments>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Tue, 17 Apr 2018 13:00:51 +0000</pubDate>
				<category><![CDATA[PIC Projects]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=2040</guid>

					<description><![CDATA[<p>The idea of this electronic queuing system is to display both sequence number and counter number in three seven segment displays. For example, when counter 1 presses his button, the number 1 shows up on the counter number segment. At the same time, the sequence number is incremented. This system can cater up to 99 &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/electronic-queuing-system/">Electronic Queuing System</a> appeared first on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The idea of this electronic queuing system is to display both sequence number and counter number in three seven segment displays. For example, when counter 1 presses his button, the number 1 shows up on the counter number segment. At the same time, the sequence number is incremented. This system can cater up to 99 customers and up to four counters.</p>
<h3><strong>Introduction</strong></h3>
<p><center><br />
<iframe loading="lazy" width="560" height="315" src="https://www.youtube.com/embed/Lsaks9oe9bI" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"></iframe></center><br />
This electronic queuing system uses the <a href="https://www.teachmemicro.com/pic-microcontroller-tutorials/pic16f877a-more-microcontroller-features/">PIC16F877A</a> as the microcontroller with four buttons, one 2-digit common cathode 7-segment display and one 1-digit common cathode 7-segment display. The project itself is not that hard and I would recommend it if you're new to <a href="https://www.teachmemicro.com/pic-microcontroller-tutorials/">PIC microcontrollers</a>. However, I suggest you learn more about <a href="https://www.teachmemicro.com/pic-microcontroller-tutorials/pic-interrupt-pic16f84a/">interrupt programming</a> to understand how the code works.</p>
<h3>Materials Needed</h3>
<ul>
<li><a href="https://www.win-source.net/products/detail/microchip-technology/pic16f877a-i-p.html">PIC16F877A</a></li>
<li>Dual Seven-segment Display - Common Cathode</li>
<li>Single Seven-segment Display - Common Cathode</li>
<li>74LS48 IC</li>
<li>5 x SPST Pushbutton</li>
<li>5 x 10k ohm, 1/4 W Resistors</li>
<li>4 MHz Crystal</li>
<li>2 x 22p Ceramic Capacitor</li>
</ul>
<h3><strong>Schematic Diagram</strong></h3>
<p><a href="https://www.teachmemicro.com/wp-content/uploads/2018/04/e_queue_schematic.png"><img loading="lazy" decoding="async" class="size-large wp-image-2063 aligncenter" src="https://www.teachmemicro.com/wp-content/uploads/2018/04/e_queue_schematic-1024x745.png" alt="Electronic Queuing System schematic diagram" width="618" height="450" srcset="https://www.teachmemicro.com/wp-content/uploads/2018/04/e_queue_schematic-1024x745.png 1024w, https://www.teachmemicro.com/wp-content/uploads/2018/04/e_queue_schematic-300x218.png 300w, https://www.teachmemicro.com/wp-content/uploads/2018/04/e_queue_schematic-768x559.png 768w, https://www.teachmemicro.com/wp-content/uploads/2018/04/e_queue_schematic-24x17.png 24w, https://www.teachmemicro.com/wp-content/uploads/2018/04/e_queue_schematic-36x26.png 36w, https://www.teachmemicro.com/wp-content/uploads/2018/04/e_queue_schematic-48x35.png 48w" sizes="auto, (max-width: 618px) 100vw, 618px" /></a></p>
<p>One 2-digit common cathode 7-segment display is used to count the customer number while 1 7-segment display is used to indicate the current counter. To prevent debounce on the button, I added some delays after each button press. You may need to push the button for about half a second to update the displays</p>
<h3><strong>Code</strong></h3>
<pre class="lang:c++ decode:true "><pre><code class="language-cpp">/*
 * File:   e_queue.c
 * Author: Roland
 * XC8 Code for Electronic Queuing System
 * Published on Teach Me Microcontrollers!
 * Created on April 13, 2018, 3:36 PM
 */

#define _XTAL_FREQ 4000000
#include &lt;xc.h&gt;

int count_ones;
int count_tens;
int count_val;
int counter_no;
int shifter = 0;
int dummy;

void main(void) {
    TRISB = 0b11111000;
    TRISC = 0;
    TRISD = 0;
    OPTION_REG = 0b00000100;
    INTCON = 0b10101000;
    PORTB = 0;
    PORTD = 0;
    
    while(1){;}
    
    return;
}

void updateValue(void){
     count_val++;
     count_tens = count_val/10;
     count_ones = count_val - 10*count_tens;
}
void interrupt isr(void){
    if(RBIF){
        __delay_ms(200);
       
   
        dummy = PORTB;   
        if(RB4==0){
            __delay_ms(200);
           // if(RB4==0){
                counter_no = 1;
                updateValue();
           // }
        }
        if(RB5==0){
            __delay_ms(200);
           // if(RB5==0){
             counter_no = 2;
             updateValue();
           // }
        }
        if(RB6==0){
            __delay_ms(200);
           // if(RB6==0){
             counter_no = 3;
             updateValue();
           // }
        }
        if(RB7==0){
            __delay_ms(200);
           // if(RB7==0){
             counter_no = 4;
             updateValue();
           // }
        }
        RBIF = 0;   //manual clearing of interrupt flag
    }
    
     if(TMR0IF){
            //switch digits for every interrupt. Read about POV for better understanding
            shifter++;        
            switch(shifter){
                case 1:
                    PORTC = 0b11111011;
                    PORTD = counter_no;
                    break;
                case 2:
                    PORTC = 0b11111101;
                    PORTD = count_ones;
                    break;
                case 3:
                    PORTC = 0b11111110;
                    PORTD = count_tens;
                    break;
                case 4:
                    shifter = 0;
                    break;
            }
            TMR0IF = 0;     //manual clearing of interrupt flag
    }
}</code></pre></pre>
<p>The buttons are attached to RB4 to RB7 so that I can use RB change <a href="https://www.teachmemicro.com/pic-microcontroller-tutorials/pic-interrupt-pic16f84a/">interrupt</a>. The POV shifting on the displays is done through <a href="https://www.teachmemicro.com/pic-microcontroller-tutorials/pic-timer-pic16f84a/">timer overflow</a> interrupt. You might need to change the prescale value via the OPTION register if you can still see the shifting between digits.</p>
<p>In XC8, multiple interrupts can be implemented by simply checking the corresponding interrupt flag bit. Here I checked the RBIF flag to check if the buttons RB4 to RB7 were pressed and the TMR0IF flag for shifting the digits in POV.</p>
<h3><strong>Design Files</strong></h3>
<p>Feel free to download the design files for this electronic queuing system project:</p>
[wpdm_package id='2042']
<p>If this was useful to you, a simple thanks through the comments would suffice!</p>
<p>The post <a href="https://www.teachmemicro.com/electronic-queuing-system/">Electronic Queuing System</a> appeared first on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.teachmemicro.com/electronic-queuing-system/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Adjustable Timer with Relay</title>
		<link>https://www.teachmemicro.com/adjustable-timer-relay/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=adjustable-timer-relay</link>
					<comments>https://www.teachmemicro.com/adjustable-timer-relay/#respond</comments>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Thu, 05 Apr 2018 08:11:31 +0000</pubDate>
				<category><![CDATA[PIC Projects]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=1979</guid>

					<description><![CDATA[<p>Project Overview This adjustable timer displays seconds, minutes, and hours and is powered by a PIC16F 877A microcontroller. There are five buttons included: start/stop, up for incrementing digits, down for decrementing digits, and left and right for moving between digits during adjustment. I’ve included a relay circuit that will trigger when the timer is finished. &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/adjustable-timer-relay/">Adjustable Timer with Relay</a> appeared first on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h3><strong>Project Overview</strong></h3>
<p>This adjustable timer displays seconds, minutes, and hours and is powered by a <a href="https://www.win-source.net/products/detail/microchip-technology/pic16f877a-i-p.html">PIC16F 877A</a> microcontroller. There are five buttons included: start/stop, up for incrementing digits, down for decrementing digits, and left and right for moving between digits during adjustment. I’ve included a relay circuit that will trigger when the timer is finished.</p>
<p><span id="more-1979"></span></p>
<h3><strong>Introduction</strong></h3>
<p><center><iframe loading="lazy" width="560" height="315" src="https://www.youtube.com/embed/QczSB2fHGME" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"></iframe></center><br />
A timer is a typical project but not really a simple one. Here, I designed a six-digit countdown timer that, when finished, will trigger a relay. The timer can be set to a maximum of 99 hours, 59 minutes, and 59 seconds and to a minimum of 1 second. This is useful as a timed switch for appliances or other electrical devices that draw power from mains.</p>
<h3><strong>Schematic Diagram</strong></h3>
<p><a href="https://www.teachmemicro.com/wp-content/uploads/2018/04/timer_relay.png"><img loading="lazy" decoding="async" class="aligncenter wp-image-1980 size-large" src="https://www.teachmemicro.com/wp-content/uploads/2018/04/timer_relay-1024x739.png" alt="Adjustable Timer with Relay schematic" width="618" height="446" srcset="https://www.teachmemicro.com/wp-content/uploads/2018/04/timer_relay-1024x739.png 1024w, https://www.teachmemicro.com/wp-content/uploads/2018/04/timer_relay-300x217.png 300w, https://www.teachmemicro.com/wp-content/uploads/2018/04/timer_relay-768x555.png 768w, https://www.teachmemicro.com/wp-content/uploads/2018/04/timer_relay-24x17.png 24w, https://www.teachmemicro.com/wp-content/uploads/2018/04/timer_relay-36x26.png 36w, https://www.teachmemicro.com/wp-content/uploads/2018/04/timer_relay-48x35.png 48w" sizes="auto, (max-width: 618px) 100vw, 618px" /></a></p>
<p>I wanted to use the least amount of components possible but I also don’t want to make the code too long. Thus, I settled to use one decoder even if it’s possible not to use one. The POV refresh rate is based on timer0 overflow with x32 prescale. This is using a 4 MHz crystal oscillator. Adjust the prescale through the OPTION register if you are using other oscillator frequencies.</p>
<h3><strong>Code</strong></h3>
<div class="hcb_wrap">
<pre class="prism undefined-numbers lang-c" data-lang="C"><pre><code class="language-cpp">/*
 * File:   timer_relay.c
 * Author: Roland Pelayo
 * For Adjustable Timer with Relay Project
 * See full tutorial at: https://www.teachmemicro.com/adjustable-timer-relay
 * Created on April 5, 2018, 11:25 AM
 */

#pragma config FOSC = XT        // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

#define _XTAL_FREQ 4000000
#include &lt;xc.h&gt;

//structs for the digits
struct _digits{
    int ones;
    int tens;
};
struct timer{
    struct _digits digits;          //a struct within a struct just because I wanted to :)
};

//declare struct objects for every tick
struct timer seconds = {9,5};
struct timer minutes = {9,5};
struct timer hours = {9,5};
//declare struct objects for updating
struct timer set_seconds = {9,5};
struct timer set_minutes = {9,5};
struct timer set_hours = {9,5};

bit start_timer;    //flag for starting or stopping the timer
int counter = 0;    //used for counting up/down digits during time adjustment
int shifter = 0;    //used for shifting digits left and right during time adjustment

int dummy;          //used to clear mismatch for RB Change interrupt

//Function for updating time every tick
void runTime(void){
     RB1 = !RB1;                    //make the dots blink for every tick
            seconds.digits.ones--;
            if(seconds.digits.ones &lt; 0){
                seconds.digits.tens--;
                seconds.digits.ones = 9;
                if(seconds.digits.tens &lt; 0){
                    minutes.digits.ones--;
                    minutes.digits.tens = 6;
                    if(minutes.digits.ones &lt; 0){
                        minutes.digits.tens--;
                        minutes.digits.ones = 9;
                        if(minutes.digits.tens &lt; 0){
                            hours.digits.ones--;
                            minutes.digits.tens = 6;
                            if(hours.digits.ones &lt; 0){
                                hours.digits.tens--;
                                hours.digits.ones = 9;
                            }
                        }
                    }
                }
            }
            if(seconds.digits.ones == 0 &amp;&amp; seconds.digits.tens == 0 &amp;&amp; minutes.digits.ones == 0 &amp;&amp; minutes.digits.tens == 0 &amp;&amp; hours.digits.ones == 0 &amp;&amp; hours.digits.tens == 0){
                RB2 = 1;
                start_timer = 0;
            }       
           set_seconds.digits.ones = seconds.digits.ones;
           set_seconds.digits.tens = seconds.digits.tens;
           set_minutes.digits.ones = minutes.digits.ones;
           set_minutes.digits.tens = minutes.digits.tens;
           set_hours.digits.ones = hours.digits.ones;
           set_hours.digits.tens = hours.digits.tens;
}

//Function for adjusting time
void adjustTime(int direction, int position){
    if(direction == 0){
        //decrement the digits for every button press
        switch(position){
            case 0:
                set_seconds.digits.ones--;
                if(set_seconds.digits.ones &lt; 0){
                   set_seconds.digits.ones = 9;
                }
                break;
            case 1:
                set_seconds.digits.tens--;
                if(set_seconds.digits.tens &lt; 0){
                   set_seconds.digits.tens = 5;
                }
                break;
            case 2:
                set_minutes.digits.ones--;
                if(set_minutes.digits.ones &lt; 0){
                   set_minutes.digits.ones = 9;
                }
                break;
            case 3:
                set_minutes.digits.tens--;
                if(set_minutes.digits.tens &lt; 0){
                   set_minutes.digits.tens = 5;
                }
                break;
            case 4:
                set_hours.digits.ones--;
                if(set_hours.digits.ones &lt; 0){
                   set_hours.digits.ones = 9;
                }
                break;
            case 5:
                set_hours.digits.tens--;
                if(set_hours.digits.tens &lt; 0){
                   set_hours.digits.tens = 9;
                }
                break;
        }
    }else{
       //increment the digits for every button press
       switch(position){
            case 0:
                set_seconds.digits.ones++;
                if(set_seconds.digits.ones &gt; 9){
                   set_seconds.digits.ones = 0;
                }
                break;
            case 1:
                set_seconds.digits.tens++;
                if(set_seconds.digits.tens &gt; 5){
                   set_seconds.digits.tens = 0;
                }
                break;
            case 2:
                set_minutes.digits.ones++;
                if(set_minutes.digits.ones &gt; 9){
                   set_minutes.digits.ones = 0;
                }
                break;
            case 3:
                set_minutes.digits.tens++;
                if(set_minutes.digits.tens &gt; 5){
                   set_minutes.digits.tens = 0;
                }
                break;
            case 4:
                set_hours.digits.ones++;
                if(set_hours.digits.ones &gt; 9){
                   set_hours.digits.ones = 0;
                }
                break;
            case 5:
                set_hours.digits.tens++;
                if(set_hours.digits.tens &gt; 9){
                   set_hours.digits.tens = 0;
                }
                break;
        } 
    }
}

//Function for checking buttons for adjusting time
void checkButtons(){
    __delay_ms(200);
    if(!RB3){
        shifter++;
        if(shifter &gt; 5) shifter = 0;
    }else if(!RB7){
        shifter--;
        if(shifter &lt; 0) shifter = 5;
    }else if(!RB5){
        adjustTime(1, shifter);     
    }else if(!RB6){
        adjustTime(0, shifter);
    }else{;}
    
    //the updating digits must be the same as the adjusted digits
    switch(shifter){
        case 0:
            seconds.digits.ones = set_seconds.digits.ones;
            break;
        case 1:
            seconds.digits.tens = set_seconds.digits.tens;
            break;
        case 2:
            minutes.digits.ones = set_minutes.digits.ones;
            break;
        case 3:
            minutes.digits.tens = set_minutes.digits.tens;
            break;
        case 4:
            hours.digits.ones = set_hours.digits.ones;
            break;
        case 5:
            hours.digits.tens = set_hours.digits.tens;
            break;
    }
}
void main(void) {
    INTCON = 0b10101000;        //Use RB Change interrupt
    OPTION_REG = 0b00000100;    //      Prescale 
    TRISB = 0b11111000;         //RB1, RB2 outputs, RB3-RB7 inputs
    TRISC = 0;                  //All PORTC output
    TRISD = 0;                  //All PORTD output
    RB2 = 0;                    //relay pin is initialized as cleared
    PORTC = 0;                  //initialize PORTC and PORTD as cleared
    PORTD = 0;
    
    while(1){  
        //When Start/Stop is pressed, the start_timer variable is toggled
        
        //Start Timer
        while(start_timer){
            __delay_ms(1000);   //ticks every second
            runTime();          //update digits per the specified delay above
        }
        
        //Stop/Pause Timer
        while(!start_timer){
            checkButtons();    //adjust time
        }
    }
    return;
}

//Function to turn on the dot as indicator of the digit currently adjusting
void setDot(void){
    if(!start_timer){
        if(shifter == counter-1){
            RB1 = 1;
        }else{
            RB1 = 0;
        }
    }                
}

//Interrupt service routine: The interrupts used are RB Change and Timer Interrupt. The shifting of digits is done every time
// timer0 overflows. The RB change interrupt is used for starting and stopping the timer.
void interrupt isr(void){
    //RB Change interrupt is triggered
    if(RBIF){
        dummy = PORTB;   
        if(!RB4){
            if(!start_timer){
                start_timer = 1;
            }else{
                start_timer = 0;
            }
        }
        RBIF = 0;   //manual clearing of interrupt flag
    }
    //Timer Overflow interrupt is triggered
    if(TMR0IF){
            //switch digits for every interrupt. Read about POV for better understanding
            counter++;        
            switch(counter){
                case 1:
                    PORTC = 0b11011111;
                    PORTD = seconds.digits.ones;
                    setDot();
                    break;
                case 2:
                    PORTC = 0b11101111;
                    PORTD = seconds.digits.tens;
                    setDot();
                    break;
                case 3:
                    PORTC = 0b11110111;
                    PORTD = minutes.digits.ones;
                    setDot();
                    break;
                case 4:
                    PORTC = 0b11111011;
                    PORTD = minutes.digits.tens;
                    setDot();
                    break;
                case 5:
                    PORTC = 0b11111101;
                    PORTD = hours.digits.ones;
                    setDot();
                    break;
                case 6:
                    PORTC = 0b11111110;
                    PORTD = hours.digits.tens;
                    setDot();
                    break;
                case 7:
                    counter = 0;
                    break;
            }
            TMR0IF = 0;     //manual clearing of interrupt flag
    }
}</code></pre></pre>
</div>
<p>The project was coded using Microchip XC8. There are some peculiarities with my code, especially the use of structs. You can actually remove the structs and just use simple variables. I just find the structs more readable given the number of variables I had to use.</p>
<p>I used two <a href="https://www.teachmemicro.com/pic-microcontroller-tutorials/pic-interrupt-pic16f84a/">interrupts</a> in this code: timer overflow and RB change interrupt. The timer overflow interrupt is used for POV while the RB change interrupt is responsible for starting or stopping the timer. The adjustments are not done with interrupts but by simple button testing. The debounce problem is handled by a delay after every button pressed.</p>
<p>&nbsp;</p>
<p>The post <a href="https://www.teachmemicro.com/adjustable-timer-relay/">Adjustable Timer with Relay</a> appeared first on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.teachmemicro.com/adjustable-timer-relay/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Digital Thermometer with Nokia 3310 LCD</title>
		<link>https://www.teachmemicro.com/digital-thermometer-nokia-3310-lcd/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=digital-thermometer-nokia-3310-lcd</link>
					<comments>https://www.teachmemicro.com/digital-thermometer-nokia-3310-lcd/#respond</comments>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Wed, 04 Apr 2018 09:47:23 +0000</pubDate>
				<category><![CDATA[PIC Projects]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=1968</guid>

					<description><![CDATA[<p>The Nokia 3310 LCD is a cheap option for those who want to add a graphical display to their microcontroller projects. This digital thermometer project uses this LCD to display the temperature from a LM35 temperature sensor. Introduction A temperature sensor is a fairly common microcontroller project. The sensing device in this project is a &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/digital-thermometer-nokia-3310-lcd/">Digital Thermometer with Nokia 3310 LCD</a> appeared first on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The Nokia 3310 LCD is a cheap option for those who want to add a graphical display to their microcontroller projects. This digital thermometer project uses this LCD to display the temperature from a LM35 temperature sensor.</p>
<p><span id="more-1968"></span></p>
<h3><strong>Introduction</strong></h3>
<p>A temperature sensor is a fairly common microcontroller project. The sensing device in this project is a LM35 integrated circuit that gives 10mV per degree celsius and can detect from 0 degree celsius to 100 degree celsius.</p>
<p>The <a href="https://www.win-source.net/products/detail/microchip-technology/pic16f877a-i-p.html">PIC16F877A</a> microcontroller used in this project has 10-bit ADC and a minimum sensible voltage of 4.88 mV. This means the conversion factor for the LM35 should be 10mV/2.88mV or 2.046. This value is used in the code to convert the ADC value to temperature in degree celsius.</p>
<p>The <a href="https://www.teachmemicro.com/use-pic16f877a-nokia-3310-xc8/">Nokia 3310 LCD</a> uses SPI for interfacing with a microcontroller. I’ve created two libraries for the PIC16F877A to communicate with this LCD and is included in the downloadable design files.</p>
<h3><strong>Materials Needed</strong></h3>
<ul>
<li>PIC16F877A</li>
<li>Nokia 3310/5110 LCD Breakout Board</li>
<li>LM35</li>
<li>4.7 uF Mylar Capacitor</li>
<li>SPST Pushbutton</li>
<li>4 MHz Crystal</li>
<li>2 x 22pF Ceramic Capacitor</li>
</ul>
<h3><strong>Schematic Diagram</strong></h3>
<h3><a href="https://www.teachmemicro.com/wp-content/uploads/2018/04/digital_thermometer_nokia_lcd.png"><img loading="lazy" decoding="async" class="wp-image-1971 size-large aligncenter" src="https://www.teachmemicro.com/wp-content/uploads/2018/04/digital_thermometer_nokia_lcd-1024x700.png" alt="Digital Thermometer Nokia 3310 LCD" width="618" height="422" srcset="https://www.teachmemicro.com/wp-content/uploads/2018/04/digital_thermometer_nokia_lcd-1024x700.png 1024w, https://www.teachmemicro.com/wp-content/uploads/2018/04/digital_thermometer_nokia_lcd-300x205.png 300w, https://www.teachmemicro.com/wp-content/uploads/2018/04/digital_thermometer_nokia_lcd-768x525.png 768w, https://www.teachmemicro.com/wp-content/uploads/2018/04/digital_thermometer_nokia_lcd-110x75.png 110w, https://www.teachmemicro.com/wp-content/uploads/2018/04/digital_thermometer_nokia_lcd-24x16.png 24w, https://www.teachmemicro.com/wp-content/uploads/2018/04/digital_thermometer_nokia_lcd-36x25.png 36w, https://www.teachmemicro.com/wp-content/uploads/2018/04/digital_thermometer_nokia_lcd-48x33.png 48w" sizes="auto, (max-width: 618px) 100vw, 618px" /></a></h3>
<p>This project was tested and simulated using Proteus ISIS. You will need the <a href="https://www.8051projects.net/download-d217-nokia-3310-lcd-proteus-model.html">Nokia 3310 LCD Proteus library</a> to do your own simulations.</p>
<h3><strong>Code</strong></h3>
<pre class="lang:c++ decode:true"><pre><code class="language-cpp">/*
 * File:   nokia_thermometer.c
 * Author: Roland Pelayo
 * For Digital Thermometer with Nokia LCD Project
 * 
 * Created on April 4, 2018, 3:55 PM
 */

#pragma config FOSC = XT        // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

#define _XTAL_FREQ 20000000
#include &lt;xc.h&gt;
#include &lt;stdio.h&gt;
#include &lt;conio.h&gt;
#include &lt;stdlib.h&gt;
#include &quot;pcd8544.h&quot;

int temp = 0;

unsigned int ADC_read(int channel){
    ADFM = 1; //results right justified
    ADCS0 = 0; //conversion speed = 4*Tosc
    ADCS1 = 0;
    ADCS2 = 1;
    ADCON0bits.CHS = channel;  
    ADON = 1; //turn on ADC
    __delay_ms(1);  
    GO_DONE = 1;
    while(ADCON0bits.GO_DONE == 1);
    unsigned int adval = (ADRESH &lt;&lt; 8) + ADRESL; //
    return adval;
}

void main(void) {
    lcdBegin();                //initialize LCD
    lcdClear();                //clear LCD screen
    lcdCursor(0, 0);           //place cursor at x=0,y=0
    lcdPrint(&quot;Temperature: &quot;);
    while(1){
        int adval = ADC_read(0); //read signal from LM35
        char buf[5];             //buffer to hold ADC value
        itoa(buf, adval/2.046, 10);    //convert integer (now in celsius) to string
        lcdCursor(25, 2);              //place cursor at x=25,y=2
        lcdPrint(buf);                 //print temperature value
        lcdPrint(&quot;  C&quot;);              
        __delay_ms(1000);              //some delay
    }
    return;
}</code></pre></pre>
<p>As mentioned, this project requires two libraries, pcd8544.h and SPI.h, to work. They are included in the downloadable files.</p>
<p>The signal from the LM35 is easily converted to readable data using <a href="https://www.teachmemicro.com/pic-microcontroller-tutorials/pic-adc/">analog to digital conversion</a>. In my code, the reading is done every second. You can adjust the delay for the code according to your needs.</p>
<p>The post <a href="https://www.teachmemicro.com/digital-thermometer-nokia-3310-lcd/">Digital Thermometer with Nokia 3310 LCD</a> appeared first on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.teachmemicro.com/digital-thermometer-nokia-3310-lcd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PIC16F877A Stepper Motor Controller</title>
		<link>https://www.teachmemicro.com/stepper-motor-controller/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=stepper-motor-controller</link>
					<comments>https://www.teachmemicro.com/stepper-motor-controller/#comments</comments>
		
		<dc:creator><![CDATA[Roland Pelayo]]></dc:creator>
		<pubDate>Wed, 04 Apr 2018 07:41:42 +0000</pubDate>
				<category><![CDATA[PIC Projects]]></category>
		<guid isPermaLink="false">https://www.teachmemicro.com/?p=1953</guid>

					<description><![CDATA[<p>This project is a stepper motor controller featuring the PIC16F877A microcontroller and coded using XC8. The controller has three control buttons: start, stop, forward and reverse. The project was created with a six-wire unipolar stepper motor in mind but may work with other stepper motors with some modifications. Introduction A stepper motor requires pulses in &#8230;</p>
<p>The post <a href="https://www.teachmemicro.com/stepper-motor-controller/">PIC16F877A Stepper Motor Controller</a> appeared first on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>This project is a stepper motor controller featuring the <a href="https://www.win-source.net/products/detail/microchip-technology/pic16f877a-i-p.html">PIC16F877A</a> microcontroller and coded using XC8. The controller has three control buttons: start, stop, forward and reverse. The project was created with a six-wire unipolar stepper motor in mind but may work with other stepper motors with some modifications.</p>
<p><span id="more-1953"></span></p>
<h3><strong>Introduction</strong></h3>
<p>A stepper motor requires pulses in specific pattern to move or “step”. Generally, there are three ways to move a stepper motor.</p>
<ul>
<li>Half-step - a single wire is set high while the others are set low. The pulsed wires are alternated to make a full revolution</li>
<li>Full-step - two wires are set high simultaneously while the others are set low. The paired wires are alternated to make a full revolution.</li>
<li>Microstepping - half-step and full-step patterns are combined to make finer movements.</li>
</ul>
<p>This project uses microstepping as it is the most commonly used stepping method.</p>
<h3><strong>Materials Needed</strong></h3>
<ul>
<li>PIC16F877A</li>
<li>Unipolar 6-wire Stepper Motor</li>
<li>5 x SPST pushbuttons</li>
<li>4 x BC547 NPN transistor</li>
<li>5 x 10k 1/4 W resistor</li>
<li>4 MHz crystal</li>
<li>2 x 22pF ceramic capacitor</li>
</ul>
<h3><strong>Schematic Diagram</strong></h3>
<p>The schematic diagram for the stepper motor controller is shown below:</p>
<p><a href="https://www.teachmemicro.com/wp-content/uploads/2018/04/stepper_motor_controller_sch.png"><img loading="lazy" decoding="async" class="wp-image-1954 size-large aligncenter" src="https://www.teachmemicro.com/wp-content/uploads/2018/04/stepper_motor_controller_sch-1024x667.png" alt="PIC16F877A Stepper Motor Controller Schematic" width="618" height="403" srcset="https://www.teachmemicro.com/wp-content/uploads/2018/04/stepper_motor_controller_sch-1024x667.png 1024w, https://www.teachmemicro.com/wp-content/uploads/2018/04/stepper_motor_controller_sch-300x195.png 300w, https://www.teachmemicro.com/wp-content/uploads/2018/04/stepper_motor_controller_sch-768x500.png 768w, https://www.teachmemicro.com/wp-content/uploads/2018/04/stepper_motor_controller_sch-24x16.png 24w, https://www.teachmemicro.com/wp-content/uploads/2018/04/stepper_motor_controller_sch-36x23.png 36w, https://www.teachmemicro.com/wp-content/uploads/2018/04/stepper_motor_controller_sch-48x31.png 48w" sizes="auto, (max-width: 618px) 100vw, 618px" /></a></p>
<p>Basically, each of the wires of the stepper motor is connected to a transistor switch to allow more current through the motor. A pulse from the microcontroller turns on a transistor and effectively shorts the connected wire to ground. Since the common pin is tied to the positive supply (which is separate from the microcontroller supply), the microcontroller pin must be low to make a stepper motor wire high.</p>
<p>I’ve included LEDs to have a visual representation of the stepping patterns. Obviously, omitting them will not have any adverse effect on the project’s performance.</p>
<p>Lastly, the choice of transistor depends on the current draw of your chosen stepper motor. For larger stepper motors, I suggest using darlington pairs.</p>
<h3><strong>Code</strong></h3>
<pre class="lang:c decode:true"><pre><code class="language-cpp">/*
 * File:   stepper.c
 * Author: Roland Pelayo
 * For Stepper Motor Controller Project published on Teach Me Microcontrollers!
 * Created on April 4, 2018, 1:28 PM
 */
#pragma config FOSC = XT // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)

#define _XTAL_FREQ 4000000
#include &lt;xc.h&gt;

int mode;         //1 = forward ; 0 = reverse
int ready;        //1 = stop ; 0 = start
int dummy;

//Main Routine
void main(void) {
    
    ready = 1;       //motor is stopped by default;
    TRISB = 0xF0;    //RB4, RB5, RB6, RB7 pins are input
    TRISD = 0;       //all PORTD pins are output
    INTCON = 0x88;   //global interrupts enabled, RB port change interrupt enabled
    PORTB = 0;       //initialize PORTB pins to cleared
    PORTD = 0;       //initialize PORTD pins to cleared
    
    while(1){
        if(ready==0){
            if(mode==1){          //forward direction
                PORTD = 0b11110110;
                __delay_ms(500);
                PORTD = 0b11111110;
                __delay_ms(500);
                PORTD = 0b11111100;
                __delay_ms(500);
                PORTD = 0b11111101;
                __delay_ms(500);
                PORTD = 0b11111001;
                __delay_ms(500);
                PORTD = 0b11111011;
                __delay_ms(500);
                PORTD = 0b11110011;
                __delay_ms(500);
            }         
            if(mode==0){        //reverse direction
                PORTD = 0b11110111;
                __delay_ms(500);
                PORTD = 0b11110011;
                __delay_ms(500);
                PORTD = 0b11111011;
                __delay_ms(500);
                PORTD = 0b11111001;
                __delay_ms(500);
                PORTD = 0b11111101;
                __delay_ms(500);
                PORTD = 0b11111100;
                __delay_ms(500);  
                PORTD = 0b11111110;
                __delay_ms(500);
                PORTD = 0b11110110;
                __delay_ms(500);
            }
      }
    }
    return;
}

//Interrupt Service Routine
void interrupt isr(void){
    if(RBIF){           //check RB change interrupt flag if triggered
      dummy = PORTB;    //read PORTB to clear mismatch condition
      if(!RB6){         //stop button pressed?
          ready = 1;
      }else if(!RB7){   //start button pressed?
          ready = 0;
      }else if(!RB5){   //forward button pressed?
          mode = 0;
      }else if(!RB4){   //reverse button pressed?
          mode = 1;
      }else{;}
    }
    RBIF = 0;
}</code></pre></pre>
<p>The four buttons are purposely tied to RB4, RB5, RB6 and RB7 because I wanted to use RB change interrupt. This allows me to change the stepper motor behavior even if the motor is currently turning. Using an interrupt with buttons also diminishes debounce problems. If you’re having problems understanding the code, kindly refer to my <a href="https://www.teachmemicro.com/pic-microcontroller-tutorials/pic-interrupt-pic16f84a/">interrupt tutorial</a>.</p>
<p>&nbsp;</p>
<p>The post <a href="https://www.teachmemicro.com/stepper-motor-controller/">PIC16F877A Stepper Motor Controller</a> appeared first on <a href="https://www.teachmemicro.com">Microcontroller Tutorials</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.teachmemicro.com/stepper-motor-controller/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: www.teachmemicro.com @ 2026-07-21 16:55:30 by W3 Total Cache
-->