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

<channel>
	<title>LPC2148 Tutorials - OCFreaks!</title>
	<atom:link href="https://www.ocfreaks.com/cat/embedded/lpc2148-tutorials/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.ocfreaks.com/cat/embedded/lpc2148-tutorials/</link>
	<description>Overclocking , Gaming , Technology , Robotics &#38; DIY!</description>
	<lastBuildDate>Wed, 04 Dec 2024 06:47:06 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.6.4</generator>
<site xmlns="com-wordpress:feed-additions:1">42777727</site>	<item>
		<title>LPC2148 Servo Motor Interfacing Tutorial</title>
		<link>https://www.ocfreaks.com/lpc2148-servo-motor-interfacing-tutorial/</link>
					<comments>https://www.ocfreaks.com/lpc2148-servo-motor-interfacing-tutorial/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Fri, 13 Jul 2018 11:58:51 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[LPC2148 Tutorials]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3086</guid>

					<description><![CDATA[<p>In this tutorial we go through interfacing and control of servo motors with ARM7 LPC2148 microcontroller. In my previous tutorial I had explained PWM in ARM7 LPC2148, now its time use PWM block and control servos.</p>
<p>The post <a href="https://www.ocfreaks.com/lpc2148-servo-motor-interfacing-tutorial/">LPC2148 Servo Motor Interfacing Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/servo_control_lpc214x_title.png" width="319px" height="175px" /></p>
<p>Hi again folks! In this tutorial we go through interfacing and control of servo motors with ARM7 LPC2148 microcontroller. In my <a href="https://www.ocfreaks.com/lpc2148-pwm-programming-tutorial/" target="_blank">previous tutorial</a> I had explained PWM in ARM7 LPC2148, now its time use PWM block and control servos. RC servos, as the name suggests, are used in RC airplanes, cars and even robots like hexapods, robotic arms, etc. These servos typically accept a PWM signal having a period of 20ms (i.e. a frequency of 50Hz). The commonly used RC servos have a total rotation swing of around 180 degrees(-90 to +90). 0 degree position is called &#8220;neutral&#8221; which is at the center of the total rotation swing, and hence also called the center position. </p>
<ul>
<li>
A pulse width of 500µs or 0.5ms is the minimum pulse width which positions the servo&#8217;s output shaft at -90 degrees. </li>
<li>A pulse width of 1500µs or 1.5ms positions the servo at 0 degree.</li>
<li>Finally a pulse width of 2500µs or 2.5ms is the maximum pulse width which positions the servo at +90 degrees.</li>
</ul>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/std_rc_servo_control_pwm_pulse.png" width="595px" height="340px" alt="Standard servo control pulse for common RC Servo motors" /></p>
<p>With this information, lets proceed with generating a PWM signal to control servo motors using LPC2148.</p>
<div class="special sp_blue noteinfo">PWM signal for RC servos can be generated using Timer or PWM block of LPC214x. Using the PWM block we can generate up to 6 different PWM signals and hence we can control upto 6 servos independently.</div>
<h2 class="shead">Configuring LPC2148 PWM to generate Servo PWM signal</h2>
<h4>Defining the PWM resolution</h4>
<p>Since the PWM pulses vary from 500µs to 2500µs, a resolution of 1µs is more than sufficient. Hence we will configure the PWM block for 1µs resolution and with a period of 20ms(20000µs). Make sure you go through the &#8220;PWM Prescaler (PWMPR) Calculations&#8221; explained in my <a href="https://www.ocfreaks.com/lpc2148-pwm-programming-tutorial/" target="_blank">LPC2148 PWM tutorial</a> previously. As mentioned previously in that tutorial, the basic formula for working the value of PR given resolution is:</p>
<div class="equation" style="font-size:14px;margin-bottom:10px;">Resolution in Seconds = </p>
<div class="fraction"><span class="fup">PR+1</span><span class="bar">/</span><span class="fdn">PCLK in Hz</span></div>
</div>
<p>Since we need resolution is µs scale, we can scale the equation and rewrite it as follows:</p>
<div class="equation" style="font-size:14px;margin-bottom:10px;">Resolution in µs = </p>
<div class="fraction"><span class="fup">PR+1</span><span class="bar">/</span><span class="fdn">PCLK in Mhz</span></div>
</div>
<p>Now, to get the value of PR for 1µs Resolution, given we know and have already set PCLK, can be done as follows:</p>
<div class="equation" style="font-size:14px;margin-bottom:10px;">1 µs Resolution = </p>
<div class="fraction"><span class="fup">PR+1</span><span class="bar">/</span><span class="fdn">PCLK in MHz</span></div>
</div>
<p>Hence,</p>
<div class="equation" style="font-size:14px;margin-bottom:10px;">PR = (1 x PCLK in MHz) &#8211; 1 </div>
<p>Finally, since we will be using CCLK=PCLK=60Mhz, we get PR as follows:</p>
<div class="equation" style="font-size:14px;margin-bottom:10px;">PR = (1 x 60) &#8211; 1  = 59</div>
<p>Visit my <a href="https://www.ocfreaks.com/lpc214x-pll-tutorial-for-cpu-and-peripheral-clock/" target="_blank">tutorial on LPC2148 PLL and Clock setup</a> for more on how to setup CCLK and PCLK.</p>
<h4>Setting up PWM block for 20ms period with output</h4>
<p>Now, assuming both CCLK and PCLK are configured to run at 60Mhz, PWM Block can be configured to control RC Servo as follows:</p>
<div class="highlight">
<ol style="margin-bottom:0px">
<li>Select the PWMx function on the respective IO pin.</li>
<li>Set <strong><span class="code_var">PWMPR = 59</span></strong> to get a resolution of 1us. PWMTC increments every 59+1 Clock cycles @ 60mhz.</li>
<li>Set <strong><span class="code_var">PWMMCR = 0x1</span></strong> (bit0 = 1) to Reset PWMTC on PWMMR0 (and , 0x8= interrupt when PWMMR1 matches PWMTC i.e after PWMMR1 reaches the value assigned to it)</li>
<li>Set <strong><span class="code_var">PWMMR0 = 20000</span></strong> which sets the period to 20ms for all PWM outputs.</li>
<li>Set <strong><span class="code_var">PWMMR1</span></strong> to default PWM pulse time. We will use 1500µs i.e. neutral position.</li>
<li>Set the corresponding bits in <strong><span class="code_var">PWMLER</span></strong> to update the values in match registers.</li>
<li>Set the corresponding bits <strong><span class="code_var">PWMPCR</span></strong> to enable PWMx Output.</li>
</ol>
</div>
<h4>Example to configure &#038; initialize PWM with PWM1 Output:</h4>
<pre><code class="language-cpp">
PINSEL0 |=  (1<<1); //set Bits [1:0] = 10 to select PWM1 for P0.0

PWMPR = 59; //PWMTC increments every 59+1 Clock cycles @ 60mhz to yield a resolution of 1us
PWMMCR = 0x1; //Reset PWMTC on PWMMR0 Match which defines the PWM period
PWMMR0 = 20000; //PWM period of 20ms
PWMMR1 = 1500; //Default Pulse time. Brings servo in neutral position
PWMLER = (1<<0) | (1<<1); //Enable Match 1 &#038; Match 2 Latch to update new values
PWMPCR = (1<<9); //Enable PWM1 Output
PWMTCR = (1<<1); //Reset PWM Counter
PWMTCR = (1<<0) | (1<<3); //IMP! - Enable Counter and PWM
</code></pre>
<h4>Updating new PWM/Pulse values:</h4>
<p>Once PWM1 output is enabled we need to only update PWM match register 1 i.e. PWMMR1 (& PWMLER) with new values to control our servo's position. For updating new Match values to any of the Match register, the corresponding bit in the Latch Enable Register (PWMLER) must be set to 1. After New values are updated the Latch Enable Bit in PWMLER is again reset. Hence, for every update we must set the corresponding bit in PWMLER to 1. This update will happen at the beginning of next PWM period. For more please read the register explanation given in <a href="https://www.ocfreaks.com/lpc2148-pwm-programming-tutorial/" target="_blank">LPC2148 PWM tutorial</a> previously.</p>
<p><strong>Example for updating PWMMR1:</strong></p>
<pre><code class="language-cpp">
while(1) //main control loop
{
 //...
 //..
 PWMMR1 = 900;
 PWMLER |= (1<<1); //Bit[1] corresponds to PWMMR1 Latch
 /*new value will be updated at the beginning of next Period*/
 //..
}
</code></pre>
<h2 class="shead">ARM7 LPC2148 Servo Interfacing examples</p>
<h2>
<h4>Example 1: Simple Servo Control using LPC214x</h4>
<p>In this example we will repeatedly set the servo position to +45, 0, -45 degrees which roughly corresponds to 1ms, 1.5ms and 2ms pulse widths for most RC servos. Here, we will use a delay of 2 seconds between each position. Schematic and Color coding for various servo plugs is also given in the diagram below. Please confirm the color coding of your servo plug before you proceed with any connections.</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/lpc214x_servo_interfacing_wiring_eg.png" width="505px" height="420px" alt="ARM7 LPC2148 Servo Interfacing wiring connections and schematic" /></p>
<div class="special sp_red notewarning"><strong>Note:</strong> Always double check the polarity of your connections going to servo plug. Connecting it in reserve might damage your servo permanently. The Author cannot be held responsible for any damage arising due to wrong connections for any of examples given here.</div>
<p><strong>Source Code:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera - www.ocfreaks.com
LPC2148 Servo Interfacing Tutorial - Example 1
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License: GPL.*/

#include &lt;lpc214x.h&gt;
#include "lib_funcs.h" //OCFreaks LPC214x Tutorials Library Header

int main(void)
{
	initClocks(); //Set PCLK = CCLK = 60Mhz
	initTimer0(); //For delay functions

	PINSEL0 |=  (1<<1); //set Bits [1:0] = 10 to select PWM1 for P0.0

	PWMPR = 59; //PWMTC increments every 59+1 Clock cycles @ 60mhz to yield a resolution of 1us
	PWMMCR = 0x1; //Reset PWMTC on PWMMR0 Match which defines the PWM period
	PWMMR0 = 20000; //PWM period of 20ms
	PWMMR1 = 1500; //Default Pulse time. Brings servo in neutral position
	PWMLER = (1<<0) | (1<<1); //Enable Match 1 &#038; Match 2 Latch to update new values
	PWMPCR = (1<<9); //Enable PWM1 Output
	PWMTCR = (1<<1); //Reset PWM Counter
	PWMTCR = (1<<0) | (1<<3); //IMP! - Enable Counter and PWM

	delayMS(2000); //Initial delay
	
	while(1)
	{
		PWMMR1 = 1000; //1ms Pulse
		PWMLER |= (1<<1); //Set MR1 Latch
		delayMS(2000); //2 Secs Delay
		
		PWMMR1 = 1500; //1.5ms Pulse
		PWMLER |= (1<<1);
		delayMS(2000);
		
		PWMMR1 = 2000; //2ms Pulse
		PWMLER |= (1<<1);
		delayMS(2000);
		
		PWMMR1 = 1500; //1.5ms Pulse
		PWMLER |= (1<<1);
		delayMS(2000);
	}
	
	//return 0; //This won't execute normally
}
</code></pre>
<p><strong>Project Download:</strong></p>
<div class="highlight"><strong>KEIL ARM uV5/uV4 Project for example given above is on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/Servo_Interfacing/Example_1" target="_blank">Servo Interfacing with LPC2148</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/Servo_Interfacing/Example_1" target="_blank">Download Project Zip</a>. You can find the HEX file inside objects folder.</div>
<h4>Example 2: Sweep/Interpolate Servo between two positions with LPC214x</h4>
<p>In this example we will sweep the servo between +45 & -45 degrees. The servo shaft will rotate at constant speed between the two defined locations. Here, we have to play with two parameters which define how smooth and fast will the servo move. These are: the delay between two steps and the step increment. In our case we will use a step increment of 20µs and an inter-step delay of 1 period i.e. 20ms. The wiring is same as shown for example 1.</p>
<p><strong>Source Code:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera - www.ocfreaks.com
LPC2148 Servo Interfacing Tutorial - Example 1
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License: GPL.*/

#include &lt;lpc214x.h&gt;
#include "lib_funcs.h" //OCFreaks LPC214x Tutorials Library Header

int main(void)
{
	initClocks(); //Set PCLK = CCLK = 60Mhz
	initTimer0(); //For delay functions

	PINSEL0 |=  (1<<1); //set Bits [1:0] = 10 to select PWM1 for P0.0

	PWMPR = 59; //PWMTC increments every 59+1 Clock cycles @ 60mhz to yield a resolution of 1us
	PWMMCR = 0x1; //Reset PWMTC on PWMMR0 Match which defines the PWM perioed
	PWMMR0 = 20000; //PWM period of 20ms
	PWMMR1 = 1000; //Default(starting) Pulse time for sweep.
	PWMLER = (1<<0) | (1<<1); //Enable Match 1 &#038; Match 2 Latch to update new values
	PWMPCR = (1<<9); //Enable PWM1 Output
	PWMTCR = (1<<1); //Reset PWM Counter
	PWMTCR = (1<<0) | (1<<3); //IMP! - Enable Counter and PWM

	delayMS(1000); //Initial delay
	
	int step = 20; //In us
	int stepDelay = 20; //In ms 
	int pulse=1000;
	while(1)
	{
		while(pulse<2000)
		{
			PWMMR1 = pulse;
			PWMLER |= (1<<1);
			delayMS(stepDelay);
			pulse = pulse + step;
		}
		while(pulse>1000)
		{
			PWMMR1 = pulse;
			PWMLER |= (1<<1);
			delayMS(stepDelay);
			pulse = pulse - step;
		}
	}
	
	//return 0; //This won't execute normally
}
</code></pre>
<p><strong>Project Download:</strong></p>
<div class="highlight"><strong>KEIL ARM uV5/uV4 Project for example given above is on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/Servo_Interfacing/Example_2" target="_blank">Servo Interfacing with LPC2148</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/Servo_Interfacing/Example_2" target="_blank">Download Project Zip</a>. You can find the HEX file inside objects folder.</div>
<p>The post <a href="https://www.ocfreaks.com/lpc2148-servo-motor-interfacing-tutorial/">LPC2148 Servo Motor Interfacing Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/lpc2148-servo-motor-interfacing-tutorial/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3086</post-id>	</item>
		<item>
		<title>LPC2148 Timer Capture Mode Tutorial with Frequency Counter Example</title>
		<link>https://www.ocfreaks.com/lpc2148-timer-capture-mode-tutorial-frequency-counter-example/</link>
					<comments>https://www.ocfreaks.com/lpc2148-timer-capture-mode-tutorial-frequency-counter-example/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Wed, 21 Mar 2018 17:26:23 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[LPC2148 Tutorials]]></category>
		<category><![CDATA[lpc2148]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3067</guid>

					<description><![CDATA[<p>In this tutorial we will cover how to program capture mode for timer module of ARM7 LPC2148 microcontroller along with a frequency counter example using capture input.</p>
<p>The post <a href="https://www.ocfreaks.com/lpc2148-timer-capture-mode-tutorial-frequency-counter-example/">LPC2148 Timer Capture Mode Tutorial with Frequency Counter Example</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Following the request of some of our readers, in this tutorial we will cover how to program capture mode for timer module of ARM7 LPC2148 microcontroller along with a frequency counter example using capture input. In my previous <a href="https://www.ocfreaks.com/lpc2148-timer-tutorial/" target="_blank">LPC2148 Timer tutorial</a> we saw how to setup and program the timer module.</p>
<h4>A quick recap:</h4>
<p>ARM LPC214x MCUs have two 32-bit-Timer blocks. Each Timer block can be used as a ‘Timer’ or as a ‘Counter’. A timer has a Timer Counter(TC) and Prescale Register(PR) associated with it. TC stores the current value of the count and PR stores a prescalar value. When Timer is Reset and Enabled, TC is set to 0 and incremented by 1 every ‘PR+1’ clock cycles. When it reaches its maximum value it gets reset to 0 and hence restarts counting. PR is used to set the Timer Resolution. When the timer is used in &#8216;Counter&#8217; mode, and external signal is used to increment the value of TC. </p>
<h3>Capture Channels and Input pins</h3>
<p>Each timer block has 4 Capture Channels (CAPn.0 to CAPn.3, n=Timer number) associated with it. Using these Capture channels we can take a snapshot(i.e. capture) of the current value of TC when a signal edge is detected. These channels are mapped to device pins. This mapping of Capture Channel to pins is as given below:</p>
<table class="aligncenter ocf-table" style="margin-bottom:15px; margin-top:15px;">
<tr>
<th colspan="2">Timer0</th>
<th colspan="2">Timer1</th>
</tr>
<tr>
<td>Channel</td>
<td>Pin</td>
<td>Channel</td>
<td>Pin</td>
</tr>
<tr>
<td>CAP0.0</td>
<td>P0.2/P0.22/P0.30</td>
<td>CAP1.0</td>
<td>P0.10</td>
</tr>
<tr>
<td>CAP0.1</td>
<td>P0.4</td>
<td>CAP1.1</td>
<td>P0.11</td>
</tr>
<tr>
<td>CAP0.2</td>
<td>P0.6/P0.16/P0.28</td>
<td>CAP1.2</td>
<td>P0.17/P0.19</td>
</tr>
<tr>
<td>CAP0.3</td>
<td>P0.29</td>
<td>CAP1.3</td>
<td>P0.18/P0.21</td>
</tr>
</table>
<h3>Using Capture Inputs in ARM7 LPC214x</h3>
<p>When using Capture Inputs we use Timer Block in Normal &#8216;<strong>Timer Mode</strong>&#8216; or &#8216;<strong>Counter Mode</strong>&#8216;. </p>
<ol>
<li>In <strong>Timer Mode</strong>, the Peripheral clock is used as a clock source to increment the Timer Counter(TC) every ‘PR+1’ clock cycles. Whenever a signal edge(rising/falling/both) event is detected, the timestamp i.e. the current value of TC is loaded into corresponding Capture Register(CRx) and optionally we can also generate an interrupt every time Capture Register is loaded with a new value. This behavior is configured using CCR. </li>
<li>In <strong>Counter Mode</strong>, external signal is used to increment TC every time an edge(rising/falling/both) is detected. This behavior is configured using CTCR. Corresponding bits for Capture channel must be set to zero in CCR. (See register explanation given below)</li>
</ol>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/timer_module_with_capture_lpc2148.png" width="610px" height="330px" alt="ARM7 LPC2148 Timer Capture Block diagram" /></p>
<p>Here is a simple diagram depicting the capture process. Dashed arrows(for both diagrams) signifiy the events.</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/timer_capture_input_mode_process_lpc_mcu.png" width="520px" height="155px" alt="Microcontroller Input Capture diagram" /></p>
<h2 class="shead">Capture Related Registers:</h2>
<p>Before we start with programming, first lets see the registers. Since I have already discussed main Timer Registers in my <a href="https://www.ocfreaks.com/lpc2148-timer-tutorial/" target="_blank">LPC2148 Timer tutorial</a>, we will only have a look at registers relating to capture.</p>
<div class="highlight"><strong>1) <span class="doc_ref">CCR</span> &#8211; Capture Control Register</strong>: Used to select which type of Egde(rising/falling/both) is used to Capture Registers (CR0-CR3) and optionally to generate an interrupt when a capture event occurs.</p>
<p><strong>For <span class="doc_ref">CR0</span>:</strong></p>
<ul style="margin-bottom:0px;">
<li><strong>Bit 0:</strong> Capture on CAPn.0 rising edge. When set to 1, a transition of 0 to 1 on CAPn.0 will cause CR0 to be loaded with the contents of TC. Disabled when 0.</li>
<li><strong>Bit 1:</strong> Capture on CAPn.0 falling edge. When set to 1, a transition of 1 to 0 on CAPn.0 will cause CR0 to be loaded with the contents of TC. Disabled when 0.</li>
<li><strong>Bit 2:</strong> Interrupt on CAPn.0 event. When set to 1, a CR0 load due to a CAPn.0 event will generate an interrupt. Disabled when 0.</li>
</ul>
<p>Similarly bits 3-5, 6-8, 9-11 are for <strong>CR1, CR2 &#038; CR3</strong> respectively.</p>
<p><strong>2) <span class="doc_ref">CR0 &#8211; CR3</span> &#8211; Capture Registers:</strong> Each capture register is associated with a Capture Pin. Depending on the settings in CCR, CRn can be loaded with current value of TC when a specific event occurs.</p>
<p><strong>3) <span class="doc_ref">CTCR</span> Count Control Register: Used to select between Timer or Counter Mode.</strong><br />
<strong>Bits[1:0]</strong> &#8211; Used to select Timer mode or which Edges can increment TC in counter mode.</p>
<ul style="margin-bottom:0px;">
<li>[00]: Timer Mode. PC is incremented every Rising edge of PCLK.</li>
<li>[01]: Counter Mode. TC is incremented on Rising edges on the CAP input selected by Bits[3:2].</li>
<li>[10]: Counter Mode. TC is incremented on Falling edges on the CAP input selected by Bits[3:2].</li>
<li>[11]: Counter Mode. TC is incremented on Both edges on the CAP input selected by Bits[3:2].</li>
</ul>
<p><strong>Bits[3:2]</strong> &#8211; Count Input Select. Only applicable if above bits are not [00].</p>
<ul style="margin-bottom:0px;">
<li>[00]: Used to select CAPn.0 for TIMERn as Count input.</li>
<li>[01]: Used to select CAPn.1 for TIMERn as Count input.</li>
<li>[10] &#038; [11]: Reserved.</li>
</ul>
</div>
<h2 class="shead">Frequency Counter using LPC2148 Timer Capture</h2>
<h3>Methods to Measure frequency of an external signal</h3>
<h4>We will cover two methods of Measuring Unknown Signal Frequency:</h4>
<ol>
<li><strong>By Gating/Probing</strong> &#8211; In this method we define a Gating Interval in which we count the number of pulses. <strong>What is Gating Time?</strong> &#8211; Gating Time is amount of time for which we probe the input signal. Once we know the no.of. pulses, we can easily deduce the frequency using Gating time. Here we use the external signal as clock source to increment Timer Counter (TC). The value in TC gives the number of pulses counted per Gating Time. This method relies on selecting a proper Gating Time to get valid and accurate results. </li>
<li><strong>By measuring Period using Interrupts</strong> &#8211; In this method we use an Interrupt Service Routine to find out the time between 2 consecutive pulses i.e. period of the Input signal at that particular instant. This is done using an ISR, but ISR itself is main limiting factor for the maximum frequency which can be measured. Compared to first one, this method can give accurate results, given frequency is below measurement limit.</li>
</ol>
<div class="special sp_blue noteinfo">The maximum input signal frequency which can be reliably measured using first method is half of TIMERn_PCLK, since it takes two successive edges of TIMERn_PCLK to detect one edge of external signal. Hence, using a PCLK of 60Mhz we can measure upto 30Mhz signal properly. For second method we can only measure up to around 1 Mhz due to ISR execution delay &#038; context switching overhead.</div>
<p>For measuring Square wave Signal Frequency, external hardware is not required unless the Pulse HIGH Voltage level is > 3.3 Volts, in which case a Voltage divider or Buffer is mandatory. To measure other Signal types like Saw-tooth, Sine wave we will require something that can provide Hysteresis which will define the HIGH &#038; LOW Voltage Threshold, thereby converting it into a Square signal, to detect any of the edges of the unknown signal. This can be done using a Schmitt Trigger Buffer (either Inverting or Non-Inverting &#8211; doesn&#8217;t matter).</p>
<p>For both of examples given below, we will use Timer1 module to measure frequency. Capture Channel CAP1.0 is used as capture input. CAP1.0 is mapped to Pin P0.10 on LPC214x, hence we select CAP1.0 alternate function for P0.10. </p>
<p>To generate a square wave signal, I have used LPC214x&#8217;s inbuilt PWM module which is configured with 0.05 us resolution. PWM2 output channel is used which gives output on Pin P0.7. Refer my <a href="https://www.ocfreaks.com/lpc2148-pwm-programming-tutorial/" target="_blank"> LPC2148 PWM Tutorial </a> for more on PWM. You can also use any external source like a function generator or IC-555 based generator. The example project linked below also contains <a href="https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/" target="_blank">retargeted printf() for KEIL</a> which redirects its output to UART0.</p>
<h4>Schematic</h4>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/lpc2148_input_capture_mode_eg_sch.png" width="425px" height="235px" alt="ARM7 LPC2148 Capture Mode Frequency Counter Measurement Example Schematic" /></p>
<h3>1. Frequency Counter Example using Gating/Probing:</h3>
<p>In this example we will, we use external signal as clock source for Timer1. Every positive going edge will increment the Timer1 Counter (<span class="code_var">T1TC</span>) by 1. To count the number of pulses, we start the timer and wait until Gating time. After that we stop the time and read the value in <span class="code_var">T1TC</span> which gives the no.of. pulses per gating time. For this example I have chosen a gating time of 1 seconds. Obviously, we can get more accurate results using a higher Gating time. For our purpose 1 second is enough to measure signals upto 30Mhz using PCLK=60Mhz. Given Gate time is in ms, the following equation can be used to find the frequency from counted pulses:</p>
<div class="equation">Measured Frequency in Khz = </p>
<div class="fraction"><span class="fup">Counted Pulses</span><span class="bar">/</span><span class="fdn">Gate Time in ms</span></div>
</div>
<p><strong>Source Code Snippet</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera- www.ocfreaks.com
ARM7 LPC2148 Input Capture Tutorial - Example 1 for frequency counter using ARM KEIL
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License: GPL.*/

#include &lt;lpc214x.h&gt;
#include &lt;stdio.h&gt; //visit https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/ 
#include "lib_funcs.h" //OCFreaks LPC214x Tutorials Library Header

void initPWM(void); //To generate Test Square wave
unsigned int pulses = 0;
#define GATE_TIME_MS 1000 //Probing/Gating Time in ms

int main(void)
{
	initClocks(); //Set PCLK = CCLK = 60Mhz - used by: UART, Timer & PWM
	initUART0();  //Initialize UART0 for retargeted printf()
	initTimer0(); //Init Timer for delay functions
	
	//Assuming PCLK = 60Mhz
	PINSEL0 |= (1<<21); //Select CAP1.0 for P0.10
	T1CTCR = 0x1; //Increment TC on rising edges of External Signal for CAP1.0
	T1PR = 0; //0.01667us res, 1 clock cycles @60Mhz = 0.01667 us
	T1TCR = 0x02; //Reset Timer
	T1CCR = (1<<0); //Capture on Rising Edge(0->1)
	T1TCR = 0x01; //Enable timer1

	initPWM(); //To generate square wave
	float FreqKhz = 0;
	printf("OCFreaks.com - Measuring Frequency using LCP2148 Timer Capture Ex 1:\n");
	
	while(1)
	{
		
	  T1TCR = 0x1; //Start Timer2
		delayMS(GATE_TIME_MS); //'Gate' signal for defined Time (1 second)
		T1TCR = 0x0; //Stop Timer2
		
		pulses = T1TC; //Read current value in TC, which contains  no.of. pulses counted in 1s
		T1TCR = 0x2; //Reset Timer2 TC
		
		FreqKhz = (double)pulses/GATE_TIME_MS;
		
		if(FreqKhz >= 1000.0) //Display Freq. In MHz
		{
			printf("Frequency = %0.4f MHz\n", FreqKhz/1000.0);
		}
		else //Display Freq. in KHz
		{
			printf("Frequency = %0.2f KHz\n", FreqKhz);
		}
	}

	//return 0; //This won't execute normally
}

void initPWM(void)
{
	//Refer : https://www.ocfreaks.com/lpc2148-pwm-programming-tutorial/
	/*Assuming that PLL0 has been setup with CCLK = 60Mhz and PCLK also = 60Mhz.*/
	/*This is as per the Setup & Init Sequence given in the tutorial*/

	PINSEL0 |= (1<<15); // Select PWM2 output for Pin0.7
	PWMPCR = 0x0; //Select Single Edge PWM - by default its single Edged so this line can be removed
	PWMPR = 3-1; //3 Clock cycles @60Mhz = 0.05us resoultion
	PWMMR0 = 4; //4x0.05 = 0.2us - period duration i.e. 5MHz frequency
	PWMMR2 = 2; //2x0.05 = 0.1us - pulse duration i.e. width
	PWMMCR = (1<<1); // Reset PWMTC on PWMMR0 match
	PWMLER = (1<<2) | (1<<0); // update MR0 and MR2
	PWMPCR = (1<<10); // enable PWM2 output
	PWMTCR = (1<<1) ; //Reset PWM TC &#038; PR

	//Now, the final moment - enable everything
	PWMTCR = (1<<0) | (1<<3); // enable counters and PWM Mode
	//PWM Generation goes active now!!
}
</code></pre>
<p><strong>Download Example 1 Project Files:</strong></p>
<div class="highlight"><strong>KEIL ARM uV5/uV4 Project for above example</strong> <a href="https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/Frequency_Counter/Example_1" target="_blank">ARM7 LPC214x Frequency Counter Example 1</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/Frequency_Counter/Example_1" target="_blank">Download Project Zip</a>. You can find the HEX file inside objects folder.</div>
<h3>2. Frequency Counter Example using Period Measurement:</h3>
<p>Here, a timer resolution of 0.05 micro-seconds is selected by using Prescaler value of 2 (3-1) and PCLK=CLK=60Mhz. We configure the CCR so that the capture occurs for rising edges and an interrupt is also generated. The Timer1 interrupt handler function is the at core of this example where we are measuring the period of the square wave signal. Refer my <a href="https://www.ocfreaks.com/lpc2148-interrupt-tutorial/" target="_blank">ARM7 LPC2148 Interrupt Tutorial</a> for more. Here we use 3 global variables viz.. <strong><span class="code_var">period</span>, <span class="code_var">previous</span> & <span class="code_var">current</span></strong>. We just update period with the difference of <strong><span class="code_var">current</span></strong> and <strong><span class="code_var">previous</span></strong>. But since the timer counter (TC) is free running, an overflow is bound to occur. So, we need to take care of this condition by detecting an overflow condition which is simply when <strong><span class="code_var">current</span></strong> is less than <strong><span class="code_var">previous</span></strong>. In this situation the time difference is calculated as:</p>
<div class="equation">Corrected Diff = (TC_MAX * OVF_CNT) + Current - Previous</div>
<p>where, <strong>TC_MAX</strong> = Maximum value of TC and <strong>OVF_CNT</strong> = Number of times overflow occurred. Since TC is 32bit, its max value in our case is 0xFFFFFFFF. Also, since we are not measuring extremely low frequency signals <strong>OVF_CNT</strong> will be at max 1. Another thing is that, if <strong>OVF_CNT</strong> is >=2 then we will need a datatype of <span class="code_ref"><strong>long long</strong></span> (8 bytes) to store the result since we won't be able to store the result in <span class="code_ref"><strong>int</strong></span> which is 4 bytes for KEIL ARM compiler.</p>
<p>Hence, the equation boils down to:</p>
<div class="equation">Corrected Diff = 0xFFFFFFFF + Current - Previous</div>
<p>Maximum value for frequency of external signal that can be correctly measured depends on the PCLK, Prescalar (PR) and the Latency of Timer Interrupt Routine execution. Out of the three, the main limiting factor is the interrupt latency. For example code given below, I was able to successfully able to measure square wave signals of upto 1Mhz. This frequency limit is more than enough for real-life applications like tachometer interfacing which I will cover in another tutorial.</p>
<p><strong>Source Code Snippet</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera- www.ocfreaks.com
ARM7 LPC2148 Input Capture Tutorial - Example 2 for frequency counter using ARM KEIL
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License: GPL.*/

#include &lt;lpc214x.h&gt;
#include &lt;stdio.h&gt;   //visit https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/ 
#include "lib_funcs.h" //OCFreaks LPC214x Tutorials Library Header

int main(void)
{
	initClocks(); //Set PCLK = CCLK = 60Mhz - used by: UART, Timer & PWM
	initUART0();  //Initialize UART0 for retargeted printf()
	initTimer0(); //Init Timer for delay functions
	
	//Assuming PCLK = 60Mhz
	PINSEL0 |= (1<<21); //Select CAP1.0 for P0.10
	T1CTCR = 0x0; //Run in Timer Mode
	T1PR = 3-1; //3 Clock cycles @60Mhz = 0.05us resolution
	T1TCR = 0x02; //Reset Timer
	T1CCR = (1<<0) | (1<<2); //Capture on Rising Edge(0->1) and generate an interrupt
	T1TCR = 0x01; //Enable timer1
	
	VICIntEnable |= (1<<5) ; //Enable TIMER1 IRQ
	VICVectCntl0 = (1<<5) | 5; //5th bit must 1 to enable the slot. Refer: https://www.ocfreaks.com/lpc2148-interrupt-tutorial/
	VICVectAddr0 = (unsigned) timer1ISR;

	initPWM(); //Generate Test square wave
	
	printf("OCFreaks.com - Measuring Frequency using Timer Capture\n");
	double frequencyMhz = 0;
	while(1)
	{
		frequencyMhz = (1.0 / (period*0.05) ) * 1000; //0.05 is Timer resolution in us
		printf("Frequency = %0.2f Khz\n",frequencyMhz);
		delayMS(500); //2 Udpates per second
	}
	
	//return 0; //This won't execute normally
}

__irq void timer1ISR(void)
{
	current = T1CR0;

	if(current < previous) //TC has overflowed
	{
		period = 0xFFFFFFFF + current - previous;
	}
	else
	{
		period = current - previous;
	}
	
	previous = T1CR0;
	
	T1IR = (1<<4); //write back to clear the interrupt flag
	VICVectAddr = 0x0; //Acknowledge that ISR has finished execution
}

void initPWM(void)
{
	//Refer : https://www.ocfreaks.com/lpc2148-pwm-programming-tutorial/
	/*Assuming that PLL0 has been setup with CCLK = 60Mhz and PCLK also = 60Mhz.*/
	/*This is as per the Setup &#038; Init Sequence given in the tutorial*/

	PINSEL0 |= (1<<15); // Select PWM2 output for Pin0.7
	PWMPCR = 0x0; //Select Single Edge PWM - by default its single Edged so this line can be removed
	PWMPR = 3-1; //3 Clock cycles @60Mhz = 0.05us
	PWMMR0 = 20; //20x0.05 = 1us - period duration i.e. 1MHz frequency
	PWMMR2 = 10; //10x0.05 = 0.5us - pulse duration i.e. width
	PWMMCR = (1<<1); // Reset PWMTC on PWMMR0 match
	PWMLER = (1<<2) | (1<<0); // update MR0 and MR2
	PWMPCR = (1<<10); // enable PWM2 output
	PWMTCR = (1<<1) ; //Reset PWM TC &#038; PR

	//Now, the final moment - enable everything
	PWMTCR = (1<<0) | (1<<3); // enable counters and PWM Mode
	//PWM Generation goes active now!!
}
</code></pre>
<p>In the Frequency Counter Program given above, you can increase the values for PWMMR0 and PWMMR2 to measure other lower frequencies. Trying measure frequencies >1Mhz will yield in incorrect measurement.</p>
<div class="highlight"><strong>KEIL ARM uV5/uV4 Project for above example</strong> <a href="https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/Frequency_Counter/Example_2" target="_blank">ARM7 LPC214x Frequency Counter Example 2</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/Frequency_Counter/Example_2" target="_blank">Download Project Zip</a>. You can find the HEX file inside objects folder.</div>
<p>The post <a href="https://www.ocfreaks.com/lpc2148-timer-capture-mode-tutorial-frequency-counter-example/">LPC2148 Timer Capture Mode Tutorial with Frequency Counter Example</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/lpc2148-timer-capture-mode-tutorial-frequency-counter-example/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3067</post-id>	</item>
		<item>
		<title>Interfacing HC-SR04 Ultrasonic Distance Sensor with LPC2148</title>
		<link>https://www.ocfreaks.com/interfacing-hc-sr04-ultrasonic-distance-sensor-lpc2148/</link>
					<comments>https://www.ocfreaks.com/interfacing-hc-sr04-ultrasonic-distance-sensor-lpc2148/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Tue, 09 Jan 2018 11:10:50 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[LPC2148 Tutorials]]></category>
		<category><![CDATA[lpc2148]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3051</guid>

					<description><![CDATA[<p>In this tutorial we will see how to interface an Ultrasonic distance sensor (HC-SR04) with ARM7 LPC2148 microcontroller.  HC-SR04 Ultrasonic Distance/Ranging Sensor uses ultrasound to measure distance from a object ahead of the sensor. It is similar to SONAR in concept.</p>
<p>The post <a href="https://www.ocfreaks.com/interfacing-hc-sr04-ultrasonic-distance-sensor-lpc2148/">Interfacing HC-SR04 Ultrasonic Distance Sensor with LPC2148</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this tutorial we will see how to interface an Ultrasonic distance sensor (HC-SR04) with ARM7 LPC2148 microcontroller. As the name suggests, the HC-SR04 Ultrasonic Distance/Ranging Sensor uses ultrasound to measure distance from a object ahead of the sensor. Ultrasound is a sound wave with frequency greater than the audible limit i.e. > 20Khz. HCSR-04 uses 40Khz ultrasound to measure distance between itself and any object ahead of it with a sensing range of 2 centimeters to 4 meters.</p>
<p><strong>Pinout:</strong> The module has got 4 pins viz. VCC(+5V), TRIG, ECHO, GND.</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/hcsr04_pinout.png" alt="HC-SR04 Sensor Pinout" width="275px" height="145px" /></p>
<h4>Working principle</h4>
<p>Ultrasonic Distance/Ranging Sensors are based on similar working principle to what is used in SONAR. It has got two transducers, one for transmitting ultrasound and second one for receiving the echo. Based on the time it takes for echo to arrive we can compute the distance, since we already know the speed of sound in air which is around 343 m/s or 1235 km/h (at 20°C).</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/hcsr04_working_principle.png" alt="HC-SR04 Ultrasonic Distance Sensor Working Principle" width="270px" height="230px" /></p>
<p><strong>Interfacing Steps:</strong></p>
<ol>
<li>To start distance measurement a short pulse of 10us is applied to Trigger pin.</li>
<li>After this the HC-SR04 Module will send a burst of 8 ultrasonic pulses at 40Khz.</li>
<li>It will then output a HIGH for the amount to time taken for the sound waves to reach back.</li>
<li>The pulse HIGH time is measured and then used to calculate the distance.</li>
</ol>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/hcsr04_timing_diagram.png" alt="HC-SR04 Timing Diagram waveform" width="560px" height="180px" /></p>
<h4>Distance calculations:</h4>
<p>We know speed of sound in air,</p>
<div class="equation">Vs = 343 m/s = 0.0343 cm/us</div>
<p>We also know the time it took to sound waves to emit and echo back, lets call it T. Now, by using basic distance formula we can find the distance as:</p>
<div class="equation">Distance Traveled = Speed x Time taken</div>
<div class="equation">D<sub>T</sub> = 343 <sub>m/s</sub> x T <sub>seconds</sub></div>
<p>Now, since we will be measuring ECHO ON-Time in microseconds and also to get distance in centimeters we can change the units as follows:</p>
<div class="equation">D<sub>T</sub> in cm = 0.0343 <sub>cm/us</sub> x T <sub>us</sub></div>
<p>After this we divide the computed value by 2 since the waves have traveled double distance.</p>
<div class="equation">D = </p>
<div class="fraction"><span class="fup">D<sub>T</sub></span><span class="bar">/</span><span class="fdn">2</span></div>
<p> = </p>
<div class="fraction"><span class="fup">0.0343 x T</span><span class="bar">/</span><span class="fdn">2</span></div>
<p> cm</p></div>
<h4>HC-SR04 Ultrasonic sensor Interfacing with ARM7 LPC2148 Example</h4>
<p>Now, lets do a programming exercise. For the interfacing example given below, P0.2 is configured as output and connected to TRIG pin and P0.3 is configured as input and connected to ECHO pin of the Ultrasonic Distance sensor. Timer0 module is used for generating delays with 1 us resolution. It is also used to measure time for ECHO pulse using two simple functions viz. <span class="code_var">startTimer0()</span> &#038; <span class="code_var">stopTimer0()</span>. You can check the project source code linked below for implementation details. The distance data is sent to Terminal via UART0. You can refer my <a href="https://www.ocfreaks.com/lpc2148-uart-programming-tutorial/" target="_blank">LPC2148 UART Tutorial</a> for more. The example source code also contains <a href="https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/" target="_blank">retargeted printf() for KEIL</a> which redirects its output to UART0.</p>
<div class="special sp_blue noteinfo">The HC-SR04 Ultrasonic module operates on 5Volts and hence the output HIGH on ECHO pin is also 5V. We can directly interface this on any of the GPIO pin which has a 5V tolerant pad. But its better to use a voltage divider (using 2KΩ and 1KΩ resistors) to get input from ECHO pin for additional safety. Note that we don&#8217;t need to translate 3.3V to 5V for TRIG pin since 3.3V is already a HIGH for TTL compatible input pins.</div>
<p><strong>Schematic:</strong></p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/lpc214x_hcsr04_interface.png" alt="Interfacing schematic circuit diagram for HC-SR04 with ARM7 LPC2148" width="500px" height="290px" /></p>
<p><strong>Source Code:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera- www.ocfreaks.com
Interfacing HC-SR04 Ultrasonic Distance/Ranging sensor with LPC2148 - Example Source Code for KEIL ARM.
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License: GPL.*/

#include &lt;lpc214x.h&gt;
#include &lt;stdio.h&gt; //visit https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/ 
#include "lib_funcs.h" //OCFreaks LPC214x Tutorials Library Header

#define TRIG (1<<2) //P0.2
#define ECHO (1<<3) //P0.3

int main(void)
{
	initClocks(); //Set PCLK = CCLK = 60Mhz - used by: UART, Timer and ADC
	initUART0();  //Initialize UART0 for retargeted printf()
	initTimer0(); //Init Timer for delay functions
	int echoTime=0;
	float distance=0;

	IO0DIR |= TRIG;    //Set P0.2(TRIG) as output
	IO0DIR &#038;= ~(ECHO); //Set P0.3(ECHO) as input (explicitly)
	IO0CLR |= TRIG;    //Set P0.2 LOW initially

	printf("OCFreaks.com LPC214x HC-SR04 Sensor Interfacing Tutorial\n");

	while(1)
	{
		//Output 10us HIGH on TRIG pin
		IO0SET |= TRIG;
		delayUS(10);
		IO0CLR |= TRIG;

		while(!(IO0PIN &#038; ECHO)); //Wait for a HIGH on ECHO pin
		startTimer0(); //Start counting
		while(IO0PIN &#038; ECHO); //Wait for a LOW on ECHO pin
		echoTime = stopTimer0(); //Stop counting and save value(us) in echoTime

		distance = (0.0343 * echoTime)/2; //Find the distance

		printf("Distance = %0.2fcm\n",distance);
		
		delayMS(1000); //wait 1 second for next update
	}
	
	//return 0; //This won't execute normally
}
</code></pre>
<p><strong>Screenshot:</strong></p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/lpc214x_hcsr04_ss.png" alt="HC-SR04 Demo Screenshot" width="501px" height="418px" /></p>
<p><strong>Download Project:</strong></p>
<div class="highlight"><strong>KEIL ARM uV5/uV4 Project for example given above is on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/HC-SR04_Interfacing" target="_blank">HCSR04 Ultrasonic Distance Sensor Interfacing with LPC2148</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/HC-SR04_Interfacing" target="_blank">Download Project Zip</a>. You can find the HEX file inside objects folder.</div>
<p>The post <a href="https://www.ocfreaks.com/interfacing-hc-sr04-ultrasonic-distance-sensor-lpc2148/">Interfacing HC-SR04 Ultrasonic Distance Sensor with LPC2148</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/interfacing-hc-sr04-ultrasonic-distance-sensor-lpc2148/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3051</post-id>	</item>
		<item>
		<title>Interfacing IR Sensor with ARM7 LPC2148</title>
		<link>https://www.ocfreaks.com/interfacing-ir-sensor-arm7-lpc2148/</link>
					<comments>https://www.ocfreaks.com/interfacing-ir-sensor-arm7-lpc2148/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Thu, 28 Dec 2017 15:21:15 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[LPC2148 Tutorials]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3048</guid>

					<description><![CDATA[<p>In this tutorial we will see how to interface an IR(Infra-Red) photo-diode with ARM7 LPC2148 microcontroller. An IR photodiode is a photodiode which is sensitive to IR light. An IR diode pair i.e. an IR Photodiode along with an IR LED can be used to sense obstacle or as proximity sensor.</p>
<p>The post <a href="https://www.ocfreaks.com/interfacing-ir-sensor-arm7-lpc2148/">Interfacing IR Sensor with ARM7 LPC2148</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this tutorial we will see how to interface an IR(Infra-Red) photo-diode with ARM7 LPC2148 microcontroller. A photodiode is a diode but additionally also converts light i.e. incident photons into electrical current. An IR photodiode is a photodiode which is sensitive to IR light. These photodiodes are easily identifiable since they are black. An IR diode pair i.e. an IR Photodiode along with an IR LED can be used to sense obstacle or as proximity sensor. It is also used in line-follower robots.</p>
<h4>Working principle</h4>
<p>IR LED is used as a source of Infra-Red light (Transmitter). A revered-biased IR photodiode (Sensor,Receiver) is used to detect any IR light reflected from objects in front of the pair. When reflected IR light falls on the IR photodiode it generates a small amount of current corresponding to amount of incident light and in this way it acts as an IR sensor. We can then convert this current into voltage to interface with a micrcontroller using ADC. The analog output can also be converted into 1-bit digital output using a comparator. Commonly available IR modules include a comparator(Op-AMP) or a schmitt-trigger and provide 1-bit digital output (HIGH/LOW) to indicate whether an obstacle is present or not. This makes it easy to interface IR diode pair without using ADC.</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/electronics/common/ir_sensor_working_principle.png" alt="IR sensor diode working principle" width="350px" height="155px" /></p>
<h4>IR Photodiode/LED pair (Rx/Tx) and Modules:</h4>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/electronics/common/ir_diode_pair_modules.jpg" alt="IR photodiode-led RX-TX pair and Proximity sensor line follower Modules" width="565px" height="260px" /></p>
<h2 class="shead">Converting Photo Diode current to Voltage</h2>
<p>We can convert the IR photodiode(IR Sensor) current into proportional voltage by using a Load Resistance R<sub>L</sub>. The reverse bias photodiode current (I<sub>PD</sub>) flowing through the Load Resistance creates a voltage drop which we can measure. Note that the photodiode is reverse biased and a bias voltage is given. This configuration is also known as photoconductive mode. The configuration where bias voltage is absent is called Photovoltaic mode.</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/electronics/common/ir_photodiode_current_voltage.png" alt="Convert Infra-Red IR photodiode Current to Voltage with Bias" width="425px" height="215px" /></p>
<p>We can also use an Op-AMP/Comparator to convert analog signal into digital signal using a potentiometer to set a threshold voltage which defines the sensing or triggering distance. In the diagram given below, the voltage drop is fed into non-inverting pin of LM393 Comparator as Vin. The middle leg of a 10K potentiometer is connected to inverting pin of LM393 Comparator as Vref which sets the thresholds. Depending on Vin and Vref, the comparator output is either HIGH i.e. Logic 1 or LOW i.e. Logic 0. The condition when the output is either 1 or 0 is given in the diagram. For the circuit given below a HIGH means an obstacle is detected and a LOW means no obstacle is detected. Instead of LM393 you can use any general purpose Op-AMP like LM358/LM324 as a comparator.</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/electronics/common/ir_proximity_sensor_opamp_comparator.png" alt="IR Proximity sensor obstacle avoidance using LM393 LM358 LM324 op-amp comparator" width="555px" height="210px" /></p>
<p>Similar kind of circuit is present on IR modules used for proximity sensing, obstacle detection, etc. The potentiometer on these modules is used to set the sensing range/distance. Some IR modules used for line-following robots incorporate a schmitt trigger i.e IC 7414 to convert output to digital(HIGH/LOW). The hysteresis curve of schmitt trigger defines a fixed sensing range/distance in these modules.</p>
<h2 class="shead">IR Interfacing Examples with ARM7 LPC2148</h2>
<h4>Interfacing IR photodiode using LPC214x ADC</h4>
<p>In this example we will convert the reverse bias current of IR photodiode into proportional voltage using a 10K resistor in presence of 3.3V(Vcc) biasing voltage. We will use the inbuilt ADC of LPC2148 to convert the voltage into digital readings. You can check my <a href="https://www.ocfreaks.com/lpc2148-adc-programming-tutorial/" target="_blank">ADC Tutorial</a> for more. We can set a threshold for the digital values to define sensing range. The ADC readings are inversely proportional to the proximity of an object in front. The code is very similar to <a href="https://www.ocfreaks.com/interfacing-ldr-lpc2148/" target="_blank">LDR Interfacing tutorial</a>. The example project linked below also contains <a href="https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/" target="_blank">retargeted printf() for KEIL</a> which redirects its output to UART0.</p>
<p><strong>Schematic:</strong><br />
<img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/lpc214x_ir_interfacing_analog.png" alt="Interfacing IR photodiode with LPC2148" width="425px" height="240px" /></p>
<p><strong>Example 1 Source Code:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera- www.ocfreaks.com
LPC2148 IR Sensor Interfacing Example 1 Source Code for KEIL ARM.
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
Also see: https://www.ocfreaks.com/lpc2148-adc-programming-tutorial/
License: GPL.*/

#include &lt;lpc214x.h&gt;
#include &lt;stdio.h&gt; //visit https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/ 
#include "lib_funcs.h" //OCFreaks LPC214x Tutorials Library Header

#define AD06 ((1<<9)|(1<<8)) //Select AD0.6 function for P0.4
#define SEL_AD06 (1<<6)
#define CLKDIV (15-1) // 4Mhz ADC clock (ADC_CLOCK=PCLK/CLKDIV) where "CLKDIV-1" is actually used , in our case PCLK=60mhz  
#define BURST_MODE_OFF (0<<16) // 1 for on and 0 for off
#define PowerUP (1<<21)
#define START_NOW ((0<<26)|(0<<25)|(1<<24)) //001 for starting the conversion immediately
#define ADC_DONE (1UL<<31)

#define VREF 3.3 //Reference Voltage at VREF pin

int main(void)
{
	initClocks(); //Set PCLK = CCLK = 60Mhz - used by: UART, Timer and ADC
	initUART0(); //Initialize UART0 for retargeted printf()
	initTimer0(); //Init Timer for delay functions
	
	PINSEL0 |= AD06 ; //select AD0.6 for P0.4
	int result = 0;
	unsigned long AD0CR_setup = (CLKDIV<<8) | BURST_MODE_OFF | PowerUP; //Setup ADC block
	
	printf("OCFreaks.com LPC214x IR Sensor Interfacing Tutorial - Example 1.\n");
	
	while(1)
	{
		AD0CR =  AD0CR_setup | SEL_AD06; 
		AD0CR |= START_NOW; //Start new Conversion

		while( (AD0DR6 &#038; ADC_DONE) == 0 );
		
		result = (AD0DR6>>6) & 0x3FF; //get the 10bit ADC result

		printf("AD0.6 = %d\n" , result); //Print raw ADC values corresponding to IR photo-diode reverse current 
		delayMS(500); //Slowing down Updates to 2 Updates per second
	}
	
	//return 0; //This won't execute normally
}
</code></pre>
<div class="highlight"><strong>KEIL ARM uV5/uV4 Project for example given above is on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/IR_Interfacing/Example_1" target="_blank">IR Sensor Interfacing Example 1</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/IR_Interfacing/Example_1" target="_blank">Download Project Zip</a>. You can find the HEX file inside objects folder.</div>
<h4>Interfacing IR Proximity-Sensor/Obstacle-avoidance Module with ARM7 LPC2148 using GPIO</h4>
<p>In this example will interface the IR module using Pin P0.2. Check the output logic of your IR module and edit the code accordingly. For commonly available IR Proximity Sensor modules, a LOW output means an Obstacle is detected else output is HIGH. For line-follower IR modules based on Schimtt-trigger, a HIGH output means an Obstacle is detected else output is LOW. </p>
<p><strong>Schematic:</strong><br />
<img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/lpc214x_ir_module.png" alt="Interfacing IR proximity sensor module with LPC2148" width="310px" height="220px" /></p>
<p><strong>Example 2 Source Code:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera- www.ocfreaks.com
LPC2148 IR Proximity/Obstacle-avoidance Sensor Interfacing Example 2 Source Code for KEIL ARM.
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License: GPL.*/

#include &lt;lpc214x.h&gt;
#include &lt;stdio.h&gt; //visit https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/ 
#include "lib_funcs.h" //OCFreaks LPC214x Tutorials Library Header
#define PIN0_2 (1<<2)

int main(void)
{
	initClocks(); //Set PCLK = CCLK = 60Mhz - used by: UART, Timer
	initUART0(); //Initialize UART0 for retargeted printf()
	initTimer0(); //Init Timer for delay functions

	printf("OCFreaks.com LPC214x IR Sensor Interfacing Tutorial - Example 2.\n");
	
	while(1)
	{
		//Check the O/P Logic of your IR module. Mine gives LOW when obstacle is detected else HIGH.
		if((IO0PIN &#038; PIN0_2) == 0 ) 
		{
			printf("Obstacle Detected!\n");
		}
		else
		{
			printf("No Obstacle ahead.\n");
		}

		delayMS(500); //Slowing down Updates to 2 Updates per second
	}
	
	//return 0; //This won't execute normally
}
</code></pre>
<div class="highlight"><strong>KEIL ARM uV5/uV4 Project for example given above is on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/IR_Interfacing/Example_2" target="_blank">IR Module Interfacing Example 2</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/IR_Interfacing/Example_2" target="_blank">Download Project Zip</a>. You can find the HEX file inside objects folder.</div>
<p>The post <a href="https://www.ocfreaks.com/interfacing-ir-sensor-arm7-lpc2148/">Interfacing IR Sensor with ARM7 LPC2148</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/interfacing-ir-sensor-arm7-lpc2148/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3048</post-id>	</item>
		<item>
		<title>Interfacing ADXL335 Accelerometer with LPC2148</title>
		<link>https://www.ocfreaks.com/interfacing-adxl335-accelerometer-lpc2148/</link>
					<comments>https://www.ocfreaks.com/interfacing-adxl335-accelerometer-lpc2148/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Wed, 06 Dec 2017 17:05:30 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[LPC2148 Tutorials]]></category>
		<category><![CDATA[lpc2148]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3030</guid>

					<description><![CDATA[<p>This time we will go through a tutorial on interfacing ADXL335 Accelerometer with ARM7 LPC2148 microcontroller. ADXL335 is a 3-axis acceleration sensor with analog outputs for each axis.</p>
<p>The post <a href="https://www.ocfreaks.com/interfacing-adxl335-accelerometer-lpc2148/">Interfacing ADXL335 Accelerometer with LPC2148</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>This time we will go through a tutorial on interfacing ADXL335 Accelerometer with ARM7 LPC2148 microcontroller. ADXL335 is a 3-axis acceleration sensor with analog outputs for each axis. The analog outputs are proportional to acceleration along each of the orthogonal axis. It has a minimum measurement range of <strong>±3<em>g</em></strong> where <strong><em>g</em></strong> is acceleration due to gravity at the earth&#8217;s surface (9.8m/s<sup>2</sup>). Most common applications include tilt, motion and shock sensing. The voltage supply range for ADXL335 is 1.8V to 3.6V. ADXL335 is available in 16-lead LFCSP_LQ package.</p>
<h4>Output Voltage:</h4>
<p>The output voltage(hence sensitivity) for each of the axis is directly proportional(ratiometric) with the supply voltage used. The <strong>Zero <em>g</em></strong> bias output is also proportional to the supply voltage. The <strong>Zero <em>g</em></strong> output voltage is typically <span class="doc_ref"><strong>Vs/2</strong></span> for any given valid supply voltage.</p>
<h4>Sensitivity:</h4>
<p>Sensitivity is also termed as scale factor for ADXL335 sensor is given in &#8220;<strong>milli-volts(or volts) per <em>g</em></strong>&#8221; i.e. <strong>mV/g(or V/g)</strong>. For a given Supply Voltage <strong>Vs</strong>, the sensitivity is typically <strong><span class="doc_ref">0.1xVs V/g</span></strong> or <strong><span class="doc_ref">Vsx100 mV/g</span></strong>. Hence for a <strong>Vs = 3.3V</strong> the sensitivity will be typically <strong>330mV/g</strong> or <strong>0.33V/g</strong>. We will use V/g as unit for sensitivity in the example shown later on.</p>
<h4>Converting ADC result to <em>g</em>:</h4>
<p>Lets start with the basic formula to convert a <strong>10-bit</strong> ADC result into voltage for a given VREF. The sensor output can be computed as:</p>
<div class="equation">ADC_Volts = </p>
<div class="fraction"><span class="fup">ADC_RESULT * VREF</span><span class="bar">/</span><span class="fdn">1024</span></div>
<p>V</p></div>
<p>Lets, also keep units for all voltages in volts. We get the <strong><em>g</em></strong> from ADC result as follows:</p>
<div class="equation"><strong><em>g</em></strong> = </p>
<div class="fraction"><span class="fup">ADC_Volts &#8211; Zero_G</span><span class="bar">/</span><span class="fdn">Sensitivity</span></div>
</div>
<p>Combining the above two equations, with VREF and Vs in Volts, we get,</p>
<div class="equation"><strong><em>g</em></strong> = </p>
<div class="fraction"><span class="fup">((ADC_Result*VREF)/1024) &#8211; (Vs/2)</span><span class="bar">/</span><span class="fdn">0.1*Vs</span></div>
</div>
<h4>Interfacing ADXL335 Accelerometer with ARM7 LPC2148 Example:</h4>
<p>For interfacing the Accelerometer we will use the ADC block of LPC2148. Since our sensor has 3 outputs we will use AD0.1, AD0.2, AD0.3 to read the output voltages. After fetching the ADC result we can then convert it to g for each axis. In the example given below, we will use UART0 to send the data to terminal. You can refer my <a href="https://www.ocfreaks.com/lpc2148-adc-programming-tutorial/" target="_blank">LPC2148 ADC Tutorial</a> and <a href="https://www.ocfreaks.com/lpc2148-uart-programming-tutorial/" target="_blank">UART Tutorial</a> for more. The example project linked below also contains <a href="https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/" target="_blank">retargeted printf() for KEIL</a> which redirects its output to UART0.</p>
<p><strong>Schematic:</strong></p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/adxl335_interfacing_lpc214x_schematic.png" alt="Schematic for Interfacing ADXL335 Accelerometer sensor with LPC2148" width="425px" height="285px" /></p>
<div class="special sp_red notewarning"><strong>Note:</strong> Some modules might have on board voltage regulator (and hence extra pins in interface header) which makes it easier to interface with 5V microcontrollers. Please make sure the power supply connections to the module is proper and also change the value of Vs appropriately in your program to get valid results.</div>
<p><strong>main.c source code:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera- www.ocfreaks.com
Interfacing ADXL335 Accelerometer sensor with LPC2148 - Example Source Code for KEIL ARM.
Also see: https://www.ocfreaks.com/lpc2148-adc-programming-tutorial/
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License: GPL.*/

#include &lt;lpc214x.h&gt;
#include &lt;stdio.h&gt; //visit https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/ 
#include "lib_funcs.h" //OCFreaks LPC214x Tutorials Library Header

#define SEL_AD01 (1<<1) //Select AD0.1 Channel
#define SEL_AD02 (1<<2) //Select AD0.2 Channel
#define SEL_AD03 (1<<3) //Select AD0.3 Channel
#define CLKDIV   (15-1) //4Mhz ADC clock (ADC_CLOCK=PCLK/CLKDIV) where "CLKDIV-1" is actually used, in our case PCLK=60mhz  
#define BURST_MODE_OFF (0<<16) //1 for on and 0 for off
#define PowerUP   (1<<21)
#define START_NOW ((0<<26)|(0<<25)|(1<<24)) //001 for starting the conversion immediately
#define ADC_DONE  (1UL<<31)

#define VREF 3.3 //Reference Voltage at VREF pin
#define VS 	 3.3 //Supply Voltage for ADXL335
#define ZERO_G (VS/2) //Zero g bias

int main(void)
{
	initClocks(); //Set PCLK = CCLK = 60Mhz - used by: UART, Timer and ADC
	initUART0();  //Initialize UART0 for retargeted printf()
	initTimer0(); //Init Timer for delay functions
	
	PINSEL1 |= (1<<24) | (1<<26) | (1<<28); //select AD0.1/2/3 for P0.28/29/30.
	int adcX,adcY,adcZ;
	float resultVolts,Xg,Yg,Zg;
	unsigned long ADC0CR_Setup = (CLKDIV<<8) | BURST_MODE_OFF | PowerUP;
	printf("OCFreaks.com LPC214x ADXL335 Sensor Interfacing Tutorial\n");
	
	int skipFirst = 1;
	
	while(1)
	{
		AD0CR = ADC0CR_Setup | SEL_AD01 | START_NOW;//Start new Conversion on AD0.1
		while( (AD0DR1 &#038; ADC_DONE) == 0 );
		adcX = (AD0DR1>>6) & 0x3FF; //get the 10bit ADC result
		
		AD0CR = ADC0CR_Setup | SEL_AD02 | START_NOW; //Start new Conversion on AD0.2
		while( (AD0DR2 & ADC_DONE) == 0 );
		adcY = (AD0DR2>>6) & 0x3FF; //get the 10bit ADC result
		
		AD0CR = ADC0CR_Setup | SEL_AD03 | START_NOW; //Start new Conversion on AD0.3
		while( (AD0DR3 & ADC_DONE) == 0 );
		adcZ = (AD0DR3>>6) & 0x3FF; //get the 10bit ADC result
		
		if(skipFirst) //Ignore first ADC readings.
		{
			skipFirst = 0; 
			continue;
		}
		
		//Computing in 2 steps to keep things simple.
		resultVolts = ((float)adcX * VREF) / 1024; //ADC Result converted to millivolts
		Xg = (resultVolts - ZERO_G) / (VS*0.1);
		
		resultVolts = ((float)adcY * VREF) / 1024; //ADC Result converted to millivolts
		Yg = (resultVolts - ZERO_G) / (VS*0.1);
		
		resultVolts = ((float)adcZ * VREF) / 1024; //ADC Result converted to millivolts
		Zg = (resultVolts - ZERO_G) / (VS*0.1);
		
		printf("X=%0.2fg Y=%0.2fg Z=%0.2fg\n", Xg,Yg,Zg);
		
		delayMS(250); //4 Updates per second
	}
	
	//return 0; //This won't execute normally
}
</code></pre>
<p><strong>Screenshot:</strong></p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/adxl335_lpc214x_demo.png" alt="Demo Screenshot for Interfacing ADXL335 Accelerometer sensor with LPC2148" width="469px" height="338px" /></p>
<p><strong>Project Download:</strong></p>
<div class="highlight"><strong>KEIL ARM uV5/uV4 Project for example given above is on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/ADXL335_Interfacing" target="_blank">ADXL335 Accelerometer Interfacing with LPC2148</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/ADXL335_Interfacing" target="_blank">Download Project Zip</a>. You can find the HEX file inside objects folder.</div>
<p><strong>Reference(s):</strong></p>
<ul>
<li><a href="http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL335.pdf" target="_blank">ADXL335 Datasheet</a></li>
</ul>
<p>The post <a href="https://www.ocfreaks.com/interfacing-adxl335-accelerometer-lpc2148/">Interfacing ADXL335 Accelerometer with LPC2148</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/interfacing-adxl335-accelerometer-lpc2148/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3030</post-id>	</item>
		<item>
		<title>Interfacing LM35 Sensor with LPC2148</title>
		<link>https://www.ocfreaks.com/interfacing-lm35-sensor-lpc2148/</link>
					<comments>https://www.ocfreaks.com/interfacing-lm35-sensor-lpc2148/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Sat, 02 Dec 2017 12:46:39 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[LPC2148 Tutorials]]></category>
		<category><![CDATA[lpc2148]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3020</guid>

					<description><![CDATA[<p>In this tutorial we will see how to interface LM35 Temperature sensor with ARM7 LPC2148 Microcontroller and also cover a simple interfacing example using in-built ADC. </p>
<p>The post <a href="https://www.ocfreaks.com/interfacing-lm35-sensor-lpc2148/">Interfacing LM35 Sensor with LPC2148</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this tutorial we will see how to interface LM35 Temperature sensor with ARM7 LPC2148 Microcontroller. LM35 is a well known low cost temperature sensor. It is directly calibrated in Degrees Celsius meaning that the output voltage is directly proportional to Degrees Celsius readings. Its measurement range is from -55°C to 150°C having typical accuracy(s) of 0.25°C at room temperature and 0.75°C for full range. LM35 also supports a wide range of supply voltage from 4V to 30V and is available in 4 different packages viz. TO-CAN, TO-92, SOIC and TO-220.</p>
<p><strong>LM35 Pinout for TO-92 Package:</strong></p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/lm35_to-92.png" alt="LM35 TO-92 Package" width="200px" height="160px" /></p>
<p>Pin 1 (+Vs) is the positive power supply pin, Pin 2 (V<sub>OUT</sub>) provides the output voltage linearly proportional to temperature and Pin 3 is for Ground.</p>
<p><strong>LM35 can be configured in two ways:</strong></p>
<ul style="margin-bottom:15px;">
<li>Basic Centigrade Temperature Sensor (2°C to 150°C)</li>
<li>Full Range Centigrade Temperature sensor (-55°C to 150°C)</li>
</ul>
<p>For the sake of simplicity, we will use LM35 in basic configuration. The first thing to note when interfacing LM35 with 3.3v MCUs is that LM35 has a supply voltage range of 4V to 30V. Hence, another supply of say 5V would be required to get proper readings. The second thing to note is that the output voltage has a scale factor of <strong>10mV per Degree Centigrade</strong> and this is fixed irrespective of what supply voltage you use between 4V to 30V. Hence, the output voltage can go max up to 1.5V and as low as -55mV when configured as Full Range Centigrade Sensor. </p>
<p>When using the Basic configuration we have an output swing of ~0V(20mV) to 1.5V. So, if we use a <strong>VREF of 3.3 Volts</strong> we get a resolution of 3.3V/1024 =  0.00322V or <strong>3.22mV</strong> since LPC2148 has a <strong>10-bit ADC</strong>. Considering that LM35&#8217;s typical accuracy at room temperature(25°C) is 0.25°C (worst case accuracy = 0.5°C @ 25°C) and scale factor of 10mV/°C, a resolution of 3.22mV barely fits the bill. To get better resolution we can use a lower voltage reference like 1.8V or 2V. For example, using 1.8V reference we get a resolution of 1.75mV. For the interfacing example given below, we will assume a voltage reference of 3.3V which is commonly used on development boards. If these connections are not present on your development board please make sure VREF pin is connected to 3.3V.</p>
<h4>LM35 Transfer Function &#038; Output Conversion to °C</h4>
<p>The formula for<strong> V<sub>OUT</sub></strong> is given as:</p>
<div class="equation">V<sub>OUT</sub>(mV) = 10mV/°C * T</div>
<p>Using the above formula, with VERF in Volts and Scale-factor in V/°C, we can compute the temperature(T) from <strong>10-bit</strong> ADC Result as:</p>
<div class="equation">T = </p>
<div class="fraction"><span class="fup">ADC_RESULT * VREF</span><span class="bar">/</span><span class="fdn">1024 * 0.01</span></div>
<p>°C</p></div>
<p>Which can be simplified as,</p>
<div class="equation">T = </p>
<div class="fraction"><span class="fup">ADC_RESULT * VREF * 100</span><span class="bar">/</span><span class="fdn">1024</span></div>
<p>°C</p></div>
<p>So, when using VREF = 3.3V we get,</p>
<div class="equation">T = </p>
<div class="fraction"><span class="fup">ADC_RESULT * 330</span><span class="bar">/</span><span class="fdn">1024</span></div>
<p>°C</p></div>
<h4>Example for LM35 Interfacing with ARM7 LPC2148</h4>
<p>Now lets cover a simple programming example. As obvious, we will use the ADC block of LPC214x for interfacing our temperature sensor using reference voltage as mentioned above. We will use UART0 to send the data to terminal. You can refer my <a href="https://www.ocfreaks.com/lpc2148-adc-programming-tutorial/" target="_blank">LPC2148 ADC Tutorial</a> and <a href="https://www.ocfreaks.com/lpc2148-uart-programming-tutorial/" target="_blank">UART Tutorial</a> for more. The example project linked below also contains <a href="https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/" target="_blank">retargeted printf() for KEIL</a> which redirects its output to UART0.</p>
<p><strong>Interfacing Schematic:</strong></p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/lm35_lpc2148_interface_schematic.png" alt="Schematic for Interfacing LM35 Temperature sensor with LPC2148" width="445px" height="315px" /></p>
<div class="special sp_blue noteinfo">Since we are interfacing with 5V powered device, I have included an optional ADC input protection using a 1K resistor and a 3.3V Zener Diode &#8211; just in case anything goes wrong while making the connections or with the temperature sensor.</div>
<p><strong>Source code:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera- www.ocfreaks.com
Interfacing LM35 with LPC2148 - Example Source Code for KEIL ARM.
Also see: https://www.ocfreaks.com/lpc2148-adc-programming-tutorial/
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License: GPL.*/

#include &lt;lpc214x.h&gt;
#include &lt;stdio.h&gt; //visit https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/ 
#include "lib_funcs.h" //OCFreaks LPC214x Tutorials Library Header

#define AD06 ((1<<9)|(1<<8)) //Select AD0.6 function for P0.4
#define SEL_AD06 (1<<6) //Select AD0.6 Channel
#define CLKDIV (15-1) //4Mhz ADC clock (ADC_CLOCK=PCLK/CLKDIV) where "CLKDIV-1" is actually used, in our case PCLK=60mhz  
#define BURST_MODE_OFF (0<<16) //1 for on and 0 for off
#define PowerUP (1<<21)
#define START_NOW ((0<<26)|(0<<25)|(1<<24)) //001 for starting the conversion immediately
#define ADC_DONE (1UL<<31)

#define VREF 3.3 //Reference Voltage at VREF pin

int main(void)
{
	initClocks(); //Set PCLK = CCLK = 60Mhz - used by: UART, Timer and ADC
	initUART0();  //Initialize UART0 for retargeted printf()
	initTimer0(); //Init Timer for delay functions
	
	PINSEL0 |= AD06; //select AD0.6 for P0.4
	unsigned long AD0CR_setup = (CLKDIV<<8) | BURST_MODE_OFF | PowerUP; 
	int result = 0;
	float temp = 0;
	
	printf("OCFreaks.com LPC214x LM35 Interfacing Tutorial\n");
	
	AD0CR = AD0CR_setup | SEL_AD06; //Setup ADC block
	
	AD0CR |= START_NOW; //Start new Conversion
	while( (AD0DR6 &#038; ADC_DONE) == 0 );
	//Ignore the first ADC reading.
	
	while(1)
	{
		AD0CR |= START_NOW; //Start new Conversion
		while( (AD0DR6 &#038; ADC_DONE) == 0 );
		
		result = (AD0DR6>>6) & 0x3FF; //get the 10bit ADC result
		
		temp = ((float)result * VREF * 100)/1024; //As per the Equation given in the tutorial

		printf("Temp = %0.1f Deg. Celsius\n" , temp);
		
		delayMS(1000); //1 Update per second
	}
	
	//return 0; //This won't execute normally
}
</code></pre>
<p><strong>Screenshot:</strong></p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/lm35_lpc214x_ex_ss.png" alt="Demo Screenshot for Interfacing LM35 Temperature sensor with LPC2148" width="533px" height="274px" /></p>
<div class="highlight"><strong>KEIL ARM uV5/uV4 Project for example given above is on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/LM35_Interfacing" target="_blank">LM35 Temperature Sensor Interfacing with LPC2148</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/LM35_Interfacing" target="_blank">Download Project Zip</a>. You can find the HEX file inside objects folder.</div>
<p><strong>Reference(s):</strong></p>
<ul>
<li><a href="http://www.ti.com/lit/ds/symlink/lm35.pdf" target="_blank">LM35 Temperature Sensor Datasheet</a></li>
</ul>
<p>The post <a href="https://www.ocfreaks.com/interfacing-lm35-sensor-lpc2148/">Interfacing LM35 Sensor with LPC2148</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/interfacing-lm35-sensor-lpc2148/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3020</post-id>	</item>
		<item>
		<title>Interfacing LDR with LPC2148</title>
		<link>https://www.ocfreaks.com/interfacing-ldr-lpc2148/</link>
					<comments>https://www.ocfreaks.com/interfacing-ldr-lpc2148/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Thu, 23 Nov 2017 17:08:10 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[LPC2148 Tutorials]]></category>
		<category><![CDATA[lpc2148]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3014</guid>

					<description><![CDATA[<p>This time we will go through a tutorial on Interfacing LDR with ARM7 LPC2148 microcontroller.  Light Dependent Resistor (i.e. LDR for short) is basically used to detect the intensity of light and hence, for example, we can detect if a room is dark or lit. We will also cover two interfacing examples using ADC block of LPC214x.</p>
<p>The post <a href="https://www.ocfreaks.com/interfacing-ldr-lpc2148/">Interfacing LDR with LPC2148</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>This time we will go through a tutorial on Interfacing LDR with ARM7 LPC2148 microcontroller. Light Dependent Resistor (i.e. LDR for short) is basically used to detect the intensity of light and hence, for example, we can detect if a room is dark or lit. They are also known as photoresistors or photoconductive cells. The resistance of LDR is inversely proportional to the intensity of light. Hence under dark conditions the resistance typically rises to around 500K to 5M. Under ambient light the resistance is generally around 2K to 10K. Under very bright light its resistance falls down to around few ohms, for example around 2 to 20 ohms.</p>
<p>For the examples covered in this tutorial, we will use the on-chip ADC module of LPC214x microcontroller to interface LDR. You can check my <a href="https://www.ocfreaks.com/lpc2148-adc-programming-tutorial/" target="_blank">LPC2148 ADC Programming Tutorial</a> for reference. Since we cannot directly connect an LDR to the ADC&#8217;s input, we need to convert the resistance into an equivalent voltage. Once we do this it becomes very easy to interface them. By adding another fixed resistor in series we can form a potential divider network and can connect the common of the resister and LDR to ADC&#8217;s input pin. Lets call LDR as R1 and the fixed resistor as R2. The voltage V<sub>out</sub> at the common terminal is given as:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/ldr_voltage_divider.png" alt="LDR Voltage Divider Circuit" width="310px" height="230px" /></p>
<p>Now, to implement this we need a suitable value for R2. The value of R2 in voltage-divider is primarily determined by:</p>
<ul style="margin-bottom:15px;">
<li>LDR&#8217;s maximum current</li>
<li>LDR&#8217;s Response curve [Resistance Vs LUX] (which factors in resistance in dark, bright light and ambient light)</li>
</ul>
<p>Most of the time using 3.3K or 4.7K or 10K resistor as R2 will do the job. But, always check the manufacturer&#8217;s datasheet for max operating current. In case you don&#8217;t have access to datasheet, then generally a couple of few milliamps must be safe to operate. For the ones which I have used (which have come in ~5mm package), generally 1mA to 5mA have not been an issue. Some LDR&#8217;s also allow 50mA to 75mA+ max current. In my case a resistor of 4.7K just works fine and gives a good full scale range. Given LPC2148 uses 3.3V as Vcc, a resistor of 4.7K will limit current to 0.7mA max through LDR under very bright conditions.</p>
<h4>Example 1 &#8211; Reading the voltage divider output:</h4>
<p>In this example we will read the voltage divider output, which changes as the intensity of light changes. The ADC will convert the input voltage to a proportional value between 0 and 1023. We can directly use this value(ADC Result) to detect the light intensity. A value of 0 means Dark condition and a value of 1023 means very bright light is present. With this example you can see the output values change as you change the intensity of light. Working with this example you can decide on a cut-off value or a cut-off range to trigger a function. In this example I have <a href="https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/" target="_blank">retargeted printf() to redirect its output over UART</a>. Here is the schematic for interfacing LDR with ARM7 LPC2148:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/lpc214x_ldr_ex1.png" alt="LPC214x LDR Interfacing Example 1 Schematic" width="300px" height="275px" /></p>
<p><strong>Source code:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera- www.ocfreaks.com
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
LPC2148 LDR Interfacing Example 1 Source Code for KEIL ARM.
Also see: https://www.ocfreaks.com/lpc2148-adc-programming-tutorial/
License: GPL.*/

#include &lt;lpc214x.h&gt;
#include &lt;stdio.h&gt; //For retargeted printf()
#include "lib_funcs.h" //OCFreaks LPC214x Tutorial Library Header

#define AD06 ((1<<9)|(1<<8)) //Select AD0.6 function for P0.4
#define SEL_AD06 (1<<6)
#define CLKDIV (15-1) // 4Mhz ADC clock (ADC_CLOCK=PCLK/CLKDIV) where "CLKDIV-1" is actually used , in our case PCLK=60mhz  
#define BURST_MODE_OFF (0<<16) // 1 for on and 0 for off
#define PowerUP (1<<21)
#define START_NOW ((0<<26)|(0<<25)|(1<<24)) //001 for starting the conversion immediately
#define ADC_DONE (1UL<<31)

#define VREF 3.3 //Reference Voltage at VREF pin

int main(void)
{
	initClocks(); //Set PCLK = CCLK = 60Mhz - used by: UART, Timer and ADC
	initUART0(); //Initialize UART0 for retargeted printf()
	initTimer0(); //Init Timer for delay functions
	
	PINSEL0 |= AD06 ; //select AD0.6 for P0.4
	int result = 0;
	unsigned long AD0CR_setup = (CLKDIV<<8) | BURST_MODE_OFF | PowerUP; //Setup ADC block
	
	printf("OCFreaks.com LPC214x LDR Interfacing Tutorial - Example 1.\n");
	
	while(1)
	{
		AD0CR =  AD0CR_setup | SEL_AD06; 
		AD0CR |= START_NOW; //Start new Conversion

		while( (AD0DR6 &#038; ADC_DONE) == 0 );
		
		result = (AD0DR6>>6) & 0x3FF; //get the 10bit ADC result

		printf("AD0.6 = %d\n" , result);
		delayMS(500); //Slowing down Updates to 2 Updates per second
	}
	
	//return 0; //This won't execute normally
}
</code></pre>
<div class="highlight"><strong>KEIL ARM uV5/uV4 Project for example given above on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/LDR_Interfacing/Example_1" target="_blank">LDR Interfacing with LPC2148 Example 1</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/LDR_Interfacing/Example_1" target="_blank">Download Project Zip</a>. You can find the HEX file inside objects folder.</div>
<h4>Example 2 &#8211; Turn on LED when its dark:</h4>
<p>This is a classic example for LDRs. Here we will turn-on an LED when we detect low light or dark conditions. Instead of an LED you can also connect a Relay which can then switch on a Bulb or something like heater during night in cold regions. Make sure you keep the LDR away from the LED or Bulb since we are only interested in detecting sunlight and not artificial light in this case. Schematic for this example is given as follows:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/lpc214x_ldr_ex2.png" alt="LPC214x LDR Interfacing Example 2 Schematic" width="304px" height="275px" /></p>
<p><strong>Source code:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera- www.ocfreaks.com
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
LPC2148 LDR Interfacing Example 2 Source Code for KEIL ARM.
Also see: https://www.ocfreaks.com/lpc2148-adc-programming-tutorial/
License: GPL.*/

#include &lt;lpc214x.h&gt;
#include "lib_funcs.h" //OCFreaks LPC214x Tutorial Library Header

#define AD06 ((1<<9)|(1<<8)) //Select AD0.6 function for P0.4
#define SEL_AD06 (1<<6)
#define CLKDIV (15-1) // 4Mhz ADC clock (ADC_CLOCK=PCLK/CLKDIV) where "CLKDIV-1" is actually used , in our case PCLK=60mhz  
#define BURST_MODE_OFF (0<<16) // 1 for on and 0 for off
#define PowerUP (1<<21)
#define START_NOW ((0<<26)|(0<<25)|(1<<24)) //001 for starting the conversion immediately
#define ADC_DONE (1UL<<31)
#define VREF 3.3 //Reference Voltage at VREF pin

#define CUT_OFF 200 //Define your cut-off value here

int main(void)
{
	initClocks(); //Set PCLK = CCLK = 60Mhz
	initTimer0(); //Init Timer for delay functions
	
	PINSEL0 |= AD06 ; //select AD0.6 for P0.4
	IO0DIR |= (1<<5); //Select P0.5 as output 
	int result = 0;
	unsigned long AD0CR_setup = (CLKDIV<<8) | BURST_MODE_OFF | PowerUP; //Setup ADC block
	
	while(1)
	{
		AD0CR =  AD0CR_setup | SEL_AD06; 
		AD0CR |= START_NOW; //Start new Conversion

		while( (AD0DR6 &#038; ADC_DONE) == 0 );
		
		result = (AD0DR6>>6) & 0x3FF; //get the 10bit ADC result
		
		if(result < CUT_OFF)
		{
			IO0SET = (1<<5); //LED ON
		}
		else
		{
			IO0CLR = (1<<5); //LED OFF
		}
		
		delayMS(100); //wait some time since LDRs don't react immediately.
	}
	//return 0; //This won't execute normally
}
</code></pre>
<div class="highlight"><strong>KEIL ARM uV5/uV4 Project for example given above on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/LDR_Interfacing/Example_2" target="_blank">LDR Interfacing with LPC2148 Example 2</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/LDR_Interfacing/Example_2" target="_blank">Download Project Zip</a>. You can find the HEX file inside objects folder.</div>
<p>The post <a href="https://www.ocfreaks.com/interfacing-ldr-lpc2148/">Interfacing LDR with LPC2148</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/interfacing-ldr-lpc2148/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3014</post-id>	</item>
		<item>
		<title>DHT11 and DHT22 Interfacing with LPC2148 ARM7 MCU Tutorial</title>
		<link>https://www.ocfreaks.com/dht11-dht22-interfacing-arm-lpc2148-tutorial/</link>
					<comments>https://www.ocfreaks.com/dht11-dht22-interfacing-arm-lpc2148-tutorial/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Sun, 12 Nov 2017 12:33:25 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[LPC2148 Tutorials]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=2986</guid>

					<description><![CDATA[<p>In this tutorial we will cover interfacing DHT11/DHT22 sensor with ARM7 LPC2148 microcontroller also implement an example to fetch Relative humidity and Temperature and display it in serial console.</p>
<p>The post <a href="https://www.ocfreaks.com/dht11-dht22-interfacing-arm-lpc2148-tutorial/">DHT11 and DHT22 Interfacing with LPC2148 ARM7 MCU Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this tutorial we will go through on how to interface DHT11/DHT22 sensor with LPC2148 ARM7 microcontroller. In my previous tutorial I had discussed <a href="https://www.ocfreaks.com/basics-interfacing-dht11-dht22-humidity-temperature-sensor-mcu/">basics of DHT11/DHT22 interfacing</a> &#8211; Please go through it if you are new to DHTxx Humidity and Temperature sensors.</p>
<p>Here is a quick recap of the communication process:<br />
<img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/dht/dht11_dht22_protocol.png" width="645px" height="320px" alt="DHT11 DHT22 communication process protocol" /></p>
<p>DHT11 &#038; DHT22 Data format:<br />
<img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/dht/dht_data_format.png" width="505px" height="220px" alt="DHT11 DHT22 data format" /></p>
<p>Now, lets see the algorithm or steps we need to implement for interfacing. Since only one DATA line(PIN) is used, we will use the same GPIO PIN first as OUTPUT to send START condition and then as INPUT to Receive data. </p>
<div class="highlight">
<h4>Steps For Programming DHT11/DHT22:</h4>
<ol style="margin-bottom:0px;">
<li>Configure PIN to be used to communication as OUTPUT.</li>
<li>Set the PIN O/P to LOW and wait for 18 milli-seconds.</li>
<li>Configure the PIN as INPUT. The pull-up resistor will Pull the bus to HIGH.</li>
<li>Wait until DHT11 responds and pulls the line to LOW after around 40 micro-seconds or else exit as timeout error.</li>
<li>Next, check for 80us LOW followed by 80us HIGH from DHT11. This condition denotes that DHT11 is ready to send data next.</li>
<li>Now, check for 50us LOW followed by 26us to 28us HIGH denoting data bit &#8216;0&#8217; or 50us LOW followed 70us HIGH denoting  data bit &#8216;1&#8217;. Store the interpreted bit in an array. Repeat this for each of 40 bits.</li>
<li>Extract the data bytes from array to record or display it. Optionally the checksum can be used to verify data integrity.</li>
<li>Wait for at least 1 second before starting again to fetch new data.</li>
</ol>
</div>
<h4>Program for Interfacing DHT11/DHT22 with ARM LPC2148:</h4>
<p>Now lets build a program for interfacing example. In this example we will us PIN P0.2 for communication with DHT11 sensor. For DHT22 you just need to make a slight modification in code to display the decimal part. I leave that to the reader. If you are using the bare 4 pin sensor than make sure that DATA pin is pulled up using 4.7K or 10K resistor. If you are using PCB mounted sensor which has 3 pins then external pullup resistor is not required since it is already present on the PCB. Timer0 block is used for generating delays and measuring timing of responses given by DHTxx. You can go through <a href="https://www.ocfreaks.com/lpc2148-timer-tutorial/" target="_blank" rel="noopener">LPC2148 timer tutorial</a> for reference. </p>
<p>We will also use UART0 to send data back to PC and display it using software terminal. <a href="https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/" target="_blank" rel="noopener">Printf() has been retargetted</a> such that its output gets redirected to UART0. Checkout my <a href="https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/" target="_blank" rel="noopener">tutorial on how to retarget printf() in keil</a> and <a href="https://www.ocfreaks.com/lpc2148-uart-programming-tutorial/" target="_blank" rel="noopener">LPC2148 UART tutorial</a> for more. The schematic for connections between DHT11 and LPC214x is as given below:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/lpc2148_dht11_sch.png" width="450px" height="340px" alt="LPC2148 DTH11 Interfacing Schematic" /></p>
<p>Before going through to source code, first lets go through some the functions used:</p>
<ul>
<li><span class="code_var">startTimer0()</span> &#8211; Resets counter and Enables Timer0 block.</li>
<li><span class="code_var">unsigned int stopTimer0()</span> &#8211; Disables counting and returns value in T0TC.</li>
<li><span class="code_var">checkResponse(&#8230;)</span> &#8211; Used to check the response from DHT11. It has 3 parameters viz. <span class="code_ref">unsigned int waitTimeUS, unsigned int margin, bool pinValue</span>. waitTimeUS is simply the expected wait time in micro-seconds. Margin is additional timing error or offset we can account for, since the sensor might have intrinsic timing offets. pinValue is the current expected state of pin which it must hold until the given waitTime.</li>
<li><span class="code_var">char getDataBit()</span> &#8211; This checks the pulses for a &#8216;0&#8217; or a &#8216;1&#8217; and returns the value accordingly. It will return 2 in case of an error.</li>
<li><span class="code_var">printError(const char * str)</span> &#8211; Prints error message and halts program execution by entering infinite while loop. You must reset board in this situation or you can extend the code to handle errors on the fly.</li>
</ul>
<p><strong>DHT11 Interfacing Source Code in C++:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera - www.ocfreaks.com
DHT11 Humidity and Temperature Sensor Interfacing with LCP2148 Example Source Code for KEIL ARM
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License : GPL.*/
#include &lt;lpc214x.h&gt;
#include &lt;stdio.h&gt;
#include "lib_funcs.h" //Contains timer, uart and printf retarget code - https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/

#define LOW 0
#define HIGH 1
void printError(const char * str);
void checkResponse(unsigned int waitTimeUS, unsigned int margin, bool pinValue);
char getDataBit(void);

//Using P0.2 for data communication

int main(void)
{
	bool dataBits[40] = {0};
	char dataBytes[5] = {0};
	
	initTimer0();
	initUART0();
	
	printf("OCFreaks.com - DHT11 Interfacing with LPC2148 example.\n");
	
	while(1)
	{
		//STEP 1: Set pin to output HIGH which represents idle state
		IO0DIR |= (1<<2);
		
		//STEP 2: Pull down pin for 18ms(min) to denote START
		IO0CLR |= (1<<2);
		delayUS(18000); //wait for 18ms
		
		//STEP 3: Pull HIGH and switch to input mode
		//pull-up will pull it HIGH after switching to input mode.
		IO0DIR &#038;= ~(1<<2);
		
		//STEP 4: Wait between 20 to 40us for sensor to respond
		startTimer0();
		while( (IO0PIN &#038; (1<<2)) != 0 )
		{
			if(T0TC > 40) break; //Timeout
		}
		unsigned int time = stopTimer0();
		
		if(time < 10 || time > 40) 
		{ 
			printError("Failed to communicate with sensor");
		}
		
		//STEP 5: Check for 80us LOW followed by 80us HIGH
		checkResponse(80,5,LOW);
		checkResponse(80,5,HIGH);
		
		//After this DHT sends data. Each bit has a preceding 50us LOW. After which 26-28us means '0' and 70us means '1'
		
		//STEP 6: Fetch data
		char data;
		for(int i=0; i < 40; i++)
		{
			data = getDataBit();
			
			if(data == 0 || data == 1)
			{
				dataBits[i] = data;
			}
			else printError("Data Error");
		}
		
		//STEP 7: Extract data bytes from array
		data = 0;
		for(int i=0; i<5; i++) // i is the BYTE counter
		{
			for(int j=0; j<8; j++) // j gives the current position of a bit in i'th BYTE
			{
				if( dataBits[ 8*i + j ] )
					data |= (1<<(7-j)); //we need to only shift 1's by ([BYTESZIE-1] - bitLocation) = (7-j)
			}
			dataBytes[i] = data;
			data = 0;
		}		
		
		printf("Humidity=%d%%, Temp=%d Deg. C\n",dataBytes[0], dataBytes[2]);
		
		//STEP8: Wait for atleast 1 second before probing again
		delayUS(1000000); 
	}
	//return 0;
}

void printError(const char * str)
{
	/*Print error and enter infinite loop to HALT program*/
	printf("%s\n",str);
	while(1);
}

void checkResponse(unsigned int waitTimeUS, unsigned int margin, bool pinValue)
{
	int time = 0;
	int maxwait = waitTimeUS + margin;
	
	startTimer0();
	if(pinValue)
	{
		while( IO0PIN &#038; (1<<2) )
		{
			if(T0TC > (maxwait)) break; 
		}
	}
	else
	{
		while( !(IO0PIN & (1<<2)) )
		{
			if(T0TC > (maxwait)) break; 
		}
	}
	time = stopTimer0();
	
	if(time < (waitTimeUS-margin) || time > maxwait) 
	{
		//printf("Error for wait=%d,margin=%d,pinVal=%d,time=%d\n",waitTimeUS,margin,pinValue,time);
		printError("checkResponse() Error"); //Out of range, including error margin
	}
}

char getDataBit(void)
{
	int time = 0;
	
	checkResponse(50,5,LOW); //Each data bit starts with 50us low
	
	startTimer0();
	while( IO0PIN & (1<<2) )
	{
		if(T0TC > 75)
		{
			//printError("Data Error");
			return 2; //2 = Error (Timeout for 50us LOW)
		}
	}
	time = stopTimer0();
	
	if((time > (27-10)) && (time < (27+10))) //I am getting 21 for HIGH using my DHT11 sensor, so using higher margin
	{
		return 0;
	}
	else if((time > (70-5)) && (time < (70+5)))
	{
		return 1;
	}
	else 
	{ 
		//printError("Data Error");
		return 2; //Timeout for data pulse 
	}
}
</code></pre>
<p>Here is a screen of the above example in action:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/dht11_lpc2148_example_op.png" width="549px" height="322px" alt="LPC2148 DTH11 Interfacing Example output" /></p>
<div class="highlight"><strong>KEIL ARM uV5 Project for example given above on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/DHT11_Interfacing" target="_blank" rel="noopener">DHT11 Interfacing with LPC2148 Example</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC2148-Tutorial-Examples/tree/master/DHT11_Interfacing" target="_blank" rel="noopener">Download Project Zip</a>. You can find the HEX file inside objects folder.</div>
<p>The post <a href="https://www.ocfreaks.com/dht11-dht22-interfacing-arm-lpc2148-tutorial/">DHT11 and DHT22 Interfacing with LPC2148 ARM7 MCU Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/dht11-dht22-interfacing-arm-lpc2148-tutorial/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2986</post-id>	</item>
		<item>
		<title>LPC2148 DAC Programming Tutorial</title>
		<link>https://www.ocfreaks.com/lpc2148-dac-programming-tutorial/</link>
					<comments>https://www.ocfreaks.com/lpc2148-dac-programming-tutorial/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Sat, 14 Oct 2017 13:00:54 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[LPC2148 Tutorials]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=2957</guid>

					<description><![CDATA[<p>In this discussion we will cover ARM7 LPC2148 DAC Programming Tutorial along with a basic DAC example. The DAC block in ARM7 LPC214x microcontroller is one of the simplest to program and use. Basically we feed in a digital value and the DAC block outputs it equivalent analog signal.</p>
<p>The post <a href="https://www.ocfreaks.com/lpc2148-dac-programming-tutorial/">LPC2148 DAC Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Hi again folks. Let&#8217;s get Analog! This time we will go through a discussion on ARM7 LPC2148 DAC programming tutorial. As you might be knowing, DAC stands for Digital to Analog Conversion. The DAC block in ARM7 LPC214x microcontroller is one of the simplest to program and use. Basically we feed in a digital value and the DAC block outputs it equivalent analog signal as shown below:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/mcu_dac_1.png" width="450px" height="215px" alt="Digital to Analog Conversion" /></p>
<h2 class="shead">LPC2148 DAC Block</h2>
<p>ARM7 LPC2148 MCU incorporates a 10 bit DAC and provides buffered analog output. As per the datasheet, it is implemeneted as a string DAC which is the most simplest form of DAC consisting of 2<sup>N</sup> resistors in series where N = no. of bits which simply forms a Kelvin-Varley Divider. LPC214x DAC has only 1 output pin, referred to as AOUT. The Analog voltage at the output of this pin is given as:</p>
<div class="equation">V<sub>AOUT</sub> =</p>
<div class="fraction"><span class="fup">VALUE * V<sub>REF</sub></span><span class="bar">/</span><span class="fdn">1024</span></div>
</div>
<p>Where VALUE is the 10-bit digital value which is to be converted into its Analog counterpart and V<sub>REF</sub> is the input reference voltage.</p>
<h4>Pins relating to LPC2148 DAC block:</h4>
<p><center></p>
<table>
<tr>
<th><strong>Pin</strong></th>
<th><strong>Description</strong></th>
</tr>
<tr>
<td><strong>AOUT (P0.25)</strong></td>
<td>Analog Output pin. Provides the converted Analog signal which is referenced to V<sub>SSA</sub> i.e. the Analog GND. Set Bits[19:18] in PINSEL1 register to [10] to enable this function.</td>
</tr>
<tr>
<td><strong>V<sub>REF</sub></strong></td>
<td>This is the voltage reference pin used by DAC for conversion.</td>
</tr>
<tr>
<td><strong>V<sub>DDA</sub>, V<sub>SSA</sub></strong></td>
<td>V<sub>DDA</sub> is Analog Power pin and V<sub>SSA</sub> is Ground pin used to power the DAC module. These are generally same as V<sub>CC</sub> and GND but with additional filtering to reduce noise.</td>
</tr>
</table>
<p></center></p>
<h2 class="shead">DACR register in LPC2148</h2>
<p>Only one register is used to program the DAC block in ARM7 LPC214x viz. DACR. The field containing bits 6 to 15 is used to feed a digital value which needs to be converted and bit 16 is used to select settling time. The bit significance is as shown below:</p>
<ol>
<li><strong>Bit[5:0]:</strong> Reserved.</li>
<li><strong>Bit[15:6] &#8211; VALUE:</strong> After a new VALUE is written to this field, given settling time selected using BIAS has elapsed, we get the converted Analog voltage at the output. The formula for analog voltage at AOUT pin is as shown above.</li>
<li><strong>Bit[16] &#8211; BIAS:</strong> Setting this bit to 0 selects settling time of 1us max with max current consumption of 700uA. Setting it to 1 will select settling time of 2.5us but with reduce max current consumption of 300uA.</li>
<li><strong>Bits[31:17]</strong>: Reserved</li>
</ol>
<h2 class="shead">ARM7 LPC2148 DAC example</h2>
<p>As it can been seen, programming the DAC block is very straight forward. We just need to select DAC function for P0.25 pin and feed a 10-bit value which needs to be converted into its Analog form. Lets see a basic LPC2148 DAC example. For most development boards V<sub>REF</sub> will be connected to VCC using some form of noise isolation. In this DAC example, we will be changing the output from 0V to V<sub>REF</sub> and then falling back to 0V in steps of 10ms. This DAC program will basically output a sawtooth waveform. We will be using BIAS = 0 i.e. settling time of 1us. You can connect an Oscilloscope or a Multimeter between P0.25 and GND to check the changing analog output. Since the output is buffered you can drive an LED from A<sub>OUT</sub> but it won&#8217;t glow until it reaches its forward bias voltage of around 1.7 Volts. So, keep this in mind when checking for analog output using an LED. Also, I have used Timer0 for generating delay. You can check my <a href="https://www.ocfreaks.com/lpc2148-timer-tutorial/" target="_blank">previous timer tutorial</a>.</p>
<p style="margin-bottom:0px;"><img decoding="async" style="margin-bottom:0px" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/lpc2148_dac_eg.png" width="400px" height="200px" alt="LPC2148 DAC Example Schematic" /></p>
<p style="text-align:center;">[Note: <strong>V<sub>SSA</sub></strong> and <strong>GND</strong> will be common for most development boards.]</p>
<p>C/C++ Source Code:</p>
<pre><code class="language-cpp">
/*(C) Umang Gajera - www.ocfreaks.com
LPC2148 DAC Example 1 Source Code using KEIL ARM
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License : GPL.*/

#include &lt;lpc214x.h&gt;

void initTimer0(void);
void delayMS(unsigned int milliseconds);

int main(void)
{
	initTimer0();
	PINSEL1 |= (1<<19); //Select AOUT function for P0.25. bits[19:18] = [10] 
	unsigned int value=0; //Binary value used for Digital To Analog Conversion
	while(1)
	{
		if(value > 1023) value=0; //For 10-bit DAC max-value is 2^10 - 1 = 1023
		DACR = (value<<6);
		delayMS(10);
		value++;
	}
}

void initTimer0(void)
{
	/*Assuming that PLL0 has been setup with CCLK = 60Mhz*/
	VPBDIV = 0x01; //Set PCLK = CCLK = 60Mhz
	T0CTCR = 0x0;
	T0PR = 60000-1; //60000 clock cycles @60Mhz = 1 ms
	T0TCR = 0x02; //Reset Timer
}

void delayMS(unsigned int milliseconds) //Using Timer0
{
	T0TCR = 0x02; //Reset Timer
	T0TCR = 0x01; //Enable timer
	while(T0TC < milliseconds); //wait until timer counter reaches the desired delay
	T0TCR = 0x00; //Disable timer
}
</code></pre>
<p>The post <a href="https://www.ocfreaks.com/lpc2148-dac-programming-tutorial/">LPC2148 DAC Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/lpc2148-dac-programming-tutorial/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2957</post-id>	</item>
		<item>
		<title>LPC2148 I2C Programming Tutorial</title>
		<link>https://www.ocfreaks.com/lpc2148-i2c-programming-tutorial/</link>
					<comments>https://www.ocfreaks.com/lpc2148-i2c-programming-tutorial/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Mon, 10 Apr 2017 14:42:46 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[LPC2148 Tutorials]]></category>
		<category><![CDATA[lpc2148]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=2752</guid>

					<description><![CDATA[<p>In this tutorial we will go through LPC2148 I2C programming and learn how to program it for interfacing various I2C modules, sensors and other slave devices. For those who are new to I2C Bus &#38; Protocol I have posted an I2C Basics Tutorial @ https://www.ocfreaks.com/i2c-tutorial/ Introduction A quick Recap of I2C I2C was invented by [&#8230;]</p>
<p>The post <a href="https://www.ocfreaks.com/lpc2148-i2c-programming-tutorial/">LPC2148 I2C Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this tutorial we will go through LPC2148 I2C programming and learn how to program it for interfacing various I2C modules, sensors and other slave devices. For those who are new to I2C Bus &amp; Protocol I have posted an I2C Basics Tutorial @ <a href="https://www.ocfreaks.com/i2c-tutorial/">https://www.ocfreaks.com/i2c-tutorial/</a></p>
<h2 class="shead">Introduction</h2>
<h4>A quick Recap of I2C</h4>
<p>I2C was invented by Philips in 1980s. I2C stands for Inter-Integrated Circuit and also sometimes also referred as TWI i.e. Two Wire Interface since it uses only 2 wires for data transmission and synchronization. The two wires of I2C Bus consists of:<br />
1. Data Line which is <strong>SDA i.e. Serial Data</strong><br />
2. Clock Line which is <strong>SCL i.e. Serial Clock</strong></p>
<p>I2C uses 7bit and 10bit addresses for each device connected to the bus. 10bit addressing was introduced later. In this tutorial we will use 7bit addressing since its common with sensors, eeproms, etc. A general I2C bus topology with multiple masters and multiple slaves connected to the bus at the same time is shown below:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/electronics/i2c_tutorial/i2c_bus_general_topology.png" alt="I2C/TWI Bus Topology" width="582px" height="382px" /></p>
<p>I2C bus is a <strong>Byte Oriented bus</strong>. Only a byte can be transferred at a time. Communication(Write to &amp; Read from) is always initiated by a Master. The Master first sends a <b>START</b> condition and then writes the <b>Slave Address(SLA)</b> and the <b>Direction bit(Read=1/Write=0)</b> on bus and the corresponding Slave responds accordingly.</p>
<p>Format for I2C communication protocol is given as:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/electronics/i2c_tutorial/i2c_communication_protocol.png" alt="I2C Protocol" width="558px" height="237px" /></p>
<h2 class="shead">I2C module in LPC2148 ARM7 Microcontrollers</h2>
<p>The I2C block in LPC2148 and other LPC2100 series ARM7 MCUs can be configured as either Master, Slave or both Master &amp; Slave. It also features a programmable clock which aids in using different transfer rates as required. The I2C block in LPC214x supports speeds up to 400kHz.</p>
<p class="compact_header"><strong>I2C has 4 operating modes:</strong></p>
<ol>
<li>Master Transmitter mode</li>
<li>Master Receiver mode</li>
<li>Slave Transmitter mode</li>
<li>Slave Receiver mode</li>
</ol>
<p>LPC2148 ARM7 Microcontroller supports all of these 4 modes, but in this tutorial we will go through Master Transmitter and Master Receiver modes only since implementing the Slave modes is easy once you understand the Master modes and also since Master mode is used for interfacing with Sensors, LCD Displays, and other I2C slave devices.</p>
<div class="special sp_yellow noteinfo">
<h4>Pins relating to I2C Module of LPC2148</h4>
<p class="compact_header">For I2C0 block the <strong>SLC(Clock)</strong> pin is <strong>P0.2</strong> and <strong>SDA(Data)</strong> Pin is <strong>P0.3</strong>, while for I2C1 block the <strong>SCL</strong> pin in <strong>P0.11</strong> and <strong>SDA</strong> pin is <strong>P0.14</strong>.</p>
</div>
<h2 class="shead">Registers used for programming LPC2148 I2C block</h2>
<p>Before we get into Operating mode details lets go through the registers used in I2C block of LPC214x:</p>
<p><strong>(Replace 0 with 1 for I2C1 block registers)</strong></p>
<div class="highlight"><strong>1) <span class="doc_ref">I2C0CONSET</span> (8 bit) &#8211; I2C control set register:</strong> The bits in this register control the operation of the I2C interface. Writing a 1 to a bit of this register causes the corresponding bit in the I2C control register(inside I2C block) to be set. Writing a 0 has no effect. This is a Read-Write register.</p>
<ol>
<li><strong>Bits[0 &amp; 1] :</strong> Reserved</li>
<li><strong>Bit 2 &#8211; AA &#8211; Assert Acknowledge Flag :</strong> When this bit is set to 1, an acknowledge (Logic low on SDA) will be returned when a data byte has been received in the master receiver mode. Similarly when AA is set to 0, a not acknowledge (Logic low on SDA) will be returned when a data byte has been received in the master receiver mode.</li>
<li><strong>Bit 3 &#8211; SI &#8211; I2C Interrupt Flag :</strong> This bit is set whenever the I2C state changes(Except for state code 0xF8). When SI is set the Low Period of the serial clock is stretched which is also termed as clock stretching. When SCL is HIGH, its not affected by the state of SI flag. SI must be reset using I2CONCLR register everytime.</li>
<li><strong>Bit 4 &#8211; STO &#8211; STOP Flag :</strong> When this bit is set to 1 the I2C interface will send a STOP condition.</li>
<li><strong>Bit 5 &#8211; STA &#8211; START Flag :</strong> When this bit is set to 1 the I2C interface is forced to enter Master mode and send a START Condition or send a Repeated START if its already in Master mode.</li>
<li><strong>Bit 6 &#8211; I2EN &#8211; I2C interface Enable :</strong> This bit is used to Enabled or Disable the I2C interface. When set to 1 the I2C interface is enabled and when set to 0 the I2C interface is disabled.</li>
<li><strong>Bit 7 </strong>&#8211; Reserved.</li>
</ol>
<p><strong>2) <span class="doc_ref">I2C0CONCLR</span> (8 bit) &#8211; I2C control clear register.</strong> This register is used to clear bits in I2C0CONSET register. Writing 0 no effect. The bit locations are same as that of I2C0CONSET register given above. Its a Write only register.</p>
<p><strong>3) <span class="doc_ref">I2C0STAT</span> (8 bit) </strong>&#8211; This gives the current state of I2C interface in form of state codes. This is a read only register.</p>
<p><strong>4) <span class="doc_ref">I2C0DAT</span> (8 bit)</strong> &#8211; This register contains the data that is to be transmitted or the latest received data. Data in this register is always shifted from right to left i.e. the first bit to be transmitted is the MSB (bit 7), and after a byte has been received, the first bit of received data is located at the MSB of I2C0DAT.</p>
<p><strong>5) <span class="doc_ref">I20SCLH</span> (16 bit)</strong> &#8211; This register is used to store the High time period of the SCL pulse.</p>
<p><strong>6) <span class="doc_ref">I20SCLL</span> (16 bit)</strong> &#8211; This register is used to store the Low time period of the SCL pulse.</p>
<p><strong>7) <span class="doc_ref">I2C0ADR</span> (8 bit)</strong> &#8211; I2C Slave Address register : Not applicable for master mode. Used to store the address in slave mode.</p>
</div>
<h2 class="shead">LPC2148 I2C Status Codes</h2>
<p>Before we start coding, first lets go through some status codes. Whenever an event occurs on the I2C bus a corresponding I2C status code will be set in I2CxSTAT register.</p>
<div class="special sp_cyan notestar"><strong>Status Codes Common to Master Transmitter &amp; Receiver Mode:</strong></p>
<table class="no_style">
<tbody>
<tr>
<td><span class="doc_ref">0x08</span></td>
<td>: A <strong>START condition</strong> has been transmitted. Load Slave Address + Read/Write (SLA+R/W) into I2CDAT to transmit it.</td>
</tr>
<tr>
<td><span class="doc_ref">0x10</span></td>
<td>: A <strong>REPEAT START condition</strong> has been transmitted. Load Slave Address + Read/Write (SLA+R/W) into I2CDAT to transmit it.</td>
</tr>
<tr>
<td><span class="doc_ref">0x18</span></td>
<td>: Previous state was State 0x08 or State 0x10, <b>SLA+R/W</b> has been transmitted, <b>ACK</b> has been received. The first data byte will be transmitted, an <b>ACK[Acknowledgment](AA=0)<b> bit will be received.</b></b></td>
</tr>
<tr>
<td><span class="doc_ref">0x20</span></td>
<td>: <b>SLA+R/W</b> has been transmitted, <b>NOT ACK(AA=1)</b> has been received. A <b>STOP</b> condition will be transmitted.</td>
</tr>
</tbody>
</table>
</div>
<div class="special sp_cyan notestar"><strong>Master Transmitter Status Codes:</strong></p>
<table class="no_style">
<tbody>
<tr>
<td><span class="doc_ref">0x28</span></td>
<td>: Data has been transmitted, <b>ACK(AA=0)</b> has been received. If the transmitted data was the last data byte then transmit a <b>STOP</b> condition, otherwise transmit the next data byte.</td>
</tr>
<tr>
<td><span class="doc_ref">0x30</span></td>
<td>: Data has been transmitted, <b>NOT ACK(AA=1)</b> received. A <b>STOP</b> condition will be transmitted.</td>
</tr>
<tr>
<td><span class="doc_ref">0x38</span></td>
<td>: Arbitration has been lost while sending <b>Slave Address + Write or Data</b>. The bus has been released and not addressed Slave mode is entered. A new <b>START</b> condition will be transmitted when the bus is free again.</td>
</tr>
</tbody>
</table>
</div>
<div class="special sp_cyan notestar"><strong>Master Receiver Status Codes:</strong></p>
<table class="no_style">
<tbody>
<tr>
<td><span class="doc_ref">0x40</span></td>
<td>: Previous state was State 0x08 or State 0x10. <b>Slave Address + Read (SLA+R)</b> has been transmitted, <b>ACK</b> has been received. Data will be received and <b>ACK</b> returned.</td>
</tr>
<tr>
<td><span class="doc_ref">0x48</span></td>
<td>: <b>Slave Address + Read (SLA+R)</b> has been transmitted, <b>NOT ACK</b> has been received. A <b>STOP</b> condition will be transmitted.</td>
</tr>
<tr>
<td><span class="doc_ref">0x50</span></td>
<td>: Data has been received, <b>ACK</b> has been returned. Data will be read from <b>I2DAT</b>. Additional data will be received. If this is the last data byte then <b>NOT ACK</b> will be returned, otherwise <b>ACK</b> will be returned.</td>
</tr>
<tr>
<td><span class="doc_ref">0x58</span></td>
<td>: Data has been received, <b>NOT ACK</b> has been returned. Data will be read from I2DAT. A <b>STOP</b> condition will be transmitted.</td>
</tr>
</tbody>
</table>
</div>
<div class="special sp_blue noteinfo">A Complete List of Status Codes, software response and what action is taken next by the I2C module on lpc214x is given in the <strong>Datasheet(UM10120 Rev. 02) from Page 152+ onwards</strong>. Refer the same whenever in doubt.</div>
<h2 class="shead">I2C Master Modes in LPC2148 ARM7 MCU:</h2>
<h3>I2C Master Transmitter Mode:</h3>
<p>To enter the Master Transmitted mode we set the <b>STA</b> bit to 1. After this the master will output a <b>START</b> condition(as soon as the bus is free) and the first byte is sent on the bus that will contain the address(7 bits) of the slave device along with the R/W bit. Here we set the R/W to 0 which means Write. After this the data sent a byte at a time. For each byte sent by master, the slave device sends a corresponding <b>Acknowledgement bit(AA=0)</b>. When slave is finished sending data or has no more data to send it will send a <b>&#8216;Not Acknowledge'(AA=1) bit</b> to indicate this. After this the master outputs a <b>STOP</b> condition. This is shown the figure below:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/electronics/i2c_tutorial/i2c_master_transmitter_mode.png" alt="master transmitter mode format" width="558px" height="225px" /></p>
<h3>I2C Master Receiver Mode:</h3>
<p>In this mode a slave transmitter sends data to a Master Receiver. The initialization is same that we saw for Master Transmitter above, except here we set the R/W bit to 1 which means Read. The slave acknowledges it and sends data byte(s). For each byte sent by slave, the master device sends a corresponding <b>Acknowledgement bit(AA=0)</b>. If master wants to continue it can send an Acknowledge bit to salve or if master want to stop receiving data it will send a <b>&#8216;Not Acknowledge'(AA=1) bit</b> to indicate this. After this master will output a <b>STOP</b> condition. This is shown the figure below:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/electronics/i2c_tutorial/i2c_master_receiver_mode.png" alt="master receiver mode format" width="558px" height="163px" /></p>
<div class="special sp_blue notestar">Each time any activity occurs on the bus the <b>I2C0STAT</b> will be loaded with a corresponding status code and the <b>SI</b> bit is also set which triggers the ISR if defined. Using these status codes we can check for successful transfers, errors on the bus or any other conditions and proceed accordingly. After taking appropriate actions(either inside ISR or outside of ISR) we must also clear the <b>SI</b> bit every time.</div>
<h3>Procedure for I2C communication in Master Transmitter Mode:</h3>
<div class="highlight">
<ol class="list_basic">
<li><strong>1.</strong> After Enabling I2C block Enter master mode by Setting <b>STA</b> bit which will send the <b>START</b> condition. If already in Master mode a <b>REPEAT START</b> will be send.</li>
<li><strong>2.</strong> After <b>START</b> has been sent the <b>SI</b> bit in I2C0CON will be set to 1 and value of <b>I2C0STAT</b> will be <span class="doc_ref">0x08</span> . For <b>REPEAT START</b> <b>I2C0STAT</b> will be <span class="doc_ref">0x10</span> .</li>
<li><strong>3.</strong> Now load <b>I2C0DAT</b> with 7 bit <b>Slave Address(SLA) + R/W bit i.e. SLA+RW</b>. Here it will be <b>SLA+W</b>(Note: W=0, R=1). Next clear <b>SI</b> to transfer this first byte.</li>
<li><strong>4.</strong> After <b>SLA+R/W</b> has been sent, an <b>Acknowledge/ACK(AA=0)</b> bit is received and <b>SI</b> bit is set again. At this point status code(s) <span class="doc_ref">0x28</span> , <span class="doc_ref">0x30</span> &amp; <span class="doc_ref">0x38</span> are possible.</li>
<li><strong>5.</strong> Now depending on the Status proceed further.
<ol class="list_basic">
<li><strong>5.1 </strong>In normal situation status code will be <span class="doc_ref">0x18</span> which means <b>SLA+W</b> has been Transmitted and <b>ACK(A=0)</b> has been Received.</li>
<li><strong>5.2 </strong>Next, load the data to be sent into <b>I2C0DAT</b> and then clear <b>STA</b>, <b>STO</b> and <b>SI</b> bits using <b>I2C0CONCLR</b> to transmit data.</li>
<li><strong>5.3</strong> When data has been sent and an <b>ACK</b> has been received <b>I2C0STAT</b> will be <span class="doc_ref">0x28</span> . To keep transmitting data goto step 5.2.
<ol class="list_basic">
<li><strong>5.3.1</strong> If slave sends a <b>Not Acknowledge/NACK(AA=1)</b> bit the Status code will be <span class="doc_ref">0x38</span> and a <b>STOP</b> condition will be transmitted.</li>
<li><strong>5.3.2</strong> Or you can stop the transmission with a <b>STOP</b> condition by setting <b>STO</b> bit in <b>I2C0CONSET</b>.</li>
</ol>
</li>
</ol>
</li>
</ol>
</div>
<div class="special sp_blue noteinfo">The <b>STO</b> bit in <b>I2C0CONSET</b> auto clears after the <b>STOP</b> condition is sent. So if you want to start the communication again you will need to wait till the <b>STO</b> bit clears. In code implementations not using ISR(like in our case) this is done by monitoring the <b>STO</b> bit. After <b>STO</b> bit is reset you send a <b>START</b> condition to transmit/receive data again.</div>
<h3>Procedure for I2C communication in Master Receiver Mode:</h3>
<div class="highlight">
<ol class="list_basic">
<li><strong>1.</strong> Same as in Master Transmitter Mode.</li>
<li><strong>2.</strong> Same as in Master Transmitter Mode.</li>
<li><strong>3.</strong> Here we load <b>I2C0DAT</b> with <b>Slave Address + Read bit (SLA+R)</b>. Clear <b>SI</b> to continue.</li>
<li><strong>4.</strong> After <b>SLA+R</b> has been sent, an <b>ACK(AA=0)</b> bit is received and <b>SI</b> bit is set again. At this point status code(s) <span class="doc_ref">0x38</span> , <span class="doc_ref">0x40</span> &amp; <span class="doc_ref">0x48</span> are possible.</li>
<li><strong>5.</strong> Now depending on the Status proceed further.
<ol>
<li><strong>5.1</strong> In normal situation <b>I2C0STAT</b> will be <span class="doc_ref">0x40</span> which means <b>SLA+R</b> has been Transmitted and <b>ACK</b> has been Received.</li>
<li><strong>5.2</strong> Now to receive data from Slave, set the <b>AA</b> bit and clear <b>SI</b> bit.</li>
<li><strong>5.3</strong> If Data has been sent and <b>ACK(AA=0)</b> has been returned the status code will be <span class="doc_ref">0x50</span>.
<ol>
<li><strong>5.3.1</strong> To keep on receiving data, keep on setting <b>AA</b> bit everytime.</li>
<li><strong>5.3.2</strong> To stop receiving data, send a <b>NOT ACK(AA=1)</b> by clearing <b>AA</b> bit after which status code will be <span class="doc_ref">0x58</span> which means Data has been send and <b>NOT ACK(A=1)</b> has been returned.</li>
</ol>
</li>
</ol>
</li>
</ol>
</div>
<h2 class="shead">LPC2148 I2C ARM7 Setup &amp; Programming</h2>
<div class="special sp_blue noteinfo"><strong>Implementation Note:</strong> We can either implement the I2C code using an ISR which handles every thing =or= we can implement a state driven code in which we do not use ISR but instead use functions to handle the events by waiting for <b>SI</b> bit to be set and then clearing it to trigger next action. We can also implement it using a mix of ISR and event functions.</p>
<p>In our case we will NOT implement any ISR but will be implement a state driven code. In my opinion this makes it easier to code and understand.</p></div>
<p>In order to communicate with any I2C device we need to set the <b>I2C clock frequency</b>. The I2C Clock/bit frequency is set using 2 registers: <b>I2CxSCLH and I2CxSCLL</b>. I2CxSCLH defines the number of PCLK(Peripheral Clock) cycles for the I2C Clock(SCL) High time while I2CxSCLL defines the number of PCLK cycles for the I2C Clock(SCL) Low time. It is given a simple formula as given below :</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/i2c/i2c_clock_speed_formula.png" width="400px" height="70px" /></p>
<p>Note that LPC214x ARM7 Microcontrollers support a maximum I2C frequency of 400KHz. In our case we will use a frequency of 100KHz. Given our PCLK is running at 60Mhz we need to set <b>I2C0SCLH</b> = <b>I2C0SCLL = 300 for IC20 Module</b>.</p>
<p class="compact_header">Now lets, define some bits which will help us setup the <b>I2C0ONCLR</b> and <b>I2C0CONSET</b> registers to initialize the I2C0 block before we can use it.</p>
<pre><code class="language-cpp">
#define I2EN (1&lt;&lt;6) //Enable/Disable bit
#define STA  (1&lt;&lt;5) //Start Set/Clear bit
#define STO  (1&lt;&lt;4) //Stop bit
#define SI   (1&lt;&lt;3) //Serial Interrupt Flag Clear bit
#define AA   (1&lt;&lt;2) //Assert Acknowledge Set/Clear bit
</code></pre>
<p>Now, we will define some basic &#8216;building block&#8217; functions which will help us in programming the I2C module without complicating it too much.</p>
<p class="compact_header"><strong>1. I2C initialization function &#8211; <span class="code_var">I2C0Init()</span>: </strong> It first select the I2C function of the respective pins. Then it configures the I2C bit rate(I2C bus clock), clears <span class="doc_ref">I2C0CONCLR</span> register and then finally enables the I2C0 block using <span class="doc_ref">I2C0CONSET</span> register.</p>
<pre><code class="language-cpp">
void I2C0Init(void) 
{
	PINSEL0 |= (0&lt;&lt;7)|(1&lt;&lt;6)|(0&lt;&lt;5)|(1&lt;&lt;4); //Select SCL0(P0.2) and SDA0(P0.3)
	I2C0SCLL = 300;
	I2C0SCLH = 300; //I2C0 @ 100Khz, given PCLK @ 60Mhz
	I2C0CONCLR = STA | STO | SI | AA; //Clear these bits
	I2C0CONSET = I2EN; //Enable I2C0
	//After this we are ready to communicate with any other device connected to the same bus.
}
</code></pre>
<p class="compact_header"><strong>2. SI wait function &#8211; <span class="code_var">I2C0WaitForSI(void)</span>:</strong> This functions waits for the SI bit to be set after any action taken by the I2C hardware. When this bit is set it indicates that the action taken by I2C module has been completed i.e. a new event has occurred which in turn changes the status code in <span class="doc_ref">I2C0STAT</span>.</p>
<pre><code class="language-cpp">
bool I2C0WaitForSI(void) //Wait till I2C0 block sets SI
{
	int timeout = 0;
	while ( !(I2C0CONSET &amp; SI) ) //Wait till SI bit is set. This is important!
	{
		timeout++;
		if (timeout &gt; 10000) return false; //In case we have some error on bus
	}
	return return; //SI has been set
}
</code></pre>
<p class="compact_header"><strong>3. Send START/Repeat-START function &#8211; <span class="code_var">I2C0SendStart()</span>:</strong> This functions sends a START condition as soon as the bus becomes free =or= sends a Repeat START is already in master mode and then waits till SI bit set.</p>
<pre><code class="language-cpp">
void I2C0SendStart(void)
{
	I2C0CONCLR = STA | STO | SI | AA; //Clear everything
	I2C0CONSET = STA; //Set start bit to send a start condition
	I2C0WaitForSI(); //Wait till the SI bit is set
}
</code></pre>
<p class="compact_header"><strong>4. Send STOP Function &#8211; <span class="code_var">I2C0SendStop()</span>:</strong> This function sends a STOP condition and then waits for the STO bit in <span class="doc_ref">I2C0CONSET</span> to auto clear which indicates was sent on the bus.</p>
<pre><code class="language-cpp">
void I2C0SendStop(void)
{
	int timeout = 0;
	I2C0CONSET = STO ; //Set stop bit to send a stop condition
	I2C0CONCLR = SI;
	while (I2C0CONSET &amp; STO) //Wait till STOP is send. This is important!
	{
		timeout++;
		if (timeout &gt; 10000) //In case we have some error on bus
		{
			printf("STOP timeout!\n");
			return;
		}
	}
}
</code></pre>
<p class="compact_header"><strong>5. I2C Transmit Byte function &#8211; <span class="code_var">I2C0TX_Byte(unsigned char)</span>:</strong> This function sends a byte on the I2C bus and then waits for SI to be set.</p>
<pre><code class="language-cpp">
void I2C0TX_Byte(unsigned char data)
{
 	I2C0DAT = data;
	I2C0CONCLR = STA | STO | SI; //Clear These to TX data
	I2C0WaitForSI(); //wait till TX is finished
}
</code></pre>
<p class="compact_header"><strong>6. I2C Receive Byte function &#8211; <span class="code_var">I2C0RX_Byte(bool)</span>:</strong></p>
<pre><code class="language-cpp">
unsigned char I2C0RX_Byte(bool isLast)
{
	if(isLast) I2C0CONCLR = AA; //Send NACK to stop; I2C block will send a STOP automatically, so no need to send STOP thereafter.
	else 	     I2C0CONSET = AA; //Send ACK to continue
	I2C0CONCLR = SI; //Clear SI to Start RX
	I2C0WaitForSI(); //wait till RX is finished
	return I2C0DAT;
}
</code></pre>
<p>Now armed with the I2C communication building block functions we can interface LPC2148 in Master Transmitter or Master Receiver mode with any slave device.</p>
<h2 class="shead">LPC2148 I2C Example: Interfacing 24LC64 EEPROM</h2>
<p>Now, lets do an I2C programming example where we Write and Read to an EEPROM. I&#8217;ll be using 24LC64 for this example. Make sure you refer its datasheet- just in case 😉</p>
<p>Here is the connection diagram between LPC2148 Microcontroller and EEPROM:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/i2c/i2c_24lc64_interface_schematic_arm7_lpc2148.png" alt="I2C 24LC64 EEPROM Interface schematic arm7 lpc2148" width="389px" height="306px" /></p>
<p>In order to Read and Write to EEPROM we will define 1 macro and 2 functions as follows:</p>
<p class="compact_header"><strong>1. <span class="code_var">checkStatus(int)</span> Macro function:</strong> This functions checks if the current value in <span class="doc_ref">I2C0STAT</span> is same as argument supplied to. If not it will send STOP condition and make the calling function return false which indicates an error condition.</p>
<pre><code class="language-cpp">
#define checkStatus(statusCode) \
if(I2C0STAT!=statusCode) \
{ \
	printf("Error! Expected status code: %i(decimal), Got: %i(decimal)\n",statusCode,I2C0STAT); \
	I2C0SendStop(); return false; \
}
</code></pre>
<p class="compact_header"><strong>2. <span class="code_var">I2C0WriteEEPROM(&#8230;)</span> function:</strong> This writes data from buffer to the I2C slave device. It takes 3 arguments : <span class="code_var">startDataAddress</span> &#8211; the starting address inside EEPROM where the writes must begin from , <span class="code_var">data</span> &#8211; a pointer to data buffer which contains data to be written to eeprom, <span class="code_var">length</span> &#8211; length of the data buffer.</p>
<pre><code class="language-cpp">
/*(C) Umang Gajera | Power_user_EX - www.ocfreaks.com 2011-17. LPC2148 I2C Tutorial
More Embedded tutorials @ www.ocfreaks.com/cat/embedded*/
bool I2C0WriteEEPROM(unsigned int startDataAddress, unsigned char *data, int length)
{	
	for(int count=0 ; count&lt; length ; count++ ) { I2C0SendStart(); //Send START on the Bus to Enter Master Mode checkStatus(0x08); //START sent I2C0TX_Byte(I2CSlaveAddr &amp; 0xFE); //Send SlaveAddress + 0 to indicate a write. checkStatus(0x18);//SLA+W sent and ack recevied I2C0TX_Byte((startDataAddress &amp; 0xFF00)&gt;&gt;8); //Send Word Address High byte first. (24xx64 needs 2 word address bytes)
		checkStatus(0x28); //High byte has been sent and ACK recevied

		I2C0TX_Byte(startDataAddress &amp; 0xFF); //Now send the Low byte of word Address
		checkStatus(0x28); //Low byte has been sent and ACK recevied

		I2C0TX_Byte(data[count]); //Finally send the data byte.
		checkStatus(0x28); //Data Byte has been sent and ACK recevied

		startDataAddress++; //Increment to next address
		I2C0SendStop(); //Send STOP since we are done.
		
		//Now initiate write acknowledge polling as given on page 9 of 24LC64's datasheet
		const int retryTimeout = 100;
		for(int i=0; i &lt; retryTimeout; i++)
		{
			I2C0SendStart();
			checkStatus(0x08);
			I2C0TX_Byte(I2CSlaveAddr &amp; 0xFE);
			if(I2C0STAT == 0x18) //ACK recieved which indicates completion of write cycle
			{
				I2C0SendStop();
				//printf("Write Completed! for data = %c\n",data[count]);
				goto OUT;
			}
			I2C0SendStop();
		}
		I2C0SendStop();
		printf("Warning: Write Poll Timeout! for data = %c\n",data[count]);

		OUT:; //Get us out of the loop.
	}
	return true;
}
</code></pre>
<p class="compact_header"><strong>3. <span class="code_var">I2C0ReadEEPROM(&#8230;)</span> function:</strong> This reads data to buffer from the I2C slave device. Arguments are similar to those of <span class="code_var">I2C0WriteEEPROM();</span></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera | Power_user_EX - www.ocfreaks.com 2011-17. LPC2148 I2C Tutorial
More Embedded tutorials @ www.ocfreaks.com/cat/embedded*/
bool I2C0ReadEEPROM(unsigned int startDataAddress, unsigned char *data , int length)
{ 
	unsigned char RXData = 0;
	for(int i=0; i &lt; length;i++) { I2C0SendStart(); //Send START on the Bus to Enter Master Mode checkStatus(0x08); //START sent I2C0TX_Byte(I2CSlaveAddr &amp; 0xFE); //Send SlaveAddress + 0 to indicate a write. checkStatus(0x18);//SLA+W sent and ACK recevied I2C0TX_Byte((startDataAddress &amp; 0xFF00)&gt;&gt;8); //Send Word Address High byte first. (24xx64 needs 2 word address bytes)
		checkStatus(0x28); //High byte has been sent and ACK recevied

		I2C0TX_Byte(startDataAddress &amp; 0xFF); //Now send the Low byte of word Address
		checkStatus(0x28); //Low byte has been sent and ACK recevied

		startDataAddress++; //Increment to next address		

		I2C0SendStart(); //Send Repeat START, since we are already in Master mode
		checkStatus(0x10); //Repeat START sent

		I2C0TX_Byte(I2CSlaveAddr | 0x01); //This makes SLA-RW bit to 1 which indicates read.
		checkStatus(0x40); //SLA-R has been Transmitted and ACK received.

		if(i != length-1)	RXData = I2C0RX_Byte(false); //Send NACK for last byte to indicate we want to stop
		else RXData = I2C0RX_Byte(true); //Send ACK for byte other than last byte to indicate we want to continue.
		
		data[count++] = RXData; //Write recieved data to buffer
		printf("Data='%c' ",RXData);
		
	}
	return true;
}
</code></pre>
<p class="compact_header">Finally here is the code for <span class="code_var">main()</span> function:</p>
<div class="special special sp_blue noteinfo">Note that I have used UART0 to send the <span class="code_var">printf()</span> output to serial console hence in order to view the output you must connect the UART0 pins on your LPC214x to your computer/laptop using a suitable USB to Serial convertor (I am using FTDI(FT232) based USB to Serial module). The CPU clock and PCLK are both configured @ 60Mhz using <span class="code_var">initClocks()</span> function. Source code for these functions including <span class="code_var">initUART0()</span> are present in the header file <span class="code_var">ocfreaks_sh.h</span> which is the support header file for all my LPC2148 tutorials.</div>
<pre><code class="language-cpp">
/*(C) Umang Gajera | Power_user_EX - www.ocfreaks.com 2011-17. LPC2148 I2C Tutorial
More Embedded tutorials @ www.ocfreaks.com/cat/embedded*/
#include &lt;lpc214x.h&gt;
#include "ocfreaks_sh.h" //This contains code for UART, printf(), initClocks()
#include &lt;stdint.h&gt;

#define I2EN (1&lt;&lt;6) //Enable/Disable bit
#define STA  (1&lt;&lt;5) //Start Set/Clear bit
#define STO  (1&lt;&lt;4) //Stop bit
#define SI   (1&lt;&lt;3) //Serial Interrupt Flag Clear bit
#define AA   (1&lt;&lt;2) //Assert Acknowledge Set/Clear bit

void I2C0Init(void);
bool I2C0WaitForSI(void);
void I2C0SendStart(void);
void I2C0SendStop(void);
void I2C0TX_Byte(unsigned char data);
unsigned char I2C0RX_Byte(int isLast);

bool I2C0ReadEEPROM(unsigned int addresss, unsigned char *data, int length);
bool I2C0WriteEEPROM(unsigned int address, unsigned char *data, int length);

unsigned char I2CSlaveAddr = 0xA0; //Address of EEPROM (A2=0,A1=0,A0=0)

int main(void)
{
	initClocks();
	initUART0();
	I2C0Init();

	printf("(C) ocfreaks.com - LPC2148 I2C tutorial.\nExample: Interfacing 24LC64 EEPROM.\n\n");
	
	#define BUFF_SIZE 30 //29 Characters + 1 Termination Character = 30 Total
	unsigned char bufferWrite[BUFF_SIZE] = "www.ocfreaks.com I2C Tutorial"; 
	unsigned char bufferRead[BUFF_SIZE] = {0};

	//Write data from bufferWrite to EEPROM
	printf("Writing data to EEPROM... \n");
	if( !I2C0WriteEEPROM(0,bufferWrite,BUFF_SIZE) )
	{
		printf("Writing Error!\n");
	}
	printf("Write finished!\n\n");

	//Read EEPROM Data into bufferRead
	printf("Reading data from EEPROM: \n");
	if( !I2C0ReadEEPROM(0,bufferRead,BUFF_SIZE) )
	{
		printf("Reading Error!\n");
	}

	printf("\n\nData bytes recevied are as follows:\n");
	printf("\"");
	for(int i=0; i &lt; BUFF_SIZE; i++)
	{
		printf("%c",(char)bufferRead[i]);
	}
	printf("\"");
	printf("\n\nDone!\n");
	
	while(1); //Loop infinitely.
	return 0; //Normally, this won't execute.
}
</code></pre>
<p><b>Serial Output:</b></p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/i2c/lpc2148_i2c_eeprom_example_screenshot.png" alt="I2C 24LC64 EEPROM Interface lpc214x example output screenshot" width="589px" height="322px" /></p>
<div class="highlight"><strong>Download Project Source / I2C Sample code @</strong> <a href="https://www.ocfreaks.com/imgs/_downloads/lpc2148/OCFreaks.com_LPC214x_I2C_Tutorial.zip">LPC214x I2C Tutorial.zip</a> [Successfully tested on Keil UV5.23]</div>
<p><strong>LPC2148 Development Boards that we Recommend:</strong></p>
<p><a href="https://www.amazon.in/NXP-ARM7-LPC2148-Header-Board/dp/B01LX5AN08/ref=as_li_ss_il?_encoding=UTF8&amp;psc=1&amp;refRID=1ATG383W1SGQG4FNZN0R&amp;linkCode=li2&amp;tag=o0cd4-21&amp;linkId=619cbbc7eb302c8ca4af6877b8c1152c" target="_blank" rel="noopener noreferrer"><img decoding="async" src="//ws-in.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;ASIN=B01LX5AN08&amp;Format=_SL160_&amp;ID=AsinImage&amp;MarketPlace=IN&amp;ServiceVersion=20070822&amp;WS=1&amp;tag=o0cd4-21" border="0" /></a><img decoding="async" style="border: none !important; margin: 0px !important;" src="https://ir-in.amazon-adsystem.com/e/ir?t=o0cd4-21&amp;l=li2&amp;o=31&amp;a=B01LX5AN08" alt="" width="1" height="1" border="0" /><a href="https://www.amazon.in/Development-Board-LPC2148-USB-FT232-Driver-memory/dp/B00T04NLYE/ref=as_li_ss_il?ie=UTF8&amp;qid=1491577410&amp;sr=8-8&amp;keywords=lpc2148&amp;linkCode=li2&amp;tag=o0cd4-21&amp;linkId=8628d2ee5db112ddbaab7aaedc6ec22f" target="_blank" rel="noopener noreferrer"><img decoding="async" src="//ws-in.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;ASIN=B00T04NLYE&amp;Format=_SL160_&amp;ID=AsinImage&amp;MarketPlace=IN&amp;ServiceVersion=20070822&amp;WS=1&amp;tag=o0cd4-21" border="0" /></a><img decoding="async" style="border: none !important; margin: 0px !important;" src="https://ir-in.amazon-adsystem.com/e/ir?t=o0cd4-21&amp;l=li2&amp;o=31&amp;a=B00T04NLYE" alt="" width="1" height="1" border="0" /><a href="https://www.amazon.in/LPC2148-Development-Board-Standard-Package/dp/B019QTWRVU/ref=as_li_ss_il?ie=UTF8&amp;qid=1491577410&amp;sr=8-1&amp;keywords=lpc2148&amp;linkCode=li2&amp;tag=o0cd4-21&amp;linkId=1f88a47711dbb1f232ece64e5a4a79d3" target="_blank" rel="noopener noreferrer"><img decoding="async" src="//ws-in.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;ASIN=B019QTWRVU&amp;Format=_SL160_&amp;ID=AsinImage&amp;MarketPlace=IN&amp;ServiceVersion=20070822&amp;WS=1&amp;tag=o0cd4-21" border="0" /></a><img decoding="async" style="border: none !important; margin: 0px !important;" src="https://ir-in.amazon-adsystem.com/e/ir?t=o0cd4-21&amp;l=li2&amp;o=31&amp;a=B019QTWRVU" alt="" width="1" height="1" border="0" /><a href="https://www.amazon.in/Explore-Embedded-ARM7-LPC2148-Dev/dp/B018XJ0F5Y/ref=as_li_ss_il?ie=UTF8&amp;qid=1491577410&amp;sr=8-5&amp;keywords=lpc2148&amp;linkCode=li2&amp;tag=o0cd4-21&amp;linkId=bc5b00fa1663b938453ff3d765a3e165" target="_blank" rel="noopener noreferrer"><img decoding="async" src="//ws-in.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;ASIN=B018XJ0F5Y&amp;Format=_SL160_&amp;ID=AsinImage&amp;MarketPlace=IN&amp;ServiceVersion=20070822&amp;WS=1&amp;tag=o0cd4-21" border="0" /></a><img loading="lazy" decoding="async" style="border: none !important; margin: 0px !important;" src="https://ir-in.amazon-adsystem.com/e/ir?t=o0cd4-21&amp;l=li2&amp;o=31&amp;a=B018XJ0F5Y" alt="" width="1" height="1" border="0" /></p>
<p>The post <a href="https://www.ocfreaks.com/lpc2148-i2c-programming-tutorial/">LPC2148 I2C Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/lpc2148-i2c-programming-tutorial/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2752</post-id>	</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/

Page Caching using Disk: Enhanced 

Served from: www.ocfreaks.com @ 2026-03-09 08:25:02 by W3 Total Cache
-->