<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" version="2.0">

<channel>
	<title>ermicroblog</title>
	
	<link>http://www.ermicro.com/blog</link>
	<description>Microcontrollers and Electronics Project Blog</description>
	<lastBuildDate>Mon, 25 Feb 2013 09:11:32 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/Ermicroblog" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="ermicroblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><creativeCommons:license>http://creativecommons.org/licenses/by-nc/2.0/</creativeCommons:license><item>
		<title>The ISP Breakout Board for Prototyping Your Electronic Circuit</title>
		<link>http://www.ermicro.com/blog/?p=2348</link>
		<comments>http://www.ermicro.com/blog/?p=2348#comments</comments>
		<pubDate>Mon, 25 Feb 2013 09:11:32 +0000</pubDate>
		<dc:creator>rwb</dc:creator>
				<category><![CDATA[Yet Another Tips]]></category>
		<category><![CDATA[AVR]]></category>
		<category><![CDATA[BREADBOARD]]></category>
		<category><![CDATA[ISP]]></category>

		<guid isPermaLink="false">http://www.ermicro.com/blog/?p=2348</guid>
		<description><![CDATA[In many projects presented in this blog I used the breadboard for prototyping and building the projects. Literally breadboard is mean a piece of wood (board) we usually use to cut the bread, this term later used by many of earlier electronics experimenters to descript the board they used to construct and connect all the [...]]]></description>
				<content:encoded><![CDATA[<p>In many projects presented in this blog I used the breadboard for prototyping and building the projects. Literally breadboard is mean a piece of wood (board) we usually use to cut the bread, this term later used by many of earlier electronics experimenters to descript the board they used to construct and connect all the electronics components on the piece of wood board. The breadboard has many advantages as it allow us to prototype the electronic design before going into the production and to reuse the electronics components for another project which of course will reduce the component’s cost especially for the electronics beginners.</p>
<p><span id="more-2348"></span>When prototype a microcontroller based electronic circuit, we also need to be able to program the microcontroller easily, therefore to avoid using many jumper cables between the programmer and the breadboard circuit every time we want to program the microcontroller I used this following easy to build Atmel ISP breakout board as shown on this following picture:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2013/02/ISP_Breakout_00.jpg"><img class="alignnone size-full wp-image-2349" alt="ISP_Breakout_00" src="http://www.ermicro.com/blog/wp-content/uploads/2013/02/ISP_Breakout_00.jpg" width="577" height="431" /></a></p>
<p>The ISP breakout board is constructed on the 20&#215;16 mm perforator board using one 6 pins right angle male header to connect to the breadboard and one 2&#215;3 pins male header for the ISP programmer connection. Again I used a copper enameled wire to connect all the header pins. You could read this method on the “<a title="Quick and Efficiently Wiring Your Prototype Circuit Board" href="http://www.ermicro.com/blog/?p=1940" target="_blank">Quick and Efficiently Wiring Your Prototype Circuit Board</a>” in this blog. Make sure you double check all the pins connection and next print the ISP breakout board labels and glue it on the ISP breakout board as shown on this following picture:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2013/02/ISP_Breakout_01.jpg"><img class="alignnone size-full wp-image-2350" alt="ISP_Breakout_01" src="http://www.ermicro.com/blog/wp-content/uploads/2013/02/ISP_Breakout_01.jpg" width="581" height="433" /></a></p>
<p>Now you are ready to use this ISP breakout board to program the Atmel Microcontroller based prototyping circuit. Make sure you always refer to the Atmel Microcontroller datasheet to correctly connect this ISP breakout board to your target microcontroller. The following table shows the ISP pins connection for some of the popular Atmel AVR Microcontrollers:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2013/02/ISP_Breakout_03.jpg"><img class="alignnone size-full wp-image-2351" alt="ISP_Breakout_03" src="http://www.ermicro.com/blog/wp-content/uploads/2013/02/ISP_Breakout_03.jpg" width="575" height="136" /></a></p>
<p>The following picture show the Atmel ISP breakout board is used to program the Atmel AVR ATmega168 microcontroller based project on the breadboard:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2013/02/ISP_Breakout_02.jpg"><img class="alignnone size-full wp-image-2352" alt="ISP_Breakout_02" src="http://www.ermicro.com/blog/wp-content/uploads/2013/02/ISP_Breakout_02.jpg" width="573" height="433" /></a></p>
<p>This small ISP breakout board has been very useful to me in prototyping most of the Atmel microcontroller based circuit ever since. Now you could also share the same pleasure by building this little and handy Atmel ISP breakout board by yourself.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ermicro.com/blog/?feed=rss2&amp;p=2348</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Build your own stopwatch using Maxim MAX7219 Serially Interfaced, 8-Digit LED Display Drivers</title>
		<link>http://www.ermicro.com/blog/?p=2292</link>
		<comments>http://www.ermicro.com/blog/?p=2292#comments</comments>
		<pubDate>Sat, 29 Dec 2012 08:16:07 +0000</pubDate>
		<dc:creator>rwb</dc:creator>
				<category><![CDATA[Microcontroller]]></category>
		<category><![CDATA[ADC]]></category>
		<category><![CDATA[AVR]]></category>
		<category><![CDATA[MAX7219]]></category>
		<category><![CDATA[SPI]]></category>
		<category><![CDATA[TIMER]]></category>

		<guid isPermaLink="false">http://www.ermicro.com/blog/?p=2292</guid>
		<description><![CDATA[One of the basic usage of the TIMER peripheral on every microcontroller is to provide the accurate timing mechanism. Using the TIMER peripheral as the basic timing, we could easily develop a stopwatch and display it to the 8-Digit seven segment numeric LED display. Thanks to the Maxim MAX7219 chip which enable us to interface [...]]]></description>
				<content:encoded><![CDATA[<p>One of the basic usage of the TIMER peripheral on every microcontroller is to provide the accurate timing mechanism. Using the TIMER peripheral as the basic timing, we could easily develop a stopwatch and display it to the 8-Digit seven segment numeric LED display. Thanks to the Maxim MAX7219 chip which enable us to interface this 8-Digit seven segment LED display much easier using just three wires of the SPI (serial peripheral interface) to display the hour, minute, second, and hundredth of seconds to the 8-Digit seven segments LED display.</p>
<p><span id="more-2292"></span></p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2012/12/max7219_05.jpg"><img class="aligncenter  wp-image-2293" title="max7219_05" src="http://www.ermicro.com/blog/wp-content/uploads/2012/12/max7219_05.jpg" alt="" width="560" height="420" /></a></p>
<p>On this tutorial we will learn to utilize the Atmel AVR ATMega328P microcontroller SPI peripheral to communicate with the Maxim MAX7219 chip. The AVR ATmega328P SPI peripheral will be configured as a master and Maxim MAX7219 as the SPI device slave; you could read more about the SPI in <a title="Using Serial Peripheral Interface (SPI) Master and Slave with Atmel AVR Microcontroller" href="http://www.ermicro.com/blog/?p=1050" target="_blank">Using Serial Peripheral Interface (SPI) Master and Slave with Atmel AVR Microcontroller</a> project on this blog. A simplified electronic schematic of this project is shown in this following picture.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2012/12/max7219_00.jpg"><img class="aligncenter  wp-image-2298" title="max7219_00" src="http://www.ermicro.com/blog/wp-content/uploads/2012/12/max7219_00.jpg" alt="" width="550" height="357" /></a></p>
<p>The following is the list of hardware, software, and references used to build this project:</p>
<p>1. One Maxim MAX7219: Serially Interfaced, 8-Digit LED Display Drivers<br />
2. Two common cathode 4-Digits seven segment LED display<br />
3. One Resistor: 10K Ohm<br />
4. One Capacitors 0.1uF<br />
5. AVRJazz 28PIN development board from ermicro which is based on the AVR ATmega328P microcontroller.<br />
6. Atmel AVR Studio 6.0 for coding and debugging environment<br />
7. STK500 programmer from AVR Studio 6.0, using the AVRJazz 28PIN board STK500 v2.0 bootloader<br />
8. Atmel AVR ATmega328 and Maxim MAX7219 Datasheet</p>
<p>The stopwatch project that we are going to build has these following features:</p>
<ul>
<li>Stopwatch counting up to hundredth of second when the <strong>SW1</strong> is pressed</li>
<li>Pressing the <strong>SW1</strong> once will freeze the counting display while continuing counting in the background, pressing the <strong>SW1</strong>  again will continue to display the stopwatch counting</li>
<li>Adjust the intensity of the 8-Digits seven segment LED display using the trimmer potentiometer (<strong>TP</strong>).</li>
<li>Reset the stopwatch counting by pressing the <strong>SW0</strong>.</li>
</ul>
<p>In order to accomplish this project, we will use the AVR ATmega328P 16-bit TIMER2 peripheral in compare match mode as the heart beat of the counting mechanism, the pin change interrupt is used to detect the SW1 switch, and the ADC peripheral is used to adjust the 8-Digit seven segment LED display brightness. This project also serves as a good example of how we use many of the powerful AVR ATmega328P microcontroller features at the same time. The following is the complete C code for this project:</p>
<pre>/*****************************************************************************
//  File Name    : SSegMAX7219.c
//  Version      : 1.0
//  Description  : Simple StopWatch Using Maxim MAX7219
//                 Serially Interfaced, 8-Digit LED Display Drivers
//  Author       : RWB
//  Target       : AVRJazz 28PIN Development Board
//  Compiler     : AVR-GCC 4.6.2 (AVR_8_bit_GNU_Toolchain_3.4.0_663)
//  IDE          : Atmel AVR Studio 6.0
//  Programmer   : AVRJazz 28PIN board STK500 v2.0 Bootloader
//               : AVR Visual Studio 6.0, STK500 programmer
//  Last Updated : 20 Dec 2012
*****************************************************************************/
#define F_CPU 16000000UL          // AVRJazz28PIN Board Used 16MHz
#include &lt;avr/io.h&gt;
#include &lt;util/delay.h&gt;
#include &lt;avr/interrupt.h&gt;

#define SPI_PORT PORTB
#define SPI_DDR  DDRB
#define SPI_CS   PB2

static volatile uint8_t hours,minutes,seconds,hdseconds;
static volatile uint8_t keystate;

void SPI_Write(uint8_t addr, uint8_t dataout)
{        
  // Enable CS Pin
  SPI_PORT &amp;= ~(1&lt;&lt;SPI_CS);

  // Start Address transmission (MOSI)    
  SPDR = addr;

  // Wait for transmission complete
  while(!(SPSR &amp; (1&lt;&lt;SPIF)));    

  // Start Data transmission (MOSI)
  SPDR = dataout;

  // Wait for transmission complete
  while(!(SPSR &amp; (1&lt;&lt;SPIF)));

  // Disable CS Pin
  SPI_PORT |= (1&lt;&lt;SPI_CS);    
}

void disp_digit(uint8_t dindex,uint8_t number,uint8_t nmax) {
  uint8_t digit[2];      

  if (keystate == 2) return;  

  digit[0]=0;
  digit[1]=0;

  if (number &lt;= nmax) {
    if (number &lt; 10) {      
     digit[0] = number;
    } else {
     digit[1] = number / 10;
     digit[0] = number - (digit[1] * 10);
    }
  }      

  SPI_Write(dindex,digit[0] | 0x80); // Enable DP (Decimal Point)
  SPI_Write((dindex + 1),digit[1]);
}

ISR(TIMER1_COMPA_vect)
{
  // Increase the Hundred Seconds
  hdseconds++;            // Count-up Hundredth of Seconds
  disp_digit(1,hdseconds,99);
  if (hdseconds &gt; 99) {      
    hdseconds=0;
    seconds++;            // Count-up Seconds
    disp_digit(3,seconds,59);
    if (seconds &gt; 59) {
      seconds=0;
      minutes++;          // Count-up Minutes
      disp_digit(5,minutes,59);
      if (minutes &gt; 59) {
        minutes=0;
     hours++;          // Count-up Hours
     disp_digit(7,hours,23);
     if (hours &gt; 23) hours=0;
      }
    }
  }  
  TCNT1=0;                // Reset TIMER1 Counter
}

ISR(PCINT0_vect)
{        
  if (PINB &amp; (1&lt;&lt;PB0)) {       // Check PB0 if is Pressed or Logical 0    
    if (keystate == 0) {
      TCNT1=0;    
      TIMSK1=(1&lt;&lt;OCIE1A);      // Enable Compare A Interrupt                
      keystate=1;
    } else {
    keystate++;
    if (keystate &gt; 2) {
      keystate=1;
      disp_digit(1,hdseconds,99);
      disp_digit(3,seconds,59);
      disp_digit(5,minutes,59);
      disp_digit(7,hours,23);
    }          
    }        
  }
  PCIFR=(1&lt;&lt;PCIF0);                 // Clear Pin Change Interrupt Flag
}

uint8_t adc_map(uint8_t adc)
{
  return ((adc * 15) / 255);
}

int main(void)
{    
  uint8_t cnt,ADCRead;

  // Set the PORTD as Output:
  DDRD=0xFF;
  PORTD=0x00;

  // Initial 16-bit TIMER1
  // TCNT1 Counter Increment Period: 1 / (Fclk/8)
  //                         Period = 1 / (16000000/8) = 0.0000005 Seconds
  // For 10 millisecond: 20,000 x 0.0000005 = 0.01 Seconds    
  TCCR1A=0;                         // Normal Mode
  TCCR1B=(1&lt;&lt;CS11);                 // Use prescaler of 8
  TCNT1=0;                          // Start TIMER1 counter from 0

  OCR1A=20000;                      // The Hundredth Second    
  TIFR1=(1&lt;&lt;OCF1A);                 // Clear any pending Compare A Interrupt
  TIMSK1=0;                         // Disable Compare A Interrupt

  // Initial ATmega328P Pin Change Interrupt on PB0 (PCINT0)
  PCMSK0 |= (1&lt;&lt;PCINT0);              // Activate PCINT0 Pin Change Interrupt
  PCICR |= (1&lt;&lt;PCIE0);                 // Enable PCIE0 Pin Change Interrupt
  keystate=0;                       // Key State

  // Set ADCSRA Register on ATmega328P
  // ADEN=1 - Enable the ADC Peripheral
  // ADPS2=1, ADPS1=1, and ADPS0=1 we used prescale of 128
  ADCSRA = (1&lt;&lt;ADEN) | (1&lt;&lt;ADPS2) | (1&lt;&lt;ADPS1) | (1&lt;&lt;ADPS0);
  ADCSRB = 0b00000000;          // Free Running Mode
  DIDR0  = 0b00000000;          // Use analog input for Channel 0 to 5

  // Set ADMUX Register on ATmega328P
  // Use External Voltage Reference, Left Adjust, and select the ADC channel 0
  ADMUX=0b01100000;

  // Initial the AVR ATMega328P SPI Peripheral
  // Set MOSI and SCK as output, others as input
  SPI_DDR = (1&lt;&lt;PB3)|(1&lt;&lt;PB5)|(1&lt;&lt;PB2);

  // Disable (RCK Low)
  SPI_PORT |= (1&lt;&lt;SPI_CS);

  // Enable SPI, Master, set clock rate fck/2 (maximum)
  SPCR = (1&lt;&lt;SPE)|(1&lt;&lt;MSTR);
  SPSR = (1&lt;&lt;SPI2X);

  // Set the MAX7219        
  SPI_Write(0x0C,0x01);        // Normal Operation
  SPI_Write(0x09,0xFF);        // Code B Decode for Digit 7 to 0
  SPI_Write(0x0B,0x07);        // Scan digit 7 to 0
  SPI_Write(0x0A,0x0F);        // Set Default Intensity to Max

  // Reset all Digit and set the Decimal Point
  for(cnt=1;cnt &lt;= 8;cnt=cnt+2) {
    SPI_Write(cnt,0 | 0x80);
    SPI_Write(cnt + 1,0);
  }        

  sei();                           // Enable Global Interrupt               

  for(;;) {     
   // Start ADC conversion by setting ADSC on ADCSRA Register
   ADCSRA |= (1&lt;&lt;ADSC);

   // wait until conversion complete ADSC=0 -&gt; Complete
   while (ADCSRA &amp; (1&lt;&lt;ADSC));

   // Get the 8-bit ADC the Result 
   ADCRead=ADCH;

   // Set the MAX7219 Intensity
   SPI_Write(0x0A,adc_map(ADCRead));        

   // Put Some Delay Here
   _delay_ms(100);
  }            
  return 0;
}

/* EOF: SSegMAX7219.c */</pre>
<p><strong>The Maxim MAX7219</strong></p>
<p>The MAX7219 chip from maxim is a powerful serial input/output common-cathode display driver that interfaces microcontroller to 7-segment numeric LED displays of up to 8 digits. It has a build-in BCD (binary code decimal) decoder and a brightness control. Although the main function is to drive the 8-Digits seven segment LED display but because it also capable to drive an individual LED segment i.e. segment <strong>A</strong> to segment <strong>G</strong> and <strong>DP</strong> (decimal point), therefore you could also use this chip to drive the individual LED, the LED bar-graph, or the 8&#215;8 LED matrix display. The MAX7219 could easily be daisy-chained (cascaded) to another MAX7219 chip using the <strong>DOUT</strong> pin which is useful when you want to drive 16-Digits LED display or several LED matrix display.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2012/12/max7219_02.jpg"><img class="aligncenter  wp-image-2300" title="max7219_02" src="http://www.ermicro.com/blog/wp-content/uploads/2012/12/max7219_02.jpg" alt="" width="559" height="298" /></a></p>
<p>The MAX7219 chip has 16-bit registers divided into two sections; the first upper byte (bit 8 to 15) is called the address and the lower byte (bit 0 to 7) is called the data.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2012/12/max7219_01.jpg"><img class="aligncenter  wp-image-2301" title="max7219_01" src="http://www.ermicro.com/blog/wp-content/uploads/2012/12/max7219_01.jpg" alt="" width="563" height="426" /></a></p>
<p>In order to send a command to the MAX7219 chip, first we need send the 8-bits address and next we send the 8-bits data. For example if we want to display a character 6 (six) on digit 0, then first we send the address <strong>0&#215;01</strong> to select the digit 0 and next we send the value <strong>0&#215;06</strong> to the MAX7219 16-bits register.</p>
<p>The same principle is also apply to other important MAX7219 chip commands such as activate from the shutdown mode (normal operation), use BCD decode (font B) mode, scanning limit (scanning digit 0 to 7), and adjusting the seven segment LED digit intensity please refer to the Maxim MAX7219 datasheet for the complete explanation.</p>
<p><strong>The AVR ATmega328P TIMER1 Peripheral</strong></p>
<p>The 16-bits TIMER1 peripheral is the heart beat of this stopwatch project. We used this 16-bit TIMER1 as it give more flexibility to implement the stopwatch, because of the 16-bit counter length, therefore it could counting up to 65.536 before overflow. We will use TIMER1 16-bit output compare register <strong>OCR1A</strong> (<strong>OCR1AH – OCR1AL</strong>) as the base of our hundredth of seconds counter.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2012/12/max7219_06.jpg"><img class="aligncenter  wp-image-2306" title="max7219_06" src="http://www.ermicro.com/blog/wp-content/uploads/2012/12/max7219_06.jpg" alt="" width="555" height="421" /></a></p>
<p>The Output Compare Register A (<strong>OCR1A</strong>) will be the maximum value of <strong>TCNT1</strong> register counter before it generate an interrupt. Using the AVRJazz 28PIN development board 16 Mhz external crystal resonator with prescaler of 8, we could calculate the TIMER1 clock period as follow:</p>
<p>TIMER1 Clock Period = 1 / (16000000 / 8) = <strong>0.0000005</strong> seconds</p>
<p>To get a hundredth of seconds period, the TIMER1 digital counter <strong>TCNT1</strong> register will need to count up to value of 20,000:</p>
<p>The hundredth of seconds = 20000 x 0.0000005 seconds = <strong>0.01</strong> seconds.</p>
<p>By assigning this value to the OCR1A register and activate the output compare register A interrupt, the compare match interrupt will be generated every 0.01 seconds. The following C code is the setup for the AVR ATmega328P TIMER1:</p>
<pre>// Initial 16-bit TIMER1
// TCNT1 Counter Increment Period: 1 / (Fclk/8)
// Period = 1 / (16000000/8) = 0.0000005 Seconds
// For 10 millisecond: 20,000 x 0.0000005 = 0.01 Seconds
TCCR1A=0; // Normal Mode
TCCR1B=(1&lt;&lt;CS11); // Use prescaler of 8
TCNT1=0; // Start TIMER1 counter from 0 
OCR1A=20000; // The Hundredth Second

TIFR1=(1&lt;&lt;OCF1A); // Clear any pending Compare A Interrupt
TIMSK1=0; // Disable Compare A Interrupt</pre>
<p>Next inside the compare match interrupt routine we count-up the variable <strong>hdseconds, seconds, minutes</strong>, and <strong>hours</strong> as shown on this following C code:</p>
<pre>ISR(TIMER1_COMPA_vect)
{
  // Increase the Hundred Seconds
  hdseconds++;            // Count-up Hundredth of Seconds
  disp_digit(1,hdseconds,99);
  if (hdseconds &gt; 99) {      
    hdseconds=0;
    seconds++;            // Count-up Seconds
    disp_digit(3,seconds,59);
    if (seconds &gt; 59) {
      seconds=0;
      minutes++;          // Count-up Minutes
      disp_digit(5,minutes,59);
      if (minutes &gt; 59) {
        minutes=0;
     hours++;          // Count-up Hours
     disp_digit(7,hours,23);
     if (hours &gt; 23) hours=0;
      }
    }
  }  
  TCNT1=0;                // Reset TIMER1 Counter
}</pre>
<p>Noticed inside this interrupt routine we also run the <strong>disp_digit()</strong> function which is used to send the command to the MAX7219 chip to display the corresponding digit but in order to reduce the overall execution time inside the interrupt routine we only display the changed digit at the time.</p>
<p><strong>The AVR ATmega328P External Interrupt</strong></p>
<p>The ATmega328P support two type of an external interrupt, this first one are triggered by <strong>INT0</strong> (<strong>PD2</strong>) and <strong>INT1</strong> (<strong>PD3</strong>) input pins and the second one are triggered by pin change on any of <strong>PCINT0, PCINT1, PCINT2</strong>, to <strong>PCINT23</strong> input pins. The <strong>INT0</strong> and <strong>INT1</strong> could generate an interrupt on four input signal type i.e. “<em>Low Logical Level</em>”, “<em>Any Logical Change</em>”, “<em>Falling Edge</em>”, and “<em>Rising Edge</em>” input signal, while the pins change interrupt pins only capable to generate an interrupt on “<em>Any Logical Change</em>” as shown in this following table:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2012/12/max7219_04.jpg"><img class="aligncenter  wp-image-2304" title="max7219_04" src="http://www.ermicro.com/blog/wp-content/uploads/2012/12/max7219_04.jpg" alt="" width="546" height="181" /></a></p>
<p>Both of these interrupt type has a common used, which is to generate an interrupt based on any signal change on the particular I/O ports. The external interrupt request has more flexible digital input type event but limited only on two I/O ports <strong>PD2</strong> and <strong>PD3</strong>, while the pin change interrupt request has only one type event i.e. logical change, but it could be applied to all the ATmega328P microcontroller I/O ports.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2012/12/max7219_03.jpg"><img class="aligncenter  wp-image-2305" title="max7219_03" src="http://www.ermicro.com/blog/wp-content/uploads/2012/12/max7219_03.jpg" alt="" width="573" height="377" /></a></p>
<p>In this project, we will use the AVRJazz 28PIN user switch <strong>SW1</strong> (connected to <strong>PB0</strong> pin) to generate the external interrupt (i.e. <strong>PCINT0</strong>) to control the stopwatch. The C code to initialize the AVR ATmega328P pin change interrupt is shown on these following lines:</p>
<pre>// Initial ATmega328P Pin Change Interrupt on PB0 (PCINT0)
PCMSK0 |= (1&lt;&lt;PCINT0); // Activate PCINT0 Pin Change Interrupt
PCICR |= (1&lt;&lt;PCIE0); // Enable PCIE0 Pin Change Interrupt</pre>
<p>By setting the <strong>PCINT0</strong> bit in pin change interrupt mask 0 register (<strong>PCMSK0</strong>) we activate the PB0 I/O port as the pin change interrupt source. Next we enable the <strong>PCIE0</strong> bit in pin change interrupt control register (<strong>PCICR</strong>) and global interrupt to enable the interrupt.</p>
<p>When the pin change interrupt occur the program will jump to the interrupt address (<strong>PCINT0_vector</strong>) and execute the C code inside this function:</p>
<pre>ISR(PCINT0_vect)
{        
  if (PINB &amp; (1&lt;&lt;PB0)) {       // Check PB0 if is Pressed or Logical 0    
    if (keystate == 0) {
      TCNT1=0;    
      TIMSK1=(1&lt;&lt;OCIE1A);      // Enable Compare A Interrupt                
      keystate=1;
    } else {
    keystate++;
    if (keystate &gt; 2) {
      keystate=1;
      disp_digit(1,hdseconds,99);
      disp_digit(3,seconds,59);
      disp_digit(5,minutes,59);
      disp_digit(7,hours,23);
    }          
    }        
  }
  PCIFR=(1&lt;&lt;PCIF0);                 // Clear Pin Change Interrupt Flag
}</pre>
<p>When the pin change interrupt occur on <strong>PB0</strong> we simply assign and examine the keystate variable. After system reset (pressing <strong>SW0</strong>), pressing the<strong> SW1</strong> will activate the TIMER1 output compare match A interrupt. Next when we press the <strong>SW1</strong> i.e. <strong>keystate</strong> variable is equal to 2, the <strong>disp_digit()</strong> function will simply return to the caller function( i.e. the TIMER1 compare match A interrupt) without sending any new display information to the MAX7219 chip. This allows the stopwatch counter to keep count while freezing the 8-Digits seven segment LED display.</p>
<p><strong>Inside the Project C code</strong></p>
<p>The C code begin with initializing all the necessary ATmega328P microcontroller peripheral such as the TIMER1 peripheral, external interrupt peripheral, SPI peripheral, and the Analog to Digital Conversion (ADC) peripheral where we just use the 8-bit resolution (left adjust) as the MAX7219 intensity level is only have 16 steps i.e. 0 to 15, therefore we don’t need to use the 10-bits resolution of the ATmega328P ADC peripheral. For more information about using the ATmega328P microcontroller ADC you could read <a title="Analog to Digital Converter AVR C Programming" href="http://www.ermicro.com/blog/?p=121" target="_blank">Analog to Digital Converter AVR C Programming</a> articles on this blog.</p>
<p>Next we configure the MAX7219 chip using <strong>SPI_Write()</strong> function where we activate the MAX7219 chip in normal operation, use the decode mode, activate digit scanning for digit 0 to 7, and set the default intensity to maximum as shown in this following C code:</p>
<pre>// Set the MAX7219        
SPI_Write(0x0C,0x01);        // Normal Operation
SPI_Write(0x09,0xFF);        // Code B Decode for Digit 7 to 0
SPI_Write(0x0B,0x07);        // Scan digit 7 to 0
SPI_Write(0x0A,0x0F);        // Set Default Intensity to Max

// Reset all Digit and set the Decimal Point
for(cnt=1;cnt &lt;= 8;cnt=cnt+2) {
  SPI_Write(cnt,0 | 0x80);
  SPI_Write(cnt + 1,0);
}</pre>
<p>After activating global interrupt <strong>sei()</strong> function, the program entering the infinite loop. Inside the infinite loop we read the trimmer potentiometer (<strong>TP</strong>) value and map this value (i.e. 0 to 255) to the MAX7219 chip intensity setting value (i.e. 0 to 15) using the <strong>adc_map()</strong> function before sending the command to the MAX7219 chip. Now you could enjoy the following video that showing this stopwatch project in action:</p>
<p><object width="480" height="360" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/u4JyAuzuVqI?version=3&amp;hl=en_US&amp;rel=0" /><param name="allowfullscreen" value="true" /><embed width="480" height="360" type="application/x-shockwave-flash" src="http://www.youtube.com/v/u4JyAuzuVqI?version=3&amp;hl=en_US&amp;rel=0" allowFullScreen="true" allowscriptaccess="always" allowfullscreen="true" /></object></p>
<p><strong>The Final Though</strong></p>
<p>The Maxim MAX7219 chip has much more possible interesting application especially when we used it as the individual LED driver, take advantage of its cascading ability we could even drive large number of LEDs (e.g. RGB LEDs). For example if you cascade two MAX7219 chips, in order to send information to the second MAX7219 chip you need to send two 16-bit values, the first 16-bit value will be for the second MAX7219 chip and the last 16-bit value should be the no operation command i.e. address: <strong>0&#215;00</strong> and data: <strong>0&#215;00</strong> for the first MAX7219 chip. The same principle also applies if you want to cascade several MAX7219 chips, Ok I leave this challenge for your experiment&#8217;s pleasure</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ermicro.com/blog/?feed=rss2&amp;p=2292</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The Year 2012 End Notes</title>
		<link>http://www.ermicro.com/blog/?p=2278</link>
		<comments>http://www.ermicro.com/blog/?p=2278#comments</comments>
		<pubDate>Wed, 26 Dec 2012 09:53:47 +0000</pubDate>
		<dc:creator>rwb</dc:creator>
				<category><![CDATA[Blognote]]></category>
		<category><![CDATA[AVR]]></category>
		<category><![CDATA[AVRStudio]]></category>
		<category><![CDATA[Microcontroller]]></category>

		<guid isPermaLink="false">http://www.ermicro.com/blog/?p=2278</guid>
		<description><![CDATA[This year is becoming one of the busiest year for me as I have many projects to handle (i.e. not related to the embedded system), as you know I always love to play with the electronic and embedded system although my professional job is not related to my hobby, but I always enjoy learning and [...]]]></description>
				<content:encoded><![CDATA[<p>This year is becoming one of the busiest year for me as I have many projects to handle (i.e. not related to the embedded system), as you know I always love to play with the electronic and embedded system although my professional job is not related to my hobby, but I always enjoy learning and exploring a new thing especially the embedded system and I hope you share the same passion as I did.<span id="more-2278"></span></p>
<p>During this year I finished the “<a title="ermicroblog e-book" href="http://www.ermicro.com/blog/?page_id=2318" target="_blank">Basic User’s Experiment Note</a>” e-book project which is based on the 8-bit Atmel AVR ATmega328P microcontroller using AVRJazz 28PIN development board. This e-book covering most of the Atmel AVR ATmega328P microcontroller important features and it’s aimed for the beginner’s, hobbyist or anyone who wants to learn and understand the 8-bit Atmel AVR ATmega328P microcontroller powerful features.</p>
<p>I am planning to create a second e-book project next year which is aimed to the intermediate readers where it will show how to interface to some of the popular electronic devices such as seven segment, LCD, I/O expansion, real time clock, motors, servo, and many more to the Atmel 8-bit AVR ATmega328P microcontroller.</p>
<p>It&#8217;s been a wonderful year to be with you all the ermicroblog readers, thanks to all the ermicroblog readers for your support and encouragement, during this year. I do hope this blog could bring a better understanding of how we could make use of the electronic and microcontroller in our learning journey or just as hobby and fun. May this Christmas will bring joy and bless in your heart and good hope for this coming year. Merry Christmas 25 December 2012 and Happy New Year 1 January 2013. Have a fun and nice holiday may the Heavenly Father always bless you and your family.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2012/12/year2012_01.jpg"><img class="size-full wp-image-2279 aligncenter" title="year2012_01" alt="" src="http://www.ermicro.com/blog/wp-content/uploads/2012/12/year2012_01.jpg" width="456" height="610" /></a></p>
<h4 style="text-align: center;"></h4>
<p style="text-align: center;"><strong>“Glory to God in the highest,</strong></p>
<p style="text-align: center;"><strong>and on earth peace to men on whom his favor rests – Luke 2:14″</strong></p>
<p style="text-align: center;"><strong>Merry Christmas 25 December 2012 and Happy New Year 1 January 2013</strong></p>
<p style="text-align: center;"><strong>God Bless You</strong></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ermicro.com/blog/?feed=rss2&amp;p=2278</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Year 2011 End Notes</title>
		<link>http://www.ermicro.com/blog/?p=2255</link>
		<comments>http://www.ermicro.com/blog/?p=2255#comments</comments>
		<pubDate>Sat, 24 Dec 2011 03:38:16 +0000</pubDate>
		<dc:creator>rwb</dc:creator>
				<category><![CDATA[Blognote]]></category>
		<category><![CDATA[JAZZYMICRO]]></category>
		<category><![CDATA[Robotics]]></category>
		<category><![CDATA[WIRELESS]]></category>

		<guid isPermaLink="false">http://www.ermicro.com/blog/?p=2255</guid>
		<description><![CDATA[It&#8217;s been a wonderful year to be with you all the ermicroblog readers, in the next couple of days we are going to leave this year and stepping into the next year with more exciting projects to be done. As more and more wireless devices has been developed in this past few years, in the [...]]]></description>
				<content:encoded><![CDATA[<p>It&#8217;s been a wonderful year to be with you all the ermicroblog readers, in the next couple of days we are going to leave this year and stepping into the next year with more exciting projects to be done. As more and more wireless devices has been developed in this past few years, in the year 2012 we are going to explore some of popular wireless devices available on market. I also plan to branch a new sister blog website at <a title="Jazzy Microcontrollers" href="http://www.jazzymicro.com">http://www.jazzymicro.com</a> targeted for the beginners of electronics and microcontroller enthusiast with practical approach and examples without talking much about the technical detail.<span id="more-2255"></span></p>
<p>I would like to thanks to all the ermicroblog readers for your support and encouragement, during this year. I do hope this blog could bring a better understanding of how we could make use of the electronic and microcontroller in our learning journey or just for hobby and fun.</p>
<p>Again, thank you to all of ermicroblog readers, may this Christmas will bring joy in your heart and good hope for this coming year. Merry Christmas 25 December 2011 and Happy New Year 1 January 2012. Have a fun and nice holiday may our Heavenly Father always bless you and your family.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/christmas_01.jpg"><img class="aligncenter  wp-image-2256" title="christmas_01" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/christmas_01.jpg" alt="" width="595" height="441" /></a></p>
<p style="text-align: center;"><strong>“Glory to God in the highest,</strong></p>
<p style="text-align: center;"><strong>and on earth peace to men on whom his favor rests – Luke 2:14″</strong></p>
<p style="text-align: center;"><strong>Merry Christmas 25 December 2011 and Happy New Year 1 January 2012</strong></p>
<p style="text-align: center;"><strong>God Bless You</strong></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ermicro.com/blog/?feed=rss2&amp;p=2255</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Developing Embedded Application with BASIC Language on the Microchip PIC18F Microcontroller using the Amicus18 Development system</title>
		<link>http://www.ermicro.com/blog/?p=2215</link>
		<comments>http://www.ermicro.com/blog/?p=2215#comments</comments>
		<pubDate>Fri, 23 Dec 2011 19:45:10 +0000</pubDate>
		<dc:creator>rwb</dc:creator>
				<category><![CDATA[Microcontroller]]></category>
		<category><![CDATA[ADC]]></category>
		<category><![CDATA[AMICUS18]]></category>
		<category><![CDATA[BASIC]]></category>
		<category><![CDATA[I2C]]></category>
		<category><![CDATA[LCD]]></category>
		<category><![CDATA[PCA8574]]></category>
		<category><![CDATA[PIC18F25K20]]></category>
		<category><![CDATA[PROTON BASIC]]></category>

		<guid isPermaLink="false">http://www.ermicro.com/blog/?p=2215</guid>
		<description><![CDATA[The BASIC (Beginners&#8217; All-purpose Symbolic Instruction Code) language has been known as one of the popular high level language choice in embedded system today. In fact the born and development of the personal computer (PC) we use today has been influenced by the used of BASIC language. Today there are many of professional BASIC language [...]]]></description>
				<content:encoded><![CDATA[<p>The BASIC (Beginners&#8217; All-purpose Symbolic Instruction Code) language has been known as one of the popular high level language choice in embedded system today. In fact the born and development of the personal computer (PC) we use today has been influenced by the used of BASIC language. Today there are many of professional BASIC language development tools variant targeting the Microchip PIC microcontroller.</p>
<p><span id="more-2215"></span></p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_00.jpg"><img class="alignnone  wp-image-2216" title="pbasic_00" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_00.jpg" alt="" width="584" height="458" /></a></p>
<p>On this project we will focus on the Amicus18 Proton BASIC for Microchip PIC compiler and the Amicus18 development board from Crownhill Associates and learn of how to use the Amicus18 development environment to interface with the Philips PCA8574 I<sup>2</sup>C I/O Expander connected to 2&#215;16 Hitachi HDU44780U (or its compatible) LCD.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_08.jpg"><img class="alignnone  wp-image-2219" title="pbasic_08" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_08.jpg" alt="" width="586" height="460" /></a></p>
<p>Inspired by the popular Arduino open source development system the Amicus18 board is designed to make used of various Arduino hardware add on modules or known as the Arduino shield which is widely available on the market, therefore the Amicus18 board use the same Arduino board form factor as well as the Arduino I/O port sockets as shown on this following picture:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_01.jpg"><img class="alignnone  wp-image-2220" title="pbasic_01" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_01.jpg" alt="" width="587" height="453" /></a></p>
<p>Unlike the Arduino board which is based on the Atmel 8-bits AVR ATMega328 microcontroller, the Amicus18 board is based on the Microchip 8-bits PIC18F25K20 microcontroller, therefore you could not use the Arduino development environment on the Amicus18 board. The other things that make this two board differ is the Amicus18 board use the PIC18F25K20 microcontroller which is based on the 3.3 volt working voltage while the Arduino board ATMega328 microcontroller used the 5 volt working voltage. Because of the working voltage different, make interfacing the Amicus18 board with many of the available Arduino shield board has to be examined carefully in order to make it work correctly.</p>
<p>One thing that bothers me when first using the Amicus18 board is the type A USB host connector used by the Amicus18 board similar to the type A USB host connector used in many PC (personal computer), because we have to connect the Amicus18 board with the computer in order to program it, therefore we have to use the USB cable that has similar type A USB plug on both ends (Arduino use type B USB host connector). This uncommon type of the USB cable and is quite hard to find in the market, so in this project I used the type A USB gender changer and type A USB cable extender as shown on this following picture:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_02.jpg"><img class="alignnone  wp-image-2224" title="pbasic_02" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_02.jpg" alt="" width="582" height="452" /></a></p>
<p><strong>The Amicus18 Development Environment</strong></p>
<p>The Amicus18 development environment is equipped with a free professional grade Proton BASIC compiler which is specially configured to be used with the Amicus18 board or to be more specific, this special edition of Proton BASIC compiler could only be used with the Microchip PIC18F25K20 microcontroller without any restriction and its fully optimized.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_03.jpg"><img class="alignnone  wp-image-2226" title="pbasic_03" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_03.jpg" alt="" width="591" height="372" /></a></p>
<p>Later on after hearing the request from many of the Amicus18 users, start on version 1.0.1.6 of the Proton Amicus18 Compiler (June 2011), they added support to the Microchip PIC18F25K22 microcontroller (5 volt version) as well as the original Amicus18 board Microchip PIC18F25K20 microcontroller (3.3 volt version) through the device directive <strong>Device = 18F25K20</strong> or <strong>Device = 18F25K22</strong> statement. Without the device directive statement the Amicus18 proton BASIC compiler will automatically use 18F25K20</p>
<p>But if you want to program the Amicus18 using the Microchip PIC18F25K22 (5 volt version) you have to use the Microchip PICKit2 or PICKit3 programmer because currently the Amicus18 board only support the Microchip PIC18F25K20 microcontroller (3.3 volt version) bootloader. Of course if you want to use the Amicus18 Proton BASIC for other type of Microchip PIC microcontroller you have to buy a full license of the Proton BASIC Compiler.</p>
<p>The Amicus18 proton BASIC compiler use the Microchip MPLAB ASM to generate the HEX code required by the Microchip PIC18F25K20 microcontroller, therefore you could easily compile and debug the Proton BASIC code using the Microchip MPLAB IDE as shown on this following picture:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_04.jpg"><img class="alignnone  wp-image-2227" title="pbasic_04" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_04.jpg" alt="" width="596" height="392" /></a></p>
<p>For more information on how to integrate the Amicus18 Proton BASIC compiler with the Microchip MPLAB IDE please read the “<em>Using Amicus18 Compiler with The MPLAB IDE</em>” documentation which come with the Amicus18 IDE.</p>
<p><strong>The Amicus18 Board I<sup>2</sup>C LCD Project</strong></p>
<p>As I mention before in this project we will learn to interface the Amicus18 board to the Philips PCA8574 I<sup>2</sup>C I/O Expander connected to 2&#215;16 HDU44780U LCD and at the same time you could learn of how to use the Proton BASIC language to handle Microchip PIC18FK25K20 MSSP (Master Synchronous Serial Port) in I<sup>2</sup>C (read as I square C) mode and the ADC (Analog to Digital Converter) peripheral.</p>
<p>Now let’s list down all the necessary hardware, software, and some supported documents in order to accomplish this project objective:</p>
<ul>
<li>The <a title="Amicus18 Board from Farnell" href="http://uk.farnell.com/amicus/amicus18/board-pic18f25k20-proton-amicus18/dp/1818281">Amicus18 Board</a> which you could be purchased from <a title="Amicus18 Board from Farnell" href="http://www.farnell.com">Farnell</a></li>
<li>PCA8574 Philips/NXP 8-bit I/O expander for I<sup>2</sup>C-bus</li>
<li> One Hitachi HD44780U or compatible 2&#215;16 LCD with blue back light</li>
<li>SMD Resistors 1K (1), 4.7K (1), and 10K (2)</li>
<li>8 Resistors 330 Ohm (0.25 watt)</li>
<li>Two 10K Trimpot</li>
<li> One SMD LED (1)</li>
<li>Blue LED (3 mm)</li>
<li>One SMD N-Channel MOSFET MMBF170 or equivalent</li>
<li>Breadboard and breadboard jumper cables</li>
<li>Microchip MPLAB IDE version 8.63 or the latest</li>
<li>Amicus18 IDE and Proton BASIC Compiler from Crownhill Associates</li>
<li>Reference Document: Microchip PIC18F25K20 datasheet, Philips/NXP PCA8574 datasheet, Amicus18 Hardware Manual, and Proton Amicus18 Compiler.</li>
</ul>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_09.jpg"><img class="alignnone  wp-image-2228" title="pbasic_09" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_09.jpg" alt="" width="591" height="404" /></a></p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_07.jpg"><img class="alignnone  wp-image-2229" title="pbasic_07" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_07.jpg" alt="" width="589" height="412" /></a></p>
<p>The following is the complete Amicus18 Proton BASIC code for this project:</p>
<pre>'*****************************************************************************
'*  File Name    : amidemo.bas
'*  Version      : 1.0
'*  Description  : Amicus18 Demo using Microchip PIC18F25K20 Microcontroller
'*  Author       : RWB
'*  Target       : Amicus18 Board
'*                 Philips PCA8574 I2C I/O Expander and HD4478OU 2x16 LCD
'*  Compiler     : Proton Amicus18 version 1.0.1.9
'*  IDE          : Amicus18 IDE version 1.0.1.0
'*  Programmer   : Amicus18 IDE version 1.0.1.0
'*  Last Updated : 16 Dec 2011
'****************************************************************************

' Include the ADC Macro Routines
Include "ADC.inc"                       

' Philips PCA8574 8-bit I/O Expander
Symbol PCA8574_ADDR = $4E   ' PCA8574 Device Identifier 

' LCD Command
Symbol LCD_HOME = $02
Symbol LCD_NEXT_LINE = $C0
Symbol LCD_CLEAR = $01
Symbol LCD_1CYCLE= 0
Symbol LCD_2CYCLE= 1

' PCA8574 I2C LCD Port Definition
' P7,P6,P5,P4 = Data, P3=Backlight (BL), P2=E, P1=RW, P0=RS
Dim LCD_BL As Byte
Dim LCD_EN As Byte
Dim LCD_RW As Byte
Dim LCD_RS As Byte 

' Define Variables Used in I2C LCD Routine
Dim LCDData As Byte
Dim LCDStr As String * 20
Dim ChrIndex As Byte
Dim LCDCmdType As Byte
Dim I2CData As Byte 

Dim LEDOut As Byte
Dim LEDSign As Byte
Dim LEDDelay As Word

' Initial the LCD Variables Used
LCD_BL=%00001000
LCD_EN=%00000100
LCD_RW=%00000010
LCD_RS=%00000001

' Goto Main Program Here
GoTo Main  

Write_PCA8574:
  HBStart              ' Send a Start condition
  HBusOut PCA8574_ADDR ' Send a WRITE command to PCA8574
  HBusOut I2CData      ' Send Data to PCA8574
  HBusNack             ' Send No Acknowledge to PCA8574
  HBStop               ' Send a Stop condition
  DelayUS 100          ' Put the 100us Delay Here

  Return
' EOF: Write_PC8574 Subroutine  

LCD_PutCmd:
  ' Put the Upper 4 bits data
  I2CData = (LCDData &amp; $F0)|LCD_BL|LCD_EN
  GoSub Write_PCA8574
  DelayUS 20

  ' Write Enable Pulse E: Hi -&gt; Lo
  I2CData = I2CData &amp; ~LCD_EN
  GoSub Write_PCA8574
  DelayUS 5   

  If LCDCmdType = 1 Then
    ' Put the Lower 4 bits data
    I2CData = ((LCDData &lt;&lt; 4) &amp; $F0)|LCD_BL|LCD_EN
    GoSub Write_PCA8574
    DelayUS 20                

    ' Write Enable Pulse E: Hi -&gt; Lo
    I2CData = I2CData &amp; ~LCD_EN
    GoSub Write_PCA8574
    DelayUS 5
  EndIf
  Return
' EOF LCD_putmcd Subroutine  

LCD_PutCh:
  ' Put the Upper 4 bits data
  I2CData = (LCDData &amp; $F0)|LCD_BL|LCD_EN|LCD_RS
  GoSub Write_PCA8574
  DelayUS 20

  ' Write Enable Pulse E: Hi -&gt; Lo
  I2CData = I2CData &amp; ~LCD_EN
  GoSub Write_PCA8574
  DelayUS 5   

  ' Put the Lower 4 bits data
  I2CData = ((LCDData &lt;&lt; 4) &amp; $F0)|LCD_BL|LCD_EN|LCD_RS
  GoSub Write_PCA8574
  DelayUS 20           

  ' Write Enable Pulse E: Hi -&gt; Lo
  I2CData = I2CData &amp; ~LCD_EN
  GoSub Write_PCA8574
  DelayUS 5
  Return
' EOF LCD_putch Subroutine  

LCD_Init:
  DelayMS 30

  ' Send Command $30
  LCDData=$30
  LCDCmdType=LCD_1CYCLE
  GoSub LCD_PutCmd

  ' Wait for more than 4.1 ms
  DelayMS 8

  ' Send Command $30
  LCDData=$30
  LCDCmdType=LCD_1CYCLE
  GoSub LCD_PutCmd

  ' Wait for more than 100 us
  DelayMS 1

  ' Send Command $30
  LCDData=$30
  LCDCmdType=LCD_1CYCLE
  GoSub LCD_PutCmd

  ' Function set: Set interface to be 4 bits long (only 1 cycle write).
  LCDData=$20
  LCDCmdType=LCD_1CYCLE
  GoSub LCD_PutCmd

  ' Function set: DL=0;Interface is 4 bits, N=1; 2 Lines, F=0; 5x8 dots font)
  LCDData=$28
  LCDCmdType=LCD_2CYCLE
  GoSub LCD_PutCmd 

  ' Display Off: D=0; Display off, C=0; Cursor Off, B=0; Blinking Off
  LCDData=$08
  LCDCmdType=LCD_2CYCLE
  GoSub LCD_PutCmd     

  ' Display Clear
  LCDData=LCD_CLEAR
  LCDCmdType=LCD_2CYCLE
  GoSub LCD_PutCmd       

  ' Entry Mode Set: I/D=1; Increment, S=0; No shift
  LCDData=0x06
  LCDCmdType=LCD_2CYCLE
  GoSub LCD_PutCmd   

  ' Display On, Cursor Off
  LCDData=0x0C
  LCDCmdType=LCD_2CYCLE
  GoSub LCD_PutCmd
  Return
' EOF LCD_Init Subroutine  

LCD_PutStr:
  ChrIndex = 0                ' Start at position 0 within the string
  Repeat
    LCDData=LCDStr[ChrIndex]
    If LCDData = $0A Then
      LCDData=LCD_NEXT_LINE
      LCDCmdType=LCD_2CYCLE
      GoSub LCD_PutCmd
    Else
      GoSub LCD_PutCh
    EndIf
    Inc ChrIndex              ' Move to next position within string
  Until ChrIndex = Len LCDStr
  Return
' EOF LCD_PutStr Subroutine 

' Start the Main Program
Main:
  ' Initial PORTB As Digital Output
  TRISB = %00000000
  PORTB = %00000000        

  ' Open the ADC Macro:
  '  ADC_FOSC_32 - Fosc/32
  '  ADC_RIGHT_JUST - Right justified for 10-bit operation
  '  ADC_2_TAD - TAD value of 2
  '  ADC_REF_VDD_VSS - Vref+ at Vcc : Vref- at Gnd
  '  ADC_1ANA - Use AN0 as an analogue input
  '
  OpenADC(ADC_FOSC_32 &amp; ADC_RIGHT_JUST &amp; ADC_2_TAD, ADC_REF_VDD_VSS, ADC_1ANA)

  ' Initial the LCD Display Here
  GoSub LCD_Init

  ' Display String
  LCDStr="Amicus18 DEMO\n"
  GoSub LCD_PutStr

  ' Init LED Display Variable
  LEDSign=0
  LEDOut=1  

  While 1 = 1                ' Create an endless loop
    ' Reading the 10K Trimpot on AN0
    LEDDelay= ADIn 0   

    ' Display on LCD
    LCDData=LCD_HOME
    LCDCmdType=LCD_2CYCLE
    GoSub LCD_PutCmd     

    LCDData=LCD_NEXT_LINE
    LCDCmdType=LCD_2CYCLE
    GoSub LCD_PutCmd   

    LCDStr="10B ADC: " + Str$(Dec LEDDelay) + "  "
    GoSub LCD_PutStr

    If LEDSign = 0 Then
      PORTB=LEDOut
      DelayMS LEDDelay
      LEDOut=LEDOut &lt;&lt; 1
      If LEDOut &gt;= $80 Then
        LEDSign=1
      EndIf
    Else
      PORTB=LEDOut
      DelayMS LEDDelay
      LEDOut=LEDOut &gt;&gt; 1
      If LEDOut &lt;= $01 Then
        LEDSign=0
      EndIf
    EndIf   
  Wend                       
' EOF: amidemo.bas</pre>
<p><strong>The I<sup>2</sup>C LCD Display</strong></p>
<p>The I<sup>2</sup>C (read as I square C) bus has been introduced in 1980 by Philips, and has become a de-facto world standard for data exchange between Microcontroller and various devices. The advantage of using the I<sup>2</sup>C device is because it only requires 2 wires in order to communicate to the I<sup>2</sup>C device and you could attach many of the I<sup>2</sup>C devices simultaneously on the same I<sup>2</sup>C bus. You could read more information about how the I<sup>2</sup>C protocol works in the <a title="Interfacing the Microchip PIC18 Microcontroller Master Synchronous Serial Port (MSSP) to various I&lt;sup&gt;2&lt;/sup&gt;C Devices" href="http://www.ermicro.com/blog/?p=2157">Interfacing the Microchip PIC18 Microcontroller Master Synchronous Serial Port (MSSP) to various I<sup>2</sup>C Devices</a>  article.</p>
<p>The PCA8574 I/O expander has 3-bit configurable address (000 to 111) which provides up to 7 devices that could be attached simultaneously on the same I<sup>2</sup>C bus. In this project the Philips PCA8574 8-bits I/O expander is used to control the Hitachi HD44780U (or its compatible) 2&#215;16 LCD. The complete I<sup>2</sup>C 2&#215;16 LCD schematic is shown on this following picture.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_05.jpg"><img class="alignnone  wp-image-2232" title="pbasic_05" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_05.jpg" alt="" width="592" height="364" /></a></p>
<p>In this project I used the 4-bit modes of Hitachi 44780U 2&#215;16 LCD driver to send the data from the PCA8574 I/O expander</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_06.jpg"><img class="alignnone  wp-image-2233" title="pbasic_06" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_06.jpg" alt="" width="590" height="346" /></a></p>
<p>The Philips PCA8574 <strong>SDA</strong> (Serial Data, pin 15) and <strong>SCL</strong> (Serial Clock, pin 14) are connected to the Amicus18 board <strong>SDA</strong> pin (<strong>RC4</strong>) and<strong> SCL</strong> pin (<strong>RC5</strong>). These two pins are also called the I<sup>2</sup>C bus where you could attach many of the I<sup>2</sup>C devices on the same bus. Noticed that you need 2 pull-up resistors (value between 2.2K to10K) on each of the I<sup>2</sup>C bus, these pull-up resistors is very important in the I<sup>2</sup>C bus protocol without them the I<sup>2</sup>C bus protocol will not work.</p>
<p><strong>The I<sup>2</sup>C LCD Project BASIC Code</strong></p>
<p>The strength of using the Amicus18 Proton BASIC from Crownhill Associates because it’s a fully compiler language, this mean your BASIC code first will be compiled into the equivalent Microchip PIC assembler code by the Proton BASIC compiler and next the Amicus18 IDE will use the Microchip MPLAB ASM (Assembler) compiler to produce a native Microchip PIC HEX code to be loaded into the PIC18F25K20 microcontroller flash program memory, therefore you need to install the Microchip MPLAB IDE first in order to use the Amicus18 development environment correctly. You could clearly see the compiling phase result when you use the Microchip MPLAB IDE to compile and debug your BASIC code using the Proton BASIC compiler.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_10.jpg"><img class="alignnone  wp-image-2234" title="pbasic_10" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pbasic_10.jpg" alt="" width="587" height="475" /></a></p>
<p>The BASIC code starts by initializing the PORTB as a digital output using the PORTB tri-state buffer registered called TRISB to be <strong>%00000000</strong>. The PORTB is used to drive the 8 LED indicators in this project as shown on this following BASIC code:</p>
<pre>' Initial PORTB As Digital Output
TRISB = %0000000
PORTB = %00000000</pre>
<pre>' Open the ADC Macro:
' ADC_FOSC_32 - Fosc/32
' ADC_RIGHT_JUST - Right justified for 10-bit operation
' ADC_2_TAD - TAD value of 2
' ADC_REF_VDD_VSS - Vref+ at Vcc : Vref- at Gnd
' ADC_1ANA - Use AN0 as an analogue input
'
OpenADC(ADC_FOSC_32 &amp; ADC_RIGHT_JUST &amp; ADC_2_TAD, ADC_REF_VDD_VSS, ADC_1ANA)</pre>
<pre>' Initial the LCD Display Here
GoSub LCD_Init</pre>
<p>The <strong>OpenADC()</strong> macro function is used to initialized the Microchip PIC18F25K20 microcontroller ADC peripheral to read the 10K trimpot attached to the <strong>AN0</strong> (<strong>RA0</strong>) analog port. Next we call the <strong>LCD_Init()</strong> subroutine to initial the 2&#215;16 HD44780U LCD connected to the Philips PCA8574 I<sup>2</sup>C I/O expander. In order to communicate with the PCA8574 chip I used the Proton BASIC <strong>HBusOut</strong> command, this command will automatically use the Microchip PIC18 microcontroller Master Synchronous Serial Port (MSSP) peripheral to communicate with the I<sup>2</sup>C devices. The complete subroutine to write to the Philips PCA8574 I<sup>2</sup>C I/O expander port is implemented in <strong>Write_PCA8574</strong> subroutine.</p>
<pre>Write_PCA8574:
  HBStart              ' Send a Start condition
  HBusOut PCA8574_ADDR ' Send a WRITE command to PCA8574
  HBusOut I2CData      ' Send Data to PCA8574
  HBusNack             ' Send No Acknowledge to PCA8574
  HBStop               ' Send a Stop condition
  DelayUS 100          ' Put the 100us Delay Here
  Return
' EOF: Write_PC8574 Subroutine</pre>
<p>From the <strong>Write_PCA8574</strong> subroutine you could clearly see that in order to send a 8-bit data to the PCA8574 I<sup>2</sup>C chip, first we have to send the I<sup>2</sup>C <strong>START</strong> signal (<strong>HBStart</strong> command) follow by sending the PCA8574 address ($43, 43 in hex notation or 67 in decimal notation) using the <strong>HBusOut</strong> command. Because the I<sup>2</sup>C bus could be connected with many I<sup>2</sup>C devices, therefore every I<sup>2</sup>C devices have their own unique address to be called by the master I<sup>2</sup>C device (i.e. PIC18F25K20 microcontroller).</p>
<p>Next we send the actual data using the <strong>HBusOut</strong> command followed by <strong>HBusNack</strong> (send no acknowledge signal) and <strong>HBStop</strong> (send <strong>STOP</strong> signal) to tell the PCA8574 that we stop sending the data. The I<sup>2</sup>C LCD complete subroutine is implemented in <strong>LCD_PutCmd</strong>, <strong>LCD_PutCh</strong>, <strong>LCD_Init</strong>, and <strong>LCD_PutStr</strong>. You could read the complete explanation of how to drive the Hitachi 44780U 2&#215;16 LCD on this following article <a title="AVR LCD Thermometer Using ADC and PWM Project" href="http://www.ermicro.com/blog/?p=519">AVR LCD Thermometer Using ADC and PWM Project</a>.</p>
<p>Inside the infinite loop (i.e. while – wend statement) we read the 10K trimpot value using the ADC peripheral port <strong>AN0</strong> (<strong>RA0</strong>) and use this value in a <strong>DelayMS</strong> command and display it on the 2&#215;16 LCD. Next we display the bit shifted pattern on the 8 LED connected to the <strong>PORTB</strong>.</p>
<p>Now you could watch and enjoy the entire project presented here on this following video, where you could watch how we use the Amicus18 development environment and Amicus18 Proton BASIC language to interface with the I<sup>2</sup>C 2&#215;16 LCD device.</p>
<p><object width="480" height="360" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/cRAhEV2mrSY?version=3&amp;hl=en_US" /><param name="allowfullscreen" value="true" /><embed width="480" height="360" type="application/x-shockwave-flash" src="http://www.youtube.com/v/cRAhEV2mrSY?version=3&amp;hl=en_US" allowFullScreen="true" allowscriptaccess="always" allowfullscreen="true" /></object></p>
<p><strong>The Final Though</strong></p>
<p>The Amicus18 development environment could be consider as one of the embedded development framework that try to wrap all the “<em>technical complexity</em>” in developing the embedded system using the well known BASIC language, therefore it depend heavily on the “<em>build-in</em>” hardware function (library) that provided by the Amicus18 Proton BASIC compiler to achieve its objective (i.e. easy to use). The good things about the free Amicus18 Proton BASIC compiler that you could write your own BASIC code functions, and distribute this code to other Amicus18 users. But if you prefer to use a C language instead of a BASIC language, than the Amicus18 board could be considered as just another Microchip 28-pins PIC18F family development board with Arduino board form factor.</p>
<p>As I demonstrate in this project because the Amicus18 Proton BASIC compiler use the Microchip MPLAB ASM to produce the final Microchip PIC HEX code, many of the C language style operator has been adopted especially for bit manipulation (e.g. bit shifting, AND/OR, and NOT), and this make developing the embedded system with Amicus18 Proton BASIC become interesting and fun.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ermicro.com/blog/?feed=rss2&amp;p=2215</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Interfacing the Microchip PIC18F Microcontroller Master Synchronous Serial Port (MSSP) to various I2C Devices</title>
		<link>http://www.ermicro.com/blog/?p=2157</link>
		<comments>http://www.ermicro.com/blog/?p=2157#comments</comments>
		<pubDate>Sun, 11 Dec 2011 03:39:43 +0000</pubDate>
		<dc:creator>rwb</dc:creator>
				<category><![CDATA[Microcontroller]]></category>
		<category><![CDATA[24LC02B]]></category>
		<category><![CDATA[EEPROM]]></category>
		<category><![CDATA[HD44780U]]></category>
		<category><![CDATA[I2C]]></category>
		<category><![CDATA[LCD]]></category>
		<category><![CDATA[MCP23008]]></category>
		<category><![CDATA[MCP9801]]></category>
		<category><![CDATA[PCA8574]]></category>
		<category><![CDATA[PIC18F14K22]]></category>
		<category><![CDATA[TC1321]]></category>

		<guid isPermaLink="false">http://www.ermicro.com/blog/?p=2157</guid>
		<description><![CDATA[The Inter-Integrated Circuit or I2C (read as I square C) bus has been introduced in 1980 by Philips, and has become a de-facto world standard for data exchange between Microcontroller and various devices such as temperature sensor, ADC (analog to digital converter), DAC (digital to analog converter), I/O expander, EEPROM, and many more. With more [...]]]></description>
				<content:encoded><![CDATA[<p>The Inter-Integrated Circuit or I<sup>2</sup>C (read as I square C) bus has been introduced in 1980 by Philips, and has become a de-facto world standard for data exchange between Microcontroller and various devices such as temperature sensor, ADC (analog to digital converter), DAC (digital to analog converter), I/O expander, EEPROM, and many more. With more than thousand different IC devices have been manufactured with an I<sup>2</sup>C-bus interface, making the understanding of the working principle of this I<sup>2</sup>C bus is an essential knowledge that has to be acquired by anyone who want to involve in the embedded world professionally or just as hobbyist.<span id="more-2157"></span></p>
<p>In this project we will learn of how to use the powerful 8-Bit Microchip PIC18F14K22 microcontroller Master Synchronous Serial Port (MSSP) in the I<sup>2</sup>C master mode to control various I<sup>2</sup>C devices simultaneously</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_01.jpg"><img class="alignnone size-full wp-image-2158" title="pic18I2C_01" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_01.jpg" alt="" width="578" height="471" /></a></p>
<p><strong>The I<sup>2</sup>C Bus Protocol</strong></p>
<p>The I<sup>2</sup>C bus use master and slave communication principle which mean the slave will response to any master request and only one master or one slave could use the I<sup>2</sup>C bus at the time (half-duplex communication). Therefore the master and slave have to be connected known as “Wired OR” connection using the pull-up resistors for both the I<sup>2</sup>C serial data (SDA) and serial clock (SCL) as shown on this following picture.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_00.jpg"><img class="alignnone size-full wp-image-2165" title="pic18I2C_00" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_00.jpg" alt="" width="584" height="406" /></a></p>
<p>Unlike the SPI (Serial Peripheral Interface) slave devices, the I<sup>2</sup>C devices don’t have the chip select (<strong>CS</strong>) pin where the SPI master could simply drive the CS pin to logic “0” in order to communicate with the target SPI slave device, instead in I<sup>2</sup>C protocol the I<sup>2</sup>C master will transmit the I<sup>2</sup>C slave device unique address in order to communicate with it.</p>
<p>When the I<sup>2</sup>C bus is idle both of the SDA and SCL line will be logic “1”. When the I<sup>2</sup>C master want to start communicate first it will send the <strong>START</strong> signal by putting the SDA line to logic “0” then it start to send the 7-bit I<sup>2</sup>C slave address followed by 1-bit I<sup>2</sup>C bus transfer direction command (WRITE logic “0” or READ logic “1”). The 7-bits I<sup>2</sup>C slave address consists of the upper 4-bits (ID3, ID2, ID1, and ID0) whose are the device specific ID (identification) and encoded within each of the I<sup>2</sup>C slave device.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_02.jpg"><img class="alignnone size-full wp-image-2169" title="pic18I2C_02" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_02.jpg" alt="" width="575" height="255" /></a></p>
<p>The next 3-bits address is called a configurable I<sup>2</sup>C slave device address as it depend on the address pins (A2, A1, and A0) on the I<sup>2</sup>C slave device logical input. For example if we connect the A2, A1, and A0 pins to the ground (GND) or logic “0”, then these 3-bits become “000” or if connect these pins to VCC, then these 3-bits become “111”. For example the complete I<sup>2</sup>C slave address for writing to the Microchip 24LC0B EEPROM whose configurable address A2, A1, and A0 pins connected to logic “0” is “10100000”.</p>
<p>After the I<sup>2</sup>C master send the I<sup>2</sup>C slave address, then the I<sup>2</sup>C slave address will response by pulling the SDA line to low (logical “0”) and this is known as the <em>acknowledge</em> (ACK) to the I2C master. Next the I2C master will continue send the data or terminated the communication by changing the SDA line from logic “0” to logic “1” or known as the STOP signal to all the I<sup>2</sup>C slave devices and the I<sup>2</sup>C bus is back to the idle state status which both of SDA and SCL line is not being driven by both of I<sup>2</sup>C master and slave devices. In idle state the pull-up resistors will pull-up the SDA and SCL lines to become logic “1”.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_06.jpg"><img class="alignnone size-full wp-image-2170" title="pic18I2C_06" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_06.jpg" alt="" width="580" height="476" /></a></p>
<p>The I<sup>2</sup>C master read operation could be done by supplying the read transfer command (LSB) with logic “1”, for example the complete I<sup>2</sup>C slave address for reading from the Microchip 24LC02B EEPROM whose configurable address A2, A1, and A0 pins connected to logic “0” is “10100001”. Next the I<sup>2</sup>C master will send the <em>not acknowledge</em> (NACK) signal (logic “1”) to the I<sup>2</sup>C slave before sending the STOP signal, this NACK signal usually will tell the I<sup>2</sup>C slave device to stop transmitting any data to the I<sup>2</sup>C master.</p>
<p>Sometimes before the I<sup>2</sup>C master read operation could be accomplish (indirect read), we have to do the I<sup>2</sup>C master write operation first which is used to set the I2C slave internal register, then we send the RESTART signal condition (i.e. STOP and START signal) followed by the I<sup>2</sup>C master read operation command.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_07.jpg"><img class="alignnone size-full wp-image-2171" title="pic18I2C_07" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_07.jpg" alt="" width="571" height="560" /></a></p>
<p><strong>The I<sup>2</sup>C Project</strong></p>
<p>As I mention before in this project we learn to control various I<sup>2</sup>C slave devices simultaneously using the Microchip PIC18F14K22 microcontroller, now let’s list down all the necessary hardware, software, and some supported documents in order to accomplish this project objective:</p>
<ul>
<li>Microchip PICkit<sup>TM</sup> Serial I<sup>2</sup>C Demo Board, this board has Microchip 2K I<sup>2</sup>C 24LC0B EEPROM, MCP9801 Microchip 2-Wire High-Accuracy Temperature Sensor, MCP3221 Microchip Low Power 12-Bit A/D Converter With I2C Interface, TC1321 Microchip 10-Bit Digital-to-Analog Converter with Two-Wire Interface, and MCP23008</li>
<li>Microchip 8-Bit I/O Expander with Serial Interface</li>
<li>Additional SMD pull-up 10K (2) resistors for the PICKit Serial I2C Demo Board, you need to solder these two SMD resistors on the board.</li>
<li>PCA8574 Philips/NXP 8-bit I/O expander for I<sup>2</sup>C-bus</li>
<li>One Hitachi HD44780U or compatible 2&#215;16 LCD with blue backlight</li>
<li>SMD Resistors 1K (1) and 4.7K (1)</li>
<li>One 10K Trimpot</li>
<li>One SMD LED (1)</li>
<li>One SMD N-Channel MOSFET MMBF170 or equivalent</li>
<li>One half size breadboard for the I2C LCD</li>
<li>JazMate 5 and 3.3 volt LM2587 switching power supply from <a title="ERMICRO Store" href="http://www.ermicro.com">ermicro</a></li>
<li>PICJazz 20-PIN learning board with Microchip PIC18F14K22 microcontroller from <a title="ERMICRO Store" href="http://www.ermicro.com">ermicro</a></li>
<li>Microchip PICKit2 programmer (used in this project), you could also use the Microchip PICKit3 programmer.</li>
<li>Microchip MPLAB IDE version 8.63 and Microchip HI-TECH C PRO for the PIC18 MCU Family (Lite) V9.63PL3</li>
<li>Reference Document: Microchip PIC18F14K22 datasheet, Microchip 24LC02B datasheet, Microchip MCP9801 datasheet, Microchip MCP3221 datasheet, Microchip TC1321 datasheet, Microchip MCP23008 datasheet, and Philips/NXP PCA8574 datasheet.</li>
</ul>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_09.jpg"><img class="alignnone size-full wp-image-2172" title="pic18I2C_09" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_09.jpg" alt="" width="582" height="399" /></a></p>
<p>&nbsp;</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_03.jpg"><img class="alignnone size-full wp-image-2173" title="pic18I2C_03" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_03.jpg" alt="" width="573" height="449" /></a></p>
<p>The following is the complete C source code for this project:</p>
<pre>/* ***************************************************************************
**  File Name    : i2cmaster.c
**  Version      : 1.0
**  Description  : I2C Master With Microchip PIC18F14K22 Microcontroller
**  Author       : RWB
**  Target       : PICJazz 20PIN Board: PIC18F14K22
**                 Microchip PICKit Serial I2C Demo Board
**                 Philips PCA8574 I2C I/O Expander and 2x16 LCD
**  Compiler     : HI-TECH C PRO for the PIC18 MCU Family (Lite)  V9.63PL3
**  IDE          : Microchip MPLAB IDE v8.63
**  Programmer   : Microchip PICkit 2 - Operating System Version 2.32.0
**  Last Updated : 16 Nov 2011
** ***************************************************************************/
#include &lt;pic18.h&gt;

/*
** PIC18F14K22 Configuration Bit
** Alternative Microchip MPLAB IDE Menu Configure -&gt; Configuration Bits
**
** CONFIG1H: CONFIGURATION REGISTER 1 HIGH
** FCMEN = OFF  - Fail-Safe Clock Monitor disabled
** PCLKEN = ON  - Primary Clock Enable
** PLLEN = OFF  - PLL is under software control
** FOSC = IRC   - Internal RC Oscillator
** CONFIG2L: CONFIGURATION REGISTER 2 LOW
** PWRTEN = OFF - Power Up Timer Enabled
** BOREN = OFF  - Brown-out Reset disabled in hardware and software
** CONFIG2H: CONFIGURATION REGISTER 2 HIGH
** WDTEN = OFF  - WDT is controlled by SWDTEN bit of the WDTCON register
** CONFIG3H: CONFIGURATION REGISTER 3 HIGH
** MCLRE = ON   - MCLR pin enabled, RE3 input pin disabled
** HFOFST = ON  - Clocking the CPU without waiting for the oscillator to stabilize
** CONFIG4L: CONFIGURATION REGISTER 4 LOW
** XINST = ON   - Instruction set extension and Indexed Addressing mode enabled
** STVREN = ON  - Stack full/underflow will cause Reset
** LVP = ON     - Single-Supply ICSP Enable
** CONFIG5H, CONFIG6L, CONFIG6H, CONFIG7L, CONFIG7H - All Not Protected
*/
__CONFIG(1, 0x2800);
__CONFIG(2, 0x0001);
__CONFIG(3, 0x8800);
__CONFIG(4, 0x0065);
__CONFIG(5, 0xFFFF);
__CONFIG(6, 0xFFFF);
__CONFIG(7, 0xFFFF);

// I2C Bus Control Definition
#define I2C_DATA_ACK 0
#define I2C_DATA_NOACK 1
#define I2C_WRITE_CMD 0
#define I2C_READ_CMD 1

#define I2C_START_CMD 0
#define I2C_REP_START_CMD 1
#define I2C_REQ_ACK 0
#define I2C_REQ_NOACK 0

// Microchip MCP23008 8-bit I/O Expander
#define MCP23008_ADDR 0x40   // MCP23008 Device Identifier
#define IODIR 0x00           // MCP23008 I/O Direction Register
#define GPIO  0x09           // MCP23008 General Purpose I/O Register
#define OLAT  0x0A           // MCP23008 Output Latch Register

// Microchip 24LC02B 2KB I2C EEPROM
#define M24LC02B_ADDR  0xA0  // 24LC02B Device Identifier

// Microchip MCP9801 I2C Temperature Sensor
#define MCP9801_ADDR  0x92  // MCP9801 Device Identifier
#define TEMP_REGISTER 0x00  // MCP9801 Ambient Temperature Register
#define CONF_REGISTER 0x01  // MCP9801 Configuration Register
#define TEMP_SAMPLE 5

// Microchip MCP3221 I2C ADC
#define MCP3221_ADDR  0x9A  // MCP3221 Device Identifier

// Microchip TC1321 I2C DAC
#define TC1321_ADDR  0x90   // TC1321 Device Identifier
#define DATA_REGISTER 0x00  // TC1321 Data Register Select Command
#define CONF_REGISTER 0x01  // TC1321 Config Register Select Command

// Philips PCA8574 8-bit I/O Expander
#define PCA8574_ADDR 0x4E   // PCA8574 Device Identifier 

// PCA8574 I2C LCD Port Definition
// P7,P6,P5,P4 = Data, P3=Backlight (BL), P2=E, P1=RW, P0=RS
#define LCD_BL 0b00001000
#define LCD_EN 0b00000100
#define LCD_RW 0b00000010
#define LCD_RS 0b00000001

// LCD Command
#define LCD_HOME 0x02
#define LCD_NEXT_LINE 0xC0
#define LCD_CLEAR 0x01
#define LCD_1CYCLE 0
#define LCD_2CYCLE 1

// Using Internal Clock of 16 Mhz
#define FOSC 16000000UL
#define MAX_DATA 32           

// Used for Displaying the Numeric Value
char sdigit[]={'0','0','0','0','0','\0'};

// Simple Delay Function, you might adjust the value for different clock speed
#define	delay_us(x) {unsigned char _dcnt; \
		    _dcnt = (x)/(24000000UL/FOSC)|1; \
		    while(--_dcnt != 0) continue; \
                    }

void delay_ms(unsigned int cnt)
{
  unsigned char i;

  if (cnt == 0) return;
  do {
    i = 5;
    do {
      delay_us(164);
    } while(--i);
  } while(--cnt);
}

// Start PIC18F14K22 I2C Function
void i2c_init(void) {
  // Initial PIC18F14K22 I2C bus Ports: RB4 - SDA and RB6 - SCL, Set as Input
  TRISBbits.TRISB4 = 1;
  TRISBbits.TRISB6 = 1;  

  // Initial the PIC18F14K22 MSSP Peripheral I2C Master Mode
  // I2C Master Clock Speed: 16000000 / ((4 * (SSPADD + 1)) = 16000000 / (4 * (39 + 1))
  SSPSTAT = 0x80;      // Slew Rate is disable for 100 kHz mode
  SSPCON1 = 0x28;      // Enable SDA and SCL, I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))
  SSPCON2 = 0x00;      // Reset MSSP Control Register
  SSPADD = 39;         // Standard I2C Clock speed: 100 kHz  

  PIR1bits.SSPIF=0;    // Clear MSSP Interrupt Flag
}

void i2c_idle(void)
{
  // Wait I2C Bus and Status Idle (i.e. ACKEN, RCEN, PEN, RSEN, SEN)
  while (( SSPCON2 &amp; 0x1F ) || ( SSPSTATbits.R_nW));
}

void i2c_start(unsigned char stype)
{
  i2c_idle();                     // Ensure the I2C module is idle
  if (stype == I2C_START_CMD) {
    SSPCON2bits.SEN = 1;          // Start I2C Transmission
    while(SSPCON2bits.SEN);
  } else {
    SSPCON2bits.RSEN = 1;         // ReStart I2C Transmission
    while(SSPCON2bits.RSEN);
  }
}

void i2c_stop(void)
{
  // Stop I2C Transmission
  SSPCON2bits.PEN = 1;
  while(SSPCON2bits.PEN);
}

unsigned char i2c_slave_ack(void)
{
  // Return: 1 = Acknowledge was not received from slave
  //         0 = Acknowledge was received from slave
  return(SSPCON2bits.ACKSTAT);
}

void i2c_write(unsigned char data)
{
  // Send the Data to I2C Bus
  SSPBUF = data;
  if (SSPCON1bits.WCOL)         // Check for write collision
    return;  

  while(SSPSTATbits.BF);        // Wait until write cycle is complete
  i2c_idle();                   // Ensure the I2C module is idle
}

void i2c_master_ack(unsigned char ack_type)
{
  SSPCON2bits.ACKDT = ack_type;   // 1 = Not Acknowledge, 0 = Acknowledge
  SSPCON2bits.ACKEN = 1;          // Enable Acknowledge
  while (SSPCON2bits.ACKEN == 1);
}

unsigned char i2c_read(void)
{
  // Ensure the I2C module is idle
  i2c_idle();                         

  // Enable Receive Mode
  SSPCON2bits.RCEN = 1;           // Enable master for 1 byte reception
  while(!SSPSTATbits.BF);         // Wait until buffer is full
  return(SSPBUF);
}

unsigned char Read_24LC02B(unsigned int mem_addr)
{
  unsigned char data;

  // Start the I2C Transmission
  i2c_start(I2C_START_CMD);

  // Write 24LC02B Control Byte - Write
  i2c_write(M24LC02B_ADDR|I2C_WRITE_CMD);  

  // Sending the 24LC02B 8-Bit Memory Address Pointer
  i2c_write(mem_addr &amp; 0x00FF);     

  // ReStart the I2C Transmission
  i2c_start(I2C_REP_START_CMD);

  // Write 24LC02B Control Byte - Read
  i2c_write(M24LC02B_ADDR|I2C_READ_CMD); 

  // Read Data from 24LC02B EEPROM
  data=i2c_read(); 

  // Master send No Acknowledge Required to the Slave
  i2c_master_ack(I2C_DATA_NOACK);  

  // Stop the I2C Transmission
  i2c_stop();  

  return(data);
}

void Write_24LC02B(unsigned int mem_addr,unsigned char data)
{
  // Start the I2C Write Transmission
  i2c_start(I2C_START_CMD);

  // Write I2C OP Code
  i2c_write(M24LC02B_ADDR|I2C_WRITE_CMD);     

  // Sending the 24LC02B 8-bit Memory Address Pointer
  i2c_write(mem_addr &amp; 0x00FF);       

  // Write data to 24LC02B EEPROM
  i2c_write(data);   

  // Stop I2C Transmission
  i2c_stop();  

  // Put some delay 5ms here
  delay_ms(5);
}

void Write_MCP23008(unsigned char reg_addr,unsigned char data)
{
  // Start the I2C Write Transmission
  i2c_start(I2C_START_CMD);

  // Write I2C OP Code
  i2c_write(MCP23008_ADDR|I2C_WRITE_CMD); 

  // Sending the Register Address
  i2c_write(reg_addr);  

  // Write data to MCP23008 Register
  i2c_write(data);   

  // Stop I2C Transmission
  i2c_stop();
}

unsigned int Read_MCP3221(void)
{
  unsigned int adcdata;
  unsigned char hidata,lodata;

  // Start the I2C Write Transmission
  i2c_start(I2C_START_CMD);    

  // Read MCP3221 I2C ADC Control Byte - Read
  i2c_write(MCP3221_ADDR|I2C_READ_CMD);     

  // Get the High Byte of MCP3221 A/D Conversion
  hidata=i2c_read();

  // Send Acknowledge to the Slave
  i2c_master_ack(I2C_DATA_ACK);  

  // Get the Low Byte of MCP3221 A/D Conversion
  lodata=i2c_read();   

  // Send No Acknowledge to the Slave
  i2c_master_ack(I2C_DATA_NOACK);  

  // Stop I2C Transmission
  i2c_stop();  

  // Return 12-bit ADC Data
  adcdata = lodata;
  adcdata += ((int)hidata) &lt;&lt; 8;      

  return(adcdata);
} 

void Write_MCP9801(unsigned char reg_addr,unsigned char data) {
  // Start the I2C Write Transmission
  i2c_start(I2C_START_CMD);   

  // Write MCP9801 I2C OP Code
  i2c_write(MCP9801_ADDR|I2C_WRITE_CMD);    

  // Sending the Register Address
  i2c_write(reg_addr);

  // Write data to MCP9801 Register
  i2c_write(data);        

  // Stop I2C Transmission
  i2c_stop();
} 

unsigned char Read_MCP9801(unsigned char *dval) {
  unsigned char hidata,lodata;
  char decval[]={0,25,50,75};     

  // Start the I2C Write Transmission
  i2c_start(I2C_START_CMD);        

  // Read MCP9801 I2C Temp Sensor Control Byte - Read
  i2c_write(MCP9801_ADDR|I2C_READ_CMD);        

  // Get the High Byte of MCP9801 I2C Temp Sensor
  hidata=i2c_read();   

  // Send Acknowledge to the Slave
  i2c_master_ack(I2C_DATA_ACK);     

  // Get the Low Byte of MCP9801 I2C Temp Sensor
  lodata=i2c_read();      

  // Send No Acknowledge to the Slave
  i2c_master_ack(I2C_DATA_NOACK);     

  // Stop I2C Transmission
  i2c_stop();     

  // Return 10-bit Temp Sensor Data
  *dval=decval[lodata &gt;&gt; 6];           // Convert lower data to decimal.

  return(hidata);
}

void Write_PCA8574(unsigned char data)
{
  // Start the I2C Write Transmission
  i2c_start(I2C_START_CMD);

  // Write PCA8574 I2C OP Code
  i2c_write(PCA8574_ADDR|I2C_WRITE_CMD);   

  // Write data to PCA8574 Register
  i2c_write(data);     

  // Send No Acknowledge to the Slave
  i2c_master_ack(I2C_DATA_NOACK);  

  // Stop I2C Transmission
  i2c_stop();
}

/*
** PCA8574 I2C LCD Routine
** LCD Data PCA8574: P7,P6,P5,P4
** LCD Control: P3: Back Light, P2: E-Enable, P1:RW, P0: RS
*/
void LCD_putcmd(unsigned char data,unsigned char cmdtype)
{
  unsigned char lcddata;  

  // Put the Upper 4 bits data
  lcddata = (data &amp; 0xF0)|LCD_BL;
  Write_PCA8574(lcddata | LCD_EN);
  delay_us(2);      // Delay 2us for 16 MHz Internal Clock   

  // Write Enable Pulse E: Hi -&gt; Lo
  Write_PCA8574(lcddata &amp; ~LCD_EN);
  delay_us(1);      // Delay 1us for 16 MHz Internal Clock   

  // cmdtype = 0; One cycle write, cmdtype = 1; Two cycle writes
  if (cmdtype) {
    // Put the Lower 4 bits data
    lcddata = ((data &lt;&lt; 4) &amp; 0xF0)|LCD_BL;
    Write_PCA8574(lcddata | LCD_EN);
    delay_us(2);    // Delay 2us for 16 MHz Internal Clock    

    // Write Enable Pulse E: Hi -&gt; Lo
    Write_PCA8574(lcddata &amp; ~LCD_EN);
    delay_us(1);    // Delay 1us for 16 MHz Internal Clock
  }
}

void LCD_putch(unsigned char data)
{
  unsigned char lcddata;

  // Put the Upper 4 bits data
  lcddata = (data &amp; 0xF0)|LCD_BL|LCD_RS;
  Write_PCA8574(lcddata | LCD_EN);
  delay_us(2);      // Delay 2us for 16 MHz Internal Clock     

  // Write Enable Pulse E: Hi -&gt; Lo
  Write_PCA8574(lcddata &amp; ~LCD_EN);
  delay_us(1);      // Delay 1us for 16 MHz Internal Clock   

  // Put the Lower 4 bit data
  lcddata = ((data &lt;&lt; 4) &amp; 0xF0)|LCD_BL|LCD_RS;
  Write_PCA8574(lcddata | LCD_EN);
  delay_us(2);      // Delay 2us for 16 MHz Internal Clock    

  // Write Enable Pulse E: Hi -&gt; Lo
  Write_PCA8574(lcddata &amp; ~LCD_EN);
  delay_us(1);      // Delay 1us for 16 MHz Internal Clock
}

void LCD_init(void)
{
  // Wait for more than 15 ms after VCC rises to 4.5 V
  delay_ms(30);

  // Send Command 0x30
  LCD_putcmd(0x30,LCD_1CYCLE);

  // Wait for more than 4.1 ms
  delay_ms(8);

  // Send Command 0x30
  LCD_putcmd(0x30,LCD_1CYCLE);

  // Wait for more than 100 us
  delay_ms(1);           

  // Send Command 0x30
  LCD_putcmd(0x30,LCD_1CYCLE);

  // Function set: Set interface to be 4 bits long (only 1 cycle write).
  LCD_putcmd(0x20,LCD_1CYCLE);  

  // Function set: DL=0;Interface is 4 bits, N=1; 2 Lines, F=0; 5x8 dots font)
  LCD_putcmd(0x28,LCD_2CYCLE);

  // Display Off: D=0; Display off, C=0; Cursor Off, B=0; Blinking Off
  LCD_putcmd(0x08,LCD_2CYCLE);

  // Display Clear
  LCD_putcmd(LCD_CLEAR,LCD_2CYCLE);

  // Entry Mode Set: I/D=1; Increament, S=0; No shift
  LCD_putcmd(0x06,LCD_2CYCLE);

  // Display On, Cursor Off
  LCD_putcmd(0x0C,LCD_2CYCLE);
}

void LCD_puts(const char *s)
{
  while(*s != 0) {      // While not Null
    if (*s == '\n')
      LCD_putcmd(LCD_NEXT_LINE,LCD_2CYCLE);  // Goto Second Line
    else
      LCD_putch(*s);
    s++;
  }
}

// Implementing integer value from 0 to 65530
char *num2str(unsigned int number,unsigned char start_digit)
{
   unsigned char digit;

   if (number &gt; 65530) number = 0;    

   digit = '0';                       // Start with ASCII '0'
   while(number &gt;= 10000)             // Keep Looping for larger than 10000
   {
     digit++;                         // Increase ASCII character
     number -= 10000;                 // Subtract number with 10000
   }

   sdigit[0]='0';                     // Default first Digit to '0'
   if (digit != '0') sdigit[0]=digit; // Put the first digit

   digit = '0';                       // Start with ASCII '0'
   while(number &gt;= 1000)              // Keep Looping for larger than 1000
   {
     digit++;                         // Increase ASCII character
     number -= 1000;                  // Subtract number with 1000
   }

   sdigit[1]='0';                     // Default Second Digit to '0'
   if (digit != '0') sdigit[1]=digit; // Put the Second digit

   digit = '0';                       // Start with ASCII '0'
   while(number &gt;= 100)               // Keep Looping for larger than 100
   {
     digit++;                         // Increase ASCII character
     number -= 100;                   // Subtract number with 100
   }

   sdigit[2]='0';                     // Default Second Digit to '0'
   if (digit != '0') sdigit[2]=digit; // Put the Second digit

   digit = '0';                       // Start with ASCII '0'
   while(number &gt;= 10)                // Keep Looping for larger than 10
   {
     digit++;                         // Increase ASCII character
     number -= 10;                    // Subtract number with 10
   }

   sdigit[3]='0';                     // Default Second Digit to '0'
   if (digit != '0') sdigit[3]=digit; // Put the Second digit

   sdigit[4]='0' + number;
   return(sdigit + start_digit);
}

void Write_TC1321(unsigned int data)
{
  unsigned int dac_out;

  // Start the I2C Write Transmission
  i2c_start(I2C_START_CMD);

  // Write TC1321 I2C OP Code
  i2c_write(TC1321_ADDR|I2C_WRITE_CMD);   

  // Select TC1321 Data Register
  i2c_write(DATA_REGISTER);       

  // Write 10-bit Data to the TC1321 Data Register
  // Format xxxx xxxx xx00 0000 

  // Write High Byte Data
  dac_out=(data &lt;&lt; 6) &amp; 0xFF00;   i2c_write(dac_out &gt;&gt; 8);       

  // Write Low Byte Data
  dac_out=(data &lt;&lt; 6) &amp; 0x00C0;
  i2c_write(dac_out);       

  // Stop I2C Transmission
  i2c_stop();
}

void main(void)
{
  unsigned char buffer[MAX_DATA]= {0b00000001,0b00000011,0b00000110,0b00001100,0b00011001,
  		  	           0b00110011,0b01100110,0b11001100,0b10011000,0b00110000,
			           0b01100000,0b11000000,0b10000000,0b00000000,0b00000000,
			           0b00000000,0b10000000,0b11000000,0b01100000,0b00110000,
			           0b10011000,0b11001100,0b01100110,0b00110011,0b00011001,
			           0b00001100,0b00000110,0b00000011,0b00000001,0b00000000,
			           0b00000000,0b00000000};		

  unsigned int addr_ptr,delay_value,adc_value;
  unsigned char eeprom_data,temp_value,temp,dvalue,sign,tsample,disp_stat,press_count;
  unsigned char LED[3] = {0x01,0x02,0x04};	 

  OSCCON=0x70;         // Select 16 MHz internal clock 

  TRISA = 0x03;        // Input for RA0 and RA3
  TRISB = 0x00;        // Input for PORTB
  TRISC = 0x00;        // Set All on PORTC as Output
  PORTC = 0x00;        // Reset PORTC
  ANSEL = 0x00;        // Set AN0 - Analog Input and PORT AN1 to AN7 as Digital I/O
  ANSELH = 0x00;       // Set PORT AN8 to AN11 as Digital I/O    

  // Initial the PIC18F14K22 I2C Master
  i2c_init(); 

  // Init the PIC18F14K22 ADC Peripheral
  ADCON0=0b00000001;   // ADC port Channel 0 (AN0), Enable ADC
  ADCON1=0b00000000;   // Use Internal Voltage Reference (Vdd and Vss)
  ADCON2=0b10101011;   // Right justify result, 12 TAD, Select the FRC for 16 MHz 

  // Initial LCD using 4 bits data interface
  LCD_init();
  LCD_puts("PICJazz 18F14K22\n");    

  // Initial and Write the 24LC02B 2K I2C EEPROM
  for(addr_ptr=0;addr_ptr &lt; MAX_DATA;addr_ptr++) {
   Write_24LC02B(addr_ptr,buffer[addr_ptr]);
  }            

  // Initial the MCP23008 8-bit I2C I/O Expander
  Write_MCP23008(IODIR,0b00000000);
  Write_MCP23008(GPIO,0x00);    // Reset all the Output Port         

  // Initial the MCP9801 10-bit I2C Digital Temperature Sensor
  Write_MCP9801(CONF_REGISTER,0b00100000); // Used 10-Bit Mode
  Write_MCP9801(TEMP_REGISTER,0b00000000); // Select Temperature Register    

  // Reset the TC1321 DAC Voltage Output
  Write_TC1321(0);         

  addr_ptr=0;                   // EEPROM Address Pointer
  tsample=TEMP_SAMPLE;          // Temperature Sample
  press_count=0;                // Debounce Button Pressed Count
  disp_stat=0;                  // Default Display Temperature
  PORTC=LED[disp_stat];         // Display Status Monitor        

  for(;;) {                     // Loop Forever
    if (PORTAbits.RA1 == 0) {   // Read Switch
      if (++press_count &gt; 4) {  // Read 5 Times for Simple Debounce
        press_count=0;          // Reset Press Count Variable
        if (++disp_stat &gt; 2)
           disp_stat=0;

        PORTC=LED[disp_stat];   // Display Status on PORTC

        LCD_putcmd(LCD_CLEAR,LCD_2CYCLE);  // LCD Clear
        LCD_putcmd(LCD_HOME,LCD_2CYCLE);   // LCD Home
        LCD_puts("PICJazz 18F14K22\n");
      }
    }              

    // Read the PIC18K14K22 10-Bit AN0 ADC Input
    ADCON0bits.GO_nDONE=1;
    while (ADCON0bits.GO_nDONE) continue;  // Wait conversion done
    adc_value=ADRESL;                      // Get the 8 bit LSB result
    adc_value += (ADRESH &lt;&lt; 8);            // Get the 2 bit MSB result         

    // Write to the TC1321 10-Bit DAC
    Write_TC1321(adc_value);      

    // Read 24LC0B I2C EEPROM Data
    eeprom_data=Read_24LC02B(addr_ptr);                 

    // Write to MCP23008 I2C I/O
    Write_MCP23008(GPIO,eeprom_data);        

    // Increase the Serial EEPROM Index Pointer
    if (++addr_ptr &gt;= MAX_DATA) addr_ptr=0;                    

    // Read the MCP3221 I2C 12-Bit ADC
    delay_value=Read_MCP3221();            

    // Read the MCP9801 I2C Digital Temp Sensor
    if (++tsample &gt; TEMP_SAMPLE) {
      temp_value=Read_MCP9801(&amp;dvalue);
      temp=temp_value &amp; 0x7F;
      sign=temp_value &amp; 0x80;         

      // Reset Temperature Sample
      tsample=0;
    }        

    // Display to I2C PCA8574 I/O LCD
    LCD_putcmd(LCD_HOME,LCD_2CYCLE);       // LCD Home
    LCD_putcmd(LCD_NEXT_LINE,LCD_2CYCLE);  // Goto Second Line

    switch(disp_stat) {
      case 0:                              // Display Temperature
        LCD_puts("Temp:"); 

        // Put negative sign
        if (sign == 0x80) {
          LCD_putch('-');
          temp = ~(temp &amp; 0x7F);
        } else {
          LCD_putch(' ');
        }

        // Now put the Temperature value;
        LCD_puts(num2str(temp,2));        // Display Temperature
        LCD_putch('.');
        LCD_puts(num2str(dvalue,3));      // Display the decimal part
        LCD_putch(0xDF); LCD_putch('C');  // Put Degree and Centigrade sign
        break;
      case 1:                             // Display 10-Bit PIC18K14K22 ADC Value
        LCD_puts("10B ADC: ");
        LCD_puts(num2str(adc_value,1));   // 10-Bit ADC Value for DAC
        break;
      case 2:                             // Display 12-Bit MCP3221 ADC Value
        LCD_puts("12B ADC: ");
        LCD_puts(num2str(delay_value,1)); // 12-Bit ADC Value for Delay
        break;
    } 

    // Used 12-bit ADC for Loops Delay
    delay_ms(delay_value);
  }
}

/* EOF: i2cmaster.c */</pre>
<p><strong>The Microchip PIC18F14K22 MSSP Module</strong></p>
<p>The Microchip PIC18F14K22 microcontroller I<sup>2</sup>C peripheral actually is the part of Master Synchronous Serial Port (MSSP) peripheral inside the PIC18F14K22 microcontroller. Each module could be operated in one of the two modes: Serial Peripheral Interface (SPI) or Inter-Integrated Circuit (I<sup>2</sup>C). The I<sup>2</sup>C module could support both I<sup>2</sup>C master and I<sup>2</sup>C slave modes. For the purpose of this tutorial we will only focusing on the I<sup>2</sup>C Master mode.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_04.jpg"><img class="alignnone size-full wp-image-2174" title="pic18I2C_04" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_04.jpg" alt="" width="584" height="198" /></a></p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_05.jpg"><img class="alignnone size-full wp-image-2175" title="pic18I2C_05" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_05.jpg" alt="" width="583" height="343" /></a></p>
<p>To initialize the I<sup>2</sup>C peripheral inside the PIC18F14K22 microcontroller we need to enable the SDA and SLC pins for the I<sup>2</sup>C master operation using the Synchronous Serial Port Enable bit (<strong>SSPEN</strong>) and set the I<sup>2</sup>C master clock frequency using the MSSP Synchronous Serial Port Mode Select bits <strong>SSPM&lt;3:0&gt;</strong> in control register 1 (<strong>SSPCON1</strong>). Next we set the Baud Rate Register (<strong>SSPADD</strong>) so the I<sup>2</sup>C master will generate the required I2C frequency clock at 100 kHz. These following are the complete C code for initializing the PIC18F14K22 microcontroller MSSP in I<sup>2</sup>C master mode.</p>
<pre>// Initial PIC18F14K22 I2C bus Ports: RB4 - SDA and RB6 - SCL, Set as Input
TRISBbits.TRISB4 = 1;
TRISBbits.TRISB6 = 1;</pre>
<pre>// Initial the PIC18F14K22 MSSP Peripheral I2C Master Mode
// I2C Master Clock Speed: 16000000 / ((4 * (SSPADD + 1)) = 16000000 / (4 * (39 + 1))
SSPSTAT = 0x80; // Slew Rate is disable for 100 kHz mode
SSPCON1 = 0x28; // Enable SDA and SCL, I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))
SSPCON2 = 0x00; // Reset MSSP Control Register
SSPADD = 39; // Standard I2C Clock speed: 100 kHz</pre>
<pre>PIR1bits.SSPIF=0; // Clear MSSP Interrupt Flag</pre>
<p>Transmitting and receiving I<sup>2</sup>C data to and from the I<sup>2</sup>C bus is done in the <strong>SSPBUF</strong> register, therefore by placing the data on this register we instruct the MSSP module to start the I<sup>2</sup>C master data transmission. The I<sup>2</sup>C write is implemented in <strong>i2c_write()</strong> function as shown on these following C codes:</p>
<pre>// Send the Data to I2C Bus
SSPBUF = data;
if (SSPCON1bits.WCOL) // Check for write collision
  return;</pre>
<pre>while(SSPSTATbits.BF); // Wait until write cycle is complete
i2c_idle(); // Ensure the I2C module is idle</pre>
<p>The Buffer Full bit (<strong>BF</strong>) in MSSP status register (<strong>SSPSTAT</strong>) is used to check the I<sup>2</sup>C master buffer. When the I2C master has shift all the 8-bit data through the MSSP shift register (<strong>SSPSR</strong>) then the <strong>BF</strong> bit will be cleared (logic “0”). Next we use <strong>ACKEN</strong> (Acknowledge Sequence Enable), <strong>RCEN</strong> (Receive Enable), <strong>PEN</strong> (Stop Condition Enable), RSEN (Repeated Start Condition), <strong>SEN</strong> (Start Condition Enable) bits in MSSP control register 2 (<strong>SSPCON2</strong>) , and read/write information bit (<strong>R/W</strong>) in <strong>SSPSTAT</strong> register to check the I2C bus idle condition. This I<sup>2</sup>C bus idle checker is implemented in <strong>i2c_idle()</strong> function.</p>
<p>The I<sup>2</sup>C master reading could be done by setting the <strong>RCEN</strong> bit in <strong>SSPCON2</strong> register and wait until the <strong>BF</strong> bit in <strong>SSPSTAT</strong> register is being clear, next the 8-bit data could be retrieve from the <strong>SSPBUF</strong> register. The I<sup>2</sup>C read is implemented in <strong>i2c_read()</strong> function as shown on these following C codes:</p>
<pre>// Ensure the I2C module is idle
i2c_idle();</pre>
<pre>// Enable Receive Mode</pre>
<pre>SSPCON2bits.RCEN = 1; // Enable master for 1 byte reception
while(!SSPSTATbits.BF); // Wait until buffer is full
return(SSPBUF);</pre>
<p>The I<sup>2</sup>C master START, STOP, and slave NACK signal are implemented in <strong>i2c_start()</strong>, <strong>i2c_stop()</strong>, and <strong>i2c_slave_ack()</strong> functions. Now as you understand the principle of how the PIC18F14K22 microcontroler MSSP in I<sup>2</sup>C master work, next I used this following block diagram template to perform the PIC18F14K22 MSSP I<sup>2</sup>C master write and read operation to various I<sup>2</sup>C slave devices used in this project. For the complete information about the MSSP in I2C mode please refers to the Microchip PIC18F14K22 microcontroller datasheet.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_08.jpg"><img class="alignnone size-full wp-image-2177" title="pic18I2C_08" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_08.jpg" alt="" width="574" height="425" /></a></p>
<p><strong>The Microchip 2KBit I<sup>2</sup>C Serial EEPROM</strong></p>
<p>The 24LC02B is a 2 Kbit Electrically Erasable PROM (EEPROM). The device is organized as one block of 256 x 8-bit memory with a I<sup>2</sup>C interface</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_10.jpg"><img class="alignnone size-full wp-image-2178" title="pic18I2C_10" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_10.jpg" alt="" width="578" height="317" /></a></p>
<p>Because the Microchip 24LC02B I<sup>2</sup>C EEPROM only has 2Kbit (256 byte) memory, therefore we only need 8-bit address pointer to write or read data to or from the EEPROM. For the I<sup>2</sup>C EEPROM that has memory more than 256 byte such as Microchip 24AA128 EEPROM (128 Kbit) you have to use the 16-bit address pointer this mean first you need to send the upper 8-bits of the EEPROM address then next the lower 8-bits of the EEPROM address.</p>
<p>In this project I used the 24LC02B I2C EEPROM to store the 8-bits LED data pattern and next retrieve the data to be displayed by the Microchip MCP23008 I<sup>2</sup>C 8-bits I/O expansion. The complete 24LC02B write and read (I<sup>2</sup>C indirect data read) operation is implemented in <strong>Write_24LC02B()</strong> and <strong>Read_24LC02B()</strong> functions. For more information on how to operate the Microchip 24LC02B please refers to the 24LC02B datasheet.</p>
<p><strong>The Microchip MCP9801 I<sup>2</sup>C Temperature Sensor</strong></p>
<p>The Microchip MCP9801 is the I<sup>2</sup>C temperature sensors which convert temperatures between -55°C and +125°C to a digital word. It provide an accuracy of ±1°C (max.) from -10°C to +85°C</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_11.jpg"><img class="alignnone size-full wp-image-2179" title="pic18I2C_11" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_11.jpg" alt="" width="564" height="294" /></a></p>
<p>The Microchip MCP9801 could be configured to output 9-bits, 10-bits, 11-bits, or 12-bits digital precision temperature reading, in this project I used the 10-bits precision mode which could measure the temperature from +0.25 °C to 125 °C. Setting the MCP9801 could be done by choosing the correct register through the MCP9801 register pointer. These following C codes show how to configure the MCP9801 temperature sensor to use the 10-bits precision and set the MCP9801 register pointer to point to the temperature register for the temperature data reading:</p>
<pre>// Initial the MCP9801 10-bit I2C Digital Temperature Sensor
Write_MCP9801(CONF_REGISTER,0b00100000); // Used 10-Bit Mode
Write_MCP9801(TEMP_REGISTER,0b00000000); // Select Temperature Register</pre>
<p>The MCP9801 also capable to rise an alert on ALERT pin (pin 3 is an open collector), If the ambient temperature exceeds the limit preconfigured maximum temperature on the temperature limit-set register. The complete MCP9801 write and read operation is implemented in <strong>Write_MCP9801()</strong> and <strong>Read_MCP9801()</strong> functions. For more information on how to operate the Microchip MCP29801 please refers to the MCP29801 datasheet.</p>
<p><strong>The Microchip MCP3221 I<sup>2</sup>C Analog to Digital Converter</strong></p>
<p>The Microchip MCP3221 is a successive approximation A/D converter with 12-bit resolution, unlike the other I<sup>2</sup>C device, the MCP3221 doesn’t have the A2, A1, and A0 pins, instead this address is hard coded inside the chip (A2=1, A1=0, and A0=1). Therefore you could only connect one MCP3221 temperature sensor on the same I<sup>2</sup>C bus, according to the datasheet if you need different address setting you need to contact the Microchip Technology Inc.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_12.jpg"><img class="alignnone size-full wp-image-2180" title="pic18I2C_12" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_12.jpg" alt="" width="563" height="350" /></a></p>
<p>Because the MCP3221 has 12-bits ADC output, therefore we need to read it twice. First the MCP3221 will send the upper 8-bits (high byte) data and next the lower 8-bits data (low bytes).</p>
<p>I used the MCP3221 ADC reading to give a delay inside the infinite loop; this will give an adjustable speed of the LED chasing effect display (attached on MCP23008 8-bit I/O expansion) according to the ADC value returned by MCP3221. The complete MCP3221 read operation is implemented in <strong>Read_MCP3221()</strong> function. For more information on how to operate the Microchip MCP3221 please refers to the MCP3221 datasheet.</p>
<p><strong>The Microchip TC1321 I<sup>2</sup>C Digital to Analog (DAC) Converter</strong></p>
<p>The Microchip TC1321 is a serially accessible 10-bits voltage output digital-to-analog converter (DAC). The DAC produces an output voltage that ranges from ground to an externally supplied reference voltage. The TC1321 is ideal to be used in the Programmable Voltage Sources and the Digital Controlled Amplifiers/Attenuators. The TC1321 also doesn’t have the A2, A1, and A0 pins, instead this address is hard coded inside the chip (A2=0, A1=0, and A0=0). Therefore you could only connect one TC1321 DAC on the same I2C bus.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_13.jpg"><img class="alignnone size-full wp-image-2181" title="pic18I2C_13" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_13.jpg" alt="" width="560" height="325" /></a></p>
<p>The 10-bits TC1321 I<sup>2</sup>C DAC circuit above used the Microchip MCP1525 2.5 volt voltage reference for the DAC circuitry to convert the 10-bits digital input to the corresponding analog output according to this following formula:</p>
<p><strong>Vout = Vref (DATA/1024)</strong></p>
<p>Therefore using the voltage reference of 2.5 volt, the DAC voltage output (Vout) will swing from 0 volt to maximum of 2.5 volt according to the 10-bits data input. In this project the 10-bits data input is provided by the PIC18F14K22 internal 10-bits ADC peripheral on channel 0 (AN0) which is connected to 10K user trimpot and the TC1321 DAC output voltage (Vout)  is simply connected to the DVM (Digital Volt Meter). The complete TC1321 write operation is implemented in <strong>Write_TC1321()</strong> function. For more information on how to operate the Microchip TC1321 please refers to the TC1321 datasheet.</p>
<p><strong>The Microchip MCP23008 I<sup>2</sup>C 8-Bit I/O Expander</strong></p>
<p>The Microchip MCP23008 I<sup>2</sup>C 8-bits I/O Expander has the 3-bit configurable address (000 to 111) which provides up to 7 devices that could be attached simultaneously on the same I<sup>2</sup>C bus. This will give you a total of 56 ports. MCP23008 also come with 11 internal register to control its operation.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_14.jpg"><img class="alignnone size-full wp-image-2182" title="pic18I2C_14" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_14.jpg" alt="" width="580" height="295" /></a></p>
<p>Before we could use the MCP23008 I/O ports first we have to configure the I/O port as the output port or input port using the MCP23008 I/O direction register (<strong>IODIR</strong>). To write or read the MCP23008 I/O port we have to use the general purpose I/O register (<strong>GPIO</strong>).</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_15.jpg"><img class="alignnone size-full wp-image-2183" title="pic18I2C_15" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_15.jpg" alt="" width="580" height="201" /></a></p>
<p>In this project I used all the MCP23008 I/O ports expander to display the LED pattern retrieved from the 24LC02B EEPROM. These following C codes show of how to initialize the MCP23008 I/O ports as an output ports.</p>
<pre>// Initial the MCP23008 8-bit I2C I/O Expander
Write_MCP23008(IODIR,0b00000000);
Write_MCP23008(GPIO,0x00); // Reset all the Output Port</pre>
<p>The complete MCP23008 write operation is implemented in <strong>Write_MCP23008()</strong> function. For more information on how to operate the Microchip MCP23008 please refers to the MCP23008 datasheet.</p>
<p><strong>The Philips PCA8574 I<sup>2</sup>C 8-bits I/O Expander</strong></p>
<p>Comparing to the Microchip MCP23008, the Philips PCA8574 is more simple to operate all you need is to directly write or read to or from the PCA857A I/O register ports. Similar to the MCP23008 I/O expander, the PCA8574 I/O expander has 3-bit configurable address (000 to 111) which provides up to 7 devices that could be attached simultaneously on the same I2C bus. In this project the Philips PCA8574 8-bits I/O expander is used to control the Hitachi HD44780U (or its compatible) 2&#215;16 LCD. The complete I<sup>2</sup>C 2&#215;16 LCD schematic is shown on this following picture.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_16.jpg"><img class="alignnone size-full wp-image-2184" title="pic18I2C_16" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_16.jpg" alt="" width="575" height="395" /></a></p>
<p>In this project I used the 4-bit modes of Hitachi 44780U 2&#215;16 LCD driver to send the data from the PCA8574 I/O expander. You could read the complete explanation of how to drive the Hitachi 44780U 2&#215;16 LCD on this following article <a title="AVR LCD Thermometer Using ADC and PWM Project" href="http://www.ermicro.com/blog/?p=519" target="_blank">AVR LCD Thermometer Using ADC and PWM Project</a>.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_17.jpg"><img class="alignnone size-full wp-image-2185" title="pic18I2C_17" src="http://www.ermicro.com/blog/wp-content/uploads/2011/12/pic18I2C_17.jpg" alt="" width="575" height="338" /></a></p>
<p>The complete PCA8574 write operation is implemented in <strong>Write_PCA8574()</strong> function. For more information on how to operate the Philips PCA8574 please refers to the PCA8574 datasheet.</p>
<p><strong>Inside the Infinite Loop</strong></p>
<p>The program begins with the port initialization and continues with the PIC18F14K22 MSSP and the PIC18F14K22 ADC peripheral configuration. The internal ADC peripheral is used to provide the Microchip TC1321 I<sup>2</sup>C DAC with the required 10-bit digital input where the ADC value is taken from the 10K user trimpot connected to the <strong>AN0</strong> port. The following is the C code to initialize the PIC18F14K22 ADC peripheral:</p>
<pre>// Init the PIC18F14K22 ADC Peripheral
ADCON0=0b00000001; // ADC port Channel 0 (AN0), Enable ADC
ADCON1=0b00000000; // Use Internal Voltage Reference (Vdd and Vss)
ADCON2=0b10101011; // Right justify result, 12 TAD, Select the FRC for 16 MHz</pre>
<p>We use the “<em>right justify</em>” ADC result setting to get the 10-bit result and store it on the <strong>adc_value</strong> variable inside the infinite loop as shown on this following C code:</p>
<pre>// Read the PIC18K14K22 10-Bit AN0 ADC Input
ADCON0bits.GO_nDONE=1;
while (ADCON0bits.GO_nDONE) continue; // Wait conversion done
adc_value=ADRESL; // Get the 8 bit LSB result
adc_value += (ADRESH &lt;&lt; 8); // Get the 2 bit MSB result</pre>
<p>The ADC result (<strong>adc_value</strong>) is used as the input to Microchip TC1321 I<sup>2</sup>C DAC as shown in this following C code:</p>
<pre>// Write to the TC1321 10-Bit DAC
Write_TC1321(adc_value);</pre>
<p>You could read more information about using the Microchip PIC ADC peripheral on these following articles <a title="PIC Analog to Digital Converter C Programming " href="http://www.ermicro.com/blog/?p=660" target="_blank">PIC Analog to Digital Converter C Programming</a> and <a title="PIC18 Microcontroller Analog to Digital Converter with Microchip C18 Compiler" href="http://www.ermicro.com/blog/?p=1408" target="_blank">PIC18 Microcontroller Analog to Digital Converter with Microchip C18 Compiler</a></p>
<p>After initializing the PIC18F14K22 ADC peripheral, the program continue initializing the PCA8574 I<sup>2</sup>C 2&#215;16 LCD, Microchip 24LC02B 2KB I<sup>2</sup>C EEPROM, Microchip MCP23008 8-bit I<sup>2</sup>C I/O Expander, Microchip MCP9801 I<sup>2</sup>C Temperature Sensor, and Microchip TC1321 I<sup>2</sup>C DAC consecutively. Next the program enters the infinite loop and performs reading and writing to all of these I<sup>2</sup>C devices.</p>
<p>Now you could watch and enjoy the entire project presented here on this following video, where you could watch how we use the Microchip PIC18F14K22 MSSP I<sup>2</sup>C master to control various I<sup>2</sup>C slave device simultaneously.</p>
<p><object width="480" height="360" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/inBmGRQPt6U?version=3&amp;hl=en_US" /><param name="allowfullscreen" value="true" /><embed width="480" height="360" type="application/x-shockwave-flash" src="http://www.youtube.com/v/inBmGRQPt6U?version=3&amp;hl=en_US" allowFullScreen="true" allowscriptaccess="always" allowfullscreen="true" /></object></p>
<p><strong>The Final Though</strong></p>
<p>The I<sup>2</sup>C nowadays is become a popular choice of the embedded system interface because of its main advantages of using 2 wire bus interface. On this tutorial you’ve learned to utilize the Microchip PIC18F14K22 microcontroller MSSP in I<sup>2</sup>C master mode to control various I<sup>2</sup>C devices simultaneously. Hopefully what you’ve learned here could extend your knowledge of how to use various I<sup>2</sup>C slave devices out there in your next embedded system project.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ermicro.com/blog/?feed=rss2&amp;p=2157</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Line Follower Robot with Texas Instruments 16-Bit MSP430G2231 Microcontroller</title>
		<link>http://www.ermicro.com/blog/?p=2104</link>
		<comments>http://www.ermicro.com/blog/?p=2104#comments</comments>
		<pubDate>Sat, 10 Sep 2011 18:41:02 +0000</pubDate>
		<dc:creator>rwb</dc:creator>
				<category><![CDATA[Robotics]]></category>
		<category><![CDATA[ADC]]></category>
		<category><![CDATA[LDR]]></category>
		<category><![CDATA[LFR]]></category>
		<category><![CDATA[MSP430G2231]]></category>
		<category><![CDATA[Texas Instruments]]></category>

		<guid isPermaLink="false">http://www.ermicro.com/blog/?p=2104</guid>
		<description><![CDATA[When Texas Instruments (TI) introduced their new value line 16-bit microcontroller complete with the programmer and development board named MSP430 Value Line LaunchPad in the mid of 2010 for only USD 4.30 include the shipping cost, this make it as the cheapest programmer and development board platform that you could ever find in the market. [...]]]></description>
				<content:encoded><![CDATA[<p>When Texas Instruments (TI) introduced their new value line 16-bit microcontroller complete with the programmer and development board named MSP430 Value Line LaunchPad in the mid of 2010 for only USD 4.30 include the shipping cost, this make it as the cheapest programmer and development board platform that you could ever find in the market. Therefore the introduction of the MSP430 value line LaunchPad development board make a tremendous impact especially among the electronics hobbyist, students, and enthusiast because now the big boy (TI) is seriously taking part in the electronic hobbyist market and directly compete their 16-bit class value line microcontrollers to the 8-bit class microcontrollers which are mostly dominated by Atmel and Microchip.<span id="more-2104"></span></p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_02.jpg"><img class="alignnone size-full wp-image-2105" title="msp430_lfr_02" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_02.jpg" alt="" width="583" height="454" /></a></p>
<p>The MSP430 Value Line LaunchPad development board is come with the eclipse based Texas Instruments integrated development environment (IDE) called Code Composer Studio (downloadable from the TI website) and equiped with the professional grade C compiler and debugger, which make the development of MSP430 microcontroller based embedded system become easy and fun.</p>
<p>As you know most of the electronics hobbyist used the popular 8-bit class microcontroller to most of their embedded project such as AVR microcontroller from Atmel and PIC microcontroller from Microchip. Now you might wonder why we have to learn another type of microcontroller as most of the modern microcontroller has already provided all the necessary features that we need. Why not, learning another type of microcontroller is one of the fascinating and challenging topics to be learned especially for the true electronics hobbyist as this will broaden our knowledge and utilize what is the best on each of the microcontroller types to support our future embedded system project.</p>
<p><strong>The MSP430 Microcontroller Project</strong></p>
<p>After many considerations of what is the attractive way to introduce this MSP430 microcontroller, instead of just started with a common blinking LED, I decided to built a simple and yet most popular robot,&#8230;yes,&#8230;is another Line Follower Robot (LFR) using the Texas Instruments 14 pins 16-bit MSP430G2231 microcontroller that come with the MSP430 Value Line LaunchPad development board. Because I think building a robot will give you the basic knowledge and understanding you needs to start explores many of the advance features offered by this 16-bit MSP430 value lines microcontrollers by yourself.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_00.jpg"><img class="alignnone size-full wp-image-2107" title="msp430_lfr_00" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_00.jpg" alt="" width="586" height="437" /></a></p>
<p>If you notice on the above picture this Line Follower Robot (LFR) used a similar CD chassis, DC geared motor, and sensors found on my previous articles &#8220;<a title="The LM324 Quad Op-Amp Line Follower Robot with Pulse Width Modulation" href="http://www.ermicro.com/blog/?p=1908" target="_blank">The LM324 Quad Op-Amp Line Follower Robot with Pulse Width Modulation</a>&#8220;. Therefore this project also serves as a good example of the &#8220;digital&#8221; version of the analog LFR we&#8217;ve built before.</p>
<p>The following is the complete electronic schematic of the Line Follower Robot:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_01.jpg"><img class="alignnone size-full wp-image-2108" title="msp430_lfr_01" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_01.jpg" alt="" width="577" height="396" /></a></p>
<p>Now let list down all the necessary electronic components and other supported materials to build this LFR:</p>
<p>1. Resistors: 220 (2), 470 (1), 10K (3), 22K (2), and 47K (1)<br />
2. Light Dependent Resistor (2)<br />
3. Capacitors: 0.1uF (3), 1uF (1) and 47uF/16v (1)<br />
4. Diodes: 1N4148 (2)<br />
5. High Intensity 3 mm blue Light Emitting Diode (3)<br />
6. N-Channel MOSFET: BS170 (3)<br />
7. IC: ACS 1722A 3.3 volt voltage regulator or equivalent<br />
8. Texas Instruments MSP430 Value Line LaunchPad Development Board<br />
9. DC Motor: Solarbotics GM2 Geared DC motor with Wheel (2)<br />
10. One reset push button switch<br />
11. Perforated PCB: 70 x 55 mm for the main board and 50 x 15 mm for the sensors board<br />
12. 4 x AA Battery holder<br />
13. CD/DVD ROM (2)<br />
14. Plastic Beads and Paper Clip for the castor (the third wheel)<br />
15. Bolt, Nuts, Double Tape and Standard Electrical Tape for the black line<br />
16. Texas Instruments Code Composer Studio Core Edition version 4.2.1.00004 (used in this project)<br />
17. Texas Instruments MSP430G2231 microcontroller datasheet SLAS694 and SLAU144F.</p>
<p>The complete firmware for this Line Follower Robot project is developed with the C language:</p>
<pre>/*****************************************************************************
//  File Name    : LineFollower.c
//  Version      : 1.0
//  Description  : The MSP430G2231 Line Follower Robot
//  Author       : RWB
//  Target       : MSP430G2231 Custom Line Follower Board
//  Compiler     : Code Composer Studio Version: 4.2.1.00004
//  IDE          : Code Composer Studio Version: 4.2.1.00004
//  Programmer   : Texas Instruments MSP430 Launchpad Board
//  Last Updated : 16 Aug 2011
*****************************************************************************/
#include &lt;msp430g2231.h&gt;</pre>
<pre>#define LEFT_MOTOR BIT0
#define RIGHT_MOTOR BIT6
#define LEFT_LDR BIT4
#define RIGHT_LDR BIT5
#define SENSOR_LED BIT7</pre>
<pre>#define MAX_COUNT 100</pre>
<pre>// Sensor Calibration
#define CAL_SAMPLES 5
#define CAL_SPEED1 75
#define CAL_SPEED2 40
#define CAL_MOVE_DELAY 320</pre>
<pre>// PWM Duty Cycle Threshold
#define MAX_THRESHOLD 75
#define MIN_THRESHOLD 60</pre>
<pre>// Sensor Status
#define LEFT_SENSOR 0
#define RIGHT_SENSOR 1</pre>
<pre>unsigned int pwm_count=0;
unsigned int pwm_m1=0;
unsigned int pwm_m2=0;
unsigned int min_leftLDR=0;
unsigned int max_leftLDR=0;
unsigned int min_rightLDR=0;
unsigned int max_rightLDR=0;</pre>
<pre>unsigned int adc2cycle(unsigned int adc, unsigned int in_min, unsigned int in_max)
{
  unsigned int adc_val;

  // Calculate the result and put it within 0 to 100% PWM Duty Cycle value
  adc_val = 100 - ((adc - in_min) * 100 / (in_max - in_min));
  if (adc_val &lt;= MIN_THRESHOLD)
     adc_val=0;
  if (adc_val &gt;= MAX_THRESHOLD)
     adc_val=MAX_THRESHOLD;
  return(adc_val);
}</pre>
<pre>void DelayMs(unsigned int ms)
{
  while(ms--) {
    __delay_cycles(1000);     // 1 ms delay for 1 MHz Internal Clock
  }
}</pre>
<pre>// TimerA Channel 0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
  // The PWM Period is about: 101 x 0.1 ms = 10.1 ms
  pwm_count++;
  if (pwm_count &gt;= MAX_COUNT) {
    pwm_count=0;
    P1OUT |= LEFT_MOTOR;      // Turn On Left Motor
    P1OUT |= RIGHT_MOTOR;     // Turn On Right Motor
  }</pre>
<pre>  if (pwm_count == pwm_m1) {
    P1OUT &amp;= ~LEFT_MOTOR;     // Turn Off Left Motor
  }    

  if (pwm_count == pwm_m2) {
    P1OUT &amp;= ~RIGHT_MOTOR;    // Turn Off Right Motor
  }
}</pre>
<pre>unsigned int ReadSensor(unsigned char chn_stat)
{
  ADC10CTL0 &amp;= ~ENC;	            // Disable ADC10
  if (chn_stat) {
  	ADC10CTL1 &amp;= ~INCH_4;  	        // Deselect ADC Channel 4
    ADC10CTL1 |= INCH_5;            // Select ADC Channel 5 (A5), Right LDR
  } else {
  	ADC10CTL1 &amp;= ~INCH_5;           // Deselect ADC Channel 5
    ADC10CTL1 = INCH_4;             // Select ADC Channel 4 (A4), Left LDR
  }
  ADC10CTL0 |= ENC + ADC10SC;       // Enable ADC10 and Conversion start
  while (ADC10CTL1 &amp; ADC10BUSY);    // Wait for ADC Conversion
  return(ADC10MEM); 	            // Return ADC Value
}</pre>
<pre>void CalibrateSensor()
{
  unsigned char i;
  unsigned int tmp_left,tmp_right;   

  // Get the Maximum Value Sensor Value (over black line)
  P1OUT |= SENSOR_LED;                      // Turn On the Sensor LED
  DelayMs(1000);                            // Give enough time to light the LDR

  tmp_left=0;
  tmp_right=0;
  for(i=0; i &lt; CAL_SAMPLES; i++) {
    tmp_left += ReadSensor(LEFT_SENSOR);    // Read The Left LDR (A4)
    __delay_cycles(50);
    tmp_right += ReadSensor(RIGHT_SENSOR);  // Read The Right LDR (A5)
    __delay_cycles(50);
  }
  max_leftLDR = tmp_left / CAL_SAMPLES;     // Get the Max Left Average Value
  max_rightLDR = tmp_right / CAL_SAMPLES;   // Get the Max Right Average Value

  // Now move the robot to the next calibration stage
  pwm_m1=CAL_SPEED1;
  pwm_m2=CAL_SPEED2;
  DelayMs(CAL_MOVE_DELAY);  

  // Turn off the Motor (Duty Cycle 0)
  pwm_m1=0;
  pwm_m2=0;

  // Get the Minimum Value Sensor Value (over white line)
  tmp_left=0;
  tmp_right=0;
  for(i=0; i &lt; CAL_SAMPLES; i++) {
    tmp_left += ReadSensor(LEFT_SENSOR);    // Read The Left LDR (A4)
    __delay_cycles(50);
    tmp_right += ReadSensor(RIGHT_SENSOR);  // Read The Right LDR (A5)
    __delay_cycles(50);
  }
  min_leftLDR = tmp_left / CAL_SAMPLES;     // Get the Min Left Average Value
  min_rightLDR = tmp_right / CAL_SAMPLES;   // Get the Min Right Average Value  

  // Blink the Sensor LED after calibrating
  for(i=0; i &lt; CAL_SAMPLES; i++) {
    P1OUT &amp;= ~SENSOR_LED;                   // Turn Off LED
    DelayMs(500);
    P1OUT |= SENSOR_LED;                    // Turn On LED
    DelayMs(30);
  }
}</pre>
<pre>void main(void)
{
  unsigned int sensor_val;

  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

  // P1.0,P1.6 and P1.7 output, Other as Input
  P1DIR = LEFT_MOTOR + RIGHT_MOTOR + SENSOR_LED;</pre>
<pre>  // Enable the pull-down resistor on the unused input ports
  P1REN = BIT1 + BIT2 + BIT3;
  P2REN = BIT6 + BIT7;</pre>
<pre>  // Reset all the Output
  P1OUT = 0x00;

  // TIMER A channel 0 will interrupt every 100 cycles
  // Interrupt time counter period: 100 / 1.000.000 = 0.1 ms
  TACCTL0 = CCIE;                           // CCR0 interrupt enabled
  TACCR0 = 99;
  TACTL = TASSEL_2 + MC_1;                  // Start Timer, SMCLK, Up Mode

  // Start the ADC10 Peripheral
  // Vref = Vcc, 16 ADC Clock, Enable ADC10
  ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON;  

  // Sample-and-hold ADC10SC bit, ADC10 Clock /1, ADC10 Source Clock, Single Channel Conversion
  ADC10CTL1 = SHS_0 + ADC10DIV_0 + ADC10SSEL_0 + CONSEQ_0;
  ADC10AE0 = LEFT_LDR + RIGHT_LDR;          // Enable A4 and A5 as ADC Input
  DelayMs(1);                               // Wait for ADC Ref to settle

  // Initial the PWM Duty Cycle and Enable the MSP430 Interrupts
  pwm_count=0;
  pwm_m1=0;
  pwm_m2=0;
  __enable_interrupt();          

  // Now we Calibrate the LDR Sensors
  CalibrateSensor();
  DelayMs(1000);                            // Delay 1000 ms before start

  // Loop Forever
  for(;;) {
  	// Read the Left LDR Sensor and make sure is within the range
  	sensor_val=ReadSensor(LEFT_SENSOR);
  	if (sensor_val &gt; max_leftLDR)
  	  sensor_val=max_leftLDR;
  	if (sensor_val &lt; min_leftLDR)
  	  sensor_val=min_leftLDR;

  	// Assigned the Left PWM Duty Cycle
  	pwm_m1=adc2cycle(sensor_val,min_leftLDR,max_leftLDR);
  	__delay_cycles(20);   

  	// Read the Right LDR Sensor and make sure is within the range
  	sensor_val=ReadSensor(RIGHT_SENSOR);
  	if (sensor_val &gt; max_rightLDR)
  	  sensor_val=max_rightLDR;
  	if (sensor_val &lt; min_rightLDR)
  	  sensor_val=min_rightLDR;

  	// Assigned the Right PWM Duty Cycle
  	pwm_m2=adc2cycle(sensor_val,min_rightLDR,max_rightLDR);
  	__delay_cycles(20);
  }
}</pre>
<pre>/* EOF: LineFollower.c */</pre>
<p><strong>The Line Follower Robot Working Principle</strong></p>
<p>This Line Follower Robot design used the photocell sensor known as a Light Dependent Resistor (LDR) made from Cadmium Sulphide (CdS) to detect the black track line, when the LDR is above the black track line it will give a high resistance value while above the white background and it will give a low resistance value. Together with the 22K resistor, they will form what&#8217;s known as the voltage divider circuit. This voltage divider circuit sensor will provide the varying voltage according to the amount of the light intensity reflected back to the LDR. The blue Light Emitting Diode (LED) will provide a constant light source for the sensors.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_03.jpg"><img class="alignnone size-full wp-image-2109" title="msp430_lfr_03" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_03.jpg" alt="" width="583" height="272" /></a></p>
<p>Next the MSP430G2231 microconttroller will translate this varying voltage using its analog to digital conversion (ADC) peripheral into the DC motor rotation speed using what known as the Pulse Width Modulation (PWM) signal. Because this LFR used the &#8220;<em>differential steering</em>&#8221; (i.e. used two independent DC motor for steering) method, therefore by varying the left and the right DC motor rotation speed proportionally to the light intensity received by both of the left and right LDR, we could easily make the robot to navigate the black track line successfully.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_04.jpg"><img class="alignnone size-full wp-image-2111" title="msp430_lfr_04" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_04.jpg" alt="" width="588" height="420" /></a><br />
<strong></strong></p>
<p><strong>The MSP430G2231 Microcontroller</strong></p>
<p>The Mixed Signal Processing (MSP) 430 series microcontroller is first introduced in the late of 1990 by Texas Instruments. It&#8217;s a 16-bit RISC (reduced instruction set computer) microcontroller with Von Neumann architecture where the CPU, I/O, and memory shared the same 16-bit control, address, and data bus. The MSP430 is specially design for low consumption and optimize to be used with the C compiler.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_05.jpg"><img class="alignnone size-full wp-image-2112" title="msp430_lfr_05" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_05.jpg" alt="" width="584" height="158" /></a></p>
<p>The &#8220;G&#8221; value line series such as the 14-pin MSP430G2231 microcontroller is introduced together with the price phenomenal LaunchPad development board. This microcontroller has these following interesting features which I&#8217;m sure as the electronics hobbyist you will eager to try it by yourself.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_06.jpg"><img class="alignnone size-full wp-image-2113" title="msp430_lfr_06" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_06.jpg" alt="" width="585" height="252" /></a></p>
<p>One of the features that make this 14-pin MSP430G2231 microcontroller special is the build in on-chip emulation logic using what is called &#8220;<em>Spy-Bi-Wire</em>&#8221; or also known as 2-wire JTAG (Joint Test Action Group). This useful feature enables us to step the C code line by line, set a break point, and check the variables or registers value while the chip is in the circuit (in circuit programming and debugging).</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_09.jpg"><img class="alignnone size-full wp-image-2114" title="msp430_lfr_09" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_09.jpg" alt="" width="578" height="451" /></a><br />
<strong></strong></p>
<p><strong>The MSP430G2231 Microcontroller Input/Output (I/O)</strong></p>
<p>The MSP430G2231 microcontroller has 10 I/O, 8 pins on the first ports (P1) and 2 pins on the second ports (P2). All these ports are configurable as the general purpose input or output ports and often they multiplexed with other I/O function such as A/D (analog to digital) input, PWM out, USI (Universal Serial Interface), Clock Input, Crystal Oscillator Input, and JTAG I/O terminal.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_07.jpg"><img class="alignnone size-full wp-image-2116" title="msp430_lfr_07" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_07.jpg" alt="" width="584" height="403" /></a></p>
<p>As you&#8217;ve seen from the table above, the LFR only used several I/O ports and as rules of thumb the unused I/O ports have to be configured as the output ports and leave them unconnected. Alternatively you could configure all the unused ports as the input ports (default on power-up reset) and enable the pull-down resistor in order to avoid the unpredictable &#8220;<em>floating</em>&#8221; inputs problem arise in your project. The following C code shows how to configure the necessary I/O ports for this LFR:</p>
<pre>#define LEFT_MOTOR BIT0
#define RIGHT_MOTOR BIT6
#define LEFT_LDR BIT4
#define RIGHT_LDR BIT5
#define SENSOR_LED BIT7
...</pre>
<pre>// P1.0,P1.6 and P1.7 output, Other as Input
P1DIR = LEFT_MOTOR + RIGHT_MOTOR + SENSOR_LED;</pre>
<pre>// Enable the pull-down resistor on the unused input ports
P1REN = BIT1 + BIT2 + BIT3;
P2REN = BIT6 + BIT7;</pre>
<pre>// Reset the Output
P1OUT = 0x00;</pre>
<p>The <strong>P1DIR</strong> (port 1 direction) register is used to configure the I/O port direction, where each bit of this 16-bit corresponding to the I/O ports (<strong>P1.0</strong> to <strong>P1.7</strong>). By enabling the corresponding bit we simply tell the MSP430G2231 microcontroller to configure the port as an output port. Next the <strong>P1REN</strong> (port 1 pull-up/pull-down resistor) register, by enabling the corresponding bit we could enable the pull-down resistor (configured as input) or pull-up resistor (configured as output).</p>
<p>The MSP430G2231 microcontroller <strong>P1OUT</strong> (port 1 output) register is used to control the output port logical state, it used to turn on and off the <strong>P1.0</strong> and <strong>P1.6</strong> to generate the required PWM signal. I used these ports because these ports are connected with two LED in the MSP430 LaunchPad development board, therefore you could easily test the PWM output using these LEDs. The <strong>P1.7</strong> output port is also used to control the sensor LED; beside as the sensor light source, it also serves as a sign indicator when the LFR finish calibrating the sensors. The following code use C language bit operator to turn on and off the port using the MSP430G2231 microcontroller <strong>P1OUT</strong> register:</p>
<pre>// Reset all the Output
P1OUT = 0x00;
...
...
P1OUT |= LEFT_MOTOR;      // Turn On Left Motor
P1OUT |= RIGHT_MOTOR;     // Turn On Right Motor
...
...
P1OUT &amp;= ~LEFT_MOTOR;     // Turn Off Left Motor
...
...
P1OUT &amp;= ~RIGHT_MOTOR;    // Turn Off Right Motor
...
...
P1OUT &amp;= ~SENSOR_LED;     // Turn Off LED
...
P1OUT |= SENSOR_LED;      // Turn On LED
...
...</pre>
<p>From the data sheet the maximum output current for each port is about 6 mA and for all outputs combined is about 48 mA, this of course is not suitable for driving the DC motor directly; therefore in this project I used the n-channel MOSFET (Metal Oxide Semiconductor Field Effect Transistor) BS170 to drive the DC motor and sensor LED. The advantage of using MOSFET because this type of transistor has very high input impedance on its Gate (G) terminal which mean its need very low current in order to operate and its has a low ON resistance between the its Drain (D) and Source (S) terminals called Rds especially when operate on higher DC voltage supply compare to the ordinary Bipolar Junction Transistor (BJT).</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_08.jpg"><img class="alignnone size-full wp-image-2117" title="msp430_lfr_08" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_08.jpg" alt="" width="585" height="406" /></a></p>
<p>By applying voltage greater than the Vgs threshold voltage i.e. voltage applied between the Gate and Source terminal, it&#8217;s about 2 volt on the BS170 MOSFET, we could bring the MOSFET into its saturate stage (ON) and this voltage level could be easily provided by the MSP430G2231 microcontroller output port.</p>
<p><strong>The MSP430G2231 Pulse Width Modulation</strong></p>
<p>Pulse Width Modulation (PWM) is a technique widely used in modern switching circuit to control the amount of power given to the electrical device (i.e. the DC motor). By simply switches ON and OFF the power supplied to the DC motor rapidly and the average amount of energy received by the DC motor is corresponding to the ON and OFF period (duty cycle); therefore by varying the ON period i.e. longer or shorter than the OFF period, we could control the DC motor rotation speed.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_10.jpg"><img class="alignnone size-full wp-image-2118" title="msp430_lfr_10" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_10.jpg" alt="" width="580" height="453" /></a></p>
<p>The MSP430G2231 microcontroller actually has two capture/compare registers that could be used for generating the PWM automatically, but because we need two independent PWM sources with the configurable PWM duty cycle and on the specific PWM frequency, therefore we could not use the built in PWM which is provided by the MSP4302231 microcontroller. Instead on this LFR project I used the software PWM which is based on the MSP430G2231 Timer_A channel 0 interrupt.</p>
<p>The basic software PWM could be made by first creating the basic digital ramp counter for the PWM signal period and then use the variable to be compared with the ramp counter value and this will create the necessary PWM duty cycle as shown on this following diagram:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_11.jpg"><img class="alignnone size-full wp-image-2119" title="msp430_lfr_11" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_11.jpg" alt="" width="579" height="404" /></a></p>
<p>The basic digital ramp counter used the <strong>pwm_count</strong> variable to count from 0 to <strong>MAX_COUNT</strong> and start to count from 0 again repeatedly. The <strong>pwm_count</strong> will provide a constant period to the PWM signal. Next we need two variables <strong>pwm_m1</strong> and <strong>pwm_m2</strong> to be compared with the <strong>pwm_count</strong> variable. When the <strong>pwm_count</strong> reach 0, we simply turn ON the MSP430G2231 microcontroller output port and when the <strong>pwm_count</strong> equal to the <strong>pwm_m1</strong> or <strong>pwm_m2</strong> value, we simply turn OFF the MSP430G2231 microcontroller output port. Therefore by varying both of the <strong>pwm_m1</strong> or <strong>pwm_m2</strong> variables value we could control the PWM signal duty cycle.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_12.jpg"><img class="alignnone size-full wp-image-2121" title="msp430_lfr_12" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_12.jpg" alt="" width="589" height="320" /></a></p>
<p>We used the MSP430G2231 microcontroller Timer_A in &#8220;<em>Up Mode</em>&#8221; to actually increase and control the <strong>pwm_count</strong> value and when the Timer_A counter register (<strong>TAR</strong>) equal to Timer A Capture/Control Register channel 0 (<strong>TACCR0</strong>) it will generate the interrupt. Because on this project I used MSP430G2231 microcontroller standard Sub Main Clock (<strong>SMCLK</strong>) of 1 MHz for the Timer_A clock source, thus assigning 99 to the <strong>TACCR0</strong> register will make the Timer_A channel 0 to generate interrupt on every 100 (<strong>TACCR0 + 1</strong>) cycles or about 0.1 ms as shown on this following C code:</p>
<pre>// TIMER A channel 0 will interrupt every 100 cycles
// Interrupt time counter period: 100 / 1.000.000 = 0.1 ms
TACCTL0 = CCIE;                           // CCR0 interrupt enabled
TACCR0 = 99;
TACTL = TASSEL_2 + MC_1;                  // Start Timer, SMCLK, Up Mode</pre>
<p>The software PWM implementation is implemented inside the Timer_A channel 0 interrupt function handler as show on this following C code:</p>
<pre>// TimerA Channel 0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
  // The PWM Period is about: 101 x 0.1 ms = 10.1 ms
  pwm_count++;
  if (pwm_count &gt;= MAX_COUNT) {
    pwm_count=0;
    P1OUT |= LEFT_MOTOR;      // Turn On Left Motor
    P1OUT |= RIGHT_MOTOR;     // Turn On Right Motor
  }</pre>
<pre>  if (pwm_count == pwm_m1) {
    P1OUT &amp;= ~LEFT_MOTOR;     // Turn Off Left Motor
  }    

  if (pwm_count == pwm_m2) {
    P1OUT &amp;= ~RIGHT_MOTOR;    // Turn Off Right Motor
  }
}</pre>
<p>By choosing <strong>MAX_COUNT</strong> of 100, we could get the PWM period about 101 x 0.1ms, which is about 10.1 ms or we could say that the PWM frequency is about 100 Hz and by assigning each of the <strong>pwm_m1</strong> and <strong>pwm_m2</strong> variables value from 0 to 100, we could get the PWM duty cycle output varying from 0 to 100%.</p>
<p>The <strong>pwm_m1</strong> and <strong>pwm_m2</strong> variables value is supplied by the digital value from the left and the right sensors from the <strong>adc2cycle()</strong> function which basically set the upper and lower PWM duty cycle value returned to these variables. The upper and lower threshold setting is depend on the black line track and the sensors characteristic and could be changed by changing each of the <strong>MAX_THRESHOLD</strong> and the <strong>MIN_THRESHOLD</strong> definition value.<br />
<strong></strong></p>
<p><strong>The MSP430G2231 ADC Peripheral</strong></p>
<p>The MSP430G2231 microcontroller has one 10-bit Analog to Digital Conversion (ADC) peripheral also known as ADC10 peripheral with 8 channel (A0 to A7), where the channel (A10) is specially used for the internal thermometer. The MSP430G2231 ADC10 peripheral used what is called &#8220;<em>Successive Approximation Method</em>&#8221; to convert the analog input from one of these channels to the 10-bit digital representation and stores the result in the <strong>ADC10MEM</strong> register.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_13.jpg"><img class="alignnone size-full wp-image-2122" title="msp430_lfr_13" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_13.jpg" alt="" width="584" height="395" /></a></p>
<p>The ADC10 peripheral is controlled by two control registers, <strong>ADC10CTL0</strong> and <strong>ADC10CTL1</strong>. Thus by setting the <strong>ADC10ON</strong> bit (logical high) in <strong>ADC10CTL0</strong> register we enable this ADC core. The most important thing to remember that these ADC10 control registers can only be modified when <strong>ENC</strong> (Enable Conversion) bit in <strong>ADC10CTL0</strong> is low (<strong>ENC = 0</strong>) and prior to the A/D conversion this bit has to be set to 1 (logical high).</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_14.jpg"><img class="alignnone size-full wp-image-2123" title="msp430_lfr_14" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_14.jpg" alt="" width="583" height="384" /></a></p>
<p>The MSP430G2231 ADC10 peripheral have four operating mode which could be selected by setting the <strong>CONSEQx</strong> bits in the <strong>ADC10CTL1</strong> (ADC10 Control Register 1) and on this LFR project we will use the &#8220;<em>Single Channel Single Conversion Mode</em>&#8220;. The following C code show how we setup the MSP430G2231 microcontroller ADC10 peripheral:</p>
<pre>// Start the ADC10 Peripheral
// Vref = Vcc, 16 ADC Clock, Enable ADC10
ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON;  

// Sample-and-hold ADC10SC bit, ADC10 Clock /1, ADC10 Source Clock, Single Channel Conversion
ADC10CTL1 = SHS_0 + ADC10DIV_0 + ADC10SSEL_0 + CONSEQ_0;
ADC10AE0 = LEFT_LDR + RIGHT_LDR;          // Enable A4 and A5 as ADC Input
DelayMs(1);                               // Wait for ADC Ref to settle</pre>
<p>The multiplexer analog channels input could be selected by assigning the corresponding <strong>INCHx </strong>bits in the <strong>ADC10CTL1</strong> register. The actual A/D conversion is take placed in the <strong>ReadSensor()</strong> function, as shown on this following C code:</p>
<pre>unsigned int ReadSensor(unsigned char chn_stat)
{
  ADC10CTL0 &amp;= ~ENC;	             // Disable ADC10
  if (chn_stat) {
    ADC10CTL1 &amp;= ~INCH_4;  	     // Deselect ADC Channel 4
    ADC10CTL1 |= INCH_5;            // Select ADC Channel 5 (A5), Right LDR
  } else {
  	ADC10CTL1 &amp;= ~INCH_5;           // Deselect ADC Channel 5
    ADC10CTL1 = INCH_4;             // Select ADC Channel 4 (A4), Left LDR
  }
  ADC10CTL0 |= ENC + ADC10SC;       // Enable ADC10 and Conversion start
  while (ADC10CTL1 &amp; ADC10BUSY);    // Wait for ADC Conversion
  return(ADC10MEM); 	              // Return ADC Value
}</pre>
<p>Noticed on the C code above that before we change the ADC10 control register (i.e. <strong>ADC10CTL0</strong> and <strong>ADC10CTL1</strong>), we have to disable the ADC10 first be resetting the <strong>ENC</strong> bit on <strong>ADC10CTL0</strong> register then prior to the A/D conversion we set (enable) the <strong>ENC</strong> and <strong>ADC10SC</strong> (ADC10 Start Conversion) bits in <strong>ADC10CTL0</strong> register. Next we wait the conversion by checking the <strong>ADC10BUSY</strong> bit on the <strong>ADC10CTL1</strong> register. When the <strong>ADC10BUSY</strong> bit is become &#8220;0&#8243; means the conversion is done and we could retrieve the stored 10-bit digital value in the <strong>ADC10MEM</strong> register.</p>
<p>One of the most important features on this LFR project is the used of the calibration phase in the <strong>CalibrateSensor()</strong> function. In the calibration phase we read the sensors for their maximum value (i.e. on the black line) and the minimum (i.e. on the white background) value. This calibration phase will ensure both of the left and right sensors provide equal value to the PWM generator for driving DC motor. The actual algorithm to make this LFR navigate the black track line successfully is shown on this following C code:</p>
<pre>// Loop Forever
for(;;) {
	// Read the Left LDR Sensor and make sure is within the range
  	sensor_val=ReadSensor(LEFT_SENSOR);
  	if (sensor_val &gt; max_leftLDR)
  	  sensor_val=max_leftLDR;
  	if (sensor_val &lt; min_leftLDR)
  	  sensor_val=min_leftLDR;

  	// Assigned the Left PWM Duty Cycle
  	pwm_m1=adc2cycle(sensor_val,min_leftLDR,max_leftLDR);
  	__delay_cycles(20);   

  	// Read the Right LDR Sensor and make sure is within the range
  	sensor_val=ReadSensor(RIGHT_SENSOR);
  	if (sensor_val &gt; max_rightLDR)
  	  sensor_val=max_rightLDR;
  	if (sensor_val &lt; min_rightLDR)
  	  sensor_val=min_rightLDR;

  	// Assigned the Right PWM Duty Cycle
  	pwm_m2=adc2cycle(sensor_val,min_rightLDR,max_rightLDR);
  	__delay_cycles(20);
}</pre>
<p><strong>The Line Follower Robot Assembly</strong></p>
<p>The Line Follower Robot first is constructed on the breadboard in order to test the circuit before I move it to the perforated PCB (70 x 55 mm); I used a similar wiring method to wire the circuit on the main LFR perforated PCB as explained on my previous article &#8220;<a title="Quick and Efficiently Wiring Your Prototype Circuit Board" href="http://www.ermicro.com/blog/?p=1940" target="_blank">Quick and Efficiently Wiring Your Prototype Circuit Board</a>&#8220;.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_15.jpg"><img class="alignnone size-full wp-image-2126" title="msp430_lfr_15" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_15.jpg" alt="" width="582" height="473" /></a></p>
<p>The Line Follower Robot construction could be constructed freely but the easiest one is to use the discarded CD/DVD ROM as shown on these following pictures:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_16.jpg"><img class="alignnone size-full wp-image-2127" title="msp430_lfr_16" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_16.jpg" alt="" width="584" height="469" /></a></p>
<p>I glued the two CDROM together in order to make more room and attached the two GM2 DC motors, 4xAA battery holder, main board, and sensor board using the double tape. The sensors (LDR and LED) are constructed in a small perforated PCB (50 x 15 mm) with this following guidance:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_17.jpg"><img class="alignnone size-full wp-image-2134" title="msp430_lfr_17" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_17.jpg" alt="" width="579" height="279" /></a></p>
<p>Finally using the Texas Instruments MSP430 Value Line LaunchPad development board Spy-Bi-Wire connector and the Texas Instruments Code Composer Studio Core Edition v4.2.1.00004 (used in this project), we could easily programming and debugging the LFR firmware:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_18.jpg"><img class="alignnone size-full wp-image-2129" title="msp430_lfr_18" src="http://www.ermicro.com/blog/wp-content/uploads/2011/09/msp430_lfr_18.jpg" alt="" width="585" height="387" /></a><br />
After putting all the parts together and downloading the code into the MSP430G2231 microcontroller flash RAM now is time to watch how this nice Line Follower Robot in action:</p>
<p><object width="480" height="390" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/GswMP3i62Q8?version=3&amp;hl=en_US&amp;rel=0" /><param name="allowfullscreen" value="true" /><embed width="480" height="390" type="application/x-shockwave-flash" src="http://www.youtube.com/v/GswMP3i62Q8?version=3&amp;hl=en_US&amp;rel=0" allowFullScreen="true" allowscriptaccess="always" allowfullscreen="true" /></object></p>
<p>Another interesting video of this MSP430G2231 based Line Follower Robot:</p>
<p><object width="480" height="360" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/1IMWSU_udCQ?version=3&amp;hl=en_US" /><param name="allowfullscreen" value="true" /><embed width="480" height="360" type="application/x-shockwave-flash" src="http://www.youtube.com/v/1IMWSU_udCQ?version=3&amp;hl=en_US" allowFullScreen="true" allowscriptaccess="always" allowfullscreen="true" /></object></p>
<p>&nbsp;</p>
<p><strong>The Final Thought</strong></p>
<p>As you&#8217;ve seen from the demo video above this Texas Instruments 16-bit MSP430G2231 microcontroller based Line Follower Robot design could handle and smoothly navigate the complex black track line using just two LDR sensors. I hope this Line Follower Robot project will trigger your passion to learn more about this powerful 16-bit MSP430 value line series microcontroller from Texas Instruments.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ermicro.com/blog/?feed=rss2&amp;p=2104</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>Make Your Own Arduino Shield Cradle</title>
		<link>http://www.ermicro.com/blog/?p=2056</link>
		<comments>http://www.ermicro.com/blog/?p=2056#comments</comments>
		<pubDate>Sun, 03 Jul 2011 05:15:56 +0000</pubDate>
		<dc:creator>rwb</dc:creator>
				<category><![CDATA[Microcontroller]]></category>
		<category><![CDATA[ARDUINO]]></category>
		<category><![CDATA[ethernet]]></category>
		<category><![CDATA[PIC16F1829]]></category>
		<category><![CDATA[SPI]]></category>
		<category><![CDATA[TCP/IP]]></category>
		<category><![CDATA[W5100]]></category>
		<category><![CDATA[wiznet]]></category>

		<guid isPermaLink="false">http://www.ermicro.com/blog/?p=2056</guid>
		<description><![CDATA[One of the advantages with the open source software and hardware such as Arduino (based on Atmel 8-bit AVR ATMega328 microcontroller) is the enormous &#8220;add-on&#8221; hardware called &#8220;Arduino Shield&#8221; that we could easily expand the Arduino main board and turn it into many cool and useful embedded system applications e.g. DC motor controller, web server, [...]]]></description>
				<content:encoded><![CDATA[<p>One of the advantages with the open source software and hardware such as Arduino (based on Atmel 8-bit AVR ATMega328 microcontroller) is the enormous &#8220;add-on&#8221; hardware called &#8220;Arduino Shield&#8221; that we could easily expand the Arduino main board and turn it into many cool and useful embedded system applications e.g. DC motor controller, web server, wireless application, GSM/GPRS modem and many more. The Arduino framework is so popular that many vendors come with their new Arduino shield module design almost every year.</p>
<p><span id="more-2056"></span>The enormous variety of the Arduino shield hardware in the market also trigger other vendor to take advantage of this condition and start to make their own &#8220;Arduino like&#8221; main board using other type of microcontroller such as Microchip PIC 8-bits PIC18F25K20 microcontroller (Amicus18), Atmel 32-bit ARM7 AT91SAM7X512 microcontroller (netduino), STMicroelectronics 32-bits ARM Cortex M3 STM32F103RB microcontroller (Leaf Maple), NXP 32-bits ARM7 LPC2387 microcontroller (FEZ Panda), etc.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_03.jpg"><img class="alignnone size-full wp-image-2057" title="arduino_shield_03" src="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_03.jpg" alt="" width="577" height="447" /></a></p>
<p>But unfortunately there is one &#8220;hick-up&#8221; on the Arduino main board design, at a glimpse you will think that this Arduino shield hardware will perfectly feed on the standard prototype board or breadboard,&#8230; hmmm&#8230; you could clearly see from this picture bellow that the digital I/O port&#8217;s gaps (<strong>J1</strong> and <strong>J3</strong> also called digital 1 and digital 2) in the Arduino main board is deliberately not designed for this purpose in mind. On the contrary the analog (<strong>J2</strong>) and <strong>POWER</strong> ports meets the standard gap width. This mean we could not use and plug any standard Arduino shield hardware directly into the prototype board.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_04.jpg"><img class="alignnone size-full wp-image-2058" title="arduino_shield_04" src="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_04.jpg" alt="" width="576" height="450" /></a></p>
<p>As good electronics hobbyists this &#8220;hick-up&#8221; will not prevent us to take advantage of this useful Arduino Shield stuff out there, therefore I used the Sparkfun Arduino ProtoShield board design and turn it into the Arduino Shield Cradle so we could use this Arduino shield with other development board as well. At the end of this tutorial I will present a simple Arduino Shield Cradle tester project using the standard Arduino EtherShield (with Wiznet W5100 chip) connected to PICJazz 20PIN board running Microchip PIC16F1829 microcontroller and run a simple ICMP (Internet Control Message Protocol) test over the Ethernet connection.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_02.jpg"><img class="alignnone size-full wp-image-2059" title="arduino_shield_02" src="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_02.jpg" alt="" width="579" height="450" /></a><br />
<strong></strong></p>
<p><strong>The Arduino Shield Cradle</strong></p>
<p>Instead of making our own Arduino Shield Cradle PCB design it is easier to make used of what is already available in the market, therefore I choose the Sparkfun Arduino ProtoShield Board v2.5 design and with just adding a few electronic parts we could have a nice Arduino Shield Cradle that could be used with any Arduino Shield hardware. This Arduino Shield Cradle also is equipped with a build-in 3.3 volt voltage regulator using Advanced Monolithic Systems AMS1117 low drop voltage regulator chip.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_01.jpg"><img class="alignnone size-full wp-image-2060" title="arduino_shield_01" src="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_01.jpg" alt="" width="580" height="331" /></a></p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_08.jpg"><img class="alignnone size-full wp-image-2061" title="arduino_shield_08" src="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_08.jpg" alt="" width="580" height="343" /></a></p>
<p>Now let&#8217;s list down all the necessary hardware and software needed to accomplished these projects:</p>
<p>1. One 330 Ohm Resistor<br />
2. Capacitor: 0.1uF (1) and 47uF/16v (1)<br />
3. Advanced Monolithic Systems AMS1117, 3.3 volt Low Drop Voltage Regulator<br />
4. One 3 mm blue LED<br />
5. One momentary reset push button<br />
6. One 2 Pin Polarized Connector for power supply<br />
7. Standard Arduino board female pin head connector (2 x 8-pin and 2 x 6-pin)<br />
8. Bended male extension pin head connector (2 x 8-pin and 2 x 6-pin)<br />
9. Sparkfun ProtoShield Board v2.5 design<br />
10. <a title="PICJazz 20PIN Learning and Development Board" href="http://www.ermicro.com/blog/?p=15" target="_blank">PICJazz 20-PIN</a> learning board from ermicro with Microchip 8-bit PIC16F1829 Microcontroller<br />
11. Arduino Ethernet Shield W5100<br />
12. Microchip PICKit3 programmer<br />
13. Microchip MPLAB IDE version 8.63 and Microchip HI-TECH C Compiler for the PIC10/12/16 MCU family version 9.80<br />
14. Reference Document: Microchip PIC16F1829 datasheet, Arduino Ethernet Shield W5100 datasheet, Wiznet W5100 datasheet, and Arduino Board datasheet.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_05.jpg"><img class="alignnone size-full wp-image-2062" title="arduino_shield_05" src="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_05.jpg" alt="" width="575" height="447" /></a></p>
<p>The following pictures show of how I constructed this Arduino Shield Cradle using the Sparkfun Arduino ProtoShield board design.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_06.jpg"><img class="alignnone size-full wp-image-2064" title="arduino_shield_06" src="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_06.jpg" alt="" width="585" height="256" /></a></p>
<p>As you could see from the Arduino Shield Cradle assembly above, you only need a view jumper to connect all the required electronic parts because I make used of the available PCB design connection. For example I placed the 47 uF capacitor on the S2 switch; 0.1uF capacitor on ICSP connector; I make used of the Arduino ProtoShield board LED2 with R2 (330 Ohm) as the AMS1117 3.3 volt indicator and the BlueSMiRF connector for the Arduino Shield Cradle board 5 volt power terminal. At the bottom you only need one jumper to connect the AMS1117 Vout (3.3 volt) to pin 2 on the Arduino ProtoShield board JP1 (Power Pin). The following picture show the complete Arduino Shield Cradle tested with the 5 Volt voltage regulators.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_07.jpg"><img class="alignnone size-full wp-image-2065" title="arduino_shield_07" src="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_07.jpg" alt="" width="575" height="447" /></a></p>
<p><strong>Testing the Arduino Shield Cradle</strong></p>
<p>Of course this project is not complete without testing our Arduino Shield Cradle, therefore to make it more interesting I used the Arduino Ethernet Shield W5100 as our target hardware shield to test this Arduino Shiled Cradle. This time I used one of the Microchip 20 pin 8-bit newest and powerful midrange PIC16F1829 microcontroller with PICJazz 20PIN development board.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_09.jpg"><img class="alignnone size-full wp-image-2066" title="arduino_shield_09" src="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_09.jpg" alt="" width="575" height="353" /></a></p>
<p>The Microchip PIC16F1829 microcontroller could be considered as the product that fills the gap between the PIC16F midrange and the PIC18F high-end series. It&#8217;s equipped with many peripherals that before only could be found on the PIC18F high-end series such as In-Circuit Debug (ICD) via Two Pins, Internal temperature Sensor, 5 Timers, Two Enhanced CCP (ECCP) Modules, Two Master Synchronous Serial Port (MSSP) with SPI (Serial Peripheral Interface) and I2C (read I square C), and mTouch Sensing Oscillator Module.</p>
<p>On this tutorial I will use the PIC16F1829 SPI peripheral to communicate with the Arduino Ethernet Shield W5100. Basically the Wiznet W5100 (used in standard Arduino Ethernet Shield) implements a full-featured of standard IEEE 802.3 (Ethernet physical and data link layer) and powerful TCP/IP stack inside the chip; this make the Wiznet W5100 chip is a nature choice for integrating the embedded system into the internet.</p>
<p>By initializing the Wiznet W5100 chip we will activate the build-in ICMP (Internet Control Message Protocol, documented in RFC 792) protocol server inside the chip, therefore we could easily test the W5100 chip by sending the &#8220;<strong>ping</strong>&#8221; command and receive &#8220;<strong>alive</strong>&#8221; response from it. The following is the complete C code for initializing the Arduino Ethernet Shield W5100:</p>
<pre>/* **********************************************************************************
**  File Name    : picping.c
**  Version      : 1.0
**  Description  : Wiznet 5100 Arduino Shield Cradle Demo
**  Author       : RWB
**  Target       : PICJazz 20PIN with Microchip PIC16F1829 Microcontroller
**  Compiler     : Microchip HI-TECH C Compiler for the PIC10/12/16 MCU family V9.80
**  IDE          : Microchip MPLAB IDE v8.63
**  Programmer   : Microchip PICKit3 Firmware Suite Version 01.26.43
**  Last Updated : 28 May 2011
** ***********************************************************************************/
#include &lt;pic.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;</pre>
<pre>/*   PIC16F1829 Configuration Bit:
**   CONFIG1 Address 0x8007
**
**   FOSC_INTOSC - Internal OSC, I/O function on CLKIN pin
**   WDTE_OFF    - Wacthdog Timer Disable
**   PWRTE_ON    - Power Up Timer Enable
**   MCLRE_ON    - Master Clear Enable
**   CP_OFF      - Program memory code protection is disabled
**   CPD_OFF     - Data memory code protection is enabled
**   BOREN_ON    - Brown-out Reset Enable
**   IESO_OFF    - Internal/External Switchover mode is disabled
**   FCMEN_OFF   - Fail-Safe Clock Monitor is disabled
*/
__CONFIG(FOSC_INTOSC &amp; WDTE_OFF &amp; PWRTE_ON &amp; MCLRE_ON &amp; CP_OFF &amp; CPD_OFF &amp; BOREN_ON &amp; IESO_OFF &amp; FCMEN_OFF);</pre>
<pre>/*   PIC16F1829 Configuration Bit:
**   CONFIG2 Address 0x8008
**
**   WRT_OFF     - Write protection off
**   PLLEN_OFF   - 4x PLL Disabled
**   STVREN_ON   - Stack Overflow or Underflow will cause a Reset
**   BORV_19     - Brown-out Reset Voltage (VBOR) set to 1.9 V
**   LVP_ON      - Low-voltage programming enabled
**
*/
__CONFIG(WRT_OFF &amp; PLLEN_OFF &amp; STVREN_ON &amp; BORV_19 &amp; LVP_ON);</pre>
<pre>// Using Internal Clock of 8 MHz
#define FOSC 8000000L</pre>
<pre>// UART Baud Rate
#define BAUD_RATE 19200</pre>
<pre>// Wiznet W5100 Register Addresses
#define MR   0x0000   // Mode Register
#define GAR  0x0001   // Gateway Address: 0x0001 to 0x0004
#define SUBR 0x0005   // Subnet mask Address: 0x0005 to 0x0008
#define SAR  0x0009   // Source Hardware Address (MAC): 0x0009 to 0x000E
#define SIPR 0x000F   // Source IP Address: 0x000F to 0x0012
#define RMSR 0x001A   // RX Memory Size Register
#define TMSR 0x001B   // TX Memory Size Register</pre>
<pre>// Wiznet W5100 Op Code
#define WIZNET_WRITE_OPCODE 0xF0
#define WIZNET_READ_OPCODE 0x0F</pre>
<pre>// PIC16F1829 TIMER6 Based Delay Implementation Function
void _delay_ms(unsigned int ms)
{
  unsigned int i;</pre>
<pre>  // TIMER6 Period = PR6 x 4 x Tosc x Prescaller second
  // TIMER6 Period = 50 x 4 x 1/8000000 x 4 = 0.0001 second = 0.1 ms</pre>
<pre>  PR6=50;                           // Maximum Counter
  for (i=0; i &lt;= (ms * 10);i++) {
    TMR6=0;                         // Reset TIMER6 Counter
    PIR3bits.TMR6IF=0;              // Clear TIMER6 Interrupt Flag
    T6CONbits.TMR6ON=1;             // Turn On TIMER6
    while(PIR3bits.TMR6IF != 1);    // Wait until TMR6 &gt; PR6 (Overflow)
    T6CONbits.TMR6ON=0;             // Turn Off TIMER6
  }
}</pre>
<pre>void UARTInit(void)
{
  unsigned int BRGValue;</pre>
<pre>  TRISBbits.TRISB5 = 1;         // Set Port RB5 for UART RX (Input)
  TRISBbits.TRISB7 = 0;         // Set Port RB7 for UART TX (Output)</pre>
<pre>  // Baud Rate formula for SYNC=0 (Async), BRG16=0 (8-bit), BRGH=1 (High Speed)
  // 0.16% Error for 8 MHz Oscilator Clock. Actual Rate will be 19231.
  // BAUD_RATE = FOSC / (16 x (SPBRGL:SPBGRH + 1))
  BRGValue=(unsigned int) ((FOSC/BAUD_RATE)/16) - 1;
  SPBRGH=(BRGValue &gt;&gt; 8 ) &amp; 0x00FF;
  SPBRGL=BRGValue;</pre>
<pre>  TXSTA = 0b00100100;  // Async, 8 bit, High Speed, and Enable Transmit (TXEN=1)
  RCSTA = 0b10010000;  // Serial Port Enable, Async,8-bit and Enable Receipt (CREN=1)
  BAUDCON=0b00000000;
}</pre>
<pre>void putch(unsigned char data)
{
  // Send Data when PIR1bits.TXIF bit is clear
  while(!PIR1bits.TXIF) continue;
  TXREG = data;
}</pre>
<pre>unsigned char getch(void) {
  // Get Data when PIR1bits.RCIF bit is clear
  while(!PIR1bits.RCIF) continue;
  return RCREG;
}</pre>
<pre>unsigned char getche(void)
{
  unsigned char c;</pre>
<pre>  putch(c = getch());
  return c;
}</pre>
<pre>void ansi_cl(void)
{
  // ANSI clear screen: cl=\E[H\E[J
  putchar(27);
  putchar('[');
  putchar('H');
  putchar(27);
  putchar('[');
  putchar('J');
}</pre>
<pre>void ansi_me(void)
{
  // ANSI turn off all attribute: me=\E[0m
  putchar(27);
  putchar('[');
  putchar('0');
  putchar('m');
}</pre>
<pre>void SPI_Write(unsigned int addr,unsigned char data)
{
  // Activate the CS pin
  PORTCbits.RC6 = 0;</pre>
<pre>  // Start Wiznet W5100 Write OpCode transmission
  SSP1BUF = WIZNET_WRITE_OPCODE;</pre>
<pre>  // Wait for transmission complete
  while(!SSP1STATbits.BF);</pre>
<pre>  // Start Wiznet W5100 Address High Bytes transmission
  SSP1BUF = (addr &amp; 0xFF00) &gt;&gt; 8;</pre>
<pre>  // Wait for transmission complete
  while(!SSP1STATbits.BF);</pre>
<pre>  // Start Wiznet W5100 Address Low Bytes transmission
  SSP1BUF = addr &amp; 0x00FF;</pre>
<pre>  // Wait for transmission complete
  while(!SSP1STATbits.BF);   

  // Start Data transmission
  SSP1BUF = data;</pre>
<pre>  // Wait for transmission complete
  while(!SSP1STATbits.BF);</pre>
<pre>  // CS pin is not active
  PORTCbits.RC6 = 1;
}</pre>
<pre>unsigned char SPI_Read(unsigned int addr)
{
  // Activate the CS pin
  PORTCbits.RC6 = 0;</pre>
<pre>  // Start Wiznet W5100 Read OpCode transmission
  SSP1BUF = WIZNET_READ_OPCODE;</pre>
<pre>  // Wait for transmission complete
  while(!SSP1STATbits.BF);</pre>
<pre>  // Start Wiznet W5100 Address High Bytes transmission
  SSP1BUF = (addr &amp; 0xFF00) &gt;&gt; 8;</pre>
<pre>  // Wait for transmission complete
  while(!SSP1STATbits.BF);</pre>
<pre>  // Start Wiznet W5100 Address Low Bytes transmission
  SSP1BUF = addr &amp; 0x00FF;</pre>
<pre>  // Wait for transmission complete
  while(!SSP1STATbits.BF);   

  // Send Dummy transmission for reading the data
  SSP1BUF = 0x00;</pre>
<pre>  // Wait for transmission complete
  while(!SSP1STATbits.BF);  

  // CS pin is not active
  PORTCbits.RC6 = 1;</pre>
<pre>  return(SSP1BUF);
}</pre>
<pre>void W5100_Init(void)
{
  // Ethernet Setup
  unsigned char mac_addr[] = {0x00,0x16,0x36,0xDE,0x58,0xF6};
  unsigned char ip_addr[] = {192,168,2,10};
  unsigned char sub_mask[] = {255,255,255,0};
  unsigned char gtw_addr[] = {192,168,2,1};</pre>
<pre>  // Setting the Wiznet W5100 Mode Register: 0x0000
  SPI_Write(MR,0x80);            // MR = 0b10000000;
  _delay_ms(1);
  printf("Reading MR: %d\n\r\n\r",SPI_Read(MR));</pre>
<pre>  // Setting the Wiznet W5100 Gateway Address (GAR): 0x0001 to 0x0004
  printf("Setting Gateway Address %d.%d.%d.%d\n\r",gtw_addr[0],gtw_addr[1],\
          gtw_addr[2],gtw_addr[3]);
  SPI_Write(GAR + 0,gtw_addr[0]);
  SPI_Write(GAR + 1,gtw_addr[1]);
  SPI_Write(GAR + 2,gtw_addr[2]);
  SPI_Write(GAR + 3,gtw_addr[3]);
  _delay_ms(1);</pre>
<pre>  printf("Reading GAR: %d.%d.%d.%d\n\r\n\r",SPI_Read(GAR + 0),SPI_Read(GAR + 1),\
          SPI_Read(GAR + 2),SPI_Read(GAR + 3));</pre>
<pre>  // Setting the Wiznet W5100 Source Address Register (SAR): 0x0009 to 0x000E
  printf("Setting Source Address %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n\r",mac_addr[0],mac_addr[1],\
          mac_addr[2],mac_addr[3],mac_addr[4],mac_addr[5]);
  SPI_Write(SAR + 0,mac_addr[0]);
  SPI_Write(SAR + 1,mac_addr[1]);
  SPI_Write(SAR + 2,mac_addr[2]);
  SPI_Write(SAR + 3,mac_addr[3]);
  SPI_Write(SAR + 4,mac_addr[4]);
  SPI_Write(SAR + 5,mac_addr[5]);
  _delay_ms(1);</pre>
<pre>  printf("Reading SAR: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n\r\n\r",SPI_Read(SAR + 0),SPI_Read(SAR + 1),\
          SPI_Read(SAR + 2),SPI_Read(SAR + 3),SPI_Read(SAR + 4),SPI_Read(SAR + 5));</pre>
<pre>  // Setting the Wiznet W5100 Sub Mask Address (SUBR): 0x0005 to 0x0008
  printf("Setting Sub Mask Address %d.%d.%d.%d\n\r",sub_mask[0],sub_mask[1],\
          sub_mask[2],sub_mask[3]);
  SPI_Write(SUBR + 0,sub_mask[0]);
  SPI_Write(SUBR + 1,sub_mask[1]);
  SPI_Write(SUBR + 2,sub_mask[2]);
  SPI_Write(SUBR + 3,sub_mask[3]);
  _delay_ms(1);</pre>
<pre>  printf("Reading SUBR: %d.%d.%d.%d\n\r\n\r",SPI_Read(SUBR + 0),SPI_Read(SUBR + 1),\
          SPI_Read(SUBR + 2),SPI_Read(SUBR + 3));</pre>
<pre>  // Setting the Wiznet W5100 IP Address (SIPR): 0x000F to 0x0012
  printf("Setting IP Address %d.%d.%d.%d\n\r",ip_addr[0],ip_addr[1],\
          ip_addr[2],ip_addr[3]);
  SPI_Write(SIPR + 0,ip_addr[0]);
  SPI_Write(SIPR + 1,ip_addr[1]);
  SPI_Write(SIPR + 2,ip_addr[2]);
  SPI_Write(SIPR + 3,ip_addr[3]);
  _delay_ms(1);</pre>
<pre>  printf("Reading SIPR: %d.%d.%d.%d\n\r\n\r",SPI_Read(SIPR + 0),SPI_Read(SIPR + 1),\
          SPI_Read(SIPR + 2),SPI_Read(SIPR + 3));

  // Setting the Wiznet W5100 RX and TX Memory Size, we use 2KB for Rx/Tx 4 channel
  printf("Setting Wiznet RMSR and TMSR\n\r\n\r");
  SPI_Write(RMSR,0x55);
  SPI_Write(TMSR,0x55);</pre>
<pre>  printf("Wiznet W5100 Initialized is Done!\n\r");
}</pre>
<pre>void main(void)
{
  OSCCON=0x70;         // Select 8 MHz internal clock 

  // PIC16F1829 I/O Port Initialization
  PORTA = 0x00;        // Initial PORT A
  LATA  = 0x00;        // Clear PORT A
  TRISA = 0x03;        // Input for RA0 and RA1
  ANSELA = 0b00000001; // Set Port AN0 to analog input Others as digital I/O</pre>
<pre>  PORTB = 0x00;        // Initial PORT B
  LATB  = 0x00;        // Clear PORT B
  TRISB = 0x00;        // Set Port B as Output
  ANSELB = 0b00000000; // Set all as digital Output</pre>
<pre>  PORTC = 0x00;        // Initial PORT C
  LATC  = 0x00;        // Clear PORT C
  TRISC = 0x00;        // Set Port C as Output
  ANSELC = 0b00000000; // Set all as digital Output</pre>
<pre>  // TIMER6 Delay Initialization
  // TIMER6 Period = PR6 x 4 x Tosc x Prescaller second
  T6CON = 0b00000010;  // Used Prescaler 4</pre>
<pre>  // Initial the PIC16F1829 Ehanced UART
  UARTInit();</pre>
<pre>  // Initial the PIC16F1829 SPI Peripheral
  TRISCbits.TRISC6 = 0;   // RC6/SS - Output (Chip Select)
  TRISCbits.TRISC7 = 0;   // RC7/SDO - Output (Serial Data Out)
  TRISBbits.TRISB4 = 1;   // RB4/SDI - Input (Serial Data In)
  TRISBbits.TRISB6 = 0;   // RB6/SCK - Output (Clock)

  SSP1STAT = 0x40;        // Set SMP=0 and CKE=1
  SSP1CON = 0x20;         // Enable SSP1EN=1, SSP1M = 0000 - SPI Master with Fsosc/4
  PORTCbits.RC6 = 1;      // Disable Chip Select</pre>
<pre>  // Disabling the interrupts.
  INTCON=0;</pre>
<pre>  // Initial the Wiznet W5100
  ansi_me();
  ansi_cl();
  printf("PICJazz 20PIN - Microchip PIC16F1829 Microcontroller\n\r");
  printf("Arduino Ethernet W5100 Shield Cradle Initialized\n\r\n\r");
  W5100_Init();  

  // Loop forever
  for(;;) {
  }
}</pre>
<pre>/* EOF: picping.c */</pre>
<p>After compiling and downloading the HEX program into the PICJazz 20PIN board; connect the RJ45 connector UTP ethernet cable to your hubs/switch or you could connect directly with the cross configuration cable to your computer. Use the serial terminal such as Hyperterminal, puTTY or Tera Term and configure it to accept the serial connection with 19200 baud rate, 8-bit data with No Parity Check.</p>
<p>Now you are ready to test the Arduino Shield Ethernet W5100 by using the &#8220;<strong>ping</strong>&#8221; command as shown on these following pictures:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_10.jpg"><img class="alignnone size-full wp-image-2067" title="arduino_shield_10" src="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_10.jpg" alt="" width="579" height="426" /></a></p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_11.jpg"><img class="alignnone size-full wp-image-2068" title="arduino_shield_11" src="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_11.jpg" alt="" width="577" height="338" /></a></p>
<p>You could read detail information of how to use the Wiznet W5100 chip on &#8220;<a title="Integrating Wiznet W5100, WIZ811MJ network module with Atmel AVR Microcontroller" href="http://www.ermicro.com/blog/?p=1773" target="_blank">Integrating Wiznet W5100, WIZ811MJ network module with Atmel AVR Microcontroller</a>&#8221; and using Microchip PIC microcontroller SPI (Serial Peripheral Interface) on &#8220;<a title="Using Serial Peripheral Interface (SPI) with Microchip PIC18 Families Microcontroller" href="http://www.ermicro.com/blog/?p=1846" target="_blank">Using Serial Peripheral Interface (SPI) with Microchip PIC18 Families Microcontroller</a>&#8221; articles.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_12.jpg"><img class="alignnone size-full wp-image-2098" title="arduino_shield_12" src="http://www.ermicro.com/blog/wp-content/uploads/2011/07/arduino_shield_12.jpg" alt="" width="581" height="386" /></a></p>
<p>Now it&#8217;s time to watch the Arduino Shield Cradle assembly and testing process on this following video:</p>
<p><object width="480" height="390" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/f-l7XQIU6n8?version=3&amp;hl=en_US" /><param name="allowfullscreen" value="true" /><embed width="480" height="390" type="application/x-shockwave-flash" src="http://www.youtube.com/v/f-l7XQIU6n8?version=3&amp;hl=en_US" allowFullScreen="true" allowscriptaccess="always" allowfullscreen="true" /></object></p>
<p><strong>The Final Thought</strong></p>
<p>One of the Arduino framework successful stories is come from the various well designs Arduino Shield hardware available on the market, which could bring broader range of various embedded application that could be applied with the Arduino board. Now with the Arduino Shield Cradle in your hand you could easily use these various shields on any development board or microcontroller type in your next embedded application project.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ermicro.com/blog/?feed=rss2&amp;p=2056</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Working with Atmel AVR Microcontroller Basic Pulse Width Modulation (PWM) Peripheral</title>
		<link>http://www.ermicro.com/blog/?p=1971</link>
		<comments>http://www.ermicro.com/blog/?p=1971#comments</comments>
		<pubDate>Sat, 30 Apr 2011 15:59:34 +0000</pubDate>
		<dc:creator>rwb</dc:creator>
				<category><![CDATA[Microcontroller]]></category>
		<category><![CDATA[ADC]]></category>
		<category><![CDATA[ATMEGA168]]></category>
		<category><![CDATA[AVR]]></category>
		<category><![CDATA[PWM]]></category>

		<guid isPermaLink="false">http://www.ermicro.com/blog/?p=1971</guid>
		<description><![CDATA[Pulse Width Modulation (PWM) is a technique widely used in modern switching circuit to control the amount of power given to the electrical device.  This method simply switches ON and OFF the power supplied to the electrical device rapidly. The average amount of energy received by the electrical device is corresponding to the ON and [...]]]></description>
				<content:encoded><![CDATA[<p>Pulse Width Modulation (PWM) is a technique widely used in modern switching circuit to control the amount of power given to the electrical device.  This method simply switches ON and OFF the power supplied to the electrical device rapidly. The average amount of energy received by the electrical device is corresponding to the ON and OFF period (duty cycle); therefore by varying the ON period i.e. longer or shorter, we could easily control the amount of energy received by the electrical device. The Light Emitting Diode (LED) will respond to this pulse by dimming or brighten its light while the electrical motor will respond to this pulse by turning its rotor slow or fast.<span id="more-1971"></span></p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_01.jpg"><img class="alignnone size-full wp-image-1974" title="avr_pwm_01" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_01.jpg" alt="" width="585" height="181" /></a></p>
<p>The above picture show a typical Pulse Width Modulation (PWM), the PWM duty cycle is the proportion of the signal &#8220;ON&#8221; time to one period (T) of the signal time. The duty cycle will be higher when the ON time is longer than the OFF time and vice versa. Duty cycle is expressed in percentage; therefore you could define the duty cycle of PWM signal as follow:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_08.jpg"><br />
</a></p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_08.jpg"><img class="alignnone size-full wp-image-1975" title="avr_pwm_08" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_08.jpg" alt="" width="572" height="80" /></a></p>
<p>The 100% PWM duty cycle means it&#8217;s fully ON and we could say that 100% of the power or energy is delivered to the electrical device, while 15% duty cycle means only 15% of the power is being delivered to the electrical device.  This average in power could be presented as average in voltage as follow:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_09.jpg"><img class="size-full wp-image-1976 aligncenter" title="avr_pwm_09" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_09.jpg" alt="" width="302" height="64" /></a></p>
<p>The PWM signal normally has a fixed frequency (period) with a duty cycle that could vary from 0% to 100%. Now you understand that by just adjusting the PWM duty cycle we could easily control the LED brightness or the electrical motor spinning speed.</p>
<p>Today most of modern microcontroller has a build in PWM peripheral inside; this make generating PWM signal is become easy and straightforward, you could read more about non microcontroller PWM base generator on &#8220;<a title="The LM324 Quad Op-Amp Line Follower Robot with Pulse Width Modulation" href="http://www.ermicro.com/blog/?p=1908" target="_blank">The LM324 Quad Op-Amp Line Follower Robot with Pulse Width Modulation</a>&#8221; article on this blog.  On this tutorial we are going to use Atmel AVR ATMega168 microcontroller which support up to 6 PWM output simultaneously and at the end of this tutorial we will take advantage of all the available PWM peripheral to make a nice RGB LED Light and Sound Show.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_23.jpg"><img class="alignnone size-full wp-image-1977" title="avr_pwm_23" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_23.jpg" alt="" width="577" height="428" /></a></p>
<p><strong>The AVR Microcontroller PWM Peripheral</strong></p>
<p>Most of the microcontroller PWM peripheral depends on the TIMER peripheral to provide the PWM signals frequency. The PWM peripheral will use the TIMER counter register (<strong>TCNT</strong>) as a digital step-up /down and continuously compare to the pre-determine duty cycle register (<strong>OCR</strong> &#8211; output compare register) value.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_00.jpg"><img class="alignnone size-full wp-image-1978" title="avr_pwm_00" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_00.jpg" alt="" width="578" height="220" /></a></p>
<p>When <strong>TCNT</strong> equal to <strong>OCR</strong> value the wave generator circuit will set (ON) or reset (OFF) the corresponding microcontroller PWM I/O ports. The following picture show a simplified version of Atmel AVR ATMega168 microcontroller PWM peripheral (please refer to the Atmel ATMega48/88/168/328 datasheet for more information):</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_02.jpg"><img class="alignnone size-full wp-image-1979" title="avr_pwm_02" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_02.jpg" alt="" width="580" height="346" /></a></p>
<p>Each of the AVR ATMega168 microcontrollers TIMER has two PWM channels named channel A and channel B, where each channel has its own output compare register (<strong>OCR</strong>).  From the diagram above you could see that both channel share the same TIMER counter register (<strong>TCNT</strong>), this mean you could only have one PWM frequency for each TIMER (TIMER0, TIMER1, and TIMER2) but you could have different duty cycle on each channel (A and B). The AVR ATMega48/88/168/328 microcontroller provides three PWM modes which are Fast PWM Mode, Phase Correct PWM Mode, and Phase and Frequency Correct Mode.  The last mode is only available on TIMER1 (16-bit timer). Ok before we continue let&#8217;s list down the hardware and software needed for this tutorial:</p>
<p>1.	<a title="AVRJazz Mega168/328 Board" href="http://www.ermicro.com/blog/?p=1" target="_blank">AVRJazz Mega168</a> or AVRJazz Ultimate 28P board (I used in this project), you could also use any AVR ATMega168 board or bare ATMega168, whatever available to you (the electronics components listed here is just for the final project)<br />
2.	One Bread board<br />
3.	Resistors:  10K (1), 15K (1), and 18 (1)<br />
4.	One 10K Trimpot<br />
5.	Non polar Capacitor 0.1uF (3) and 0.01uF (1)<br />
6.	Polar Capacitor 220uF/16V (1) and 10uF/16V (1)<br />
7.	 One 5 mm RGB LED<br />
8.	National Semiconductor LM386 IC<br />
9.	One white ping-pong ball for defusing the RGB LED light<br />
10.	One Speaker<br />
11.	The latest Atmel AVRStudio (in this project I used v4.18) and WinAVR GNU-C Compiler (in this project I used WinAVR 20100110)<br />
12.	AVR Microcontroller Programmer<br />
13.	Atmel ATMega48/88/168/328 and LM386 datasheet.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_20.jpg"><img class="alignnone size-full wp-image-1980" title="avr_pwm_20" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_20.jpg" alt="" width="581" height="455" /></a><br />
<strong></strong></p>
<p><strong>The AVR Fast PWM Mode</strong></p>
<p>The AVR fast PWM mode could generate the most high frequency PWM waveform compared to the other two PWM modes (i.e. Phase Correct or Phase and Frequency Correct mode). This PWM mode simply uses the TIMER counter register (<strong>TCNTn</strong>, where n represent the TIMER 0, TIMER1, and TIMER2 respectively) incremental value which is start from <strong>0&#215;00</strong> (BOTTOM) to 0xFF (8-bit TOP) or <strong>0xFFFF</strong> (16-bit TOP).</p>
<p>When the TIMER counter register  reach the output compare register  (<strong>OCRnA</strong> or <strong>OCRnB</strong>) value  then the wave generator circuit will CLEAR (logical low) the output compare bit channel (<strong>OCnA</strong> or <strong>OCnB</strong>).  When the TIMER counter register value reach the TOP value then it will SET (logical high) the output compare bit channel and the whole process will repeat again from BOTTOM. This PWM generation process could be shown on this following diagram:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_03.jpg"><img class="alignnone size-full wp-image-1981" title="avr_pwm_03" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_03.jpg" alt="" width="580" height="449" /></a></p>
<p>As shown on the diagram above, the behavior of output compare bit channel (<strong>OCnA</strong> or <strong>OCnB</strong>) output could be set to non-inverting (CLEAR  and SET) or inverting (SET and CLEAR) mode by setting the compare match channel bit (<strong>COMnA1</strong>, <strong>COMnA0</strong>, <strong>COMnB1</strong>, and <strong>COMnB0</strong>) on Timer/Counter register A (<strong>TCCRnA</strong>). The Fast PWM mode could be set by setting the wave generation mode bit (<strong>WGM01</strong> and <strong>WGM00</strong>) on Timer/Counter register A (<strong>TCCRnA</strong>) and <strong>WGM02</strong> bit on <strong>TCCRnB</strong> register. When the TIMER counter register (<strong>TCNTn</strong>) equal to Output Compare Register (<strong>OCRnA</strong> or <strong>OCRnB</strong>) it will generate the Output Compare interrupt and when the <strong>TCNTn</strong> register reach TOP it will generate the TIMER overflow interrupt (<strong>TOV</strong>).</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_12.jpg"><img class="alignnone size-full wp-image-1990" title="avr_pwm_12" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_12.jpg" alt="" width="581" height="433" /></a></p>
<p>As you see at the Atmel AVR microcontroller PWM peripheral diagram above when we update the Output Compare Register (<strong>OCRnA</strong> and <strong>OCRnB</strong>) value, the value will be updated on the Output Compare Register Buffer first and when the TIMER0 Counter Register (<strong>TCNT0</strong>) reach TOP then the <strong>OCRn</strong> register will be updated with the <strong>OCRn</strong> buffer value and at the same time the Output Compare Bits (<strong>OCnA </strong>or <strong>OCnB</strong>) will be set.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_04.jpg"><img class="alignnone size-full wp-image-1991" title="avr_pwm_04" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_04.jpg" alt="" width="575" height="416" /></a></p>
<p>On this following C code, we are going to use TIMER0 Fast PWM mode on both channel A and channel B.</p>
<pre>//***************************************************************************
//  File Name	 : avrpwm01.c
//  Version	 : 1.0
//  Description  : AVR TIMER0 Fast PWM Mode
//  Author       : RWB
//  Target       : AVRJazz Ultimate 28PIN Board
//  Compiler     : AVR-GCC 4.3.3; avr-libc 1.6.7 (WinAVR 20100110)
//  IDE          : Atmel AVR Studio 4.18
//  Programmer   : AVRJazz Mega168 STK500 v2.0 Bootloader
//               : AVR Visual Studio 4.18, STK500 programmer
//  Last Updated : 21 March 2011
//***************************************************************************
#include &lt;avr/io.h&gt;
#include &lt;util/delay.h&gt;</pre>
<pre>int main(void)
{
  unsigned char duty_cyc_a,duty_cyc_b;</pre>
<pre>  // Initial PORT Used
  DDRD = 0b11111111;     // Set PORTD: Output
  PORTD = 0x00;</pre>
<pre>  // Initial TIMER0 Fast PWM
  // Fast PWM Frequency = fclk / (N * 256), Where N is the Prescaler
  // f_PWM = 11059200 / (64 * 256) = 675 Hz
  TCCR0A = 0b10100011; // Fast PWM 8 Bit, Clear OCA0/OCB0 on Compare Match, Set on TOP
  TCCR0B = 0b00000011; // Used 64 Prescaler
  TCNT0 = 0;           // Reset TCNT0
  OCR0A = 0;           // Initial the Output Compare register A &amp; B
  OCR0B = 0;</pre>
<pre>  duty_cyc_a=0;	// Initial Duty Cycle for Channel A
  duty_cyc_b=255;	// Initial Duty Cycle for Channel B

  for(;;) {            // Loop Forever
    while(duty_cyc_a &lt; 255) {
      OCR0A=duty_cyc_a++;
      OCR0B=duty_cyc_b--;
       _delay_ms(10);
    }

    while(duty_cyc_b &lt; 255) {
      OCR0A=duty_cyc_a--;
      OCR0B=duty_cyc_b++;
      _delay_ms(10);
    }
  }

  return 0;	        // Standard Return Code
}</pre>
<pre>/* EOF: avrpwm01.c */</pre>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_05.jpg"><img class="alignnone size-full wp-image-1992" title="avr_pwm_05" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_05.jpg" alt="" width="578" height="405" /></a></p>
<p>The TIMER0 Fast PWM mode is activated by setting the Wave Generation Mode bits <strong>WGM02=0</strong>, <strong>WGM01=1</strong>, and <strong>WGM00 = 1</strong> on TIMER0 Timer/Counter control Registers (<strong>TCCR0A</strong> and <strong>TCCR0B</strong>) as follow:</p>
<pre>// Initial TIMER0 Fast PWM
// Fast PWM Frequency = fclk / (N * 256), Where N is the Prescaler
// f_PWM = 11059200 / (64 * 256) = 675 Hz
TCCR0A = 0b10100011; // Fast PWM 8 Bit, Clear OCA0/OCB0 on Compare Match, Set on TOP
TCCR0B = 0b00000011; // Used 64 Prescaler</pre>
<p>Therefore by assigning the Clock Set Bit <strong>CS02 = 0</strong>, <strong>CS01 = 1</strong>, and <strong>CS00 = 1</strong> respectively, we tell the TIMER0 to use 64 as a prescaler, therefore you could calculate the PWM frequency if we use 11059200 Hz external crystal as follow:</p>
<p>PWM Frequency = Freq Clock / (prescaler  x 256) = 11059200 / (64 x 256) = <strong>675 Hz</strong></p>
<p>You could freely choose or experiment with any PWM frequency that work best with the electrical devices that you want to control with the Fast PWM mode signal.</p>
<p>One of disadvantage using the Fast PWM mode to generate the PWM signal is the PWM phase is shifted when we change the PWM duty cycle. This because when the TIMER0 Counter Register (<strong>TCNTn</strong>) reach TOP and start from BOTTOM it will always SET (or CLEAR) the Output Compare Bits (<strong>OCnA</strong> or <strong>OCnB</strong>) despite the Output Compare Register (<strong>OCRnA</strong> and <strong>OCRnB</strong>) value; therefore when we change the duty cycle in Fast PWM mode the PWM signal phase is always shifted as illustrated on this following diagram:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_07.jpg"><img class="alignnone size-full wp-image-1993" title="avr_pwm_07" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_07.jpg" alt="" width="577" height="421" /></a></p>
<p>This make the Fast PWM mode is not suitable when we want to use for controlling the motor speed precisely; therefore on our next discussion we will correct this shifted phase effect by using the AVR microcontroller Phase Correct PWM mode for generating the PWM signal.</p>
<p>Now as you understand of how to use the Fast PWM mode on TIMER0, you could easily adapt this principal to TIMER1 (16-bit) and TIMER2 (8-bit). Please refer to the Atmel ATMega48/88/168/328 datasheet for complete information.</p>
<p><strong>The AVR Phase Correct PWM Mode</strong></p>
<p>Differ from the Fast PWM Mode, the Phase Correct PWM mode is using dual slope TIMER counter. Basically the TIMER counter register (<strong>TCNTn</strong>) will increase its value (up counter) from BOTTOM to TOP and then decrease its value (down counter) from TOP to BOTTOM. When the TIMER counter register equal to the Output Compare Register (<strong>OCRnA</strong> and <strong>OCRnB</strong>) then the wave generator bit will simply toggle the Output Compare channel (<strong>OCnA</strong> and <strong>OCnB</strong>) as shown on this following diagram:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_06.jpg"><img class="alignnone size-full wp-image-1996" title="avr_pwm_06" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_06.jpg" alt="" width="579" height="452" /></a></p>
<p>As shown on the diagram above you could see that the Phase Correct PWM mode will have half of the PWM signal frequency compared to the fast PWM mode. Because of the dual slope technique used in the Phase Correct PWM mode to generate the PWM signal, therefore the phase correct PWM mode is more precision and suitable to be used as a motor controller, because as we change the PWM signal duty  cycle the phase between each duty cycles remain the same as illustrated on this following diagram:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_14.jpg"><img class="alignnone size-full wp-image-1997" title="avr_pwm_14" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_14.jpg" alt="" width="578" height="381" /></a></p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_13.jpg"><img class="alignnone size-full wp-image-1998" title="avr_pwm_13" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_13.jpg" alt="" width="579" height="432" /></a></p>
<p>On this following C code, we are going to use TIMER0 Phase Correct PWM mode on both channel A and channel B.</p>
<pre>//***************************************************************************
//  File Name	 : avrpwm02.c
//  Version	 : 1.0
//  Description  : AVR TIMER0 Phase Correct PWM Mode
//  Author       : RWB
//  Target       : AVRJazz Ultimate 28PIN Board
//  Compiler     : AVR-GCC 4.3.3; avr-libc 1.6.7 (WinAVR 20100110)
//  IDE          : Atmel AVR Studio 4.18
//  Programmer   : AVRJazz Mega168 STK500 v2.0 Bootloader
//               : AVR Visual Studio 4.18, STK500 programmer
//  Last Updated : 21 March 2011
//***************************************************************************
#include &lt;avr/io.h&gt;
#include &lt;util/delay.h&gt;</pre>
<pre>int main(void)
{
  unsigned char duty_cyc_a,duty_cyc_b;</pre>
<pre>  // Initial PORT Used
  DDRD = 0b11111111;     // Set PORTD: Output
  PORTD = 0x00;</pre>
<pre>  // Initial TIMER0 Phase Correct PWM
  // Fast PWM Frequency = fclk / (N * 510), Where N is the Prescaler
  // f_PWM = 11059200 / (64 * 510) = 338.82 Hz
  TCCR0A = 0b10100001; // Phase Correct PWM 8 Bit, Clear OCA0/OCB0 on Compare Match, Set on TOP
  TCCR0B = 0b00000011; // Used 64 Prescaler
  TCNT0 = 0;           // Reset TCNT0
  OCR0A = 0;           // Initial the Output Compare register A &amp; B
  OCR0B = 0;</pre>
<pre>  duty_cyc_a=0;		   // Initial Duty Cycle for Channel A
  duty_cyc_b=255;	   // Initial Duty Cycle for Channel B

  for(;;) {            // Loop Forever
	while(duty_cyc_a &lt; 255) {
	  OCR0A=duty_cyc_a++;
	  OCR0B=duty_cyc_b--;
	  _delay_ms(10);
	}

	while(duty_cyc_b &lt; 255) {
	  OCR0A=duty_cyc_a--;
	  OCR0B=duty_cyc_b++;
	  _delay_ms(10);
	}
  }

  return 0;	           // Standard Return Code
}</pre>
<pre>/* EOF: avrpwm02.c */</pre>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_10.jpg"><img class="alignnone size-full wp-image-1999" title="avr_pwm_10" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_10.jpg" alt="" width="576" height="419" /></a></p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_11.jpg"><img class="alignnone size-full wp-image-2000" title="avr_pwm_11" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_11.jpg" alt="" width="579" height="399" /></a></p>
<p>The TIMER0 Phase Correct PWM mode is activated by setting the Wave Generation Mode bits <strong>WGM02=0</strong>, <strong>WGM01=0</strong>, and <strong>WGM00 = 1</strong> on TIMER0 Timer/Counter control Registers (<strong>TCCR0A</strong> and <strong>TCCR0B</strong>) as follow:</p>
<pre>// Initial TIMER0 Phase Correct PWM
// Fast PWM Frequency = fclk / (N * 510), Where N is the Prescaler
// f_PWM = 11059200 / (64 * 510) = 338.82 Hz
TCCR0A = 0b10100001; // Phase Correct PWM 8 Bit, Clear OCA0/OCB0 on Compare Match, Set on TOP
TCCR0B = 0b00000011; // Used 64 Prescaler</pre>
<p>Therefore by assigning the Clock Set Bit <strong>CS02 = 0</strong>, <strong>CS01 = 1</strong>, and <strong>CS00 = 1</strong> respectively, we tell the TIMER0 to use 64 as a prescaler, therefore the Phase Correct PWM frequency could be calculated as follow:</p>
<p>PWM Frequency = Freq Clock / (prescaler  x 510) = 11059200 / (64 x 510) = <strong>338.82 Hz</strong></p>
<p>Again you could easily adapt this principal to TIMER1 (16-bit) and TIMER2 (8-bit) as well (please refer to Atmel ATMega48/88/168/328 datasheet for complete information).</p>
<p><strong>The AVR Phase and Frequency Correct PWM Mode</strong></p>
<p>The Phase and Frequency Correct PWM Mode feature is only available on TIMER1 (16-bit). Basically the Phase and Frequency Correct PWM mode use the same dual slope technique used in Phase Correct PWM mode to generate the PWM signal. These two modes actually are identical if we never change the PWM signal frequency, but if we need to change the PWM signal frequency on fly, then we need to use the AVR ATMega168 microcontroller Phase and Frequency Correct mode to generate the PWM signal.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_15.jpg"><img class="alignnone size-full wp-image-2001" title="avr_pwm_15" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_15.jpg" alt="" width="576" height="450" /></a></p>
<p>Differ from the Phase Correct PWM Mode, in Phase and Frequency Correct PWM Mode the Output Compare Register (<strong>OCRnA</strong> and <strong>OCRnB</strong>) is updated from the buffer when the Timer Counter Register (<strong>TCNTn</strong>) reaches BOTTOM instead of TOP in Phase Correct PWM Mode. The frequency could be change by changing the TOP value, here you could understand why we need to use the Phase and Frequency Correct PWM mode, because as we change the frequency and at the same time the PWM peripheral update the Output Compare register (<strong>OCRnA</strong> and <strong>OCRnB</strong>) then there will be a glitch in the PWM frequency signal.</p>
<p>In Phase and Frequency Correct PWM mode because the Output Compare Register is updated at the BOTTON therefore the rising and falling length of the PWM signal is always equal this result in frequency being corrected when we change the frequency on fly.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_16.jpg"><img class="alignnone size-full wp-image-2013" title="avr_pwm_16" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_16.jpg" alt="" width="576" height="518" /></a></p>
<p>Typically in controlling the electrical device with PWM signal we seldom change the PWM frequency on fly, therefore the common application for this mode is to generate the sound. On this following C code example I used the Phase and Frequency Correct PWM to generated tone. Another example of using this PWM mode could be read in &#8220;<a title="AVR Twinkle Twinkle Using PWM Project" href="http://www.ermicro.com/blog/?p=580" target="_blank">AVR Twinkle-Twinkle Song Using PWM Project</a>&#8221; article on this blog.</p>
<pre>//***************************************************************************
//  File Name	 : avrpwm03.c
//  Version	 : 1.0
//  Description  : AVR TIMER0 Phase and Frequency Correct PWM Mode
//  Author       : RWB
//  Target       : AVRJazz Ultimate 28PIN Board
//  Compiler     : AVR-GCC 4.3.3; avr-libc 1.6.7 (WinAVR 20100110)
//  IDE          : Atmel AVR Studio 4.18
//  Programmer   : AVRJazz Mega168 STK500 v2.0 Bootloader
//               : AVR Visual Studio 4.18, STK500 programmer
//  Last Updated : 21 March 2011
//***************************************************************************
#include &lt;avr/io.h&gt;
#include &lt;util/delay.h&gt;</pre>
<pre>// Notes Frequency from http://www.phy.mtu.edu/~suits/notefreqs.html
// The Original frequency value (decimal) is converted to the integer value
#define C4  262
#define Cc4 277
#define D4  294
#define Dc4 311
#define E4  330
#define F4  349
#define Fc4 370
#define G4  392
#define Gc4 415
#define A4  440
#define Ac4 466
#define B4  494

#define C5  523
#define Cc5 554
#define D5  587
#define Dc5 622
#define E5  659
#define F5  698
#define Fc5 740
#define G5  783
#define Gc5 831
#define A5  880
#define Ac5 932
#define B5  988</pre>
<pre>#define C6  1047</pre>
<pre>// LED Display variables
unsigned char ledstat,led_out;</pre>
<pre>// PlayNotes function
void PlayNotes(unsigned int note_frequency,unsigned int duration)
{
   unsigned int top_value,duty_cycle;</pre>
<pre>   // Calculate the Top Value
   // TOP = Board Clock Frequency / (2 x N x Notes Frequency)
   // Where N is Prescler: 8
   topvalue=(F_CPU / (16 * note_frequency));</pre>
<pre>   // Reset the TIMER1 16 bit Counter
   TCNT1H = 0;
   TCNT1L = 0;

   // Set the TIMER1 Counter TOP value on ICR1H and ICR1L
   ICR1H = (top_value &gt;&gt; 8 ) &amp; 0x00FF;
   ICR1L = top_value;   

   // Set the TIMER1 PWM Duty Cycle on OCR1AH and OCR1AL
   // Always use half of the TOP value (PWM Ducty Cycle ~ 50%)
   duty_cycle=top_value / 2;</pre>
<pre>   OCR1AH=(duty_cycle &gt;&gt; 8 ) &amp; 0x00FF;
   OCR1AL=duty_cycle;</pre>
<pre>   // Turn ON the TIMER1 Prescaler of 8
   TCCR1B |= (1&lt;&lt;CS11); 

   // Notes Delay Duration
   _delay_ms(duration); 

   // Turn OFF the TIMER1 Prescaler of 8
   TCCR1B &amp;= ~(1&lt;&lt;CS11);</pre>
<pre>   // Delay Between Each Notes 1/5 duration
   _delay_ms(duration * 1/5);
}</pre>
<pre>// Display LED function
void DisplayLED(void)
{
  if (ledstat) {
    PORTD=led_out;</pre>
<pre>    led_out=led_out &lt;&lt; 1;
    if (led_out &gt;= 0x80) ledstat=0;
  } else {
    PORTD=led_out;
    led_out=led_out &gt;&gt; 1;
    if (led_out &lt;= 0x01) ledstat=1;
  }
}</pre>
<pre>int main(void)
{
  unsigned int notes[25]={C4,Cc4,D4,Dc4,E4,F4,Fc4,G4,Gc4,A4,Ac4,B4,
                          C5,Cc5,D5,Dc5,E5,F5,Fc5,G5,Gc5,A5,Ac5,B5,C6};
  int icount;
  unsigned char pstat;
  unsigned int idelay;</pre>
<pre>  // Initial PORT Used
  DDRD = 0b11111111;   // Set PORTD as Output
  PORTD = 0b00000000;
  DDRB = 0b11111110;   // Set PB0 as Input and other as Output
  PORTB = 0b00000000;</pre>
<pre>  // Initial the ADC Peripheral
  ADCSRA = (1&lt;&lt;ADEN) | (1&lt;&lt;ADPS2) | (1&lt;&lt;ADPS1);</pre>
<pre>  // Use Free running Mode
  ADCSRB = 0b00000000;</pre>
<pre>  // Disable digital input on Channel 0
  DIDR0 = 0b00000001;</pre>
<pre>  // Initial TIMER1 Phase and Frequency Correct PWM
  // Set the Timer/Counter Control Register
  TCCR1A = 0b11000000; // Set OC1A when up counting, Clear when down counting
  TCCR1B = 0b00010000; // Phase/Freq-correct PWM, top value = ICR1, Prescaler: Off    	         

  // Initial Variables
  icount=0;
  pstat=1;
  led_out=1;
  ledstat=1;
  for(;;) {            // Loop Forever
    // Reading User Trimpot on Analog Channel 0
   ADMUX=0;</pre>
<pre>   // Start conversion by setting ADSC on ADCSRA Register
   ADCSRA |= (1&lt;&lt;ADSC);</pre>
<pre>   // wait until convertion complete ADSC=0 -&gt; Complete
   while (ADCSRA &amp; (1&lt;&lt;ADSC));</pre>
<pre>   // Get the ADC Result
   idelay=ADCW;</pre>
<pre>    DisplayLED();
    if (pstat) {
	  PlayNotes(notes[icount++],idelay);
	  if (icount &gt; 24) {
		icount=24;
		pstat=0;
      }
    } else {
	  PlayNotes(notes[icount--],idelay);
	  if (icount &lt; 0) {
		icount=0;
		pstat=1;
      }
    }
  }

  return 0;	           // Standard Return Code
}</pre>
<pre>/* EOF: avrpwm03.c */

<a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_17.jpg"><img class="alignnone size-full wp-image-2014" title="avr_pwm_17" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_17.jpg" alt="" width="576" height="367" /></a></pre>
<p>To generate a controllable tone, we need to produce the exact frequency on each notes, the notes frequency could be found at this website address <em> http://www.phy.mtu.edu/~suits/notefreqs.html</em>.  In order to generate the <strong>C5</strong> note we have to produce the PWM frequency of <strong>523.23 Hz</strong> at 50% duty cycle. Therefore by setting the Wave Generation Mode Bits <strong>WGM13=1</strong>, <strong>WGM12=0</strong>, <strong>WGM11=0</strong>, and <strong>WGM10=0</strong> respectively, we choose the TIMER1 Phase and Frequency Correct PWM mode which has TOP value set on TIMER1 Input Capture Registers <strong>ICR1H</strong> and <strong>ICR1L</strong>; the Pulse Width is set on TIMER1 Output Compare Registers <strong>OCR1A</strong> and <strong>OCR1B</strong>.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_19.jpg"><img class="alignnone size-full wp-image-2015" title="avr_pwm_19" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_19.jpg" alt="" width="579" height="265" /></a></p>
<p>With the precaler being set to 8 and board frequency of 1109200 Hz, we could easily calculate the TOP value of theC5 note as follow:</p>
<p>PWM Frequency = Freq Clock / (2 x N x TOP) = Freq Clock / (16 x TOP)</p>
<p>Or</p>
<p>TOP = Freq Clock / (16 x PWM Frequency) = 11059200 / (16 x 523) = <strong>1322</strong></p>
<p>Now by assigning the TOP value to the Input Capture Registers (<strong>ICR1H</strong> and <strong>ICR1L</strong>) and half of the TOP value to the Output Compare Register (<strong>OCR1AH</strong> and <strong>OCR1AL</strong>) we could produce the C5 notes with 50% duty cycle as shown on this following C code:</p>
<pre>// Calculate the Top Value
// TOP = Board Clock Frequency / (2 x N x Notes Frequency)
// Where N is Prescler: 8
topvalue=(F_CPU / (16 * note_frequency));</pre>
<pre>// Set the TIMER1 Counter TOP value on ICR1H and ICR1L
ICR1H = (top_value &gt;&gt; 8 ) &amp; 0x00FF;
ICR1L = top_value;</pre>
<pre>// Set the TIMER1 PWM Duty Cycle on OCR1AH and OCR1AL
// Always use half of the TOP value (PWM Ducty Cycle ~ 50%)
duty_cycle=top_value / 2;</pre>
<pre>OCR1AH=(duty_cycle &gt;&gt; 8 ) &amp; 0x00FF;
OCR1AL=duty_cycle;</pre>
<p>Because the <strong>ICR1H</strong> and <strong>ICR1L</strong> are the 8-bit registers, therefore we use the C language shift right operator to assign the upper 8-bit <strong>top_value</strong> to <strong>ICR1H</strong> and the lower 8-bit TOP value to <strong>ICR1L</strong>. We use similar principal to both <strong>OCR1H</strong> and <strong>OCR1L</strong> for the PWM duty cycle value (<strong>duty_cycle</strong>). The complete C code is implemented in <strong>PlayNotes() </strong>function, which accept the frequency and duration parameters to produce the needed sound.   The AVR ATMega168 microcontroller ADC peripheral is used to control the playing notes delay by passing the trimpot voltage reading connected to ADC channel 0 (<strong>PC0</strong>), we could control the notes duration as shown on this following C code:</p>
<pre>// Reading User Trimpot on Analog Channel 0
ADMUX=0;</pre>
<pre>// Start conversion by setting ADSC on ADCSRA Register
ADCSRA |= (1&lt;&lt;ADSC);</pre>
<pre>// wait until convertion complete ADSC=0 -&gt; Complete
while (ADCSRA &amp; (1&lt;&lt;ADSC));</pre>
<pre>// Get the ADC Result
idelay=ADCW;
...
...
PlayNotes(notes[icount++],idelay);</pre>
<p>For more information about using Atmel AVR microcontroller ADC peripheral you could read &#8220;<a title="Analog to Digital Converter AVR C Programming" href="http://www.ermicro.com/blog/?p=121" target="_blank">Analog to Digital Converter AVR C Programming</a>&#8221; articles on this blog</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_18.jpg"><img class="alignnone size-full wp-image-2016" title="avr_pwm_18" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_18.jpg" alt="" width="577" height="428" /></a><br />
<strong></strong></p>
<p><strong>The RGB LED Light and Sound Show</strong></p>
<p>On this last tutorial we will put all together the AVR ATMega168 basic PWM lessons that we&#8217;ve learned and making some interesting RGB LED and Sound show as shown on this following schematic:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_21.jpg"><img class="alignnone size-full wp-image-2020" title="avr_pwm_21" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_21.jpg" alt="" width="584" height="394" /></a></p>
<p>This RGB light and Sound show project used the well known LM386 linear amplifier IC from National Semiconductor which recently has been acquired by Texas Instrument (April 2011) to produce a quite loud sound from the TIMER1 Phase and Correct Frequency PWM mode through the speaker.  The TIMER1 Output Compare Channel A (<strong>PB1</strong>) PWM signal is being passed through the passive low pass filter (<em>is also called an integrator circuit for a non sinusoidal input signal such as square wave and triangle wave</em>) in order to shape the square wave forms to become the sinusoidal wave forms before being amplified by the LM386 IC.</p>
<p>To make the low pass filter (LPF) become a good integrator circuit we have to choose the LPF cutoff frequency much less than the lowest frequency produced by the PWM signal but at the same time still produce an adequate signal level to drive the LM386 amplifier input. The cutoff frequency of LPF could be calculated as this following formula:</p>
<p>Frequency = 1 / (2 x pi x RC), where pi = 3.14159, R is resistance in Ohm, and C is capacitance in Farad</p>
<p>The lowest frequency produce by PWM signal is <strong>262 Hz</strong> (C4 note), therefore by choosing R = 15K and C = 0.1uF, we could calculate the LPF cutoff frequency as follow:</p>
<p>Frequency = 1 / (2 x 3.14159 x 15000 x 0.0000001) = <strong>106.10 Hz</strong></p>
<p>This method is used to ensure that we could get a quite nice sound produced on the speaker instead of just using raw square wave signal as shown on this following oscilloscope picture:</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_22.jpg"><img class="alignnone size-full wp-image-2017" title="avr_pwm_22" src="http://www.ermicro.com/blog/wp-content/uploads/2011/05/avr_pwm_22.jpg" alt="" width="582" height="432" /></a></p>
<p>Each of the RGB LED cathodes is driven by TIMER0 Fast PWM channel A, channel B, and TIMER2 Phase Correct PWM channel B respectively.  The following is the complete C code for our RGB LED Light and Sound Show final project:</p>
<pre>//***************************************************************************
//  File Name	 : avrpwm04.c
//  Version	 : 1.0
//  Description  : AVR TIMER0 Phase and Frequency Correct PWM Mode
//  Author       : RWB
//  Target       : AVRJazz Ultimate 28PIN Board
//  Compiler     : AVR-GCC 4.3.3; avr-libc 1.6.7 (WinAVR 20100110)
//  IDE          : Atmel AVR Studio 4.18
//  Programmer   : AVRJazz Mega168 STK500 v2.0 Bootloader
//               : AVR Visual Studio 4.18, STK500 programmer
//  Last Updated : 22 March 2011
//***************************************************************************
#include &lt;avr/io.h&gt;
#include &lt;util/delay.h&gt;
#include &lt;avr/interrupt.h&gt;
#include &lt;stdlib.h&gt;</pre>
<pre>// Notes Frequency from http://www.phy.mtu.edu/~suits/notefreqs.html
// The Original frequency value (decimal) is converted to the integer value
#define C4  262
#define Cc4 277
#define D4  294
#define Dc4 311
#define E4  330
#define F4  349
#define Fc4 370
#define G4  392
#define Gc4 415
#define A4  440
#define Ac4 466
#define B4  494

#define C5  523
#define Cc5 554
#define D5  587
#define Dc5 622
#define E5  659
#define F5  698
#define Fc5 740
#define G5  783
#define Gc5 831
#define A5  880
#define Ac5 932
#define B5  988</pre>
<pre>#define C6  1047</pre>
<pre>volatile unsigned char duty_cyc_a,duty_cyc_b, duty_cyc_c,led_a,led_b,led_c;
volatile unsigned int tempo;</pre>
<pre>// TIMER1 Overflow Interrupt
ISR(TIMER1_OVF_vect)
{
  cli();                  // Disable Interrupt</pre>
<pre>  // Reading User Trimpot on Analog Channel 0
  ADMUX = 0;</pre>
<pre>  // Start conversion by setting ADSC on ADCSRA Register
  ADCSRA |= (1&lt;&lt;ADSC);</pre>
<pre>  // wait until convertion complete ADSC=0 -&gt; Complete
  while (ADCSRA &amp; (1&lt;&lt;ADSC));</pre>
<pre>  // Get the ADC Result
  tempo=ADCW;      

  if (led_a) {
    if (duty_cyc_a &lt; 255) {
  	  OCR0A=duty_cyc_a++;
    } else {
	  led_a=0;
    }
  } else {
    if (duty_cyc_a &gt; 0) {
  	  OCR0A=duty_cyc_a--;
    } else {
	  led_a=1;
	  duty_cyc_a=TCNT1L;
    }
  }

  if (led_b) {
    if (duty_cyc_b &lt; 255) {
  	  OCR0B=duty_cyc_b++;
    } else {
	  led_b=0;
    }
  } else {
    if (duty_cyc_b &gt; 0) {
  	  OCR0B=duty_cyc_b--;
    } else {
	  led_b=1;
      duty_cyc_b=(unsigned char) rand() % 255; ;
    }
  }

  if (led_c) {
    if (duty_cyc_c &lt; 255) {
      OCR2B=duty_cyc_c++;
    } else {
	  led_c=0;
	}
  } else {
    if (duty_cyc_c &gt; 0) {
      OCR2B=duty_cyc_c--;
    } else {
	  led_c=1;
      duty_cyc_c=TCNT1H;
    }
  }</pre>
<pre>  sei();                      // Enable Interrupt
}</pre>
<pre>// PlayNotes function
void PlayNotes(unsigned int note_frequency,unsigned int duration)
{
   unsigned int top_value,duty_cycle;</pre>
<pre>   // Calculate the Top Value
   // TOP = Board Clock Frequency / (2 x N x Notes Frequency)
   // Where N is Prescler: 8
   topvalue=(F_CPU / (16 * note_frequency));</pre>
<pre>   // Reset the TIMER1 16 bit Counter
   TCNT1H = 0;
   TCNT1L = 0;

   // Set the TIMER1 Counter TOP value on ICR1H and ICR1L
   ICR1H = (top_value &gt;&gt; 8 ) &amp; 0x00FF;
   ICR1L = top_value;   

   // Set the TIMER1 PWM Duty Cycle on OCR1AH and OCR1AL
   // Always use half of the TOP value (PWM Ducty Cycle ~ 50%)
   duty_cycle=top_value / 2;</pre>
<pre>   OCR1AH=(duty_cycle &gt;&gt; 8 ) &amp; 0x00FF;
   OCR1AL=duty_cycle;</pre>
<pre>   // Turn ON the TIMER1 Prescaler of 8
   TCCR1B |= (1&lt;&lt;CS11); 

   // Notes Delay Duration
   _delay_ms(duration); 

   // Turn OFF the TIMER1 Prescaler of 8
   TCCR1B &amp;= ~(1&lt;&lt;CS11);</pre>
<pre>   // Delay Between Each Notes
   _delay_ms(duration * 1/5);
}</pre>
<pre>int main(void)
{
  unsigned char song_index;</pre>
<pre>  // Initial PORT Used
  DDRD = 0b11111111;   // Set PORTD as Output
  PORTD = 0b00000000;
  DDRB = 0b11111110;   // Set PB0 as Input and other as Output
  PORTB = 0b00000000;</pre>
<pre>  // Initial the ADC Peripheral
  ADCSRA = (1&lt;&lt;ADEN) | (1&lt;&lt;ADPS2) | (1&lt;&lt;ADPS1);</pre>
<pre>  // Use Free running Mode
  ADCSRB = 0b00000000;</pre>
<pre>  // Disable digital input on Channel 0
  DIDR0 = 0b00000001;</pre>
<pre>  // Initial TIMER0 Fast PWM
  // Fast PWM Frequency = fclk / (N * 256), Where N is the prescaler
  // f_PWM = 11059200 / (64 * 256) = 675 Hz
  TCCR0A = 0b10100011; // Fast PWM 8 Bit, Clear OCA0/OCB0 on Compare Match, Set on TOP
  TCCR0B = 0b00000011; // Used 64 Prescaler
  TCNT0 = 0;           // Reset TCNT0
  OCR0A = 0;           // Initial the Output Compare register A &amp; B
  OCR0B = 0;</pre>
<pre>  // Initial TIMER1 Phase and Frequency Correct PWM
  // Set the Timer/Counter Control Register
  TCCR1A = 0b11000000; // Set OC1A when up counting, Clear when down counting
  TCCR1B = 0b00010000; // Phase/Freq-correct PWM, top value = ICR1, Prescaler: Off    	         

  TIMSK1 = (1&lt;&lt;TOIE1); // Enable Overflow Interrupt</pre>
<pre>  // Initial TIMER2 Phase Correct PWM Mode
  // Phase Correct PWM Frequency = fclk / (N * 512), Where N is the prescaler
  // f_PWM = 11059200 / (64 * 512) = 337.5 Hz
  TCCR2A = 0b00100001; // Fast PWM 8 Bit, Clear OC2B on Compare Match, Set on TOP
  TCCR2B = 0b00000011; // Used 64 Prescaler
  TCNT2 = 0;           // Reset TCNT2
  OCR2B = 0;           // Initial the Output Compare register A &amp; B</pre>
<pre>  duty_cyc_a=(unsigned char) rand() % 255;
  led_a=1;
  duty_cyc_b=(unsigned char) rand() % 255;
  led_b=1;
  duty_cyc_c=(unsigned char) rand() % 255;
  led_c=1;</pre>
<pre>  sei();               // Enable Interrupt</pre>
<pre>  song_index=0;
  tempo=0;

  for(;;) {            // Loop Forever
	// Playing "What a Wonderfull World" Song Notes
	PlayNotes(G4,300 + tempo); PlayNotes(A4,100 + tempo);
        PlayNotes(C5,500 + tempo); PlayNotes(C5,450 + tempo);
	PlayNotes(G5,1150 + tempo); PlayNotes(A5,350 + tempo);
        PlayNotes(A5,350 + tempo); PlayNotes(A5,150 + tempo);
	PlayNotes(G5,1150 + tempo); PlayNotes(F5,450 + tempo);
        PlayNotes(F5,300 + tempo); PlayNotes(F5,250 + tempo);
	PlayNotes(E5,1150 + tempo); PlayNotes(D5,600 + tempo);
        PlayNotes(E5,175 + tempo); PlayNotes(D5,100 + tempo);
	PlayNotes(C5,1050 + tempo);</pre>
<pre>	PlayNotes(C5,550 + tempo); PlayNotes(C5,175 + tempo);
        PlayNotes(C5,100 + tempo); PlayNotes(C5,100 + tempo);
	PlayNotes(C5,150 + tempo); PlayNotes(C5,1300 + tempo);
        PlayNotes(C5,600 + tempo); PlayNotes(B4,200 + tempo);
	PlayNotes(C5,200); PlayNotes(D5,200 + tempo);</pre>
<pre>	if (song_index &gt;= 1) {
	  PlayNotes(C5,1600 + tempo);</pre>
<pre>	  if (song_index == 3) {
	    _delay_ms(100 + tempo);
	    PlayNotes(C5,550 + tempo); PlayNotes(C5,175 + tempo);
            PlayNotes(C5,100 + tempo); PlayNotes(C5,100 + tempo);
	    PlayNotes(C5,150 + tempo); PlayNotes(C5,1300 + tempo);
            PlayNotes(C5,800 + tempo); PlayNotes(B4,400 + tempo);
	    PlayNotes(C5,300 + tempo); PlayNotes(D5,300 + tempo);
            PlayNotes(C5,2300 + tempo);</pre>
<pre>	    song_index = 0;
	  } else {
	    song_index=2;
      }
    } else {
	  PlayNotes(E5,1100 + tempo); PlayNotes(E5,800 + tempo);
          PlayNotes(D5,1600 + tempo);
	  song_index=1;
    }</pre>
<pre>    if (song_index == 2) {
      _delay_ms(100 + tempo);</pre>
<pre>      PlayNotes(C5,450 + tempo); PlayNotes(D5,150 + tempo);
      PlayNotes(D5,50 + tempo); PlayNotes(D5,50 + tempo);
      PlayNotes(D5,1 + tempo); PlayNotes(D5,1000 + tempo);
      PlayNotes(G4,450 + tempo); PlayNotes(E5,150 + tempo);
      PlayNotes(E5,50 + tempo); PlayNotes(E5,50 + tempo);
      PlayNotes(E5,1 + tempo); PlayNotes(E5,1000 + tempo);</pre>
<pre>      PlayNotes(C5,350 + tempo); PlayNotes(D5,250 + tempo);
      PlayNotes(D5,100 + tempo); PlayNotes(D5,75 + tempo);
      PlayNotes(D5,350 + tempo); PlayNotes(C5,150 + tempo);
      PlayNotes(D5,250 + tempo); PlayNotes(E5,1000 + tempo);
      PlayNotes(E5,250 + tempo); PlayNotes(G5,175 + tempo);
      PlayNotes(A5,450 + tempo); PlayNotes(A5,100 + tempo);</pre>
<pre>      PlayNotes(E5,150 + tempo); PlayNotes(G5,1000 + tempo);
      PlayNotes(A5,100 + tempo); PlayNotes(A5,50 + tempo);
      PlayNotes(E5,150 + tempo); PlayNotes(G5,1000 + tempo);	

      PlayNotes(A5,100 + tempo); PlayNotes(A5,50 + tempo);
      PlayNotes(E5,150 + tempo); PlayNotes(G5,1000 + tempo);
      PlayNotes(F5,450 + tempo); PlayNotes(E5,650);
      PlayNotes(D5,1300 + tempo);</pre>
<pre>      song_index =3;
    }
  }

  return 0;	           // Standard Return Code
}</pre>
<pre>/* EOF: avrpwm04.c */</pre>
<p>From the C code above you could see that we use all the available AVR ATMega168 microcontroller PWM sources to drive both the RGB LED and at the same time playing &#8220;<em>What a Wonderful  World</em>&#8221; song.  By using the TIMER1 overflow interrupt (<strong>TOIE1=1</strong> in TIMER1 interrupt mask register <strong>TIMSK1</strong>) we could display the RGB LED and at the same time playing the song notes.</p>
<p>The RGB LED PWM duty cycle is achieved by assigning both random value and the 16-bit TIMER1 counter value (<strong>TCNT1H</strong> and <strong>TCNT1L</strong>) to the Output Compare Register (<strong>OCRn</strong>) in <strong>ISR(TIMER1_OVF_vect)</strong> function routine. With this method we could get the desired RGB LED light effect which is depend on the song notes. Of course you could experiment with other register value as well (e.g . <strong>ICR1H</strong> and <strong>ICR1L</strong> registers).</p>
<p>Now it&#8217;s time to watch all the basic AVR PWM experiments we&#8217;ve done on this following video:</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="480" height="390" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/cITU3DiV3Bo?fs=1&amp;hl=en_US" /><embed type="application/x-shockwave-flash" width="480" height="390" src="http://www.youtube.com/v/cITU3DiV3Bo?fs=1&amp;hl=en_US" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p><strong>The Final Thought</strong></p>
<p>Knowing the basic working principal of the Atmel AVR microcontroller PWM peripheral is one of knowledge that should be learned by anyone who want to involve in the embedded world professionally or just as a hobbyists. I hope this basic AVR PWM tutorial will give you a solid AVR PWM knowledge to be used in your next embedded project.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ermicro.com/blog/?feed=rss2&amp;p=1971</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Quick and Efficiently Wiring Your Prototype Circuit Board</title>
		<link>http://www.ermicro.com/blog/?p=1940</link>
		<comments>http://www.ermicro.com/blog/?p=1940#comments</comments>
		<pubDate>Wed, 02 Feb 2011 13:11:12 +0000</pubDate>
		<dc:creator>rwb</dc:creator>
				<category><![CDATA[Yet Another Tips]]></category>
		<category><![CDATA[AWG]]></category>
		<category><![CDATA[PCB]]></category>
		<category><![CDATA[PROTOTYPE]]></category>
		<category><![CDATA[WIRING]]></category>

		<guid isPermaLink="false">http://www.ermicro.com/blog/?p=1940</guid>
		<description><![CDATA[Many times we need to quick wiring the electronic circuit on the prototype board (perforator board). One of the problems wiring this kind of prototyping board using the ordinary wire (PTFE insulated wire) is it become difficult and looks clumsy when the electronic circuit become complex, especially if we want to rewire the same terminal [...]]]></description>
				<content:encoded><![CDATA[<p>Many times we need to quick wiring the electronic circuit on the prototype board (perforator board). One of the problems wiring this kind of prototyping board using the ordinary wire (PTFE insulated wire) is it become difficult and looks clumsy when the electronic circuit become complex, especially if we want to rewire the same terminal more than once.<span id="more-1940"></span> Now take a look at this prototype board wiring method used in &#8220;<a title="LM324 Op-Amp Line Follower Robot with Pulse Width Modulation" href="http://www.ermicro.com/blog/?p=1908" target="_blank">LM324 Op-Amp Line Follower Robot with Pulse Width Modulation</a>&#8221; article on this blog.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/02/proto_wire_00.jpg"><img class="alignnone size-full wp-image-1941" title="proto_wire_00" src="http://www.ermicro.com/blog/wp-content/uploads/2011/02/proto_wire_00.jpg" alt="" width="580" height="260" /></a></p>
<p>From the above picture you could see that I used the copper enameled wire that you could easily found in many discarded electrical transformator. You could use any enameled copper with the AWG (American Wage Gauge) number 25 to 30 (0.45466 mm to 0.254 mm) for wiring your board. Any non switching 250mA to 1000mA discarded wall adapter transformator are a good candidate for the copper enameled wire sources or you could buy it on your local electric/electronic store.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/02/proto_wire_01.jpg"><img class="alignnone size-full wp-image-1942" title="proto_wire_01" src="http://www.ermicro.com/blog/wp-content/uploads/2011/02/proto_wire_01.jpg" alt="" width="579" height="433" /></a></p>
<p>Before applying solder thin on this wire, you need to remove the enameled layer at the soldering point with the utility knife and use tweezers to place the wire on the board. You could also use the glue gun and apply small amount of it to the enameled wire group to make them stiffer and stable.</p>
<p><a href="http://www.ermicro.com/blog/wp-content/uploads/2011/02/proto_wire_03.jpg"><img class="alignnone size-full wp-image-1943" title="proto_wire_03" src="http://www.ermicro.com/blog/wp-content/uploads/2011/02/proto_wire_03.jpg" alt="" width="582" height="452" /></a></p>
<p>Using this wiring method you could easily populate more electronics components in relatively small prototype board and opening the possibility to hand wiring the surface mount components (SMC) such as the TQFP (Thin Quad Flat Pack) and SOIC (Small Out-Line Integrated Circuit) which is found in many microcontroller package.  Hoping this tip could help you prototype your own project quickly and efficiently&#8230; Happy wiring&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ermicro.com/blog/?feed=rss2&amp;p=1940</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
