<?xml version="1.0" encoding="iso-8859-1"?><!-- generator="b2evolution/3.3.3" -->
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Microcontrollers and YOU!</title>
		<link>http://mcuplace.com/mcu/blog4.php</link>
		<atom:link rel="self" type="application/rss+xml" href="http://mcuplace.com/mcu/blog4.php?tempskin=_rss2" />
		<description></description>
		<language>en-US</language>
		<docs>http://blogs.law.harvard.edu/tech/rss</docs>
		<admin:generatorAgent rdf:resource="http://b2evolution.net/?v=3.3.3"/>
		<ttl>60</ttl>
				<item>
			<title>A new beginning</title>
			<link>http://mcuplace.com/mcu/blog4.php/2010/04/30/a-new-beginning</link>
			<pubDate>Sat, 01 May 2010 03:10:53 +0000</pubDate>			<dc:creator>anthony</dc:creator>
			<category domain="main">Code</category>			<guid isPermaLink="false">54@http://mcuplace.com/mcu/</guid>
						<description>&lt;p&gt;Recently I've had the wonderful opportunity to TA ESE 123 at Stony Brook University with Professor David Westerfeld. Over the past semester I've been working in the student lab, helping with their assignments and lab tasks. For the second half of the class however, the students were to build a digital clock combined with a USB charger. The project took advantage of AVR mirocontrollers for the digital clock part of the design. Being a freshman level class, it would be a daunting task to teach not only basic electric theory, but combine that with basic microcontroller theory combined with learning assembly. I decided it would be best to write a handout that went over all the basics of computation theory, microcontrollers as well as completely outline the hardware and software aspects of the digital clock. The resulting document is about 30 pages of insight, knowledge and experience all dedicated to the project this semester of ESE 123. The audience of this document is the beginner and expert alike, I hope that anyone who reads it learns something new. &lt;/p&gt;

&lt;p&gt;Attached to this post is the full handout, it introduces a new line of hardware for this blog, the AVR series of microcontrollers. The specific chip used in the project was the ATtiny48 microcontroller. I am also attaching the full commented code.&lt;/p&gt;

&lt;p&gt;Get the full writeup here:  &lt;a href=&quot;http://mcuplace.com/mcu/media/blogs/blog//Digiclock.pdf&quot;&gt;Write Up&lt;/a&gt;&lt;br /&gt;
Grab the code here:  &lt;a href=&quot;http://mcuplace.com/mcu/media/blogs/blog//code.zip&quot;&gt;Code&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;*Note, the code was written by Professor Westerfeld and cannot be used without his consent.&lt;/p&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://mcuplace.com/mcu/blog4.php/2010/04/30/a-new-beginning&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>Recently I've had the wonderful opportunity to TA ESE 123 at Stony Brook University with Professor David Westerfeld. Over the past semester I've been working in the student lab, helping with their assignments and lab tasks. For the second half of the class however, the students were to build a digital clock combined with a USB charger. The project took advantage of AVR mirocontrollers for the digital clock part of the design. Being a freshman level class, it would be a daunting task to teach not only basic electric theory, but combine that with basic microcontroller theory combined with learning assembly. I decided it would be best to write a handout that went over all the basics of computation theory, microcontrollers as well as completely outline the hardware and software aspects of the digital clock. The resulting document is about 30 pages of insight, knowledge and experience all dedicated to the project this semester of ESE 123. The audience of this document is the beginner and expert alike, I hope that anyone who reads it learns something new. </p>

<p>Attached to this post is the full handout, it introduces a new line of hardware for this blog, the AVR series of microcontrollers. The specific chip used in the project was the ATtiny48 microcontroller. I am also attaching the full commented code.</p>

<p>Get the full writeup here:  <a href="http://mcuplace.com/mcu/media/blogs/blog//Digiclock.pdf">Write Up</a><br />
Grab the code here:  <a href="http://mcuplace.com/mcu/media/blogs/blog//code.zip">Code</a></p>


<p>*Note, the code was written by Professor Westerfeld and cannot be used without his consent.</p><div class="item_footer"><p><small><a href="http://mcuplace.com/mcu/blog4.php/2010/04/30/a-new-beginning">Original post</a> blogged on <a href="http://b2evolution.net/">b2evolution</a>.</small></p></div>]]></content:encoded>
								<comments>http://mcuplace.com/mcu/blog4.php/2010/04/30/a-new-beginning#comments</comments>
			<wfw:commentRss>http://mcuplace.com/mcu/blog4.php?tempskin=_rss2&#38;disp=comments&#38;p=54</wfw:commentRss>
		</item>
				<item>
			<title>Introducing the PIC18</title>
			<link>http://mcuplace.com/mcu/blog4.php/2009/12/22/introducing-the-pic18</link>
			<pubDate>Wed, 23 Dec 2009 02:57:41 +0000</pubDate>			<dc:creator>anthony</dc:creator>
			<category domain="main">Informative</category>
<category domain="alt">General</category>			<guid isPermaLink="false">51@http://mcuplace.com/mcu/</guid>
						<description>&lt;p&gt;I figured it'd be a good time to move to a more capable microcontroller as the projects on the blog seems to be getting more and more complicated and lets face it, keeping up with our PIC16 and their limitations can get a little annoying when you're moving lots of important data. We need more pins, we need more features on the chip and we need better instructions.&lt;/p&gt;

&lt;p&gt;Enter the PIC18 series from microchip. &lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=2696&amp;amp;param=en537796&quot;&gt;http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=2696&amp;amp;param=en537796&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The PIC18 is the most high end 8-bit microcontroller that microchip offers. It has many advantages over the lower end PIC16s the biggest being a new and improved instruction-set and memory management system.&lt;/p&gt;

&lt;p&gt;I suggest you take a look at a datasheet for a PIC, everything in this article will reference:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://ww1.microchip.com/downloads/en/DeviceDoc/39605F.pdf&quot;&gt;http://ww1.microchip.com/downloads/en/DeviceDoc/39605F.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A new memory system:&lt;/p&gt;

&lt;p&gt;The coolest thing with the PIC18s is an Access Bank system. In this system the MCUs RAM is divided up into 16 banks (0-15)&gt; Each bank has however many memory addresses(Depending on PIC, for example the PIC18F1220 has 256 byte banks) and you select which bank you want with the BSR (Bank Select Register). This sounds awfully similar to ram-pages of the PIC16F however its the access bank delimiter in the opcode that makes life so much easier. The access bank is the first 128 Bytes of bank 0 (Our General purpose registers) and the last 128 of bank 15 (Our Special Function registers) by default all operations are done in the access bank (a=0)This allows us to access a good amount of GPR and all of our SFR without ever changing what bank were working in. No more STATUS,RPx calls. However if we want to access ram outside the access bank we have to set the access bank delimiter call in the instruction to 1 and then by default you will be working in whatever bank happens to be set in the BSR.&lt;/p&gt;

&lt;p&gt;Software accessible Stack:&lt;/p&gt;

&lt;p&gt;I'm not too familiar with this feature, but the PIC18 allows you to control the stack from software, you also have complete control over the stack pointer, this is extremely powerful and not offered on the PIC16&lt;/p&gt;

&lt;p&gt;New and improved modules:&lt;/p&gt;

&lt;p&gt;The PIC18 series features an 8-bit hardware multiplier. Microchip provides sample code for doing all sorts of fun arithmetic. This is good if you want to crunch numbers but don't want to go into a full DSP. Also some PIC18s feature on chip USB and other goodies.&lt;/p&gt;

&lt;p&gt;Priority interrupts:&lt;/p&gt;

&lt;p&gt;This is another really cool feature. The PIC18 features two interrupt vectors, one high priority and one low priority. This allows you to have a really complex interrupt scheme allowing really sophisticated user interaction. For every interrupt you can choose what priority it is. An example of this is having a sample system for a sensor have highest priority while the user interface is low priority, that way even if the user is interacting the device to cause an interrupt, you don't interrupt the sample of the sensor if it is time sensitive.&lt;/p&gt;

&lt;p&gt;NEW INSTRUCTIONS!:&lt;/p&gt;

&lt;p&gt;This feature is going to take me the longest to get used to, but the PIC18 features a plethora of new instructions to make our lives easier. One nice and needed one is a MOVFF instruction (move from one register to another) These instructions are meant to speed up your code and make execution much faster. All new instructions follow a similar style to the traditional ones, they just do more for the clock. You can take a look at them on page 193 of the datasheet.&lt;/p&gt;

&lt;p&gt;Free C compiler:&lt;/p&gt;

&lt;p&gt;Microchip offers a free c-compiler for the PIC18 series for MPLAB, i haven't used it but its free and its a c compiler.&lt;/p&gt;

&lt;p&gt;Tons of other stuff i still have to figure out:&lt;br /&gt;
I'm working on it :P&lt;/p&gt;

&lt;p&gt;The PIC18 series is a really powerful line and there isn't much that they cant do. The first project i will be posting with them is a Digitial Audio Processor, we'll be taking advantage of the priority interrupts to make really fast and efficient code.&lt;/p&gt;

&lt;p&gt;Hope to see you soon, happy programming!&lt;/p&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://mcuplace.com/mcu/blog4.php/2009/12/22/introducing-the-pic18&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>I figured it'd be a good time to move to a more capable microcontroller as the projects on the blog seems to be getting more and more complicated and lets face it, keeping up with our PIC16 and their limitations can get a little annoying when you're moving lots of important data. We need more pins, we need more features on the chip and we need better instructions.</p>

<p>Enter the PIC18 series from microchip. </p>

<p><a href="http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;nodeId=2696&amp;param=en537796">http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;nodeId=2696&amp;param=en537796</a></p>

<p>The PIC18 is the most high end 8-bit microcontroller that microchip offers. It has many advantages over the lower end PIC16s the biggest being a new and improved instruction-set and memory management system.</p>

<p>I suggest you take a look at a datasheet for a PIC, everything in this article will reference:</p>

<p><a href="http://ww1.microchip.com/downloads/en/DeviceDoc/39605F.pdf">http://ww1.microchip.com/downloads/en/DeviceDoc/39605F.pdf</a></p>

<p>A new memory system:</p>

<p>The coolest thing with the PIC18s is an Access Bank system. In this system the MCUs RAM is divided up into 16 banks (0-15)> Each bank has however many memory addresses(Depending on PIC, for example the PIC18F1220 has 256 byte banks) and you select which bank you want with the BSR (Bank Select Register). This sounds awfully similar to ram-pages of the PIC16F however its the access bank delimiter in the opcode that makes life so much easier. The access bank is the first 128 Bytes of bank 0 (Our General purpose registers) and the last 128 of bank 15 (Our Special Function registers) by default all operations are done in the access bank (a=0)This allows us to access a good amount of GPR and all of our SFR without ever changing what bank were working in. No more STATUS,RPx calls. However if we want to access ram outside the access bank we have to set the access bank delimiter call in the instruction to 1 and then by default you will be working in whatever bank happens to be set in the BSR.</p>

<p>Software accessible Stack:</p>

<p>I'm not too familiar with this feature, but the PIC18 allows you to control the stack from software, you also have complete control over the stack pointer, this is extremely powerful and not offered on the PIC16</p>

<p>New and improved modules:</p>

<p>The PIC18 series features an 8-bit hardware multiplier. Microchip provides sample code for doing all sorts of fun arithmetic. This is good if you want to crunch numbers but don't want to go into a full DSP. Also some PIC18s feature on chip USB and other goodies.</p>

<p>Priority interrupts:</p>

<p>This is another really cool feature. The PIC18 features two interrupt vectors, one high priority and one low priority. This allows you to have a really complex interrupt scheme allowing really sophisticated user interaction. For every interrupt you can choose what priority it is. An example of this is having a sample system for a sensor have highest priority while the user interface is low priority, that way even if the user is interacting the device to cause an interrupt, you don't interrupt the sample of the sensor if it is time sensitive.</p>

<p>NEW INSTRUCTIONS!:</p>

<p>This feature is going to take me the longest to get used to, but the PIC18 features a plethora of new instructions to make our lives easier. One nice and needed one is a MOVFF instruction (move from one register to another) These instructions are meant to speed up your code and make execution much faster. All new instructions follow a similar style to the traditional ones, they just do more for the clock. You can take a look at them on page 193 of the datasheet.</p>

<p>Free C compiler:</p>

<p>Microchip offers a free c-compiler for the PIC18 series for MPLAB, i haven't used it but its free and its a c compiler.</p>

<p>Tons of other stuff i still have to figure out:<br />
I'm working on it :P</p>

<p>The PIC18 series is a really powerful line and there isn't much that they cant do. The first project i will be posting with them is a Digitial Audio Processor, we'll be taking advantage of the priority interrupts to make really fast and efficient code.</p>

<p>Hope to see you soon, happy programming!</p><div class="item_footer"><p><small><a href="http://mcuplace.com/mcu/blog4.php/2009/12/22/introducing-the-pic18">Original post</a> blogged on <a href="http://b2evolution.net/">b2evolution</a>.</small></p></div>]]></content:encoded>
								<comments>http://mcuplace.com/mcu/blog4.php/2009/12/22/introducing-the-pic18#comments</comments>
			<wfw:commentRss>http://mcuplace.com/mcu/blog4.php?tempskin=_rss2&#38;disp=comments&#38;p=51</wfw:commentRss>
		</item>
				<item>
			<title>The Fundamentals of Digital Audio</title>
			<link>http://mcuplace.com/mcu/blog4.php/2009/12/08/the-fundamentals-of-digital-audio</link>
			<pubDate>Tue, 08 Dec 2009 05:15:17 +0000</pubDate>			<dc:creator>anthony</dc:creator>
			<category domain="main">Informative</category>
<category domain="alt">General</category>			<guid isPermaLink="false">50@http://mcuplace.com/mcu/</guid>
						<description>&lt;p&gt;Digital audio is a very powerful thing, we listen to our iPods every day, we stream music from websites using our computers and we work with many algorithms derived from techniques in digital audio. Digital audio has its roots in wave mechanics and is a very fundamental process for modern computation. We will be discussing sound as a wave, some basic properties of waves and how to convert a wave into something which you can store in memory, and techniques to play that wave back. We&amp;#8217;ll start with an introduction to sound and how to represent sound as a wave, and a mathematical function.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;An introduction to sound:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Sound is a wave, and like all waves it transfers energy through a medium, in this case it is usually air. Whenever something emits a &amp;#8220;sound&amp;#8221; it compresses air molecules, these compressed air molecules exert a force on uncompressed ones, this starts a chain reaction and sound propagates; this is the essence of a sound wave. For sound to exist you need a medium, be it air, a solid, liquid or plasma. The sound wave will travel through that medium until it dissipates completely and is undetectable.  Sound is usually the result of a force or stress on an object, you hit a tuning fork on a table, and it will vibrate at a particular frequency. To better visualize a sound wave mathematically, we will look at strign vibrations. &lt;/p&gt;

&lt;p&gt;&lt;b&gt;String Vibrations:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Like a turning fork, a string when plucked vibrates a particular frequency. The frequency at which a string vibrates at is due to its mass, length and tension on that string. The frequency which is most prevalent is called the fundamental frequency, when you play middle c on an instrument the fundamental frequency is 261 Hz. Now if middle c is a set frequency, why does middle c sound different on different instruments? The answer is because the sound from an instrument inst pure, each instrument has a unique harmonic structure which delivers a unique sound. To understand this more let&amp;#8217;s look at the math of a wave.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Mathematical representation of a sound wave:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;The nice thing about waves, is we can represent them mathematically, the simplest being that of a sine wave. Sine is a natural function which oscillates between crest to crest at a particular frequency. We can represent a pure oscillating sound by the following function.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/cgi-bin/mimetex.cgi?F(t) = A sin(\omega t + \phi)&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Where A is the amplitude (sine is a function which oscillates between 1 and -1, multiplying it by A will result in A as the amplitude). The Greek letter omega is the angular frequency which is denoted in radians/second and the Greek letter phi denotes the angular offset (for all cases in this article we can consider it zeros). A &amp;#8220;Pure&amp;#8221; sound is that which is sinusoidal, we here these all the time on cheap synthesizers, when a sound is sinusoidal, it can be represented by the above formula alone. If a synthesizer were to play middle c, it would produce a sine wave of frequency 261Hz (omega = 640) and what you would notice is that it sounds like the right pitch, but no natural instrument sounds like a pure tone.  When an instrument makes a tone, it is usually comprised of its fundamental frequency and higher order oscillations called harmonics. Harmonics are usually either &amp;#189;(Strings) or &amp;#190;(Closed tube) integer multiples of the fundamental frequency of a lesser amplitude. Because of this we can consider and natural tone a superposition of fundamental sine waves and harmonic sine waves. Most tones in nature are comprised of a superposition of sine waves. We can use this fact to break down any complex sound into a series of many simple ones governed by the very simple formula above.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Synthesizer theorem:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Breaking a complex sound into a series of sine waves can be done using a Fourier series. A Fourier series simply is a mathematical series which can break apart any repeating oscillations into a series of simpler sine waves. We use a Fourier transform to translate an arbitrary function into a series of sine functions. For the purpose of this article we&amp;#8217;ll use a Fourier series as a concept and we won&amp;#8217;t be exploring the math behind it (Maybe one day).&lt;/p&gt;

&lt;p&gt;To give a quick example of this we can consult Wikipedia. We all know and love our humble saw tooth wave; If we find the Fourier series of a saw tooth wave we get the following series as a result.&lt;br /&gt;
 &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/cgi-bin/mimetex.cgi?F(x)=2 \sum_{n=1}^{\infty}\frac{(-1)^{n+1}}{n}sin(nx)&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If we take n=1 we get the fundamental frequency of the series:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/cgi-bin/mimetex.cgi?F(x) =2sin(x)&quot; /&gt;&lt;/p&gt;
&lt;div class=&quot;image_block&quot;&gt;&lt;img src=&quot;http://mcuplace.com/mcu/media/blogs/blog/sine.gif&quot; alt=&quot;&quot; title=&quot;&quot; width=&quot;315&quot; height=&quot;133&quot; /&gt;&lt;/div&gt;

&lt;p&gt;If we take the first 5 terms we get:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/cgi-bin/mimetex.cgi?F(x) = 2sin(x)-sin(2x)+.5sin(3x)-.25sin(4x)+.125sin(5x)&quot; /&gt;&lt;/p&gt;
&lt;div class=&quot;image_block&quot;&gt;&lt;img src=&quot;http://mcuplace.com/mcu/media/blogs/blog/sawtooth.gif&quot; alt=&quot;&quot; title=&quot;&quot; width=&quot;315&quot; height=&quot;124&quot; /&gt;&lt;/div&gt;

&lt;p&gt;As we take n to infinity, we get a better and better approximation of our function. This is the fundamental way in which analog synthesizers would generate more complicated sounds, they would take several sine wave oscillators which they would combine in ways to reproduce a wave, and they wouldn&amp;#8217;t need many because after a while the approximation was good enough to replicate the sound. This is fine and dandy, but in digital circuits we do not use sine waves as our building blocks, instead we use impulses.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The Impulse wave:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;An impulse wave is completely different from a sine wave, instead of taking a wave as an infinite series of sine waves; we take the function and evaluate its value at a specific time t. We break the function up into many steps and by taking the value at every step we can reconstruct the wave. In this scenario as step size goes to infinity, we get a better reconstruction of the wave.&lt;/p&gt;

&lt;p&gt;In this graph we have 5 impulses (red) that make up the waveform (green). Each impulse exists at time t and has a definite height to it. We break up a wave into specific impulses with definite height, we do this every sample. If the red waveform were 10KHz and we had 5 impulses per period, our sample frequency would be 50KHz. Each sample all we do is record the height of the waveform at that time. &lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://mcuplace.com/mcu/media/blogs/blog/impulse.jpg&quot; rel=&quot;lightbox&quot;&gt;&lt;/p&gt;&lt;div class=&quot;image_block&quot;&gt;&lt;img src=&quot;http://mcuplace.com/mcu/media/blogs/blog/impulse.jpg&quot; alt=&quot;&quot; title=&quot;&quot; width=&quot;400&quot; height=&quot;280&quot; /&gt;&lt;/div&gt;&lt;/a&gt;&lt;p&gt;&lt;/p&gt;

&lt;p&gt;If we were to reconstruct the wave using our impulses we would get the following:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://mcuplace.com/mcu/media/blogs/blog/step.jpg&quot; rel=&quot;lightbox&quot;&gt;&lt;/p&gt;&lt;div class=&quot;image_block&quot;&gt;&lt;img src=&quot;http://mcuplace.com/mcu/media/blogs/blog/step.jpg&quot; alt=&quot;&quot; title=&quot;&quot; width=&quot;400&quot; height=&quot;280&quot; /&gt;&lt;/div&gt;&lt;/a&gt;&lt;p&gt;&lt;/p&gt;

&lt;p&gt;As you can see, its not a pretty picture, but if you were to filter the signal, you would get a pretty good reconstruction of the original. To increase reconstruction we increase the sample rate and get more samples of the waveform per period. A wave with 100 samples/wave looks much more accurate than one with 10 samples/wave.&lt;/p&gt;

&lt;p&gt;One golden rule is that your sampling frequency should always be above that of your highest recorded sound (Or at least the ones you would like to capture)&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Digital Audio:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;The heart of digital audio is taking an analog sound signal in the form of voltage over time and doing periodic analog to digital conversions and then storing these results in memory for later use. &lt;/p&gt;

&lt;p&gt;Lets go back to our graph with the impulses. Lets say the vertical axis is voltage and the horizontal is time. Every impulse we sample a wave:&lt;/p&gt;
&lt;pre&gt;
IMPULSE # -- VOLTAGE -- A2D(Int)(VDD=5V) -- T(uS)(@50KHz/Sample)
1         --  .1     --  5               -- 20
2         --  .2     --  10              -- 40
3         --  .3     --  15              -- 60
4         --  .4     --  21              -- 80
5         --  .5     --  26              -- 100
6         --  .1     --  5               -- 120
7         --  .2     --  10              -- 140
8         --  .3     --  15              -- 160
9         --  .4     --  21              -- 180
10        --  .5     --  26              -- 200
etc...
&lt;/pre&gt;
&lt;p&gt;In all digital audio systems there are two things which determine your bandwidth. &lt;br /&gt;
The first is bit-rate which is how many bits you use to convert the signal. A bit-rate of 8-bits can break a signal up into 256 parts, thus a 5V signal has an ideal resolution of (5/256) 19mV(not bad!).&lt;/p&gt;

&lt;p&gt;The second is sampling-rate, this is how often you sample a waveform, typical MP3 sample rates are about 44.1KHZ or one sample every 22uS.&lt;/p&gt;

&lt;p&gt;The bandwidth of a signal is simply the sample-rate times the bit-rate.&lt;/p&gt;

&lt;p&gt;The advantage of a digital system is that 22uS is rather slow, we can do a lot of work between sampling and storing a waveform, and with some good code we can produce high-quality powerful audio systems which are easy and cheap to make.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;What now?&lt;/b&gt;&lt;br /&gt;
So now that we have an introduction to basic properties of sound, what can we do now? In upcoming posts i will be discussing the PIC18 series of micro-controllers, and some sample code to do audio pass-through and eventually storing and playing back a waveform.&lt;/p&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://mcuplace.com/mcu/blog4.php/2009/12/08/the-fundamentals-of-digital-audio&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>Digital audio is a very powerful thing, we listen to our iPods every day, we stream music from websites using our computers and we work with many algorithms derived from techniques in digital audio. Digital audio has its roots in wave mechanics and is a very fundamental process for modern computation. We will be discussing sound as a wave, some basic properties of waves and how to convert a wave into something which you can store in memory, and techniques to play that wave back. We&#8217;ll start with an introduction to sound and how to represent sound as a wave, and a mathematical function.</p>

<p><b>An introduction to sound:</b></p>

<p>Sound is a wave, and like all waves it transfers energy through a medium, in this case it is usually air. Whenever something emits a &#8220;sound&#8221; it compresses air molecules, these compressed air molecules exert a force on uncompressed ones, this starts a chain reaction and sound propagates; this is the essence of a sound wave. For sound to exist you need a medium, be it air, a solid, liquid or plasma. The sound wave will travel through that medium until it dissipates completely and is undetectable.  Sound is usually the result of a force or stress on an object, you hit a tuning fork on a table, and it will vibrate at a particular frequency. To better visualize a sound wave mathematically, we will look at strign vibrations. </p>

<p><b>String Vibrations:</b></p>

<p>Like a turning fork, a string when plucked vibrates a particular frequency. The frequency at which a string vibrates at is due to its mass, length and tension on that string. The frequency which is most prevalent is called the fundamental frequency, when you play middle c on an instrument the fundamental frequency is 261 Hz. Now if middle c is a set frequency, why does middle c sound different on different instruments? The answer is because the sound from an instrument inst pure, each instrument has a unique harmonic structure which delivers a unique sound. To understand this more let&#8217;s look at the math of a wave.</p>

<p><b>Mathematical representation of a sound wave:</b></p>

<p>The nice thing about waves, is we can represent them mathematically, the simplest being that of a sine wave. Sine is a natural function which oscillates between crest to crest at a particular frequency. We can represent a pure oscillating sound by the following function.</p>

<p><img src="http://mcuplace.com/cgi-bin/mimetex.cgi?F(t) = A sin(\omega t + \phi)" /></p>

<p>Where A is the amplitude (sine is a function which oscillates between 1 and -1, multiplying it by A will result in A as the amplitude). The Greek letter omega is the angular frequency which is denoted in radians/second and the Greek letter phi denotes the angular offset (for all cases in this article we can consider it zeros). A &#8220;Pure&#8221; sound is that which is sinusoidal, we here these all the time on cheap synthesizers, when a sound is sinusoidal, it can be represented by the above formula alone. If a synthesizer were to play middle c, it would produce a sine wave of frequency 261Hz (omega = 640) and what you would notice is that it sounds like the right pitch, but no natural instrument sounds like a pure tone.  When an instrument makes a tone, it is usually comprised of its fundamental frequency and higher order oscillations called harmonics. Harmonics are usually either &#189;(Strings) or &#190;(Closed tube) integer multiples of the fundamental frequency of a lesser amplitude. Because of this we can consider and natural tone a superposition of fundamental sine waves and harmonic sine waves. Most tones in nature are comprised of a superposition of sine waves. We can use this fact to break down any complex sound into a series of many simple ones governed by the very simple formula above.</p>

<p><b>Synthesizer theorem:</b></p>

<p>Breaking a complex sound into a series of sine waves can be done using a Fourier series. A Fourier series simply is a mathematical series which can break apart any repeating oscillations into a series of simpler sine waves. We use a Fourier transform to translate an arbitrary function into a series of sine functions. For the purpose of this article we&#8217;ll use a Fourier series as a concept and we won&#8217;t be exploring the math behind it (Maybe one day).</p>

<p>To give a quick example of this we can consult Wikipedia. We all know and love our humble saw tooth wave; If we find the Fourier series of a saw tooth wave we get the following series as a result.<br />
 </p>

<p><img src="http://mcuplace.com/cgi-bin/mimetex.cgi?F(x)=2 \sum_{n=1}^{\infty}\frac{(-1)^{n+1}}{n}sin(nx)" /></p>

<p>If we take n=1 we get the fundamental frequency of the series:</p>

<p><img src="http://mcuplace.com/cgi-bin/mimetex.cgi?F(x) =2sin(x)" /></p>
<div class="image_block"><img src="http://mcuplace.com/mcu/media/blogs/blog/sine.gif" alt="" title="" width="315" height="133" /></div>

<p>If we take the first 5 terms we get:</p>

<p><img src="http://mcuplace.com/cgi-bin/mimetex.cgi?F(x) = 2sin(x)-sin(2x)+.5sin(3x)-.25sin(4x)+.125sin(5x)" /></p>
<div class="image_block"><img src="http://mcuplace.com/mcu/media/blogs/blog/sawtooth.gif" alt="" title="" width="315" height="124" /></div>

<p>As we take n to infinity, we get a better and better approximation of our function. This is the fundamental way in which analog synthesizers would generate more complicated sounds, they would take several sine wave oscillators which they would combine in ways to reproduce a wave, and they wouldn&#8217;t need many because after a while the approximation was good enough to replicate the sound. This is fine and dandy, but in digital circuits we do not use sine waves as our building blocks, instead we use impulses.</p>

<p><b>The Impulse wave:</b></p>

<p>An impulse wave is completely different from a sine wave, instead of taking a wave as an infinite series of sine waves; we take the function and evaluate its value at a specific time t. We break the function up into many steps and by taking the value at every step we can reconstruct the wave. In this scenario as step size goes to infinity, we get a better reconstruction of the wave.</p>

<p>In this graph we have 5 impulses (red) that make up the waveform (green). Each impulse exists at time t and has a definite height to it. We break up a wave into specific impulses with definite height, we do this every sample. If the red waveform were 10KHz and we had 5 impulses per period, our sample frequency would be 50KHz. Each sample all we do is record the height of the waveform at that time. </p>

<p><a href="http://mcuplace.com/mcu/media/blogs/blog/impulse.jpg" rel="lightbox"></p><div class="image_block"><img src="http://mcuplace.com/mcu/media/blogs/blog/impulse.jpg" alt="" title="" width="400" height="280" /></div></a><p></p>

<p>If we were to reconstruct the wave using our impulses we would get the following:</p>

<p><a href="http://mcuplace.com/mcu/media/blogs/blog/step.jpg" rel="lightbox"></p><div class="image_block"><img src="http://mcuplace.com/mcu/media/blogs/blog/step.jpg" alt="" title="" width="400" height="280" /></div></a><p></p>

<p>As you can see, its not a pretty picture, but if you were to filter the signal, you would get a pretty good reconstruction of the original. To increase reconstruction we increase the sample rate and get more samples of the waveform per period. A wave with 100 samples/wave looks much more accurate than one with 10 samples/wave.</p>

<p>One golden rule is that your sampling frequency should always be above that of your highest recorded sound (Or at least the ones you would like to capture)</p>

<p><b>Digital Audio:</b></p>

<p>The heart of digital audio is taking an analog sound signal in the form of voltage over time and doing periodic analog to digital conversions and then storing these results in memory for later use. </p>

<p>Lets go back to our graph with the impulses. Lets say the vertical axis is voltage and the horizontal is time. Every impulse we sample a wave:</p>
<pre>
IMPULSE # -- VOLTAGE -- A2D(Int)(VDD=5V) -- T(uS)(@50KHz/Sample)
1         --  .1     --  5               -- 20
2         --  .2     --  10              -- 40
3         --  .3     --  15              -- 60
4         --  .4     --  21              -- 80
5         --  .5     --  26              -- 100
6         --  .1     --  5               -- 120
7         --  .2     --  10              -- 140
8         --  .3     --  15              -- 160
9         --  .4     --  21              -- 180
10        --  .5     --  26              -- 200
etc...
</pre>
<p>In all digital audio systems there are two things which determine your bandwidth. <br />
The first is bit-rate which is how many bits you use to convert the signal. A bit-rate of 8-bits can break a signal up into 256 parts, thus a 5V signal has an ideal resolution of (5/256) 19mV(not bad!).</p>

<p>The second is sampling-rate, this is how often you sample a waveform, typical MP3 sample rates are about 44.1KHZ or one sample every 22uS.</p>

<p>The bandwidth of a signal is simply the sample-rate times the bit-rate.</p>

<p>The advantage of a digital system is that 22uS is rather slow, we can do a lot of work between sampling and storing a waveform, and with some good code we can produce high-quality powerful audio systems which are easy and cheap to make.</p>

<p><b>What now?</b><br />
So now that we have an introduction to basic properties of sound, what can we do now? In upcoming posts i will be discussing the PIC18 series of micro-controllers, and some sample code to do audio pass-through and eventually storing and playing back a waveform.</p><div class="item_footer"><p><small><a href="http://mcuplace.com/mcu/blog4.php/2009/12/08/the-fundamentals-of-digital-audio">Original post</a> blogged on <a href="http://b2evolution.net/">b2evolution</a>.</small></p></div>]]></content:encoded>
								<comments>http://mcuplace.com/mcu/blog4.php/2009/12/08/the-fundamentals-of-digital-audio#comments</comments>
			<wfw:commentRss>http://mcuplace.com/mcu/blog4.php?tempskin=_rss2&#38;disp=comments&#38;p=50</wfw:commentRss>
		</item>
				<item>
			<title>Weak Pull up Resistors.</title>
			<link>http://mcuplace.com/mcu/blog4.php/2009/09/21/weak-pull-up-resistors</link>
			<pubDate>Tue, 22 Sep 2009 02:53:24 +0000</pubDate>			<dc:creator>anthony</dc:creator>
			<category domain="alt">Informative</category>
<category domain="main">General</category>			<guid isPermaLink="false">48@http://mcuplace.com/mcu/</guid>
						<description>&lt;p&gt;I haven't posted in a while so i figured i'd get back into the swing of things by posting a short post on the pic's internal weak pull up resistors.&lt;/p&gt;

&lt;p&gt;What are pull up resistors?&lt;/p&gt;

&lt;p&gt;A pull up resistor is a fairly high resistance (usually 1K for TTL and 10K for CMOS) resistor to pull a pin to a high logic level. This is very useful as this prevents your logic levels from floating between 1 and 0. This also lets to prime a pin to a certain logic level and have an event (such as a button press) be used to then pull your pin to another logic level.&lt;/p&gt;

&lt;p&gt;You can also pull pins down to ground if you desire using the same method (except hooking the resistor between the pin and ground instead of the pin and vdd)&lt;/p&gt;

&lt;p&gt;For the pic16f690 you can enable WPA by clearing bit 7 of OPTION_REG (cleared by default) and setting the appropriate bits in the WPUA(bank 1) and WPUB(bank 2) registers.&lt;/p&gt;

&lt;p&gt;This feature is extremely useful in keeping more hardware inside the pic and using as little external hardware as possible. &lt;/p&gt;

&lt;p&gt;Often you will pull up a pin to vdd and have a button press short the pin to ground (making the pin a 0) instead of having an external resistor you can just use the on-chip WPA resistors. &lt;/p&gt;

&lt;p&gt;So, just a short write up for now, but i have plenty of stuff coming in the next coming weeks.&lt;/p&gt;

&lt;p&gt;I would like to introduce the PIC18 line of microcontrollers and begin posing some more sophisticated tutorials. &lt;/p&gt;

&lt;p&gt;I will also be updating the circuit blog to include some soldering advice. &lt;/p&gt;

&lt;p&gt;Most importantly, i need suggestions and comments, if there is a guide you would like to see, please don't hesitate to ask!&lt;/p&gt;

&lt;p&gt;I'm looking forward to the next year to bring even more exciting content to my blog!&lt;/p&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://mcuplace.com/mcu/blog4.php/2009/09/21/weak-pull-up-resistors&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>I haven't posted in a while so i figured i'd get back into the swing of things by posting a short post on the pic's internal weak pull up resistors.</p>

<p>What are pull up resistors?</p>

<p>A pull up resistor is a fairly high resistance (usually 1K for TTL and 10K for CMOS) resistor to pull a pin to a high logic level. This is very useful as this prevents your logic levels from floating between 1 and 0. This also lets to prime a pin to a certain logic level and have an event (such as a button press) be used to then pull your pin to another logic level.</p>

<p>You can also pull pins down to ground if you desire using the same method (except hooking the resistor between the pin and ground instead of the pin and vdd)</p>

<p>For the pic16f690 you can enable WPA by clearing bit 7 of OPTION_REG (cleared by default) and setting the appropriate bits in the WPUA(bank 1) and WPUB(bank 2) registers.</p>

<p>This feature is extremely useful in keeping more hardware inside the pic and using as little external hardware as possible. </p>

<p>Often you will pull up a pin to vdd and have a button press short the pin to ground (making the pin a 0) instead of having an external resistor you can just use the on-chip WPA resistors. </p>

<p>So, just a short write up for now, but i have plenty of stuff coming in the next coming weeks.</p>

<p>I would like to introduce the PIC18 line of microcontrollers and begin posing some more sophisticated tutorials. </p>

<p>I will also be updating the circuit blog to include some soldering advice. </p>

<p>Most importantly, i need suggestions and comments, if there is a guide you would like to see, please don't hesitate to ask!</p>

<p>I'm looking forward to the next year to bring even more exciting content to my blog!</p><div class="item_footer"><p><small><a href="http://mcuplace.com/mcu/blog4.php/2009/09/21/weak-pull-up-resistors">Original post</a> blogged on <a href="http://b2evolution.net/">b2evolution</a>.</small></p></div>]]></content:encoded>
								<comments>http://mcuplace.com/mcu/blog4.php/2009/09/21/weak-pull-up-resistors#comments</comments>
			<wfw:commentRss>http://mcuplace.com/mcu/blog4.php?tempskin=_rss2&#38;disp=comments&#38;p=48</wfw:commentRss>
		</item>
				<item>
			<title>PIC Memory Organization &#38; EEPROM Control</title>
			<link>http://mcuplace.com/mcu/blog4.php/2009/04/01/pic-data-memory-organization</link>
			<pubDate>Wed, 01 Apr 2009 12:23:47 +0000</pubDate>			<dc:creator>anthony</dc:creator>
			<category domain="main">Informative</category>
<category domain="alt">General</category>			<guid isPermaLink="false">44@http://mcuplace.com/mcu/</guid>
						<description>&lt;p&gt;One of the most key features of any electronic system is how memory is organized. This includes how much Ram and Rom, how they are subdivided and how to access the memory. Every series of PIC is different and every PIC has different amounts of memory. It is your job to understand how memory is mapped in your system and to use if efficiently. &lt;/p&gt;

&lt;p&gt;A memory system defines a system, it is the one thing that makes it unique and when you master it, you master a system. This has two effects, it makes a system hard to master, and it makes other systems easier to use. Every system from X86 to PowerPC to our PICs are essentially the same thing, ROM to store program data, RAM to store variables and running code and a processor to crunch data. No matter what, a processor might have different instructions, but it still is a beast that doesn&amp;#8217;t change too much. ROM and RAM define a system; every system is going to use it differently.  The logic rarely changes system to system however the code can do a complete 360 depending on what system you use just because of how memory is mapped. &lt;/p&gt;

&lt;p&gt;First let&amp;#8217;s define a few things:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;RAM (Random Access Memory):&lt;/b&gt; This is the place where your variables reside (General Purpose Registers), and how you access special function registers. When you setup a Cblock or set a variable to an address, this is where it&amp;#8217;s going. RAM is super fast but very limited, and everything is stored temporarily. RAM is merely to hold values that are important to current operation.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;ROM (Read-Only Memory):&lt;/b&gt; ROM is like your hard disk, its where all permanent data is stored, like your program. This is marginally slower but not too slow. Unlike your hard disk, this ROM is super fast since it&amp;#8217;s on die. When you program your code onto a PIC this is where it goes. &lt;/p&gt;

&lt;p&gt;Since a lot of this blog focuses on the PIC16F690 I am going to be going over the memory architecture of it.&lt;br /&gt;
 &lt;br /&gt;
Everything on memory organization can be found in the section 2.0 Memory Organization: &lt;br /&gt;
&lt;a href=&quot;http://ww1.microchip.com/downloads/en/DeviceDoc/41262E.pdf&quot;&gt;http://ww1.microchip.com/downloads/en/DeviceDoc/41262E.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first section goes over a few things you should know:&lt;/p&gt;

&lt;p&gt;The RAM is partitioned into 4 banks (0-3). Depending on the data you&amp;#8217;re addressing depends on which bank you need to access.  In each bank you&amp;#8217;ll find a mirage of General Purpose Registers, used for storing program variables, and Special Function Registers, used for controlling the microcontroller. The next few tables&amp;#8217; show where these SFR reside and what banks they&amp;#8217;re located in. The rest is just trivial stuff we&amp;#8217;ve gone over before.&lt;/p&gt;

&lt;p&gt;Likewise how the RAM is partitioned so is the ROM. The ROM is compromised by Program Memory and Data Memory. Program memory is reserved for your program (however on PIC18&amp;#8217;s and above you can write to it and use it for data). Data memory is used exclusively for storing data. On the PIC16F690 it is 256 Bytes. Writing and controlling this DATA ROM is not as straight forward as controlling a GPR.&lt;/p&gt;

&lt;p&gt;The PIC has a built in EEPROM control module which you use to read and write to EEPROM.&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;
The EEPROM Control Module:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;This module is fairly simple and allows you to store program variables in hard data for later use. 256 Bytes doesn&amp;#8217;t sound like much but it does come in handy.&lt;br /&gt;
 &lt;br /&gt;
&lt;b&gt;The Registers:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;EECON1:&lt;/b&gt; Control register.&lt;br /&gt;
&lt;b&gt;EECON2:&lt;/b&gt; Non implemented register used in writing data (see below)&lt;br /&gt;
&lt;b&gt;EEDAT:&lt;/b&gt; This is the register that holds the data to be written or has been read.&lt;br /&gt;
&lt;b&gt;EEDATH:&lt;/b&gt; Some memory is larger than 8 bits so this is the High portion of the register that contains the MSB of a non 8-bit number.&lt;br /&gt;
&lt;b&gt;EEADR:&lt;/b&gt; This is the register that holds the memory address of the a data to be read or written&lt;br /&gt;
&lt;b&gt;EEADRH:&lt;/b&gt; The high register for EEADR for non 8-bit addresses.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The Sequence:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Write (Data memory only):&lt;/i&gt;&lt;br /&gt;
Configure EEPROM for write&lt;br /&gt;
Set the address to be written to EEADR and EEADRH&lt;br /&gt;
Set the data in the data registers&lt;br /&gt;
Initiate a write sequence and wait. &lt;/p&gt;

&lt;p&gt;&lt;i&gt;Read (Data and program memory):&lt;/i&gt;&lt;br /&gt;
Configure EEPROM for read&lt;br /&gt;
Set the address to be read to EEADR and EEADRH&lt;br /&gt;
Initiate a read sequence and wait. &lt;br /&gt;
Data will be in the data register.&lt;/p&gt;

&lt;p&gt;The sequence is pretty straightforward, the only tough part is the control so lets go over EECON1.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;EECON1: EEPROM control register&lt;/b&gt;&lt;br /&gt;
&lt;i&gt;Bit 7:&lt;/i&gt; EEPGD &amp;#8211; 1: Access Program Memory 0: Acess Data memory&lt;br /&gt;
&lt;i&gt;Bit 6-4:&lt;/i&gt; Unimplemented&lt;br /&gt;
&lt;i&gt;Bit 3:&lt;/i&gt; WRERR &amp;#8211; 1: There was a write error 0: Write operation completed&lt;br /&gt;
&lt;i&gt;Bit 2:&lt;/i&gt; WREN &amp;#8211; 1: Allows write to EEPROM 0: Write is not allowed&lt;br /&gt;
&lt;i&gt;Bit 1:&lt;/i&gt; WR &amp;#8211; 1: Initiates a write 0: Write is complete&lt;br /&gt;
&lt;i&gt;Bit 0:&lt;/i&gt; RD &amp;#8211; 1: Initiates a Read 0: Read is complete.&lt;/p&gt;

&lt;p&gt;As you can see, this module is pretty simple a sample read code will be something of the sort:&lt;/p&gt;

&lt;pre&gt;
clrf  EECON1 ;Read Data memory, do not allow writes
movlw 0x00
movwf EEADR
movwf EEADRH   ;Clear address location start at 00
bsf   EECON1,0  ;Initiate read
btfsc EECON1,0  ;Wait till clear
goto  $-1
movfw EEDAT     ;Move read data to where-ever
movwf DAT
&lt;/pre&gt;

&lt;p&gt;Reading from EEPROM will be very similar to the above routine just make sure you're in the right banks for each register (EECON1 and EEDAT/EEADR aren't in the same bank)&lt;/p&gt;

&lt;p&gt;Writing to the EEPROM isn't exactly as intuitive as reading but is still pretty easy:&lt;/p&gt;

&lt;p&gt;Just like above, you set up the EECON1 register for whatever you're doing and move the data you want to write into EEDAT and the address you want to in EEADR and EEADRH. After you do that, you initiate a write sequence such as the following:&lt;/p&gt;

&lt;pre&gt;
WRITE:
	bsf      STATUS,RP0
	movlw    0x55      
	movwf    EECON2
	movlw    0xAA
	movwf    EECON2
	bsf      EECON1,WR   
	btfsc    EECON1,WR
	goto     $-1
	bcf      STATUS,RP0
	return
&lt;/pre&gt;

&lt;p&gt;Now, to write to data EEPROM you must write 0x55 then 0xAA to EECON2 (one after another) and then set the WR bit on EECON1. &lt;/p&gt;

&lt;p&gt;This sequence is what is required by Microchip in their data sheet. &lt;/p&gt;

&lt;p&gt;Other thank that, EEPROM control is fairly straight forward and is very powerful. &lt;/p&gt;

&lt;p&gt;Good luck and any questions/concerns please feel free to send me an EMAIL.&lt;/p&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://mcuplace.com/mcu/blog4.php/2009/04/01/pic-data-memory-organization&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>One of the most key features of any electronic system is how memory is organized. This includes how much Ram and Rom, how they are subdivided and how to access the memory. Every series of PIC is different and every PIC has different amounts of memory. It is your job to understand how memory is mapped in your system and to use if efficiently. </p>

<p>A memory system defines a system, it is the one thing that makes it unique and when you master it, you master a system. This has two effects, it makes a system hard to master, and it makes other systems easier to use. Every system from X86 to PowerPC to our PICs are essentially the same thing, ROM to store program data, RAM to store variables and running code and a processor to crunch data. No matter what, a processor might have different instructions, but it still is a beast that doesn&#8217;t change too much. ROM and RAM define a system; every system is going to use it differently.  The logic rarely changes system to system however the code can do a complete 360 depending on what system you use just because of how memory is mapped. </p>

<p>First let&#8217;s define a few things:</p>

<p><b>RAM (Random Access Memory):</b> This is the place where your variables reside (General Purpose Registers), and how you access special function registers. When you setup a Cblock or set a variable to an address, this is where it&#8217;s going. RAM is super fast but very limited, and everything is stored temporarily. RAM is merely to hold values that are important to current operation.</p>

<p><b>ROM (Read-Only Memory):</b> ROM is like your hard disk, its where all permanent data is stored, like your program. This is marginally slower but not too slow. Unlike your hard disk, this ROM is super fast since it&#8217;s on die. When you program your code onto a PIC this is where it goes. </p>

<p>Since a lot of this blog focuses on the PIC16F690 I am going to be going over the memory architecture of it.<br />
 <br />
Everything on memory organization can be found in the section 2.0 Memory Organization: <br />
<a href="http://ww1.microchip.com/downloads/en/DeviceDoc/41262E.pdf">http://ww1.microchip.com/downloads/en/DeviceDoc/41262E.pdf</a></p>

<p>The first section goes over a few things you should know:</p>

<p>The RAM is partitioned into 4 banks (0-3). Depending on the data you&#8217;re addressing depends on which bank you need to access.  In each bank you&#8217;ll find a mirage of General Purpose Registers, used for storing program variables, and Special Function Registers, used for controlling the microcontroller. The next few tables&#8217; show where these SFR reside and what banks they&#8217;re located in. The rest is just trivial stuff we&#8217;ve gone over before.</p>

<p>Likewise how the RAM is partitioned so is the ROM. The ROM is compromised by Program Memory and Data Memory. Program memory is reserved for your program (however on PIC18&#8217;s and above you can write to it and use it for data). Data memory is used exclusively for storing data. On the PIC16F690 it is 256 Bytes. Writing and controlling this DATA ROM is not as straight forward as controlling a GPR.</p>

<p>The PIC has a built in EEPROM control module which you use to read and write to EEPROM.<br />
<b><br />
The EEPROM Control Module:</b></p>

<p>This module is fairly simple and allows you to store program variables in hard data for later use. 256 Bytes doesn&#8217;t sound like much but it does come in handy.<br />
 <br />
<b>The Registers:</b></p>

<p><b>EECON1:</b> Control register.<br />
<b>EECON2:</b> Non implemented register used in writing data (see below)<br />
<b>EEDAT:</b> This is the register that holds the data to be written or has been read.<br />
<b>EEDATH:</b> Some memory is larger than 8 bits so this is the High portion of the register that contains the MSB of a non 8-bit number.<br />
<b>EEADR:</b> This is the register that holds the memory address of the a data to be read or written<br />
<b>EEADRH:</b> The high register for EEADR for non 8-bit addresses.</p>

<p><b>The Sequence:</b></p>

<p><i>Write (Data memory only):</i><br />
Configure EEPROM for write<br />
Set the address to be written to EEADR and EEADRH<br />
Set the data in the data registers<br />
Initiate a write sequence and wait. </p>

<p><i>Read (Data and program memory):</i><br />
Configure EEPROM for read<br />
Set the address to be read to EEADR and EEADRH<br />
Initiate a read sequence and wait. <br />
Data will be in the data register.</p>

<p>The sequence is pretty straightforward, the only tough part is the control so lets go over EECON1.</p>

<p><b>EECON1: EEPROM control register</b><br />
<i>Bit 7:</i> EEPGD &#8211; 1: Access Program Memory 0: Acess Data memory<br />
<i>Bit 6-4:</i> Unimplemented<br />
<i>Bit 3:</i> WRERR &#8211; 1: There was a write error 0: Write operation completed<br />
<i>Bit 2:</i> WREN &#8211; 1: Allows write to EEPROM 0: Write is not allowed<br />
<i>Bit 1:</i> WR &#8211; 1: Initiates a write 0: Write is complete<br />
<i>Bit 0:</i> RD &#8211; 1: Initiates a Read 0: Read is complete.</p>

<p>As you can see, this module is pretty simple a sample read code will be something of the sort:</p>

<pre>
clrf  EECON1 ;Read Data memory, do not allow writes
movlw 0x00
movwf EEADR
movwf EEADRH   ;Clear address location start at 00
bsf   EECON1,0  ;Initiate read
btfsc EECON1,0  ;Wait till clear
goto  $-1
movfw EEDAT     ;Move read data to where-ever
movwf DAT
</pre>

<p>Reading from EEPROM will be very similar to the above routine just make sure you're in the right banks for each register (EECON1 and EEDAT/EEADR aren't in the same bank)</p>

<p>Writing to the EEPROM isn't exactly as intuitive as reading but is still pretty easy:</p>

<p>Just like above, you set up the EECON1 register for whatever you're doing and move the data you want to write into EEDAT and the address you want to in EEADR and EEADRH. After you do that, you initiate a write sequence such as the following:</p>

<pre>
WRITE:
	bsf      STATUS,RP0
	movlw    0x55      
	movwf    EECON2
	movlw    0xAA
	movwf    EECON2
	bsf      EECON1,WR   
	btfsc    EECON1,WR
	goto     $-1
	bcf      STATUS,RP0
	return
</pre>

<p>Now, to write to data EEPROM you must write 0x55 then 0xAA to EECON2 (one after another) and then set the WR bit on EECON1. </p>

<p>This sequence is what is required by Microchip in their data sheet. </p>

<p>Other thank that, EEPROM control is fairly straight forward and is very powerful. </p>

<p>Good luck and any questions/concerns please feel free to send me an EMAIL.</p><div class="item_footer"><p><small><a href="http://mcuplace.com/mcu/blog4.php/2009/04/01/pic-data-memory-organization">Original post</a> blogged on <a href="http://b2evolution.net/">b2evolution</a>.</small></p></div>]]></content:encoded>
								<comments>http://mcuplace.com/mcu/blog4.php/2009/04/01/pic-data-memory-organization#comments</comments>
			<wfw:commentRss>http://mcuplace.com/mcu/blog4.php?tempskin=_rss2&#38;disp=comments&#38;p=44</wfw:commentRss>
		</item>
				<item>
			<title>Accelerate</title>
			<link>http://mcuplace.com/mcu/blog4.php/2009/01/31/accelerate</link>
			<pubDate>Sat, 31 Jan 2009 20:55:06 +0000</pubDate>			<dc:creator>anthony</dc:creator>
			<category domain="alt">Code</category>
<category domain="main">Projects</category>			<guid isPermaLink="false">39@http://mcuplace.com/mcu/</guid>
						<description>&lt;p&gt;&lt;b&gt;The project:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;This project is a simple but fun one. We are going to be using a tri-axis accelerometer to collect analog data from and then display it on the LCD. Our output on the LCD will look like:&lt;/p&gt;

&lt;p&gt;|X||:|| ||Digit1||Digit2||Digit3|&lt;br /&gt;
|Y||:|| ||Digit1||Digit2||Digit3|&lt;br /&gt;
|Z||:|| ||Digit1||Digit2||Digit3|&lt;/p&gt;

&lt;p&gt;The X:, Y:, and Z: are all static and only have to be sent once. (once you update the DDRAM address it stays there until power is cut) The digits however, have to be updated as we get new values, thus it is dynamically updated in our code and sent periodically.&lt;/p&gt;

&lt;p&gt;This algorithm is fairly simple and works automatically. The procedure goes:&lt;/p&gt;

&lt;p&gt;-Initialize the MCU&lt;br /&gt;
-Initialize the LCD&lt;br /&gt;
-Draw the static information&lt;br /&gt;
-Collect the analog information&lt;br /&gt;
-Convert the raw data into digits&lt;br /&gt;
-Display the data on the LCD.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The Code:&lt;/b&gt;&lt;/p&gt;
&lt;pre&gt;
The Code:  #include p16F690.inc
     __config (_INTRC_OSC_NOCLKOUT &amp;amp; _WDT_OFF &amp;amp; _PWRTE_OFF &amp;amp; _MCLRE_OFF &amp;amp; _CP_OFF &amp;amp; _BOR_OFF &amp;amp; _IESO_OFF &amp;amp; _FCMEN_OFF)
org 0              ; Begginning of code
cblock 0x20
	CHARLOCATION
	RESULT
	ONES	
	TENS
	HUNDREDS
	TEMP
	DELAY1
	DELAY2
	COUNT
endc
PORTS:
	bsf       STATUS,RP1     ; Bank 2
	movlw     0x14           ; RA2 &amp;amp; 4 Configured for analog AN2,3
	movwf     ANSEL          ; 
	movlw     0x08           ; RB5 configured for analog (AN11)
	movwf     ANSELH
	bcf       STATUS,RP1
	bsf       STATUS,RP0     ; select Register Page 1
	movlw     0x00           ; Move the hex value of 0 to multi purpose register W
    movwf     TRISC          ; make IO PortC all output
	movlw     0x16           ; Make Ra4,2 and 1 Input
	movwf     TRISA
	movlw     0x20           ;RB5 Input
	movwf     TRISB
	movlw     0x10           ;set A2d Clock 
    movwf     ADCON1
	bcf       STATUS,RP0     ;Exit bank 1
	;initialize 
	clrf      PORTC
	clrf      PORTA
	clrf      PORTB
	clrf      COUNT
	clrf      TEMP
	call      INITIALIZELCD
	call      DRAWLCD
MAIN:                                           ; Our MAIN routine gets the analog value off a port, and updates the LCD with the info
	movlw     0x41                             
	movwf     ADCON0     ;Channel 2
	call      A2D        ;Get A2D value
	movwf     RESULT
	movlw     0x83       ;Char position 03
	call      UPDATELCD  ;Call Update LCD, having the char position in W
	movlw     0x4D  
	movwf     ADCON0     ;Channel 3
	call      A2D
	movwf     RESULT
	movlw     0xC3       ;Char Position 43
	call      UPDATELCD	
	movlw     0x6D  
	movwf     ADCON0     ;Channel 11
	call      A2D
	movwf     RESULT
	movlw     0x97      ;Char position 17
	call      UPDATELCD
	call      DELAY
	goto 	  MAIN      ; Return to main
A2D:
	nop 
	nop
	nop
	nop
	nop                 ; wait 5 uS
	bsf       ADCON0,GO ; Start the conversion
	btfss     ADCON0,GO ; Bit will stay high untill conversion is complete
	goto      $-1       ; Untill then keep going back
    movf      ADRESH,w
	return
INITIALIZELCD:          ;Initialization Routine for the LCD
	bsf       PORTC,0   ;Put CMD 0 on port C
	call      SEND      ;Call Send routine, Sends command and waits for busy flag
  	movlw     0x38      ; Set Function, 8 Bit, 5X10 Dots, Two line
  	movwf     PORTC
	call      SEND
	movlw     b'00001100' ; Turn on the Display (0x0B
	movwf     PORTC
	call      SEND
        movlw     0x06       ; Set entry mode to: Increment Adress counter, no shift.
	movwf     PORTC
	call      SEND
	return
DRAWLCD:                 ; Routine which draws static display
	movlw     0x80       ; Start with the DDRAM address 0x00
	call      WRITELOC   ; Call Function to write the DDRAM address
	movlw     'X'        ;Move the ASCII value of 'X' to W
	call      WRITECHAR  ; Call function to write the Char to DDRAM address
	movlw     0x3A       
	call      WRITECHAR
	movlw     0xC0       
	call      WRITELOC
	movlw     'Y'
	call      WRITECHAR
	movlw     0x3A
	call      WRITECHAR
	movlw     0x94       
	call      WRITELOC
	movlw     'Z'
	call      WRITECHAR
	movlw     0x3A
	call      WRITECHAR  ; Continue untill all static elements drawm
	return
WRITECHAR:               ; Function to write a characture 
	movwf     TEMP       ; Move value to temp register
	call      BUSYCHK    ; Check Busy flag
	bsf       PORTA,0    ; Turn on Data 
	movfw     TEMP       ; Move from Temp to W
	movwf     PORTC      ; Then to PORTC
	call      SEND       ; Send
	bcf       PORTA,0    ; Turn off Data
	return
WRITELOC:
	movwf     TEMP       ;Move value to temp
	call      BUSYCHK    ;Check busy flag
	movfw     TEMP       ;Temp -&gt; W
	movwf     PORTC      ;W -&gt; Portc
	call      SEND       ;SEND
	return
UPDATELCD:               ; Routine to update the dynamic elements of the LCD
	call      WRITELOC   ; Init the LCD at the proper DDRAM location
	clrf      ONES       ; Clear Vars
	clrf      TENS
	clrf      HUNDREDS
	call      CALCULATE  ; Call calculate routine which takes raw A2D value and separates them into digits
	movfw     HUNDREDS   ; Write the Hundreds digit to the LCD
	call      TABLE1
	call      WRITECHAR
	movfw     TENS       ;Write Tens
	call      TABLE1
	call      WRITECHAR
	movfw     ONES       ;Write Ones
	call      TABLE1
	call      WRITECHAR
	return
CALCULATE:               ; Basic math routine, takes Result from A2D and separates into 1's 10's and 100's
	movlw     0x00
	bcf       STATUS,2
	xorwf     RESULT,w
	btfsc     STATUS,2
	return    
	movlw     0x0A
	bcf       STATUS,2
	subwf     ONES,w
	btfsc     STATUS,2
	goto      UPDATETENS
	decf      RESULT,f
	incf      ONES,f
	goto      CALCULATE
UPDATETENS:
	clrf      ONES
	incf      TENS,f
	movlw     0x09
	bcf       STATUS,2
	subwf     TENS,w
	btfsc     STATUS,2
	call      UPDATEHUNS
	decf      RESULT,f
	goto      CALCULATE
UPDATEHUNS:
	clrf      TENS
	incf      HUNDREDS,f
	movlw     0x09
	bcf       STATUS,2
	subwf     HUNDREDS,w
	btfsc     STATUS,2
	incf      HUNDREDS,f
	return
SEND:                         ;Use this routine to send a command to the LCD. Placement doesnt matter as it does two BSYFLG checks
	;Send
	bsf       PORTB,4         ; Set E line High
	nop       
	nop
	nop
	nop
	bcf       PORTB,4         ;Wait a bit then set it low, sending command to LCD
BUSYCHK:
	bsf       STATUS,RP0      ; Port C, all input
	movlw     0xff	
	movwf     TRISC
	bcf       STATUS,RP0
	bsf       PORTA,5         ;Set Read
	nop
	nop
	bsf       PORTB,4         ;E Line high
	nop       
	nop
	nop
	nop
	bcf       PORTB,4          ;Wait, Now low, Polling busy flag
	btfsc     PORTC,7          ; Wait untill busy flag is clear.     
	goto      $-7
	bcf       PORTA,5          ;Turn off Read
	bsf       STATUS,RP0
	movlw     0x00	
	movwf     TRISC
	bcf       STATUS,RP0       ;Port c all output
	return
TABLE1:                        ;Generic Table: Decimal -&gt; ASCII
	addwf     PCL;	
	retlw     0x30
	retlw     0x31
	retlw     0x32
	retlw     0x33
	retlw     0x34
	retlw     0x35
	retlw     0x36
	retlw     0x37
	retlw     0x38
	retlw     0x39
	return
DELAY:                       ;Generic Delay
	decfsz    DELAY1
	goto      DELAY
	decfsz    DELAY2
	goto      DELAY
	return
 end
&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;The Breakdown:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;This code is fairly simple, there are no interrupts to worry about. We set up our variables in available registers as always. Our ports routine is much of the same, we set the appropriate ports for analog function and then set the appropriate I/O&lt;br /&gt;
&lt;i&gt;&lt;br /&gt;
Initialize the LCD:&lt;/i&gt;&lt;/p&gt;

&lt;pre&gt;
INITIALIZELCD:          ;Initialization Routine for the LCD
	bsf       PORTC,0   ;Put CMD 0 on port C
	call      SEND      ;Call Send routine, Sends command and waits for busy flag
  	movlw     0x38      ; Set Function, 8 Bit, 5X10 Dots, Two line
  	movwf     PORTC
	call      SEND
	movlw     b'00001100' ; Turn on the Display (0x0B
	movwf     PORTC
	call      SEND
        movlw     0x06       ; Set entry mode to: Increment Adress counter, no shift.
	movwf     PORTC
	call      SEND
	return
&lt;/pre&gt;

&lt;p&gt;Remember all those commands? We have to first tell the LCD what we want it to do before we start writing to the DDRAM. We set our LCD up for how were going to use it. This a fairly common initialization routine. We turn on the display, set 8 bit data control, two line, 5x10 font, and we have the address counter increment on write to DDRAM.&lt;/p&gt;

&lt;p&gt;This routine we load the command we want into PORTC and then call our Send routine&lt;br /&gt;
&lt;i&gt;&lt;br /&gt;
The Send Routine:&lt;/i&gt;&lt;/p&gt;

&lt;pre&gt;
SEND:                         ;Use this routine to send a command to the LCD. Placement doesnt matter as it does two BSYFLG checks
	;Send
	bsf       PORTB,4         ; Set E line High
	nop       
	nop
	nop
	nop
	bcf       PORTB,4         ;Wait a bit then set it low, sending command to LCD
BUSYCHK:
	bsf       STATUS,RP0      ; Port C, all input
	movlw     0xff	
	movwf     TRISC
	bcf       STATUS,RP0
	bsf       PORTA,5         ;Set Read
	nop
	nop
	bsf       PORTB,4         ;E Line high
	nop       
	nop
	nop
	nop
	bcf       PORTB,4          ;Wait, Now low, Polling busy flag
	btfsc     PORTC,7          ; Wait untill busy flag is clear.     
	goto      $-7
	bcf       PORTA,5          ;Turn off Read
	bsf       STATUS,RP0
	movlw     0x00	
	movwf     TRISC
	bcf       STATUS,RP0       ;Port c all output
	return
&lt;/pre&gt;

&lt;p&gt;To send data the the LCD we have to toggle the E line. We set it high momentarily then we set it low. Once we do that the LCD reads the command and performs an internal operation. As this happens the BSY Flag is set on the LCD and we poll this until it is clear. After which we continue with normal operation by exiting the routine &lt;/p&gt;

&lt;p&gt;Drawing the Static Display:&lt;/p&gt;

&lt;p&gt;We draw all the static information by first setting the DDRAM address position and then putting the value we wish to send into w and then calling a routine which sends the value to the LCD&lt;/p&gt;

&lt;pre&gt;
WRITELOC:
	movwf     TEMP       ;Move value to temp
	call      BUSYCHK    ;Check busy flag
	movfw     TEMP       ;Temp -&gt; W
	movwf     PORTC      ;W -&gt; Portc
	call      SEND       ;SEND
	return
&lt;/pre&gt;

&lt;p&gt;Basic routine that makes it a little more mechanical to write data to the LCD. The value in W is sent to the LCD&lt;/p&gt;

&lt;pre&gt;
WRITECHAR:               ; Function to write a characture 
	movwf     TEMP       ; Move value to temp register
	call      BUSYCHK    ; Check Busy flag
	bsf       PORTA,0    ; Turn on Data 
	movfw     TEMP       ; Move from Temp to W
	movwf     PORTC      ; Then to PORTC
	call      SEND       ; Send
	bcf       PORTA,0    ; Turn off Data
	return
&lt;/pre&gt;

&lt;p&gt;Another routine specially designed for writing a character to a DDRAM address. This sets our PORTA,0 (Instruction/Data) high as we send Data to the LCD.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;The MAIN routine:&lt;/i&gt;&lt;br /&gt;
The main routine is fairly simple, we generate an A2D result and then call the routine which does the dynamic updating of the LCD (we do this 3 times for each of the 3 axis (xyz)&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Updating the LCD:&lt;/i&gt;&lt;/p&gt;

&lt;pre&gt;
UPDATELCD:               ; Routine to update the dynamic elements of the LCD
	call      WRITELOC   ; Init the LCD at the proper DDRAM location
	clrf      ONES       ; Clear Vars
	clrf      TENS
	clrf      HUNDREDS
	call      CALCULATE  ; Call calculate routine which takes raw A2D value and separates them into digits
	movfw     HUNDREDS   ; Write the Hundreds digit to the LCD
	call      TABLE1
	call      WRITECHAR
	movfw     TENS       ;Write Tens
	call      TABLE1
	call      WRITECHAR
	movfw     ONES       ;Write Ones
	call      TABLE1
	call      WRITECHAR
	return
&lt;/pre&gt;

&lt;p&gt;This is another simple routine, we take the A2D result, break it down into its individual digits and send it to the LCD. We provide the DDRAM address in w before we call the function, thus this can be used for more than 1 axis making our code much more efficient.&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;
Conclusion:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Overall this is a fairly easy project that goes over the basics of controlling an HD44780 character LCD using a tri axis accelerometer as an analog input. &lt;/p&gt;

&lt;p&gt;Ill leave you with a picture of the completed project as well the source and hex. Enjoy!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://mcuplace.com/mcu/media/blogs/blog/IMG00058.jpg&quot; alt=&quot;&quot; title=&quot;&quot; width=&quot;400&quot; height=&quot;300&quot; /&gt; &lt;/p&gt;

&lt;p&gt;Whats next:  Making it display proper units&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://mcuplace.com/mcu/media/blogs/blog/ameter.asm&quot; title=&quot;&quot;&gt;Source&lt;/a&gt; &lt;br /&gt;
&lt;a href=&quot;http://mcuplace.com/mcu/media/blogs/blog/ameter.HEX&quot; title=&quot;&quot;&gt;Hex&lt;/a&gt;&lt;/p&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://mcuplace.com/mcu/blog4.php/2009/01/31/accelerate&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p><b>The project:</b></p>

<p>This project is a simple but fun one. We are going to be using a tri-axis accelerometer to collect analog data from and then display it on the LCD. Our output on the LCD will look like:</p>

<p>|X||:|| ||Digit1||Digit2||Digit3|<br />
|Y||:|| ||Digit1||Digit2||Digit3|<br />
|Z||:|| ||Digit1||Digit2||Digit3|</p>

<p>The X:, Y:, and Z: are all static and only have to be sent once. (once you update the DDRAM address it stays there until power is cut) The digits however, have to be updated as we get new values, thus it is dynamically updated in our code and sent periodically.</p>

<p>This algorithm is fairly simple and works automatically. The procedure goes:</p>

<p>-Initialize the MCU<br />
-Initialize the LCD<br />
-Draw the static information<br />
-Collect the analog information<br />
-Convert the raw data into digits<br />
-Display the data on the LCD.</p>

<p><b>The Code:</b></p>
<pre>
The Code:  #include p16F690.inc
     __config (_INTRC_OSC_NOCLKOUT &amp; _WDT_OFF &amp; _PWRTE_OFF &amp; _MCLRE_OFF &amp; _CP_OFF &amp; _BOR_OFF &amp; _IESO_OFF &amp; _FCMEN_OFF)
org 0              ; Begginning of code
cblock 0x20
	CHARLOCATION
	RESULT
	ONES	
	TENS
	HUNDREDS
	TEMP
	DELAY1
	DELAY2
	COUNT
endc
PORTS:
	bsf       STATUS,RP1     ; Bank 2
	movlw     0x14           ; RA2 &amp; 4 Configured for analog AN2,3
	movwf     ANSEL          ; 
	movlw     0x08           ; RB5 configured for analog (AN11)
	movwf     ANSELH
	bcf       STATUS,RP1
	bsf       STATUS,RP0     ; select Register Page 1
	movlw     0x00           ; Move the hex value of 0 to multi purpose register W
    movwf     TRISC          ; make IO PortC all output
	movlw     0x16           ; Make Ra4,2 and 1 Input
	movwf     TRISA
	movlw     0x20           ;RB5 Input
	movwf     TRISB
	movlw     0x10           ;set A2d Clock 
    movwf     ADCON1
	bcf       STATUS,RP0     ;Exit bank 1
	;initialize 
	clrf      PORTC
	clrf      PORTA
	clrf      PORTB
	clrf      COUNT
	clrf      TEMP
	call      INITIALIZELCD
	call      DRAWLCD
MAIN:                                           ; Our MAIN routine gets the analog value off a port, and updates the LCD with the info
	movlw     0x41                             
	movwf     ADCON0     ;Channel 2
	call      A2D        ;Get A2D value
	movwf     RESULT
	movlw     0x83       ;Char position 03
	call      UPDATELCD  ;Call Update LCD, having the char position in W
	movlw     0x4D  
	movwf     ADCON0     ;Channel 3
	call      A2D
	movwf     RESULT
	movlw     0xC3       ;Char Position 43
	call      UPDATELCD	
	movlw     0x6D  
	movwf     ADCON0     ;Channel 11
	call      A2D
	movwf     RESULT
	movlw     0x97      ;Char position 17
	call      UPDATELCD
	call      DELAY
	goto 	  MAIN      ; Return to main
A2D:
	nop 
	nop
	nop
	nop
	nop                 ; wait 5 uS
	bsf       ADCON0,GO ; Start the conversion
	btfss     ADCON0,GO ; Bit will stay high untill conversion is complete
	goto      $-1       ; Untill then keep going back
    movf      ADRESH,w
	return
INITIALIZELCD:          ;Initialization Routine for the LCD
	bsf       PORTC,0   ;Put CMD 0 on port C
	call      SEND      ;Call Send routine, Sends command and waits for busy flag
  	movlw     0x38      ; Set Function, 8 Bit, 5X10 Dots, Two line
  	movwf     PORTC
	call      SEND
	movlw     b'00001100' ; Turn on the Display (0x0B
	movwf     PORTC
	call      SEND
        movlw     0x06       ; Set entry mode to: Increment Adress counter, no shift.
	movwf     PORTC
	call      SEND
	return
DRAWLCD:                 ; Routine which draws static display
	movlw     0x80       ; Start with the DDRAM address 0x00
	call      WRITELOC   ; Call Function to write the DDRAM address
	movlw     'X'        ;Move the ASCII value of 'X' to W
	call      WRITECHAR  ; Call function to write the Char to DDRAM address
	movlw     0x3A       
	call      WRITECHAR
	movlw     0xC0       
	call      WRITELOC
	movlw     'Y'
	call      WRITECHAR
	movlw     0x3A
	call      WRITECHAR
	movlw     0x94       
	call      WRITELOC
	movlw     'Z'
	call      WRITECHAR
	movlw     0x3A
	call      WRITECHAR  ; Continue untill all static elements drawm
	return
WRITECHAR:               ; Function to write a characture 
	movwf     TEMP       ; Move value to temp register
	call      BUSYCHK    ; Check Busy flag
	bsf       PORTA,0    ; Turn on Data 
	movfw     TEMP       ; Move from Temp to W
	movwf     PORTC      ; Then to PORTC
	call      SEND       ; Send
	bcf       PORTA,0    ; Turn off Data
	return
WRITELOC:
	movwf     TEMP       ;Move value to temp
	call      BUSYCHK    ;Check busy flag
	movfw     TEMP       ;Temp -> W
	movwf     PORTC      ;W -> Portc
	call      SEND       ;SEND
	return
UPDATELCD:               ; Routine to update the dynamic elements of the LCD
	call      WRITELOC   ; Init the LCD at the proper DDRAM location
	clrf      ONES       ; Clear Vars
	clrf      TENS
	clrf      HUNDREDS
	call      CALCULATE  ; Call calculate routine which takes raw A2D value and separates them into digits
	movfw     HUNDREDS   ; Write the Hundreds digit to the LCD
	call      TABLE1
	call      WRITECHAR
	movfw     TENS       ;Write Tens
	call      TABLE1
	call      WRITECHAR
	movfw     ONES       ;Write Ones
	call      TABLE1
	call      WRITECHAR
	return
CALCULATE:               ; Basic math routine, takes Result from A2D and separates into 1's 10's and 100's
	movlw     0x00
	bcf       STATUS,2
	xorwf     RESULT,w
	btfsc     STATUS,2
	return    
	movlw     0x0A
	bcf       STATUS,2
	subwf     ONES,w
	btfsc     STATUS,2
	goto      UPDATETENS
	decf      RESULT,f
	incf      ONES,f
	goto      CALCULATE
UPDATETENS:
	clrf      ONES
	incf      TENS,f
	movlw     0x09
	bcf       STATUS,2
	subwf     TENS,w
	btfsc     STATUS,2
	call      UPDATEHUNS
	decf      RESULT,f
	goto      CALCULATE
UPDATEHUNS:
	clrf      TENS
	incf      HUNDREDS,f
	movlw     0x09
	bcf       STATUS,2
	subwf     HUNDREDS,w
	btfsc     STATUS,2
	incf      HUNDREDS,f
	return
SEND:                         ;Use this routine to send a command to the LCD. Placement doesnt matter as it does two BSYFLG checks
	;Send
	bsf       PORTB,4         ; Set E line High
	nop       
	nop
	nop
	nop
	bcf       PORTB,4         ;Wait a bit then set it low, sending command to LCD
BUSYCHK:
	bsf       STATUS,RP0      ; Port C, all input
	movlw     0xff	
	movwf     TRISC
	bcf       STATUS,RP0
	bsf       PORTA,5         ;Set Read
	nop
	nop
	bsf       PORTB,4         ;E Line high
	nop       
	nop
	nop
	nop
	bcf       PORTB,4          ;Wait, Now low, Polling busy flag
	btfsc     PORTC,7          ; Wait untill busy flag is clear.     
	goto      $-7
	bcf       PORTA,5          ;Turn off Read
	bsf       STATUS,RP0
	movlw     0x00	
	movwf     TRISC
	bcf       STATUS,RP0       ;Port c all output
	return
TABLE1:                        ;Generic Table: Decimal -> ASCII
	addwf     PCL;	
	retlw     0x30
	retlw     0x31
	retlw     0x32
	retlw     0x33
	retlw     0x34
	retlw     0x35
	retlw     0x36
	retlw     0x37
	retlw     0x38
	retlw     0x39
	return
DELAY:                       ;Generic Delay
	decfsz    DELAY1
	goto      DELAY
	decfsz    DELAY2
	goto      DELAY
	return
 end
</pre>

<p><b>The Breakdown:</b></p>

<p>This code is fairly simple, there are no interrupts to worry about. We set up our variables in available registers as always. Our ports routine is much of the same, we set the appropriate ports for analog function and then set the appropriate I/O<br />
<i><br />
Initialize the LCD:</i></p>

<pre>
INITIALIZELCD:          ;Initialization Routine for the LCD
	bsf       PORTC,0   ;Put CMD 0 on port C
	call      SEND      ;Call Send routine, Sends command and waits for busy flag
  	movlw     0x38      ; Set Function, 8 Bit, 5X10 Dots, Two line
  	movwf     PORTC
	call      SEND
	movlw     b'00001100' ; Turn on the Display (0x0B
	movwf     PORTC
	call      SEND
        movlw     0x06       ; Set entry mode to: Increment Adress counter, no shift.
	movwf     PORTC
	call      SEND
	return
</pre>

<p>Remember all those commands? We have to first tell the LCD what we want it to do before we start writing to the DDRAM. We set our LCD up for how were going to use it. This a fairly common initialization routine. We turn on the display, set 8 bit data control, two line, 5x10 font, and we have the address counter increment on write to DDRAM.</p>

<p>This routine we load the command we want into PORTC and then call our Send routine<br />
<i><br />
The Send Routine:</i></p>

<pre>
SEND:                         ;Use this routine to send a command to the LCD. Placement doesnt matter as it does two BSYFLG checks
	;Send
	bsf       PORTB,4         ; Set E line High
	nop       
	nop
	nop
	nop
	bcf       PORTB,4         ;Wait a bit then set it low, sending command to LCD
BUSYCHK:
	bsf       STATUS,RP0      ; Port C, all input
	movlw     0xff	
	movwf     TRISC
	bcf       STATUS,RP0
	bsf       PORTA,5         ;Set Read
	nop
	nop
	bsf       PORTB,4         ;E Line high
	nop       
	nop
	nop
	nop
	bcf       PORTB,4          ;Wait, Now low, Polling busy flag
	btfsc     PORTC,7          ; Wait untill busy flag is clear.     
	goto      $-7
	bcf       PORTA,5          ;Turn off Read
	bsf       STATUS,RP0
	movlw     0x00	
	movwf     TRISC
	bcf       STATUS,RP0       ;Port c all output
	return
</pre>

<p>To send data the the LCD we have to toggle the E line. We set it high momentarily then we set it low. Once we do that the LCD reads the command and performs an internal operation. As this happens the BSY Flag is set on the LCD and we poll this until it is clear. After which we continue with normal operation by exiting the routine </p>

<p>Drawing the Static Display:</p>

<p>We draw all the static information by first setting the DDRAM address position and then putting the value we wish to send into w and then calling a routine which sends the value to the LCD</p>

<pre>
WRITELOC:
	movwf     TEMP       ;Move value to temp
	call      BUSYCHK    ;Check busy flag
	movfw     TEMP       ;Temp -> W
	movwf     PORTC      ;W -> Portc
	call      SEND       ;SEND
	return
</pre>

<p>Basic routine that makes it a little more mechanical to write data to the LCD. The value in W is sent to the LCD</p>

<pre>
WRITECHAR:               ; Function to write a characture 
	movwf     TEMP       ; Move value to temp register
	call      BUSYCHK    ; Check Busy flag
	bsf       PORTA,0    ; Turn on Data 
	movfw     TEMP       ; Move from Temp to W
	movwf     PORTC      ; Then to PORTC
	call      SEND       ; Send
	bcf       PORTA,0    ; Turn off Data
	return
</pre>

<p>Another routine specially designed for writing a character to a DDRAM address. This sets our PORTA,0 (Instruction/Data) high as we send Data to the LCD.</p>

<p><i>The MAIN routine:</i><br />
The main routine is fairly simple, we generate an A2D result and then call the routine which does the dynamic updating of the LCD (we do this 3 times for each of the 3 axis (xyz)</p>

<p><i>Updating the LCD:</i></p>

<pre>
UPDATELCD:               ; Routine to update the dynamic elements of the LCD
	call      WRITELOC   ; Init the LCD at the proper DDRAM location
	clrf      ONES       ; Clear Vars
	clrf      TENS
	clrf      HUNDREDS
	call      CALCULATE  ; Call calculate routine which takes raw A2D value and separates them into digits
	movfw     HUNDREDS   ; Write the Hundreds digit to the LCD
	call      TABLE1
	call      WRITECHAR
	movfw     TENS       ;Write Tens
	call      TABLE1
	call      WRITECHAR
	movfw     ONES       ;Write Ones
	call      TABLE1
	call      WRITECHAR
	return
</pre>

<p>This is another simple routine, we take the A2D result, break it down into its individual digits and send it to the LCD. We provide the DDRAM address in w before we call the function, thus this can be used for more than 1 axis making our code much more efficient.<br />
<b><br />
Conclusion:</b></p>

<p>Overall this is a fairly easy project that goes over the basics of controlling an HD44780 character LCD using a tri axis accelerometer as an analog input. </p>

<p>Ill leave you with a picture of the completed project as well the source and hex. Enjoy!</p>

<p><img src="http://mcuplace.com/mcu/media/blogs/blog/IMG00058.jpg" alt="" title="" width="400" height="300" /> </p>

<p>Whats next:  Making it display proper units</p>

<p><a href="http://mcuplace.com/mcu/media/blogs/blog/ameter.asm" title="">Source</a> <br />
<a href="http://mcuplace.com/mcu/media/blogs/blog/ameter.HEX" title="">Hex</a></p><div class="item_footer"><p><small><a href="http://mcuplace.com/mcu/blog4.php/2009/01/31/accelerate">Original post</a> blogged on <a href="http://b2evolution.net/">b2evolution</a>.</small></p></div>]]></content:encoded>
								<comments>http://mcuplace.com/mcu/blog4.php/2009/01/31/accelerate#comments</comments>
			<wfw:commentRss>http://mcuplace.com/mcu/blog4.php?tempskin=_rss2&#38;disp=comments&#38;p=39</wfw:commentRss>
		</item>
				<item>
			<title>Intro to the HD44780 character based LCD</title>
			<link>http://mcuplace.com/mcu/blog4.php/2009/01/31/intro-to-the-hd44780-character-based-lcd</link>
			<pubDate>Sat, 31 Jan 2009 18:51:03 +0000</pubDate>			<dc:creator>anthony</dc:creator>
			<category domain="main">Informative</category>			<guid isPermaLink="false">38@http://mcuplace.com/mcu/</guid>
						<description>&lt;p&gt;This post is going to go over using an HD44780 character LCD. These LCDs come in many sizes by are usually defined by how many characters they display; split by how many lines and characters per line.&lt;/p&gt;

&lt;p&gt;The one thing about these LCDs is that they have a built in microcontroller, so we are going to be using our PIC microcontrollers to interface with the built in MCU on the HD44780 LCD. &lt;/p&gt;

&lt;p&gt;Interfacing with the LCD is rather easy but often guides are very vague on exactly what you have to do. I will be going over how to statically and dynamically update the LCD using our PICs.&lt;/p&gt;

&lt;p&gt;The LCDs work by first configuring how the LCD operates (usually an initializing routine you use from code to code. The way the LCD displays data is that each &quot;character cell&quot; corresponds to a DDRAM address (Display Data RAM) you load the ASCII Hex value into the DDRAM address and the corresponding cell displays that character. Thats it! Its pretty easy to use these LCDs. &lt;br /&gt;
&lt;b&gt;&lt;br /&gt;
How it works:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I would first like to post a wonderful link which i used to learn how to use these LCDs. It has all the info you need but is a little confusing if you don't know what to look for.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Link: &lt;a href=&quot;http://home.iae.nl/users/pouweha/lcd/lcd.shtml&quot;&gt;http://home.iae.nl/users/pouweha/lcd/lcd.shtml&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;Any HD44780 character LCD with &lt;=80 characters (less than or equal to) will have 16 pins. For MOST LCDs (ALWAYS consult your data sheet first) &lt;/p&gt;

&lt;p&gt;&lt;b&gt;Pin 1&lt;/b&gt; is VSS(Ground)&lt;br /&gt;
&lt;b&gt;Pin 2&lt;/b&gt; is VDD(Pos voltage) &lt;br /&gt;
&lt;b&gt;Pin 3 &lt;/b&gt;is Vee, or voltage for contrast adjustment you hook this up in a voltage divider configuration with a potentiometer or trimmer. You use this to adjust contrast. &lt;br /&gt;
&lt;b&gt;Pin 4&lt;/b&gt; is the RS line which controls whether your sending data or an instruction. 0 is for an instruction, 1 for data.&lt;br /&gt;
&lt;b&gt;Pin 5&lt;/b&gt; is Read/Write from/to the LCD, 0 for Write, 1 for Read.&lt;br /&gt;
&lt;b&gt;Pin 6&lt;/b&gt; is the most important, it is the Enable signal, The enable line for the HD44780 is edge triggered, on a falling edge (1-&gt;0) The HD44780 reads whatever is on the data bus. This is the one thing people have most trouble with.&lt;br /&gt;
&lt;b&gt;Pins 7-14&lt;/b&gt; is the primary data bus. Its 8 bits long and you can either hook it up to a spare 8 bit port or use serial communication and a shift register. &lt;br /&gt;
&lt;b&gt;Pin 15&lt;/b&gt; is the anode to the back light. Make sure you put correct voltage across this and the cathode&lt;br /&gt;
&lt;b&gt;Pin 16&lt;/b&gt; is the cathode to the back light.&lt;/p&gt;

&lt;p&gt;Now that you know the pin out lets look at some instructions:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Commands:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Instructions control the operation of the LCD, They clear the DDRAM addresses, reset the address counter, set how the address counter functions, how the text displays and various other functions. We do all this before we send any data to the LCD, this initializes the LCD and gets it ready for accepting data and displaying it in a meaningful fashion.&lt;/p&gt;

&lt;p&gt;To send an instruction we set the RS and R/W lines both low. When this happens we put the instruction we want onto our data bus and send it by setting the enable line from high to low. &lt;/p&gt;

&lt;p&gt;&lt;b&gt;The Instruction set:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Command: Clear Home&lt;/i&gt;&lt;br /&gt;
RS:0&lt;br /&gt;
RW:0&lt;br /&gt;
DB:0x01&lt;/p&gt;

&lt;p&gt;This command clears the DDRAM and sets the address counter to 0x00&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Command: Return Home&lt;/i&gt;&lt;br /&gt;
RS:0&lt;br /&gt;
RW:0&lt;br /&gt;
DB:0x02&lt;/p&gt;

&lt;p&gt;Moves the address counter to 0x00, leaves the DDRAM untouched.&lt;br /&gt;
&lt;i&gt;&lt;br /&gt;
Command: Entry Mode&lt;/i&gt;&lt;br /&gt;
RS:0&lt;br /&gt;
RW:0&lt;br /&gt;
DB:0x04-0x07 (000001MS)&lt;/p&gt;

&lt;p&gt;This controls what the cursor does when it gets a command. Bit &quot;M&quot; controls weather its to the left or the right. 0 will decrement the cursor position, (move it to the left) a 1 will increment the cursor position (move it to the right). S Controls if the display shifts (Where the text moves but not the cursor position) 0 is off and 1 is on.&lt;br /&gt;
&lt;i&gt;&lt;br /&gt;
Command: Display Control&lt;/i&gt;&lt;br /&gt;
RS:0&lt;br /&gt;
RW:0&lt;br /&gt;
DB:0x08-0x0F (00001DCB)&lt;/p&gt;

&lt;p&gt;Sets weather the display is on(D) (useful), if the cursor is on(C) and if the cursor blinks(B). A 1 correlates to enabled.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Command: Cursor / Display shift.&lt;/i&gt;&lt;br /&gt;
RS:0&lt;br /&gt;
RW:0&lt;br /&gt;
DB:0x10-0x1F (0001SDxx)&lt;/p&gt;

&lt;p&gt;This allows you to shift(S) the display(1) or the Cursor(0) and what direction(D) left(0), right(1)&lt;br /&gt;
&lt;i&gt;&lt;br /&gt;
Command: Function Set&lt;/i&gt;&lt;br /&gt;
RS:0&lt;br /&gt;
RW:0&lt;br /&gt;
DB:0x20-0x3F (001LNFxx)&lt;/p&gt;

&lt;p&gt;Sets basic control information for the LCD&lt;/p&gt;

&lt;p&gt;L - Data Length: 0 - 4-Bit communication (We will be using 8-bit) 1 - 8-bit communication&lt;br /&gt;
N - 1 line or 2 line: 0 - 1 line 1 - 2 line, (just set to 1)&lt;br /&gt;
F - Font: 0 - 5X7 Dots 1 - 5X10 dots. Set to 1&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Command: Set CGRAM address&lt;/i&gt;&lt;br /&gt;
RS:0&lt;br /&gt;
RW:0&lt;br /&gt;
DB:0x40-0x7F (01(ADDRESS))&lt;/p&gt;

&lt;p&gt;HD44780 LCDs support custom characters, CGRAM is where you set them, i will not be covering custom characters in this post. &lt;br /&gt;
&lt;i&gt;&lt;br /&gt;
Command: Set DDRAM address&lt;/i&gt;&lt;br /&gt;
RS:0&lt;br /&gt;
RW:0&lt;br /&gt;
DB:0x80-0xFF (1(ADDRESS))&lt;/p&gt;

&lt;p&gt;This sets the DDRAM address which you will start sending data to.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Sending Command to the LCD:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;To send commands to the LCD we have to do several things.&lt;br /&gt;
-Set the RS and RW line&lt;br /&gt;
-Put the data/instruction we want to send on our data port (any 8 bit port)&lt;br /&gt;
-Send it&lt;br /&gt;
To send data to the HD44780 we set the E line high, do a few NOPs and then set it low. The HD44780 reads the command and operates accordingly. &lt;/p&gt;

&lt;p&gt;While the HD44780 is performing an operation we cannot send data to it. There are two ways we can make sure we don't send information while the LCD is busy. One is to just wait long enough for the LCD to finish. The other is to check the built in BUSY signal of the HD44780, I prefer this method as it is much quicker. &lt;/p&gt;

&lt;p&gt;&lt;b&gt;The Busy Flag:&lt;/b&gt;&lt;br /&gt;
RS:0&lt;br /&gt;
RW:1&lt;br /&gt;
DB:(BF(ADDRESS))&lt;/p&gt;

&lt;p&gt;When we set RW to 1 (read/write) we read the busy flag as well as the address counter. To read the busy flag we set RW to 1 and then the E line from 1 to 0. This will put the busy flag on DB7. A simple BTFSS loop will allow you to check the busy flag. &lt;/p&gt;

&lt;p&gt;&lt;b&gt;Writing Data to the LCD:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Writing data encompasses several functions:&lt;/p&gt;

&lt;p&gt;-Initializing the LCD &lt;br /&gt;
We set the proper functions for the LCD to operate and set it up for data transfer&lt;br /&gt;
-Selecting the first memory location&lt;br /&gt;
We send the first DDRAM address we want to write at (most parts sending 0x80 will set us to the first character)&lt;br /&gt;
-Writing the hex value for the char we wish to display&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Command: Write&lt;/i&gt;&lt;br /&gt;
RS:1&lt;br /&gt;
RW:0&lt;br /&gt;
DB:Character&lt;/p&gt;

&lt;p&gt;To write a char we just load the HEX value that corresponds to the data we wish to display, set RS to 1 and send the data (E1-&gt;0)&lt;/p&gt;

&lt;p&gt;We keep writing as long as we want to stay on whatever line we started at. Every time you write, the address counter automatically increments, no need to keep resending the DDRAM address.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Command: Read&lt;/i&gt;&lt;br /&gt;
RS:0&lt;br /&gt;
RW:1&lt;br /&gt;
DB:Address Contents&lt;/p&gt;

&lt;p&gt;This command reads the current address's contents.&lt;/p&gt;

&lt;p&gt;With this, you have all the information to control the HD44780 based character LCD. I will be posting Code and a project involving this LCD so stay tuned!&lt;/p&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://mcuplace.com/mcu/blog4.php/2009/01/31/intro-to-the-hd44780-character-based-lcd&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>This post is going to go over using an HD44780 character LCD. These LCDs come in many sizes by are usually defined by how many characters they display; split by how many lines and characters per line.</p>

<p>The one thing about these LCDs is that they have a built in microcontroller, so we are going to be using our PIC microcontrollers to interface with the built in MCU on the HD44780 LCD. </p>

<p>Interfacing with the LCD is rather easy but often guides are very vague on exactly what you have to do. I will be going over how to statically and dynamically update the LCD using our PICs.</p>

<p>The LCDs work by first configuring how the LCD operates (usually an initializing routine you use from code to code. The way the LCD displays data is that each "character cell" corresponds to a DDRAM address (Display Data RAM) you load the ASCII Hex value into the DDRAM address and the corresponding cell displays that character. Thats it! Its pretty easy to use these LCDs. <br />
<b><br />
How it works:</b></p>

<p>I would first like to post a wonderful link which i used to learn how to use these LCDs. It has all the info you need but is a little confusing if you don't know what to look for.</p>

<p><i>Link: <a href="http://home.iae.nl/users/pouweha/lcd/lcd.shtml">http://home.iae.nl/users/pouweha/lcd/lcd.shtml</a></i></p>

<p>Any HD44780 character LCD with <=80 characters (less than or equal to) will have 16 pins. For MOST LCDs (ALWAYS consult your data sheet first) </p>

<p><b>Pin 1</b> is VSS(Ground)<br />
<b>Pin 2</b> is VDD(Pos voltage) <br />
<b>Pin 3 </b>is Vee, or voltage for contrast adjustment you hook this up in a voltage divider configuration with a potentiometer or trimmer. You use this to adjust contrast. <br />
<b>Pin 4</b> is the RS line which controls whether your sending data or an instruction. 0 is for an instruction, 1 for data.<br />
<b>Pin 5</b> is Read/Write from/to the LCD, 0 for Write, 1 for Read.<br />
<b>Pin 6</b> is the most important, it is the Enable signal, The enable line for the HD44780 is edge triggered, on a falling edge (1->0) The HD44780 reads whatever is on the data bus. This is the one thing people have most trouble with.<br />
<b>Pins 7-14</b> is the primary data bus. Its 8 bits long and you can either hook it up to a spare 8 bit port or use serial communication and a shift register. <br />
<b>Pin 15</b> is the anode to the back light. Make sure you put correct voltage across this and the cathode<br />
<b>Pin 16</b> is the cathode to the back light.</p>

<p>Now that you know the pin out lets look at some instructions:</p>

<p><b>Commands:</b></p>

<p>Instructions control the operation of the LCD, They clear the DDRAM addresses, reset the address counter, set how the address counter functions, how the text displays and various other functions. We do all this before we send any data to the LCD, this initializes the LCD and gets it ready for accepting data and displaying it in a meaningful fashion.</p>

<p>To send an instruction we set the RS and R/W lines both low. When this happens we put the instruction we want onto our data bus and send it by setting the enable line from high to low. </p>

<p><b>The Instruction set:</b></p>

<p><i>Command: Clear Home</i><br />
RS:0<br />
RW:0<br />
DB:0x01</p>

<p>This command clears the DDRAM and sets the address counter to 0x00</p>

<p><i>Command: Return Home</i><br />
RS:0<br />
RW:0<br />
DB:0x02</p>

<p>Moves the address counter to 0x00, leaves the DDRAM untouched.<br />
<i><br />
Command: Entry Mode</i><br />
RS:0<br />
RW:0<br />
DB:0x04-0x07 (000001MS)</p>

<p>This controls what the cursor does when it gets a command. Bit "M" controls weather its to the left or the right. 0 will decrement the cursor position, (move it to the left) a 1 will increment the cursor position (move it to the right). S Controls if the display shifts (Where the text moves but not the cursor position) 0 is off and 1 is on.<br />
<i><br />
Command: Display Control</i><br />
RS:0<br />
RW:0<br />
DB:0x08-0x0F (00001DCB)</p>

<p>Sets weather the display is on(D) (useful), if the cursor is on(C) and if the cursor blinks(B). A 1 correlates to enabled.</p>

<p><i>Command: Cursor / Display shift.</i><br />
RS:0<br />
RW:0<br />
DB:0x10-0x1F (0001SDxx)</p>

<p>This allows you to shift(S) the display(1) or the Cursor(0) and what direction(D) left(0), right(1)<br />
<i><br />
Command: Function Set</i><br />
RS:0<br />
RW:0<br />
DB:0x20-0x3F (001LNFxx)</p>

<p>Sets basic control information for the LCD</p>

<p>L - Data Length: 0 - 4-Bit communication (We will be using 8-bit) 1 - 8-bit communication<br />
N - 1 line or 2 line: 0 - 1 line 1 - 2 line, (just set to 1)<br />
F - Font: 0 - 5X7 Dots 1 - 5X10 dots. Set to 1</p>

<p><i>Command: Set CGRAM address</i><br />
RS:0<br />
RW:0<br />
DB:0x40-0x7F (01(ADDRESS))</p>

<p>HD44780 LCDs support custom characters, CGRAM is where you set them, i will not be covering custom characters in this post. <br />
<i><br />
Command: Set DDRAM address</i><br />
RS:0<br />
RW:0<br />
DB:0x80-0xFF (1(ADDRESS))</p>

<p>This sets the DDRAM address which you will start sending data to.</p>

<p><b>Sending Command to the LCD:</b></p>

<p>To send commands to the LCD we have to do several things.<br />
-Set the RS and RW line<br />
-Put the data/instruction we want to send on our data port (any 8 bit port)<br />
-Send it<br />
To send data to the HD44780 we set the E line high, do a few NOPs and then set it low. The HD44780 reads the command and operates accordingly. </p>

<p>While the HD44780 is performing an operation we cannot send data to it. There are two ways we can make sure we don't send information while the LCD is busy. One is to just wait long enough for the LCD to finish. The other is to check the built in BUSY signal of the HD44780, I prefer this method as it is much quicker. </p>

<p><b>The Busy Flag:</b><br />
RS:0<br />
RW:1<br />
DB:(BF(ADDRESS))</p>

<p>When we set RW to 1 (read/write) we read the busy flag as well as the address counter. To read the busy flag we set RW to 1 and then the E line from 1 to 0. This will put the busy flag on DB7. A simple BTFSS loop will allow you to check the busy flag. </p>

<p><b>Writing Data to the LCD:</b></p>

<p>Writing data encompasses several functions:</p>

<p>-Initializing the LCD <br />
We set the proper functions for the LCD to operate and set it up for data transfer<br />
-Selecting the first memory location<br />
We send the first DDRAM address we want to write at (most parts sending 0x80 will set us to the first character)<br />
-Writing the hex value for the char we wish to display</p>

<p><i>Command: Write</i><br />
RS:1<br />
RW:0<br />
DB:Character</p>

<p>To write a char we just load the HEX value that corresponds to the data we wish to display, set RS to 1 and send the data (E1->0)</p>

<p>We keep writing as long as we want to stay on whatever line we started at. Every time you write, the address counter automatically increments, no need to keep resending the DDRAM address.</p>

<p><i>Command: Read</i><br />
RS:0<br />
RW:1<br />
DB:Address Contents</p>

<p>This command reads the current address's contents.</p>

<p>With this, you have all the information to control the HD44780 based character LCD. I will be posting Code and a project involving this LCD so stay tuned!</p><div class="item_footer"><p><small><a href="http://mcuplace.com/mcu/blog4.php/2009/01/31/intro-to-the-hd44780-character-based-lcd">Original post</a> blogged on <a href="http://b2evolution.net/">b2evolution</a>.</small></p></div>]]></content:encoded>
								<comments>http://mcuplace.com/mcu/blog4.php/2009/01/31/intro-to-the-hd44780-character-based-lcd#comments</comments>
			<wfw:commentRss>http://mcuplace.com/mcu/blog4.php?tempskin=_rss2&#38;disp=comments&#38;p=38</wfw:commentRss>
		</item>
				<item>
			<title>Project: UChat</title>
			<link>http://mcuplace.com/mcu/blog4.php/2008/12/28/project-uchat</link>
			<pubDate>Sun, 28 Dec 2008 17:32:20 +0000</pubDate>			<dc:creator>anthony</dc:creator>
			<category domain="alt">Code</category>
<category domain="main">Projects</category>			<guid isPermaLink="false">37@http://mcuplace.com/mcu/</guid>
						<description>&lt;p&gt;The basis of this project is 5 7 segment displays, One of which the user controls and uses to select a number 0-9, and 4 of which store previously received values.  There are 3 buttons; Increment decrement and send, all of do their respectable functions.&lt;/p&gt;

&lt;p&gt;This project takes advantage of the following procedures:&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Asynchronous Serial Communication &lt;/i&gt;&amp;#8211; We use the UART module on the PIC16F690 to transmit data from one PIC to another. We use a 9600 baud with the transmitter and receiver set asynchronously.  RB5 is RX and RB7 is TX &lt;br /&gt;
&lt;i&gt;&lt;br /&gt;
Multiplexed 7-segment Displays&lt;/i&gt; &amp;#8211; One problem with running 5 segment displays is the sheer number of pins we&amp;#8217;d need to run each one individually. Each display has 7 segments and a common cathode. For all of the displays that&amp;#8217;s 40 pins we&amp;#8217;d need to run all those displays. Multiplexing is where we only run one display at an instantaneous moment. We do this but loading the data for one display onto PORTC, then using another port to switch the CC connection using a bipolar transistor.  We keep rotating the output on PORTC and the CC we are switching until we&amp;#8217;ve gotten to the last display. This happens so fast all the displays seem like they&amp;#8217;re on at one given time.  One thing to consider when using a multiplexed display is that the outputs must be turned off when you rotate the display, otherwise you will get ghosting of the previous value.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Interrupts&lt;/i&gt; &amp;#8211; We use the interrupt on change and the receive interrupt to handle user input. &lt;/p&gt;

&lt;p&gt;&lt;b&gt;The Code:&lt;/b&gt;&lt;/p&gt;
&lt;pre&gt;
#include p16F690.inc
     __config (_INTRC_OSC_NOCLKOUT &amp;amp; _WDT_OFF &amp;amp; _PWRTE_OFF &amp;amp; _MCLRE_OFF &amp;amp; _CP_OFF &amp;amp; _BOR_OFF &amp;amp; _IESO_OFF &amp;amp; _FCMEN_OFF)
org 0
;Declare Variables
	cblock 0x20
DISPLAY
FIRSTDISP
SECONDDISP
THIRDDISP
FOURTHDISP
CURRENTDISP
STATUS_TEMP
TEMP
DELAY1
DELAY2
GROUND
W_TEMP
	endc
	goto 	PORTS ;Skip interrupt
;;;;;;;;;;;;;;
;  INTERUPT  ;
;;;;;;;;;;;;;;
	org 0x04
INTERUPT:
	bcf       INTCON,7      ;Turn off interrupts
	movwf     W_TEMP        ; Move W to temp
	bcf       STATUS,RP0    ; Goto bank 0
	bcf       STATUS,RP1    ; Goto bank 0
	btfsc     INTCON,0      ; Check for IOCA/B int
	goto      BUTTONPRESS   ; Yes, goto button press routine
	btfss     PIR1,RCIF     ; No, Check if value received
	goto      OUT           ; No, leave interrupt
	call      RX            ; Yes , receive the value
OUT:
	movf      W_TEMP,w 		; Restore W
	bcf       PIR1,RCIF     ; Clear flag
	bcf       INTCON,0      ; Clear flags
	bsf       INTCON,7      ; Restart interrupts
	retfie                  ; Return from interrupt
BUTTONPRESS:
	btfss     PORTA,3       ;Check first button
	call      INCREASE      ;Goto said function
	btfss     PORTB,4       ;Check Decrement button pressed, 
	call      DECREASE      ;Goto Said function
	btfss     PORTB,6       ;Check if TX button pressed
	call      TX            ; Goto TX routine
	call      DELAY	     	; Button Debounce	
	goto      OUT
INCREASE:
	incf      DISPLAY       ;Increment display
	movlw     0x0A          ; Move 10d to W
	bcf       STATUS,2      ;Clear Z bit
	subwf     DISPLAY,w     ;Subtract w from display
	btfsc     STATUS,2      ;Check if z bit set
	clrf      DISPLAY       ; Yes, clear display
	return                  ; no, return
DECREASE:
	incf      DISPLAY       ;Increment display (incase 0)
	bcf       STATUS,2      ;Z bit
	decf      DISPLAY       ;Decrement display
	btfsc     STATUS,2      ; Check z bit
	goto      INITIALIZE    ;Yes, reinitialize the display
	decf      DISPLAY       ;No, Decrement display
	return                  
INITIALIZE:
	movlw     0x09          ;Move 9d to w
	movwf     DISPLAY       ; Move it to display
	return
TX:
	btfss     PIR1 , TXIF    ; TXIF is set if TXREG has no character
 	goto      $-1            ; Loop until TXIF is cleared
 	movf      DISPLAY,w      ; Data to be transmitted over serial port
 	movwf 	  TXREG          ; Copy data to transmit register
 	bsf       STATUS,RP0     ; RAM PAGE 1
	btfss 	  TXSTA , TRMT   ; Wait until transmission is completed
 	goto      $-1            ; Loop back until transmission completed
	bcf       STATUS,RP0     ; Bank 0
 	return
RX:
	btfss     PIR1,RCIF     ; Wait for value to be recieved
	goto      $-1           ; loop
	bcf       PIR1,RCIF     ; Clear flag
	movf      RCREG,w       ; Move recieved word to w
	movwf     TEMP          ; then to var temp
	clrf      FOURTHDISP    ;Clear 4th display &lt;- 3rd Disp &lt;- Second Display &lt;- First Display &lt;- Temp
	movfw     THIRDDISP
	movwf     FOURTHDISP
	movfw     SECONDDISP
	movwf     THIRDDISP
	movfw     FIRSTDISP
	movwf     SECONDDISP
	movfw     TEMP
	movwf     FIRSTDISP
	return
DELAY:                     ; Generic Delay routine
	decfsz   DELAY1
	goto     DELAY
	decfsz   DELAY2
	goto     DELAY
	return
PORTS:
	; Analog
	bsf       STATUS,RP1    ; Bank 2
	clrf      ANSEL         ; All pins are digital I/O
 	clrf 	  ANSELH        ; All pins are digital I/O
	bcf       STATUS,RP1    ; Bank 0 
	; Tris
	bsf       STATUS,RP0     ; goto bank 1
	movlw     0x00           ; Move the hex value of 0 to multi purpose register W
              movwf     TRISC          ; make IO PortC all output
	movlw     b'01010000'    ; Move move b'01010000' to w
               movwf     TRISB          ; move to tris
	movlw     b'00001000'    ;Make porta.3 input rest output
	movwf     TRISA
	bcf       STATUS,RP0    ; goto bank 0
	; Interrupt
	bsf       INTCON,7      ;Set up global interrupts
	bsf       INTCON,6      ;Peripferal Interupts
	bsf       INTCON,3      ; IOCA/B interupt
	bsf       STATUS,RP0    ; Bank 1
	bsf       PIE1,5        ; Enable Interupt on Recieve
	bcf       STATUS,RP0    ; Bank 0
	bcf       PIR1,RCIF     ; Clear Flag
	bcf       INTCON,0      ; IOCA/B change flag
	; IOCB
	bsf       STATUS,RP1    ;Bank2
	movlw     b'01010000'   ; Make ports 4 and 6 IOC
	movwf     IOCB
	bcf       STATUS,RP1    
	bsf       STATUS,RP0    ;Bank1
	; IOCA
	movlw     b'00001000'   ;Make porta.3 IOC
	movwf     IOCA
	;serial comm transmit
	movlw     d'25'          ; Move the value of 25 or 0x19, to the baud rate genrator
	movwf     SPBRG          ; this will make the baud rate = to 9600 at a 4mhz internal clock in high speed mode
	bsf       TXSTA,BRGH     ;baud rate high
	bsf       TXSTA,TXEN     ;Enable Transmission
	bcf       TXSTA,SYNC     ;asynchronous
	bcf       STATUS,RP0     ;Exit bank 1
	;Serial comm Receive
	bsf       RCSTA,SPEN     ;Set serial port enable high
	bsf       RCSTA,CREN     ; Enable receiver
	; Initialize
	clrf      DISPLAY
	clrf      FIRSTDISP
	clrf      SECONDDISP
	clrf      THIRDDISP
	clrf	  FOURTHDISP
	movlw     0x01            ;Move 0x01 to ground
	movwf     GROUND
	movlw     0x20            ;Start pointer at DISLAY location: 0x20
	movwf     FSR
;;;;;;;;;;;;;;;;;;
;  MAIN ROUTINE  ;
;;;;;;;;;;;;;;;;;;
MAIN:
	bsf       STATUS,RP0 ;goto bank 1 and turn off display
	movlw     0xff
	movwf     TRISA
	movlw     0xff
	movwf     TRISC
	bcf       STATUS,RP0 ;bank 0
;Begin rotate
	movfw     INDF
	call      TABLE
	movwf     PORTC
	movfw     GROUND
	movwf     PORTA
;Turn on Displays
	bsf       STATUS,RP0
	movlw     0x00           
  	 movwf     TRISC          
	movlw     b'00001000'           
	movwf     TRISA
	bcf       STATUS,RP0
;Finish rotating
	rlf       GROUND
	call      RA3
	incf      FSR
	movlw     0x25
	bcf       STATUS,2
	subwf     FSR,w
	btfsc     STATUS,2
	call      CLEAR
	goto      MAIN
RA3:
	btfss     GROUND,3
	return
	rlf       GROUND
	return
CLEAR:
	movlw     0x20	
	movwf     FSR
	movlw     0x01
	movwf     GROUND
	return
TABLE:                          ;Generic lookup table
	addwf     PCL      ;            1;
	retlw     b'00111111';0      ;;;;;;;
	retlw     b'00000110';1    6 ;     ; 2
	retlw     b'01011011';2      ;  7  ;
	retlw     b'01001111';3      ;;;;;;;
	retlw     b'01100110';4    5 ;     ; 3
	retlw     b'01101101';5      ;     ;
	retlw     b'01111100';6      ;;;;;;;
	retlw     b'00000111';7         4
	retlw     b'01111111';8
	retlw     b'01100111';9
	return
end
;end
&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;The Breakdown:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Initialization:&lt;/i&gt; &lt;br /&gt;
	We initialize our variables to hold temporary values as well as the current values in each display.&lt;br /&gt;
Ports:&lt;br /&gt;
	We set all digital I/O, Port C all output, Port A 0,1,2,4,5 as output 3 as input, Port B 4,6 as input, 7 and 5 as TX and RX respectively.  The I/O Structure for this code is:&lt;br /&gt;
PORTC &amp;#8211; Primary 7-Segment driver&lt;br /&gt;
PORTA - Drives the line for the ground for the common cathode as well as the send input&lt;br /&gt;
PORTB &amp;#8211; Handles serial comm., as well as increment and decrement inputs.&lt;br /&gt;
	We use the interrupt on change for Port A and B; we set up that interrupt for its respectful inputs&lt;br /&gt;
	We set up the UART module for asynchronous communication, high speed baud and we turn on TX and RX.&lt;br /&gt;
	We finally clear the display variables, set the ground to the first position and set the pointer to look at the first digit&amp;#8217;s memory location (0x20)&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Main:&lt;/i&gt;&lt;br /&gt;
	We turn off the outputs to prevent ghosting. Since we can only change one port at one time and the display uses to ports to display data we shut off the ports, change the value and then update the ports. Thus we prevent the previous value from being displayed on top of the current one. We display the current value by using the value in that digit&amp;#8217;s block of memory into a lookup table and then outputting to PORTC, along with the respectable ground for that digit&amp;#8217;s display being HIGH.&lt;br /&gt;
	After that we update the pointer reference to the next digit and rotate the ground position.  We must note however, when the ground is at RA3 (input only) we rotate it once more since were using it as input.&lt;br /&gt;
	Once we reach the end of the rotation, we reinitialize the displays.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Interrupts:&lt;/i&gt;&lt;br /&gt;
	The interrupt routine is fairly simple it handles 4 conditions.&lt;br /&gt;
-Increment pressed&lt;br /&gt;
-Decrement pressed&lt;br /&gt;
-Send pressed&lt;br /&gt;
-Value Receive&lt;br /&gt;
	The first two conditions are fairly simple, the interrupt happens we pool for a button press and then we update the first digit&amp;#8217;s value.&lt;br /&gt;
	The send routine, pools for a button press, if it was the first digit is loaded into the TX reg and is sent out.&lt;br /&gt;
	When a value is received, we enter the RX routine, we store the value into a temp register and we begin updating the displays.&lt;br /&gt;
	Temp&gt;&gt;First&gt;&gt;Second&gt;&gt;Third&gt;&gt;Fourth&gt;&gt;Clear&lt;br /&gt;
	We do this by rotating the display into the next one. I.e. the third display into the fourth, etc.&lt;br /&gt;
	If no conditions are met, we just exit the interrupt.&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;
Conclusion:&lt;/b&gt;&lt;br /&gt;
	This is a fairly simple project but it takes advantage of the PIC&amp;#8217;s resources and on board hardware, we end up using 19 of the 20 pins of the PIC MCU. This is a great demo for serial communication between two PIC MCUs. I&amp;#8217;ve expanded this project to include two Zigbee RF modules in which the two modules talk to each other wirelessly.  &lt;/p&gt;

&lt;p&gt;&lt;b&gt;Where to go from here:&lt;/b&gt;&lt;br /&gt;
	There is one major downside to this project, and that is the displays. The 7-segments are horribly inefficient and lack much flexibility.  One way I&amp;#8217;d like to expand this project is to add a LCD screen and a keypad matrix to expand the user input and possible output.&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;
General Note:&lt;/b&gt;&lt;br /&gt;
	I went through the explanation of the code very quickly in this article. As the code gets more complicated I won&amp;#8217;t be able to keep revisiting basic techniques and explaining everything. That is what the previous posts are for, to lay the basic ground work down.  If you need further explanation feel free to email me, I&amp;#8217;m glad to break it down if you need it.&lt;/p&gt;

&lt;p&gt;Thanks once again for taking the time to read this, Source and hex as always, is below.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.mcuplace.com/mcu/media/blogs/blog/chat.asm&quot; title=&quot;&quot;&gt;Source&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.mcuplace.com/mcu/media/blogs/blog/chat.HEX&quot; title=&quot;&quot;&gt;Hex&lt;/a&gt;&lt;/p&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://mcuplace.com/mcu/blog4.php/2008/12/28/project-uchat&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>The basis of this project is 5 7 segment displays, One of which the user controls and uses to select a number 0-9, and 4 of which store previously received values.  There are 3 buttons; Increment decrement and send, all of do their respectable functions.</p>

<p>This project takes advantage of the following procedures:</p>

<p><i>Asynchronous Serial Communication </i>&#8211; We use the UART module on the PIC16F690 to transmit data from one PIC to another. We use a 9600 baud with the transmitter and receiver set asynchronously.  RB5 is RX and RB7 is TX <br />
<i><br />
Multiplexed 7-segment Displays</i> &#8211; One problem with running 5 segment displays is the sheer number of pins we&#8217;d need to run each one individually. Each display has 7 segments and a common cathode. For all of the displays that&#8217;s 40 pins we&#8217;d need to run all those displays. Multiplexing is where we only run one display at an instantaneous moment. We do this but loading the data for one display onto PORTC, then using another port to switch the CC connection using a bipolar transistor.  We keep rotating the output on PORTC and the CC we are switching until we&#8217;ve gotten to the last display. This happens so fast all the displays seem like they&#8217;re on at one given time.  One thing to consider when using a multiplexed display is that the outputs must be turned off when you rotate the display, otherwise you will get ghosting of the previous value.</p>

<p><i>Interrupts</i> &#8211; We use the interrupt on change and the receive interrupt to handle user input. </p>

<p><b>The Code:</b></p>
<pre>
#include p16F690.inc
     __config (_INTRC_OSC_NOCLKOUT &amp; _WDT_OFF &amp; _PWRTE_OFF &amp; _MCLRE_OFF &amp; _CP_OFF &amp; _BOR_OFF &amp; _IESO_OFF &amp; _FCMEN_OFF)
org 0
;Declare Variables
	cblock 0x20
DISPLAY
FIRSTDISP
SECONDDISP
THIRDDISP
FOURTHDISP
CURRENTDISP
STATUS_TEMP
TEMP
DELAY1
DELAY2
GROUND
W_TEMP
	endc
	goto 	PORTS ;Skip interrupt
;;;;;;;;;;;;;;
;  INTERUPT  ;
;;;;;;;;;;;;;;
	org 0x04
INTERUPT:
	bcf       INTCON,7      ;Turn off interrupts
	movwf     W_TEMP        ; Move W to temp
	bcf       STATUS,RP0    ; Goto bank 0
	bcf       STATUS,RP1    ; Goto bank 0
	btfsc     INTCON,0      ; Check for IOCA/B int
	goto      BUTTONPRESS   ; Yes, goto button press routine
	btfss     PIR1,RCIF     ; No, Check if value received
	goto      OUT           ; No, leave interrupt
	call      RX            ; Yes , receive the value
OUT:
	movf      W_TEMP,w 		; Restore W
	bcf       PIR1,RCIF     ; Clear flag
	bcf       INTCON,0      ; Clear flags
	bsf       INTCON,7      ; Restart interrupts
	retfie                  ; Return from interrupt
BUTTONPRESS:
	btfss     PORTA,3       ;Check first button
	call      INCREASE      ;Goto said function
	btfss     PORTB,4       ;Check Decrement button pressed, 
	call      DECREASE      ;Goto Said function
	btfss     PORTB,6       ;Check if TX button pressed
	call      TX            ; Goto TX routine
	call      DELAY	     	; Button Debounce	
	goto      OUT
INCREASE:
	incf      DISPLAY       ;Increment display
	movlw     0x0A          ; Move 10d to W
	bcf       STATUS,2      ;Clear Z bit
	subwf     DISPLAY,w     ;Subtract w from display
	btfsc     STATUS,2      ;Check if z bit set
	clrf      DISPLAY       ; Yes, clear display
	return                  ; no, return
DECREASE:
	incf      DISPLAY       ;Increment display (incase 0)
	bcf       STATUS,2      ;Z bit
	decf      DISPLAY       ;Decrement display
	btfsc     STATUS,2      ; Check z bit
	goto      INITIALIZE    ;Yes, reinitialize the display
	decf      DISPLAY       ;No, Decrement display
	return                  
INITIALIZE:
	movlw     0x09          ;Move 9d to w
	movwf     DISPLAY       ; Move it to display
	return
TX:
	btfss     PIR1 , TXIF    ; TXIF is set if TXREG has no character
 	goto      $-1            ; Loop until TXIF is cleared
 	movf      DISPLAY,w      ; Data to be transmitted over serial port
 	movwf 	  TXREG          ; Copy data to transmit register
 	bsf       STATUS,RP0     ; RAM PAGE 1
	btfss 	  TXSTA , TRMT   ; Wait until transmission is completed
 	goto      $-1            ; Loop back until transmission completed
	bcf       STATUS,RP0     ; Bank 0
 	return
RX:
	btfss     PIR1,RCIF     ; Wait for value to be recieved
	goto      $-1           ; loop
	bcf       PIR1,RCIF     ; Clear flag
	movf      RCREG,w       ; Move recieved word to w
	movwf     TEMP          ; then to var temp
	clrf      FOURTHDISP    ;Clear 4th display <- 3rd Disp <- Second Display <- First Display <- Temp
	movfw     THIRDDISP
	movwf     FOURTHDISP
	movfw     SECONDDISP
	movwf     THIRDDISP
	movfw     FIRSTDISP
	movwf     SECONDDISP
	movfw     TEMP
	movwf     FIRSTDISP
	return
DELAY:                     ; Generic Delay routine
	decfsz   DELAY1
	goto     DELAY
	decfsz   DELAY2
	goto     DELAY
	return
PORTS:
	; Analog
	bsf       STATUS,RP1    ; Bank 2
	clrf      ANSEL         ; All pins are digital I/O
 	clrf 	  ANSELH        ; All pins are digital I/O
	bcf       STATUS,RP1    ; Bank 0 
	; Tris
	bsf       STATUS,RP0     ; goto bank 1
	movlw     0x00           ; Move the hex value of 0 to multi purpose register W
              movwf     TRISC          ; make IO PortC all output
	movlw     b'01010000'    ; Move move b'01010000' to w
               movwf     TRISB          ; move to tris
	movlw     b'00001000'    ;Make porta.3 input rest output
	movwf     TRISA
	bcf       STATUS,RP0    ; goto bank 0
	; Interrupt
	bsf       INTCON,7      ;Set up global interrupts
	bsf       INTCON,6      ;Peripferal Interupts
	bsf       INTCON,3      ; IOCA/B interupt
	bsf       STATUS,RP0    ; Bank 1
	bsf       PIE1,5        ; Enable Interupt on Recieve
	bcf       STATUS,RP0    ; Bank 0
	bcf       PIR1,RCIF     ; Clear Flag
	bcf       INTCON,0      ; IOCA/B change flag
	; IOCB
	bsf       STATUS,RP1    ;Bank2
	movlw     b'01010000'   ; Make ports 4 and 6 IOC
	movwf     IOCB
	bcf       STATUS,RP1    
	bsf       STATUS,RP0    ;Bank1
	; IOCA
	movlw     b'00001000'   ;Make porta.3 IOC
	movwf     IOCA
	;serial comm transmit
	movlw     d'25'          ; Move the value of 25 or 0x19, to the baud rate genrator
	movwf     SPBRG          ; this will make the baud rate = to 9600 at a 4mhz internal clock in high speed mode
	bsf       TXSTA,BRGH     ;baud rate high
	bsf       TXSTA,TXEN     ;Enable Transmission
	bcf       TXSTA,SYNC     ;asynchronous
	bcf       STATUS,RP0     ;Exit bank 1
	;Serial comm Receive
	bsf       RCSTA,SPEN     ;Set serial port enable high
	bsf       RCSTA,CREN     ; Enable receiver
	; Initialize
	clrf      DISPLAY
	clrf      FIRSTDISP
	clrf      SECONDDISP
	clrf      THIRDDISP
	clrf	  FOURTHDISP
	movlw     0x01            ;Move 0x01 to ground
	movwf     GROUND
	movlw     0x20            ;Start pointer at DISLAY location: 0x20
	movwf     FSR
;;;;;;;;;;;;;;;;;;
;  MAIN ROUTINE  ;
;;;;;;;;;;;;;;;;;;
MAIN:
	bsf       STATUS,RP0 ;goto bank 1 and turn off display
	movlw     0xff
	movwf     TRISA
	movlw     0xff
	movwf     TRISC
	bcf       STATUS,RP0 ;bank 0
;Begin rotate
	movfw     INDF
	call      TABLE
	movwf     PORTC
	movfw     GROUND
	movwf     PORTA
;Turn on Displays
	bsf       STATUS,RP0
	movlw     0x00           
  	 movwf     TRISC          
	movlw     b'00001000'           
	movwf     TRISA
	bcf       STATUS,RP0
;Finish rotating
	rlf       GROUND
	call      RA3
	incf      FSR
	movlw     0x25
	bcf       STATUS,2
	subwf     FSR,w
	btfsc     STATUS,2
	call      CLEAR
	goto      MAIN
RA3:
	btfss     GROUND,3
	return
	rlf       GROUND
	return
CLEAR:
	movlw     0x20	
	movwf     FSR
	movlw     0x01
	movwf     GROUND
	return
TABLE:                          ;Generic lookup table
	addwf     PCL      ;            1;
	retlw     b'00111111';0      ;;;;;;;
	retlw     b'00000110';1    6 ;     ; 2
	retlw     b'01011011';2      ;  7  ;
	retlw     b'01001111';3      ;;;;;;;
	retlw     b'01100110';4    5 ;     ; 3
	retlw     b'01101101';5      ;     ;
	retlw     b'01111100';6      ;;;;;;;
	retlw     b'00000111';7         4
	retlw     b'01111111';8
	retlw     b'01100111';9
	return
end
;end
</pre>
<p><b>The Breakdown:</b></p>

<p><i>Initialization:</i> <br />
	We initialize our variables to hold temporary values as well as the current values in each display.<br />
Ports:<br />
	We set all digital I/O, Port C all output, Port A 0,1,2,4,5 as output 3 as input, Port B 4,6 as input, 7 and 5 as TX and RX respectively.  The I/O Structure for this code is:<br />
PORTC &#8211; Primary 7-Segment driver<br />
PORTA - Drives the line for the ground for the common cathode as well as the send input<br />
PORTB &#8211; Handles serial comm., as well as increment and decrement inputs.<br />
	We use the interrupt on change for Port A and B; we set up that interrupt for its respectful inputs<br />
	We set up the UART module for asynchronous communication, high speed baud and we turn on TX and RX.<br />
	We finally clear the display variables, set the ground to the first position and set the pointer to look at the first digit&#8217;s memory location (0x20)</p>

<p><i>Main:</i><br />
	We turn off the outputs to prevent ghosting. Since we can only change one port at one time and the display uses to ports to display data we shut off the ports, change the value and then update the ports. Thus we prevent the previous value from being displayed on top of the current one. We display the current value by using the value in that digit&#8217;s block of memory into a lookup table and then outputting to PORTC, along with the respectable ground for that digit&#8217;s display being HIGH.<br />
	After that we update the pointer reference to the next digit and rotate the ground position.  We must note however, when the ground is at RA3 (input only) we rotate it once more since were using it as input.<br />
	Once we reach the end of the rotation, we reinitialize the displays.</p>

<p><i>Interrupts:</i><br />
	The interrupt routine is fairly simple it handles 4 conditions.<br />
-Increment pressed<br />
-Decrement pressed<br />
-Send pressed<br />
-Value Receive<br />
	The first two conditions are fairly simple, the interrupt happens we pool for a button press and then we update the first digit&#8217;s value.<br />
	The send routine, pools for a button press, if it was the first digit is loaded into the TX reg and is sent out.<br />
	When a value is received, we enter the RX routine, we store the value into a temp register and we begin updating the displays.<br />
	Temp>>First>>Second>>Third>>Fourth>>Clear<br />
	We do this by rotating the display into the next one. I.e. the third display into the fourth, etc.<br />
	If no conditions are met, we just exit the interrupt.<br />
<b><br />
Conclusion:</b><br />
	This is a fairly simple project but it takes advantage of the PIC&#8217;s resources and on board hardware, we end up using 19 of the 20 pins of the PIC MCU. This is a great demo for serial communication between two PIC MCUs. I&#8217;ve expanded this project to include two Zigbee RF modules in which the two modules talk to each other wirelessly.  </p>

<p><b>Where to go from here:</b><br />
	There is one major downside to this project, and that is the displays. The 7-segments are horribly inefficient and lack much flexibility.  One way I&#8217;d like to expand this project is to add a LCD screen and a keypad matrix to expand the user input and possible output.<br />
<b><br />
General Note:</b><br />
	I went through the explanation of the code very quickly in this article. As the code gets more complicated I won&#8217;t be able to keep revisiting basic techniques and explaining everything. That is what the previous posts are for, to lay the basic ground work down.  If you need further explanation feel free to email me, I&#8217;m glad to break it down if you need it.</p>

<p>Thanks once again for taking the time to read this, Source and hex as always, is below.</p>

<p><a href="http://www.mcuplace.com/mcu/media/blogs/blog/chat.asm" title="">Source</a><br />
<a href="http://www.mcuplace.com/mcu/media/blogs/blog/chat.HEX" title="">Hex</a></p><div class="item_footer"><p><small><a href="http://mcuplace.com/mcu/blog4.php/2008/12/28/project-uchat">Original post</a> blogged on <a href="http://b2evolution.net/">b2evolution</a>.</small></p></div>]]></content:encoded>
								<comments>http://mcuplace.com/mcu/blog4.php/2008/12/28/project-uchat#comments</comments>
			<wfw:commentRss>http://mcuplace.com/mcu/blog4.php?tempskin=_rss2&#38;disp=comments&#38;p=37</wfw:commentRss>
		</item>
			</channel>
</rss>
