<?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>Embedded - OCFreaks!</title>
	<atom:link href="https://www.ocfreaks.com/cat/embedded/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.ocfreaks.com/cat/embedded/</link>
	<description>Overclocking , Gaming , Technology , Robotics &#38; DIY!</description>
	<lastBuildDate>Wed, 04 Dec 2024 06:47:16 +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>Create new STM32 project in Keil uVision 5 tutorial</title>
		<link>https://www.ocfreaks.com/create-new-stm32-project-keil-uvision-5-tutorial/</link>
					<comments>https://www.ocfreaks.com/create-new-stm32-project-keil-uvision-5-tutorial/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Wed, 25 Jul 2018 10:51:26 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[guide]]></category>
		<category><![CDATA[stm32]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3103</guid>

					<description><![CDATA[<p>In this tutorial we see how to create project in KEIL MDK uVision 5 for STM32 ARM Cortex-M based MCUs. Its for beginners  who want to get started in programming STM32 with Keil. This tutorial also applies for all supported devices across the STM32 Family.</p>
<p>The post <a href="https://www.ocfreaks.com/create-new-stm32-project-keil-uvision-5-tutorial/">Create new STM32 project in Keil uVision 5 tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/common/keil_5_title.png" class="aligncenter" alt="" width="445px" height="227px" /></p>
<p>In this tutorial we see how to create project in KEIL MDK uVision 5 for STM32 ARM Cortex-M based MCUs. Its for beginners who want to get started in programming STM32 with Keil. This tutorial also applies for all supported devices across the STM32 Family viz. STM32F0/F1/F2/F4/F7/etc/. Keil uV 5 is much different than older Keil uV4. uVision 5 has integrated pack installer which is used to install specific MCU family packs and other libraries. To create project for STM32 MCU, you will first need to install <strong>MDK5 software packs</strong> for your microcontroller family. Either you can download it separately or do it from within the IDE.I recommend adding software packs using IDE.</p>
<p>Basically three(or more?) types of STM32 Keil projects can be created:</p>
<ol>
<li>One that uses CMSIS(core) only.</li>
<li>One that is based on Standard Peripheral Library.</li>
<li>Finally, one that is based on HAL (Hardware abstraction Layer) Library.</li>
</ol>
<p>For the sake of this tutorial we will see how to create CMSIS and SPL based STM32F103C8 Keil uv5 project, as an example, but will work exactly the same for STM32F0, STM32F4, and other families. I will cover HAL based projects in another tutorial. </p>
<h2 class="shead">1) Installing prerequisite STM32 Keil software pack</h2>
<p><strong>If already installed, you can SKIP this.</strong></p>
<p><strong>Step A.</strong> Download latest Keil MDK uVision5 from <a href="https://www.keil.com/demo/eval/arm.htm" target="_blank">Keil&#8217;s website</a>.</p>
<p><strong>Step B.</strong> Install Keil uVision 5 to default path.</p>
<p><strong>STEP C.</strong> Open Keil 5 and click on <span class="doc_ref">&#8220;Pack Installer&#8221;</span> icon as shown below:</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/common/keil5_pack_installer.png" class="aligncenter" alt="" width="687px" height="179px" /></p>
<p><strong>STEP D.</strong> On the left half on the window, under <span class="doc_ref">&#8220;Devices&#8221;</span> type <span class="doc_ref">&#8220;STM3F103C8&#8221;</span><br />
(<strong>or</strong> other device name depending on the device present on your development board) in search box and select the MCU in the list below. Now, on the right half of the window click on the <span class="doc_ref">&#8220;install&#8221;</span> button which is towards to the right of <span class="doc_ref">&#8220;Keil:STM32F1xxx_DFP&#8221;</span> and <span class="doc_ref">&#8220;Keil:STM32NUCLEO_B&#8221;</span>. Repeat this step if want to add support for other device family. After this, wait until pack installer finishes downloading the required pack files for selected MCU.</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/stm32_keil_uv5_project_cmsis_spl/c_install_stm32_dfp.png" class="aligncenter" alt="keil install software pack for STM32" width="691px" height="447px" /></p>
<p>Alternatively, you can manually download the software pack and install it directly from <a href="https://www.keil.com/dd2/pack/">MDK5 Software Packs</a>. It will be present Under <span class="doc_ref">&#8220;KEIL-> STMicroelectronics STM32F1 Series Device Support, Drivers&#8221;</span>. In general for STM32Fx Devices.</p>
<p><strong>STEP E.</strong> After installing from Pack Installer you will get a confirmation to reload packs. Click <span class="doc_ref">&#8220;Yes&#8221;</span> as shown below:</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/common/keil5_pack_install_confirm.png" class="aligncenter" alt="" width="322px" height="165px" /></p>
<h2 class="shead">2) Step by step Tutorial</h2>
<p>Okay, so now we have the necessary packs installed to create our first STM32 project in Keil 5. Just follow the steps mentioned below to create a new project in Keil uV 5 or if your project is not working properly:</p>
<h4>Step 1.</h4>
<p>Open the Keil IDE, under main menu goto <span class="doc_ref">&#8220;Project->New uVision Project&#8230;&#8221;</span> and a window prompt will open asking to save the new project. Type your desired project name and save.</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/common/keil5_new_project.png" class="aligncenter" alt="new project" width="513px" height="141px" /></p>
<h4>Step 2.</h4>
<p>After that, a new window will appear as shown below. Make sure <span class="doc_ref">&#8220;Software Packs&#8221;</span> is selected for the 1st drop down. In the search box below it, type <span class="doc_ref">&#8220;STM32F103C8&#8221;</span> and then select the device from list below. For e.g.: STM32F103C8 for STM32 Blue Pill, STM32F103RB for Nucleo-F103RB, STM32F030R8 for Nucleo-F030R8 and so on.</p>
<p>Finally click <span class="doc_ref">&#8220;OK&#8221;</span>. </p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/stm32_keil_uv5_project_cmsis_spl/3_select_stm32_mcu.png" class="aligncenter" alt="select STM32 target MCU" width="626px" height="468px" /></p>
<h4>Step 3.</h4>
<p><strong>A. For CMSIS: </strong><br />
Inside the <span class="doc_ref">&#8220;Manage Run-Time Environment Window&#8221;</span> select the check boxes for <span class="doc_ref">&#8220;CORE&#8221;</span> under <span class="doc_ref">&#8220;CMSIS&#8221;</span> and <span class="doc_ref">&#8220;Startup&#8221;</span> under <span class="doc_ref">&#8220;Device&#8221;</span>. If you want to select any other libraries you can do so by selecting the respective checkboxes. Selecting <span class="doc_ref">&#8220;Startup&#8221;</span> will automatically add all the necessary startup/boot files required for STM32F1xx device, so we don&#8217;t have to import them from external sources. The selection of libraries can be changed any time later.</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/stm32_keil_uv5_project_cmsis_spl/4_stm32_cmsis_startup.png" class="aligncenter" alt="Select libraries" width="560px" height="549px" /></p>
<p><strong>B. For Standard Peripheral Library (SPL):</strong><br />
If you want to use SPL, the select the required peripheral library components as required. Note that some components have dependencies as well, so you will also need to include dependent components. For. E.g. GPIO needs RCC to enable clocks. </p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/stm32_keil_uv5_project_cmsis_spl/4b_stm32_spl.png" class="aligncenter" alt="Select components for SPL" width="560px" height="603px" /></p>
<h4>Step 4.</h4>
<p>Now click on <span class="doc_ref">&#8220;Options for Target&#8221;</span> button as shown below:</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/stm32_keil_uv5_project_cmsis_spl/5_target_options_stm32.png" class="aligncenter" alt="Keil Options for Target" width="540px" height="196px" /></p>
<p>Make sure the settings match as shown below.</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/stm32_keil_uv5_project_cmsis_spl/6_setting_stm32.png" class="aligncenter" alt="Target settings" width="626px" height="468px" /></p>
<h4>Step 5.</h4>
<p>Now, click on the <span class="doc_ref">&#8220;Output&#8221;</span> tab. If you want to generate hex file then you can check <span class="doc_ref">&#8220;Create HEX File&#8221;</span>. You also enter a suitable name for the executable output file.</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/stm32_keil_uv5_project_cmsis_spl/7_output_hex_file.png" class="aligncenter" alt="Create Hex File" width="580px" height="282px" /></p>
<h4>Step 6.</h4>
<p>Then click on the <span class="doc_ref">&#8220;Linker&#8221;</span> tab and Under that tab check the checkbox option which says <span class="doc_ref">&#8220;Use Memory Layout from Target Dialog&#8221;</span>.</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/common/keil5_linker_options.png" class="aligncenter" alt="keil linker options" width="626px" height="268px" /></p>
<h4>Step 7.</h4>
<p>Now, under the <span class="doc_ref">&#8220;Debug&#8221;</span> tab, select ST-LINK as debugger since its the most common for debugging and programming STM32. Finally to click <span class="doc_ref">&#8220;OK&#8221;</span> to apply settings and close window.</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/stm32_keil_uv5_project_cmsis_spl/8_select_debugger.png" class="aligncenter" alt="STM32 Keil uv5 Debug options" width="626px" height="468px" /></p>
<h4>Step 8.</h4>
<p>Now, in the source navigation pane on the left area, right click on <span class="doc_ref">&#8220;Source Group 1&#8221;</span> and select <span class="doc_ref">&#8220;Add New Item to Group &#8216;Source Group 1&#8242;&#8221;</span>.</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/stm32_keil_uv5_project_cmsis_spl/9_add_files.png" class="aligncenter" alt="add new item to source" width="517px" height="370px" /></p>
<h4>Step 9.</h4>
<p>A new window will pop-up to add an item as shown below. Select <span class="doc_ref">&#8220;C File (.c)&#8221;</span> or C++ File (.cpp) , then enter the name of the file in the text box to the right of <span class="doc_ref">&#8220;Name:&#8221;</span> and click <span class="doc_ref">&#8220;Add&#8221;</span>.</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/stm32_keil_uv5_project_cmsis_spl/10.png" class="aligncenter" alt="add files to keil project" width="460px" height="435px" /></p>
<h4>Step 10.</h4>
<p>Now you can write your code in the editor. To compile your program Press <span class="doc_ref">&#8220;F7&#8221;</span> key or in the main menu goto <span class="doc_ref">&#8220;Project->Build Target&#8221;.</span> To check for any compilation errors you can have a look at the build output at the bottom of main window. Two screenshots of the Keil MDK uVision 5 are given below. </p>
<p><strong>A. For CMSIS Core Project:</strong><br />
<img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/stm32_keil_uv5_project_cmsis_spl/12a_compile_cmsis_only.png" class="aligncenter" alt="Keil uv5 screenshot STM32 CMSIS" width="688px" height="549px" /> </p>
<p><strong>B. For Standard Peripheral Library based Project</strong>:</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/embedded/stm32_keil_uv5_project_cmsis_spl/12b_compile_spl.png" class="aligncenter" alt="Keil uv5 screenshot STM32 SPL" width="690px" height="550px" /> </p>
<p>The post <a href="https://www.ocfreaks.com/create-new-stm32-project-keil-uvision-5-tutorial/">Create new STM32 project in Keil uVision 5 tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/create-new-stm32-project-keil-uvision-5-tutorial/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3103</post-id>	</item>
		<item>
		<title>MSP430 Timer Programming Tutorial</title>
		<link>https://www.ocfreaks.com/msp430-timer-programming-tutorial/</link>
					<comments>https://www.ocfreaks.com/msp430-timer-programming-tutorial/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Sun, 22 Jul 2018 12:12:35 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[MSP430]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3099</guid>

					<description><![CDATA[<p>In this tutorial we will go through MSP430 Timer programming for MSP430x2xx devices like MSP430G2553, MSP430G2231 found on Launchpad development board. We will also cover two timer examples.</p>
<p>The post <a href="https://www.ocfreaks.com/msp430-timer-programming-tutorial/">MSP430 Timer Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="tocpostimage">In this tutorial we will go through MSP430 Timer programming for MSP430x2xx devices like <strong>MSP430G2553, MSP430G2231</strong> found on Launchpad development board. MSP430G2 devices have two 16-bit timers i.e. <strong>Timer_A and Timer_B</strong>. Timer_B is slightly different than Timer_A and also has few more features, but it is <strong>NOT</strong> implemented in both MSP430G2553 and MSP430G2331 micro-controllers. Hence, we will focus on <strong>Timer_A</strong> for this tutorial.</p>
<div class="toc_container">
<span class="toc_title">Table of Contents</span></p>
<div class="toc">
<ol class="toc_list">
<li class="toc_text"><a href="#Intro"><span>Introduction</span></a></li>
<li class="toc_text"><a href="#Timer_Regs"><span>MSP430 Timer Registers</span></a></li>
<li class="toc_text"><a href="#Timer_Config"><span>Configuring &#038; Setting Up Timer in MSP430</span></a></li>
<li class="toc_text"><a href="#Timer_Formulae"><span>Handy MSP430 Timer Formulae for delay calculations</span></a></li>
<li class="toc_text"><a href="#Timer_Examples"><span>MSP430 Timer Examples</span></a></li>
<ol class="toc_list">
<li class="toc_text"><a href="#Example_1"><span>A simple Delay function using Interrupt</span></a></li>
<li class="toc_text"><a href="#Example_2"><span>Blinky using MSP430 Timer Interrupt</span></a></li>
</ol>
</ol>
</div>
</div>
<h2 class="shead" id="Intro" style="margin-top:5px;">Introduction</h2>
<p>MSP430G2553 has two Timer_As viz. <strong>Timer0_A3</strong> and <strong>Timer1_A3</strong> which features 3 capture/compare registers while MSP430G2231 has only 1 timer called <strong>Timer0_A2</strong> with only 2 capture/compare registers. In addition to Capture, Timer_A also supports PWM outputs and interrupts. They also include a Watchdog Timer (WDT+) which I will discuss in another tutorial.</p>
<div class="special sp_blue noteinfo">The naming convention used in datasheet is &#8220;<strong>Timer<em>n</em>_A<em>x</em></strong>&#8221; where <strong>n</strong> = Timer module number, <strong>x</strong> = no. of. capture/compare registers supported.</div>
<p>Timer_A supports four different clock sources: ACLK, SMCLK and 2 external sources: TACLK or INCLK. The selected clock source can then be divided by 1,2,4 or 8. The register used for counting is called TAR(16-bit R/W) and can increment or decrement for each rising edge of clock signal. Compared to Timer blocks of other microcontrollers, these MCUs don&#8217;t support prescaler.  </p>
<h4>Timer Modes:</h4>
<p><strong>Timer_A supports 4 modes of operation:</strong></p>
<ol style="margin-bottom:10px;">
<li><strong>Stop Mode:</strong> In this mode the Timer is Halted.</li>
<li><strong>Up Mode:</strong> Timer repeatedly counts from Zero to value stored in Capture/Compare Register 0 (TACCR0).</li>
<li><strong>Continuous:</strong> Timer repeatedly counts from Zero to 0xFFFF, which is maximum value for 16-bit TAR.</li>
<li><strong>Up/Down Mode:</strong> Timer repeatedly counts from Zero up to the value in TACCR0 and back down to zero.</li>
</ol>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/msp430-tutorial/msp430_timer_modes.png" width="470px" height="620px" alt="Timer Modes in MSP430 microcontrollers"></p>
<h2 class="shead" id="Timer_Regs">MSP430 Timer Registers</h2>
<p><strong>1) <span class="doc_ref">TAR</span> &#8211; Timer Counter Register:</strong> Holds the current count for Timer_A.</p>
<p><strong>2) <span class="doc_ref">TACCRx</span> &#8211; Timer Capture/Compare Register:</strong> In Compare mode, it holds compare value to be compared against TAR. In Capture mode, it holds the current value of TAR when a capture is performed. Maximum value it can store is 0xFFFF since its a 16 bit register.</p>
<p><strong>3) <span class="doc_ref">TACTL</span> &#8211; Control Register:</strong> Used to configure Timer_A. This register is divided as follows:</p>
<ul>
<li><strong>Bit[0] &#8211; <span class="doc_ref">TAIFG</span> &#8211; Timer_A Interrupt Flag</strong>. 0 = No interrupt pending, 1 = Interrupt pending.</li>
<li><strong>Bit[1] &#8211; <span class="doc_ref">TAIE</span> &#8211; Timer_A Interrupt Enable.</strong> 0 = Interrupt Disabled, 1 = Interrupt Enabled.</li>
<li><strong>Bit[2] &#8211; <span class="doc_ref">TACLR</span> &#8211; Timer_A clear.</strong> Setting this bit resets TAR, clock divider, and the count direction. It is automatically reset and is always read as zero.</li>
<li><strong>Bits[5:4] &#8211; <span class="doc_ref">MCx</span> &#8211; Mode Control bits.</strong> Used to select between 4 different modes as given:<br />
[00] = MC_0 &#8211; Stop mode: Timer is halted.<br />
[01] = MC_1 &#8211; Up mode: Timer counts up to TACCR0.<br />
[10] = MC_2 &#8211; Continuous mode: Timer counts up to 0xFFFF.<br />
[11] = MC_3 &#8211; Up/down mode: Timer counts up to TACCR0 then down to 0x0000.</li>
<li><strong>Bit[7:6] &#8211; <span class="doc_ref">IDx</span> &#8211; Input divider.</strong> Selects input clock divider.<br />
[00] = ID_0 &#8211; /1<br />
[01] = ID_1 &#8211; /2<br />
[10] = ID_2 &#8211; /4<br />
[11] = ID_3 &#8211; /8</li>
<li><strong>Bits[9:8] <span class="doc_ref">TASSELx</span> &#8211; Timer_A clock source select.</strong><br />
[00] = TASSEL_0 &#8211; TACLK<br />
[01] = TASSEL_1 &#8211; ACLK<br />
[10] = TASSEL_2 &#8211; SMCLK<br />
[11] = TASSEL_3 &#8211; INCLK (check datasheet)</li>
<li>Other Bits &#8211; Reserved</li>
</ul>
<p><strong>3) <span class="doc_ref">TACCTLx</span> &#8211; Capture/Compare Control Register:</strong> Used to configure capture/compare options. I will only cover the parts of this register which are applicable to this tutorial. We will see it in detail in other tutorials(for Capture mode &#038; PWM).</p>
<ul>
<li><strong>Bit[0] &#8211; <span class="doc_ref">CCIFG</span> &#8211; Capture/compare interrupt flag:</strong> 0 = interrupt pending, 1 = Interrupt pending.</li>
<li><strong>Bit[4] &#8211; <span class="doc_ref">CCIE</span> &#8211; Capture/compare interrupt enable:</strong> This bit enables the interrupt request of the corresponding CCIFG flag. 0 = Interrupt disabled = 1 Interrupt enabled.</li>
<li><strong>Bit[8] &#8211; <span class="doc_ref">CAP</span> &#8211; Capture mode:</strong> Used to select between Compare and Capture mode. We will this bit in its default setting i.e. = 0. 0 = Compare mode, 1 = Capture mode.</li>
</ul>
<p><strong>4) <span class="doc_ref">TAIV</span> &#8211; Interrupt Vector Register:</strong> Used to identify the flag which requested an interrupt. This is a read only register and only uses 3 bits [3:1] called TAIVx. The values for TAIVx which corresponds to various sources is as given below:</p>
<ul>
<li>0x00 = No Interrupt Pending.</li>
<li>0x02 = Capture/Compare 1 &#8211; TACCR1 CCIFG.</li>
<li>0x04 = Capture/Compare 2 &#8211; TACCR2 CCIFG.</li>
<li>0x0A = Timer(TAR) Overflow &#8211; TAIFG.</li>
<li>Other &#8211; Reserved.</li>
</ul>
<div class="special sp_blue noteinfo"><strong>Timer Register Naming Convention:</strong> Using the register names as given in user manual will default to Timer0_A3 registers. For e.g. TACTL is same as TA0CTL. Note that Timer registers are defined as TA<strong>n</strong>CTL, TA<strong>n</strong>CCR0 and so on.. where <strong>n</strong> = Timer module number(in our case 0 or 1). For Timer1_A3 these names will be TA<strong>1</strong>CTL, TA<strong>1</strong>CCR0 and so on. TA<strong>0</strong>CTL and other Timer0_A3 are just redefined as TACTL, TACCR0 and so on. </div>
<h2 class="shead" id="Timer_Config">Configuring &#038; Setting Up Timer in MSP430</h2>
<p>Given, clocks are configured properly, <strong>basic setup</strong> of Timer_A can be done follows:</p>
<ul style="margin-bottom:10px;">
<li>Set the Compare value in <span class="code_var">TACCR0</span> if using Up mode or Up/Down mode. Timer may be stopped by using <span class="code_var">TACCR0 = 0;</span> and can be started/restarted any time by writing a non-zero compare value in <span class="code_var">TACCR0</span> whenever Timer is to be used. Total Counts by timer will be <span class="code_var">TACCR0 + 1</span>.</li>
<li>Set CCIE(Capture/Counter Interrupt Enable) bit in <span class="code_var">TACCTL0</span> to enable interrupt for <strong>CCR0</strong>. We also keep the CAP bit to default value(=0) to enable Compare mode.</li>
<li>Select Clock Source, Input Clock divider and Timer mode using <span class="code_var">TASSELx, IDx, MCx</span> fields respectively.</li>
<li>Enable global Interrupts and we are done.</li>
</ul>
<div class="special sp_yellow noteinfo">Note that TACCR0 has dedicated interrupt vector. Other TACCRx have common interrupt vector(see TAIVx and section 12.2.6 on page 367 in User Manual).</div>
<p>In examples given below we will use Up mode with input clock source as SMCLK(MCx = MC_1) without an divider(IDx = ID_0 i.e. divide by 1). We will set MCLK and SMCLK to run at 1MHz, both sourcing clock from DCO. This is the default configuration.</p>
<pre><code class="language-cpp">
TACCR0 = ..; //Compare Value for TAR
TACCTL0 |= CCIE; //Enable interrupt for CCR0.
TACTL = TASSEL_2 + ID_0 + MC_1; //Select SMCLK, SMCLK/1 , Up Mode
_enable_interrupt();
/* More code */
</code></pre>
<h2 class="shead" id="Timer_Formulae">Handy MSP430 Timer Formulae for delay calculations</h2>
<p>Formula for amount of time taken to increment TAR count by 1 is given as:</p>
<div class="equation" style="font-size:16px;margin-bottom:10px;">Resolution(Delay per TAR Count) in Seconds = </p>
<div class="fraction"><span class="fup">DIV</span><span class="bar">/</span><span class="fdn">Input Clock in Hz</span></div>
</div>
<p>where DIV = Input Clock divider either 1,2,4 or 8.</p>
<p><strong>E.g.:</strong> When using divider of /2 and Input clock of 4MHz we get timer resolution as,</p>
<div class="equation" style="font-size:15px;margin-bottom:10px;">Resolution = </p>
<div class="fraction"><span class="fup">2</span><span class="bar">/</span><span class="fdn">4 x 10<sup>6</sup>Hz</span></div>
<p>Seconds = 0.5 x 10<sup>-6</sup> Seconds = 0.5 µS</div>
<p>The time required for TAR to count from 0 and reach TACCR0 (i.e. overflow or TAR period) is given as:</p>
<div class="equation" style="font-size:16px;margin-bottom:10px;">Timer Period in Seconds = </p>
<div class="fraction"><span class="fup">DIV x (TACCR0 + 1)</span><span class="bar">/</span><span class="fdn">Input Clock in Hz</span></div>
</div>
<p>We subtract 1 from TACCR0 since TAR counts &#8220;TACCR0+1&#8221; times to overflow. This is because count starts from 0.</p>
<p><strong>E.g.:</strong> When using divider of /2, Input clock of 4MHz and TACCR0 = 1000-1 = 999, we get Timer Period as,</p>
<div class="equation" style="font-size:15px;margin-bottom:10px;">Timer Period = </p>
<div class="fraction"><span class="fup">2 x (999 + 1)</span><span class="bar">/</span><span class="fdn">4 x 10<sup>6</sup>Hz</span></div>
<p> = 0.5 x 1000 x 10<sup>-6</sup> S = 500 µS</div>
<h2 class="shead" id="Timer_Examples">MSP430 Timer Examples</h2>
<p>Now, lets cover 2 Timer examples. Both examples are valid for MSP430G2553 , MSP430G2231 and similar MCUs.</p>
<h4 id="Example_1">Example 1: A simple Delay function using Interrupt</h4>
<p>Of-course, we have the option of using inbuilt function <span class="code_var">__delay_cycles(..)</span>, but wheres the fun if we don&#8217;t implement a similar function using Timer? Anyways, in this example we will define a function called <strong><span class="code_var">delayMS(int msec)</span></strong> which generates delay as per given input in mill-seconds. This function is used in conjunction with Timer_A Interrupt for <strong>CCR0</strong>. The time is counting, ISR continuously increments an Overflow counter when <span class="code_var">TAR</span> reaches value in <span class="code_var">TACCR0</span>. We set the value in <span class="code_var">TACCR0</span> such that counting from 0 to <span class="code_var">TACCR0</span> takes exactly 1ms, and hence we get a resolution of 1ms for our delay function. This function will give more accurate delay as MCLK increases, since it contains a few statements which eat up proportionate amount CPU cycles. Now, since we are using <strong>Timer Clock = 1MHz</strong> (SMCLK=1MHz), 1000 ticks will equal to 1ms. Hence, we use <span class="code_var">TACCR0 = 1000</span> inside delay function. In general for <strong>Y</strong> MHz timer clock, <strong>Y</strong> x 1000 ticks are required for 1ms delay. Before exiting the function we use <span class="code_var">TACCR0 = 0</span> to stop the Timer.</p>
<pre><code class="language-cpp">
#include &lt;msp430.h&gt;

void initTimer_A(void);
void delayMS(int msecs);

unsigned int OFCount;

int main(void)
{
	WDTCTL = WDTPW + WDTHOLD; //Stop watchdog timer
	P1DIR |= BIT0; //Configure P1.0 as Output

	//Set MCLK = SMCLK = 1MHz
	BCSCTL1 = CALBC1_1MHZ;
	DCOCTL = CALDCO_1MHZ;

	initTimer_A();
	_enable_interrupt();

	while(1)
	{
		P1OUT |= BIT0; //Drive P1.0 HIGH - LED1 ON
		delayMS(500); //Wait 0.5 Secs

		P1OUT &= ~BIT0; //Drive P1.0 LOW - LED1 OFF
		delayMS(500); //Wait 0.5 Secs
	}
}

void initTimer_A(void)
{
	//Timer0_A3 Configuration
	TACCR0 = 0; //Initially, Stop the Timer
	TACCTL0 |= CCIE; //Enable interrupt for CCR0.
	TACTL = TASSEL_2 + ID_0 + MC_1; //Select SMCLK, SMCLK/1, Up Mode
}

void delayMS(int msecs)
{
	OFCount = 0; //Reset Over-Flow counter
	TACCR0 = 1000-1; //Start Timer, Compare value for Up Mode to get 1ms delay per loop
	//Total count = TACCR0 + 1. Hence we need to subtract 1.

	while(i<=msecs);

	TACCR0 = 0; //Stop Timer
}

//Timer ISR
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A_CCR0_ISR(void)
{
	OFCount++; //Increment Over-Flow Counter
}
</code></pre>
<h4 id="Example_2">Example 2: Blinky using MSP430 Timer Interrupt</h4>
<p>In this example, instead of using a dedicated delay function we place the blinky code inside the Timer_A Interrupt itself. The Timer initialization code is same as before. The Timer is never stopped and it repeatedly restarts counting when <span class="code_var">TAR</span> reaches <span class="code_var">TACCR0</span> to generate 1ms delay. Similar to previous example, an overflow counter is maintained by ISR itself. We just need to define how much delay(in ms) we require. This is done by defining a MACRO <span class="code_var">BLINKY_DELAY_MS</span>. Also, note that we won't be using Low Power Mode (LMP0). If you want to use LMP0 than make sure <span class="code_var">TACCR0</span> has a suitable maximum value along with higher clock divider, so CPU stays disabled most of the time. In our case we can use <span class="code_var">TACCR0 = 50000;</span> and use overflow count limit of 10 for 500ms delay. In this way the ISR is called every 50ms when clock divider is 1, and every 200ms when clock divider is 4.</p>
<pre><code class="language-cpp">
#include &lt;msp430.h&gt;
#define BLINKY_DELAY_MS 500 //Change this as per your needs

void initTimer_A(void);
void delayMS(int msecs);

unsigned int OFCount;

int main(void)
{
	WDTCTL = WDTPW + WDTHOLD; //Stop watchdog timer
	P1DIR |= BIT0; //Configure P1.0 as Output

	//Set MCLK = SMCLK = 1MHz
	BCSCTL1 = CALBC1_1MHZ;
	DCOCTL = CALDCO_1MHZ;

	initTimer_A();
	_enable_interrupt();

	OFCount  = 0;
	TACCR0 = 1000-1; //Start Timer, Compare value for Up Mode to get 1ms delay per loop
	/*Total count = TACCR0 + 1. Hence we need to subtract 1.
	1000 ticks @ 1MHz will yield a delay of 1ms.*/

	while(1);
}

void initTimer_A(void)
{
	//Timer Configuration
	TACCR0 = 0; //Initially, Stop the Timer
	TACCTL0 |= CCIE; //Enable interrupt for CCR0.
	TACTL = TASSEL_2 + ID_0 + MC_1; //Select SMCLK, SMCLK/1 , Up Mode
}

//Timer ISR
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A_CCR0_ISR(void)
{
	OFCount++;
	if(OFCount >= BLINKY_DELAY_MS)
	{
		P1OUT ^= BIT0;
		OFCount = 0;
	}
}
</code></pre>
<p>The post <a href="https://www.ocfreaks.com/msp430-timer-programming-tutorial/">MSP430 Timer Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/msp430-timer-programming-tutorial/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3099</post-id>	</item>
		<item>
		<title>LPC1768 Timer Input Capture &#038; Frequency Counter Tutorial</title>
		<link>https://www.ocfreaks.com/lpc1768-timer-input-capture-frequency-counter-tutorial/</link>
					<comments>https://www.ocfreaks.com/lpc1768-timer-input-capture-frequency-counter-tutorial/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Tue, 17 Jul 2018 18:28:46 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[lpc1768]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3092</guid>

					<description><![CDATA[<p>In this tutorial we will go through the programming of input capture mode for timer module of ARM Cortex-M3 LPC176x microcontrollers along with a frequency counter example using capture input.</p>
<p>The post <a href="https://www.ocfreaks.com/lpc1768-timer-input-capture-frequency-counter-tutorial/">LPC1768 Timer Input Capture &#038; Frequency Counter 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 the programming of input capture mode for timer module of ARM Cortex-M3 LPC1768 microcontroller along with a frequency counter example using capture input. In my previous <a href="https://www.ocfreaks.com/lpc1768-timer-programming-tutorial/" target="_blank">LPC1768 Timer tutorial</a> we saw how to setup and program the timer module.</p>
<h3>Capture Channels and Input pins</h3>
<p>Each timer block in LPC176x has 2 Input Capture Channels (CAPn.0 &#038; CAPn.1, n=Timer number). 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:5px;">
<tr>
<th colspan="2">Timer0</th>
<th colspan="2">Timer1</th>
<th colspan="2">Timer2</th>
<th colspan="2">Timer3</th>
</tr>
<tr>
<td>Ch.</td>
<td>Pin</td>
<td>Ch.</td>
<td>Pin</td>
<td>Ch.</td>
<td>Pin</td>
<td>Ch.</td>
<td>Pin</td>
</tr>
<tr>
<td>CAP0.0</td>
<td>P1.26</td>
<td>CAP1.0</td>
<td>P0.18</td>
<td>CAP2.0</td>
<td>P0.4</td>
<td>CAP3.0</td>
<td>P0.23</td>
</tr>
<tr>
<td>CAP0.1</td>
<td>P1.27</td>
<td>CAP1.1</td>
<td>P0.19</td>
<td>CAP2.1</td>
<td>P0.5</td>
<td>CAP3.1</td>
<td>P0.24</td>
</tr>
</table>
<h3>Using Capture Inputs in LPC176x</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/lpc1768-tutorial/lpc176x_timer_module_with_capture.png" width="610px" height="340px" alt="ARM CORTEX-M3 LPC1768 LPC1769 Timer Capture Block diagram" /></p>
<p>Here is a simple diagram depicting the capture process. Dashed arrows(for both diagrams) signify 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>Since I have already discussed main Timer Registers in my <a href="https://www.ocfreaks.com/lpc1768-timer-programming-tutorial/" target="_blank">LPC1768 Timer tutorial</a>, we will only have a look at registers relating to capture.</p>
<div class="highlight"><strong>1) <span class="doc_ref">CCRx</span> &#8211; Capture Control Register</strong>: Used to select which type of Egde(rising/falling/both) is used to Capture Registers (CR0-CR1) 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, are for <strong>CR1</strong>.</p>
<p><strong>2) <span class="doc_ref">CR0 &#038; CR1</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 LPC1768 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 TIMERn_PCLK of 100Mhz we can measure upto 50Mhz signal properly. For second method we can only measure up to around 0.83 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 Timer2 module to measure frequency. Capture Channel CAP2.0 is used as capture input. CAP2.0 is mapped to Pin P0.4 on LPC1768, hence we select CAP2.0 alternate function for P0.4. On mbed platform P0.4 is labelled as p30 and P2.0 as p26. Schematic is also same for both.</p>
<p>To generate a square wave output, we can use LPC176x&#8217;s inbuilt PWM module, configured with 0.02 us resolution. PWM1.1 output channel is used which gives output on Pin P2.0. Refer my <a href="https://www.ocfreaks.com/lpc1768-pwm-programming-tutorial/" target="_blank"> LPC1768 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 projects linked below also contain <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/lpc1768-tutorial/lpc176x_input_capture_mode_eg_sch.png" width="465px" height="275px" alt="ARM Cortex-M3 LPC1768/LPC1769 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 Timer2. Every positive going edge will increment the Timer2 Counter (<span class="code_var">LPC_TIM2->TC</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">LPC_TIM2->TC</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 50Mhz using TIMER2_PCLK=100Mhz. 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
LPC176x Input Capture Tutorial - Example 1(Using Gating) for frequency counter using ARM KEIL
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License: GPL.*/

#include &lt;lpc17xx.h&gt;
#include &lt;stdio.h&gt; //for printf() - https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/
#include "ocf_lpc176x_lib.h" //contains initUART0(), initTimer0() & putc() to retarget printf()

void initPWM(void);
unsigned int pulses = 0;
#define GATE_TIME_MS 1000 // Probing/Gating Time in ms

int main(void)
{
	//SystemInit(); //Gets called by Startup code, sets CCLK=100Mhz, PCLK=25Mhz
	initUART0(); //Initialize UART0 for uart_printf() - see ocf_lpc176x_lib.c
	initTimer0(); //For delayMS() - see ocf_lpc176x_lib.c
	
	/*Using CCLK = 100Mhz and PCLK_TIMER2 = 100Mhz.*/
	LPC_SC->PCONP |= (1<<22); //Power-Up Timer2 module. It is disabled by default.
	LPC_SC->PCLKSEL1 |= (1<<12); //Set bits[13:12] = [01] to select PCLK_TIMER2 = CCLK i.e. 100Mhz in our case. 
	LPC_PINCON->PINSEL0 |= (1<<9) | (1<<8); //Set Bits[9:8] = [11] to Select CAP2.0 for P0.4
	LPC_TIM2->CTCR = 0x1; //Increment TC on rising edges of External Signal for CAP2.0
	LPC_TIM2->PR = 0; //Using lowest PR gives most accurate results
	LPC_TIM2->CCR = 0x0; //Must be [000] for selected CAP input
	LPC_TIM2->TCR = 0x2; //Reset & Disable Timer2 Initially
	
	initPWM(); //To generate square wave signal	
	float FreqKhz = 0;
	printf("OCFreaks.com - LPC1768x Frequency Counter Example 1:\n");

	while(1)
	{
		LPC_TIM2->TCR = 0x1; //Start Timer2
		delayMS(GATE_TIME_MS); //'Gate' signal for defined Time (1 second)
		LPC_TIM2->TCR = 0x0; //Stop Timer2
		
		pulses = LPC_TIM2->TC; //Read current value in TC, which contains  no.of. pulses counted in 1s
		LPC_TIM2->TCR = 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/lpc1768-pwm-programming-tutorial/
	/*Using CCLK = 100Mhz and PCLK_PWM1 = 100Mhz.*/
	
	//By default PWM1 block is powered-on
	LPC_SC->PCLKSEL0 |= (1<<12); //Set bits[13:12] = [01] to select PCLK_PWM1 = CCLK i.e. 100Mhz in our case. 
	LPC_PINCON->PINSEL4 |= (1<<0); // Select PWM1.1 output for Pin2.0
	LPC_PWM1->PCR = 0x0; //Select Single Edge PWM - by default its single Edged so this line can be removed
	LPC_PWM1->PR = 0; //PR+1 = 0+1 = 1 Clock cycle @100Mhz = 0.01us = 10ns
	LPC_PWM1->MR0 = 4; //4x0.01 = 0.04us - period duration i.e. 25Mhz Test frequency
	LPC_PWM1->MR1 = 2; //2x0.01 = 0.02us - pulse duration (50% duty cycle)
	LPC_PWM1->MCR = (1<<1); // Reset PWMTC on PWMMR0 match
	LPC_PWM1->LER = (1<<1) | (1<<0); // update MR0 and MR2
	LPC_PWM1->PCR = (1<<9); // enable PWM1.1 output
	LPC_PWM1->TCR = (1<<1) ; //Reset PWM TC &#038; PR

	LPC_PWM1->TCR = (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/LPC1768-Tutorial-Examples/tree/master/Frequency_Counter/Example_1" target="_blank">LPC176x Frequency Counter Example 1</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC1768-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.02us (or 20ns) is selected by using Prescaler value of 1 with PCLK=CCLK=100Mhz. We configure CCR so that the capture occurs for rising edges and an interrupt is also generated.</p>
<p>The main logic of this frequency counter example lies in the Timer2 interrupt handler function itself where we are measuring the period of the square wave signal. 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>
<div class="special sp_blue noteinfo">Maximum value for frequency of external signal that can be reliably measured depends on the PCLK, Prescalar (PR) and the execution Latency of Timer Interrupt Routine. Out of the three, the main limiting factor is the interrupt execution latency. If the frequency is too fast, an Interrupt Request (IRQ) will be raised even before current IRQ has been served. If this happens the pending interrupt flag will be set and cpu will immediately serve the same ISR without entering main() function. This will happen back to back and the code inside main() won't execute unless signal frequency is reduced. Also, for measurement to be reliable, NO new IRQ must be raised while ISR is under execution.</p>
<p style="margin-bottom:0px;">Hence, inside ISR we will have to add additional code to indicate this condition using a flag. Inevitably this will increase the interrupt latency, but never the less we will be able reject 'over-the-limit' frequencies without stalling the code inside main(). While testing the code given below I was able to measure frequencies around 833Khz or 0.83Mhz without stalling code inside main.</p>
</div>
<p><strong>Source Code Snippet</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera - www.ocfreaks.com
LPC176x Input Capture Tutorial - Example 2 for Frequency counter using ARM KEIL
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License: GPL.*/

#include &lt;lpc17xx.h&gt;
#include &lt;stdio.h&gt; //for printf() - https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/
#include "ocf_lpc176x_lib.h" //contains initUART0(), initTimer0() & putc() to retarget printf()

void initPWM(void);
unsigned int period = 0;
unsigned int previous = 0;
unsigned int current = 0 ;
int limitFlag = 0;
#define TIMER_RES 0.02 //Depends on Timer PCLK and PR. Used to convert measured period to frequency. 

int main(void)
{
	//SystemInit(); //Gets called by Startup code, sets CCLK=100Mhz, PCLK=25Mhz
	initUART0(); //Initialize UART0 for uart_printf() - see ocf_lpc176x_lib.c
	initTimer0(); //For delayMS() - see ocf_lpc176x_lib.c
	
	/*Using CCLK = 100Mhz and PCLK_TIMER2 = 100Mhz.*/
	LPC_SC->PCONP |= (1<<22); //Power-Up Timer2 module. It is disabled by default.
	LPC_SC->PCLKSEL1 |= (1<<12); //Set bits[13:12] = [01] to select PCLK_TIMER2 = CCLK i.e. 100Mhz in our case. 
	LPC_PINCON->PINSEL0 |= (1<<9) | (1<<8); //Set Bits[9:8] = [11] to Select CAP2.0 for P0.4
	LPC_TIM2->CTCR = 0x0;
	LPC_TIM2->PR = 1; //PR+1 = 1+1 = 2 clock cycles @ 100Mhz = 0.02us res
	LPC_TIM2->TCR = 0x02; //Reset Timer
	LPC_TIM2->CCR = (1<<0) | (1<<2); //Capture on Rising Edge(0->1) and generate an interrupt
	LPC_TIM2->TCR = 0x01; //Enable timer1
	
	NVIC_EnableIRQ(TIMER2_IRQn); //Enable TIMER2 IRQ
	initPWM(); //To generate square wave	
	
	printf("OCFreaks.com - Frequency Counter Example 2\n");

	while(1)
	{
		if(limitFlag)
		{
			printf("Input Frequency limit reached!\n");
			NVIC_EnableIRQ(TIMER2_IRQn); //Try to measure signal frequency again
			delayMS(500);
		}
		else
		{
			printf("Frequency = %0.2f Khz\n",((1.0/(period*TIMER_RES)) * 1000)); //Convert to frequency, 0.02 is Timer resolution
			delayMS(500); //2 Udpates per second
		}
	}
	
	//return 0; //This won't execute normally
}

void TIMER2_IRQHandler(void)
{
	LPC_TIM2->IR |= (1<<4); //Clear Interrupt Flag
	current = LPC_TIM2->CR0;
	if(current < previous) //TC has overflowed
	{
		period = 0xFFFFFFFF + current - previous;
	}
	else
	{
		period = current - previous;
	}
	previous = current; //LPC_TIM2->CR0;
	
	if(period < 60)
	{
		NVIC_DisableIRQ(TIMER2_IRQn);
		limitFlag = 1;
	}
	else limitFlag = 0;
}

void initPWM(void)
{
	//Refer: https://www.ocfreaks.com/lpc1768-pwm-programming-tutorial/
	/*Using CCLK = 100Mhz and PCLK_PWM1 = 100Mhz.*/
	
	//By default PWM1 block is powered-on
	LPC_SC->PCLKSEL0 |= (1<<12); //Set bits[13:12] = [01] to select PCLK_PWM1 = CCLK i.e. 100Mhz in our case. 
	LPC_PINCON->PINSEL4 |= (1<<0); // Select PWM1.1 output for Pin2.0
	LPC_PWM1->PCR = 0x0; //Select Single Edge PWM - by default its single Edged so this line can be removed
	LPC_PWM1->PR = 1; //PR+1 = 1+1 = 2 Clock cycles @100Mhz = 0.02us
	LPC_PWM1->MR0 = 80; //80x0.02 = 1.6us - period duration i.e. 625Khz Test frequency
	LPC_PWM1->MR1 = 40; //40x0.02 = 0.8us - pulse duration (50% duty cycle)
	LPC_PWM1->MCR = (1<<1); // Reset PWMTC on PWMMR0 match
	LPC_PWM1->LER = (1<<1) | (1<<0); // update MR0 and MR2
	LPC_PWM1->PCR = (1<<9); // enable PWM1.1 output
	LPC_PWM1->TCR = (1<<1) ; //Reset PWM TC &#038; PR

	LPC_PWM1->TCR = (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 LPC_PWM1->MR0 and LPC_PWM1->MR1 to measure other lower frequencies. The program will reject frequencies above 833.3 Khz.</p>
<p><strong>Download Example 2 Project Files:</strong></p>
<div class="highlight"><strong>KEIL ARM uV5/uV4 Project for above example</strong> <a href="https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/Frequency_Counter/Example_2" target="_blank">LPC176x Frequency Counter Example 2</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC1768-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/lpc1768-timer-input-capture-frequency-counter-tutorial/">LPC1768 Timer Input Capture &#038; Frequency Counter Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/lpc1768-timer-input-capture-frequency-counter-tutorial/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3092</post-id>	</item>
		<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>Interfacing IR Sensor with LPC1768</title>
		<link>https://www.ocfreaks.com/interfacing-ir-sensor-lpc1768/</link>
					<comments>https://www.ocfreaks.com/interfacing-ir-sensor-lpc1768/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Thu, 03 May 2018 15:03:46 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[lpc1768]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3082</guid>

					<description><![CDATA[<p>In this tutorial we will discuss how to interface an IR(Infra-Red) photo-diode with ARM Cortex-M3 LPC1768 microcontroller and cover two IR interfacing examples.</p>
<p>The post <a href="https://www.ocfreaks.com/interfacing-ir-sensor-lpc1768/">Interfacing IR Sensor with LPC1768</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this tutorial we will discuss how to interface an IR(Infra-Red) photo-diode with ARM Cortex-M3 LPC1768 microcontroller. Its also applicable to LPC1769 and other devices of same family. A photodiode is a diode which additionally 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 and similar robots.</p>
<h4>Working principle</h4>
<p>An IR LED is used as a source of Infra-Red light (i.e. a Transmitter). A revered-biased IR photodiode (Sensor, i.e. a 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>The IR photodiode(IR Sensor) current can be converted 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 distance. In the diagram given below, the voltage drop is given 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 logic HIGH means an obstacle is detected and a logic 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 LPC1768</h2>
<h4>Interfacing IR photodiode using LPC176x 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 12-bit ADC of LPC1768 to convert the voltage into digital readings. You can check my <a href="https://www.ocfreaks.com/lpc1768-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-lpc1768/" target="_blank">LPC176x 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/lpc1768-tutorial/lpc176x_ir_interfacing_analog.png" alt="Interfacing IR photodiode with LPC1768" width="430px" height="250px" /></p>
<p><strong>Example 1 Source Code:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera - www.ocfreaks.com
LPC1768/LPC1769 IR Sensor Interfacing Example 1 Source Code for KEIL ARM.
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
Also refer: https://www.ocfreaks.com/lpc1768-adc-programming-tutorial/
License : GPL.*/

#include &lt;lpc17xx.h&gt;
#include &lt;stdio.h&gt; //for printf() - https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/
#include "ocf_lpc176x_lib.h" //contains initUART0(), initTimer0() & putc() to retarget printf()

#define ADC_CLK_EN (1<<12)
#define SEL_AD0_0  (1<<0) //Select Channel AD0.0 
#define CLKDIV     1 //ADC clock-divider (ADC_CLOCK=PCLK/CLKDIV+1) = 12.5Mhz @ 25Mhz PCLK
#define PWRUP      (1<<21) //setting it to 0 will power it down
#define START_CNV  (1<<24) //001 for starting the conversion immediately
#define ADC_DONE   (1U<<31) //define it as unsigned value or compiler will throw #61-D warning
#define ADCR_SETUP_SCM ((CLKDIV<<8) | PWRUP)
#define VREF       3.3 //Reference Voltage at VREFP pin, given VREFN = 0V(GND)

int main(void)
{
	//SystemInit(); //Gets called by Startup code, sets CCLK=100Mhz, PCLK=25Mhz
	initUART0(); //Initialize UART0 for uart_printf() - defined in ocf_lpc176x_lib.c
	initTimer0(); //For delayMS() - defined in ocf_lpc176x_lib.c

	LPC_SC->PCONP |= ADC_CLK_EN;
	LPC_PINCON->PINSEL1 |= (1<<14); //select AD0.0 for P0.23
	LPC_ADC->ADCR =  ADCR_SETUP_SCM | SEL_AD0_0;
	int result = 0;
	
	printf("OCFreaks.com LPC176x IR Sensor Interfacing Tutorial - Example 1.\n");
	
	while(1)
	{
		LPC_ADC->ADCR |= START_CNV; //Start new Conversion

		while((LPC_ADC->ADDR0 & ADC_DONE) == 0); //Wait untill conversion is finished
		
		result = (LPC_ADC->ADDR0>>4) & 0xFFF; //12 bit Mask to extract result
		
		printf("AD0.0 = %d\n" , result); //Display raw result
		
		delayMS(500); //Slowing down Updates to 2 Updates per second
	}
	
	//return 0; //This won't execute
}
</code></pre>
<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/LPC1768-Tutorial-Examples/tree/master/IR_Interfacing/Example_1" target="_blank">IR Sensor Interfacing Example 1</a>, <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC1768-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 LPC1768 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/lpc1768-tutorial/lpc176x_ir_module.png" alt="Interfacing IR proximity sensor module with LPC1768" width="310px" height="220px" /></p>
<p><strong>Example 2 Source Code:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera - www.ocfreaks.com
LPC176x IR Proximity/Obstacle-avoidance Sensor Interfacing Example 2 Source Code for KEIL ARM.
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
Also refer: https://www.ocfreaks.com/lpc1768-adc-programming-tutorial/
License : GPL.*/

#include &lt;lpc17xx.h&gt;
#include &lt;stdio.h&gt; //for printf() - https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/
#include "ocf_lpc176x_lib.h" //contains initUART0(), initTimer0() & putc() to retarget printf()
#define PIN0_1 (1<<1)

int main(void)
{
	//SystemInit(); //Gets called by Startup code, sets CCLK=100Mhz, PCLK=25Mhz
	initUART0(); //Initialize UART0 for uart_printf() - defined in ocf_lpc176x_lib.c
	initTimer0(); //For delayMS() - defined in ocf_lpc176x_lib.c
	
	printf("OCFreaks.com LPC176x ADC Tutorial Example 1.\nSoftware Controlled ADC Mode on AD0.0 Channel.\n");
	
	while(1)
	{
		//Check the O/P Logic of your IR module. Mine gives LOW when obstacle is detected else HIGH.
		if((LPC_GPIO0->FIOPIN & PIN0_1) == 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
}
</code></pre>
<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/LPC1768-Tutorial-Examples/tree/master/IR_Interfacing/Example_2" target="_blank">IR Sensor Interfacing Example 2</a>, <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC1768-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-lpc1768/">Interfacing IR Sensor with LPC1768</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/interfacing-ir-sensor-lpc1768/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3082</post-id>	</item>
		<item>
		<title>Interfacing HC-SR04 Ultrasonic Distance Sensor with LPC1768</title>
		<link>https://www.ocfreaks.com/interfacing-hc-sr04-ultrasonic-distance-sensor-lpc1768/</link>
					<comments>https://www.ocfreaks.com/interfacing-hc-sr04-ultrasonic-distance-sensor-lpc1768/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Thu, 12 Apr 2018 17:43:53 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[lpc1768]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3075</guid>

					<description><![CDATA[<p>In this tutorial I will discuss, how to interface an Ultrasonic distance sensor (HC-SR04) with ARM Cortex-M3 LPC1768 microcontroller. The HC-SR04 Ultrasonic Distance/Ranging Sensor uses ultrasound to measure distance from a object ahead of the sensor.</p>
<p>The post <a href="https://www.ocfreaks.com/interfacing-hc-sr04-ultrasonic-distance-sensor-lpc1768/">Interfacing HC-SR04 Ultrasonic Distance Sensor with LPC1768</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this tutorial I will discuss, how to interface an Ultrasonic distance sensor (HC-SR04) with ARM Cortex-M3 LPC1768 microcontroller. The HC-SR04 Ultrasonic Distance/Ranging Sensor uses ultrasound to measure distance from a object ahead of the sensor. Ultrasound is a soundwave having frequency greater than the audible limit i.e. > 20Khz. HCSR-04 module 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="" 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 the 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="" width="270px" height="230px" /></p>
<p><strong>HC-SR04 Interfacing Steps:</strong></p>
<ol>
<li>To start distance measurement a short pulse of 10us is applied to Trigger pin.</li>
<li>After receiving trigger pulse, the HC-SR04 Module sends 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="" 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 for sound waves to emit and echo back, lets call this time taken 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 LPC1768 Example</h4>
<p>In the interfacing example given below, P0.0 of LPC176x is configured as output and connected to TRIG pin and P0.1 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/lpc1768-uart-programming-tutorial/" target="_blank">LPC1768 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 5 Volts 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/lpc1768-tutorial/hcsr04_lpc176x_interfacing.png" alt="LPC1768 HC-SR04 Interfacing Schematic" width="495px" 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 LPC1768/LPC1769 - Example Source Code for KEIL ARM.
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License: GPL.*/

#include &lt;lpc17xx.h&gt;
#include &lt;stdio.h&gt; //for printf() - https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/
#include "ocf_lpc176x_lib.h" //contains initUART0(), initTimer0() & putc() to retarget printf()

#define TRIG (1<<0) //P0.0
#define ECHO (1<<1) //P0.1

int main(void)
{
	//SystemInit(); //Gets called by Startup code, sets CCLK=100Mhz, PCLK=25Mhz
	initUART0(); //Initialize UART0 for retargeted printf() - defined in ocf_lpc176x_lib.c
	initTimer0(); //Init Timer for delay functions - defined in ocf_lpc176x_lib.c
	int echoTime=0;
	float distance=0;

	LPC_GPIO0->FIODIR |= TRIG;    //Set P0.2(TRIG) as output
	LPC_GPIO0->FIODIR &= ~(ECHO); //Set P0.3(ECHO) as input (explicitly)
	LPC_GPIO0->FIOCLR |= TRIG;    //Set P0.2 LOW initially

	printf("OCFreaks.com LPC176x HC-SR04 Sensor Interfacing Tutorial\n");

	while(1)
	{
		//Output 10us HIGH on TRIG pin
		LPC_GPIO0->FIOPIN |= TRIG;
		delayUS(10);
		LPC_GPIO0->FIOCLR |= TRIG;

		while(!(LPC_GPIO0->FIOPIN & ECHO)); //Wait for a HIGH on ECHO pin
		startTimer0(); //Start counting
		while(LPC_GPIO0->FIOPIN & 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); //1 update per second
	}
	//return 0; //This won't execute normally
}
</code></pre>
<p><strong>Download Project:</strong></p>
<div class="highlight"><strong>KEIL ARM uV5 Project for example given above is on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/HCSR04_Interfacing" target="_blank">HCSR04 Ultrasonic Distance Sensor Interfacing with LPC1768</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/HCSR04_Interfacing" target="_blank">Download Project Zip</a>. You can find the HEX file inside objects folder.</div>
<p><strong>Screenshot:</strong></p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc1768-tutorial/hcsr04_lpc176x_ss.png" alt="LPC176x HC-SR04 example screenshot" width="501px" height="418px" /></p>
<p>The post <a href="https://www.ocfreaks.com/interfacing-hc-sr04-ultrasonic-distance-sensor-lpc1768/">Interfacing HC-SR04 Ultrasonic Distance Sensor with LPC1768</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-lpc1768/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3075</post-id>	</item>
		<item>
		<title>Interfacing LM35 Temperature Sensor with LPC1768</title>
		<link>https://www.ocfreaks.com/interfacing-lm35-temperature-sensor-lpc1768/</link>
					<comments>https://www.ocfreaks.com/interfacing-lm35-temperature-sensor-lpc1768/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Tue, 03 Apr 2018 17:31:56 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[lpc1768]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3070</guid>

					<description><![CDATA[<p>In this tutorial we will go through the interfacing of LM35 Temperature sensor with ARM Cortex-M3 LPC1768 Microcontroller with an example. LM35 is a well known low cost temperature sensor and is directly calibrated in Degrees Celsius meaning that the output voltage is directly proportional to Degrees Celsius readings.</p>
<p>The post <a href="https://www.ocfreaks.com/interfacing-lm35-temperature-sensor-lpc1768/">Interfacing LM35 Temperature Sensor with LPC1768</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this tutorial I will discuss the interfacing of LM35 Temperature sensor with ARM Cortex-M3 LPC1768 Microcontroller. LM35 is a well known low cost temperature sensor and is directly calibrated in Degrees Celsius meaning that the output voltage is directly proportional to Degrees Celsius readings. It has a measurement range is between -55°C to 150°C giving typical accuracy(s) of 0.25°C at room temperature and 0.75°C for full range. LM35 Temperature sensor 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 giving different ranges:</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>To keep things simple, we will interface LM35 in basic configuration. The first thing to note when interfacing LM35 with 3.3v MCUs, like LPC1768/LPC1769, 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 we use apply between 4V to 30V. Hence, the output voltage of LM35 can reach a maximum of 1.5V and a minimum of -55mV when configured as Full Range Centigrade Sensor. </p>
<p>When using the Basic configuration we get 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/4096 = 0.0008056V or <strong>0.8mV</strong> since LPC1768 has a <strong>12-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 0.8mV is more than sufficient. </p>
<p>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 VREFP pin is connected to 3.3V reference and VREFN to reference ground (0V).</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>12-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">4096 * 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">4096</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">4096</span></div>
<p>°C</p></div>
<h4>Example for LM35 Temperature Sensor Interfacing with LPC1768</h4>
<p>Now lets go through a simple programming example. As obvious, we will use the ADC block of LPC176x for interfacing our temperature sensor using reference voltage as mentioned above. The result obtained from ADC conversion is converted to temperature(in Deg. Celsius) reading using the equations given above. We will use UART0 to send the data to terminal. You can refer my <a href="https://www.ocfreaks.com/lpc1768-adc-programming-tutorial/" target="_blank">LPC1768 ADC Tutorial</a> and <a href="https://www.ocfreaks.com/lpc1768-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>LM35 Interfacing Schematic:</strong></p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc1768-tutorial/lm35_lpc176x_interface_schematic.png" alt="Schematic for Interfacing LM35 Temperature sensor with LPC1768 LPC1769" width="405px" height="275px" /></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 Temperature Sensor with LPC1768/LPC1769 - Example Source Code for KEIL ARM.
Also see: https://www.ocfreaks.com/lpc1768-adc-programming-tutorial/
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License: GPL.*/

#include &lt;lpc17xx.h&gt;
#include &lt;stdio.h&gt; //For retargeted printf() - https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/ 
#include "ocf_lpc176x_lib.h" //contains initUART0(), initTimer0() & putc() to retarget printf() 

#define ADC_CLK_EN (1<<12)
#define SEL_AD0_0  (1<<0) //Select Channel AD0.0 
#define CLKDIV     1 //ADC clock-divider (ADC_CLOCK=PCLK/CLKDIV+1) = 12.5Mhz @ 25Mhz PCLK
#define PWRUP      (1<<21) //setting it to 0 will power it down
#define START_CNV  (1<<24) //001 for starting the conversion immediately
#define ADC_DONE   (1U<<31) //define it as unsigned value or compiler will throw #61-D warning
#define ADCR_SETUP_SCM ((CLKDIV<<8) | PWRUP)
#define VREF       3.3 //Reference Voltage at VREFP pin, given VREFN = 0V(GND) - not used in this example.

int main(void)
{
	//SystemInit(); //Gets called by Startup code, sets CCLK=100Mhz, PCLK=25Mhz
	initUART0(); //Initialize UART0 for retargeted printf() 
	initTimer0(); //For delayMS()

	LPC_SC->PCONP |= ADC_CLK_EN;
	LPC_PINCON->PINSEL1 |= (1<<14); //select AD0.0 for P0.23
	LPC_ADC->ADCR = ADCR_SETUP_SCM | SEL_AD0_0;
	int result = 0;
	float temp = 0;
	
	printf("OCFreaks.com LPC176x LDR Interfacing - Example 1.\n");
	
	while(1)
	{
		LPC_ADC->ADCR |= START_CNV; //Start new Conversion (Software controlled)

		while((LPC_ADC->ADDR0 & ADC_DONE) == 0); //Wait untill conversion is finished
		
		result = (LPC_ADC->ADDR0>>4) & 0xFFF; //12 bit Mask to extract result
		
		temp = ((float)result * VREF * 100)/4096; //As per the Equation given in the tutorial

		printf("Temp = %0.1f Deg. Celsius\n" , temp);
		
		delayMS(500); //Slowing down Updates to 2 Updates per second
	}
	
	//return 0; //This won't execute
}
</code></pre>
<div class="highlight">
<strong>Download Project</strong><br />
KEIL ARM uV5/uV4 Project for example given above is on GitHub @ <a href="https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/LM35_Interfacing" target="_blank">LM35 Temperature Sensor Interfacing with LPC1768</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/LM35_Interfacing" target="_blank">Download Project Zip</a>. You can find the HEX file inside objects folder.</div>
<p><strong>Screenshot:</strong></p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc1768-tutorial/lm35_lpc176x_ex_ss.png" alt="Demo Screenshot for Interfacing LM35 Temperature sensor with LPC1768 LPC1769" width="501px" height="274px" /></p>
<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-temperature-sensor-lpc1768/">Interfacing LM35 Temperature Sensor with LPC1768</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/interfacing-lm35-temperature-sensor-lpc1768/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3070</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 DHT11 &#038; DHT22 Sensor with LPC1768</title>
		<link>https://www.ocfreaks.com/interfacing-dht11-dht22-sensor-lpc1768/</link>
					<comments>https://www.ocfreaks.com/interfacing-dht11-dht22-sensor-lpc1768/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Tue, 13 Mar 2018 15:57:24 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[lpc1768]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3062</guid>

					<description><![CDATA[<p>In this tutorial we learn how to interface DHT11 and DHT22 Humidity and Temperature sensor with ARM Cortex-M3 LPC1768 microcontroller.</p>
<p>The post <a href="https://www.ocfreaks.com/interfacing-dht11-dht22-sensor-lpc1768/">Interfacing DHT11 &#038; DHT22 Sensor with LPC1768</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this tutorial we learn how to interface DHT11 and DHT22 Humidity and Temperature sensor with ARM Cortex-M3 LPC1768 microcontroller. I had discussed <a href="https://www.ocfreaks.com/basics-interfacing-dht11-dht22-humidity-temperature-sensor-mcu/">basics of DHT11/DHT22 interfacing</a> in my previous tutorial. Please go through it if you are new to DHTxx Humidity and Temperature sensors.</p>
<h4>A quick recap of the communication process:</h4>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/dht/dht11_dht22_protocol.png" width="645px" height="320px" alt="DHT11 DHT22 Humidity and Temperature Sensor communication process protocol" /></p>
<h4>DHT11 &#038; DHT22 Data format:</h4>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/dht/dht_data_format.png" width="505px" height="220px" alt="DHT11 DHT22 Humidity and Temperature Sensor data format" /></p>
<p>Now, lets have a look at steps we need to implement for Programming DTH11/DHT22. 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 required for DHT11/DHT22 Interfacing:</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 LPC1768/LCP1769:</h4>
<p>In this example we will use PIN P0.0 (marked as P9 on mbed board) for communication with DHT11 sensor. For DHT22 you just need to make a small change 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 module is used for generating delay and measuring timing of responses given by DHTxx. You can go through <a href="https://www.ocfreaks.com/lpc1768-timer-programming-tutorial/" target="_blank" rel="noopener">LPC1768 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 targeted</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/lpc1768-uart-programming-tutorial/" target="_blank" rel="noopener">LPC1768 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/lpc1768-tutorial/dht11_lpc1768.png" width="350px" height="250px" 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 DHTxx. 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 Humidity &#038; Temperature sensor Interfacing Source Code Snippet</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera - www.ocfreaks.com
DHT11 Humidity and Temperature Sensor Interfacing with LPC1768/LPC1769 Example Source Code for KEIL ARM
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License : GPL.*/
#include &lt;lpc17xx.h&gt;
#include &lt;stdio.h&gt; //For retargeted printf() - https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/
#include "ocf_lpc176x_lib.h" //contains initUART0(), initTimer0() & putc() to retarget printf()

#define LOW 0
#define HIGH 1
void printError(const char * str);
void checkResponse(unsigned int waitTimeUS, unsigned int margin, unsigned char pinValue);
char getDataBit(void);

#define DATA_PIN (1<<0) //Using P0.0 for data communication

int main(void)
{
	unsigned char dataBits[40] = {0};
	char dataBytes[5] = {0};
	
	initTimer0();
	initUART0();
	
	printf("OCFreaks.com - Interfacing DHT11 with LPC1768 Example.\n");
	
	while(1)
	{
		//STEP 1: Set pin to output HIGH which represents idle state
		LPC_GPIO0->FIODIR |= DATA_PIN;
		
		//STEP 2: Pull down pin for 18ms(min) to denote START
		LPC_GPIO0->FIOCLR |= DATA_PIN;
		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.
		LPC_GPIO0->FIODIR &= ~(DATA_PIN);
		
		//STEP 4: Wait between 20 to 40us for sensor to respond
		startTimer0();
		while((LPC_GPIO0->FIOPIN & DATA_PIN) != 0)
		{
			if(LPC_TIM0->TC > 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 DHTxx 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, unsigned char pinValue)
{
	int time = 0;
	int maxwait = waitTimeUS + margin;
	
	startTimer0();
	if(pinValue)
	{
		while(LPC_GPIO0->FIOPIN & DATA_PIN)
		{
			if(LPC_TIM0->TC > (maxwait)) break; 
		}
	}
	else
	{
		while( !(LPC_GPIO0->FIOPIN & DATA_PIN) )
		{
			if(LPC_TIM0->TC > (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(LPC_GPIO0->FIOPIN & DATA_PIN)
	{
		if(LPC_TIM0->TC > 75)
		{
			return 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 
	{ 
		return 2; //Error - Timeout for data pulse
	}
}

</code></pre>
<p>Here is a screenshot of the above example in action:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc1768-tutorial/dht11_lpc1768_example_ss.png" width="549px" height="290px" alt="LPC1768 DTH11 DHT22 Humidity and Temperature sensor Interfacing Example output" /></p>
<div class="highlight"><strong>KEIL ARM uV5 Project for example given above @</strong> <a href="https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/DHT11_Interfacing" target="_blank" rel="noopener">DHT11 Interfacing with LPC1768 Example</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC1768-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/interfacing-dht11-dht22-sensor-lpc1768/">Interfacing DHT11 &#038; DHT22 Sensor with LPC1768</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/interfacing-dht11-dht22-sensor-lpc1768/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3062</post-id>	</item>
		<item>
		<title>Interfacing LDR with LPC1768</title>
		<link>https://www.ocfreaks.com/interfacing-ldr-lpc1768/</link>
					<comments>https://www.ocfreaks.com/interfacing-ldr-lpc1768/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Thu, 01 Feb 2018 17:20:41 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[lpc1768]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3059</guid>

					<description><![CDATA[<p>In this discussion we will cover how to Interface LDR with LPC1768/LPC1769 microcontroller.  Light Dependent Resistor (i.e. LDR for short) is basically used to detect the intensity of light. We will also cover two interfacing examples using in built 12-bit ADC block of LPC176x MCU.</p>
<p>The post <a href="https://www.ocfreaks.com/interfacing-ldr-lpc1768/">Interfacing LDR with LPC1768</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this tutorial we will see Interfacing of LDR with ARM Cortex-M3 LPC1768 microcontroller. Light Dependent Resistor is the full form of LDR and they are basically used to detect the intensity of light. They are also known as photoresistors or photoconductive cells. The resistance of an LDR is inversely proportional to the intensity of light directly falling on it. 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 goes down to around few ohms &#8211; in 2 to 20 Ohms range.</p>
<p>For the examples covered in this tutorial, we will use the inbuilt 12bit-ADC module of LPC1768/LPC1769 microcontroller to interface LDR. You can check my <a href="https://www.ocfreaks.com/lpc1768-adc-programming-tutorial/" target="_blank">LPC1768 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. By adding another fixed resistor in series we can form a voltage divider network and can connect the common of the resister and LDR to ADC&#8217;s input pin. Lets use 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 LPC176x 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 4095. We can directly use this value(ADC conversion Result) to detect the intensity of light. A value near 0 means Dark condition and a value near 4096 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 then select a suitable 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>. The schematic is as shown below:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc1768-tutorial/lpc176x_ldr_ex1.png" alt="LPC1768/LPC1769 LDR Interfacing Example 1 Schematic" width="305px" height="265px" /></p>
<p><strong>Source code:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera- www.ocfreaks.com
LPC1768/LPC1769 LDR Interfacing Example 1 Source Code for KEIL ARM.
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
Also see: https://www.ocfreaks.com/lpc1768-adc-programming-tutorial/
License: GPL.*/

#include &lt;lpc17xx.h&gt;
#include &lt;stdio.h&gt; //For retargeted printf() - https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/ 
#include "ocf_lpc176x_lib.h" //contains initUART0(), initTimer0() & putc() to retarget printf() 

#define ADC_CLK_EN (1<<12) 
#define SEL_AD0_0  (1<<0) //Select Channel AD0.0 
#define CLKDIV     1 //ADC clock-divider (ADC_CLOCK=PCLK/CLKDIV+1) = 12.5Mhz @ 25Mhz PCLK
#define PWRUP      (1<<21) //setting it to 0 will power it down
#define START_CNV  (1<<24) //001 for starting the conversion immediately
#define ADC_DONE   (1U<<31) //define it as unsigned value or compiler will throw #61-D warning
#define ADCR_SETUP_SCM ((CLKDIV<<8) | PWRUP)
//#define VREF       3.3 //Reference Voltage at VREFP pin, given VREFN = 0V(GND) - not used in this example.

int main(void)
{
	//SystemInit(); //Gets called by Startup code, sets CCLK=100Mhz, PCLK=25Mhz
	initUART0(); //Initialize UART0 for retargeted printf() 
	initTimer0(); //For delayMS()

	LPC_SC->PCONP |= ADC_CLK_EN;
	LPC_PINCON->PINSEL1 |= (1<<14); //select AD0.0 for P0.23
	LPC_ADC->ADCR = ADCR_SETUP_SCM | SEL_AD0_0;
	int result = 0;
	
	printf("OCFreaks.com LPC176x LDR Interfacing - Example 1.\n");
	
	while(1)
	{
		LPC_ADC->ADCR |= START_CNV; //Start new Conversion (Software controlled)

		while((LPC_ADC->ADDR0 & ADC_DONE) == 0); //Wait untill conversion is finished
		
		result = (LPC_ADC->ADDR0>>4) & 0xFFF; //12 bit Mask to extract result
		
		printf("AD0.0 = %d\n",result);
		
		delayMS(500); //Slowing down Updates to 2 Updates per second
	}
	
	//return 0; //This won't execute
}
</code></pre>
<div class="highlight"><strong>KEIL ARM uV5/uV4 Project for example given above on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/LDR_Interfacing/Example_1" target="_blank">LDR Interfacing with LPC1768 Example 1</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC1768-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>In this interfacing example 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/lpc1768-tutorial/lpc176x_ldr_ex2.png" alt="LPC1768/LPC1769 LDR Interfacing Example 2 Schematic" width="315px" height="280px" /></p>
<p><strong>Source code:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera- www.ocfreaks.com
LPC1768/LPC1769 LDR Interfacing Example 2 Source Code for KEIL ARM.
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
Also see: https://www.ocfreaks.com/lpc1768-adc-programming-tutorial/
License: GPL.*/

#include &lt;lpc176x.h&gt;
#include "ocf_lpc176x_lib.h"

#define ADC_CLK_EN (1<<12)
#define SEL_AD0_0  (1<<0) //Select Channel AD0.0 
#define CLKDIV     1 //ADC clock-divider (ADC_CLOCK=PCLK/CLKDIV+1) = 12.5Mhz @ 25Mhz PCLK
#define PWRUP      (1<<21) //setting it to 0 will power it down
#define START_CNV  (1<<24) //001 for starting the conversion immediately
#define ADC_DONE   (1U<<31) //define it as unsigned value or compiler will throw #61-D warning
#define ADCR_SETUP_SCM ((CLKDIV<<8) | PWRUP)
//#define VREF       3.3 //Reference Voltage at VREFP pin, given VREFN = 0V(GND) - not used in this example.

#define LDR_CUT_OFF 750 //Define your cut-off value here

int main(void)
{
	//SystemInit(); //Gets called by Startup code, sets CCLK=100Mhz, PCLK=25Mhz
	initTimer0(); //For delayMS()

	LPC_SC->PCONP |= ADC_CLK_EN;
	LPC_PINCON->PINSEL1 |= (1<<14); //select AD0.0 for P0.23
	LPC_ADC->ADCR = ADCR_SETUP_SCM | SEL_AD0_0;
	LPC_GPIO0->FIODIR |= (1<<0); //Set P0.0 as output
	LPC_GPIO0->FIOCLR |= (1<<0); //LED initially OFF
	
	int result = 0;
	
	while(1)
	{
		LPC_ADC->ADCR |= START_CNV; //Start new Conversion (Software controlled)

		while((LPC_ADC->ADDR0 & ADC_DONE) == 0);
		
		result = (LPC_ADC->ADDR0>>4) & 0xFFF; //12 bit Mask to extract result
		
		if(result < LDR_CUT_OFF)
		{
			LPC_GPIO0->FIOSET |= (1<<0); //drive P0.0 HIGH - LED ON
		}
		else
		{
			LPC_GPIO0->FIOCLR |= (1<<0); //drive P0.0 LOW - LED OFF
		}
		
		delayMS(50); //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/LPC1768-Tutorial-Examples/tree/master/LDR_Interfacing/Example_2" target="_blank">LDR Interfacing with LPC1768 Example 2</a> [Successfully tested on Keil uV5.23], <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC1768-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-lpc1768/">Interfacing LDR with LPC1768</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/interfacing-ldr-lpc1768/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3059</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-05 01:04:09 by W3 Total Cache
-->