tag:blogger.com,1999:blog-39982804971330810402024-02-19T16:55:42.614+01:00PIC Microcontroller ProjectsElectronic projects using Microchip PIC® microcontrollers for hobbyists and students with C codes and simulation files.PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comBlogger170125tag:blogger.com,1999:blog-3998280497133081040.post-43932752387660847882017-09-25T23:59:00.000+02:002018-06-02T19:30:32.965+02:00Remote controlled USB mouse using PIC18F4550Building a USB mouse using PIC18F4550 microcontroller and CCS C compiler is easy as shown in the link below:<br />
<a href="http://ccspicc.blogspot.com/2016/09/pic18f4550-usb-hid-mouse-pic18f2550.html" target="_blank">USB Mouse using PIC18F4550 microcontroller</a><br />
Also, it is not hard to add an infrared remote control to the previous USB project. This post shows how did I build a simple IR remote controlled USB mouse using PIC18F4550 microcontroller and Car MP3 IR remote control (NEC protocol).<br />
The link below shows how to decode NEC IR remote control (remote controls may not have the same code messages, so to know the code of each button we've to decode it first):<br />
<a href="http://ccspicc.blogspot.com/2017/07/nec-protocol-decoder-pic-microcontroller.html" target="_blank">NEC Protocol decoder with PIC16F887 microcontroller</a><br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC18F4550 microcontroller</li>
<li>IR remote control (NEC protocol)</li>
<li>IR receiver</li>
<li>8MHz Crystal Oscillator</li>
<li>2 x 22pF capacitors</li>
<li>47uF polarized capacitor </li>
<li>470nF Capacitor</li>
<li>10K ohm resistor </li>
<li>USB Connector</li>
<li>+5V Power Supply (USB VCC can be used)</li>
<li>Breadboard</li>
<li>Jumper Wires</li>
</ul>
<script async="" src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<ins class="adsbygoogle" data-ad-client="ca-pub-9821904216837075" data-ad-format="fluid" data-ad-layout="in-article" data-ad-slot="9358819745" style="display: block; text-align: center;"></ins><script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
<span style="color: #cc0000;"><span style="font-size: large;">Remote controlled USB mouse using PIC18F4550 circuit:</span></span><br />
<div style="text-align: center;">
</div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibpvTqVzdG6O6mHkzQO4INikhfryUD2E3MtR3YATixjcDa1W02UL0sPmYemv4LEwlKVR6-GgdVXDUdAOFfr-cfb4Wb7AB4Vl1U2MSHAoyzRCKdtiB0kTQzSbnVKEI7DfQN_I_saUKObOU/s1600/pic18f4550+usb+mouse+ir+remote+control.png" imageanchor="1"><img alt="Remote controlled USB mouse using PIC18F4550 circuit" border="0" height="314" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibpvTqVzdG6O6mHkzQO4INikhfryUD2E3MtR3YATixjcDa1W02UL0sPmYemv4LEwlKVR6-GgdVXDUdAOFfr-cfb4Wb7AB4Vl1U2MSHAoyzRCKdtiB0kTQzSbnVKEI7DfQN_I_saUKObOU/s640/pic18f4550+usb+mouse+ir+remote+control.png" title="Remote controlled USB mouse using PIC18F4550 circuit" width="640" /></a> </div>
The IR receiver has 3 pins: GND, VCC and OUT. The OUT pin is connected to RB0 (INT0 pin).<br />
The circuit shown above is powered from an external 5V source which means there is no need to connect the VCC pin of the USB connector, but this pin can be used to supply the circuit and therefore the external 5V source has to be removed.<br />
In this project the microcontroller runs with 8 MHz crystal oscillator and MCLR pin function is disabled.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Remote controlled USB mouse using PIC18F4550 C code:</span></span><br />
The C code below was tested with CCS C compiler version 5.051.<br />
In this project the PIC18F4550 MCU runs with 8 MHz crystal oscillator and it is configured so that the MCU runs at 8 MHz. I enabled PLL2 for the USB module in order to get 48 MHz which allows the USB module to run at full speed (12 Mbps).<br />
The output of the IR receiver is connected to the external interrupt 0 pin (RB0/INT0) and with that I used it to decode the IR remote control. The NEC code massage is 32-bit long (2 words).<br />
I used Timer1 to measure pulse and space widths and I used Timer1 interrupt to reset the decoding process in case of very long pulse or very long space (time out). Timer1 is configured to increment every 1 us. So for example for the 9 ms pulse I used the interval between 8500 and 9500.<br />
I used Timer3 with the repeated remote control codes. If a button is pressed with hold the remote control will send the button massage code and then it sends <span style="background-color: yellow;">9 ms pulse --> 2.5 ms space --> 562 us</span> pulse and so on every 110 ms. (more details at: <a href="http://www.sbprojects.com/knowledge/ir/nec.php" target="_blank">http://www.sbprojects.com/knowledge/ir/nec.php</a>)<br />
From previous if a button is pressed with hold it will continuously sets Timer3 to the value 25000 ( <span style="background-color: yellow;">set_timer3(25000);</span> ). When the button is released Timer3 will overflow and its interrupt will reset the code message ( <span style="background-color: yellow;">nec_code = 0;</span> ).<br />
<br/>
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- ccslink1 -->
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-9821904216837075"
data-ad-slot="2075108943"
data-ad-format="link"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script><br/>
The function <span style="background-color: yellow;">usb_put_packet(1, out_data, 4, USB_DTS_TOGGLE);</span> sends a packet of 4 bytes from the array <span style="background-color: yellow;">out_data</span> over USB.The variable array <span style="background-color: yellow;">out_data</span> is a 4-byte array where:<br />
Byte 1 corresponds to button status. The left button of the mouse is
represented by <span style="background-color: yellow;">1</span> and the right button is represented by <span style="background-color: yellow;">3</span>.<br />
Byte 2 and byte 3 correspond to X axis and Y axis directions respectively.<br />
Byte 4 for the mouse wheel which is not used in this project.<br />
The
X axis and Y axis bytes are signed int8 which can vary from -127 to
127. The ( - ) sign indicates direction ( for X axis left/right and for Y
axis up/down) and the number means number of steps at a time.<br />
The remote control which I used is shown below:<br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6Z1ITNT8EF5JEVyCLXf0rPCfdr_pfe69pPWSl-wmwIRCIQsAF_AjMAMM3_Tk3H1cyIgrDxkE-b6iXoJ06JV4NgRLeRtH7aHwVd7CTtRKNhbtvE-175fWkk0Q7Ja76miogqVKw0U3zGkU/s1600/car-mp3-nec-remote-control.jpg" imageanchor="1"><img alt="Car MP3 IR remote control" border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6Z1ITNT8EF5JEVyCLXf0rPCfdr_pfe69pPWSl-wmwIRCIQsAF_AjMAMM3_Tk3H1cyIgrDxkE-b6iXoJ06JV4NgRLeRtH7aHwVd7CTtRKNhbtvE-175fWkk0Q7Ja76miogqVKw0U3zGkU/s320/car-mp3-nec-remote-control.jpg" title="Car MP3 IR remote control" width="180" /></a></div>
I used the buttons numbered from 1 to 6 where:<br />
<style>
#mytable{
width:60%
}
#mytable, th, td {
border: 1px solid black;
border-collapse: collapse;
}
#mytable th, #mytable td {
padding: 5px;
text-align: center;
}
</style>
<br />
<table id="mytable">
<tbody>
<tr>
<th>Button Number</th>
<th>Function</th>
<th>Code</th>
</tr>
<tr>
<td>1</td>
<td>Left button</td>
<td>0x40BF30CF</td>
</tr>
<tr>
<td>2</td>
<td>Move cursor up</td>
<td>0x40BFB04F</td>
</tr>
<tr>
<td>3</td>
<td>Right button</td>
<td>0x40BF708F</td>
</tr>
<tr>
<td>4</td>
<td>Move cursor left</td>
<td>0x40BF08F7</td>
</tr>
<tr>
<td>5</td>
<td>Move cursor down</td>
<td>0x40BF8877</td>
</tr>
<tr>
<td>6</td>
<td>Move cursor right</td>
<td>0x40BF48B7</td>
</tr>
</tbody></table>
<br />
The complete C code is below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">// IR Remote controlled USB mouse using PIC18F4550 microcontroller CCS C code.</span>
<span style="color: #7e7e7e;">// Car MP3 IR remote control is used (NEC protocol)</span>
<span style="color: #7e7e7e;">// http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;">// electronnote@gmail.com</span>
<span style="color: red;">#include</span> <18F4550.h>
<span style="color: red;">#fuses</span> HS, CPUDIV1, PLL2, USBDIV, VREGEN, NOMCLR, NOWDT, NOLVP
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 8MHz)
<span style="color: red;">#include</span> <usb_desc_mouse.h>
<span style="color: red;">#include</span><pic18_usb.h>
<span style="color: red;">#include</span><usb.c>
<span style="color: blue;">signed</span> <span style="color: blue;">int8</span> out_data[4] = {0, 0, 0, 0};
<span style="color: blue;">short</span> nec_ok = 0, repeated = 0;
<span style="color: blue;">int8</span> i, nec_state = 0;
<span style="color: blue;">int32</span> nec_code;
<span style="color: red;">#INT_EXT</span> <span style="color: #7e7e7e;">// External interrupt</span>
<span style="color: blue;">void</span> ext_isr(<span style="color: blue;">void</span>){
<span style="color: blue;">int16</span> time;
<span style="color: blue;">if</span>(nec_state != 0){
time = get_timer1(); <span style="color: #7e7e7e;">// Store Timer1 value</span>
set_timer1(0); <span style="color: #7e7e7e;">// Reset Timer1</span>
}
<span style="color: blue;">switch</span>(nec_state){
<span style="color: blue;">case</span> 0 : <span style="color: #7e7e7e;">// Start receiving IR data (we're at the beginning of 9ms pulse)</span>
setup_timer_1( T1_INTERNAL | T1_DIV_BY_2 ); <span style="color: #7e7e7e;">// Enable Timer1 module with internal clock source and prescaler = 2</span>
set_timer1(0); <span style="color: #7e7e7e;">// Reset Timer1 value</span>
nec_state = 1; <span style="color: #7e7e7e;">// Next state: end of 9ms pulse (start of 4.5ms space)</span>
i = 0;
ext_int_edge( L_TO_H ); <span style="color: #7e7e7e;">// Toggle external interrupt edge</span>
<span style="color: blue;">return</span>;
<span style="color: blue;">case</span> 1 : <span style="color: #7e7e7e;">// End of 9ms pulse</span>
<span style="color: blue;">if</span>((time > 9500) || (time < 8500)){ <span style="color: #7e7e7e;">// Invalid interval ==> stop decoding and reset</span>
nec_state = 0; <span style="color: #7e7e7e;">// Reset decoding process</span>
setup_timer_1(T1_DISABLED); <span style="color: #7e7e7e;">// Stop Timer1 module</span>
}
<span style="color: blue;">else</span>
nec_state = 2; <span style="color: #7e7e7e;">// Next state: end of 4.5ms space (start of 562µs pulse)</span>
ext_int_edge( H_TO_L ); <span style="color: #7e7e7e;">// Toggle external interrupt edge</span>
<span style="color: blue;">return</span>;
<span style="color: blue;">case</span> 2 : <span style="color: #7e7e7e;">// End of 4.5ms space</span>
<span style="color: blue;">if</span>((time > 5000) || (time < 1500)){ <span style="color: #7e7e7e;">// Invalid interval ==> stop decoding and reset</span>
nec_state = 0; <span style="color: #7e7e7e;">// Reset decoding process</span>
setup_timer_1(T1_DISABLED); <span style="color: #7e7e7e;">// Stop Timer1 module</span>
<span style="color: blue;">return</span>;
}
nec_state = 3; <span style="color: #7e7e7e;">// Next state: end of 562µs pulse (start of 562µs or 1687µs space)</span>
<span style="color: blue;">if</span>(time < 3000) <span style="color: #7e7e7e;">// Check if previous code is repeated</span>
repeated = 1;
ext_int_edge( L_TO_H ); <span style="color: #7e7e7e;">// Toggle external interrupt edge</span>
<span style="color: blue;">return</span>;
<span style="color: blue;">case</span> 3 : <span style="color: #7e7e7e;">// End of 562µs pulse</span>
<span style="color: blue;">if</span>((time > 700) || (time < 400)){ <span style="color: #7e7e7e;">// Invalid interval ==> stop decoding and reset</span>
nec_state = 0; <span style="color: #7e7e7e;">// Reset decoding process</span>
setup_timer_1(T1_DISABLED); <span style="color: #7e7e7e;">// Disable Timer1 module</span>
}
<span style="color: blue;">else</span>{
<span style="color: #7e7e7e;">// Check if the code is repeated</span>
<span style="color: blue;">if</span>(repeated){
set_timer3(25000);
repeated = 0;
nec_ok = 1; <span style="color: #7e7e7e;">// Decoding process is finished with success</span>
<span style="color: blue;">return</span>;
}
nec_state = 4; <span style="color: #7e7e7e;">// Next state: end of 562µs or 1687µs space</span>
}
ext_int_edge( H_TO_L ); <span style="color: #7e7e7e;">// Toggle external interrupt edge</span>
<span style="color: blue;">return</span>;
<span style="color: blue;">case</span> 4 : <span style="color: #7e7e7e;">// End of 562µs or 1687µs space</span>
<span style="color: blue;">if</span>((time > 1800) || (time < 400)){ <span style="color: #7e7e7e;">// Invalid interval ==> stop decoding and reset</span>
nec_state = 0; <span style="color: #7e7e7e;">// Reset decoding process</span>
setup_timer_1(T1_DISABLED); <span style="color: #7e7e7e;">// Disable Timer1 module</span>
<span style="color: blue;">return</span>;
}
<span style="color: blue;">if</span>( time > 1000) <span style="color: #7e7e7e;">// If space width > 1ms (short space)</span>
bit_set(nec_code, (31 - i)); <span style="color: #7e7e7e;">// Write 1 to bit (31 - i)</span>
<span style="color: blue;">else</span> <span style="color: #7e7e7e;">// If space width < 1ms (long space)</span>
bit_clear(nec_code, (31 - i)); <span style="color: #7e7e7e;">// Write 0 to bit (31 - i)</span>
i++;
<span style="color: blue;">if</span>(i > 31){ <span style="color: #7e7e7e;">// If all bits are received</span>
nec_ok = 1; <span style="color: #7e7e7e;">// Decoding process OK</span>
}
nec_state = 3; <span style="color: #7e7e7e;">// Next state: end of 562µs pulse (start of 562µs or 1687µs space)</span>
ext_int_edge( L_TO_H ); <span style="color: #7e7e7e;">// Toggle external interrupt edge</span>
}
}
<span style="color: red;">#INT_TIMER1</span> <span style="color: #7e7e7e;">// Timer1 interrupt (used for time out)</span>
<span style="color: blue;">void</span> timer1_isr(<span style="color: blue;">void</span>){
nec_ok = 0;
nec_state = 0; <span style="color: #7e7e7e;">// Reset decoding process</span>
ext_int_edge( H_TO_L ); <span style="color: #7e7e7e;">// External interrupt edge from high to low</span>
setup_timer_1(T1_DISABLED); <span style="color: #7e7e7e;">// Disable Timer1 module</span>
clear_interrupt(INT_TIMER1); <span style="color: #7e7e7e;">// Clear Timer1 interrupt flag bit</span>
}
<span style="color: red;">#INT_TIMER3</span> <span style="color: #7e7e7e;">// Timer1 interrupt (used for time out)</span>
<span style="color: blue;">void</span> timer3_isr(<span style="color: blue;">void</span>){
nec_code = 0;
setup_timer_3(T3_DISABLED); <span style="color: #7e7e7e;">// Disable Timer3 module</span>
clear_interrupt(INT_TIMER3); <span style="color: #7e7e7e;">// Clear Timer3 interrupt flag bit</span>
}
<span style="color: blue;">void</span> main(){
delay_ms(500);
usb_init(); <span style="color: #7e7e7e;">// Initialize USB hardware</span>
enable_interrupts(GLOBAL); <span style="color: #7e7e7e;">// Enable global interrupts</span>
enable_interrupts(PERIPH);
enable_interrupts(INT_EXT_H2L); <span style="color: #7e7e7e;">// Enable external interrupt</span>
clear_interrupt(INT_TIMER1); <span style="color: #7e7e7e;">// Clear Timer1 interrupt flag bit</span>
enable_interrupts(INT_TIMER1); <span style="color: #7e7e7e;">// Enable Timer1 interrupt</span>
clear_interrupt(INT_TIMER3); <span style="color: #7e7e7e;">// Clear Timer3 interrupt flag bit</span>
enable_interrupts(INT_TIMER3); <span style="color: #7e7e7e;">// Enable Timer3 interrupt</span>
<span style="color: blue;">while</span>(TRUE){
<span style="color: blue;">if</span>(nec_ok){ <span style="color: #7e7e7e;">// If the mcu successfully receives NEC protocol message</span>
nec_ok = 0; <span style="color: #7e7e7e;">// Reset decoding process</span>
nec_state = 0;
setup_timer_1(T1_DISABLED); <span style="color: #7e7e7e;">// Disable Timer1 module</span>
set_timer3(25000);
setup_timer_3( T3_INTERNAL | T1_DIV_BY_8 ); <span style="color: #7e7e7e;">// Enable Timer3 module with internal clock source and prescaler = 8 </span>
<span style="color: blue;">if</span>(nec_code == 0x40BF30CF) <span style="color: #7e7e7e;">// Button 1 code (mouse left button)</span>
out_data[0] = 1;
<span style="color: blue;">if</span>(nec_code == 0x40BFB04F) <span style="color: #7e7e7e;">// Button 2 code (move cursor up)</span>
out_data[2] = -1;
<span style="color: blue;">if</span>(nec_code == 0x40BF708F) <span style="color: #7e7e7e;">// Button 3 code (mouse right button)</span>
out_data[0] = 3;
<span style="color: blue;">if</span>(nec_code == 0x40BF08F7) <span style="color: #7e7e7e;">// Button 4 code (move cursor left)</span>
out_data[1] = -1;
<span style="color: blue;">if</span>(nec_code == 0x40BF8877) <span style="color: #7e7e7e;">// Button 5 code (move cursor down)</span>
out_data[2] = 1;
<span style="color: blue;">if</span>(nec_code == 0x40BF48B7) <span style="color: #7e7e7e;">// Button 6 code (move cursor right)</span>
out_data[1] = 1;
<span style="color: blue;">while</span>(nec_code != 0)
usb_put_packet(1, out_data, 4, USB_DTS_TOGGLE); <span style="color: #7e7e7e;">// Send USB packet</span>
delay_ms(10);
out_data[0] = 0;
out_data[1] = 0;
out_data[2] = 0;
usb_put_packet(1, out_data, 4, USB_DTS_TOGGLE); <span style="color: #7e7e7e;">// Send USB packet</span>
}
}
}
</pre>
<span style="color: #cc0000;"><span style="font-size: large;">Remote controlled USB mouse using PIC18F4550 video:</span></span><br />
The following video is divided into 2 parts, part shows PC screen which is the main part and the small part shows my simple hardware circuit (sorry for video quality).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/YqLkuZxu91g/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/YqLkuZxu91g?feature=player_embedded" width="320"></iframe></div>
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-29059009559216509602017-09-25T16:53:00.000+02:002017-09-25T16:53:14.293+02:00Interfacing PIC24FJ64GB002 with LCD<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimoRdmDtsebso23qhVK7MBjyuITI45qIJVNtKTPCVWyO4ukzOMn1FBZ0lWRAksMC7zLYBBSOI0m3aEeXqCLkHClqyuLrJbHqE2Ns6ihxe__sHLj2LkRLlTxX0Mss6KkNt3OjwRccDtor8/s1600/PIC24FJ64GB002+with+1602+LCD+hardware+circuit.JPG" imageanchor="1"><img alt="PIC24FJ64GB002 16-bit MCU with 1602 LCD hardware circuit" border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimoRdmDtsebso23qhVK7MBjyuITI45qIJVNtKTPCVWyO4ukzOMn1FBZ0lWRAksMC7zLYBBSOI0m3aEeXqCLkHClqyuLrJbHqE2Ns6ihxe__sHLj2LkRLlTxX0Mss6KkNt3OjwRccDtor8/s400/PIC24FJ64GB002+with+1602+LCD+hardware+circuit.JPG" title="PIC24FJ64GB002 16-bit MCU with 1602 LCD hardware circuit" width="400" /></a></div>
This post shows how to interface LCD screen (16x2, 20x'4 ....) with PIC24FJ64GB002 microcontroller where the compiler used is CCS C.<br />
The PIC24FJ64GB002 is a 16-bit microcontroller runs with 3.3V while is the LCD used in this example is 5V. The PIC24FJ64GB002 has some 5.5V tolerant input pins (RB5, RB7, RB8, RB9, RB10 and RB11), with this pins we can apply 5V to the microcontroller without any problem.<br />
An other good thing with this microcontroller is the open drain outputs, each output pin can be configured to work as an open drain output.<br />
In this project I used a serial-in parallel-out shift register to minimize number of pins used by the LCD because we don't have enough 5.5V tolerant input pins to connect another 5V device. With the shift register the LCD will use only 3 pins which means we've gained at least 3 pins.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC24FJ64GB002 microcontroller</li>
<li>AMS1117 3V3 voltage regulator</li>
<li>16x2 LCD screen </li>
<li>74HC595 shift register (74HC164N and CD4094 also work)</li>
<li>100uF polarized capacitor</li>
<li>10uF polarized capacitor</li>
<li>4 x 0.1uF ceramic capacitor </li>
<li>4 x 10K ohm resistor </li>
<li>10K variable resistor</li>
<li>100 ohm resistor</li>
<li>5V power source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">Interfacing PIC24FJ64GB002 with LCD circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjh4AHzdEEptJhAZu26P-w0eHkIyKAkHrsFTrQ3pbk_s2l0S1ai5_zXmwF-GkLh1qxU0J6PpC9rrKk04s1mLrAcyCfaLlN7e-PlyuYm0JEsFBxgil599Bk8Aa1LTAqq7-PRE_skHAKgIA/s1600/pic24fj64gb002-lcd-16x2.png" imageanchor="1"><img alt="PIC24FJ64GB002 microcontroller with 16x2 LCD circuit diagram" border="0" height="260" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjh4AHzdEEptJhAZu26P-w0eHkIyKAkHrsFTrQ3pbk_s2l0S1ai5_zXmwF-GkLh1qxU0J6PpC9rrKk04s1mLrAcyCfaLlN7e-PlyuYm0JEsFBxgil599Bk8Aa1LTAqq7-PRE_skHAKgIA/s640/pic24fj64gb002-lcd-16x2.png" title="PIC24FJ64GB002 microcontroller with 16x2 LCD circuit diagram" width="640" /></a></div>
In this example the PIC24FJ64GB002 MCU runs with its internal oscillator.<br />
The AMS1117 3V3 voltage regulator is used to supply the MCU with 3.3V from the 5V source.<br />
The E (Enable) pin of the LCD screen is connected directly to pin RB7 (#16) of the microcontroller. The C (Clock) pin of the shift register is connected to pin RB8 (#17) of the microcontroller. The last shift register pin which named D (Data) is connected to pin RB9 (#18) of the microcontroller.<br />
The three pins: RB7, RB8 and RB9 are 5.5V tolerant input pins and can be configured to be an open drain outputs. With the open drain outputs and 5V pull up resistors we get what our LCD needs (logic 0 of 0V and logic 1 of 5V).<br />
<span style="color: #cc0000;"><span style="font-size: large;">Interfacing PIC24FJ64GB002 with LCD C code:</span></span><br />
The C code below was tested with CCS C compiler version 5.051.<br />
To be able to compile the code below a 3-wire LCD driver has to be added to the project folder. Download link might be found in the post below:<br />
<a href="http://ccspicc.blogspot.com/2016/08/3-wire-lcd-driver-ccs-pic-c-74hc595-hef4094.html" target="_blank">3-Wire LCD driver for CCS PIC C compiler</a><br />
I used the command <span style="background-color: yellow;">set_open_drain_b(value)</span> to configure the open-drain output pins of the PIC24FJ64GB002 MCU. For example if I want pin RB0 to be an open-drain output I just write:<br />
<span style="background-color: yellow;">set_open_drain_b(1);</span><br />
For pins RB7, RB8 and RB9 I used:<br />
<span style="background-color: yellow;">set_open_drain_b(0x380);</span><br />
where 0x380 = 896 = 0b0000001110000000<br />
Complete C code is below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">// Interfacing PIC24FJ64GB002 with LCD example CCS C code</span>
<span style="color: #7e7e7e;">// Internal oscillator used @ 8 MHz</span>
<span style="color: #7e7e7e;">// http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;">// electronnote@gmail.com</span>
<span style="color: #7e7e7e;">// 3-Wire LCD module connections</span>
<span style="color: red;">#define</span> LCD_DATA_PIN PIN_B9
<span style="color: red;">#define</span> LCD_CLOCK_PIN PIN_B8
<span style="color: red;">#define</span> LCD_EN_PIN PIN_B7
<span style="color: #7e7e7e;">// End 3-Wire LCD module connections</span>
<span style="color: red;">#include</span> <24FJ64GB002.h>
<span style="color: red;">#fuses</span> FRC NOWDT NOJTAG OSCIO SOSC_IO
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 8M)
<span style="color: red;">#include</span> <3WireLCD.c> <span style="color: #7e7e7e;">// 3-wire LCD source file</span>
<span style="color: blue;">unsigned</span> <span style="color: blue;">int8</span> i;
<span style="color: blue;">void</span> main(){
output_b(0);
set_open_drain_b(0x380); <span style="color: #7e7e7e;">// Configure RB7, RB8 and RB9 pins as an open-drain outputs</span>
delay_ms(500); <span style="color: #7e7e7e;">// Wait 1/2 second</span>
lcd_initialize(); <span style="color: #7e7e7e;">// Initialize LCD module</span>
lcd_cmd(LCD_CLEAR); <span style="color: #7e7e7e;">// LCD Clear</span>
lcd_goto(3, 1); <span style="color: #7e7e7e;">// Go to column 3 line 1</span>
lcd_out(<span style="color: #de00d0;">"Hello world!"</span>);
delay_ms(1000); <span style="color: #7e7e7e;">// Wait 1 second</span>
<span style="color: blue;">while</span>(TRUE){
<span style="color: blue;">for</span>(i = 0; i < 200; ++i){
lcd_goto(7, 2); <span style="color: #7e7e7e;">// Go to column 7 row 4</span>
printf(lcd_out, <span style="color: #de00d0;">"%3u"</span>, i); <span style="color: #7e7e7e;">// Write i with 3 numbers max</span>
delay_ms(500);
}
}
}
</pre>
PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-4226584499469609582017-09-25T11:35:00.000+02:002017-09-25T17:28:07.059+02:00PIC24FJ64GB002 LED Blink example with CCS C compilerThis small post shows how to simply blink an LED using PIC24FJ64GB002 16-bit microcontroller and CCS C compiler.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC24FJ64GB002 microcontroller</li>
<li>AMS1117 3V3 voltage regulator</li>
<li>2 x 10uF polarized capacitor</li>
<li>4 x 0.1uF ceramic capacitor</li>
<li>10K ohm resistor</li>
<li>100 ohm resistor</li>
<li>330 ohm resistor</li>
<li>LED</li>
<li>5V source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">PIC24FJ64GB002 LED Blink example circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMF4M2wtIuq9woKqiTZ1DL3KDjQN8oY5oIkCGUX6XOh30OEzhDM2jMaTnSh4poRkO1ntPhxwueojAgoa6fEmQwmwOo7Dnr769CQKd2cH-_9hBTKtSPeWmN5eeZj9F5BWjJ7RhIiZNyOA8/s1600/pic24fj64gb002-led-blink-ccs-c.png" imageanchor="1"><img alt="PIC24FJ64GB002 LED blink example circuit" border="0" height="472" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMF4M2wtIuq9woKqiTZ1DL3KDjQN8oY5oIkCGUX6XOh30OEzhDM2jMaTnSh4poRkO1ntPhxwueojAgoa6fEmQwmwOo7Dnr769CQKd2cH-_9hBTKtSPeWmN5eeZj9F5BWjJ7RhIiZNyOA8/s640/pic24fj64gb002-led-blink-ccs-c.png" title="PIC24FJ64GB002 LED blink example circuit" width="640" /></a></div>
The PIC24FJ64GB002 microcontroller works with 3.3V only and supply it we need a 3.3V source or a 5V source and AMS1117 3V3 voltage regulator.<br />
The LED is connected to pin RB0 through 330 ohm resistor. <br />
In this example the PIC24FJ64GB002 microcontroller runs with its internal oscillator.<br />
<span style="color: #cc0000;"><span style="font-size: large;">PIC24FJ64GB002 LED Blink example C code:</span></span><br />
The C code below was tested with CCS C compiler version 5.051.<br />
In this example the LED blinks with a frequency of 1Hz (500ms ON and 500ms OFF ==> period = 1s).<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 340px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">// PIC24FJ64GB002 LED blink example CCS C code</span>
<span style="color: #7e7e7e;">// Internal oscillator used @ 8 MHz</span>
<span style="color: #7e7e7e;">// http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;">// electronnote@gmail.com</span>
<span style="color: red;">#include</span> <24FJ64GB002.h>
<span style="color: red;">#fuses</span> FRC NOWDT NOJTAG OSCIO SOSC_IO
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 8M)
<span style="color: red;">#define</span> LED PIN_B0 <span style="color: #7e7e7e;">// Led is connected to pin RB0</span>
<span style="color: blue;">void</span> main(){
<span style="color: blue;">while</span>(TRUE){
output_toggle(LED); <span style="color: #7e7e7e;">// Toggle led pin status</span>
delay_ms(500); <span style="color: #7e7e7e;">// Wait 500 ms</span>
}
}
</pre>
PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-26426014129469615882017-09-24T13:13:00.001+02:002017-09-24T13:13:19.095+02:00Distance meter using PIC16F887 and HC-SR04 ultrasonic sensorThis topic shows how to make a simple distance meter using PIC16F887 microcontroller and HC-SR04 ultrasonic sensor.<br />
The HC-SR04 ultrasonic sensor can measure distances form 2cm to 400cm with an accuracy of 3mm. This sensor module
includes ultrasonic transmitter, ultrasonic receiver and control
circuit.<br />
The HC-SR04 ultrasonic sensor has 4 pins as shown below where:<br />
VCC : Positive power supply (+5V)<br />
Trig : Trigger input pin<br />
Echo : Echo output pin<br />
GND : Ground (0V)<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGxRGa3iAYakpBUJWNsCCur_aPCneMUXfxRA9mg7IhM0Vywp4CncbYFTFdrGS-0-1BPbaHkpHAs_AiEmHJchlMAShMJC5RldW2pUOFsaWF0QfXhcoBF8KK_zGAsNk-t2_BFa9CMPVxtJc/s1600/hc-sr04-ultrasonic-sensor.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="HC-SR04 Ultrasonic sensor pin out" border="0" data-original-height="453" data-original-width="790" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGxRGa3iAYakpBUJWNsCCur_aPCneMUXfxRA9mg7IhM0Vywp4CncbYFTFdrGS-0-1BPbaHkpHAs_AiEmHJchlMAShMJC5RldW2pUOFsaWF0QfXhcoBF8KK_zGAsNk-t2_BFa9CMPVxtJc/s320/hc-sr04-ultrasonic-sensor.jpg" title="HC-SR04 Ultrasonic sensor pin out" width="320" /></a></div>
<b>HC-SR04 ultrasonic sensor timing diagram:</b><br />
The timing diagram of the HC-SR04 ultrasonic sensor is shown below.<br />
First
we have to supply the sensor trigger pin with a pulse of 10µs and the
sensor will automatically send 8 cycles burst of ultrasound at 40 kHz
and raise its echo pin. The Echo is a distance object that is pulse
width and the range in proportion. We can calculate the range through
the time interval between sending trigger signal and receiving echo
signal. Formula: uS / 58 = centimeters or uS / 148 =inch; or:<br />
the range = high level time * sound velocity (340M/S) / 2.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGI1UoauRiPmpjxCectRJmY0HuJgWRgaIxu5QN16-nEw_MkJzcLCygIxyryNMVHbK_8eTBYRdFSV4E4GJxZzNu0QU2sxCOlNgKhb-vR5vI5DFYeeWXFnQ05AChc2F64JUsAnNkxrs9nxY/s1600/hc-sr04-ultrasonic-sensor-timing-diagram.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="HC-SR04 Ultrasonic sensor timing" border="0" data-original-height="337" data-original-width="731" height="294" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGI1UoauRiPmpjxCectRJmY0HuJgWRgaIxu5QN16-nEw_MkJzcLCygIxyryNMVHbK_8eTBYRdFSV4E4GJxZzNu0QU2sxCOlNgKhb-vR5vI5DFYeeWXFnQ05AChc2F64JUsAnNkxrs9nxY/s640/hc-sr04-ultrasonic-sensor-timing-diagram.png" title="HC-SR04 Ultrasonic sensor timing" width="640" /></a></div>
<div style="text-align: center;">
</div>
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC16F887 microcontroller</li>
<li>HC-SR04 ultrasonic sensor</li>
<li>16x2 LCD screen</li>
<li>10K variable resistor</li>
<li>+5V source </li>
<li>Breadboard</li>
<li>Jumper Wires</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">Distance meter using PIC16F887 and HC-SR04 ultrasonic sensor circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrHZP6ZpyRIdHWDo8MEca2zgx-99Vjs9WoupwdoU8VmCMj_SFX06JIIBL8VtWhU35jdFXeUkHaZOEo20QI1A5dMB3CtMB9YG9noVkLkzrjFeZLS6Eut1tDyBrXYyNosutbqYhKAm57e3Y/s1600/pic16f887+hc-sr04+ultrasonic+sensor+distance+meter.png" imageanchor="1"><img alt="Interfacing PIC16F887 with HC-SR04 ultrasonic sensor circuit diagram" border="0" height="488" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrHZP6ZpyRIdHWDo8MEca2zgx-99Vjs9WoupwdoU8VmCMj_SFX06JIIBL8VtWhU35jdFXeUkHaZOEo20QI1A5dMB3CtMB9YG9noVkLkzrjFeZLS6Eut1tDyBrXYyNosutbqYhKAm57e3Y/s640/pic16f887+hc-sr04+ultrasonic+sensor+distance+meter.png" title="Interfacing PIC16F887 with HC-SR04 ultrasonic sensor circuit diagram" width="640" /></a></div>
In this project the PIC16F887 MCU runs with its internal oscillator and MCLR pin function is disabled.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Distance meter using PIC16F887 and HC-SR04 ultrasonic sensor C code:</span></span><br />
The C code below was tested with CCS C compiler version 5.051.<br />
The PIC16F887 runs with its internal oscillator @ 8MHz. <br />
Basically I used Timer1 module to measure the pulse widths which comes from the Echo pin of the HC-SR04 sensor, the width of the pulse is related to the distance. Timer1 is configured to increment every 1us (prescaler = 2):<br />
<span style="background-color: yellow;">SETUP_TIMER_1(T1_INTERNAL | T1_DIV_BY_2);</span><br />
First of all the MCU sends a pulse of 10 us to the sensor via pin RB1 which is the trigger pin of the sensor, then the MCU waits until the sensor raises its Echo pin (function <span style="background-color: yellow;">wait_sensor()</span> ). If the waiting time is higher than 990 us ==> time out and the function <span style="background-color: yellow;">wait_sensor()</span> returns 0.<br />
if the function <span style="background-color: yellow;">wait_sensor()</span> returned 1, the microcontroller starts measuring the width of the Echo pin pulse (in us) using the function <span style="background-color: yellow;">get_distance()</span>, if the time > 24990 (distance > 400 cm) ==> out of range, otherwise the measured time will be converted to distance (in cm) by dividing it by 58.<br />
No interrupt is used in this example.<br />
The complete C code is below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">/*</span>
<span style="color: #7e7e7e;"> Distance meter using HC-SR04 ultrasonic sensor and PIC16F887 CCS C code.</span>
<span style="color: #7e7e7e;"> Echo and trigger pins of the HC-SR04 are connected to RB0 and RB1 respectively.</span>
<span style="color: #7e7e7e;"> http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;"> electronnote@gmail.com</span>
<span style="color: #7e7e7e;">*/</span>
<span style="color: #7e7e7e;">//LCD module connections</span>
<span style="color: red;">#define</span> LCD_RS_PIN PIN_D0
<span style="color: red;">#define</span> LCD_RW_PIN PIN_D1
<span style="color: red;">#define</span> LCD_ENABLE_PIN PIN_D2
<span style="color: red;">#define</span> LCD_DATA4 PIN_D3
<span style="color: red;">#define</span> LCD_DATA5 PIN_D4
<span style="color: red;">#define</span> LCD_DATA6 PIN_D5
<span style="color: red;">#define</span> LCD_DATA7 PIN_D6
<span style="color: #7e7e7e;">//End LCD module connections</span>
<span style="color: red;">#include</span> <16F887.h>
<span style="color: red;">#fuses</span> INTRC_IO, NOMCLR, NOBROWNOUT, NOLVP
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 8MHz)
<span style="color: red;">#use</span> fast_io(B)
<span style="color: red;">#include</span> <lcd.c>
<span style="color: blue;">int16</span> i, distance;
<span style="color: blue;">int1</span> wait_sensor(){
i = 0;
set_timer1(0); <span style="color: #7e7e7e;">// Reset Timer1</span>
<span style="color: blue;">while</span>(!input(PIN_B0) && (i < 1000))
i = get_timer1(); <span style="color: #7e7e7e;">// Read Timer1 and store its value in i</span>
<span style="color: blue;">if</span>(i > 990)
<span style="color: blue;">return</span> 0;
<span style="color: blue;">else</span>
<span style="color: blue;">return</span> 1;
}
<span style="color: blue;">int16</span> get_distance(){
i = 0;
set_timer1(0);
<span style="color: blue;">while</span>(input(PIN_B0) && (i < 25000))
i = get_timer1();
<span style="color: blue;">return</span> i;
}
<span style="color: blue;">void</span> main(){
setup_oscillator(OSC_8MHZ); <span style="color: #7e7e7e;">// Set internal oscillator to 8MHz</span>
output_b(0);
set_tris_b(1); <span style="color: #7e7e7e;">// Configure RB0 pin as input</span>
delay_ms(1000);
lcd_init(); <span style="color: #7e7e7e;">// Initialize LCD module</span>
lcd_putc(<span style="color: #de00d0;">'\f'</span>); <span style="color: #7e7e7e;">// Clear LCD</span>
lcd_gotoxy(4, 1); <span style="color: #7e7e7e;">// Go to column 4 row 1</span>
lcd_putc(<span style="color: #de00d0;">"Distance:"</span>);
SETUP_TIMER_1(T1_INTERNAL | T1_DIV_BY_2); <span style="color: #7e7e7e;">// Configure Timer 1 to increment by 1 every 1 us</span>
<span style="color: blue;">while</span>(TRUE){
<span style="color: #7e7e7e;">// Send 10us pulse to HC-SR04 Trigger pin</span>
output_high(PIN_B1);
delay_us(10);
output_low(PIN_B1);
<span style="color: #7e7e7e;">// Read pulse comes from HC-SR04 Echo pin</span>
<span style="color: blue;">if</span>(wait_sensor()){
distance = get_distance();
<span style="color: blue;">if</span>(distance > 24990){
lcd_gotoxy(3, 2); <span style="color: #7e7e7e;">// Go to column 3 row 2</span>
lcd_putc(<span style="color: #de00d0;">"Out Of Range"</span>);
}
<span style="color: blue;">else</span> {
distance = i/58; <span style="color: #7e7e7e;">// Calculate the distance</span>
lcd_gotoxy(3, 2); <span style="color: #7e7e7e;">// Go to column 3 row 2</span>
lcd_putc(<span style="color: #de00d0;">" cm "</span>);
lcd_gotoxy(6, 2); <span style="color: #7e7e7e;">// Go to column 6 row 2</span>
printf(lcd_putc, <span style="color: #de00d0;">"%3Lu"</span>, distance);
}
}
<span style="color: blue;">else</span> {
lcd_gotoxy(3, 2); <span style="color: #7e7e7e;">// Go to column 3 row 2</span>
lcd_putc(<span style="color: #de00d0;">" Time Out "</span>);
}
delay_ms(100);
}
}
<span style="color: #7e7e7e;">// End of code</span>
</pre>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRMqbkk8aRtoMhtaAZBP9zS5xRZtnQ4sK-FEnRCTahZ84S7Fo4yMN4z8HqCfBWY-o19_Go5ayXNu9QBGjUTQto4LV5HOT8PDN4n6okvLEEes6NyKASgulAwtrW54OWJR9eEXUSROaCMnE/s1600/PIC16F887+and+HC-SR04+ultrasonic+sensor+hardware+circuit.JPG" imageanchor="1"><img alt="PIC16F887 MCU and HC-SR04 ultrasonic sensor hardware circuit" border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRMqbkk8aRtoMhtaAZBP9zS5xRZtnQ4sK-FEnRCTahZ84S7Fo4yMN4z8HqCfBWY-o19_Go5ayXNu9QBGjUTQto4LV5HOT8PDN4n6okvLEEes6NyKASgulAwtrW54OWJR9eEXUSROaCMnE/s400/PIC16F887+and+HC-SR04+ultrasonic+sensor+hardware+circuit.JPG" title="PIC16F887 MCU and HC-SR04 ultrasonic sensor hardware circuit" width="400" /></a></div>
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-38649308997619480372017-09-22T20:36:00.000+02:002017-09-22T20:36:11.634+02:00Other Projects<a href="http://ccspicc.blogspot.com/2017/09/FAT16-FAT32-library-PIC-microcontroller.html" target="_blank"><span style="font-size: large;">SD card FAT library for CCS C compiler</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/08/fat16-library-for-pic-microcontroller.html" target="_blank"><span style="font-size: large;">FAT16 Library for CCS C compiler</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/08/mmc-sd-card-driver-for-ccs-compiler.html" target="_blank"><span style="font-size: large;">MMC/SD Card driver for CCS PIC C compiler</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2016/10/st7735-spi-tft-display-driver-library.html" target="_blank"><span style="font-size: large;">ST7735 SPI TFT Display Driver for CCS PIC C compiler</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2016/08/3-wire-lcd-driver-ccs-pic-c-74hc595-hef4094.html" target="_blank"><span style="font-size: large;">3-Wire LCD driver for CCS PIC C compiler</span></a>
PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-47210222376881063962017-09-20T21:59:00.000+02:002018-06-03T19:16:57.601+02:00PIC16F887 projects<div style="text-align: center;">
<span style="font-size: 50px;">PIC16F887 microcontroller projects</span></div>
<br />
<a href="http://ccspicc.blogspot.com/2017/09/distance-meter-PIC16F887-HC-SR04.html" target="_blank"><span style="font-size: large;">Distance meter using PIC16F887 and HC-SR04 ultrasonic sensor</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/09/wave-audio-player-pic16f887.html" target="_blank"><span style="font-size: x-large;">Wave audio player using PIC16F887 microcontroller</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/09/ds3231-rtcc-alarm-temperature-pic16f887.html" target="_blank"><span style="font-size: x-large;">Real time clock and temperature monitor using PIC16F887 and DS3231</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/09/read-text-files-from-fat16-sd-card-pic16f887.html" target="_blank"><span style="font-size: x-large;">Read text files from FAT16 SD card with PIC16F887</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/09/mmcsd-card-raw-data-read-pic16f887.html" target="_blank"><span style="font-size: x-large;">MMC/SD Card raw data read with PIC16F887 microcontroller</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/08/rs232-uart-example-pic16f887.html" target="_blank"><span style="font-size: x-large;">UART Example for PIC16F887 microcontroller using CCS PIC C compiler</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/08/esc-brushless-motor-control-pic16f887.html" target="_blank"><span style="font-size: x-large;">Sensorless brushless DC motor drive with an ESC and PIC16F887</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/08/rf-transmitter-receiver-pic16f887-microcontroller.html" target="_blank"><span style="font-size: x-large;">RF Transmitter and receiver system using PIC16F887</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/08/pic16f887-lm35-temperature-sensor.html" target="_blank"><span style="font-size: x-large;">Interfacing PIC16F887 with LM35 temperature sensor</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/08/rtos-pic16f887-example.html" target="_blank"><span style="font-size: x-large;">RTOS Example with PIC16F887 microcontroller</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/07/brushless-dc-motor-drive-pic16f887.html" target="_blank"><span style="font-size: x-large;">CD-ROM Sensored brushless DC motor drive with PIC16F887 microcontroller</span></a><br />
<br />
<script async="" src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<ins class="adsbygoogle" data-ad-client="ca-pub-9821904216837075" data-ad-format="fluid" data-ad-layout="in-article" data-ad-slot="9358819745" style="display: block; text-align: center;"></ins><script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
<a href="http://ccspicc.blogspot.com/2017/07/st7735-tft-display-pic16f887.html" target="_blank"><span style="font-size: x-large;">ST7735 TFT Display with PIC16F887 example</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/07/dc-motor-remote-control-circuit-pic16f887.html" target="_blank"><span style="font-size: x-large;">Two DC motors control with NEC IR remote control</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/07/pic16f887-ds3231-real-time-clock-set-button.html" target="_blank"><span style="font-size: x-large;">Interfacing DS3231 with PIC16F887 microcontroller</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/07/dc-motor-remote-control-circuit-pic16f887.html" target="_blank"><span style="font-size: x-large;">Two motors control using PIC16F887 and L293D</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/07/nec-protocol-decoder-pic-microcontroller.html" target="_blank"><span style="font-size: x-large;">NEC Protocol decoder with PIC16F887 microcontroller</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/07/rc5-remote-control-decoder-pic16f887.html" target="_blank"><span style="font-size: x-large;">RC5 Decoder with PIC16F887 microcontroller and CCS C compiler</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/07/DS1307-PIC16F887-RTC.html" target="_blank"><span style="font-size: x-large;">DS1307 Interfacing with PIC16F887</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/07/LM335-PIC16F887-temperature-sensor-circuit.html" target="_blank"><span style="font-size: x-large;">Interfacing PIC16F887 with LM335 temperature sensor</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/07/pic16f887-dht22-simulation.html" target="_blank"><span style="font-size: x-large;">PIC16F887 Microcontroller with DHT22 digital sensor</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/07/pic16f887-dht11-sensor-with-simulation.html" target="_blank"><span style="font-size: x-large;">Interfacing PIC16F887 with DHT11 sensor</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/07/pic16f887-lcd-display-example.html" target="_blank"><span style="font-size: x-large;">Interfacing PIC16F887 with LCD display</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/06/pic16f887-timer0-timer1-external-interrupts.html" target="_blank"><span style="font-size: x-large;">PIC16F887 Timers and Interrupts</span></a><br />
<br />
<a href="http://ccspicc.blogspot.com/2017/06/led-blink-pic16f887.html" target="_blank"><span style="font-size: x-large;">LED Blink with PIC16F887 microcontroller</span></a><br />
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-48502727931033270212017-09-18T21:07:00.000+02:002017-09-20T23:15:30.250+02:00Wave audio player using PIC16F887 microcontrollerThis small project shows how to make a simple wave audio player using PIC16F887 microcontroller and SD card. The WAV audio file used in this project is 8000 Hz, 8-bit stereo (2 channels).<br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC16F887 microcontroller</li>
<li>SD card (formatted with FAT16 or FAT32 file system)</li>
<li>ASM1117 3.3 voltage regulator</li>
<li>Audio amplifier (ex: PC speaker, LM386 ......)</li>
<li>Speaker</li>
<li>20 MHz crystal oscillator</li>
<li>2 x 22pF ceramic capacitors</li>
<li>3 x 3.3K ohm resistor</li>
<li>3 x 2.2K ohm resistor</li>
<li>10K ohm resistor</li>
<li>2 x 1K ohm resistor </li>
<li>3 x 10uF polarized capacitor</li>
<li>100nF ceramic capacitor</li>
<li>5V Power source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">The Circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUe1t7_0W90_1an1TrBvkf7wvcrMvpz0TkEncUR89Zmi6PRVUUN6yEWqXpMADxK71Jzg1e2GsvJ0A0flWLC8_DLfh0Bu95YoVbdommQzWg5zKG3ldEsPBQswx4Y2yp5HlxetKTrBAg-YM/s1600/pic16f887-sd-card-wave-player-circuit.png" imageanchor="1"><img border="0" height="350" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUe1t7_0W90_1an1TrBvkf7wvcrMvpz0TkEncUR89Zmi6PRVUUN6yEWqXpMADxK71Jzg1e2GsvJ0A0flWLC8_DLfh0Bu95YoVbdommQzWg5zKG3ldEsPBQswx4Y2yp5HlxetKTrBAg-YM/s640/pic16f887-sd-card-wave-player-circuit.png" width="640" /></a></div>
The microcontroller generates audio using PWM technique, if the wave
audio file is mono (1 channel) the microcontroller will generate only 1
PWM signal (PWM1) and hence we will hear the sound from 1 speaker only.
If the wave audio file is stereo both speakers will give sound.<br />
In this project the PIC16F887 runs with 20MHz crystal oscillator which is the maximum speed of this microcontroller, MCLR pin function is disabled. <br />
<span style="color: #cc0000;"><span style="font-size: large;">The C code:</span></span><br />
The C code below was tested with CCS C compiler versions 5.051.<br />
In this project I used the FAT library (FAT16 and FAT32), its source file can be found in the the following topic:<br />
<a href="https://ccspicc.blogspot.com/2017/09/FAT16-FAT32-library-PIC-microcontroller.html" target="_blank">SD card FAT library for CCS C compiler</a><br />
I tested this project with FAT32 8 GB and FAT16 2 GB micro-SD cards.<br />
The name of the wave audio file which I used was <span style="background-color: yellow;">mywav</span> (mywav.wav with the extension), its sample rate is 8000 Hz with 2 channels (stereo).<br />
First of all I initialized the SD card using the function: <span style="background-color: yellow;">sdcard_init();</span>
this function return 0 if the initialization was OK and non-zero if
there was an error. After the initialization of the SD card I
initialized the FAT file system using the function <span style="background-color: yellow;">fat_init();</span> and then I opened the wave audio file with the pre-selected name <span style="background-color: yellow;">mywav.wav</span>, all the three previous function returns 0 if OK and no-zero if error.<br />
If the initialization of the SD card, the FAT system and opening of the file were OK that means the variable which named <span style="background-color: yellow;">ok = 0</span> and playing the wave file starts using the function <span style="background-color: yellow;">play();</span> .<br />
To detect if the wave file is mono (1 channel) or stereo (2 channels), I read the byte 22 of the wave file using the function :<br />
<span style="background-color: yellow;">sdcard_read_byte(address_pointer + 22, &channel_count);</span><br />
where the variable <span style="background-color: yellow;">address_pointer</span> belongs to the FAT library, this variable allows me to know the
starting address of the wave audio file.<br />
If the wave file is mono ==>
<span style="background-color: yellow;">channel_count =1</span> and if it is stereo ==> <span style="background-color: yellow;">channel_count = 2<span style="background-color: white;">.</span></span><br />
I
set the data buffer to 16 so each time the microcontroller reads 32
bytes from the SD card. The data buffer can be less or higher than 16.<br />
The function <span style="background-color: yellow;">fat_read_data(16, data)</span> keeps reading file data from the SD card until it returns 1 which means end of the wave file is reached.<br />
The
wave file must be 8-bit and for that I configured the PWM outputs to
give the maximum frequency with 8-bit resolution, for that I configured
Timer2 module as shown below:<br />
<span style="background-color: yellow;">setup_timer_2(T2_DIV_BY_1, 63, 1);</span><br />
The resolution of the PWM signal can be calculated using the function:<br />
PWM Resolution = Log[(PR2 + 1)*4]/Log(2) = Log[(63 + 1)*4]/Log(2) = 8<br />
The
PWM frequency should be as higher as possible and with the previous
configuration I got a PWM frequency of 78.125 KHz. It can be calculated
with the function below:<br />
PWM_Frequency = Fosc/[(PR2 + 1)*4*TMR2_Prescaler] = 20*10^6/[(63 + 1)*4*1] = 78.125 KHz.<br />
If <span style="background-color: yellow;">channel_count = 2<span style="background-color: white;">
the 2nd PWM duty cycle also will be updated and the sound will be
generated from PWM1 (RC2) and PWM2 (RC1) outputs (left and right).</span></span><br />
Now how did I used Timer1 module and the wave file sample rate (8000 Hz):<br />
the
PWM duty cycles have to be updated every 125 us ( = 1/8000Hz), for
that I used Timer1 to make the MCU waits for 125 us. In this example I
didn't use Timer1 interrupt.<br />
I configured Timer1 module to
increment on every MCU cycle (0.2 us) and to compute Timer1 value
(values between 2 updates) I used the function:<br />
Fosc/[sample rate * 4) = 20 * 10^6/(8000 * 4) = 625<br />
where sample rate = 18000 and Fosc = 20 * 10^6 . <br />
In
this example I used the value 500 instead of 625 because I got a slow
audio streaming (i.e: some instructions are spent on loops). <br />
The complete C code is the one below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">/*</span>
<span style="color: #7e7e7e;"> WAV Audio Player using PIC16F887 microcontroller and SD card CCS C code.</span>
<span style="color: #7e7e7e;"> FAT Library for CCS C compiler must be installed</span>
<span style="color: #7e7e7e;"> http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;"> electronnote@gmail.com</span>
<span style="color: #7e7e7e;">*/</span>
<span style="color: #7e7e7e;">// SD Card module connections</span>
<span style="color: red;">#define</span> SDCARD_SPI_HW
<span style="color: red;">#define</span> SDCARD_PIN_SELECT PIN_D3
<span style="color: #7e7e7e;">// End SD card module connections</span>
<span style="color: red;">#include</span> <16F887.h>
<span style="color: red;">#fuses</span> NOMCLR, HS, NOBROWNOUT, NOLVP
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 20MHz)
<span style="color: red;">#use</span> fast_io(D)
<span style="color: red;">#include</span> <FAT_Lib.c>
<span style="color: blue;">const</span> <span style="color: blue;">int8</span> *wav = <span style="color: #de00d0;">"mywav.wav"</span>;
<span style="color: blue;">int1</span> ok = 0;
<span style="color: blue;">int8</span> i, j, data[16], channel_count;
<span style="color: blue;">void</span> play(){
sdcard_read_byte(address_pointer + 22, &channel_count); <span style="color: #7e7e7e;">// Read number of channels</span>
<span style="color: blue;">while</span>(fat_read_data(16, data) == 0){
<span style="color: blue;">for</span>(i = 0; i < 16; i++){
set_timer1(0);
j = data[i];
set_pwm1_duty((<span style="color: blue;">int16</span>)j); <span style="color: #7e7e7e;">// Update PWM1 duty cycle</span>
<span style="color: blue;">if</span>(channel_count == 2){ <span style="color: #7e7e7e;">// If 2-channel wave file (stereo)</span>
i++; <span style="color: #7e7e7e;">// increment i</span>
j = data[i];
set_pwm2_duty((<span style="color: blue;">int16</span>)j); <span style="color: #7e7e7e;">// Update PWM2 duty cycle</span>
}
<span style="color: blue;">while</span>(get_timer1() < 500); <span style="color: #7e7e7e;">// Wait some time (about 125us) to update the duty cycles</span>
}
}
}
<span style="color: blue;">void</span> main(){
delay_ms(2000);
setup_ccp1(CCP_PWM); <span style="color: #7e7e7e;">// Configure CCP1 as a PWM</span>
setup_ccp2(CCP_PWM); <span style="color: #7e7e7e;">// Configure CCP2 as a PWM</span>
set_pwm1_duty(0); <span style="color: #7e7e7e;">// set PWM1 duty cycle to 0</span>
set_pwm2_duty(0); <span style="color: #7e7e7e;">// set PWM2 duty cycle to 0</span>
setup_timer_2(T2_DIV_BY_1, 63, 1); <span style="color: #7e7e7e;">// Set PWM frequency to maximum with 8-bit resolution</span>
setup_timer_1( T1_INTERNAL | T1_DIV_BY_1 ); <span style="color: #7e7e7e;">// Timer1 configuration</span>
ok |= sdcard_init(); <span style="color: #7e7e7e;">// Initialize the SD card module</span>
ok |= fat_init(); <span style="color: #7e7e7e;">// Initialize FAT library</span>
ok |= fat_open_file(wav); <span style="color: #7e7e7e;">// Open the wave file</span>
<span style="color: blue;">if</span>(ok == 0){
play();
}
set_pwm1_duty(0); <span style="color: #7e7e7e;">// set PWM1 duty cycle to 0</span>
set_pwm2_duty(0); <span style="color: #7e7e7e;">// set PWM2 duty cycle to 0</span>
} <span style="color: #7e7e7e;">// End</span>
</pre>
The video below shows the result of the example except that the MCU used is PIC16F877A:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/j-Z448ZoO3w/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/j-Z448ZoO3w?feature=player_embedded" width="320"></iframe></div>
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-43216508750065577052017-09-17T22:02:00.001+02:002018-06-02T19:34:24.997+02:00WAV Player using PIC16F877A and SD cardThis post shows how did I made a simple wave audio player using PIC16F877A microcontroller where the wave audio file is stored in 8 GB micro SD card.<br />
The wave file which I used was 8000 Hz, 8-bit stereo (2 channels), I convert it from MP3 format to WAV format using a free and open source software named audacity (site: <a href="http://www.audacityteam.org/" target="_blank">http://www.audacityteam.org/</a>).<br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC16F877A microcontroller</li>
<li>SD card (formatted with FAT16 or FAT32)</li>
<li>ASM1117 3.3 voltage regulator</li>
<li>Audio amplifier (ex: PC speaker, LM386 ......)</li>
<li>Speaker</li>
<li>20 MHz crystal oscillator</li>
<li>2 x 22pF ceramic capacitors</li>
<li>3 x 3.3K ohm resistor</li>
<li>3 x 2.2K ohm resistor</li>
<li>2 x 10K ohm resistor</li>
<li>2 x 1K ohm resistor </li>
<li>3 x 10uF polarized capacitor</li>
<li>100nF ceramic capacitor</li>
<li>5V Power source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<ins class="adsbygoogle"
style="display:block; text-align:center;"
data-ad-layout="in-article"
data-ad-format="fluid"
data-ad-client="ca-pub-9821904216837075"
data-ad-slot="9358819745"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
<br/>
<span style="color: #cc0000;"><span style="font-size: large;">The Circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_0BJgxUawvJTWKBlDSk2JBqskc42MrzOCmbDht9pZ085kBrENSI8msBBy3iOXKctjGP23P15vLh7guATXeNEvKrMzvYdeEztMHe27lVVJof2preAmKunUlCh8Ju6w1drwdZi-qjvFFsE/s1600/wav-player-pic16f877a-sd-card.png" imageanchor="1"><img alt="WAV player using PIC16F877A and SD card circuit" border="0" height="366" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_0BJgxUawvJTWKBlDSk2JBqskc42MrzOCmbDht9pZ085kBrENSI8msBBy3iOXKctjGP23P15vLh7guATXeNEvKrMzvYdeEztMHe27lVVJof2preAmKunUlCh8Ju6w1drwdZi-qjvFFsE/s640/wav-player-pic16f877a-sd-card.png" title="WAV player using PIC16F877A and SD card circuit" width="640" /></a></div>
The microcontroller generates audio using PWM technique, if the wave audio file is mono (1 channel) the microcontroller will generate only 1 PWM signal (PWM1) and hence we will hear the sound from 1 speaker only. If the wave audio file is stereo both speakers will give sound.<br />
<span style="color: #cc0000;"><span style="font-size: large;">The C code:</span></span><br />
The C code below was tested with CCS C compiler versions 5.051.<br />
In this project I used the FAT library (FAT16 and FAT32), its source file can be found in the the following topic:<br />
<a href="https://ccspicc.blogspot.com/2017/09/FAT16-FAT32-library-PIC-microcontroller.html" target="_blank">SD card FAT library for CCS C compiler</a><br />
I tested this project with FAT32 8 GB and FAT16 2 GB micro-SD cards.<br />
The name of the wave audio file which I used was <span style="background-color: yellow;">mywav</span> (mywav.wav with the extension), its sample rate is 8000 Hz with 2 channels (stereo).<br />
First of all I initialized the SD card using the function: <span style="background-color: yellow;">sdcard_init();</span>
this function return 0 if the initialization was OK and non-zero if
there was an error. After the initialization of the SD card I
initialized the FAT file system using the function <span style="background-color: yellow;">fat_init();</span> and then I opened the wave audio file with the pre-selected name <span style="background-color: yellow;">mywav.wav</span>, all the three previous function returns 0 if OK and no-zero if error.<br />
If the initialization of the SD card, the FAT system and opening of the file were OK that means the variable which named <span style="background-color: yellow;">ok = 0</span> and playing the wave file starts using the function <span style="background-color: yellow;">play();</span> .<br />
To detect if the wave file is mono (1 channel) or stereo (2 channels), I read the byte 22 of the wave file using the function :<br />
<span style="background-color: yellow;">sdcard_read_byte(address_pointer + 22, &channel_count);</span><br />
where the variable <span style="background-color: yellow;">address_pointer</span> belongs to the FAT library, this variable allows me to know the
starting address of the wave audio file.<br />
If the wave file is mono ==>
<span style="background-color: yellow;">channel_count =1</span> and if it is stereo ==> <span style="background-color: yellow;">channel_count = 2<span style="background-color: white;">.</span></span><br />
I
set the data buffer to 16 so each time the microcontroller reads 32
bytes from the SD card. The data buffer can be less or higher than 16.<br />
The function <span style="background-color: yellow;">fat_read_data(16, data)</span> keeps reading file data from the SD card until it returns 1 which means end of the wave file is reached.<br />
<br/>
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- ccslink1 -->
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-9821904216837075"
data-ad-slot="2075108943"
data-ad-format="link"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script><br/>
The
wave file must be 8-bit and for that I configured the PWM outputs to
give the maximum frequency with 8-bit resolution, for that I configured
Timer2 module as shown below:<br />
<span style="background-color: yellow;">setup_timer_2(T2_DIV_BY_1, 63, 1);</span><br />
The resolution of the PWM signal can be calculated using the function:<br />
PWM Resolution = Log[(PR2 + 1)*4]/Log(2) = Log[(63 + 1)*4]/Log(2) = 8<br />
The
PWM frequency should be as higher as possible and with the previous
configuration I got a PWM frequency of 78.125 KHz. It can be calculated
with the function below:<br />
PWM_Frequency = Fosc/[(PR2 + 1)*4*TMR2_Prescaler] = 20*10^6/[(63 + 1)*4*1] = 78.125 KHz.<br />
If <span style="background-color: yellow;">channel_count = 2<span style="background-color: white;">
the 2nd PWM duty cycle also will be updated and the sound will be
generated from PWM1 (RC2) and PWM2 (RC1) outputs (left and right).</span></span><br />
Now how did I used Timer1 module and the wave file sample rate (8000 Hz):<br />
the
PWM duty cycles have to be updated every 125 us ( = 1/8000Hz), for
that I used Timer1 to make the MCU waits for 125 us. In this example I
didn't use Timer1 interrupt.<br />
I configured Timer1 module to
increment on every MCU cycle (0.2 us) and to compute Timer1 value
(values between 2 updates) I used the function:<br />
Fosc/[sample rate * 4) = 20 * 10^6/(8000 * 4) = 625<br />
where sample rate = 18000 and Fosc = 20 * 10^6 . <br />
In
this example I used the value 500 instead of 625 because I got a slow
audio streaming (i.e: some instructions are spent on loops). <br />
The complete C code is the one below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">/*</span>
<span style="color: #7e7e7e;"> WAV Player using PIC16F877A microcontroller and SD card CCS C code.</span>
<span style="color: #7e7e7e;"> http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;"> electronnote@gmail.com</span>
<span style="color: #7e7e7e;">*/</span>
<span style="color: #7e7e7e;">// SD Card module connections</span>
<span style="color: red;">#define</span> SDCARD_SPI_HW
<span style="color: red;">#define</span> SDCARD_PIN_SELECT PIN_D3
<span style="color: #7e7e7e;">// End SD card module connections</span>
<span style="color: red;">#include</span> <16F877A.h>
<span style="color: red;">#fuses</span> HS,NOWDT,NOPROTECT,NOLVP
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 20MHz)
<span style="color: red;">#use</span> fast_io(D)
<span style="color: red;">#include</span> <FAT_Lib.c>
<span style="color: blue;">const</span> <span style="color: blue;">int8</span> *wav = <span style="color: #de00d0;">"mywav.wav"</span>;
<span style="color: blue;">int1</span> ok = 0;
<span style="color: blue;">int8</span> i, j, data[16], channel_count;
<span style="color: blue;">void</span> play(){
sdcard_read_byte(address_pointer + 22, &channel_count); <span style="color: #7e7e7e;">// Read number of channels</span>
<span style="color: blue;">while</span>(fat_read_data(16, data) == 0){
<span style="color: blue;">for</span>(i = 0; i < 16; i++){
set_timer1(0);
j = data[i];
set_pwm1_duty((<span style="color: blue;">int16</span>)j); <span style="color: #7e7e7e;">// Update PWM1 duty cycle</span>
<span style="color: blue;">if</span>(channel_count == 2){ <span style="color: #7e7e7e;">// If 2-channel wave file (stereo)</span>
i++; <span style="color: #7e7e7e;">// increment i</span>
j = data[i];
set_pwm2_duty((<span style="color: blue;">int16</span>)j); <span style="color: #7e7e7e;">// Update PWM2 duty cycle</span>
}
<span style="color: blue;">while</span>(get_timer1() < 500); <span style="color: #7e7e7e;">// Wait some time (about 125us) to update the duty cycles</span>
}
}
}
<span style="color: blue;">void</span> main(){
delay_ms(2000);
setup_ccp1(CCP_PWM); <span style="color: #7e7e7e;">// Configure CCP1 as a PWM</span>
setup_ccp2(CCP_PWM); <span style="color: #7e7e7e;">// Configure CCP2 as a PWM</span>
set_pwm1_duty(0); <span style="color: #7e7e7e;">// set PWM1 duty cycle to 0</span>
set_pwm2_duty(0); <span style="color: #7e7e7e;">// set PWM2 duty cycle to 0</span>
setup_timer_2(T2_DIV_BY_1, 63, 1); <span style="color: #7e7e7e;">// Set PWM frequency to maximum with 8-bit resolution</span>
setup_timer_1( T1_INTERNAL | T1_DIV_BY_1 );
ok |= sdcard_init(); <span style="color: #7e7e7e;">// Initialize the SD card module</span>
ok |= fat_init(); <span style="color: #7e7e7e;">// Initialize FAT library</span>
ok |= fat_open_file(wav); <span style="color: #7e7e7e;">// Open the wave file</span>
<span style="color: blue;">if</span>(ok == 0){
play();
}
set_pwm1_duty(0); <span style="color: #7e7e7e;">// set PWM1 duty cycle to 0</span>
set_pwm2_duty(0); <span style="color: #7e7e7e;">// set PWM2 duty cycle to 0</span>
} <span style="color: #7e7e7e;">// End</span>
</pre>
<span style="color: #cc0000;"><span style="font-size: large;">Wave player using PIC16F877A microcontroller and SD card video:</span></span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/j-Z448ZoO3w/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/j-Z448ZoO3w?feature=player_embedded" width="320"></iframe></div>
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-40113801388492123462017-09-16T22:42:00.001+02:002017-09-20T23:12:34.801+02:00PIC12F1822 + DS3231 + Remote ControlPIC12F1822 is a small microcontroller has only 8 pins which is not enough for building a real time clock using DS3231 with set buttons because the DS3231 needs 2 pins and the LCD screen needs 3 pins, therefore I've only 1 free pin. I connected that pin to an IR receiver and I used a remote control with a lot of buttons where I used only 3 buttons and the problem solved.<br />
This post shows how did I build a simple real time clock using PIC12F1822, 1602 LCD and DS3231 with Car MP3 IR remote control (NEC protocol RC).<br />
Before this project I made a NEC remote control decoder using PIC12F1822 MCU:<br />
<a href="http://ccspicc.blogspot.com/2016/09/extended-nec-protocol-decoder-pic12f1822-c-code.html" target="_blank">Extended NEC Protocol Decoder Using PIC12F1822 Microcontroller</a><br />
Time and calendar are displayed on 1602 LCD with the help of a serial-in parallel-out shift register (74HC595, 74HC164, CD4094 .....) as what I made in the example below:<br />
<a href="http://ccspicc.blogspot.com/2016/09/pic12f1822-lcd-scroll-one-line.html" target="_blank">Interfacing PIC12F1822 microcontroller with LCD display </a><br />
The
DS3231 uses I2C protocol to interface with the master device which is
in our example the PIC12F1822 MCU which has one I2C module.<br />
The I2C
protocol uses only two lines: SCL (Serial Clock) and SDA (Serial Data)
which are in the PIC12F1822 pin RA1 and pin RA2 respectively.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC12F1822 microcontroller</li>
<li>DS3231 board - <a href="https://datasheets.maximintegrated.com/en/ds/DS3231.pdf" target="_blank"><i>datasheet</i></a></li>
<li>1602 LCD screen</li>
<li>74HC595 shift register (74HC164 and CD4094 can be used)</li>
<li>IR receiver </li>
<li>10K ohm variable resistor</li>
<li>47uF capacitor</li>
<li>5V supply source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;"> The Circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3Yvj4aAAyaOZhTwzKiYn3rEtTWe5O-Oso_ymREV7s33mkyhpgSIH7HZxvT_ZeK5qSKGtrlrTX5YQsaWz_5RpUCLMnzloTvjyVaKGWfqzX354vmFsvjm0LWSh-UFuFhGSNd926YaAEsOI/s1600/pic12f1822+mcu+ds3231+rtc+car+mp3+nec+remote+control.png" imageanchor="1"><img alt="PIC12F1822 + DS3231 + Car MP3 remote control circuit" border="0" height="424" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3Yvj4aAAyaOZhTwzKiYn3rEtTWe5O-Oso_ymREV7s33mkyhpgSIH7HZxvT_ZeK5qSKGtrlrTX5YQsaWz_5RpUCLMnzloTvjyVaKGWfqzX354vmFsvjm0LWSh-UFuFhGSNd926YaAEsOI/s640/pic12f1822+mcu+ds3231+rtc+car+mp3+nec+remote+control.png" title="PIC12F1822 + DS3231 + Car MP3 remote control circuit" width="640" /></a></div>
The IR receiver has 3 pins: GND, VCC and OUT. Pin OUT is connected to pin RA3 of the PIC12F1822.<br />
The LCD screen with the 74HC595 shift register are connected to pins: RA0 (Enable), RA4 (Data) and RA5 (Clock).<br />
The DS3231 board SCL and SDA are connected to pins RA1 and RA2 respectively.<br />
In this project the PIC12F1822 uses its internal oscillator and MCLR pin is configured as a digital pin.<br />
<span style="color: #cc0000;"><span style="font-size: large;">The Code:</span></span><br />
The C code below was tested with CCS C compiler version 5.051.<br />
The hardware I2C module of the PIC12F1822 MCU is initialized and configured using the function below with a speed of 100KHz:<br />
<span style="background-color: yellow;">#use I2C(master, I2C1, FAST = 100000)</span><br />
<div class="Style1" style="margin-right: 0px;">
master: set the microcontroller to the master mode</div>
I2C1: use first I2C module.<br />
The DS3231 works with BCD format only and to convert the BCD to
decimal and vise versa I used the 2 functions below. Before displaying
(after reading from DS3231), the data have to be converted from BCD to
decimal, and before writing to the DS3231 (after editing the parameters)
the data have to be converted from decimal to BCD:<br />
<span style="background-color: yellow;"><span style="color: blue;">int8</span> bcd_to_decimal(number)</span><br />
<span style="background-color: yellow;"><span style="color: blue;">int8</span> decimal_to_bcd(number) </span><br />
Each function returns the converted value of the variable <span style="background-color: yellow;">number</span>.<br />
<span style="background-color: yellow;"><span style="color: blue;">void</span> DS3231_display() :</span>
displays time and calendar data, before displaying time and calendar
data are converted from BCD format to decimal format using the function <span style="background-color: yellow;">bcd_to_decimal(number)</span> .<br />
<span style="background-color: yellow;"><span style="color: blue;">int8</span> edit(x, y, parameter) :</span> I used this function to edit time calendar parameters (minutes, hours, date, month and year). I used a variable named<span style="background-color: yellow;"> i </span>to distinguish between the parameters:<br />
i = 0, 1 : time hours and minutes respectively<br />
i = 2, 3, 4: calendar date, month and year respectively<br />
After the edit of time and calendar, the data have to be converted back to BCD format using the function <span style="background-color: yellow;">decimal_to_bcd(number)</span> and written back to the DS3231.<br />
<span style="background-color: yellow;"><span style="color: blue;">void</span> blink() :</span>
this small function works as a delay except that it is interrupted by the IR remote control codes for buttons 1, 2 and 3. When called
and without pressing any of the three button the total time is 10 x 25ms = 250ms.
With this function we can see the blinking of the selected parameter
with a frequency of 2Hz. So a delay of 250ms comes after the print of
the selected parameter and after that delay a 2 spaces is printed which
makes the parameter disappears from the LCD and another 250ms delay
comes after the print of the 2 spaces.<br />
The remote control buttons and their codes are shown in the image below:<br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTjVsjGXJnOr4B8-B1wsIAROT0MmuUKT2nVJPTIqZV6JsOkOUG1XS9H3owDjAVcTvdumvpIfenZfmCeehithgPtg1lDF2xrM-MY7Gv4I2iqQ8GnxEeUhSlmdyRFYseY1icN2efvPkGFWg/s1600/nec_remote_control_buttons_rtcc.jpg" imageanchor="1"><img alt="Car MP3 IR remote control button codes" border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTjVsjGXJnOr4B8-B1wsIAROT0MmuUKT2nVJPTIqZV6JsOkOUG1XS9H3owDjAVcTvdumvpIfenZfmCeehithgPtg1lDF2xrM-MY7Gv4I2iqQ8GnxEeUhSlmdyRFYseY1icN2efvPkGFWg/s400/nec_remote_control_buttons_rtcc.jpg" title="Car MP3 IR remote control button codes" width="357" /></a> </div>
<div class="separator" style="clear: both; text-align: center;">
</div>
I used only 3 buttons where button 1 selects the parameter which we want to set (hours, minutes, date, month or year). Button 2 increments the selected parameter and button 3 decrements it. The rest of buttons have no effect on the circuit.<br />
Finally the interfacing of the LCD with the PIC12F1822 needs a small driver which can be found in the the following topic:<br />
<a href="http://ccspicc.blogspot.com/2016/08/3-wire-lcd-driver-ccs-pic-c-74hc595-hef4094.html" target="_blank">3-Wire LCD driver for CCS PIC C compiler</a><br />
The complete C code is the one below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">/* Interfacing PIC12F1822 MCU with DS3231 with NEC IR remote control (Car MP3)</span>
<span style="color: #7e7e7e;"> http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;"> electronnote@gmail.com</span>
<span style="color: #7e7e7e;">*/</span>
<span style="color: #7e7e7e;">//LCD module connections</span>
<span style="color: red;">#define</span> LCD_DATA_PIN PIN_A5
<span style="color: red;">#define</span> LCD_CLOCK_PIN PIN_A4
<span style="color: red;">#define</span> LCD_EN_PIN PIN_A0
<span style="color: #7e7e7e;">//End LCD module connections</span>
<span style="color: red;">#include</span> <12F1822.h>
<span style="color: red;">#fuses</span> NOMCLR INTRC_IO PLL_SW
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock=32000000)
<span style="color: red;">#use</span> fast_io(A)
<span style="color: red;">#include</span> <3WireLCD.c> <span style="color: #7e7e7e;">// 3-Wire LCD driver source file</span>
<span style="color: red;">#define</span> IR_Sensor PIN_A3
<span style="color: red;">#use</span> I2C(master, I2C1, FAST = 100000)
<span style="color: blue;">int1</span> nec_ok = 0;
<span style="color: blue;">int8</span> i, second, minute, hour, date, month, year;
<span style="color: blue;">int32</span> nec_code;
<span style="color: blue;">void</span> nec_remote_read(){
<span style="color: blue;">int8</span> j;
<span style="color: blue;">int16</span> count = 0;
<span style="color: #7e7e7e;">// Check 9ms pulse (remote control sends logic high)</span>
<span style="color: blue;">while</span>(!input(IR_Sensor) && (count < 9500))
count = GET_TIMER1();
<span style="color: blue;">if</span>((count > 9499) || (count < 8500))
<span style="color: blue;">return</span>;
<span style="color: #7e7e7e;">// Check 4.5ms space (remote control sends logic low)</span>
SET_TIMER1(0);
count = 0;
<span style="color: blue;">while</span>((input(IR_Sensor)) && (count < 5000))
count = GET_TIMER1();
<span style="color: blue;">if</span>((count > 4999) || (count < 1500))
<span style="color: blue;">return</span>;
<span style="color: blue;">if</span>(count < 3000){ <span style="color: #7e7e7e;">// Check if previous code is repeated</span>
SET_TIMER1(0);
count = 0;
<span style="color: blue;">while</span>(!input(IR_Sensor) && (count < 650))
count = GET_TIMER1();
<span style="color: blue;">if</span>((count > 649) || (count < 500))
<span style="color: blue;">return</span>;
<span style="color: #7e7e7e;">// Check if the repeated code is for button 2 or 3</span>
<span style="color: blue;">if</span>((nec_code == 0x40BF807F || nec_code == 0x40BF40BF)){
nec_ok = 1; <span style="color: #7e7e7e;">// Decoding process is finished with success</span>
disable_interrupts(INT_RA3); <span style="color: #7e7e7e;">// Disable the external interrupt</span>
<span style="color: blue;">return</span>;
}
}
<span style="color: #7e7e7e;">// Read message (32 bits)</span>
<span style="color: blue;">for</span>(j = 0; j < 32; j++){
SET_TIMER1(0);
count = 0;
<span style="color: blue;">while</span>(!input(IR_Sensor) && (count < 650))
count = GET_TIMER1();
<span style="color: blue;">if</span>((count > 649) || (count < 500))
<span style="color: blue;">return</span>;
count = 0;
SET_TIMER1(0);
<span style="color: blue;">while</span>((input(IR_Sensor)) && (count < 1800))
count = GET_TIMER1();
<span style="color: blue;">if</span>( (count > 1799) || (count < 400))
<span style="color: blue;">return</span>;
<span style="color: blue;">if</span>( count > 1000) <span style="color: #7e7e7e;">// If space width > 1ms</span>
bit_set(nec_code, (31 - j)); <span style="color: #7e7e7e;">// Write 1 to bit (31 - j)</span>
<span style="color: blue;">else</span> <span style="color: #7e7e7e;">// If space width < 1ms</span>
bit_clear(nec_code, (31 - j)); <span style="color: #7e7e7e;">// Write 0 to bit (31 - j)</span>
}
disable_interrupts(INT_RA3);
nec_ok = 1;
<span style="color: blue;">return</span>;
}
#INT_RA <span style="color: #7e7e7e;">// RA port interrupt on change</span>
<span style="color: blue;">void</span> ra_isr(<span style="color: blue;">void</span>){
SET_TIMER1(0);
SETUP_TIMER_1(T1_INTERNAL | T1_DIV_BY_8); <span style="color: #7e7e7e;">// Configure Timer 1 to increment every 1 us </span>
nec_remote_read();
SETUP_TIMER_1(T1_DISABLED); <span style="color: #7e7e7e;">// Stop Timer1 module</span>
clear_interrupt(INT_RA);
}
<span style="color: blue;">int8</span> bcd_to_decimal(number){ <span style="color: #7e7e7e;">// Convert BCD to decimal function</span>
<span style="color: blue;">return</span>((number >> 4) * 10 + (number & 0x0F));
}
<span style="color: blue;">int8</span> decimal_to_bcd(number){ <span style="color: #7e7e7e;">// Convert decimal to BCD function</span>
<span style="color: blue;">return</span>(((number / 10) << 4) + (number % 10));
}
<span style="color: blue;">void</span> ds3231_display(){
<span style="color: #7e7e7e;">// Convert data from BCD format to decimal format</span>
second = bcd_to_decimal(second);
minute = bcd_to_decimal(minute);
hour = bcd_to_decimal(hour);
date = bcd_to_decimal(date);
month = bcd_to_decimal(month);
year = bcd_to_decimal(year);
<span style="color: #7e7e7e;">// End conversion</span>
lcd_goto(13, 1);
printf(lcd_out,<span style="color: #de00d0;">"%02u"</span>, second); <span style="color: #7e7e7e;">// Display seconds</span>
lcd_goto(10, 1);
printf(lcd_out,<span style="color: #de00d0;">"%02u"</span>, minute); <span style="color: #7e7e7e;">// Display minutes</span>
lcd_goto(7, 1);
printf(lcd_out,<span style="color: #de00d0;">"%02u"</span>, hour); <span style="color: #7e7e7e;">// Display hours</span>
lcd_goto(7, 2);
printf(lcd_out,<span style="color: #de00d0;">"%02u"</span>, date); <span style="color: #7e7e7e;">// Display date</span>
lcd_goto(10, 2);
printf(lcd_out,<span style="color: #de00d0;">"%02u"</span>, month); <span style="color: #7e7e7e;">// Display month</span>
lcd_goto(15, 2);
printf(lcd_out,<span style="color: #de00d0;">"%02u"</span>, year); <span style="color: #7e7e7e;">// Display year</span>
}
<span style="color: blue;">void</span> _reset(){
nec_ok = 0; <span style="color: #7e7e7e;">// Reset decoding process</span>
enable_interrupts(INT_RA3_H2L); <span style="color: #7e7e7e;">// Enable RA3 interrupt (High to low)</span>
}
<span style="color: blue;">void</span> <span style="color: blue;">blink</span>(){
<span style="color: blue;">int8</span> j = 0;
<span style="color: blue;">while</span>((!nec_ok || (nec_code != 0x40BF00FF) && (nec_code != 0x40BF40BF) && (nec_code != 0x40BF807F)) && (j < 10)){
j++;
delay_ms(25);
}
}
<span style="color: blue;">int8</span> edit(x, y, parameter){
_reset();
<span style="color: blue;">while</span>(TRUE){
<span style="color: blue;">if</span>(nec_ok && nec_code == 0x40BF40BF){ <span style="color: #7e7e7e;">// If button RB1 is pressed</span>
parameter++;
<span style="color: blue;">if</span>(i == 0 && parameter > 23) <span style="color: #7e7e7e;">// If hours > 23 ==> hours = 0</span>
parameter = 0;
<span style="color: blue;">if</span>(i == 1 && parameter > 59) <span style="color: #7e7e7e;">// If minutes > 59 ==> minutes = 0</span>
parameter = 0;
<span style="color: blue;">if</span>(i == 2 && parameter > 31) <span style="color: #7e7e7e;">// If date > 31 ==> date = 1</span>
parameter = 1;
<span style="color: blue;">if</span>(i == 3 && parameter > 12) <span style="color: #7e7e7e;">// If month > 12 ==> month = 1</span>
parameter = 1;
<span style="color: blue;">if</span>(i == 4 && parameter > 99) <span style="color: #7e7e7e;">// If year > 99 ==> year = 0</span>
parameter = 0;
}
<span style="color: blue;">if</span>(nec_ok && nec_code == 0x40BF807F){
<span style="color: blue;">if</span>(i == 0 && parameter < 1)
parameter = 24;
<span style="color: blue;">if</span>(i == 1 && parameter < 1)
parameter = 60;
<span style="color: blue;">if</span>(i == 2 && parameter < 2)
parameter = 32;
<span style="color: blue;">if</span>(i == 3 && parameter < 2)
parameter = 13;
<span style="color: blue;">if</span>(i == 4 && parameter < 1)
parameter = 100;
parameter--;
}
lcd_goto(x, y);
printf(lcd_out,<span style="color: #de00d0;">"%02u"</span>, parameter);
<span style="color: blue;">if</span>(nec_ok){
delay_ms(200);
_reset();
}
<span style="color: blue;">blink</span>();
lcd_goto(x, y);
lcd_out(<span style="color: #de00d0;">" "</span>); <span style="color: #7e7e7e;">// Display two spaces</span>
<span style="color: blue;">blink</span>();
<span style="color: blue;">if</span>(nec_ok && nec_code == 0x40BF00FF){
lcd_goto(x, y);
printf(lcd_out,<span style="color: #de00d0;">"%02u"</span>, parameter);
i++; <span style="color: #7e7e7e;">// Increment 'i' for the next parameter</span>
<span style="color: blue;">return</span> parameter; <span style="color: #7e7e7e;">// Return parameter value and exit</span>
}
}
}
<span style="color: blue;">void</span> main() {
setup_oscillator(OSC_8MHZ | OSC_PLL_ON); <span style="color: #7e7e7e;">// Set internal oscillator to 32MHz (8MHz and PLL)</span>
set_tris_a(0x0E); <span style="color: #7e7e7e;">// Configure RA1, RA2 & RA3 as inputs</span>
port_a_pullups(8); <span style="color: #7e7e7e;">// Enable pin RA3 internal pull-up</span>
lcd_initialize(); <span style="color: #7e7e7e;">// Initialize LCD module</span>
lcd_cmd(LCD_CLEAR); <span style="color: #7e7e7e;">// LCD Clear</span>
enable_interrupts(GLOBAL); <span style="color: #7e7e7e;">// Enable global interrupts</span>
clear_interrupt(INT_RA); <span style="color: #7e7e7e;">// Clear RA IOC flag bit</span>
enable_interrupts(INT_RA3_H2L); <span style="color: #7e7e7e;">// Enable RA3 interrupt (High to low)</span>
lcd_goto(1, 1); lcd_out(<span style="color: #de00d0;">"TIME: : :"</span>);
lcd_goto(1, 2); lcd_out(<span style="color: #de00d0;">"DATE: / /20"</span>);
<span style="color: blue;">while</span>(TRUE){
<span style="color: blue;">if</span>(nec_ok == 1){ <span style="color: #7e7e7e;">// If a NEC remote code was received</span>
<span style="color: blue;">if</span>(nec_code == 0x40BF00FF){ <span style="color: #7e7e7e;">// If the remote code is for button 1</span>
i = 0;
hour = edit(7, 1, hour);
minute = edit(10, 1, minute);
date = edit(7, 2, date);
month = edit(10, 2, month);
year = edit(15, 2, year);
<span style="color: #7e7e7e;">// Convert decimal to BCD</span>
minute = decimal_to_bcd(minute);
hour = decimal_to_bcd(hour);
date = decimal_to_bcd(date);
month = decimal_to_bcd(month);
year = decimal_to_bcd(year);
<span style="color: #7e7e7e;">// End conversion</span>
<span style="color: #7e7e7e;">// Write data to DS3231 RTC</span>
i2c_start(); <span style="color: #7e7e7e;">// Start I2C protocol</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(0); <span style="color: #7e7e7e;">// Send register address</span>
i2c_write(0); <span style="color: #7e7e7e;">// Reset seconds and start oscillator</span>
i2c_write(minute); <span style="color: #7e7e7e;">// Write minute value to DS3231</span>
i2c_write(hour); <span style="color: #7e7e7e;">// Write hour value to DS3231</span>
i2c_write(1); <span style="color: #7e7e7e;">// Write day value (not used)</span>
i2c_write(date); <span style="color: #7e7e7e;">// Write date value to DS3231</span>
i2c_write(month); <span style="color: #7e7e7e;">// Write month value to DS3231</span>
i2c_write(year); <span style="color: #7e7e7e;">// Write year value to DS3231</span>
}
_reset(); <span style="color: #7e7e7e;">// Call _reset function</span>
}
i2c_start(); <span style="color: #7e7e7e;">// Start I2C protocol</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(0); <span style="color: #7e7e7e;">// Send register address</span>
i2c_start(); <span style="color: #7e7e7e;">// Restart I2C</span>
i2c_write(0xD1); <span style="color: #7e7e7e;">// Initialize data read</span>
second = i2c_read(1); <span style="color: #7e7e7e;">// Read seconds from register 0</span>
minute = i2c_read(1); <span style="color: #7e7e7e;">// Read minutes from register 1</span>
hour = i2c_read(1); <span style="color: #7e7e7e;">// Read hour from register 2</span>
i2c_read(1); <span style="color: #7e7e7e;">// Read day from register 3 (not used)</span>
date = i2c_read(1); <span style="color: #7e7e7e;">// Read date from register 4</span>
month = i2c_read(1); <span style="color: #7e7e7e;">// Read month from register 5</span>
year = i2c_read(0); <span style="color: #7e7e7e;">// Read year from register 6</span>
i2c_stop(); <span style="color: #7e7e7e;">// Stop I2C protocol</span>
DS3231_display(); <span style="color: #7e7e7e;">// Display time & calendar</span>
delay_ms(50);
}
}
<span style="color: #7e7e7e;">// End of code.</span>
</pre>
<span style="color: #cc0000;"><span style="font-size: large;">Small video:</span></span><br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/vDlhzV4Uqgw/0.jpg" src="https://www.youtube.com/embed/vDlhzV4Uqgw?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-34047716315148199902017-09-15T16:01:00.000+02:002018-06-02T19:39:04.577+02:00Wave player using PIC18F4550 microcontrollerMaking an audio player (.wav files) using PIC microcontroller is not complicated especially when the MCU has a PWM module. This topic shows how to build an audio player using PIC18F4550 microcontroller where the the file is stored in an SD card with FAT16 or FAT32 file system.<br />
In this project I used a wave file with sample rate of 16000 Hz and 2 channels (stereo). The file I used originally it was an MP3 file and I converted it to 8-bit wav format using an audio converter named audacity, it is a free and open source audio software (site: <a href="http://www.audacityteam.org/" target="_blank">http://www.audacityteam.org/</a>).<br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC18F4550 microcontroller</li>
<li>SD card</li>
<li>ASM1117 3.3 voltage regulator</li>
<li>Audio amplifier (ex: PC speaker, LM386 ......)</li>
<li>Speaker</li>
<li>8 MHz crystal oscillator</li>
<li>2 x 22pF ceramic capacitors</li>
<li>3 x 3.3K ohm resistor</li>
<li>3 x 2.2K ohm resistor</li>
<li>10K ohm resistor</li>
<li>1K ohm resistor </li>
<li>2 x 10uF polarized capacitor</li>
<li>100nF ceramic capacitor</li>
<li>5V Power source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
<script async="" src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<ins class="adsbygoogle" data-ad-client="ca-pub-9821904216837075" data-ad-format="fluid" data-ad-layout="in-article" data-ad-slot="9358819745" style="display: block; text-align: center;"></ins><script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script><br/>
<span style="color: #cc0000;"><span style="font-size: large;">The Circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIaVzID41pep9JwgC0ZUAW2UqY1wEswpuVhP1fX-NfgC8khq6AsyvPdO7VOqC2r2hH-kUisV75-3lJvx-pc-pGYJBNqrkpYQtJ2Eg_on4cmE8217k8fe4yB9daJ7N4np4fX1gqOXE3ocA/s1600/audio-wave-player-sd-card-pic18f4550.png" imageanchor="1"><img alt="Wave player using PIC18F4550 microcontroller circuit" border="0" height="344" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIaVzID41pep9JwgC0ZUAW2UqY1wEswpuVhP1fX-NfgC8khq6AsyvPdO7VOqC2r2hH-kUisV75-3lJvx-pc-pGYJBNqrkpYQtJ2Eg_on4cmE8217k8fe4yB9daJ7N4np4fX1gqOXE3ocA/s640/audio-wave-player-sd-card-pic18f4550.png" title="Wave player using PIC18F4550 microcontroller circuit" width="640" /></a></div>
<br />
The AMS1117 3.3V voltage regulator is used to supply the SD card with
3.3V. Also 3 voltage dividers are used to step down the 5V which comes
from the microcontroller (come from RD2, RC7 and RB1) to about 3V which
is sufficient for the SD
card. Each voltage divider consists of 2K2 and 3K3 resistors. Pin RB0 of
the microcontroller is connected directly to the SD card MISO pin with a
pull-up resistor of 10K ohm.<br />
Hardware SPI module is used by the microcontroller to read data from the SD card, the SPI pins of the PIC18F4550 MCU are:<br />
<ul>
<li>SD0 (RC7): connected to pin MOSI of the SD card</li>
<li>SCK (RB1): connected to pin SCK of the SD card</li>
<li>SDI (RB0): connected to pin MISO of the SD card </li>
</ul>
There is an other pin which is CS (Chip Select or slave select) can be
connected to any digital output pin (defined in the code), this pin is
connected to SS pin of the SD cards.<br />
The audio is generated using PWM technique, basically the PIC18F4550 has two PWM modules and their output are RC2 and RC1 for PWM1 and PWM2 respectively. An audio amplifier is needed to amplify the audio. In my circuit I used PC speaker as an amplifier. If the audio is stereo (2 channels) connect the same amplification circuit and use PWM2 output pin (RC1).<br />
In this project PIC18F4550 MCU runs with 8 MHz crystal oscillator and MCLR pin function is disabled. <br />
<span style="color: #cc0000;"><span style="font-size: large;">The C code:</span></span><br />
The C code below was tested with CCS C compiler versions 5.051 and 5.070.<br />
The microcontroller runs at 48MHz (8MHz + PLL).<br />
In this project I used the FAT library (FAT16 and FAT32), its source file can be found in the the following topic:<br />
<a href="https://ccspicc.blogspot.com/2017/09/FAT16-FAT32-library-PIC-microcontroller.html" target="_blank">SD card FAT library for CCS C compiler</a><br />
I tested this project with FAT32 8 GB and FAT16 2 GB micro-SD card.<br />
The name of the wave audio file which I used was <span style="background-color: yellow;">audio</span> (audio.wav with the extension), its sample rate is 16000 Hz with 2 channels (stereo).<br />
First of all I initialized the SD card using the function: <span style="background-color: yellow;">sdcard_init();</span> this function return 0 if the initialization was OK and non-zero if there was an error. After the initialization of the SD card I initialized the FAT file system using the function <span style="background-color: yellow;">fat_init();</span> and then I opened the wave audio file with the pre-selected name <span style="background-color: yellow;">audio.wav</span>, all the three previous function returns 0 if OK and no-zero if error.<br />
If the initialization of the SD card, the FAT system and opening of the file were OK that means the variable which named <span style="background-color: yellow;">ok = 0</span> and playing the wave file starts using the function <span style="background-color: yellow;">play();</span> .<br />
The wave file header size is 44 bytes which I skipped using the variable <span style="background-color: yellow;">file_pointer</span>. The variable <span style="background-color: yellow;">file_pointer</span> belongs to the FAT library, this variable can be between 0 and the opened file size, for example if a file of size 500 byte is opened the variable <span style="background-color: yellow;">file_pointer</span> starts from 0 and ends to 500, it is incremented with the function <span style="background-color: yellow;">fat_read_file</span> according to the selected size. Generally it can be neglected in this project and the line below can be removed from the code:<br />
<span style="background-color: yellow;">file_pointer += 44;</span><br />
To detect if the wave file is mono (1 channel) or stereo (2 channels), I read the byte 22 of the wave file using the function :<br />
<span style="background-color: yellow;">sdcard_read_byte(address_pointer + 22, &channel_count);</span><br />
where <span style="background-color: yellow;">address_pointer</span> also belongs to the FAT library, this variable allows me to know the starting address of the wave audio file. If the wave file is mono ==> <span style="background-color: yellow;">channel_count =1</span> and if it is stereo ==> <span style="background-color: yellow;">channel_count = 2<span style="background-color: white;">.</span></span><br />
I set the data buffer to 32 so each time the microcontroller reads 32 bytes from the SD card. The data buffer can be less or higher than 32.<br />
The function <span style="background-color: yellow;">fat_read_data(32, data)</span> keeps reading file data from the SD card until it returns 1 which means end of file is reached.<br />
<br/>
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- ccslink1 -->
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-9821904216837075"
data-ad-slot="2075108943"
data-ad-format="link"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script><br/>
The wave file must be 8-bit and for that I configured the PWM outputs to give the maximum frequency with 8-bit resolution, for that I configured Timer2 module as shown below:<br />
<span style="background-color: yellow;">setup_timer_2(T2_DIV_BY_1, 63, 1);</span><br />
The resolution of the PWM signal can be calculated using the function:<br />
PWM Resolution = Log[(PR2 + 1)*4]/Log(2) = Log[(63 + 1)*4]/Log(2) = 8<br />
The PWM frequency should be as higher as possible and with the previous configuration I got a PWM frequency of 187.5 KHz. It can be calculated with the function below:<br />
PWM_Frequency = Fosc/[(PR2 + 1)*4*TMR2_Prescaler] = 48*10^6/[(63 + 1)*4*1] = 187.5 KHz.<br />
If <span style="background-color: yellow;">channel_count = 2<span style="background-color: white;"> the 2nd PWM duty cycle also will be updated and the sound will be generated from PWM1 (RC2) and PWM2 (RC1) outputs (left and right).</span></span><br />
Now how did I used Timer1 module and the wave file sample rate (16000 Hz):<br />
the PWM duty cycles have to be updated every 62.5 us ( = 1/16000Hz), for that I used Timer1 to make the MCU waits for 62.5 us. In this example I didn't use Timer1 interrupt.<br />
I configured Timer1 module to increment on every MCU cycle (about 83 ns) and to compute Timer1 value (values between 2 updates) I used the function:<br />
Fosc/[sample rate * 4) = 48 * 10^6/(16000 * 4) = 750<br />
where sample rate = 16000 and Fosc = 48 * 10^6 . <br />
In this example I used the value 650 instead of 750 because I got a slow audio streaming (i.e: some instructions are spent on loops).<br />
The complete C code is the one below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">// Wave player using PIC18F4550 microcontroller and SD card.</span>
<span style="color: #7e7e7e;">// http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;">// electronnote@gmail.com</span>
<span style="color: #7e7e7e;">// SD Card module connections</span>
<span style="color: red;">#define</span> SDCARD_SPI_HW
<span style="color: red;">#define</span> SDCARD_PIN_SELECT PIN_D2
<span style="color: #7e7e7e;">// End SD card module connections</span>
<span style="color: red;">#include</span> <18F4550.h>
<span style="color: red;">#fuses</span> NOMCLR HSPLL PLL2 CPUDIV1
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 48MHz)
<span style="color: red;">#use</span> fast_io(D)
<span style="color: red;">#include</span> <FAT_Lib.c>
<span style="color: blue;">const</span> <span style="color: blue;">int8</span> *wav = <span style="color: #de00d0;">"audio.wav"</span>;
<span style="color: blue;">int1</span> ok = 0;
<span style="color: blue;">int8</span> i, j, data[32], channel_count;
<span style="color: blue;">void</span> play(){
file_pointer += 44; <span style="color: #7e7e7e;">// Skip wave file header (44 bytes)</span>
sdcard_read_byte(address_pointer + 22, &channel_count); <span style="color: #7e7e7e;">// Read number of channels</span>
<span style="color: blue;">while</span>(fat_read_data(32, data) == 0){
<span style="color: blue;">for</span>(i = 0; i < 32; i++){
set_timer1(0);
j = data[i];
set_pwm1_duty((<span style="color: blue;">int16</span>)j); <span style="color: #7e7e7e;">// Update PWM1 duty cycle</span>
<span style="color: blue;">if</span>(channel_count == 2){ <span style="color: #7e7e7e;">// If 2-channel wave file (stereo)</span>
i++; <span style="color: #7e7e7e;">// increment i</span>
j = data[i];
set_pwm2_duty((<span style="color: blue;">int16</span>)j); <span style="color: #7e7e7e;">// Update PWM2 duty cycle</span>
}
<span style="color: blue;">while</span>(get_timer1() < 650); <span style="color: #7e7e7e;">// Wait some time (about 62.5us) to update the duty cycles</span>
}
}
}
<span style="color: blue;">void</span> main(){
delay_ms(2000);
setup_ccp1(CCP_PWM); <span style="color: #7e7e7e;">// Configure CCP1 as a PWM</span>
setup_ccp2(CCP_PWM); <span style="color: #7e7e7e;">// Configure CCP2 as a PWM</span>
set_pwm1_duty(0); <span style="color: #7e7e7e;">// set PWM1 duty cycle to 0</span>
set_pwm2_duty(0); <span style="color: #7e7e7e;">// set PWM2 duty cycle to 0</span>
setup_timer_2(T2_DIV_BY_1, 63, 1); <span style="color: #7e7e7e;">// Set PWM frequency to maximum with 8-bit resolution</span>
setup_timer_1( T1_INTERNAL | T1_DIV_BY_1 );
ok |= sdcard_init(); <span style="color: #7e7e7e;">// Initialize the SD card module</span>
ok |= fat_init(); <span style="color: #7e7e7e;">// Initialize FAT library</span>
ok |= fat_open_file(wav); <span style="color: #7e7e7e;">// Open the wave file</span>
<span style="color: blue;">if</span>(ok == 0){
play();
}
set_pwm1_duty(0); <span style="color: #7e7e7e;">// set PWM1 duty cycle to 0</span>
set_pwm2_duty(0); <span style="color: #7e7e7e;">// set PWM2 duty cycle to 0</span>
} <span style="color: #7e7e7e;">// End</span>
</pre>
<span style="color: #cc0000;"><span style="font-size: large;">Wave player using PIC18F4550 microcontroller video:</span></span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/D0zyh5r1iqE/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/D0zyh5r1iqE?feature=player_embedded" width="320"></iframe></div>
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-13329849480899663872017-09-15T15:53:00.000+02:002018-06-03T19:19:28.605+02:00SD card FAT library for CCS C compilerThis is a simple FAT library (FAT16 and FAT32) for CCS PIC C compiler for reading files from MMC/SD card module. This library works with PIC microcontrollers with limited RAM and ROM like PIC12F1840 MCU. This library works with FAT16 and FAT32 formatted MMC/SD card, it's automatically detects the FAT type (FAT16 or FAT32).<br />
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<ins class="adsbygoogle"
style="display:block; text-align:center;"
data-ad-layout="in-article"
data-ad-format="fluid"
data-ad-client="ca-pub-9821904216837075"
data-ad-slot="9358819745"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
<br/>
<span style="font-size: large;"><span style="color: #cc0000;">About the FAT library:</span></span><br />
<ul>
<li>MMC/SD Card driver integrated in the library</li>
<li>This library is for reading files only</li>
<li>This library works with MMC/SD cards which do not have MBR (Master Boot Record) on its first sector. The MMC/SD card may run on PC or camera but the library may not be able to detect the FAT file system and hence FAT initialization error because the MBR and to make it run just format the card using Windows</li>
<li>Only short file name is supported (file name + extension < 13 characters)</li>
<li>Only one file can be opened at a time, if a 2nd file is opened the first file will be automatically closed</li>
<li>The user can set buffer size starting from 1 byte. Bigger buffer size --> higher speed.</li>
<li>Letter case insensitive</li>
<li>Library functions read files from the root directory only.</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">Library Functions:</span></span><br />
<span style="background-color: yellow;"><span style="background-color: white;"><span style="background-color: yellow;"><b></b><span style="background-color: white;"><b>MMC/SD card and MCU connection:</b></span></span></span></span><br />
<span style="background-color: yellow;"><span style="background-color: white;"><span style="background-color: yellow;"><span style="background-color: white;">The MMC or the SD card is interfaced with the microcontroller using SPI protocol, with this library I can use hardware SPI module of the microcontroller or software SPI which is implemented by the compiler. The hardware SPI is much faster than the software SPI.</span></span></span></span><br />
<span style="background-color: yellow;"><span style="background-color: white;"><span style="background-color: yellow;"><span style="background-color: white;"><u>Examples: </u></span></span></span></span><br />
<span style="background-color: yellow;"><span style="background-color: white;"><span style="background-color: yellow;"><span style="background-color: white;">Hardware SPI module is used and the CS pin is connected to pin RB3:</span></span></span></span><br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 82px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">// SD Card module connections</span>
<span style="color: red;">#define</span> SDCARD_SPI_HW
<span style="color: red;">#define</span> SDCARD_PIN_SELECT PIN_B3
<span style="color: #7e7e7e;">// End of SD card module connections</span>
</pre>
Software SPI: here the SD card communicates with the microcontroller via soft SPI:<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 125px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">// SD Card module connections</span>
<span style="color: red;">#define</span> SDCARD_PIN_SDI PIN_B0
<span style="color: red;">#define</span> SDCARD_PIN_SDO PIN_B1
<span style="color: red;">#define</span> SDCARD_PIN_SCL PIN_B2
<span style="color: red;">#define</span> SDCARD_PIN_SELECT PIN_B3
<span style="color: #7e7e7e;">// End of SD card module connections</span>
</pre>
<span style="background-color: yellow;"><span style="background-color: white;"><span style="background-color: yellow;">sdcard_init(); </span>: Initializes the media. Returns 0 if OK, non-zero if error. This function must be called before any other function.</span></span><br />
<span style="background-color: yellow;"><span style="background-color: white;"><span style="background-color: yellow;">sdcard_read_byte(int32 addr, int8* data); </span>: Reads a byte from the MMC/SD card at address <span style="background-color: yellow;">addr</span>, saves it to pointer <span style="background-color: yellow;">data</span>. Returns 0 if OK, non-zero if error. </span> </span><br />
<span style="background-color: yellow;">fat_init(); </span>: Initializes the FAT library. Returns 0 if OK, 1 if error.<br />
<span style="background-color: yellow;">fat_open_file(int8* fname); </span>: Opens file stream. <span style="background-color: yellow;">fname</span> is file name. Returns 0 if OK and 1 if the opening process faced problem (file not found, long file name ...........).<br />
<span style="background-color: yellow;">fat_read_data(int32 size, int8* data); </span>: Reads an array <span style="background-color: yellow;">data </span>of size <span style="background-color: yellow;">size</span> from the opened file. Returns 0 if OK, 1 if error or end of file is reached.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Library Download:</span></span><br />
<a href="https://drive.google.com/open?id=0ByrcgOkOu0vgcEtUSTE3bTNKU2s" target="_blank"><b>FAT Library for CCS PIC C compiler</b></a><br />
<br />
<span style="color: #cc0000;"><span style="font-size: large;">Examples:</span></span><br />
<a href="https://ccspicc.blogspot.com/2017/09/wave-audio-player-pic18f4550.html" target="_blank">Wave player using PIC18F4550 microcontroller</a><br />
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-43474017191901584952017-09-08T19:01:00.000+02:002017-09-20T23:12:34.812+02:00Interfacing SD card with PIC12F1822 (Raw data read)With the tiny microcontroller PIC12F1822 we can read raw data (sectors) stored in the SD card. The SD card can work in SPI mode which makes our interfacing more better since the PIC12F1822 MCU has a built-in SPI module (MSSP module).<br />
This post shows how to interface the SD card with the PIC12F1822 microcontroller in order to read the raw data stored in it (the SD card).<br />
SD card raw data means that there is no use of system files like
FAT16 or FAT32. Serial monitor is used to display the data after reading
it and here the UART protocol is used.<br />
the link below shows a small PIC12F1822 MCU UART example:<br />
<a href="http://ccspicc.blogspot.com/2017/09/pic12f1822-uart-example-max232.html" target="_blank">PIC12F1822 UART example with CCS C compiler</a><br />
In this project I used the MMC/SD card driver for CCS C compiler which is described in the post at the link below:<br />
<a href="http://ccspicc.blogspot.com/2017/08/mmc-sd-card-driver-for-ccs-compiler.html" target="_blank">MMC/SD Card driver for CCS PIC C compiler</a><br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC12F1822 microcontroller</li>
<li>SD Card</li>
<li>AMS1117 3.3V voltage regulator</li>
<li>3 x 3.3K ohm resistor</li>
<li>3 x 2.2K ohm resistor</li>
<li>10K ohm resistor</li>
<li>5 x 10uF polarized capacitor</li>
<li>100nF ceramic capacitor</li>
<li>MAX232 chip</li>
<li>Female RS232 connector</li>
<li>5V Power source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">Interfacing SD card with PIC12F1822 MCU circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM5_CCeyZw0yNEOm8CZCaCZ7_82ypZBOLAPu4rGEzTj6YvKprtlnbFze8dc9wpy5o2RUY7cPQohRx8hWWC3l3NFVoJI-JDDckI7slVEUgi1psEpgwRVbnzEgsbbk4EvQo3OEXFU7XYqcQ/s1600/pic12f1822-spi-mmc-sd-card-sector-read.png" imageanchor="1"><img alt="Interfacing PIC12F1822 MCU with SD card circuit" border="0" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM5_CCeyZw0yNEOm8CZCaCZ7_82ypZBOLAPu4rGEzTj6YvKprtlnbFze8dc9wpy5o2RUY7cPQohRx8hWWC3l3NFVoJI-JDDckI7slVEUgi1psEpgwRVbnzEgsbbk4EvQo3OEXFU7XYqcQ/s640/pic12f1822-spi-mmc-sd-card-sector-read.png" title="Interfacing PIC12F1822 MCU with SD card circuit" width="640" /></a></div>
The AMS1117 3.3V voltage regulator is used to supply the SD card with
3.3V. Also 3 voltage dividers are used to step down the 5V which comes
from the microcontroller (come from RA0, RA1 and RA4) to about 3V which is sufficient for the SD
card. Each voltage divider consists of 2K2 and 3K3 resistors. Pin RA2 of the microcontroller is connected directly to the SD card MISO pin with a pull-up resistor of 10K ohm.<br />
MAX232
integrated circuit is used to interface the microcontroller with the
PC, I connected just one wire (RA5) because I need to transmit data from
the SD card to the microcontroller and then from the microcontroller to
the PC, there is no need to connect the second wire because I don't need to send data from the PC to the microcontroller.<br />
Hardware SPI module is used by the microcontroller to read data from the SD card, the SPI pins of the PIC12F1822 MCU are:<br />
<ul>
<li>SD0 (RA0): connected to pin MOSI of the SD card</li>
<li>SCK (RA1): connected to pin SCK of the SD card</li>
<li>SDI (RA2): connected to pin MISO of the SD card </li>
</ul>
and there is an other pin which is CS (Chip Select) can be
connected to any digital output pin (defined in the code), this pin is
connected to SS pin of the SD card.<br />
In this project PIC12F1822 MCU uses its internal oscillator and MCLR pin function is disabled. <br />
<span style="color: #cc0000;"><span style="font-size: large;">SD Card raw data read using PIC16F887 CCS C code:</span></span><br />
The C code below was tested with CCS PIC C compiler version 5.051.<br />
There are two functions in the code:<span style="background-color: yellow;"> sdcard_read_byte</span> and <span style="background-color: yellow;">sdcard_read_data</span>.
I used the first function to read byte with address 0 and I used the
second function to read sector number 0. Since the PIC12F1822 has only 128 bytes of RAM, I can not upload all the sector data (512 bytes) in
one time, I divided the sector into 16 32-byte parts, so 16 x 32 = 512.
The <span style="background-color: yellow;">sdcard_read_data</span> function allows us to read data from the SD card starting from any address with any size we want.<br />
The functions<span style="background-color: yellow;"> sdcard_init</span> , <span style="background-color: yellow;">sdcard_read_byte</span> and <span style="background-color: yellow;">sdcard_read_data</span> return 0 if OK and non-zero if an error has been occurred. <br />
Complete C code is below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">/* Interfacing PIC12F1822 MCU with SD card CCS C code.</span>
<span style="color: #7e7e7e;"> This example shows raw data read of the SD card.</span>
<span style="color: #7e7e7e;"> This example does not use any file system (FAT16, FAT32 ...).</span>
<span style="color: #7e7e7e;"> MMC/SD card driver for CCS C compiler must be installed!</span>
<span style="color: #7e7e7e;"> http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;"> electronnote@gmail.com</span>
<span style="color: #7e7e7e;">*/</span>
<span style="color: #7e7e7e;">// SD Card module connections</span>
<span style="color: red;">#define</span> SDCARD_SPI_HW <span style="color: #7e7e7e;">// Hardware SPI module is used for the SD card</span>
<span style="color: red;">#define</span> SDCARD_PIN_SELECT PIN_A4 <span style="color: #7e7e7e;">// SD card chip select pin is connected to pin RD3</span>
<span style="color: #7e7e7e;">// End SD card module connections</span>
<span style="color: red;">#include</span> <12F1822.h>
<span style="color: red;">#fuses</span> NOMCLR INTRC_IO PLL_SW
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock=32000000)
<span style="color: red;">#use</span> fast_io(A)
<span style="color: red;">#use</span> rs232(xmit = PIN_A5, rcv = PIN_A3, baud = 9600)
<span style="color: red;">#include</span> <sdcard.c> <span style="color: #7e7e7e;">// SD card diver source file</span>
<span style="color: blue;">int8</span> i, j, one_byte, _data[32], <span style="color: blue;">size</span> = 32;
<span style="color: blue;">void</span> main() {
set_tris_a(4);
setup_oscillator(OSC_8MHZ | OSC_PLL_ON); <span style="color: #7e7e7e;">// Set internal oscillator to 8MHz with PLL enabled (32MHz)</span>
delay_ms(2000);
printf(<span style="color: #de00d0;">"\r"</span>); <span style="color: #7e7e7e;">// Set cursor to first position</span>
printf(<span style="color: #de00d0;">"*** Interfacing PIC12F1822 MCU with SD card ***"</span>);
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
printf(<span style="color: #de00d0;">"Initializing the SD card..."</span>);
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
i = sdcard_init(); <span style="color: #7e7e7e;">// Initialize the SD card module</span>
<span style="color: blue;">if</span>(i == 0){ <span style="color: #7e7e7e;">// If the SD card has been successfully initialized</span>
<span style="color: #7e7e7e;">// Read 1 single byte</span>
printf(<span style="color: #de00d0;">"Read byte with address 0:"</span>);
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
delay_ms(2000);
<span style="color: blue;">if</span>(sdcard_read_byte(0, &one_byte) == 0)
printf(<span style="color: #de00d0;">"%X\n\r"</span>, one_byte); <span style="color: #7e7e7e;">// Print the value of 'one_byte' in hex format and start new line</span>
<span style="color: #7e7e7e;">// Read 1 sector</span>
printf(<span style="color: #de00d0;">"Read sector 0:"</span>); <span style="color: #7e7e7e;">// Sector 0 from address 0 to 511 (512 bytes)</span>
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
delay_ms(2000);
<span style="color: blue;">for</span>( i = 0; i < 16; i++){
<span style="color: blue;">if</span>(sdcard_read_data((<span style="color: blue;">int32</span>)i * <span style="color: blue;">size</span>, <span style="color: blue;">size</span>, _data) == 0){
<span style="color: blue;">for</span>(j = 0; j < 32; j++)
printf(<span style="color: #de00d0;">"%X"</span>, _data[j]); <span style="color: #7e7e7e;">// Print 32 byte of data in hex format</span>
}
}
}
<span style="color: #7e7e7e;">// End</span>
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
printf(<span style="color: #de00d0;">"*** END ***"</span>);
<span style="color: blue;">while</span>(TRUE) ; <span style="color: #7e7e7e;">// Endless loop</span>
}
</pre>
Finally I got the result shown in the following image:<br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSPZ99AxlxysfB6p-joOleNu1N4qO6YjGFjiLXPicgcL2jIP-4xMZuOnM8KWDS-G6tnikCAyKCUMuqDMvOYJ3ay4qKe-Ay73qDNOxVvdSQSmRSixikrBAqUSqXSgoLFPBKzQ3l15C4CJQ/s1600/pic12f1822-sd-card-serial-monitor-output.png" imageanchor="1"><img alt="Read SD card sector using PIC12F1822 serial monitor output" border="0" height="456" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSPZ99AxlxysfB6p-joOleNu1N4qO6YjGFjiLXPicgcL2jIP-4xMZuOnM8KWDS-G6tnikCAyKCUMuqDMvOYJ3ay4qKe-Ay73qDNOxVvdSQSmRSixikrBAqUSqXSgoLFPBKzQ3l15C4CJQ/s640/pic12f1822-sd-card-serial-monitor-output.png" title="Read SD card sector using PIC12F1822 serial monitor output" width="640" /></a></div>
PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-17156005934143090022017-09-08T11:59:00.000+02:002017-09-20T23:12:34.774+02:00PIC12F1822 UART example with CCS C compilerThe tiny microcontroller PIC12F1822 has a built-in hardware UART module which allows us to easily transmit and receive data. This topic shows a simple UART example using CCS PIC C compiler. In this example I'm going to send/receive data to/from the PC over RS232.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC12F1822 microcontroller</li>
<li>MAX232 -- <a href="http://www.ti.com/lit/ds/symlink/max232.pdf" target="_blank">datasheet</a></li>
<li>4 x 10uF polarized capacitor</li>
<li>Female RS232 connector</li>
<li>Breadboard</li>
<li>5V power source</li>
<li>Jumper wires </li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">PIC12F1822 UART example circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE1t981xKVKjIlhqF25fA21aMEfwA2lT6TCzDUxPBoEAxB0_3_gvwA7NLWztzpSE4624rrQ4CBckOlh9aU9RlFJ1dhonHi2Ks-5fIgZzRIHzgzBw8RBbMk_d7Ef-PcScT9c2o-8RlYO_M/s1600/pic12f1822-rs232-uart-example.png" imageanchor="1"><img alt="PIC12F1822 UART example circuit" border="0" height="216" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE1t981xKVKjIlhqF25fA21aMEfwA2lT6TCzDUxPBoEAxB0_3_gvwA7NLWztzpSE4624rrQ4CBckOlh9aU9RlFJ1dhonHi2Ks-5fIgZzRIHzgzBw8RBbMk_d7Ef-PcScT9c2o-8RlYO_M/s640/pic12f1822-rs232-uart-example.png" title="PIC12F1822 UART example circuit" width="640" /></a></div>
To interface the PIC12F1822 MCU with the PC we need MAX232 signal
level converter as shown in the circuit diagram. There are 2 lines
between the PIC12F1822 and the MAX232 and also two lines between the
MAX232 and the female COM connector. One line for data transmit and the
other one for data receive. The PIC12F1822 is configured in the C code (default configuration) so that the UART module RX function is on pin RA1 and TX function is on pin RA0.<br />
The female COM connector is connected
to the PC using RS232 cable, this cable has to be male-female because
the PC RS232 port type is male.<br />
In this example the PIC12F1822 MCU runs with its internal oscillator and MCLR pin function is disabled. <br />
<span style="color: #cc0000;"><span style="font-size: large;">UART Example for PIC16F84A microcontroller C code:</span></span><br />
The function <span style="background-color: yellow;">#use rs232(UART1, baud = 9600)</span> is used to configure the UART protocol. Here the hardware UART module is used.<br />
where:<br />
9600 is the baud rate.<br />
The functions used in the C code are:<br />
<span style="background-color: yellow;">printf:</span> sends a string of characters over RS232 transmission pin (TX).<br />
<span style="background-color: yellow;"><span class="hcp3">putc</span>:</span> send a character over RS232 transmission pin (TX).<br />
<span style="background-color: yellow;">if(kbhit()):</span> test if a character is ready for <span style="background-color: yellow;">getc()</span> function.<br />
<span style="background-color: yellow;">getc():</span> read the character.<br />
Complete C code for CCS C compiler is below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">/* PIC12F1822 UART example with CCS C compiler.</span>
<span style="color: #7e7e7e;"> http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;"> electronnote@gmail.com</span>
<span style="color: #7e7e7e;">*/</span>
<span style="color: red;">#include</span> <12F1822.h>
<span style="color: red;">#fuses</span> NOMCLR INTRC_IO PLL_SW
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock=32000000)
<span style="color: red;">#use</span> rs232(UART1, baud = 9600)
<span style="color: blue;">const</span> <span style="color: blue;">char</span> message[] = <span style="color: #de00d0;">"PIC12F1822 microcontroller UART example"</span> ;
<span style="color: blue;">int8</span> i = 0, j;
<span style="color: blue;">void</span> main() {
setup_oscillator(OSC_8MHZ | OSC_PLL_ON); <span style="color: #7e7e7e;">// Set internal oscillator to 8MHz with PLL enabled (32MHz)</span>
delay_ms(2000); <span style="color: #7e7e7e;">// Wait 2 seconds</span>
<span style="color: #7e7e7e;">// Print text</span>
printf(<span style="color: #de00d0;">"\r"</span>); <span style="color: #7e7e7e;">// Set cursor to first position</span>
printf(<span style="color: #de00d0;">"Hello world!"</span>);
<span style="color: #7e7e7e;">// Print list of characters</span>
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
<span style="color: blue;">while</span>(message[i] != <span style="color: #de00d0;">'\0'</span>){
putc(message[i]); <span style="color: #7e7e7e;">// Write character</span>
delay_ms(100); <span style="color: #7e7e7e;">// Wait 100 ms</span>
i++; <span style="color: #7e7e7e;">// Increment i</span>
}
<span style="color: #7e7e7e;">// Print numbers</span>
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
<span style="color: blue;">for</span>(i = 0; i < 21; i++){
printf(<span style="color: #de00d0;">"%u\n\r"</span>, i); <span style="color: #7e7e7e;">// Print i and start new line</span>
delay_ms(500);
}
<span style="color: #7e7e7e;">// Receive and send data over UART</span>
<span style="color: blue;">while</span>(TRUE){
<span style="color: blue;">if</span>(kbhit()){ <span style="color: #7e7e7e;">// If a character available</span>
j = getc(); <span style="color: #7e7e7e;">// UART read</span>
putc(j); <span style="color: #7e7e7e;">// Send it back</span>
}
}
}
</pre>
PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-78213501957404408682017-09-08T08:55:00.000+02:002017-09-20T23:12:34.865+02:00Interfacing PIC12F1822 with 1602 LCD and LM35 temperature sensorThis post shows a simple interfacing of PIC16F1822 microcontroller with 16x2 LCD and LM35 analog temperature sensor. <br />
The LM35 temperature sensor is a three pin device (VCC, OUT and GND)
with an output voltage linearly related to Centigrade temperature. Since
the LM35 output varies with dependent to the temperature we need ADC
(Analog-to-Digital Converter) module to measure this voltage.<br />
The LM35 output has linear +10mV/°C scale factor means the following:<br />
If the output voltage = 10mV ---> temperature = 1°C<br />
If the output voltage = 100mV ---> temperature = 10°C<br />
If the output voltage = 200mV ---> temperature = 20°C<br />
If the output voltage = 370mV ---> temperature = 37°C<br />
and so on.<br />
<b>LM35 Futures (from datasheet):</b><br />
<ul>
<li>Calibrated Directly in ° Celsius (Centigrade)</li>
<li>Linear + 10 mV/°C Scale Factor</li>
<li>0.5°C Ensured Accuracy (at +25°C)</li>
<li>Rated for Full −55°C to +150°C Range</li>
<li>Suitable for Remote Applications</li>
<li>Low Cost Due to Wafer-Level Trimming</li>
<li>Operates from 4 to 30 V</li>
<li>Less than 60-μA Current Drain</li>
<li>Low Self-Heating, 0.08°C in Still Air</li>
<li>Nonlinearity Only ±¼°C Typical</li>
<li>Low Impedance Output, 0.1 Ω for 1 mA Load</li>
</ul>
The ADC
module converts analog data into digital data. The PIC12F1822 MCU has a 10-bit ADC module and a built-in fixed voltage reference (FVR) which makes it a good choice for this application. With the fixed voltage reference we get approximately an exact
result. Normally negative and positive references of the ADC module are
VSS and VDD respectively, but VDD is not exactly equal to 5.00V and here we should
use the fixed voltage reference as a positive reference of the ADC
module.<br />
The PIC12F1822 has 3 fixed voltage references: 1.024V,
2.048V and 4.096V. For example if we set the fixed voltage reference to
4.096V and the ADC module is configured so that the negative and the
positive references are VSS and FVR (Fixed Voltage Reference)
respectively, in this case the equivalent 10-bit digital value of 4.096
is 1023 and 3.00V is 3.00 * 1023/4.096 = 749 , and so on.<br />
In this project I used FVR = 1.024V because the LM35 output is generally less than 1V and also it gave me better result (let's say higher resolution). Now the ADC module works in the interval between 0 and 1.024V.<br />
The temperature value is displayed on 1602 LCD display. This
LCD is interfaced with the microcontroller using 74HC595 (74HC164 .....) shift register
as what was done in this post:<br />
<a href="http://ccspicc.blogspot.com/2016/09/pic12f1822-lcd-scroll-one-line.html" target="_blank">Interfacing PIC12F1822 microcontroller with LCD display</a> <br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC12F1822 microcontroller</li>
<li>LM35 temperature sensor -- <a href="http://www.ti.com/lit/ds/symlink/lm35.pdf" target="_blank">datasheet</a></li>
<li>1602 LCD screen</li>
<li>74HC595 shift register </li>
<li>10K ohm variable resistor</li>
<li>Breadboard</li>
<li>5V voltage source</li>
<li>Jumper wires</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">Interfacing PIC12F1822 with LM35 sensor circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhis67ksrCOnZXW3SjZvc8O0QoYe_DkpBMAxPvOFGDeUOwi7h99K237Mk_TPnu0NACR5dSwhmq5mp3Zd9fNQnAAA83Pde_jVNPDyQ8PtiAY_CTtgNla0DSwBtVe6SJ8GtqaTxldFgXBe9E/s1600/interfacing-pic12f1822-lm35-temperature-sensor.png" imageanchor="1"><img alt="Interfacing PIC12F1822 microcontroller with LM35 sensor circuit" border="0" height="342" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhis67ksrCOnZXW3SjZvc8O0QoYe_DkpBMAxPvOFGDeUOwi7h99K237Mk_TPnu0NACR5dSwhmq5mp3Zd9fNQnAAA83Pde_jVNPDyQ8PtiAY_CTtgNla0DSwBtVe6SJ8GtqaTxldFgXBe9E/s640/interfacing-pic12f1822-lm35-temperature-sensor.png" title="Interfacing PIC12F1822 microcontroller with LM35 sensor circuit" width="640" /></a></div>
The output of the LM35 temperature sensor is connected to analog channel 0 (RA0) of the PIC12F1822 microcontroller.<br />
The 1602 LCD display pins are connected to 74HC595 shift register except
the Enable pin (E) which is connected directly to the PIC12F1822 MCU. With the
help of the shift register 74HC595, the LCD uses only 3 data lines:
clock, data and enable. Other types of serial-in parallel-out shift
registers can be used such as 74HC164 and CD4094 (74HC4094).<br />
In this example the PIC12F1822 MCU uses its internal oscillator and MCLR pin function is disabled.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Interfacing PIC12F1822 with LM35 temperature sensor C code:</span></span><br />
The C code below was tested with CCS PIC C compiler version 5.051.<br />
Reading voltage quantity using the ADC gives us a number between 0
and 1023 (10-bit resolution), 0V is represented by 0 and 1.024V is
represented by 1023 (ADC positive reference comes from FVR which is set to 1.024V) . Converting back the ADC digital value is easy, we can use the following equation for that conversion:<br />
Voltage (in Volts) = ADC reading * 1.024 / 1024<br />
Multiplying the previous result by 100 (LM35 scale factor is 10mV/°C = 0.01V/°C) will gives the actual temperature:<br />
Temperature(°C) = ADC reading * 0.1<br />
where 0.1 = 100 * 1.024 / 1024<br />
The complete C code is the one below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">/* Interfacing PIC12F1822 with LM35 temperature sensor C code.</span>
<span style="color: #7e7e7e;"> The temperature result is displayed on 1602 LCD screen with</span>
<span style="color: #7e7e7e;"> the help of a shift register (74HC595, 74HC164 ....).</span>
<span style="color: #7e7e7e;"> Serial LCD driver for CCS C must be added to the project.</span>
<span style="color: #7e7e7e;"> http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;"> electronnote@gmail.com</span>
<span style="color: #7e7e7e;">*/</span>
<span style="color: #7e7e7e;">// Serial LCD module connections</span>
<span style="color: red;">#define</span> LCD_DATA_PIN PIN_A5
<span style="color: red;">#define</span> LCD_CLOCK_PIN PIN_A4
<span style="color: red;">#define</span> LCD_EN_PIN PIN_A2
<span style="color: #7e7e7e;">// End serial LCD module connections</span>
<span style="color: red;">#include</span> <12F1822.h>
<span style="color: red;">#device</span> ADC = 10
<span style="color: red;">#fuses</span> NOMCLR INTRC_IO PLL_SW
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock=32000000)
<span style="color: red;">#use</span> fast_io(A)
<span style="color: red;">#include</span> <3WireLCD.c> <span style="color: #7e7e7e;">// 3-wire serial LCD driver source file</span>
<span style="color: blue;">float</span> temp;
<span style="color: blue;">void</span> main() {
setup_oscillator(OSC_8MHZ | OSC_PLL_ON); <span style="color: #7e7e7e;">// Set internal oscillator to 8MHz with PLL enabled (32MHz)</span>
lcd_initialize(); <span style="color: #7e7e7e;">// Initialize LCD module</span>
lcd_cmd(LCD_CLEAR); <span style="color: #7e7e7e;">// LCD Clear</span>
setup_vref(VREF_ADC_1v024); <span style="color: #7e7e7e;">// Configure FVR to supply ADC positive reference with 1.024V</span>
setup_adc(ADC_CLOCK_INTERNAL); <span style="color: #7e7e7e;">// ADC Module uses its internal oscillator</span>
setup_adc_ports(sAN0 | VSS_FVR); <span style="color: #7e7e7e;">// Configure AN0 pin as analog - Voltage reference: VSS - FVR(1.024V)</span>
set_adc_channel(0); <span style="color: #7e7e7e;">// Select channel 0 (AN0)</span>
lcd_goto(3, 1); <span style="color: #7e7e7e;">// Go to column 3 row 1</span>
printf(lcd_out, <span style="color: #de00d0;">"Temperature:"</span>);
<span style="color: blue;">while</span>(TRUE){
delay_ms(1000);
temp = read_adc() * 0.1; <span style="color: #7e7e7e;">// Read analog voltage and convert it to Kelvin (0.1 = 100*1.024/1024)</span>
lcd_goto(6, 2); <span style="color: #7e7e7e;">// Go to column 6 row 2</span>
printf(lcd_out, <span style="color: #de00d0;">"%4.1fßC"</span>, temp); <span style="color: #7e7e7e;">// Display LM35 temperature result (float format)</span>
}
}
</pre>
<span style="color: #cc0000;"><span style="font-size: large;">The Result:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8GKsIUBXkx5W2nkdbYMzj_XolXEX0woiazWNvAwWLPPZJJxd8OnWMWaPwun8tTDncG4DADVNYQGIXIKyzXq-g9bpP9XLOXbCBAe78zRgXOTn_XfbsCJ0sZEIanw4jFrjO0l2yx4v3WFo/s1600/Interfacing-pic12f1822-mcu-lm35-temperature-sensor-hardware-circuit.JPG" imageanchor="1"><img alt="PIC12F1822 with LM35 temperature sensor hardware circuit" border="0" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8GKsIUBXkx5W2nkdbYMzj_XolXEX0woiazWNvAwWLPPZJJxd8OnWMWaPwun8tTDncG4DADVNYQGIXIKyzXq-g9bpP9XLOXbCBAe78zRgXOTn_XfbsCJ0sZEIanw4jFrjO0l2yx4v3WFo/s400/Interfacing-pic12f1822-mcu-lm35-temperature-sensor-hardware-circuit.JPG" title="PIC12F1822 with LM35 temperature sensor hardware circuit" width="400" /></a></div>
<div style="text-align: center;">
<br /></div>
PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-60883737156191740572017-09-07T18:45:00.000+02:002017-09-20T23:12:34.832+02:00PIC12F1822 + 1602 LCD + LM335 Temperature Sensorthe LM335 is a 3-pin analog device which can measure temperature
(converts temperature to analog voltage). This sensor requires an ADC to
convert the analog data into digital data.<br />
This topic shows how to build a thermometer using PIC12F1822 microcontroller and LM335 analog temperature sensor.<br />
The LM335 sensor has the following features (from LM335 datasheet):<br />
<ul>
<li>Directly Calibrated to the Kelvin Temperature Scale</li>
<li>1°C Initial Accuracy Available</li>
<li>Operates from 400 μA to 5 mA</li>
<li>Less than 1-Ω Dynamic Impedance</li>
<li>Easily Calibrated</li>
<li>Wide Operating Temperature Range</li>
<li>200°C Overrange</li>
<li>Low Cost</li>
</ul>
The LM135 has a breakdown voltage directly proportional to
absolute temperature at 10 mV/°K. For example if the LM335 output voltage is equal to 3.03 (3030 mV) that means the temperature is: 303 Kelvin =
30 °Celsius.<br />
The PIC12F1822 is an 8-bit microcontroller which has 4 analog channels with 10-bit resolution. The good thing with this microcontroller is the fixed voltage reference. With the fixed voltage reference we get approximately an exact result. Normally negative and positive references of the ADC module are VSS and VDD, but VDD is not exactly equal to 5.00V and here we should use the fixed voltage reference as a positive reference of the ADC module.<br />
The PIC12F1822 has 3 fixed voltage references: 1.024V, 2.048V and 4.096V. For example if we set the fixed voltage reference to 4.096V and the ADC module is configured so that the negative and the positive references are VSS and FVR (Fixed Voltage Reference) respectively, in this case the equivalent 10-bit digital value of 4.096 is 1023 and 3.00V is 3.00 * 1023/4.096 = 749 , and so on.<br />
In this project I used 4.096 because the LM335 output is between 2.23V (temperature = -50°C) and 3.98V (temperature = +125°C).<br />
The temperature values (Kelvin and degree Celsius) are displayed on 1602 LCD display. This
LCD is interfaced with the microcontroller using 74HC595 (74HC164 .....) shift register
as what was done in this post:<br />
<a href="http://ccspicc.blogspot.com/2016/09/pic12f1822-lcd-scroll-one-line.html" target="_blank">Interfacing PIC12F1822 microcontroller with LCD display</a> <br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC12F1822 microcontroller</li>
<li>LM335 Temperature sensor - <a href="https://drive.google.com/open?id=0ByrcgOkOu0vgWng0ZmZQOTRCTk0" target="_blank">datasheet</a></li>
<li>1602 LCD Screen</li>
<li>74HC595 shift register </li>
<li>10K ohm variable resistor</li>
<li>2.2K ohm resistor</li>
<li>+5V Power supply source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">Interfacing PIC12F1822 with LM335 temperature sensor circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwgzTrM0E62Zhg27hS7pAefdiP8YfSclEapjitzDzdNaBFLtPwnvGzvnUfDFCb6gNOE2wncnYU7ElJ6H2MSMif70U29aldqDXSLEer5xK_Ra9pf5XLfr97bovmUBZjJX5sJ7GS2c31rK0/s1600/Digital+thermometer+using+PIC12F1822+and+LM335.png" imageanchor="1"><img alt="Interfacing PIC12F1822 MCU with LM335 temperature sensor and 1602 LCD circuit" border="0" height="342" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwgzTrM0E62Zhg27hS7pAefdiP8YfSclEapjitzDzdNaBFLtPwnvGzvnUfDFCb6gNOE2wncnYU7ElJ6H2MSMif70U29aldqDXSLEer5xK_Ra9pf5XLfr97bovmUBZjJX5sJ7GS2c31rK0/s640/Digital+thermometer+using+PIC12F1822+and+LM335.png" title="Interfacing PIC12F1822 MCU with LM335 temperature sensor and 1602 LCD circuit" width="640" /></a></div>
The LM335 sensor has 3 pins (from left to right):<br />
Pin 1 for calibration, not used in this example<br />
Pin 2: output<br />
Pin 3: GND (ground).<br />
The
output pin of the LM335 sensor is connected to analog channel 0 (RA0). I
chose the 2.2K ohm because as written in the datasheet for optimum
accuracy the current flows through the LM335 should be 1mA. For example
if the temperature = 27°C, the output will be 3.00V and assume the
supply voltage is exactly 5.00V that means the current flows through the
sensor is ( 5 - 3)/2.2 = 0.90mA which is good enough. Also the value
2.2K is a standard value and well used.<br />
The 1602 LCD display pins are connected to 74HC595 shift register except
the Enable pin (E) which is connected directly to PIC12F1822. With the
help of the shift register 74HC595 the LCD uses only 3 data lines:
clock, data and enable. Other types of serial-in parallel-out shift
registers can be used such as 74HC164 and CD4094 (74HC4094).<br />
In this example the PIC12F1822 MCU uses its internal oscillator and MCLR pin function is disabled.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Interfacing PIC12F1822 with LM335 temperature sensor C code:</span></span><br />
This code was tested with CCS PIC C compiler version 5.051.<br />
To compile the C code below, the serial LCD driver source file must be added to the project just by downloading the source file and putting it on the project folder. The download link of the serial LCD driver is in this post:<br />
<a href="http://ccspicc.blogspot.com/2016/08/3-wire-lcd-driver-ccs-pic-c-74hc595-hef4094.html" target="_blank">3-Wire LCD driver for CCS PIC C compiler</a><br />
The complete C code is the one below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">/* Thermometer using PIC12F1822 microcontroller and LM335 sensor C code.</span>
<span style="color: #7e7e7e;"> The temperature results (kelvin and degree Celsius) are displayed on</span>
<span style="color: #7e7e7e;"> 1602 LCD screen with the help of a shift register (74HC595, 74HC164 ....).</span>
<span style="color: #7e7e7e;"> Serial LCD driver for CCS C must be added to the project.</span>
<span style="color: #7e7e7e;"> http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;"> electronnote@gmail.com</span>
<span style="color: #7e7e7e;">*/</span>
<span style="color: #7e7e7e;">// Serial LCD module connections</span>
<span style="color: red;">#define</span> LCD_DATA_PIN PIN_A5
<span style="color: red;">#define</span> LCD_CLOCK_PIN PIN_A4
<span style="color: red;">#define</span> LCD_EN_PIN PIN_A2
<span style="color: #7e7e7e;">// End serial LCD module connections</span>
<span style="color: red;">#include</span> <12F1822.h>
<span style="color: red;">#device</span> ADC = 10
<span style="color: red;">#fuses</span> NOMCLR INTRC_IO PLL_SW
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock=32000000)
<span style="color: red;">#use</span> fast_io(A)
<span style="color: red;">#include</span> <3WireLCD.c> <span style="color: #7e7e7e;">// 3-wire serial LCD driver source file</span>
<span style="color: blue;">char</span> celsius_temp[] = <span style="color: #de00d0;">"Temp = 00.0ßC"</span>;
<span style="color: blue;">char</span> kelvin_temp[] = <span style="color: #de00d0;">"= 00.0 K"</span>;
<span style="color: blue;">signed</span> <span style="color: blue;">int16</span> Kelvin, Celsius;
<span style="color: blue;">void</span> main() {
setup_oscillator(OSC_8MHZ | OSC_PLL_ON); <span style="color: #7e7e7e;">// Set internal oscillator to 8MHz with PLL enabled (32MHz)</span>
lcd_initialize(); <span style="color: #7e7e7e;">// Initialize LCD module</span>
lcd_cmd(LCD_CLEAR); <span style="color: #7e7e7e;">// LCD Clear</span>
setup_vref(VREF_ADC_4v096); <span style="color: #7e7e7e;">// Configure FVR to supply ADC positive reference with 4.096V</span>
setup_adc(ADC_CLOCK_INTERNAL); <span style="color: #7e7e7e;">// ADC Module uses its internal oscillator</span>
setup_adc_ports(sAN0 | VSS_FVR); <span style="color: #7e7e7e;">// Configure AN0 pin as analog - Voltage reference: VSS - FVR(4.096V)</span>
set_adc_channel(0); <span style="color: #7e7e7e;">// Select channel 0 (AN0)</span>
<span style="color: blue;">while</span>(TRUE){
delay_ms(1000);
Kelvin = (read_adc() + 1) * 0.4; <span style="color: #7e7e7e;">// Read analog voltage and convert it to Kelvin (0.4 = 100*4.096/1024)</span>
Celsius = Kelvin - 273; <span style="color: #7e7e7e;">// Convert Kelvin to degree Celsius</span>
<span style="color: blue;">if</span>(Celsius < 0){
Celsius = <span style="color: blue;">abs</span>(Celsius); <span style="color: #7e7e7e;">// Absolute value</span>
celsius_temp[7] = <span style="color: #de00d0;">'-'</span>; <span style="color: #7e7e7e;">// Put minus '-' sign</span>
}
<span style="color: blue;">else</span>
celsius_temp[7] = <span style="color: #de00d0;">' '</span>; <span style="color: #7e7e7e;">// Put space ' '</span>
<span style="color: blue;">if</span> (Celsius > 99)
celsius_temp[7] = <span style="color: #de00d0;">'1'</span>; <span style="color: #7e7e7e;">// Put 1 (of hundred)</span>
celsius_temp[8] = (Celsius / 10) % 10 + 48;
celsius_temp[9] = Celsius % 10 + 48;
kelvin_temp[2] = (Kelvin / 100) % 10 + 48;
kelvin_temp[3] = (Kelvin / 10) % 10 + 48;
kelvin_temp[4] = Kelvin % 10 + 48;
lcd_goto(1, 1); <span style="color: #7e7e7e;">// Go to column 1 row 1</span>
printf(lcd_out, celsius_temp); <span style="color: #7e7e7e;">// Display Celsius_temp</span>
lcd_goto(6, 2); <span style="color: #7e7e7e;">// Go to column 6 row 2</span>
printf(lcd_out, kelvin_temp); <span style="color: #7e7e7e;">// Display kelvin_temp</span>
}
}
</pre>
<span style="color: #cc0000;"><span style="font-size: large;">The Result:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9OHO64NMA52tgrlmMP8gErXogJijYhWe4FD3G5hs-Tz3vJ5sXoNY9n_Azvb3deghksMhzjQylrBFM7X2kU5xBusiZ7zLTcyLyWd7a-oUG3ocUZr5qh2Un1Jqe5CJa44d93bzFjHI2zpY/s1600/PIC12F1822+with+LM335+temperature+sensor+hardware+circuit.JPG" imageanchor="1"><img alt="A hardware circuit of PIC12F1822 MCU, LCD and LM335 temperature sensor" border="0" height="425" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9OHO64NMA52tgrlmMP8gErXogJijYhWe4FD3G5hs-Tz3vJ5sXoNY9n_Azvb3deghksMhzjQylrBFM7X2kU5xBusiZ7zLTcyLyWd7a-oUG3ocUZr5qh2Un1Jqe5CJa44d93bzFjHI2zpY/s640/PIC12F1822+with+LM335+temperature+sensor+hardware+circuit.JPG" title="A hardware circuit of PIC12F1822 MCU, LCD and LM335 temperature sensor" width="640" /></a></div>
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-79869873152970670322017-09-06T23:23:00.000+02:002017-09-20T23:14:19.448+02:00Interfacing PIC16F84 with DS3231 RTCThis post shows how to make a real time clock and calendar using PIC16F84 and DS3231 RTC.<br />
The
DS3231 uses I2C protocol to interface with the master device which is in this example the PIC16F84A MCU. In this project software I2C is used because the PIC16F84A MCU has no hardware I2C module.<br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBcMcWoSJPJ7jpqVNG_llEQA3jRA96_I2sqFuXA33pTN8D9BTIhSCQVcNOw6OiMszKLLZ0bGOpRnEajymM3KupAps0y3NTMbkNftuQX-uez64K9kZ7a1SMtoOmRypx4sPYebsMRn6v96E/s1600/PIC16F84A+with+DS3231+RTC+hardware+circuit.jpg" imageanchor="1"><img alt="A hardware circuit for DS3231 RTC and PIC16F84A" border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBcMcWoSJPJ7jpqVNG_llEQA3jRA96_I2sqFuXA33pTN8D9BTIhSCQVcNOw6OiMszKLLZ0bGOpRnEajymM3KupAps0y3NTMbkNftuQX-uez64K9kZ7a1SMtoOmRypx4sPYebsMRn6v96E/s640/PIC16F84A+with+DS3231+RTC+hardware+circuit.jpg" title="A hardware circuit for DS3231 RTC and PIC16F84A" width="640" /></a></div>
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC16F84A microcontroller</li>
<li>1602 LCD screen</li>
<li>8MHz crystal oscillator</li>
<li>2 x 22pF ceramic capacitor</li>
<li>10K ohm variable resistor</li>
<li>3 x 10K ohm resistor</li>
<li>2 x push button</li>
<li>5V supply source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
DS3231 board contains the following components:<br />
<ul>
<li>DS3231 RTC - <a href="https://datasheets.maximintegrated.com/en/ds/DS3231.pdf" target="_blank"><i>datasheet</i></a></li>
<li>2 x 4.7K ohm resistors</li>
<li>0.1uF ceramic capacitor</li>
<li>3V coin cell battery</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">Interfacing PIC16F84 with DS3231 RTC circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhn_SCkZ0DEBxeqr21lIcTEB01D1M7jBIJkYlnXcdDAIHqVmIzbeqlNT-UrdRgTj01buyvwhpyFdcVmmV3SgFyDqKWGpBEY5_1aRJllMQw37vqqjOdsHU6ZMI3NGBVkj99wVpHwjG197jY/s1600/interfacing+pic16f84a+with+ds3231+real+time+clock+with+setup+buttons.png" imageanchor="1"><img alt="Interfacing PIC16F84A with DS3231 real time clock-calendar circuit" border="0" height="442" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhn_SCkZ0DEBxeqr21lIcTEB01D1M7jBIJkYlnXcdDAIHqVmIzbeqlNT-UrdRgTj01buyvwhpyFdcVmmV3SgFyDqKWGpBEY5_1aRJllMQw37vqqjOdsHU6ZMI3NGBVkj99wVpHwjG197jY/s640/interfacing+pic16f84a+with+ds3231+real+time+clock+with+setup+buttons.png" title="Interfacing PIC16F84A with DS3231 real time clock-calendar circuit" width="640" /></a></div>
In the circuit there are 2 push
buttons (B1 & B2) connected to pin RA2 and pin RA3, the two push
buttons are used to set the time as well as the calendar parameters (minutes, hours, date, month and year). Button B1 selects the parameter and B2 increments the selected parameter.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Interfacing PIC16F84 with DS3231 RTC C code:</span></span><br />
The C code below was tested with CCS PIC C compiler version 5.051.<br />
I used the function below to initialize the software I2C where pin RA0 and pin RA1 are used for SDA and SCL lines respectively (PIC16F84A is used as master device):<br />
<span style="background-color: yellow;"><span style="color: red;">#use</span> I2C(MASTER, SDA=PIN_A0, SCL=PIN_A1, FAST=100000)</span><br />
The DS3231 works with BCD format only and to convert the BCD to
decimal and vise versa I used the 2 functions below. Before displaying (after reading from DS3231), the data have to be converted from BCD to decimal, and before writing to the DS3231 (after editing the parameters) the data have to be converted from decimal to BCD:<br />
<span style="background-color: yellow;"><span style="color: blue;">int8</span> bcd_to_decimal(number)</span><br />
<span style="background-color: yellow;"><span style="color: blue;">int8</span> decimal_to_bcd(number) </span><br />
Each function returns the converted value of the variable <span style="background-color: yellow;">number</span>.<br />
<span style="background-color: yellow;"><span style="color: blue;">void</span> DS3231_display() :</span>
displays time and calendar data, before displaying time and calendar
data are converted from BCD format to decimal format using the function <span style="background-color: yellow;">bcd_to_decimal(number)</span> .<br />
<span style="background-color: yellow;"><span style="color: blue;">int8</span> edit(x, y, parameter) :</span> I used this function to edit time calendar parameters (minutes, hours, date, month and year). I used a variable named<span style="background-color: yellow;"> i </span>to distinguish between the parameters:<br />
i = 0, 1 : time hours and minutes respectively<br />
i = 2, 3, 4: calendar date, month and year respectively<br />
After the edit of time and calendar, the data have to be converted back to BCD format using the function <span style="background-color: yellow;">decimal_to_bcd(number)</span> and written to the DS3231.<br />
<span style="background-color: yellow;"><span style="color: blue;">void</span> blink() :</span>
this small function works as a delay except that it is interrupted by
the buttons B1 (connected to RA2) and B2 (connected to RA3). When called
and without pressing any button the total time is 10 x 25ms = 250ms.
With this function we can see the blinking of the selected parameter
with a frequency of 2Hz. So a delay of 250ms comes after the print of
the selected parameter and after that delay a 2 spaces is printed which
makes the parameter disappears from the LCD and another 250ms delay
comes after the print of the 2 spaces.<br />
The complete C code is the one below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">// Real time clock - calendar with DS3231 and PIC16F84A CCS C code.</span>
<span style="color: #7e7e7e;">// http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;">// electronnote@gmail.com</span>
<span style="color: #7e7e7e;">//LCD module connections</span>
<span style="color: red;">#define</span> LCD_RS_PIN PIN_B0
<span style="color: red;">#define</span> LCD_RW_PIN PIN_B1
<span style="color: red;">#define</span> LCD_ENABLE_PIN PIN_B2
<span style="color: red;">#define</span> LCD_DATA4 PIN_B3
<span style="color: red;">#define</span> LCD_DATA5 PIN_B4
<span style="color: red;">#define</span> LCD_DATA6 PIN_B5
<span style="color: red;">#define</span> LCD_DATA7 PIN_B6
<span style="color: #7e7e7e;">//End LCD module connections</span>
<span style="color: red;">#include</span> <16F84A.h>
<span style="color: red;">#fuses</span> HS,NOWDT,PUT,NOPROTECT
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 8000000)
<span style="color: red;">#use</span> fast_io(A)
<span style="color: red;">#use</span> fast_io(B)
<span style="color: red;">#include</span> <lcd.c>
<span style="color: red;">#use</span> I2C(MASTER, SDA=PIN_A0, SCL=PIN_A1, FAST=100000)
<span style="color: blue;">int8</span> i, second, minute, hour, date, month, year;
<span style="color: blue;">int8</span> bcd_to_decimal(number){ <span style="color: #7e7e7e;">// Convert BCD to decimal function</span>
<span style="color: blue;">return</span>((number >> 4) * 10 + (number & 0x0F));
}
<span style="color: blue;">int8</span> decimal_to_bcd(number){ <span style="color: #7e7e7e;">// Convert decimal to BCD function</span>
<span style="color: blue;">return</span>(((number / 10) << 4) + (number % 10));
}
<span style="color: blue;">void</span> ds3231_display(){
second = bcd_to_decimal(second);
minute = bcd_to_decimal(minute);
hour = bcd_to_decimal(hour);
date = bcd_to_decimal(date);
month = bcd_to_decimal(month);
year = bcd_to_decimal(year);
lcd_gotoxy(13, 1);
printf(lcd_putc,<span style="color: #de00d0;">"%02u"</span>, second); <span style="color: #7e7e7e;">// Display seconds</span>
lcd_gotoxy(10, 1);
printf(lcd_putc,<span style="color: #de00d0;">"%02u"</span>, minute); <span style="color: #7e7e7e;">// Display minutes</span>
lcd_gotoxy(7, 1);
printf(lcd_putc,<span style="color: #de00d0;">"%02u"</span>, hour); <span style="color: #7e7e7e;">// Display hours</span>
lcd_gotoxy(7, 2);
printf(lcd_putc,<span style="color: #de00d0;">"%02u"</span>, date); <span style="color: #7e7e7e;">// Display date</span>
lcd_gotoxy(10, 2);
printf(lcd_putc,<span style="color: #de00d0;">"%02u"</span>, month); <span style="color: #7e7e7e;">// Display month</span>
lcd_gotoxy(15, 2);
printf(lcd_putc,<span style="color: #de00d0;">"%02u"</span>, year); <span style="color: #7e7e7e;">// Display year</span>
}
<span style="color: blue;">void</span> <span style="color: blue;">blink</span>(){
<span style="color: blue;">int8</span> j = 0;
<span style="color: blue;">while</span>(j < 10 && input(PIN_A2) && input(PIN_A3)){
j++;
delay_ms(25);
}
}
<span style="color: blue;">unsigned</span> <span style="color: blue;">int8</span> edit(x, y, parameter){
<span style="color: blue;">while</span>(!input(PIN_A2)); <span style="color: #7e7e7e;">// Wait until button RB0 is released</span>
<span style="color: blue;">while</span>(TRUE){
<span style="color: blue;">while</span>(!input(PIN_A3)){ <span style="color: #7e7e7e;">// If button RB1 is pressed</span>
parameter++;
<span style="color: blue;">if</span>(i == 0 && parameter > 23) <span style="color: #7e7e7e;">// If hours > 23 ==> hours = 0</span>
parameter = 0;
<span style="color: blue;">if</span>(i == 1 && parameter > 59) <span style="color: #7e7e7e;">// If minutes > 59 ==> minutes = 0</span>
parameter = 0;
<span style="color: blue;">if</span>(i == 2 && parameter > 31) <span style="color: #7e7e7e;">// If date > 31 ==> date = 1</span>
parameter = 1;
<span style="color: blue;">if</span>(i == 3 && parameter > 12) <span style="color: #7e7e7e;">// If month > 12 ==> month = 1</span>
parameter = 1;
<span style="color: blue;">if</span>(i == 4 && parameter > 99) <span style="color: #7e7e7e;">// If year > 99 ==> year = 0</span>
parameter = 0;
lcd_gotoxy(x, y);
printf(lcd_putc,<span style="color: #de00d0;">"%02u"</span>, parameter); <span style="color: #7e7e7e;">// Display parameter</span>
delay_ms(200); <span style="color: #7e7e7e;">// Wait 200ms</span>
}
lcd_gotoxy(x, y);
lcd_putc(<span style="color: #de00d0;">" "</span>); <span style="color: #7e7e7e;">// Display two spaces</span>
<span style="color: blue;">blink</span>();
lcd_gotoxy(x, y);
printf(lcd_putc,<span style="color: #de00d0;">"%02u"</span>, parameter); <span style="color: #7e7e7e;">// Display parameter</span>
<span style="color: blue;">blink</span>();
<span style="color: blue;">if</span>(!input(PIN_A2)){ <span style="color: #7e7e7e;">// If button RA2 is pressed</span>
i++; <span style="color: #7e7e7e;">// Increament 'i' for the next parameter</span>
<span style="color: blue;">return</span> parameter; <span style="color: #7e7e7e;">// Return parameter value and exit</span>
}
}
}
<span style="color: blue;">void</span> main(){
lcd_init(); <span style="color: #7e7e7e;">// Initialize LCD module</span>
lcd_putc(<span style="color: #de00d0;">'\f'</span>); <span style="color: #7e7e7e;">// LCD clear</span>
lcd_gotoxy(1, 1); lcd_putc(<span style="color: #de00d0;">"TIME: : :"</span>);
lcd_gotoxy(1, 2); lcd_putc(<span style="color: #de00d0;">"DATE: / /20"</span>);
<span style="color: blue;">while</span>(TRUE){
<span style="color: blue;">if</span>(!input(PIN_A2)){ <span style="color: #7e7e7e;">// If RB0 button is pressed</span>
i = 0;
hour = edit(7, 1, hour);
minute = edit(10, 1, minute);
date = edit(7, 2, date);
month = edit(10, 2, month);
year = edit(15, 2, year);
<span style="color: #7e7e7e;">// Convert decimal to BCD</span>
minute = decimal_to_bcd(minute);
hour = decimal_to_bcd(hour);
date = decimal_to_bcd(date);
month = decimal_to_bcd(month);
year = decimal_to_bcd(year);
<span style="color: #7e7e7e;">// End conversion</span>
<span style="color: #7e7e7e;">// Write data to DS3231 RTC</span>
i2c_start(); <span style="color: #7e7e7e;">// Start I2C protocol</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(0); <span style="color: #7e7e7e;">// Send register address</span>
i2c_write(0); <span style="color: #7e7e7e;">// Reset sesonds and start oscillator</span>
i2c_write(minute); <span style="color: #7e7e7e;">// Write minute value to DS3231</span>
i2c_write(hour); <span style="color: #7e7e7e;">// Write hour value to DS3231</span>
i2c_write(1); <span style="color: #7e7e7e;">// Write day value (not used)</span>
i2c_write(date); <span style="color: #7e7e7e;">// Write date value to DS3231</span>
i2c_write(month); <span style="color: #7e7e7e;">// Write month value to DS3231</span>
i2c_write(year); <span style="color: #7e7e7e;">// Write year value to DS3231</span>
delay_ms(200); <span style="color: #7e7e7e;">// Wait 200ms</span>
}
i2c_start(); <span style="color: #7e7e7e;">// Start I2C protocol</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(0); <span style="color: #7e7e7e;">// Send register address</span>
i2c_start(); <span style="color: #7e7e7e;">// Restart I2C</span>
i2c_write(0xD1); <span style="color: #7e7e7e;">// Initialize data read</span>
second = i2c_read(1); <span style="color: #7e7e7e;">// Read seconds from register 0</span>
minute = i2c_read(1); <span style="color: #7e7e7e;">// Read minuts from register 1</span>
hour = i2c_read(1); <span style="color: #7e7e7e;">// Read hour from register 2</span>
i2c_read(1); <span style="color: #7e7e7e;">// Read day from register 3 (not used)</span>
date = i2c_read(1); <span style="color: #7e7e7e;">// Read date from register 4</span>
month = i2c_read(1); <span style="color: #7e7e7e;">// Read month from register 5</span>
year = i2c_read(0); <span style="color: #7e7e7e;">// Read year from register 6</span>
i2c_stop(); <span style="color: #7e7e7e;">// Stop I2C protocol</span>
DS3231_display(); <span style="color: #7e7e7e;">// Diaplay time & calendar</span>
delay_ms(50);
}
}
</pre>
<span style="color: #cc0000;"><span style="font-size: large;">Simulation video:</span></span><br />
The video below shows the project simulation using Proteus.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/N_G6bNJQhh4/0.jpg" src="https://www.youtube.com/embed/N_G6bNJQhh4?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-85759401091406153992017-09-06T12:24:00.000+02:002017-09-20T23:14:19.456+02:00Interfacing PIC16F84A with SD cardThis topic shows a simple interfacing of 2 GB micro SD card with PIC16F84A microcontroller.<br />
I used the PIC16F84A to read the SD card raw data which doesn't require a microcontroller with high RAM or ROM. In this interfacing I used software SPI because the PIC16F84A doesn't have a built-in hardware SPI module.<br />
In this example there is no need for file systems (FAT16, FAT32 ...) because we're dealing with raw data which stored in the SD card memory spaces.<br />
CCS IDE serial monitor is used to display the data after reading it and here the UART protocol is used. I used software UART because the PIC16F84A also does not have a UART module.<br />
the link below shows a small PIC16F84A MCU UART example:<br />
<a href="http://ccspicc.blogspot.com/2017/09/software-uart-rs232-pic16f84a.html" target="_blank">Software UART for PIC16F84A microcontroller</a><br />
In this project I used the MMC/SD card driver for CCS C compiler which is described in the post at the link below:<br />
<a href="http://ccspicc.blogspot.com/2017/08/mmc-sd-card-driver-for-ccs-compiler.html" target="_blank">MMC/SD Card driver for CCS PIC C compiler</a><br />
The PIC16F84A MCU has only 68 bytes of data RAM which
means that it is not possible to load an entire sector of
512 bytes, but we can read many sectors byte by byte.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC16F84A microcontroller</li>
<li>8 MHz crystal</li>
<li>2 x 22pF ceramic capacitors </li>
<li>SD Card</li>
<li>AMS1117 3.3V voltage regulator</li>
<li>3 x 3.3K ohm resistor</li>
<li>3 x 2.2K ohm resistor</li>
<li>2 x 10K ohm resistor</li>
<li>5 x 10uF polarized capacitor</li>
<li>100nF ceramic capacitor</li>
<li>MAX232 chip</li>
<li>Female RS232 connector</li>
<li>Male-female RS232 cable </li>
<li>5V Power source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">Interfacing SD card with PIC16F84A MCU circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuAignA2_DxJLWUClBkj_jC1PYqB-yjovwbrmzyy43ZcM-5Wg77MfGNtAusNaR5BbDx2TwOA2tDR9rG2kCcu0wzHQFcGH6aDdgf1_HRssC5kSMk8ymVQcoD7BnKJjtd9sCOKdwNsfadrc/s1600/interfacing+mmc+sd+card+with+PIC16F84A.png" imageanchor="1"><img alt="Interfacing PIC16F84A with SD card circuit" border="0" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuAignA2_DxJLWUClBkj_jC1PYqB-yjovwbrmzyy43ZcM-5Wg77MfGNtAusNaR5BbDx2TwOA2tDR9rG2kCcu0wzHQFcGH6aDdgf1_HRssC5kSMk8ymVQcoD7BnKJjtd9sCOKdwNsfadrc/s640/interfacing+mmc+sd+card+with+PIC16F84A.png" title="Interfacing PIC16F84A with SD card circuit" width="640" /></a></div>
The AMS1117 3.3V voltage regulator is used to supply the SD card with
3.3V. Also, 3 voltage dividers are used to step down the 5V which comes
from the microcontroller to about 3V which is sufficient for the SD
card. Each voltage divider consists of 2K2 and 3K3 resistors.<br />
The MISO of the SD card is connected directly to the microcontroller. <br />
MAX232
integrated circuit is used to interface the microcontroller with the
PC, I connected just one wire (RB3) because I need to transmit data from
the SD card to the microcontroller and then from the microcontroller to
the PC, there is no need to connect the second wire because I don't
have to send data from the PC to the microcontroller.<br />
In this project the PIC16F84A MCU runs with 8MHz crystal oscillator.<br />
<span style="color: #cc0000;"><span style="font-size: large;">SD Card raw data read using PIC16F84A CCS C code:</span></span><br />
The C code below was tested with CCS PIC C compiler version 5.051.<br />
Software SPI is used to interface the MCU with the SD card with 4 data lines: SDI, SDO, SCL and CS. <br />
The code below reads the SD card sector 0, sector size is 512 bytes. To be able to read the whole sector I used the function <span style="background-color: yellow;">sdcard_read_byte<span style="background-color: white;"> which allows me to read any byte located in the SD card. For example the function <span style="background-color: yellow;">sdcard_read_byte(200, &value);</span> reads the byte of address <span style="background-color: yellow;">200</span> and saves its data (1 byte) in the variable pointer <span style="background-color: yellow;">value</span>.</span></span><br />
The functions <span style="background-color: yellow;"> sdcard_init</span> and <span style="background-color: yellow;">sdcard_read_byte<span style="background-color: white;"> return 0 if OK, non-zero if error.</span></span><br />
<span style="background-color: yellow;"><span style="background-color: white;">Complete C code is below. </span></span><br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">// Interfacing PIC16F84A with SD card CCS C code.</span>
<span style="color: #7e7e7e;">// http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;">// electronnote@gmail.com</span>
<span style="color: #7e7e7e;">// SD Card module connections</span>
<span style="color: red;">#define</span> SDCARD_PIN_SDI PIN_B7
<span style="color: red;">#define</span> SDCARD_PIN_SCL PIN_B6
<span style="color: red;">#define</span> SDCARD_PIN_SDO PIN_B5
<span style="color: red;">#define</span> SDCARD_PIN_SELECT PIN_B4
<span style="color: #7e7e7e;">// End SD card module connections</span>
<span style="color: red;">#include</span> <16F84A.h>
<span style="color: red;">#fuses</span> HS,NOWDT,PUT,NOPROTECT
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 8000000)
<span style="color: red;">#use</span> fast_io(B)
<span style="color: red;">#use</span> rs232(xmit = PIN_B3, rcv = PIN_B2, baud = 9600)
<span style="color: red;">#include</span> <sdcard.c> <span style="color: #7e7e7e;">// SD Card driver source file</span>
<span style="color: blue;">int8</span> value;
<span style="color: blue;">int16</span> i;
<span style="color: blue;">void</span> main() {
output_drive(PIN_B3); <span style="color: #7e7e7e;">// Configure pin RB3 as output</span>
printf(<span style="color: #de00d0;">"\r"</span>); <span style="color: #7e7e7e;">// Set cursor to first position</span>
printf(<span style="color: #de00d0;">"Read Sector 0:"</span>);
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
<span style="color: blue;">if</span>(sdcard_init() == 0){ <span style="color: #7e7e7e;">// Initialize the SD card; returns 0 if OK, non-zero if error</span>
printf(<span style="color: #de00d0;">"Card init OK"</span>);
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
<span style="color: blue;">for</span>(i=0; i<512;i++){ <span style="color: #7e7e7e;">// Read sector byte-by-byte (total: 512 bytes)</span>
sdcard_read_byte(i, &value);
printf(<span style="color: #de00d0;">"%X"</span>, value); <span style="color: #7e7e7e;">// Print 'value' with hexadecimal format</span>
}
}
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
printf(<span style="color: #de00d0;">"End."</span>);
}
</pre>
Finally I got the output shown below:<br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuOAtCnyxcvSrAwWlfXYv3WDJblIbFwhLUjvxiIn0ftgErhyphenhyphen-rWTUa9leiqviGp6KqFPZuAGI-v4hip7T8YnN6CmdKi4ufOyf5dpg53O4x_-hp8J4umbEnqJUU-qI9SU8UlP8L3MsbNuc/s1600/pic16f84a+sd+card+output.png" imageanchor="1"><img alt="Read SD card sector using PIC16F84A output" border="0" height="454" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuOAtCnyxcvSrAwWlfXYv3WDJblIbFwhLUjvxiIn0ftgErhyphenhyphen-rWTUa9leiqviGp6KqFPZuAGI-v4hip7T8YnN6CmdKi4ufOyf5dpg53O4x_-hp8J4umbEnqJUU-qI9SU8UlP8L3MsbNuc/s640/pic16f84a+sd+card+output.png" title="Read SD card sector using PIC16F84A output" width="640" /></a></div>
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-64280778295440445392017-09-06T07:56:00.001+02:002017-09-20T23:14:19.434+02:00Software UART for PIC16F84A microcontrollerThe microcontroller PIC16F84A has no hardware UART module, but we can use software UART to send/receive data to/from the PC via RS232 cable (COM port). This topic shows a simple example for the use of the UART protocol with the PIC16F84A MCU.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC16F84A microcontroller</li>
<li>8MHz crystal</li>
<li>2 x 22pF ceramic capacitors </li>
<li>10K ohm resistor </li>
<li>MAX232 -- <a href="http://www.ti.com/lit/ds/symlink/max232.pdf" target="_blank">datasheet</a></li>
<li>4 x 10uF polarized capacitor</li>
<li>Female RS232 connector</li>
<li>Breadboard</li>
<li>5V power source</li>
<li>Jumper wires </li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">UART Example for PIC16F84A microcontroller circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhU9N1c0OnjPJ0Z15P2jenkTommzm6U_6ebCAE18B_XL721bKrIb3HtijEdIzftgXgZ3e2MNE5ioe2HCS3c_aYnK3EacFJugyoUqbTH5qaIxqqwFBOQ_Pid78ldJaNyxFZ44LqSTIRU4wM/s1600/pic16f84a+software+uart+example+circuit.png" imageanchor="1"><img alt="Software UART RS232 for PIC16F84A circuit" border="0" height="438" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhU9N1c0OnjPJ0Z15P2jenkTommzm6U_6ebCAE18B_XL721bKrIb3HtijEdIzftgXgZ3e2MNE5ioe2HCS3c_aYnK3EacFJugyoUqbTH5qaIxqqwFBOQ_Pid78ldJaNyxFZ44LqSTIRU4wM/s640/pic16f84a+software+uart+example+circuit.png" title="Software UART RS232 for PIC16F84A circuit" width="640" /></a></div>
To interface the PIC16F84A MCU with the PC we need MAX232 signal level converter as shown in the circuit diagram. There are 2 lines between the PIC16F84A and the MAX232 and also two lines between the MAX232 and the female COM connector. One line for data transmit and the other one for data receive.<br />
The female COM connector is connected to the PC using RS232 cable, this cable has to be male-female because the PC RS232 port type is male.<br />
In this example the PIC16F84A MCU runs with 8MHz crystal oscillator. <br />
<span style="color: #cc0000;"><span style="font-size: large;">UART Example for PIC16F84A microcontroller C code:</span></span><br />
The function <span style="background-color: yellow;"><i>#use rs232(xmit = PIN_B4, rcv = PIN_B5, baud = 2400)</i></span> is used to configure the UART protocol. Here software UART is used.<br />
where:<br />
xmit is the transmit pin (RB4)<br />
rcv is the receive pin (RB5) <br />
2400 is the baud rate.<br />
The functions used in the C code are:<br />
<span style="background-color: yellow;"><i>printf:</i></span> sends a string of characters over RS232 transmission pin (TX).<br />
<span style="background-color: yellow;"><i><span class="hcp3">putc</span>:</i></span> send a character over RS232 transmission pin (TX).<br />
<span style="background-color: yellow;"><i>getc():</i></span> read character if available.<br />
Complete C code for CCS C compiler is below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">// Software UART example for PIC16F84A.</span>
<span style="color: #7e7e7e;">// http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;">// electronnote@gmail.com</span>
<span style="color: red;">#include</span> <16F84A.h>
<span style="color: red;">#fuses</span> HS, NOWDT, PUT, NOPROTECT
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 8000000)
<span style="color: red;">#use</span> fast_io(B)
<span style="color: red;">#use</span> rs232(xmit = PIN_B4, rcv = PIN_B5, baud = 2400)
<span style="color: blue;">const</span> <span style="color: blue;">char</span> message[] = <span style="color: #de00d0;">"***** PIC16F84A microcontroller UART example *****"</span> ;
<span style="color: blue;">int8</span> i = 0, j;
<span style="color: blue;">void</span> main(){
output_drive(PIN_B4);
delay_ms(2000); <span style="color: #7e7e7e;">// Wait 2 seconds</span>
<span style="color: #7e7e7e;">// Print text</span>
printf(<span style="color: #de00d0;">"Hello world!"</span>);
<span style="color: #7e7e7e;">// Print list of characters</span>
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
<span style="color: blue;">while</span>(message[i] != <span style="color: #de00d0;">'\0'</span>){ <span style="color: #7e7e7e;">// Loop until the end of the string</span>
putc(message[i]); <span style="color: #7e7e7e;">// Write character</span>
delay_ms(100); <span style="color: #7e7e7e;">// Wait 100 ms</span>
i++; <span style="color: #7e7e7e;">// Increment i</span>
}
<span style="color: #7e7e7e;">// Print numbers</span>
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
<span style="color: blue;">for</span>(i = 0; i < 21; i++){
printf(<span style="color: #de00d0;">"%u\n\r"</span>, i); <span style="color: #7e7e7e;">// Print i and start new line</span>
delay_ms(500);
}
<span style="color: #7e7e7e;">// Receive and send character via UART</span>
<span style="color: blue;">while</span>(TRUE){
j = getc(); <span style="color: #7e7e7e;">// UART read character</span>
putc(j); <span style="color: #7e7e7e;">// Send it back</span>
}
}
</pre>
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-75082268928992101992017-09-05T18:52:00.000+02:002017-09-20T23:15:30.280+02:00Real time clock and temperature monitor using PIC16F887 and DS3231The last interfacing of the PIC16F887 microcontroller and DS3231 RTC is the building of a simple real time clock and calendar with two buttons for setting time and date. Project link is the one below:<br />
<a href="http://ccspicc.blogspot.com/2017/07/pic16f887-ds3231-real-time-clock-set-button.html" target="_blank">Interfacing DS3231 with PIC16F887 microcontroller</a><br />
In this topic I'm going to add 2 alarms and temperature monitor to the previous project since the DS3231 has 2 alarm functions and temperature sensor with an accuracy of ±3°C (for more information read the DS3231 datasheet).<br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required: </span></span><br />
<ul>
<li>PIC16F887 microcontroller</li>
<li>20x4 LCD screen</li>
<li>10K ohm variable resistor</li>
<li>330 ohm resistor</li>
<li>LED</li>
<li>3 x push button</li>
<li>5V supply source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
DS3231 board contains the following components:<br />
<ul>
<li>DS3231 RTC - <a href="https://datasheets.maximintegrated.com/en/ds/DS3231.pdf" target="_blank"><i>datasheet</i></a></li>
<li>3 x 4.7K ohm resistors</li>
<li>0.1uF ceramic capacitor</li>
<li>3V coin cell battery</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">The circuit:</span></span><br />
Circuit schematic diagram is shown below.<br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgS3djE0SEcWksYwWwtGu_PNN_zYwit6qVqoHeVMoIMTwuirSPs6fWfTjA0r5leMXjh_5tbkvt17Ko4lvZ3hyphenhyphen_FLVz-YWkT5aR9jrFqhwteC8IMNygFASJSoSpmfSc3x23SUtCpPCZlHxk/s1600/ds3231+rtc+alarm+temperature+buttons+pic16f887+microcontroller.png" imageanchor="1"><img alt="DS3231 RTCC with buttons, alarm functions and temperature monitor PIC16F887 circuit" border="0" height="432" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgS3djE0SEcWksYwWwtGu_PNN_zYwit6qVqoHeVMoIMTwuirSPs6fWfTjA0r5leMXjh_5tbkvt17Ko4lvZ3hyphenhyphen_FLVz-YWkT5aR9jrFqhwteC8IMNygFASJSoSpmfSc3x23SUtCpPCZlHxk/s640/ds3231+rtc+alarm+temperature+buttons+pic16f887+microcontroller.png" title="DS3231 RTCC with buttons, alarm functions and temperature monitor PIC16F887 circuit" width="640" /></a></div>
In this project I used the DS3231 board, this board
basically contains the main chip which is the DS3231, pull-up resistors
(4.7K) of SCL, SDA and INT/SQW lines and coin cell battery holder. There
is also 24C32 EEPROM and some other resistors (not used in this
project).<br />
The DS3231 board is supplied with 5V as the
microcontroller and the 2004 LCD, there are 3 data lined connected
between this board and the PIC16F887 MCU, SCL line is connected to pin RC3, SDA
is connected to pin RC4 and INT line is connected to pin RB0 which is the
external interrupt pin of the PIC16F887 MCU. The DS3231 interrupts the
microcontroller when there is an alarm.<br />
In the circuit there are 3
push buttons: B1, B2 and B3. These buttons are used to set time,
calendar and alarms. Time and calendar can be adjusted with B1 and B2,
button B1 selects time or date parameter (time parameters: hours and
minutes; calendar parameters: day, date, month and year) and B2
increments the selected parameter. The button B3 and B2 adjust alarm1
and alarm2 parameters (hours, minutes and ON/OFF), button B3 selects the
parameter and B2 increments the selected parameter.<br />
There is an
LED connected to pin RB4, this LED is used as an alarm indicator (alarm1 or alarm2), so if
there is an alarm the DS3231 pulls down the INT pin which interrupts the
microcontroller and the microcontroller turns the LED ON, here button
B2 turns both the LED and the occurred alarm OFF.<br />
In this project the PIC16F887 MCU uses its internal oscillator and MCLR pin function is disabled.<br />
<span style="color: #e06666;"><span style="font-size: large;">CCS C code:</span></span><br />
The C code below was tested with CCS PIC C compiler version 5.051.<br />
By reading the datasheet of the DS3231 RTC the code will be more easier!<br />
The hardware I2C module of the MCU is initialized and configured using the following CCS C function with a speed of 100KHz:<br />
<span style="background-color: yellow;">#use I2C(master, I2C1, FAST = 100000)</span><br />
<div class="Style1" style="margin-right: 0px;">
master: set the microcontroller to the master mode</div>
I2C1: use first I2C module.<br />
The DS3231 works with BCD format only (except the temperature) and to convert the BCD to
decimal and vise versa I used the following functions (example for minute
variable):<br />
<span style="background-color: yellow;">minute = (minute >> 4) * 10 + (minute & 0x0F);</span> // Convert BCD to decimal<br />
<span style="background-color: yellow;">minute = ((minute / 10) << 4) + (minute % 10); </span> // Convert decimal to BCD<u> </u><br />
<u>Code functions:</u><br />
<span style="background-color: yellow;">void DS3231_read() :</span> this function reads time and calendar data from the DS3231 (seconds, minutes, hours, day, date, month and year).<br />
<span style="background-color: yellow;">void DS3231_display() :</span>
displays time and calendar data, before displaying time and calendar
data are converted from BCD format to decimal format. This function
displays the calendar by calling a function named <span style="background-color: yellow;">void calendar_display()</span> .<br />
<span style="background-color: yellow;">void alarms_read_display() :</span>
basically this functions reads alarm1 and alarm2 minutes and hours. It
also reads the DS3231 control register, status register and 2
temperature registers.<br />
The other job of this function is to
display alarms data (hours, minutes and status) and the temperature
value. The alarm status are extracted from the control register.<br />
<span style="background-color: yellow;">int8 edit(parameter, x, y) :</span> I used this function to edit time, calendar and alarm parameters except the day. I used a variable named<span style="background-color: yellow;"> i </span>to distinguish between the parameters:<br />
i = 0, 1 : time hours and minutes respectively<br />
i = 2, 3, 4: calendar date, month and year respectively<br />
i = 5, 6: alarms hours and minutes respectively<br />
i = 7: alarm status (ON or OFF)<br />
After the edit of time/calendar/alarms the data have to be converted back to BCD format and written to the DS3231.<br />
The
MCU turns the LED ON when it interrupted by the DS3231, the DS3231
sends the interrupt signal (pulls down the INT line) when there has been
an alarm. Button B2 resets and turns OFF the alarm. If both alarms are
active, button B2 will resets and turns OFF the occurred alarm only and
keeps the other as it is. To do that we've to detect which alarm was
occurred which can be easily done by reading the status register of the
DS3231 (A1IF and A2IF flag bits). Turning ON or OFF an alarm is done by
writing to the control register (bits: INTCN, A1IE and A2IE). Always
INTCN bit should be 1. I used the following line to write 1 to the INTCN
bit and to turn OFF the occurred alarm:<br />
<span style="background-color: yellow;">i2c_write(4 | (!bit_test(status_reg, 0) & alarm1_status) | ((!bit_test(status_reg, 1) & alarm2_status) << 1));</span><br />
alarm1_status
and alarm2_status are 1-bit variables, for example if alarm1_status is 1
==> alarm1 is ON and if alarm1_status is 0 ==> alarm1 is OFF.
The same thing for alarm2.<br />
The complete C code is below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">/* Real time clock and calendar with 2 alarms and temperature monitor using</span>
<span style="color: #7e7e7e;"> PIC16F887 & DS3231 CCS PIC C code.</span>
<span style="color: #7e7e7e;"> Read DS3231 RTC datasheet to understand the code!</span>
<span style="color: #7e7e7e;"> Time & date parameters can be set using two push buttons connected to RB1 & RB2.</span>
<span style="color: #7e7e7e;"> Alarm1 and alarm2 can be set using buttons RB3 and RB2.</span>
<span style="color: #7e7e7e;"> Pin RB4 becomes high when alarm occurred and button RB2 returns it to low and</span>
<span style="color: #7e7e7e;"> turn the occurred alarm OFF.</span>
<span style="color: #7e7e7e;"> DS3231 interrupt pin is connected to PIC16F887 external interrupt pin RB0.</span>
<span style="color: #7e7e7e;"> http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;"> electronnote@gmail.com</span>
<span style="color: #7e7e7e;">*/</span>
<span style="color: #7e7e7e;">//LCD module connections</span>
<span style="color: red;">#define</span> LCD_RS_PIN PIN_D0
<span style="color: red;">#define</span> LCD_RW_PIN PIN_D1
<span style="color: red;">#define</span> LCD_ENABLE_PIN PIN_D2
<span style="color: red;">#define</span> LCD_DATA4 PIN_D3
<span style="color: red;">#define</span> LCD_DATA5 PIN_D4
<span style="color: red;">#define</span> LCD_DATA6 PIN_D5
<span style="color: red;">#define</span> LCD_DATA7 PIN_D6
<span style="color: #7e7e7e;">//End LCD module connections</span>
<span style="color: red;">#include</span> <16F887.h>
<span style="color: red;">#fuses</span> NOMCLR, INTRC_IO, NOBROWNOUT, NOLVP
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 8MHz)
<span style="color: red;">#use</span> fast_io(B)
<span style="color: red;">#use</span> fast_io(D)
<span style="color: red;">#include</span> <lcd.c>
<span style="color: red;">#use</span> I2C(master, I2C1, FAST = 100000)
<span style="color: blue;">int1</span> alarm1_status, alarm2_status;
<span style="color: blue;">char</span> time[] = <span style="color: #de00d0;">" : : "</span>,
calendar[] = <span style="color: #de00d0;">" / /20 "</span>,
alarm1[] = <span style="color: #de00d0;">"A1: : :00"</span>, alarm2[] = <span style="color: #de00d0;">"A2: : :00"</span>,
temperature[] = <span style="color: #de00d0;">"T: . C"</span>;
<span style="color: blue;">int8</span> i, second, minute, hour, day, date, month, year,
alarm1_minute, alarm1_hour, alarm2_minute, alarm2_hour,
status_reg;
<span style="color: red;">#INT_EXT</span> <span style="color: #7e7e7e;">// External interrupt routine</span>
<span style="color: blue;">void</span> ext_isr(<span style="color: blue;">void</span>){
output_high(PIN_B4);
clear_interrupt(INT_EXT);
}
<span style="color: blue;">void</span> DS3231_read(){ <span style="color: #7e7e7e;">// Read time & calendar data function</span>
i2c_start(); <span style="color: #7e7e7e;">// Start I2C protocol</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(0); <span style="color: #7e7e7e;">// Send register address (seconds register)</span>
i2c_start(); <span style="color: #7e7e7e;">// Restart I2C</span>
i2c_write(0xD1); <span style="color: #7e7e7e;">// Initialize data read</span>
second = i2c_read(1); <span style="color: #7e7e7e;">// Read seconds from register 0</span>
minute = i2c_read(1); <span style="color: #7e7e7e;">// Read minutes from register 1</span>
hour = i2c_read(1); <span style="color: #7e7e7e;">// Read hour from register 2</span>
day = i2c_read(1); <span style="color: #7e7e7e;">// Read day from register 3</span>
date = i2c_read(1); <span style="color: #7e7e7e;">// Read date from register 4</span>
month = i2c_read(1); <span style="color: #7e7e7e;">// Read month from register 5</span>
year = i2c_read(0); <span style="color: #7e7e7e;">// Read year from register 6</span>
i2c_stop(); <span style="color: #7e7e7e;">// Stop I2C protocol</span>
}
<span style="color: blue;">void</span> alarms_read_display(){ <span style="color: #7e7e7e;">// Read and display alarm1 and alarm2 data function</span>
<span style="color: blue;">int8</span> control_reg, temperature_lsb;
<span style="color: blue;">signed</span> <span style="color: blue;">int8</span> temperature_msb;
i2c_start(); <span style="color: #7e7e7e;">// Start I2C protocol</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(0x08); <span style="color: #7e7e7e;">// Send register address (alarm1 minutes register)</span>
i2c_start(); <span style="color: #7e7e7e;">// Restart I2C</span>
i2c_write(0xD1); <span style="color: #7e7e7e;">// Initialize data read</span>
alarm1_minute = i2c_read(1); <span style="color: #7e7e7e;">// Read alarm1 minutes</span>
alarm1_hour = i2c_read(1); <span style="color: #7e7e7e;">// Read alarm1 hours</span>
i2c_read(1); <span style="color: #7e7e7e;">// Skip alarm1 day/date register</span>
alarm2_minute = i2c_read(1); <span style="color: #7e7e7e;">// Read alarm2 minutes</span>
alarm2_hour = i2c_read(1); <span style="color: #7e7e7e;">// Read alarm2 hours</span>
i2c_read(1); <span style="color: #7e7e7e;">// Skip alarm2 day/date register</span>
control_reg = i2c_read(1); <span style="color: #7e7e7e;">// Read the DS3231 control register</span>
status_reg = i2c_read(1); <span style="color: #7e7e7e;">// Read the DS3231 status register</span>
i2c_read(1); <span style="color: #7e7e7e;">// Skip aging offset register</span>
temperature_msb = i2c_read(1); <span style="color: #7e7e7e;">// Read temperature MSB</span>
temperature_lsb = i2c_read(0); <span style="color: #7e7e7e;">// Read temperature LSB</span>
i2c_stop(); <span style="color: #7e7e7e;">// Stop I2C protocol</span>
<span style="color: #7e7e7e;">// Convert BCD to decimal</span>
alarm1_minute = (alarm1_minute >> 4) * 10 + (alarm1_minute & 0x0F);
alarm1_hour = (alarm1_hour >> 4) * 10 + (alarm1_hour & 0x0F);
alarm2_minute = (alarm2_minute >> 4) * 10 + (alarm2_minute & 0x0F);
alarm2_hour = (alarm2_hour >> 4) * 10 + (alarm2_hour & 0x0F);
<span style="color: #7e7e7e;">// End conversion</span>
alarm1[8] = alarm1_minute % 10 + 48;
alarm1[7] = alarm1_minute / 10 + 48;
alarm1[5] = alarm1_hour % 10 + 48;
alarm1[4] = alarm1_hour / 10 + 48;
alarm2[8] = alarm2_minute % 10 + 48;
alarm2[7] = alarm2_minute / 10 + 48;
alarm2[5] = alarm2_hour % 10 + 48;
alarm2[4] = alarm2_hour / 10 + 48;
alarm1_status = bit_test(control_reg, 0); <span style="color: #7e7e7e;">// Read alarm1 interrupt enable bit (A1IE) from DS3231 control register</span>
alarm2_status = bit_test(control_reg, 1); <span style="color: #7e7e7e;">// Read alarm2 interrupt enable bit (A2IE) from DS3231 control register</span>
<span style="color: blue;">if</span>(temperature_msb < 0){
temperature_msb = <span style="color: blue;">abs</span>(temperature_msb);
temperature[2] = <span style="color: #de00d0;">'-'</span>;
}
<span style="color: blue;">else</span>
temperature[2] = <span style="color: #de00d0;">' '</span>;
temperature_lsb >>= 6;
temperature[4] = temperature_msb % 10 + 48;
temperature[3] = temperature_msb / 10 + 48;
<span style="color: blue;">if</span>(temperature_lsb == 0 || temperature_lsb == 2){
temperature[7] = <span style="color: #de00d0;">'0'</span>;
<span style="color: blue;">if</span>(temperature_lsb == 0) temperature[6] = <span style="color: #de00d0;">'0'</span>;
<span style="color: blue;">else</span> temperature[6] = <span style="color: #de00d0;">'5'</span>;
}
<span style="color: blue;">if</span>(temperature_lsb == 1 || temperature_lsb == 3){
temperature[7] = <span style="color: #de00d0;">'5'</span>;
<span style="color: blue;">if</span>(temperature_lsb == 1) temperature[6] = <span style="color: #de00d0;">'2'</span>;
<span style="color: blue;">else</span> temperature[6] = <span style="color: #de00d0;">'7'</span>;
}
temperature[8] = 223; <span style="color: #7e7e7e;">// Degree symbol</span>
lcd_gotoxy(11, 1); <span style="color: #7e7e7e;">// Go to column 10 row 1</span>
printf(lcd_putc, temperature); <span style="color: #7e7e7e;">// Display temperature</span>
lcd_gotoxy(21, 1); <span style="color: #7e7e7e;">// Go to column 1 row 3</span>
printf(lcd_putc, alarm1); <span style="color: #7e7e7e;">// Display alarm1</span>
lcd_gotoxy(38, 1); <span style="color: #7e7e7e;">// Go to column 18 row 3</span>
<span style="color: blue;">if</span>(alarm1_status) lcd_putc(<span style="color: #de00d0;">"ON "</span>); <span style="color: #7e7e7e;">// If A1IE = 1 print 'ON'</span>
<span style="color: blue;">else</span> lcd_putc(<span style="color: #de00d0;">"OFF"</span>); <span style="color: #7e7e7e;">// If A1IE = 0 print 'OFF'</span>
lcd_gotoxy(21, 2); <span style="color: #7e7e7e;">// Go to column 1 row 4</span>
printf(lcd_putc, alarm2); <span style="color: #7e7e7e;">// Display alarm2</span>
lcd_gotoxy(38, 2); <span style="color: #7e7e7e;">// Go to column 18 row 4</span>
<span style="color: blue;">if</span>(alarm2_status) lcd_putc(<span style="color: #de00d0;">"ON "</span>); <span style="color: #7e7e7e;">// If A2IE = 1 print 'ON'</span>
<span style="color: blue;">else</span> lcd_putc(<span style="color: #de00d0;">"OFF"</span>); <span style="color: #7e7e7e;">// If A2IE = 0 print 'OFF'</span>
}
<span style="color: blue;">void</span> calendar_display(){ <span style="color: #7e7e7e;">// Display calendar function</span>
<span style="color: blue;">switch</span>(day){
<span style="color: blue;">case</span> 1: strcpy(calendar, <span style="color: #de00d0;">"Sun / /20 "</span>); <span style="color: blue;">break</span>;
<span style="color: blue;">case</span> 2: strcpy(calendar, <span style="color: #de00d0;">"Mon / /20 "</span>); <span style="color: blue;">break</span>;
<span style="color: blue;">case</span> 3: strcpy(calendar, <span style="color: #de00d0;">"Tue / /20 "</span>); <span style="color: blue;">break</span>;
<span style="color: blue;">case</span> 4: strcpy(calendar, <span style="color: #de00d0;">"Wed / /20 "</span>); <span style="color: blue;">break</span>;
<span style="color: blue;">case</span> 5: strcpy(calendar, <span style="color: #de00d0;">"Thu / /20 "</span>); <span style="color: blue;">break</span>;
<span style="color: blue;">case</span> 6: strcpy(calendar, <span style="color: #de00d0;">"Fri / /20 "</span>); <span style="color: blue;">break</span>;
<span style="color: blue;">case</span> 7: strcpy(calendar, <span style="color: #de00d0;">"Sat / /20 "</span>); <span style="color: blue;">break</span>;
<span style="color: blue;">default</span>: strcpy(calendar, <span style="color: #de00d0;">"Sat / /20 "</span>); <span style="color: blue;">break</span>;
}
calendar[13] = year % 10 + 48;
calendar[12] = year / 10 + 48;
calendar[8] = month % 10 + 48;
calendar[7] = month / 10 + 48;
calendar[5] = date % 10 + 48;
calendar[4] = date / 10 + 48;
lcd_gotoxy(1, 2); <span style="color: #7e7e7e;">// Go to column 1 row 2</span>
printf(lcd_putc, calendar); <span style="color: #7e7e7e;">// Display calendar</span>
}
<span style="color: blue;">void</span> DS3231_display(){
<span style="color: #7e7e7e;">// Convert BCD to decimal</span>
second = (second >> 4) * 10 + (second & 0x0F);
minute = (minute >> 4) * 10 + (minute & 0x0F);
hour = (hour >> 4) * 10 + (hour & 0x0F);
date = (date >> 4) * 10 + (date & 0x0F);
month = (month >> 4) * 10 + (month & 0x0F);
year = (year >> 4) * 10 + (year & 0x0F);
<span style="color: #7e7e7e;">// End conversion</span>
time[7] = second % 10 + 48;
time[6] = second / 10 + 48;
time[4] = minute % 10 + 48;
time[3] = minute / 10 + 48;
time[1] = hour % 10 + 48;
time[0] = hour / 10 + 48;
calendar_display(); <span style="color: #7e7e7e;">// Call calendar display function</span>
lcd_gotoxy(1, 1); <span style="color: #7e7e7e;">// Go to column 1 row 1</span>
printf(lcd_putc, time); <span style="color: #7e7e7e;">// Display time</span>
}
<span style="color: blue;">void</span> <span style="color: blue;">blink</span>(){
<span style="color: blue;">int8</span> j = 0;
<span style="color: blue;">while</span>(j < 10 && (input(PIN_B1) || i >= 5) && input(PIN_B2) && (input(PIN_B3) || i < 5)){
j++;
delay_ms(25);
}
}
<span style="color: blue;">int8</span> edit(parameter, x, y){
<span style="color: blue;">while</span>(!input(PIN_B1) || !input(PIN_B3)); <span style="color: #7e7e7e;">// Wait until button RB0 is released</span>
<span style="color: blue;">while</span>(TRUE){
<span style="color: blue;">while</span>(!input(PIN_B2)){ <span style="color: #7e7e7e;">// If button RB2 is pressed</span>
parameter++;
<span style="color: blue;">if</span>(((i == 0) || (i == 5)) && parameter > 23) <span style="color: #7e7e7e;">// If hours > 23 ==> hours = 0</span>
parameter = 0;
<span style="color: blue;">if</span>(((i == 1) || (i == 6)) && parameter > 59) <span style="color: #7e7e7e;">// If minutes > 59 ==> minutes = 0</span>
parameter = 0;
<span style="color: blue;">if</span>(i == 2 && parameter > 31) <span style="color: #7e7e7e;">// If date > 31 ==> date = 1</span>
parameter = 1;
<span style="color: blue;">if</span>(i == 3 && parameter > 12) <span style="color: #7e7e7e;">// If month > 12 ==> month = 1</span>
parameter = 1;
<span style="color: blue;">if</span>(i == 4 && parameter > 99) <span style="color: #7e7e7e;">// If year > 99 ==> year = 0</span>
parameter = 0;
<span style="color: blue;">if</span>(i == 7 && parameter > 1) <span style="color: #7e7e7e;">// For alarms ON or OFF (1: alarm ON, 0: alarm OFF)</span>
parameter = 0;
lcd_gotoxy(x, y);
<span style="color: blue;">if</span>(i == 7){ <span style="color: #7e7e7e;">// For alarms ON & OFF</span>
<span style="color: blue;">if</span>(parameter == 1) lcd_putc(<span style="color: #de00d0;">"ON "</span>);
<span style="color: blue;">else</span> lcd_putc(<span style="color: #de00d0;">"OFF"</span>);
}
<span style="color: blue;">else</span>
printf(lcd_putc,<span style="color: #de00d0;">"%02u"</span>, parameter); <span style="color: #7e7e7e;">// Display parameter</span>
<span style="color: blue;">if</span>(i >= 5){
DS3231_read(); <span style="color: #7e7e7e;">// Read data from DS3231</span>
DS3231_display(); <span style="color: #7e7e7e;">// Display DS3231 time and calendar</span>
}
delay_ms(200); <span style="color: #7e7e7e;">// Wait 200ms</span>
}
lcd_gotoxy(x, y); <span style="color: #7e7e7e;">// Go to LCD x column and y row</span>
lcd_putc(<span style="color: #de00d0;">" "</span>); <span style="color: #7e7e7e;">// Print two spaces</span>
<span style="color: blue;">if</span>(i == 7) lcd_putc(<span style="color: #de00d0;">" "</span>); <span style="color: #7e7e7e;">// Print space (for alarms ON & OFF)</span>
<span style="color: blue;">blink</span>(); <span style="color: #7e7e7e;">// Call blink function</span>
lcd_gotoxy(x, y); <span style="color: #7e7e7e;">// Go to LCD x column and y row</span>
<span style="color: blue;">if</span>(i == 7){ <span style="color: #7e7e7e;">// For alarms ON & OFF</span>
<span style="color: blue;">if</span>(parameter == 1) lcd_putc(<span style="color: #de00d0;">"ON "</span>);
<span style="color: blue;">else</span> lcd_putc(<span style="color: #de00d0;">"OFF"</span>);
}
<span style="color: blue;">else</span>
printf(lcd_putc,<span style="color: #de00d0;">"%02u"</span>, parameter); <span style="color: #7e7e7e;">// Display parameter</span>
<span style="color: blue;">blink</span>();
<span style="color: blue;">if</span>(i >= 5){
DS3231_read();
DS3231_display();}
<span style="color: blue;">if</span>((!input(PIN_B1) && i < 5) || (!input(PIN_B3) && i >= 5)){
i++; <span style="color: #7e7e7e;">// Increment 'i' for the next parameter</span>
<span style="color: blue;">return</span> parameter; <span style="color: #7e7e7e;">// Return parameter value and exit</span>
}
}
}
<span style="color: blue;">void</span> main(){
setup_oscillator(OSC_8MHZ); <span style="color: #7e7e7e;">// Set internal oscillator to 8MHz</span>
output_b(0);
set_tris_b(0x0F); <span style="color: #7e7e7e;">// Configure RB0 ~ 3 as input pins</span>
set_tris_d(0); <span style="color: #7e7e7e;">// Configure all PORTD pins as outputs</span>
port_b_pullups(0x0E); <span style="color: #7e7e7e;">// Enable RB1, RB2 & RB internal pull-ups</span>
enable_interrupts(GLOBAL); <span style="color: #7e7e7e;">// Enable global interrupts</span>
enable_interrupts(INT_EXT_H2L); <span style="color: #7e7e7e;">// Enable external interrupt with edge from high to low</span>
lcd_init(); <span style="color: #7e7e7e;">// Initialize LCD module</span>
lcd_putc(<span style="color: #de00d0;">'\f'</span>); <span style="color: #7e7e7e;">// LCD clear</span>
<span style="color: blue;">while</span>(TRUE){
<span style="color: blue;">if</span>(!input(PIN_B1)){ <span style="color: #7e7e7e;">// If RB1 button is pressed</span>
i = 0;
hour = edit(hour, 1, 1);
minute = edit(minute, 4, 1);
<span style="color: blue;">while</span>(!input(PIN_B1)); <span style="color: #7e7e7e;">// Wait until button RB0 released</span>
<span style="color: blue;">while</span>(TRUE){
<span style="color: blue;">while</span>(!input(PIN_B2)){ <span style="color: #7e7e7e;">// If button RB2 button is pressed</span>
day++; <span style="color: #7e7e7e;">// Increment day</span>
<span style="color: blue;">if</span>(day > 7) day = 1;
calendar_display(); <span style="color: #7e7e7e;">// Call display calendar</span>
lcd_gotoxy(1, 2); <span style="color: #7e7e7e;">// Go to column 1 row 2</span>
printf(lcd_putc, calendar); <span style="color: #7e7e7e;">// Display calendar</span>
delay_ms(200);
}
lcd_gotoxy(1, 2); <span style="color: #7e7e7e;">// Go to column 1 row 2</span>
lcd_putc(<span style="color: #de00d0;">" "</span>); <span style="color: #7e7e7e;">// Print 3 spaces</span>
<span style="color: blue;">blink</span>();
lcd_gotoxy(1, 2); <span style="color: #7e7e7e;">// Go to column 1 row 2</span>
printf(lcd_putc, calendar); <span style="color: #7e7e7e;">// Print calendar</span>
<span style="color: blue;">blink</span>(); <span style="color: #7e7e7e;">// Call blink function</span>
<span style="color: blue;">if</span>(!input(PIN_B1)) <span style="color: #7e7e7e;">// If button RB1 is pressed</span>
<span style="color: blue;">break</span>;
}
date = edit(date, 5, 2); <span style="color: #7e7e7e;">// Edit date</span>
month = edit(month, 8, 2); <span style="color: #7e7e7e;">// Edit month</span>
year = edit(year, 13, 2); <span style="color: #7e7e7e;">// Edit year</span>
<span style="color: #7e7e7e;">// Convert decimal to BCD</span>
minute = ((minute / 10) << 4) + (minute % 10);
hour = ((hour / 10) << 4) + (hour % 10);
date = ((date / 10) << 4) + (date % 10);
month = ((month / 10) << 4) + (month % 10);
year = ((year / 10) << 4) + (year % 10);
<span style="color: #7e7e7e;">// End conversion</span>
<span style="color: #7e7e7e;">// Write time & calendar data to DS3231 RTC</span>
i2c_start(); <span style="color: #7e7e7e;">// Start I2C protocol</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(0); <span style="color: #7e7e7e;">// Send register address (seconds address)</span>
i2c_write(0); <span style="color: #7e7e7e;">// Reset seconds and start oscillator</span>
i2c_write(minute); <span style="color: #7e7e7e;">// Write minute value to DS3231</span>
i2c_write(hour); <span style="color: #7e7e7e;">// Write hour value to DS3231</span>
i2c_write(day); <span style="color: #7e7e7e;">// Write day value</span>
i2c_write(date); <span style="color: #7e7e7e;">// Write date value to DS3231</span>
i2c_write(month); <span style="color: #7e7e7e;">// Write month value to DS3231</span>
i2c_write(year); <span style="color: #7e7e7e;">// Write year value to DS3231</span>
i2c_stop(); <span style="color: #7e7e7e;">// Stop I2C</span>
delay_ms(200); <span style="color: #7e7e7e;">// Wait 200ms</span>
}
<span style="color: blue;">if</span>(!input(PIN_B3)){ <span style="color: #7e7e7e;">// If RB3 button is pressed</span>
<span style="color: blue;">while</span>(!input(PIN_B3)); <span style="color: #7e7e7e;">// Wait until button RB3 released</span>
i = 5;
alarm1_hour = edit(alarm1_hour, 25, 1);
alarm1_minute = edit(alarm1_minute, 28, 1);
alarm1_status = edit(alarm1_status, 38, 1);
i = 5;
alarm2_hour = edit(alarm2_hour, 25, 2);
alarm2_minute = edit(alarm2_minute, 28, 2);
alarm2_status = edit(alarm2_status, 38, 2);
alarm1_minute = ((alarm1_minute / 10) << 4) + (alarm1_minute % 10);
alarm1_hour = ((alarm1_hour / 10) << 4) + (alarm1_hour % 10);
alarm2_minute = ((alarm2_minute / 10) << 4) + (alarm2_minute % 10);
alarm2_hour = ((alarm2_hour / 10) << 4) + (alarm2_hour % 10);
<span style="color: #7e7e7e;">// Write alarms data to DS3231</span>
i2c_start(); <span style="color: #7e7e7e;">// Start I2C</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(7); <span style="color: #7e7e7e;">// Send register address (alarm1 seconds)</span>
i2c_write(0); <span style="color: #7e7e7e;">// Write 0 to alarm1 seconds</span>
i2c_write(alarm1_minute); <span style="color: #7e7e7e;">// Write alarm1 minutes value to DS3231</span>
i2c_write(alarm1_hour); <span style="color: #7e7e7e;">// Write alarm1 hours value to DS3231</span>
i2c_write(0x80); <span style="color: #7e7e7e;">// Alarm1 when hours, minutes, and seconds match</span>
i2c_write(alarm2_minute); <span style="color: #7e7e7e;">// Write alarm2 minutes value to DS3231</span>
i2c_write(alarm2_hour); <span style="color: #7e7e7e;">// Write alarm2 hours value to DS3231</span>
i2c_write(0x80); <span style="color: #7e7e7e;">// Alarm2 when hours and minutes match</span>
i2c_write(4 | alarm1_status | (alarm2_status << 1)); <span style="color: #7e7e7e;">// Write data to DS3231 control register (enable interrupt when alarm)</span>
i2c_write(0); <span style="color: #7e7e7e;">// Clear alarm flag bits</span>
i2c_stop(); <span style="color: #7e7e7e;">// Stop I2C</span>
delay_ms(200); <span style="color: #7e7e7e;">// Wait 200ms</span>
}
<span style="color: blue;">if</span>(!input(PIN_B2) && input(PIN_B4)){ <span style="color: #7e7e7e;">// When button B2 pressed with alarm (Reset and turn OFF the alarm)</span>
output_low(PIN_B4); <span style="color: #7e7e7e;">// Turn OFF the alarm indicator</span>
i2c_start(); <span style="color: #7e7e7e;">// Start I2C</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(0x0E); <span style="color: #7e7e7e;">// Send register address (control register)</span>
<span style="color: #7e7e7e;">// Write data to control register (Turn OFF the occurred alarm and keep the other as it is)</span>
i2c_write(4 | (!bit_test(status_reg, 0) & alarm1_status) | ((!bit_test(status_reg, 1) & alarm2_status) << 1));
i2c_write(0); <span style="color: #7e7e7e;">// Clear alarm flag bits</span>
i2c_stop(); <span style="color: #7e7e7e;">// Stop I2C</span>
}
DS3231_read(); <span style="color: #7e7e7e;">// Read time and calendar parameters from DS3231 RTC</span>
alarms_read_display(); <span style="color: #7e7e7e;">// Read and display alarms parameters</span>
DS3231_display(); <span style="color: #7e7e7e;">// Display time & calendar</span>
delay_ms(50); <span style="color: #7e7e7e;">// Wait 50ms</span>
}
}
<span style="color: #7e7e7e;">// End of code</span>
</pre>
<span style="color: #cc0000;"><span style="font-size: large;">Video:</span></span><br />
After
connecting the circuit and burning the HEX file into the MCU, I got the
result shown similar to what's in the video below where the used
microcontroller is PIC16F877A.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/QE5hjYRW410/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/QE5hjYRW410?feature=player_embedded" width="320"></iframe></div>
<br />
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-13958425176817407252017-09-05T13:15:00.000+02:002017-09-20T23:15:30.208+02:00Read text files from FAT16 SD card with PIC16F887<div style="text-align: center;">
<span style="font-size: 30px;">Interfacing PIC16F887 with FAT16 SD card</span></div>
After reading raw data (bytes and sectors) from SD card, now I'm going to use FAT16 file system to read and print text file located in 2 GB SD card.<br />
Read SD card raw data topic:<br />
<a href="http://ccspicc.blogspot.com/2017/09/mmcsd-card-raw-data-read-pic16f887.html" target="_blank">MMC/SD Card raw data read with PIC16F887 microcontroller</a><br />
UART protocol is used to display the content of the text file.<br />
For this project, I used MMC/SD card driver for CCS C compiler which can be found in:<br />
<a href="http://ccspicc.blogspot.com/2017/08/mmc-sd-card-driver-for-ccs-compiler.html" target="_blank">MMC/SD Card driver for CCS PIC C compiler</a><br />
And I used FAT16 library (for reading files) for CCS C compiler which can be downloaded from:<br />
<a href="https://ccspicc.blogspot.com/2017/08/fat16-library-for-pic-microcontroller.html" target="_blank">FAT16 Library for CCS C compiler</a><br />
<br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC16F887 microcontroller</li>
<li>FAT16 formatted MMC/SD card ( <= 2 GB)</li>
<li>ASM1117 3.3 voltage regulator</li>
<li>3 x 3.3K ohm resistor</li>
<li>3 x 2.2K ohm resistor</li>
<li>10K ohm resistor</li>
<li>5 x 10uF polarized capacitor</li>
<li>100nF ceramic capacitor</li>
<li>MAX232 chip</li>
<li>Female COM port</li>
<li>5V Power source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">Read text files from FAT16 SD card with PIC16F887 circuit:</span></span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsTXzX-bnxVeK3oHbZ59ZDnPsj8PP3eQSGzDDXTPtnwVSx0_7uBntjdNeCT6lI8Xe3vegnaJm4XPeJAulYurjXBj44GsVMXNMWW8sICnMH4Gu8Ro2pbM4nUqBlevKDpk4DRHs-smsv9oA/s1600/interfacing+pic16f887+mmc+sd+card.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Read text file from FAT16 microSD card using PIC16F887 MCU circuit" border="0" data-original-height="923" data-original-width="1480" height="398" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsTXzX-bnxVeK3oHbZ59ZDnPsj8PP3eQSGzDDXTPtnwVSx0_7uBntjdNeCT6lI8Xe3vegnaJm4XPeJAulYurjXBj44GsVMXNMWW8sICnMH4Gu8Ro2pbM4nUqBlevKDpk4DRHs-smsv9oA/s640/interfacing+pic16f887+mmc+sd+card.png" title="Read text file from FAT16 microSD card using PIC16F887 MCU circuit" width="640" /></a></div>
As known the SD card voltage is 3.3V and the PIC16F887 voltage is
5V, so AMS1117 3.3V is used to step down the 5V in order to supply our
SD card with 3.3V. Also each digital output pin of the PIC16F887 MCU can be logic 0 (0V) or logic 1
(5V) and connecting the microcontroller output pins (CS , SDO and SCK)
directly to the SD card may damage it, here a voltage divider is used
to get about 3V from the 5V which is enough for the SD card. The voltage
divider consists of 3.3K and 2.2 K resistors. The MISO is connected
directly to the SDI pin of the microcontroller because it is the data
output pin of the SD card which is normally does not exceed 3.3V.<br />
I
used just one wire (RD2) to transmit data from the microcontroller to
the PC (there is no need for the MCU to receive data so the receiving
wire is not connected).<br />
The chip select pin of the SD card is connected to pin RD3 (the SD card chip select pin is active low). <br />
In this project the PIC16F887 MCU uses its internal oscillator and MCLR pin function is disabled.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Read text files from FAT16 SD card with PIC16F887 C code:</span></span><br />
The C code below was tested with CCS C compiler version 5.051.<br />
SD card driver and FAT16 library for CCS must be added to the
project, just by putting the two source codes in the project folder or the
CCS driver folder. <br />
In this example I used the hardware SPI module
of the PIC16F887, software SPI also works but the hardware one
is much faster.<br />
I named the text file
"mytext" (basically it is mytext.txt) but in the CCS C code we've to
add the extension of the file which becomes "mytext.txt". <br />
I used a read buffer of 10 bytes ( <span style="background-color: yellow;">file_data[10]</span> ), so the
microcontroller reads the text file 10 bytes by 10 bytes, it reads 10
bytes and send it to the PC via RS232 then the second 10 bytes and so on
until the function <span style="background-color: yellow;">fat16_read_data(10, file_data)</span> returns 1 which means we're at the end of the file. <br />
The functions used in the C code are:<br />
<span style="background-color: yellow;">fat16_init():</span> initializes the SD card and the FAT16 file system, return 0 if OK and 1 if error.<br />
<span style="background-color: yellow;">fat16_open_file(txt):</span> opens file with predefined name.<br />
<span style="background-color: yellow;">fat16_read_data(10, file_data):</span> read data (10 bytes) from the opened file and save it in the array <span style="background-color: yellow;">file_data</span>.<br />
<span style="background-color: yellow;">printf:</span> outputs data over RS232 where <span style="background-color: yellow;">printf("%s", file_data);</span> outputs a string of characters (<span style="background-color: yellow;">file_data</span>).<br />
Complete C code is below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">/* Read and print text file from FAT16 microSD card using PIC16F887 MCU.</span>
<span style="color: #7e7e7e;"> Fat16 library and MMC/SD card driver for CCS C compiler must be installed</span>
<span style="color: #7e7e7e;"> http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;"> electronnote@gmail.com</span>
<span style="color: #7e7e7e;">*/</span>
<span style="color: #7e7e7e;">// SD Card module connections</span>
<span style="color: red;">#define</span> SDCARD_SPI_HW <span style="color: #7e7e7e;">// Hardware SPI module is used for the SD card</span>
<span style="color: red;">#define</span> SDCARD_PIN_SELECT PIN_D3 <span style="color: #7e7e7e;">// SD card chip select pin is connected to pin RD3</span>
<span style="color: #7e7e7e;">// End SD card module connections</span>
<span style="color: red;">#include</span> <16F887.h>
<span style="color: red;">#fuses</span> NOMCLR, INTRC_IO, NOBROWNOUT, NOLVP
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 8MHz)
<span style="color: red;">#use</span> rs232(xmit = PIN_D2, rcv = PIN_D1, baud = 9600)
<span style="color: red;">#include</span> <sdcard.c> <span style="color: #7e7e7e;">// SD card diver source file</span>
<span style="color: red;">#include</span> <fat16.c> <span style="color: #7e7e7e;">// FAT16 Library source file</span>
<span style="color: blue;">int8</span> file_data[10];
<span style="color: blue;">void</span> open_file(){
<span style="color: blue;">const</span> <span style="color: blue;">int8</span> *txt = <span style="color: #de00d0;">"mytext.txt"</span>; <span style="color: #7e7e7e;">// File name 'mytext.txt'</span>
<span style="color: blue;">if</span>(fat16_open_file(txt) == 0){
printf(<span style="color: #de00d0;">"OK!"</span>);
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
<span style="color: blue;">while</span>(fat16_read_data(10, file_data) == 0) <span style="color: #7e7e7e;">// Read file data</span>
printf(<span style="color: #de00d0;">"%s"</span>, file_data); <span style="color: #7e7e7e;">// Print file data as string</span>
<span style="color: blue;">return</span>;
}
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
printf(<span style="color: #de00d0;">"File opening error!"</span>);
}
<span style="color: blue;">void</span> main(){
setup_oscillator(OSC_8MHZ); <span style="color: #7e7e7e;">// Set internal oscillator to 8MHz</span>
set_tris_d(0); <span style="color: #7e7e7e;">// Configure PORTD pins as outputs</span>
delay_ms(2000);
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
printf(<span style="color: #de00d0;">"*** Read text file from FAT16 SD card using PIC16F887 ***"</span>);
delay_ms(2000);
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
printf(<span style="color: #de00d0;">"Initializing FAT16 library ...... "</span>);
<span style="color: blue;">if</span>(fat16_init() == 0){ <span style="color: #7e7e7e;">// If FAT16 file system and SD card were successfully initialized</span>
printf(<span style="color: #de00d0;">"OK!"</span>);
delay_ms(2000);
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
printf(<span style="color: #de00d0;">"Opening file: 'mytext.txt'...... "</span>);
open_file();
}
<span style="color: blue;">else</span> { <span style="color: #7e7e7e;">// Problem occured while the initialization</span>
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
printf(<span style="color: #de00d0;">"Initialization error!"</span>);
}
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
printf(<span style="color: #de00d0;">"*** END ***"</span>);
<span style="color: blue;">while</span>(TRUE) ; <span style="color: #7e7e7e;">// Endless loop</span>
}
</pre>
After finishing the project, I got a result similar to the one shown in the video below where the used microcontroller is PIC16F877A.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/IzCcHJk1NHM/0.jpg" src="https://www.youtube.com/embed/IzCcHJk1NHM?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-36569414176501458672017-09-05T09:35:00.000+02:002017-09-20T23:15:30.235+02:00MMC/SD Card raw data read with PIC16F887 microcontroller<div style="text-align: center;">
<span style="font-size: 30px;">Interfacing MMC/SD card with PIC16F887</span></div>
This small example shows how to read SD card raw data (bytes, sectors ...). SD card raw data means that there is no use of system files like FAT16 or FAT32. Serial monitor is used to display the data after reading it and here the UART protocol is used.<br />
the link below shows a small PIC16F887 MCU UART example:<br />
<a href="http://ccspicc.blogspot.com/2017/08/rs232-uart-example-pic16f887.html" target="_blank">UART Example for PIC16F887 microcontroller using CCS PIC C compiler</a><br />
In this project I used the MMC/SD card driver for CCS C compiler which is described in the post at the link below:<br />
<a href="http://ccspicc.blogspot.com/2017/08/mmc-sd-card-driver-for-ccs-compiler.html" target="_blank">MMC/SD Card driver for CCS PIC C compiler</a><br />
The PIC16F887 MCU has only 368 bytes of data RAM which
means that it is not possible to load an entire sector of
512 bytes. That means we can't write byte or sector correctly with this
microcontroller unless an external component is added to the circuit
such as external EEPROM which of course slows the writing process. But
reading is not like writing, we can read all the SD card data byte by
byte.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC16F887 microcontroller</li>
<li>SD Card</li>
<li>AMS1117 3.3V voltage regulator</li>
<li>3 x 3.3K ohm resistor</li>
<li>3 x 2.2K ohm resistor</li>
<li>10K ohm resistor</li>
<li>5 x 10uF polarized capacitor</li>
<li>100nF ceramic capacitor</li>
<li>MAX232 chip</li>
<li>Female COM port</li>
<li>5V Power source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">Interfacing SD card with PIC16F887 MCU circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKfcPxK5L_FKFTkdctWdTaTwLZovvnDEcoZ4ZIPAKpMUXbXy1tfFBZmzEI6mSljhdVchjPeAqA1fulZnNWrDjckLMXJBImRKwQITOS2sy755D8cbRJqIQqa2ry8YbxlSA57wPhV2MG6Sg/s1600/interfacing+pic16f887+mmc+sd+card.png" imageanchor="1"><img alt="Interfacing PIC16F887 with SD card circuit" border="0" height="398" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKfcPxK5L_FKFTkdctWdTaTwLZovvnDEcoZ4ZIPAKpMUXbXy1tfFBZmzEI6mSljhdVchjPeAqA1fulZnNWrDjckLMXJBImRKwQITOS2sy755D8cbRJqIQqa2ry8YbxlSA57wPhV2MG6Sg/s640/interfacing+pic16f887+mmc+sd+card.png" title="Interfacing PIC16F887 with SD card circuit" width="640" /></a></div>
<br />
The AMS1117 3.3V voltage regulator is used to supply the SD card with
3.3V. Also 3 voltage dividers are used to step down the 5V which comes
from the microcontroller to about 3V which is sufficient for the SD
card. Each voltage divider consists of 2K2 and 3K3 resistors.<br />
MAX232
integrated circuit is used to interface the microcontroller with the
PC, I connected just one wire (RD2) because I need to transmit data from
the SD card to the microcontroller and then from the microcontroller to
the PC, there is no need to connect the second wire because I don't
have to send data from the PC to the microcontroller.<br />
Hardware SPI module is used by the microcontroller to read data from the SD card, the SPI pins of the PIC16F887 are:<br />
<ul>
<li>SCK (RC3): connected to pin SCK of the SD card</li>
<li>SDI (RC4): connected to pin MISO of the SD card</li>
<li>SD0 (RC5): connected to pin MOSI of the SD card </li>
</ul>
and there is an other pin which is CS (Chip Select) can be
connected to any digital output pin (defined in the code), this pin is
connected to SS pin of the SD card.<br />
<span style="color: #cc0000;"><span style="font-size: large;">SD Card raw data read using PIC16F887 CCS C code:</span></span><br />
The C code below was tested with CCS PIC C compiler version 5.051.<br />
There are two functions in the code:<span style="background-color: yellow;"> sdcard_read_byte</span> and <span style="background-color: yellow;">sdcard_read_data</span>.
I used the first function to read byte with address 0 and I used the
second function to read sector number 0. Since the PIC16F887 has only
368 bytes of RAM, I can not upload all the sector data (512 bytes) in
one time, I divided the sector into 16 32-byte parts, so 16 x 32 = 512.
The <span style="background-color: yellow;">sdcard_read_data</span> function allows us to read data from the SD card starting from any address with any size we want.<br />
The functions<span style="background-color: yellow;"> sdcard_init</span> , <span style="background-color: yellow;">sdcard_read_byte</span> and <span style="background-color: yellow;">sdcard_read_data</span> return 0 if OK and non-zero if an error has been occurred. <br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">// Interfacing PIC16F887 microcontroller with SD card CCS C code.</span>
<span style="color: #7e7e7e;">// This example shows raw data read of the SD card.</span>
<span style="color: #7e7e7e;">// This example does not use any file system (FAT16, FAT32 ...).</span>
<span style="color: #7e7e7e;">// MMC/SD card driver for CCS C compiler must be installed!</span>
<span style="color: #7e7e7e;">// http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;">// electronnote@gmail.com</span>
<span style="color: #7e7e7e;">// SD Card module connections</span>
<span style="color: red;">#define</span> SDCARD_SPI_HW <span style="color: #7e7e7e;">// Hardware SPI module is used for the SD card</span>
<span style="color: red;">#define</span> SDCARD_PIN_SELECT PIN_D3 <span style="color: #7e7e7e;">// SD card chip select pin is connected to pin RD3</span>
<span style="color: #7e7e7e;">// End SD card module connections</span>
<span style="color: red;">#include</span> <16F887.h>
<span style="color: red;">#fuses</span> NOMCLR, INTRC_IO, NOBROWNOUT, NOLVP
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 8MHz)
<span style="color: red;">#use</span> rs232(xmit = PIN_D2, rcv = PIN_D1, baud = 9600)
<span style="color: red;">#include</span> <sdcard.c> <span style="color: #7e7e7e;">// SD card diver source file</span>
<span style="color: blue;">int8</span> i, j, one_byte, _data[32], <span style="color: blue;">size</span> = 32;
<span style="color: blue;">void</span> main(){
setup_oscillator(OSC_8MHZ); <span style="color: #7e7e7e;">// Set internal oscillator to 8MHz</span>
set_tris_d(0); <span style="color: #7e7e7e;">// Configure PORTD pins as outputs</span>
delay_ms(2000);
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
printf(<span style="color: #de00d0;">"*** Interfacing PIC16F887 MCU with SD card ***"</span>);
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
printf(<span style="color: #de00d0;">"Initializing the SD card..."</span>);
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
i = sdcard_init(); <span style="color: #7e7e7e;">// Initialize the SD card module</span>
<span style="color: blue;">if</span>(i == 0){ <span style="color: #7e7e7e;">// If the SD card has been successfully initialized</span>
<span style="color: #7e7e7e;">// Read 1 single byte</span>
printf(<span style="color: #de00d0;">"Read byte with address 0:"</span>);
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
delay_ms(2000);
<span style="color: blue;">if</span>(sdcard_read_byte(0, &one_byte) == 0)
printf(<span style="color: #de00d0;">"%X\n\r"</span>, one_byte); <span style="color: #7e7e7e;">// Print the value of 'one_byte'</span>
<span style="color: #7e7e7e;">// Read 1 sector</span>
printf(<span style="color: #de00d0;">"Read sector 0:"</span>); <span style="color: #7e7e7e;">// Sector 0 from address 0 to 511 (512 bytes)</span>
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
delay_ms(2000);
<span style="color: blue;">for</span>( i = 0; i < 16; i++){
<span style="color: blue;">if</span>(sdcard_read_data((<span style="color: blue;">int32</span>)i * <span style="color: blue;">size</span>, <span style="color: blue;">size</span>, _data) == 0){
<span style="color: blue;">for</span>(j = 0; j < 32; j++)
printf(<span style="color: #de00d0;">"%X"</span>, _data[j]); <span style="color: #7e7e7e;">// Print 32 byte of data</span>
}
}
}
<span style="color: #7e7e7e;">// End</span>
printf(<span style="color: #de00d0;">"\n\r"</span>); <span style="color: #7e7e7e;">// Start new line</span>
printf(<span style="color: #de00d0;">"*** END ***"</span>);
<span style="color: blue;">while</span>(TRUE) ; <span style="color: #7e7e7e;">// Endless loop</span>
}
</pre>
After compiling the code and burning the HEX file into the
microcontroller and with the help of the Serial Monitor of the CCS C IDE
I got the result shown in the image below (I used a SD card with 2 GB).<br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhgNLJIM82540LYaBa0llfY4-jHBA2ih2zz2uzUPDhtdpk1Ts5J1b-Kmt1s3qD9YihqwB-OI4ei54wIMC58N-dCz8HTXIjy1taVr1C73l1f7Sofq-faPeRM0gszI6r92tB-imW6ptpL24/s1600/pic16f887+sd+card+output+serial+monitor.png" imageanchor="1"><img alt="SD card read raw dat output using PIC16F887 and CCS C serial monitor" border="0" height="451" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhgNLJIM82540LYaBa0llfY4-jHBA2ih2zz2uzUPDhtdpk1Ts5J1b-Kmt1s3qD9YihqwB-OI4ei54wIMC58N-dCz8HTXIjy1taVr1C73l1f7Sofq-faPeRM0gszI6r92tB-imW6ptpL24/s640/pic16f887+sd+card+output+serial+monitor.png" title="SD card read raw dat output using PIC16F887 and CCS C serial monitor" width="640" /></a></div>
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-43428077047674275892017-09-04T19:19:00.000+02:002018-06-03T19:22:27.189+02:00Real time clock with 2 alarms using PIC18F4550 and DS3231<div style="text-align: center;">
<span style="font-size: 30px;">Real time clock with 2 alarms and temperature sensing using PIC18F4550 and DS3231</span></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgakiUDTbTxfyWZpv4gn7f9HqmWdEqLH9dDa4bqIl0ykIA51Q9Qrt-y-Fg9MI4fvElXZ_vqsSFUcLa5m488mVk-JMsTUmp2AmkXgNLqYQ5FcIor8o9Tb0UA2XyCGtvkNhmNZqXOCXofFUg/s1600/DS3231+with+alarm+PIC18F4550+hardware+circuit.JPG" imageanchor="1"><img alt="Real time clock with 2 alarms using PIC18F4550 and DS3231 hardware circuit" border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgakiUDTbTxfyWZpv4gn7f9HqmWdEqLH9dDa4bqIl0ykIA51Q9Qrt-y-Fg9MI4fvElXZ_vqsSFUcLa5m488mVk-JMsTUmp2AmkXgNLqYQ5FcIor8o9Tb0UA2XyCGtvkNhmNZqXOCXofFUg/s640/DS3231+with+alarm+PIC18F4550+hardware+circuit.JPG" title="Real time clock with 2 alarms using PIC18F4550 and DS3231 hardware circuit" width="640" /></a> </div>
After the simple interfacing of the PIC18F4550 microcontroller with the DS3231 RTC, now let's add the alarms functionality and temperature monitor to our previous project.<br />
Interfacing PIC18F4550 with DS3231 project link:<br />
<a href="https://ccspicc.blogspot.com/2017/08/pic18f4550-ds3231-rtcc.html" target="_blank">Real time clock & calendar with PIC18F4550 and DS3231</a><br />
As written in the datasheet the DS3231 RTC has a built-in 2 alarm functions and a digital temperature sensor with an accuracy of ±3°C.<br />
<script async="" src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<ins class="adsbygoogle" data-ad-client="ca-pub-9821904216837075" data-ad-format="fluid" data-ad-layout="in-article" data-ad-slot="9358819745" style="display: block; text-align: center;"></ins><script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required: </span></span><br />
<ul>
<li>PIC18F4550 microcontroller</li>
<li>20x4 LCD screen</li>
<li>10K ohm variable resistor</li>
<li>330 ohm resistor</li>
<li>LED</li>
<li>3 x push button</li>
<li>5V supply source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
DS3231 board contains the following components:<br />
<ul>
<li>DS3231 RTC - <a href="https://datasheets.maximintegrated.com/en/ds/DS3231.pdf" target="_blank"><i>datasheet</i></a></li>
<li>3 x 4.7K ohm resistors</li>
<li>0.1uF ceramic capacitor</li>
<li>3V coin cell battery</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">The circuit:</span></span><br />
Project circuit diagram is shown below.<br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKZfHxZS6Jg2TzhndLQTi7AZT-dZ8BxRKRN-KQH-92zCkj5mWhyngxXLUW_9tAon1uTYmkBBMcuRiW1LUbAb8VP3tPTGARrINFofk7EnOe_h1ij3MmPWGJ-N6-oaHrPTF6sRLTa8Nd8FQ/s1600/ds3231-real-time-clock-calendar-alarm-temperature-pic18f4550-circuit.png" imageanchor="1"><img alt="PIC18F4550 MCU and DS3231 real time clock with two alarms and temperature monitor circuit" border="0" height="454" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKZfHxZS6Jg2TzhndLQTi7AZT-dZ8BxRKRN-KQH-92zCkj5mWhyngxXLUW_9tAon1uTYmkBBMcuRiW1LUbAb8VP3tPTGARrINFofk7EnOe_h1ij3MmPWGJ-N6-oaHrPTF6sRLTa8Nd8FQ/s640/ds3231-real-time-clock-calendar-alarm-temperature-pic18f4550-circuit.png" title="PIC18F4550 MCU and DS3231 real time clock with two alarms and temperature monitor circuit" width="640" /></a></div>
To simplify the circuit, I used the DS3231 board, this board
basically contains the main chip which is the DS3231, pull-up resistors
(4.7K) of SCL, SDA and INT/SQW lines and coin cell battery holder. There
is also 24C32 EEPROM and some other resistors (not used in this
project).<br />
The DS3231 board is supplied with 5V as the
microcontroller and the 2004 LCD, there are 3 data lined connected
between this board and the PIC18F4550 MCU, SCL line is connected to pin RB1, SDA
is connected to pin RB0 and INT line is connected to pin RB2 which is the
external interrupt 2 pin of the PIC18F4550 MCU. The DS3231 interrupts the
microcontroller when there is an alarm.<br />
In the circuit there are 3
push buttons: B1, B2 and B3. These buttons are used to set time,
calendar and alarms. Time and calendar can be adjusted with B1 and B2,
button B1 selects time or date parameter (time parameters: hours and
minutes; calendar parameters: day, date, month and year) and B2
increments the selected parameter. The button B3 and B2 adjust alarm1
and alarm2 parameters (hours, minutes and ON/OFF), button B3 selects the
parameter and B2 increments the selected parameter.<br />
There is an
LED connected to pin RB6, this LED is used as an alarm indicator (alarm1 or alarm2), so if
there is an alarm the DS3231 pulls down the INT pin which interrupts the
microcontroller and the microcontroller turns the LED ON, here button
B2 turns both the LED and the occurred alarm OFF.<br />
In this project the PIC18F4550 MCU uses its internal oscillator and MCLR pin function is disabled.<br />
<span style="color: #e06666;"><span style="font-size: large;">CCS C code:</span></span><br />
The C code below was tested with CCS C compiler version 5.051.<br />
By reading the datasheet of the DS3231 RTC the code will be more easier!<br />
The hardware I2C module of the MCU is initialized and configured using the following CCS C function with a speed of 100KHz:<br />
<span style="background-color: yellow;">#use I2C(master, I2C1, FAST = 100000)</span><br />
<div class="Style1" style="margin-right: 0px;">
master: set the microcontroller to the master mode</div>
I2C1: use first I2C module.<br />
The DS3231 works with BCD format only (except temperature) and to convert the BCD to
decimal and vise versa I used the following functions (example for minute
variable):<br />
<span style="background-color: yellow;">minute = (minute >> 4) * 10 + (minute & 0x0F);</span> // Convert BCD to decimal<br />
<span style="background-color: yellow;">minute = ((minute / 10) << 4) + (minute % 10); </span> // Convert decimal to BCD<u> </u><br />
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- ccslink1 -->
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-9821904216837075"
data-ad-slot="2075108943"
data-ad-format="link"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
<br/>
<u>Code functions:</u><br />
<span style="background-color: yellow;">void DS3231_read() :</span> this function reads time and calendar data from the DS3231 (seconds, minutes, hours, day, date, month and year).<br />
<span style="background-color: yellow;">void DS3231_display() :</span>
displays time and calendar data, before displaying time and calendar
data are converted from BCD format to decimal format. This function
displays the calendar by calling a function named <span style="background-color: yellow;">void calendar_display()</span> .<br />
<span style="background-color: yellow;">void alarms_read_display() :</span>
basically this functions reads alarm1 and alarm2 minutes and hours. It
also reads the DS3231 control register, status register and 2
temperature registers.<br />
The other job of this function is to
display alarms data (hours, minutes and status) and the temperature
value. The alarm status are extracted from the control register.<br />
<span style="background-color: yellow;">int8 edit(parameter, x, y) :</span> I used this function to edit time, calendar and alarm parameters except the day. I used a variable named<span style="background-color: yellow;"> i </span>to distinguish between the parameters:<br />
i = 0, 1 : time hours and minutes respectively<br />
i = 2, 3, 4: date month, year respectively<br />
i = 5, 6: alarms hours and minutes respectively<br />
i = 7: alarms status (ON or OFF)<br />
After the edit of time/calendar/alarms the data have to be converted back to BCD format and written to the DS3231.<br />
The
MCU turns the LED ON when it interrupted by the DS3231, the DS3231
sends the interrupt signal (pulls down the INT line) when there has been
an alarm. Button B2 resets and turns OFF the alarm. If both alarms are
active, button B2 will resets and turns OFF the occurred alarm only and
keeps the other as it is. To do that we've to detect which alarm was
occurred which can be easily done by reading the status register of the
DS3231 (A1IF and A2IF flag bits). Turning ON or OFF an alarm is done by
writing to the control register (bits: INTCN, A1IE and A2IE). Always
INTCN bit should be 1. I used the following line to write 1 to the INTCN
bit and to turn OFF the occurred alarm:<br />
<span style="background-color: yellow;">i2c_write(4 | (!bit_test(status_reg, 0) & alarm1_status) | ((!bit_test(status_reg, 1) & alarm2_status) << 1));</span><br />
alarm1_status
and alarm2_status are 1-bit variables, for example if alarm1_status is 1
==> alarm1 is ON and if alarm1_status is 0 ==> alarm1 is OFF.
The same thing for alarm2.<br />
The complete C code is below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">/* Real time clock and calendar with 2 alarms and temperature sensing using</span>
<span style="color: #7e7e7e;"> PIC18F4550 MCU & DS3231 CCS C code.</span>
<span style="color: #7e7e7e;"> Read DS3231 RTC datasheet to understand the code!</span>
<span style="color: #7e7e7e;"> Time & date parameters can be set using two push buttons connected to pins RB3 & RB4.</span>
<span style="color: #7e7e7e;"> Alarm1 and alarm2 can be set using buttons connected to pins RB5 and RB4.</span>
<span style="color: #7e7e7e;"> Pin RB6 becmoes high when an alarm occured and button RB4 returns it to low and</span>
<span style="color: #7e7e7e;"> turns the occurred alarm OFF.</span>
<span style="color: #7e7e7e;"> DS3231 interrupt pin is connected to PIC18F4550 external interrupt 2 pin (RB2).</span>
<span style="color: #7e7e7e;"> http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;"> electronnote@gmail.com</span>
<span style="color: #7e7e7e;">*/</span>
<span style="color: #7e7e7e;">// LCD module connections</span>
<span style="color: red;">#define</span> LCD_RS_PIN PIN_D0
<span style="color: red;">#define</span> LCD_RW_PIN PIN_D1
<span style="color: red;">#define</span> LCD_ENABLE_PIN PIN_D2
<span style="color: red;">#define</span> LCD_DATA4 PIN_D3
<span style="color: red;">#define</span> LCD_DATA5 PIN_D4
<span style="color: red;">#define</span> LCD_DATA6 PIN_D5
<span style="color: red;">#define</span> LCD_DATA7 PIN_D6
<span style="color: #7e7e7e;">// End LCD module connections</span>
<span style="color: red;">#include</span> <18F4550.h>
<span style="color: red;">#fuses</span> NOMCLR, INTRC_IO, NOWDT,NOPROTECT,NOLVP
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 8000000)
<span style="color: red;">#include</span> <lcd.c>
<span style="color: red;">#use</span> fast_io(B)
<span style="color: red;">#use</span> fast_io(D)
<span style="color: red;">#use</span> I2C(master, I2C1, FAST = 100000)
<span style="color: blue;">int1</span> alarm1_status, alarm2_status;
<span style="color: blue;">char</span> time[] = <span style="color: #de00d0;">" : : "</span>,
calendar[] = <span style="color: #de00d0;">" / /20 "</span>,
alarm1[] = <span style="color: #de00d0;">"A1: : :00"</span>, alarm2[] = <span style="color: #de00d0;">"A2: : :00"</span>,
temperature[] = <span style="color: #de00d0;">"T: . C"</span>;
<span style="color: blue;">int8</span> i, second, minute, hour, day, date, month, year,
alarm1_minute, alarm1_hour, alarm2_minute, alarm2_hour,
status_reg;
<span style="color: red;">#INT_EXT2</span> <span style="color: #7e7e7e;">// External interrupt routine</span>
<span style="color: blue;">void</span> ext2_isr(<span style="color: blue;">void</span>){
output_high(PIN_B6);
clear_interrupt(INT_EXT2);
}
<span style="color: blue;">void</span> DS3231_read(){ <span style="color: #7e7e7e;">// Read time & calendar data function</span>
i2c_start(); <span style="color: #7e7e7e;">// Start I2C protocol</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(0); <span style="color: #7e7e7e;">// Send register address (seconds register)</span>
i2c_start(); <span style="color: #7e7e7e;">// Restart I2C</span>
i2c_write(0xD1); <span style="color: #7e7e7e;">// Initialize data read</span>
second = i2c_read(1); <span style="color: #7e7e7e;">// Read seconds from register 0</span>
minute = i2c_read(1); <span style="color: #7e7e7e;">// Read minuts from register 1</span>
hour = i2c_read(1); <span style="color: #7e7e7e;">// Read hour from register 2</span>
day = i2c_read(1); <span style="color: #7e7e7e;">// Read day from register 3</span>
date = i2c_read(1); <span style="color: #7e7e7e;">// Read date from register 4</span>
month = i2c_read(1); <span style="color: #7e7e7e;">// Read month from register 5</span>
year = i2c_read(0); <span style="color: #7e7e7e;">// Read year from register 6</span>
i2c_stop(); <span style="color: #7e7e7e;">// Stop I2C protocol</span>
}
<span style="color: blue;">void</span> alarms_read_display(){ <span style="color: #7e7e7e;">// Read and display alarm1 and alarm2 data function</span>
<span style="color: blue;">int8</span> control_reg, temperature_lsb;
<span style="color: blue;">signed</span> <span style="color: blue;">int8</span> temperature_msb;
i2c_start(); <span style="color: #7e7e7e;">// Start I2C protocol</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(0x08); <span style="color: #7e7e7e;">// Send register address (alarm1 minutes register)</span>
i2c_start(); <span style="color: #7e7e7e;">// Restart I2C</span>
i2c_write(0xD1); <span style="color: #7e7e7e;">// Initialize data read</span>
alarm1_minute = i2c_read(1); <span style="color: #7e7e7e;">// Read alarm1 minutes</span>
alarm1_hour = i2c_read(1); <span style="color: #7e7e7e;">// Read alarm1 hours</span>
i2c_read(1); <span style="color: #7e7e7e;">// Skip alarm1 day/date register</span>
alarm2_minute = i2c_read(1); <span style="color: #7e7e7e;">// Read alarm2 minutes</span>
alarm2_hour = i2c_read(1); <span style="color: #7e7e7e;">// Read alarm2 hours</span>
i2c_read(1); <span style="color: #7e7e7e;">// Skip alarm2 day/date register</span>
control_reg = i2c_read(1); <span style="color: #7e7e7e;">// Read the DS3231 control register</span>
status_reg = i2c_read(1); <span style="color: #7e7e7e;">// Read the DS3231 status register</span>
i2c_read(1); <span style="color: #7e7e7e;">// Skip aging offset resgister</span>
temperature_msb = i2c_read(1); <span style="color: #7e7e7e;">// Read temperature MSB</span>
temperature_lsb = i2c_read(0); <span style="color: #7e7e7e;">// Read temperature LSB</span>
i2c_stop(); <span style="color: #7e7e7e;">// Stop I2C protocol</span>
<span style="color: #7e7e7e;">// Convert BCD to decimal</span>
alarm1_minute = (alarm1_minute >> 4) * 10 + (alarm1_minute & 0x0F);
alarm1_hour = (alarm1_hour >> 4) * 10 + (alarm1_hour & 0x0F);
alarm2_minute = (alarm2_minute >> 4) * 10 + (alarm2_minute & 0x0F);
alarm2_hour = (alarm2_hour >> 4) * 10 + (alarm2_hour & 0x0F);
<span style="color: #7e7e7e;">// End conversion</span>
alarm1[8] = alarm1_minute % 10 + 48;
alarm1[7] = alarm1_minute / 10 + 48;
alarm1[5] = alarm1_hour % 10 + 48;
alarm1[4] = alarm1_hour / 10 + 48;
alarm2[8] = alarm2_minute % 10 + 48;
alarm2[7] = alarm2_minute / 10 + 48;
alarm2[5] = alarm2_hour % 10 + 48;
alarm2[4] = alarm2_hour / 10 + 48;
alarm1_status = bit_test(control_reg, 0); <span style="color: #7e7e7e;">// Read alarm1 interrupt enable bit (A1IE) from DS3231 control register</span>
alarm2_status = bit_test(control_reg, 1); <span style="color: #7e7e7e;">// Read alarm2 interrupt enable bit (A2IE) from DS3231 control register</span>
<span style="color: blue;">if</span>(temperature_msb < 0){
temperature_msb = <span style="color: blue;">abs</span>(temperature_msb);
temperature[2] = <span style="color: #de00d0;">'-'</span>;
}
<span style="color: blue;">else</span>
temperature[2] = <span style="color: #de00d0;">' '</span>;
<span style="color: blue;">if</span>(temperature_msb > 99)
temperature[2] = <span style="color: #de00d0;">'1'</span>;
temperature_lsb >>= 6;
temperature[4] = temperature_msb % 10 + 48;
temperature[3] = (temperature_msb / 10) % 10 + 48;
<span style="color: blue;">if</span>(temperature_lsb == 0 || temperature_lsb == 2){
temperature[7] = <span style="color: #de00d0;">'0'</span>;
<span style="color: blue;">if</span>(temperature_lsb == 0) temperature[6] = <span style="color: #de00d0;">'0'</span>;
<span style="color: blue;">else</span> temperature[6] = <span style="color: #de00d0;">'5'</span>;
}
<span style="color: blue;">if</span>(temperature_lsb == 1 || temperature_lsb == 3){
temperature[7] = <span style="color: #de00d0;">'5'</span>;
<span style="color: blue;">if</span>(temperature_lsb == 1) temperature[6] = <span style="color: #de00d0;">'2'</span>;
<span style="color: blue;">else</span> temperature[6] = <span style="color: #de00d0;">'7'</span>;
}
temperature[8] = 223; <span style="color: #7e7e7e;">// Degree symbol</span>
lcd_gotoxy(11, 1); <span style="color: #7e7e7e;">// Go to column 10 row 1</span>
printf(lcd_putc, temperature); <span style="color: #7e7e7e;">// Display temperature</span>
lcd_gotoxy(21, 1); <span style="color: #7e7e7e;">// Go to column 1 row 3</span>
printf(lcd_putc, alarm1); <span style="color: #7e7e7e;">// Display alarm1</span>
lcd_gotoxy(38, 1); <span style="color: #7e7e7e;">// Go to column 18 row 3</span>
<span style="color: blue;">if</span>(alarm1_status) lcd_putc(<span style="color: #de00d0;">"ON "</span>); <span style="color: #7e7e7e;">// If A1IE = 1 print 'ON'</span>
<span style="color: blue;">else</span> lcd_putc(<span style="color: #de00d0;">"OFF"</span>); <span style="color: #7e7e7e;">// If A1IE = 0 print 'OFF'</span>
lcd_gotoxy(21, 2); <span style="color: #7e7e7e;">// Go to column 1 row 4</span>
printf(lcd_putc, alarm2); <span style="color: #7e7e7e;">// Display alarm2</span>
lcd_gotoxy(38, 2); <span style="color: #7e7e7e;">// Go to column 18 row 4</span>
<span style="color: blue;">if</span>(alarm2_status) lcd_putc(<span style="color: #de00d0;">"ON "</span>); <span style="color: #7e7e7e;">// If A2IE = 1 print 'ON'</span>
<span style="color: blue;">else</span> lcd_putc(<span style="color: #de00d0;">"OFF"</span>); <span style="color: #7e7e7e;">// If A2IE = 0 print 'OFF'</span>
}
<span style="color: blue;">void</span> calendar_display(){ <span style="color: #7e7e7e;">// Display calendar function</span>
<span style="color: blue;">switch</span>(day){
<span style="color: blue;">case</span> 1: strcpy(calendar, <span style="color: #de00d0;">"Sun / /20 "</span>); <span style="color: blue;">break</span>;
<span style="color: blue;">case</span> 2: strcpy(calendar, <span style="color: #de00d0;">"Mon / /20 "</span>); <span style="color: blue;">break</span>;
<span style="color: blue;">case</span> 3: strcpy(calendar, <span style="color: #de00d0;">"Tue / /20 "</span>); <span style="color: blue;">break</span>;
<span style="color: blue;">case</span> 4: strcpy(calendar, <span style="color: #de00d0;">"Wed / /20 "</span>); <span style="color: blue;">break</span>;
<span style="color: blue;">case</span> 5: strcpy(calendar, <span style="color: #de00d0;">"Thu / /20 "</span>); <span style="color: blue;">break</span>;
<span style="color: blue;">case</span> 6: strcpy(calendar, <span style="color: #de00d0;">"Fri / /20 "</span>); <span style="color: blue;">break</span>;
<span style="color: blue;">case</span> 7: strcpy(calendar, <span style="color: #de00d0;">"Sat / /20 "</span>); <span style="color: blue;">break</span>;
<span style="color: blue;">default</span>: strcpy(calendar, <span style="color: #de00d0;">"Sat / /20 "</span>); <span style="color: blue;">break</span>;
}
calendar[13] = year % 10 + 48;
calendar[12] = year / 10 + 48;
calendar[8] = month % 10 + 48;
calendar[7] = month / 10 + 48;
calendar[5] = date % 10 + 48;
calendar[4] = date / 10 + 48;
lcd_gotoxy(1, 2); <span style="color: #7e7e7e;">// Go to column 1 row 2</span>
printf(lcd_putc, calendar); <span style="color: #7e7e7e;">// Display calendar</span>
}
<span style="color: blue;">void</span> DS3231_display(){
<span style="color: #7e7e7e;">// Convert BCD to decimal</span>
second = (second >> 4) * 10 + (second & 0x0F);
minute = (minute >> 4) * 10 + (minute & 0x0F);
hour = (hour >> 4) * 10 + (hour & 0x0F);
date = (date >> 4) * 10 + (date & 0x0F);
month = (month >> 4) * 10 + (month & 0x0F);
year = (year >> 4) * 10 + (year & 0x0F);
<span style="color: #7e7e7e;">// End conversion</span>
time[7] = second % 10 + 48;
time[6] = second / 10 + 48;
time[4] = minute % 10 + 48;
time[3] = minute / 10 + 48;
time[1] = hour % 10 + 48;
time[0] = hour / 10 + 48;
calendar_display(); <span style="color: #7e7e7e;">// Call calendar display function</span>
lcd_gotoxy(1, 1); <span style="color: #7e7e7e;">// Go to column 1 row 1</span>
printf(lcd_putc, time); <span style="color: #7e7e7e;">// Display time</span>
}
<span style="color: blue;">void</span> <span style="color: blue;">blink</span>(){
<span style="color: blue;">int8</span> j = 0;
<span style="color: blue;">while</span>(j < 10 && (input(PIN_B3) || i >= 5) && input(PIN_B4) && (input(PIN_B5) || i < 5)){
j++;
delay_ms(25);
}
}
<span style="color: blue;">int8</span> edit(parameter, x, y){
<span style="color: blue;">while</span>(!input(PIN_B3) || !input(PIN_B5)); <span style="color: #7e7e7e;">// Wait until button RB0 is released</span>
<span style="color: blue;">while</span>(TRUE){
<span style="color: blue;">while</span>(!input(PIN_B4)){ <span style="color: #7e7e7e;">// If button RB2 is pressed</span>
parameter++;
<span style="color: blue;">if</span>(((i == 0) || (i == 5)) && parameter > 23) <span style="color: #7e7e7e;">// If hours > 23 ==> hours = 0</span>
parameter = 0;
<span style="color: blue;">if</span>(((i == 1) || (i == 6)) && parameter > 59) <span style="color: #7e7e7e;">// If minutes > 59 ==> minutes = 0</span>
parameter = 0;
<span style="color: blue;">if</span>(i == 2 && parameter > 31) <span style="color: #7e7e7e;">// If date > 31 ==> date = 1</span>
parameter = 1;
<span style="color: blue;">if</span>(i == 3 && parameter > 12) <span style="color: #7e7e7e;">// If month > 12 ==> month = 1</span>
parameter = 1;
<span style="color: blue;">if</span>(i == 4 && parameter > 99) <span style="color: #7e7e7e;">// If year > 99 ==> year = 0</span>
parameter = 0;
<span style="color: blue;">if</span>(i == 7 && parameter > 1) <span style="color: #7e7e7e;">// For alarms ON or OFF (1: alarm ON, 0: alarm OFF)</span>
parameter = 0;
lcd_gotoxy(x, y);
<span style="color: blue;">if</span>(i == 7){ <span style="color: #7e7e7e;">// For alarms ON & OFF</span>
<span style="color: blue;">if</span>(parameter == 1) lcd_putc(<span style="color: #de00d0;">"ON "</span>);
<span style="color: blue;">else</span> lcd_putc(<span style="color: #de00d0;">"OFF"</span>);
}
<span style="color: blue;">else</span>
printf(lcd_putc,<span style="color: #de00d0;">"%02u"</span>, parameter); <span style="color: #7e7e7e;">// Display parameter</span>
<span style="color: blue;">if</span>(i >= 5){
DS3231_read(); <span style="color: #7e7e7e;">// Read data from DS3231</span>
DS3231_display(); <span style="color: #7e7e7e;">// Display DS3231 time and calendar</span>
}
delay_ms(200); <span style="color: #7e7e7e;">// Wait 200ms</span>
}
lcd_gotoxy(x, y); <span style="color: #7e7e7e;">// Go to LCD x coloumn and y row</span>
lcd_putc(<span style="color: #de00d0;">" "</span>); <span style="color: #7e7e7e;">// Print two spaces</span>
<span style="color: blue;">if</span>(i == 7) lcd_putc(<span style="color: #de00d0;">" "</span>); <span style="color: #7e7e7e;">// Print space (for alarms ON & OFF)</span>
<span style="color: blue;">blink</span>(); <span style="color: #7e7e7e;">// Call blink function</span>
lcd_gotoxy(x, y); <span style="color: #7e7e7e;">// Go to LCD x coloumn and y row</span>
<span style="color: blue;">if</span>(i == 7){ <span style="color: #7e7e7e;">// For alarms ON & OFF</span>
<span style="color: blue;">if</span>(parameter == 1) lcd_putc(<span style="color: #de00d0;">"ON "</span>);
<span style="color: blue;">else</span> lcd_putc(<span style="color: #de00d0;">"OFF"</span>);
}
<span style="color: blue;">else</span>
printf(lcd_putc,<span style="color: #de00d0;">"%02u"</span>, parameter); <span style="color: #7e7e7e;">// Display parameter</span>
<span style="color: blue;">blink</span>();
<span style="color: blue;">if</span>(i >= 5){
DS3231_read();
DS3231_display();}
<span style="color: blue;">if</span>((!input(PIN_B3) && i < 5) || (!input(PIN_B5) && i >= 5)){
i++; <span style="color: #7e7e7e;">// Increament 'i' for the next parameter</span>
<span style="color: blue;">return</span> parameter; <span style="color: #7e7e7e;">// Return parameter value and exit</span>
}
}
}
<span style="color: blue;">void</span> main(){
setup_oscillator(OSC_8MHZ); <span style="color: #7e7e7e;">// Set internal oscillator to 8MHz</span>
output_low(PIN_B6);
output_drive(PIN_B6); <span style="color: #7e7e7e;">// Configure pin RB6 as output</span>
set_tris_d(0); <span style="color: #7e7e7e;">// Configure PORTD pins as outputs</span>
port_b_pullups(TRUE); <span style="color: #7e7e7e;">// Enable PORTB internal pull-ups</span>
enable_interrupts(GLOBAL); <span style="color: #7e7e7e;">// Enable global interrupts</span>
enable_interrupts(INT_EXT2_H2L); <span style="color: #7e7e7e;">// Enable external interrupt with edge from high to low</span>
lcd_init(); <span style="color: #7e7e7e;">// Initialize LCD module</span>
lcd_putc(<span style="color: #de00d0;">'\f'</span>); <span style="color: #7e7e7e;">// LCD clear</span>
<span style="color: blue;">while</span>(TRUE){
<span style="color: blue;">if</span>(!input(PIN_B3)){ <span style="color: #7e7e7e;">// If RB1 button is pressed</span>
i = 0;
hour = edit(hour, 1, 1);
minute = edit(minute, 4, 1);
<span style="color: blue;">while</span>(!input(PIN_B3)); <span style="color: #7e7e7e;">// Wait until button RB0 released</span>
<span style="color: blue;">while</span>(TRUE){
<span style="color: blue;">while</span>(!input(PIN_B4)){ <span style="color: #7e7e7e;">// If button RB2 button is pressed</span>
day++; <span style="color: #7e7e7e;">// Increment day</span>
<span style="color: blue;">if</span>(day > 7) day = 1;
calendar_display(); <span style="color: #7e7e7e;">// Call display calendar</span>
lcd_gotoxy(1, 2); <span style="color: #7e7e7e;">// Go to column 1 row 2</span>
printf(lcd_putc, calendar); <span style="color: #7e7e7e;">// Display calendar</span>
delay_ms(200);
}
lcd_gotoxy(1, 2); <span style="color: #7e7e7e;">// Go to column 1 row 2</span>
lcd_putc(<span style="color: #de00d0;">" "</span>); <span style="color: #7e7e7e;">// Print 3 spaces</span>
<span style="color: blue;">blink</span>();
lcd_gotoxy(1, 2); <span style="color: #7e7e7e;">// Go to column 1 row 2</span>
printf(lcd_putc, calendar); <span style="color: #7e7e7e;">// Print calendar</span>
<span style="color: blue;">blink</span>(); <span style="color: #7e7e7e;">// Call blink function</span>
<span style="color: blue;">if</span>(!input(PIN_B3)) <span style="color: #7e7e7e;">// If button RB1 is pressed</span>
<span style="color: blue;">break</span>;
}
date = edit(date, 5, 2); <span style="color: #7e7e7e;">// Edit date</span>
month = edit(month, 8, 2); <span style="color: #7e7e7e;">// Edit month</span>
year = edit(year, 13, 2); <span style="color: #7e7e7e;">// Edit year</span>
<span style="color: #7e7e7e;">// Convert decimal to BCD</span>
minute = ((minute / 10) << 4) + (minute % 10);
hour = ((hour / 10) << 4) + (hour % 10);
date = ((date / 10) << 4) + (date % 10);
month = ((month / 10) << 4) + (month % 10);
year = ((year / 10) << 4) + (year % 10);
<span style="color: #7e7e7e;">// End conversion</span>
<span style="color: #7e7e7e;">// Write time & calendar data to DS3231 RTC</span>
i2c_start(); <span style="color: #7e7e7e;">// Start I2C protocol</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(0); <span style="color: #7e7e7e;">// Send register adderss (seconds address)</span>
i2c_write(0); <span style="color: #7e7e7e;">// Reset sesonds and start oscillator</span>
i2c_write(minute); <span style="color: #7e7e7e;">// Write minute value to DS3231</span>
i2c_write(hour); <span style="color: #7e7e7e;">// Write hour value to DS3231</span>
i2c_write(day); <span style="color: #7e7e7e;">// Write day value</span>
i2c_write(date); <span style="color: #7e7e7e;">// Write date value to DS3231</span>
i2c_write(month); <span style="color: #7e7e7e;">// Write month value to DS3231</span>
i2c_write(year); <span style="color: #7e7e7e;">// Write year value to DS3231</span>
i2c_stop(); <span style="color: #7e7e7e;">// Stop I2C</span>
delay_ms(200); <span style="color: #7e7e7e;">// Wait 200ms</span>
}
<span style="color: blue;">if</span>(!input(PIN_B5)){ <span style="color: #7e7e7e;">// If RB3 button is pressed</span>
<span style="color: blue;">while</span>(!input(PIN_B5)); <span style="color: #7e7e7e;">// Wait until button RB3 released</span>
i = 5;
alarm1_hour = edit(alarm1_hour, 25, 1);
alarm1_minute = edit(alarm1_minute, 28, 1);
alarm1_status = edit(alarm1_status, 38, 1);
i = 5;
alarm2_hour = edit(alarm2_hour, 25, 2);
alarm2_minute = edit(alarm2_minute, 28, 2);
alarm2_status = edit(alarm2_status, 38, 2);
alarm1_minute = ((alarm1_minute / 10) << 4) + (alarm1_minute % 10);
alarm1_hour = ((alarm1_hour / 10) << 4) + (alarm1_hour % 10);
alarm2_minute = ((alarm2_minute / 10) << 4) + (alarm2_minute % 10);
alarm2_hour = ((alarm2_hour / 10) << 4) + (alarm2_hour % 10);
<span style="color: #7e7e7e;">// Write alarms data to DS3231</span>
i2c_start(); <span style="color: #7e7e7e;">// Start I2C</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(7); <span style="color: #7e7e7e;">// Send register address (alarm1 seconds)</span>
i2c_write(0); <span style="color: #7e7e7e;">// Write 0 to alarm1 seconds</span>
i2c_write(alarm1_minute); <span style="color: #7e7e7e;">// Write alarm1 minutes value to DS3231</span>
i2c_write(alarm1_hour); <span style="color: #7e7e7e;">// Write alarm1 hours value to DS3231</span>
i2c_write(0x80); <span style="color: #7e7e7e;">// Alarm1 when hours, minutes, and seconds match</span>
i2c_write(alarm2_minute); <span style="color: #7e7e7e;">// Write alarm2 minutes value to DS3231</span>
i2c_write(alarm2_hour); <span style="color: #7e7e7e;">// Write alarm2 hours value to DS3231</span>
i2c_write(0x80); <span style="color: #7e7e7e;">// Alarm2 when hours and minutes match</span>
i2c_write(4 | alarm1_status | (alarm2_status << 1)); <span style="color: #7e7e7e;">// Write data to DS3231 control register (enable interrupt when alarm)</span>
i2c_write(0); <span style="color: #7e7e7e;">// Clear alarm flag bits</span>
i2c_stop(); <span style="color: #7e7e7e;">// Stop I2C</span>
delay_ms(200); <span style="color: #7e7e7e;">// Wait 200ms</span>
}
<span style="color: blue;">if</span>(!input(PIN_B4) && input(PIN_B6)){ <span style="color: #7e7e7e;">// When button B2 pressed with alarm (Reset and turn OFF the alarm)</span>
output_low(PIN_B6); <span style="color: #7e7e7e;">// Turn OFF the alarm indicator</span>
i2c_start(); <span style="color: #7e7e7e;">// Start I2C</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(0x0E); <span style="color: #7e7e7e;">// Send register address (control register)</span>
<span style="color: #7e7e7e;">// Write data to control register (Turn OFF the occurred alarm and keep the other as it is)</span>
i2c_write(4 | (!bit_test(status_reg, 0) & alarm1_status) | ((!bit_test(status_reg, 1) & alarm2_status) << 1));
i2c_write(0); <span style="color: #7e7e7e;">// Clear alarm flag bits</span>
i2c_stop(); <span style="color: #7e7e7e;">// Stop I2C</span>
}
DS3231_read(); <span style="color: #7e7e7e;">// Read time and calendar parameters from DS3231 RTC</span>
alarms_read_display(); <span style="color: #7e7e7e;">// Read and display alarms parameters</span>
DS3231_display(); <span style="color: #7e7e7e;">// Diaplay time & calendar</span>
delay_ms(50); <span style="color: #7e7e7e;">// Wait 50ms</span>
}
}
<span style="color: #7e7e7e;">// End of code</span>
</pre>
<span style="color: #cc0000;"><span style="font-size: large;">Video:</span></span><br />
After connecting the circuit and burning the HEX file into the MCU, I got the result shown similar to what's in the video below where the used microcontroller is PIC16F877A.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/QE5hjYRW410/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/QE5hjYRW410?feature=player_embedded" width="320"></iframe></div>
<div style="text-align: center;">
<br /></div>
PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-13697829542580140702017-09-03T17:04:00.000+02:002017-09-20T23:15:55.259+02:00Interfacing LM35 temperature sensor with PIC18F4550 microcontroller<div style="text-align: center;">
<span style="font-size: x-large;">Interfacing PIC18F4550 with LM35 </span></div>
This small topic shows the circuit diagram and CCS C code of the interfacing of LM35 temperature sensor with PIC18F4550 microcontroller.<br />
The LM35 temperature sensor is three pin device (VCC, OUT and GND)
with an output voltage linearly related to Centigrade temperature. Since
the LM35 output varies with dependent to the temperature we need ADC
(Analog-to-Digital Converter) module to measure this voltage. The ADC
module converts analog data into digital data.<br />
The LM35 output has linear +10mV/°C scale factor means the following:<br />
If the output voltage = 10mV ---> temperature = 1°C<br />
If the output voltage = 100mV ---> temperature = 10°C<br />
If the output voltage = 200mV ---> temperature = 20°C<br />
If the output voltage = 370mV ---> temperature = 37°C<br />
and so on.<br />
<b>LM35 Futures (from datasheet):</b><br />
<ul>
<li>Calibrated Directly in ° Celsius (Centigrade)</li>
<li>Linear + 10 mV/°C Scale Factor</li>
<li>0.5°C Ensured Accuracy (at +25°C)</li>
<li>Rated for Full −55°C to +150°C Range</li>
<li>Suitable for Remote Applications</li>
<li>Low Cost Due to Wafer-Level Trimming</li>
<li>Operates from 4 to 30 V</li>
<li>Less than 60-μA Current Drain</li>
<li>Low Self-Heating, 0.08°C in Still Air</li>
<li>Nonlinearity Only ±¼°C Typical</li>
<li>Low Impedance Output, 0.1 Ω for 1 mA Load</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC18F4550 microcontroller</li>
<li>LM35 temperature sensor -- <a href="http://www.ti.com/lit/ds/symlink/lm35.pdf" target="_blank">datasheet</a></li>
<li>1602 LCD screen</li>
<li>10K ohm variable resistor</li>
<li>Breadboard</li>
<li>5V voltage source</li>
<li>Jumper wires</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">Interfacing PIC18F4550 with LM35 sensor circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnI5w-EcAXMRr_46OBwMXi67HrovV5ryZiQOrBPPTFsCe_i59BfKHtFB1G8gEj4i51yyfg7TtCbcHdCdmrTVAjS9i5xd32T8sKhEUgXj3KY41S9eFHLtqiMIRsGUDxWNn0yyrAqpTp0Ns/s1600/lm35-temperature-sensor-pic18f4550-microcontroller-circuit.png" imageanchor="1"><img alt="Interfacing PIC18F4550 with LM35 temperature sensor circuit" border="0" height="396" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnI5w-EcAXMRr_46OBwMXi67HrovV5ryZiQOrBPPTFsCe_i59BfKHtFB1G8gEj4i51yyfg7TtCbcHdCdmrTVAjS9i5xd32T8sKhEUgXj3KY41S9eFHLtqiMIRsGUDxWNn0yyrAqpTp0Ns/s640/lm35-temperature-sensor-pic18f4550-microcontroller-circuit.png" title="Interfacing PIC18F4550 with LM35 temperature sensor circuit" width="640" /></a></div>
The output of the LM35 temperature sensor is connected to analog channel 0 (AN0) of the PIC18F4550 microcontroller.<br />
In this example the MCU uses its internal oscillator and MCLR pin function is disabled.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Interfacing PIC18F4550 with LM35 temperature sensor C code:</span></span><br />
The C code below was tested with CCS PIC C compiler version 5.051.<br />
Reading voltage quantity using the ADC gives us a number between 0
and 1023 (10-bit resolution), 0V is represented by 0 and 5V is
represented by 1023. Converting back the ADC digital value is easy and
we can use the following equation for that conversion:<br />
Voltage (in Volts) = ADC reading * 5 / 1023<br />
Multiplying the previous result by 100 (LM35 scale factor is 10mV/°C = 0.01V/°C) will gives the actual temperature:<br />
Temperature(°C) = ADC reading * 0.489<br />
where 0.489 = 500 / 1023<br />
The complete C code is the one below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">/* Interfacing PIC18F4550 with LM35 analog temperature sensor CCS C code.</span>
<span style="color: #7e7e7e;"> Read LM35 datasheet to understand the code!</span>
<span style="color: #7e7e7e;"> http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;"> electronnote@gmail.com</span>
<span style="color: #7e7e7e;">*/</span>
<span style="color: #7e7e7e;">//LCD module connections</span>
<span style="color: red;">#define</span> LCD_RS_PIN PIN_D0
<span style="color: red;">#define</span> LCD_RW_PIN PIN_D1
<span style="color: red;">#define</span> LCD_ENABLE_PIN PIN_D2
<span style="color: red;">#define</span> LCD_DATA4 PIN_D3
<span style="color: red;">#define</span> LCD_DATA5 PIN_D4
<span style="color: red;">#define</span> LCD_DATA6 PIN_D5
<span style="color: red;">#define</span> LCD_DATA7 PIN_D6
<span style="color: #7e7e7e;">//End LCD module connections</span>
<span style="color: red;">#include</span> <18F4550.h>
<span style="color: red;">#fuses</span> NOMCLR, INTRC_IO
<span style="color: red;">#device</span> ADC=10
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 8MHz)
<span style="color: red;">#include</span> <lcd.c>
<span style="color: blue;">char</span> temperature[] = <span style="color: #de00d0;">" 00.0 C"</span>;
<span style="color: blue;">unsigned</span> <span style="color: blue;">int16</span> temp;
<span style="color: blue;">void</span> main(){
setup_oscillator(OSC_8MHZ); <span style="color: #7e7e7e;">// Set internal oscillator to 8MHz</span>
setup_adc(ADC_CLOCK_INTERNAL); <span style="color: #7e7e7e;">// ADC Module uses its internal oscillator</span>
setup_adc_ports(AN0); <span style="color: #7e7e7e;">// Configure AN0 pin as analog</span>
set_adc_channel(0); <span style="color: #7e7e7e;">// Select channel 0 (AN0)</span>
lcd_init(); <span style="color: #7e7e7e;">// Initialize LCD module</span>
lcd_putc(<span style="color: #de00d0;">'\f'</span>); <span style="color: #7e7e7e;">// Clear LCD</span>
lcd_gotoxy(3, 1); <span style="color: #7e7e7e;">// Go to column 3 row 1</span>
printf(lcd_putc, <span style="color: #de00d0;">"Temperature:"</span>);
temperature[5] = 223; <span style="color: #7e7e7e;"> // Put degree symbol (°)</span>
<span style="color: blue;">while</span>(TRUE){
delay_ms(1000);
temp = read_adc() * 0.489; <span style="color: #7e7e7e;">// Read analog voltage and convert it to degree celsius (0.489 = 500/1023)</span>
<span style="color: blue;">if</span> (temp > 99)
temperature[0] = 1 + 48; <span style="color: #7e7e7e;">// Put 1 (of hundred)</span>
<span style="color: blue;">else</span>
temperature[0] = <span style="color: #de00d0;">' '</span>; <span style="color: #7e7e7e;">// Put space</span>
temperature[1] = (temp / 10) % 10 + 48;
temperature[2] = temp % 10 + 48;
lcd_gotoxy(5, 2); <span style="color: #7e7e7e;">// Go to column 5 row 2</span>
printf(lcd_putc, temperature); <span style="color: #7e7e7e;">// Display LM35 temperature result</span>
}
}
</pre>
<span style="color: #cc0000;"><span style="font-size: large;">The result:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVAMERieth1XPfOGEsD5w2kvql8uhw_j15SkHAx3HvLzT1YSpwoi4DqM5CAZo970pyIvV5qYB2A9wRdZz8UGdPG5oQmqfAR7UUCB5dsnm4HKuUq4B-uxPvE7r2ROLvewp0IEfv4lHbXv4/s1600/PIC18F4550+with+LM35+temperature+sensor+hardware+circuit.JPG" imageanchor="1"><img alt="PIC18F4550 with LM35 temperature sensor hardware circuit" border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVAMERieth1XPfOGEsD5w2kvql8uhw_j15SkHAx3HvLzT1YSpwoi4DqM5CAZo970pyIvV5qYB2A9wRdZz8UGdPG5oQmqfAR7UUCB5dsnm4HKuUq4B-uxPvE7r2ROLvewp0IEfv4lHbXv4/s400/PIC18F4550+with+LM35+temperature+sensor+hardware+circuit.JPG" title="PIC18F4550 with LM35 temperature sensor hardware circuit" width="400" /></a></div>
PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-24322229402341391512017-08-30T22:55:00.000+02:002017-09-20T23:15:55.273+02:00Real time clock & calendar with PIC18F4550 and DS3231<div style="text-align: center;">
<span style="font-size: x-large;">Interfacing PIC18F4550 with DS3231 RTC</span></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZ_w35q7bkVUWfZFIlyIZePpCNCUBWO29XRbu0gqdn9OuVJL0RkQ8Mi_jBznsscbfH1ZZUYSaHsBJBvDBFE4QHQVSkOcOl7n05jxvL8hZgMozZlb6AoJlSJN_wcV6HD3UNWhdaeDQJR5w/s1600/Real+time+clock+using+PIC18F4550+and+DS3231+hardware+circuit.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="PIC18F4550 microcontroller with DS3231 RTC hardware circuit" border="0" data-original-height="720" data-original-width="1280" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZ_w35q7bkVUWfZFIlyIZePpCNCUBWO29XRbu0gqdn9OuVJL0RkQ8Mi_jBznsscbfH1ZZUYSaHsBJBvDBFE4QHQVSkOcOl7n05jxvL8hZgMozZlb6AoJlSJN_wcV6HD3UNWhdaeDQJR5w/s400/Real+time+clock+using+PIC18F4550+and+DS3231+hardware+circuit.JPG" title="PIC18F4550 microcontroller with DS3231 RTC hardware circuit" width="400" /></a> </div>
The DS3231 is a low cost , extremely accurate real time clock with a
built-in crystal oscillator. The characteristics of the DS3231 make it
one of the best choices for real time clock chips.<br />
This project shows how to build is simple real time clock and calendar (RTCC) using PIC18F4550 microcontroller and DS3231.<br />
The
DS3231 uses I2C protocol to interface with the master device which is
in our example the PIC18F4550 which has one I2C module.<br />
The I2C
protocol uses only two lines: SCL (Serial Clock) and SDA (Serial Data)
which are in the PIC18F4550 pin RB1 and pin RB0 respectively.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC18F4550 microcontroller</li>
<li>1602 LCD screen</li>
<li>10K ohm variable resistor </li>
<li>2 x push button</li>
<li>5V supply source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
DS3231 board contains the following components:<br />
<ul>
<li>DS3231 RTC - <a href="https://datasheets.maximintegrated.com/en/ds/DS3231.pdf" target="_blank"><i>datasheet</i></a></li>
<li><i> </i>2 x 4.7K ohm resistors</li>
<li>0.1uF ceramic capacitor</li>
<li>3V coin cell battery</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">Real time clock & calendar with PIC18F4550 and DS3231 circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8gMX96hVN_QdPYFP8VgD-IFAgUvqhvgT9mhgmSFViKY81TzAIIRjkFiUCVcIgPqsKRxqEdoXCxfWhYpg8jGI3Xu3V-Bh2WzNdEQqqbtHAFrsuXZRJm50by69z0y_uBmuap2DCGE_rVDY/s1600/ds3231-rtc-real-time-clock-calendar-pic18f4550-circuit.png" imageanchor="1"><img alt="Interfacing PIC18F4550 with DS3231 RTC cirucit" border="0" height="390" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8gMX96hVN_QdPYFP8VgD-IFAgUvqhvgT9mhgmSFViKY81TzAIIRjkFiUCVcIgPqsKRxqEdoXCxfWhYpg8jGI3Xu3V-Bh2WzNdEQqqbtHAFrsuXZRJm50by69z0y_uBmuap2DCGE_rVDY/s640/ds3231-rtc-real-time-clock-calendar-pic18f4550-circuit.png" title="Interfacing PIC18F4550 with DS3231 RTC cirucit" width="640" /></a></div>
The 1602 LCD has 7 data lines which are connected to pins RD0~6, the
DS3231 SCL pin is connected to pin RB1 (#34) and SDA is connected to pin
RB0 (#33) of the PIC18F4550 microcontroller.<br />
In the circuit there are 2 push
buttons (B1 & B2) connected to pin RB2 and pin RB3, the two push
buttons are used to set the time as well as the calendar parameters (minutes, hours, date......). The
button B1 selects the parameter and B2 increments the selected parameter.<br />
The 3V cell battery is used as a backup to keep time and date running in
case of main power failure. The circuit can work without this battery
but its pin (#14) has to be grounded.<br />
In this project the PIC18F4550 uses its internal oscillator and MCLR pin function is disabled.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Real time clock & calendar with PIC18F4550 and DS3231 C code:</span></span><br />
The C code below was tested with CCS C compiler version 5.051.<br />
The hardware I2C module of the PIC18F4550 is initialized and configured using the function below with a speed of 100KHz:<br />
<span style="background-color: yellow;">#use I2C(master, I2C1, FAST = 100000)</span><br />
<div class="Style1" style="margin-right: 0px;">
master: set the microcontroller to the master mode</div>
I2C1: use first I2C module.<br />
The DS3231 works with BCD format only and to convert the BCD to
decimal and vise versa I used the following functions (example for minute
variable):<br />
<span style="background-color: yellow;">minute = (minute >> 4) * 10 + (minute & 0x0F);</span> // Convert BCD to decimal<br />
<span style="background-color: yellow;">minute = ((minute / 10) << 4) + (minute % 10); </span> // Convert decimal to BCD<br />
<b><u>Code functions:</u></b><br />
<span style="background-color: yellow;">void DS3231_display() :</span> this function prints the time and calendar on the 1602 LCD screen. Before the print it converts the all the wanted data from BCD format to decimal format.<br />
<span style="background-color: yellow;">int8 edit(parameter, x, y) :</span> I used this function to edit time and calendar parameters. I used a variable named<span style="background-color: yellow;"> i </span>to distinguish between the parameters:<br />
i = 0, 1 : hours and minutes respectively<br />
i = 2, 3, 4: date, month and year respectively.<br />
After the edit of time/calendar the data have to be converted back to BCD format and written to the DS3231 (it had been converted from BCD format to decimal format by the function <span style="background-color: yellow;">void DS3231_display()<span style="background-color: white;"> </span></span>).<br />
<span style="background-color: yellow;">void blink() :</span> this small function works as a delay except that it is interrupted by the buttons B1 (connected to RB2) and B2 (connected to RB3). When called and without pressing any button the total time is 10 x 25ms = 250ms. With this function we can see the blinking of the selected parameter with a frequency of 2Hz. So a delay of 250ms comes after the print of the selected parameter and after that delay a 2 spaces is printed which makes the parameter disappears from the LCD and another 250ms delay comes after the print of the 2 spaces.<br />
The complete C code is the one below.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">/* Real time clock/calendar (RTCC) using PIC18F4550 & DS3231 CCS C code.</span>
<span style="color: #7e7e7e;"> Read DS3231 RTC datasheet to understand the code!</span>
<span style="color: #7e7e7e;"> Time & date parameters can be set using two push buttons connected to RB2 & RB3.</span>
<span style="color: #7e7e7e;"> http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;"> electronnote@gmail.com</span>
<span style="color: #7e7e7e;">*/</span>
<span style="color: #7e7e7e;">//LCD module connections</span>
<span style="color: red;">#define</span> LCD_RS_PIN PIN_D0
<span style="color: red;">#define</span> LCD_RW_PIN PIN_D1
<span style="color: red;">#define</span> LCD_ENABLE_PIN PIN_D2
<span style="color: red;">#define</span> LCD_DATA4 PIN_D3
<span style="color: red;">#define</span> LCD_DATA5 PIN_D4
<span style="color: red;">#define</span> LCD_DATA6 PIN_D5
<span style="color: red;">#define</span> LCD_DATA7 PIN_D6
<span style="color: #7e7e7e;">//End LCD module connections</span>
<span style="color: red;">#include</span> <18F4550.h>
<span style="color: red;">#fuses</span> NOMCLR, INTRC_IO, NOWDT,NOPROTECT,NOLVP
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 8000000)
<span style="color: red;">#include</span> <lcd.c>
<span style="color: red;">#use</span> fast_io(B)
<span style="color: red;">#use</span> fast_io(D)
<span style="color: red;">#use</span> I2C(master, I2C1, FAST = 100000)
<span style="color: blue;">char</span> time[] = <span style="color: #de00d0;">"TIME: : : "</span>;
<span style="color: blue;">char</span> calendar[] = <span style="color: #de00d0;">"DATE: / /20 "</span>;
<span style="color: blue;">int8</span> i, second, minute, hour, date, month, year;
<span style="color: blue;">void</span> DS3231_display(){
<span style="color: #7e7e7e;">// Convert BCD to decimal</span>
second = (second >> 4) * 10 + (second & 0x0F);
minute = (minute >> 4) * 10 + (minute & 0x0F);
hour = (hour >> 4) * 10 + (hour & 0x0F);
date = (date >> 4) * 10 + (date & 0x0F);
month = (month >> 4) * 10 + (month & 0x0F);
year = (year >> 4) * 10 + (year & 0x0F);
<span style="color: #7e7e7e;">// End conversion</span>
time[12] = second % 10 + 48;
time[11] = second / 10 + 48;
time[9] = minute % 10 + 48;
time[8] = minute / 10 + 48;
time[6] = hour % 10 + 48;
time[5] = hour / 10 + 48;
calendar[14] = year % 10 + 48;
calendar[13] = year / 10 + 48;
calendar[9] = month % 10 + 48;
calendar[8] = month / 10 + 48;
calendar[6] = date % 10 + 48;
calendar[5] = date / 10 + 48;
lcd_gotoxy(1, 1); <span style="color: #7e7e7e;">// Go to column 1 row 1</span>
printf(lcd_putc, time); <span style="color: #7e7e7e;">// Display time</span>
lcd_gotoxy(1, 2); <span style="color: #7e7e7e;">// Go to column 1 row 2</span>
printf(lcd_putc, calendar); <span style="color: #7e7e7e;">// Display calendar</span>
}
<span style="color: blue;">void</span> <span style="color: blue;">blink</span>(){
<span style="color: blue;">int8</span> j = 0;
<span style="color: blue;">while</span>(j < 10 && input(PIN_B2) && input(PIN_B3)){
j++;
delay_ms(25);
}
}
<span style="color: blue;">int8</span> edit(parameter, x, y){
<span style="color: blue;">while</span>(!input(PIN_B2)); <span style="color: #7e7e7e;">// Wait until button RB2 released</span>
<span style="color: blue;">while</span>(TRUE){
<span style="color: blue;">while</span>(!input(PIN_B3)){ <span style="color: #7e7e7e;">// If button RB3 is pressed</span>
parameter++;
<span style="color: blue;">if</span>(i == 0 && parameter > 23) <span style="color: #7e7e7e;">// If hours > 23 ==> hours = 0</span>
parameter = 0;
<span style="color: blue;">if</span>(i == 1 && parameter > 59) <span style="color: #7e7e7e;">// If minutes > 59 ==> minutes = 0</span>
parameter = 0;
<span style="color: blue;">if</span>(i == 2 && parameter > 31) <span style="color: #7e7e7e;">// If date > 31 ==> date = 1</span>
parameter = 1;
<span style="color: blue;">if</span>(i == 3 && parameter > 12) <span style="color: #7e7e7e;">// If month > 12 ==> month = 1</span>
parameter = 1;
<span style="color: blue;">if</span>(i == 4 && parameter > 99) <span style="color: #7e7e7e;">// If year > 99 ==> year = 0</span>
parameter = 0;
lcd_gotoxy(x, y);
printf(lcd_putc,<span style="color: #de00d0;">"%02u"</span>, parameter); <span style="color: #7e7e7e;">// Display parameter</span>
delay_ms(200); <span style="color: #7e7e7e;">// Wait 200ms</span>
}
lcd_gotoxy(x, y);
lcd_putc(<span style="color: #de00d0;">" "</span>);
<span style="color: blue;">blink</span>();
lcd_gotoxy(x, y); <span style="color: #7e7e7e;">// Print two spaces</span>
printf(lcd_putc,<span style="color: #de00d0;">"%02u"</span>, parameter); <span style="color: #7e7e7e;">// Print parameter</span>
<span style="color: blue;">blink</span>();
<span style="color: blue;">if</span>(!input(PIN_B2)){ <span style="color: #7e7e7e;">// If button RB2 is pressed</span>
i++; <span style="color: #7e7e7e;">// Increament 'i' for the next parameter</span>
<span style="color: blue;">return</span> parameter; <span style="color: #7e7e7e;">// Return parameter value and exit</span>
}
}
}
<span style="color: blue;">void</span> main(){
setup_oscillator(OSC_8MHZ); <span style="color: #7e7e7e;">// Set internal oscillator to 8MHz</span>
set_tris_d(0);
port_b_pullups(TRUE); <span style="color: #7e7e7e;">// Enable PORTB internal pull-ups</span>
lcd_init(); <span style="color: #7e7e7e;">// Initialize LCD module</span>
lcd_putc(<span style="color: #de00d0;">'\f'</span>); <span style="color: #7e7e7e;">// LCD clear</span>
<span style="color: blue;">while</span>(TRUE){
<span style="color: blue;">if</span>(!input(PIN_B2)){ <span style="color: #7e7e7e;">// If RB2 button is pressed</span>
i = 0;
hour = edit(hour, 6, 1);
minute = edit(minute, 9, 1);
date = edit(date, 6, 2);
month = edit(month, 9, 2);
year = edit(year, 14, 2);
<span style="color: #7e7e7e;">// Convert decimal to BCD</span>
minute = ((minute / 10) << 4) + (minute % 10);
hour = ((hour / 10) << 4) + (hour % 10);
date = ((date / 10) << 4) + (date % 10);
month = ((month / 10) << 4) + (month % 10);
year = ((year / 10) << 4) + (year % 10);
<span style="color: #7e7e7e;">// End conversion</span>
<span style="color: #7e7e7e;">// Write data to DS3231 RTC</span>
i2c_start(); <span style="color: #7e7e7e;">// Start I2C protocol</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(0); <span style="color: #7e7e7e;">// Send register address (time seconds register)</span>
i2c_write(0); <span style="color: #7e7e7e;">// Reset sesonds and start oscillator</span>
i2c_write(minute); <span style="color: #7e7e7e;">// Write minutes value to DS3231</span>
i2c_write(hour); <span style="color: #7e7e7e;">// Write hours value to DS3231</span>
i2c_write(1); <span style="color: #7e7e7e;">// Write day value (not used)</span>
i2c_write(date); <span style="color: #7e7e7e;">// Write date value to DS3231</span>
i2c_write(month); <span style="color: #7e7e7e;">// Write month value to DS3231</span>
i2c_write(year); <span style="color: #7e7e7e;">// Write year value to DS3231</span>
delay_ms(200); <span style="color: #7e7e7e;">// Wait 200ms</span>
}
i2c_start(); <span style="color: #7e7e7e;">// Start I2C protocol</span>
i2c_write(0xD0); <span style="color: #7e7e7e;">// DS3231 address</span>
i2c_write(0); <span style="color: #7e7e7e;">// Send register address (time seconds register)</span>
i2c_start(); <span style="color: #7e7e7e;">// Restart I2C</span>
i2c_write(0xD1); <span style="color: #7e7e7e;">// Initialize data read</span>
second = i2c_read(1); <span style="color: #7e7e7e;">// Read seconds from register 0</span>
minute = i2c_read(1); <span style="color: #7e7e7e;">// Read minutes from register 1</span>
hour = i2c_read(1); <span style="color: #7e7e7e;">// Read hours from register 2</span>
i2c_read(1); <span style="color: #7e7e7e;">// Read day from register 3 (not used)</span>
date = i2c_read(1); <span style="color: #7e7e7e;">// Read date from register 4</span>
month = i2c_read(1); <span style="color: #7e7e7e;">// Read month from register 5</span>
year = i2c_read(0); <span style="color: #7e7e7e;">// Read year from register 6</span>
i2c_stop(); <span style="color: #7e7e7e;">// Stop I2C protocol</span>
DS3231_display(); <span style="color: #7e7e7e;">// Diaplay time & calendar</span>
delay_ms(50); <span style="color: #7e7e7e;">// Wait 50ms</span>
}
}
</pre>
<span style="color: #cc0000;"><span style="font-size: large;"> </span></span><br />
The project should work as shown in the video below (in the video the used mcu is PIC16F877A).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/UwhJwynorgM/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/UwhJwynorgM?feature=player_embedded" width="320"></iframe></div>
<div style="text-align: center;">
</div>
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.comtag:blogger.com,1999:blog-3998280497133081040.post-81278170117889907602017-08-30T18:37:00.000+02:002017-09-20T23:15:55.429+02:00PIC18F4550 + LM335 temperature sensor example<div style="text-align: center;">
<span style="font-size: x-large;">Interfacing PIC18F4550 with LM335 analog temperature sensor</span></div>
As mentioned above, the LM335 is a 3-pin analog device which can measure temperature (converts temperature to analog voltage). This sensor requires an ADC to convert the analog data into digital one. this topic shows how to use PIC18F4550 microcontroller ADC module to measure the ambient temperature using the LM335 sensor.<br />
The LM335 sensor has the following features (from LM335 datasheet):<br />
<ul>
<li>Directly Calibrated to the Kelvin Temperature Scale</li>
<li>1°C Initial Accuracy Available</li>
<li>Operates from 400 μA to 5 mA</li>
<li>Less than 1-Ω Dynamic Impedance</li>
<li>Easily Calibrated</li>
<li>Wide Operating Temperature Range</li>
<li>200°C Overrange</li>
<li>Low Cost</li>
</ul>
The LM135 has a breakdown voltage directly proportional to
absolute temperature at 10 mV/°K. If the LM335 output voltage for
example is 3.03 (3030 mV) that means the temperature is: 303 °Kelvin =
30 °Celsius.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Hardware Required:</span></span><br />
<ul>
<li>PIC18F4550 microcontroller</li>
<li>LM335 Temperature sensor - <a href="https://drive.google.com/open?id=0ByrcgOkOu0vgWng0ZmZQOTRCTk0" target="_blank">datasheet</a></li>
<li>1602 LCD Screen</li>
<li>10K ohm potentiometer or variable resistor</li>
<li>2.2K ohm resistor</li>
<li>+5V Power supply source</li>
<li>Breadboard</li>
<li>Jumper wires</li>
</ul>
<span style="color: #cc0000;"><span style="font-size: large;">Interfacing PIC18F4550 with LM335 temperature sensor circuit:</span></span><br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSPJ4-TiJgXpYxh2saVXIUPJurQmvun6Z2YgzvVI8285k6Y-9EyjtBvdYfj-D7ht4Kk8lkc4fC3UCzHoVgzhd9LC-enDs7VsjPBwVJoJUXtvegQUpGVyRAMBl14pX8M3gLooZ8jRP3ZOQ/s1600/lm335-temperature-sensor-pic18f4550-microcontroller-circuit.png" imageanchor="1"><img alt="Interfacing PIC18F4550 microcontroller with LM335 temperature sensor" border="0" height="396" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSPJ4-TiJgXpYxh2saVXIUPJurQmvun6Z2YgzvVI8285k6Y-9EyjtBvdYfj-D7ht4Kk8lkc4fC3UCzHoVgzhd9LC-enDs7VsjPBwVJoJUXtvegQUpGVyRAMBl14pX8M3gLooZ8jRP3ZOQ/s640/lm335-temperature-sensor-pic18f4550-microcontroller-circuit.png" title="Interfacing PIC18F4550 microcontroller with LM335 temperature sensor" width="640" /></a></div>
The LM335 sensor has 3 pins (from left to right):<br />
Pin 1 for calibration, not used in this example<br />
Pin 2: output<br />
Pin 3: GND (ground).<br />
The
output pin of the LM335 sensor is connected to analog channel 0 (AN0). I
chose the 2.2K ohm because as written in the datasheet for optimum
accuracy the current flows through the LM335 should be 1mA. For example
if the temperature = 27°C, the output will be 3.00V and assume the
supply voltage is exactly 5.00V that means the current flows through the
sensor is ( 5 - 3)/2.2 = 0.90mA which is good enough. Also the value
2.2K is a standard value and well used.<br />
The 1602 LCD screen
is connected to pins RD0~6. The 10K variable resistor is used to adjust
the brightness of the screen. <br />
In this example the PIC18F4550 runs with its internal oscillator @ 8MHz and MCLR pin function is disabled.<br />
<span style="color: #cc0000;"><span style="font-size: large;">Interfacing PIC18F4550 with LM335 sensor CCS C Code:</span></span><br />
The following C code was tested with CCS PIC C compiler version 5.051.<br />
<pre style="background: rgb(230,250,250); border: 1px dashed #000000; height: 600px; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: #7e7e7e;">/* Interfacing PIC18F4550 with LM335 analog temperature sensor CCS C code.</span>
<span style="color: #7e7e7e;"> Read LM335 datasheet to understand the code!</span>
<span style="color: #7e7e7e;"> http://ccspicc.blogspot.com/</span>
<span style="color: #7e7e7e;"> electronnote@gmail.com</span>
<span style="color: #7e7e7e;">*/</span>
<span style="color: #7e7e7e;">//LCD module connections</span>
<span style="color: red;">#define</span> LCD_RS_PIN PIN_D0
<span style="color: red;">#define</span> LCD_RW_PIN PIN_D1
<span style="color: red;">#define</span> LCD_ENABLE_PIN PIN_D2
<span style="color: red;">#define</span> LCD_DATA4 PIN_D3
<span style="color: red;">#define</span> LCD_DATA5 PIN_D4
<span style="color: red;">#define</span> LCD_DATA6 PIN_D5
<span style="color: red;">#define</span> LCD_DATA7 PIN_D6
<span style="color: #7e7e7e;">//End LCD module connections</span>
<span style="color: red;">#include</span> <18F4550.h>
<span style="color: red;">#fuses</span> NOMCLR, INTRC_IO
<span style="color: red;">#device</span> ADC=10
<span style="color: red;">#use</span> <span style="color: black;">delay</span>(clock = 8MHz)
<span style="color: red;">#include</span> <lcd.c>
<span style="color: blue;">char</span> message1[] = <span style="color: #de00d0;">"Temp = 00.0 C"</span>;
<span style="color: blue;">char</span> message2[] = <span style="color: #de00d0;">"= 00.0 K"</span>;
<span style="color: blue;">signed</span> <span style="color: blue;">int16</span> Kelvin, Celsius;
<span style="color: blue;">void</span> main(){
setup_oscillator(OSC_8MHZ); <span style="color: #7e7e7e;">// Set internal oscillator to 8MHz</span>
setup_adc(ADC_CLOCK_INTERNAL); <span style="color: #7e7e7e;">// ADC Module uses its internal oscillator</span>
setup_adc_ports(AN0); <span style="color: #7e7e7e;">// Configure AN0 pin as analog</span>
set_adc_channel(0); <span style="color: #7e7e7e;">// Select channel 0 (AN0)</span>
lcd_init(); <span style="color: #7e7e7e;">// Initialize LCD module</span>
lcd_putc(<span style="color: #de00d0;">'\f'</span>); <span style="color: #7e7e7e;">// Clear LCD</span>
<span style="color: blue;">while</span>(TRUE){
delay_ms(1000); <span style="color: #7e7e7e;">// Wait 1 second</span>
Kelvin = read_adc() * 0.489; <span style="color: #7e7e7e;">// Read analog voltage and convert it to Kelvin (0.489 = 500/1023)</span>
Celsius = Kelvin - 273; <span style="color: #7e7e7e;">// Convert Kelvin to degree Celsius</span>
<span style="color: blue;">if</span>(Celsius < 0){
Celsius = <span style="color: blue;">abs</span>(Celsius); <span style="color: #7e7e7e;">// Absolute value</span>
message1[7] = <span style="color: #de00d0;">'-'</span>; <span style="color: #7e7e7e;">// Put minus '-' sign</span>
}
<span style="color: blue;">else</span>
message1[7] = <span style="color: #de00d0;">' '</span>; <span style="color: #7e7e7e;">// Put space ' '</span>
<span style="color: blue;">if</span> (Celsius > 99)
message1[7] = 1 + 48; <span style="color: #7e7e7e;">// Put 1 (of hundred)</span>
message1[8] = (Celsius / 10) % 10 + 48;
message1[9] = Celsius % 10 + 48;
message1[12] = 223; <span style="color: #7e7e7e;">// Degree symbol</span>
message2[2] = (Kelvin / 100) % 10 + 48;
message2[3] = (Kelvin / 10) % 10 + 48;
message2[4] = Kelvin % 10 + 48;
lcd_gotoxy(1, 1); <span style="color: #7e7e7e;">// Go to column 1 row 1</span>
printf(lcd_putc, message1); <span style="color: #7e7e7e;">// Display message1</span>
lcd_gotoxy(6, 2); <span style="color: #7e7e7e;">// Go to column 6 row 2</span>
printf(lcd_putc, message2); <span style="color: #7e7e7e;">// Display message2</span>
}
}
</pre>
<br />PIC Microcontroller Projectshttp://www.blogger.com/profile/04658005165341740676noreply@blogger.com