<?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>lpc1768 - OCFreaks!</title>
	<atom:link href="https://www.ocfreaks.com/tag/lpc1768/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.ocfreaks.com/tag/lpc1768/</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>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>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>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>
		<item>
		<title>LPC1768 DAC Programming Tutorial</title>
		<link>https://www.ocfreaks.com/lpc1768-dac-programming-tutorial/</link>
					<comments>https://www.ocfreaks.com/lpc1768-dac-programming-tutorial/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Thu, 16 Nov 2017 16:19:06 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[lpc1768]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=2999</guid>

					<description><![CDATA[<p>In this article, we will go through a discussion on ARM Cortex-M3 LPC1768 DAC programming tutorial. As you might be knowing, DAC stands for Digital to Analog Conversion. The DAC block in ARM Cortex-M3 LPC176x microcontroller is one of the simplest to program and also supports DMA. This tutorial is also applicable for LPC1769 MCU. We will also cover a simple LPC1768 DAC Example.</p>
<p>The post <a href="https://www.ocfreaks.com/lpc1768-dac-programming-tutorial/">LPC1768 DAC Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this article, we will go through a discussion on ARM Cortex-M3 LPC1768 DAC programming tutorial. As you might be knowing, DAC stands for Digital to Analog Conversion. The DAC block in ARM Cortex-M3 LPC176x microcontroller is one of the simplest to program and also supports DMA. This tutorial is also applicable for LPC1769 MCU. Basically we assign a digital value to a register and the DAC block outputs it equivalent analog signal as shown below:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/mcu_dac_2.png" width="460px" height="240px" alt="Digital to Analog Conversion" /></p>
<h2 class="shead">LPC1768/LPC1769 DAC Block</h2>
<p>ARM Cortex-M3 LPC176x MCUs incorporate a 10 bit DAC and provide buffered analog output. As per the datasheet, it is implemented as a string DAC which is the most simplest form of DAC consisting of 2<sup>N</sup> resistors in series where N = no. of bits which simply forms a Kelvin-Varley Divider. LPC176x DAC has only 1 output pin, referred to as <strong>AOUT</strong>. The Analog voltage at the output of this pin is given as:</p>
<div class="equation">V<sub>AOUT</sub> =</p>
<div class="fraction"><span class="fup">VALUE * (V<sub>REFP</sub>-V<sub>REFN</sub>)</span><span class="bar">/</span><span class="fdn">1024</span></div>
<p> + V<sub>REFN</sub></div>
<p>When we have  V<sub>REFN</sub> = 0, the equation boils down to:</p>
<div class="equation">V<sub>AOUT</sub> =</p>
<div class="fraction"><span class="fup">VALUE * V<sub>REFP</sub></span><span class="bar">/</span><span class="fdn">1024</span></div>
</div>
<p>Where VALUE is the 10-bit digital value which is to be converted into its Analog counterpart and V<sub>REF</sub> is the input reference voltage.</p>
<h4>Pins relating to LPC1768 DAC block:</h4>
<p><center></p>
<table>
<tr>
<th><strong>Pin</strong></th>
<th><strong>Description</strong></th>
</tr>
<tr>
<td><strong>AOUT (P0.26)</strong></td>
<td>Analog Output pin. Provides the converted Analog signal which is referenced to V<sub>SSA</sub> i.e. the Analog GND. Set Bits[21:20] in <span class="doc_ref">PINSEL1</span> register to [10] to enable this function.</td>
</tr>
<tr>
<td><strong>V<sub>REFP</sub>, V<sub>REFN</sub></strong></td>
<td>These are reference voltage input pins used for both ADC and DAC. V<sub>REFP</sub> is positive reference voltage and V<sub>REFN</sub> is negative reference voltage pin. In example shown below we will use V<sub>REFN</sub>=0V(GND).</td>
</tr>
<tr>
<td><strong>V<sub>DDA</sub>, V<sub>SSA</sub></strong></td>
<td>V<sub>DDA</sub> is Analog Power pin and V<sub>SSA</sub> is Ground pin used to power the ADC module. These are generally same as V<sub>CC</sub> and GND but with additional filtering to reduce noise.</td>
</tr>
</table>
<p></center></p>
<h2 class="shead">DAC Registers in ARM Cortex-M3 LPC176x</h2>
<p>The DAC module in ARM LPC1768/LPC1769 has 3 registers viz. <span class="doc_ref">DACR</span>, <span class="doc_ref">DACCTRL</span>, <span class="doc_ref">DACCNTVAL</span>. In this tutorial we will only go through to DACR register since the other two are related with <strong>DMA</strong> operation, explaining which is not in the scope of this tutorial. Just note that DMA is used to update new values to DACR from memory without the intervention of CPU. This is particularly useful when generation different types of waveforms using DAC. We will cover this in another tutorial.</p>
<p>Also note that the DAC doesn&#8217;t have a power control it in PCONP register. Simply select the AOUT alternate function for pin P0.26 using PINSEL1 register to enable DAC ouput.</p>
<h4>The DACR register in LPC1768</h4>
<p>The field containing bits [15:6] is used to feed a digital value which needs to be converted and bit 16 is used to select settling time. The bit significance is as shown below:</p>
<ol>
<li><strong>Bit[5:0]:</strong> Reserved.</li>
<li><strong>Bit[15:6] &#8211; VALUE:</strong> After a new VALUE is written to this field, given settling time selected using BIAS has elapsed, we get the converted Analog voltage at the output. The formula for analog voltage at AOUT pin is as shown above.</li>
<li><strong>Bit[16] &#8211; BIAS:</strong> Setting this bit to 0 selects settling time of 1us max with max current consumption of 700uA at max 1Mhz update rate. Setting it to 1 will select settling time of 2.5us but with reduce max current consumption of 300uA at max 400Khz update rate.</li>
<li><strong>Bits[31:17]</strong>: Reserved</li>
</ol>
<h2 class="shead">ARM Cortex-M3 LPC1768 DAC example</h2>
<p>As evident, without using DMA, programming the DAC block is very straight forward. We just need to select AOUT function for P0.26 pin and apply a 10-bit value which needs to be converted into its Analog form. Lets see a basic LPC1768 DAC example. For most development boards V<sub>REFP</sub> will be connected to V<sub>DD</sub>/V<sub>DDA</sub> and V<sub>REFP</sub> will be connected to V<sub>SS</sub>/V<sub>SSA</sub> using some form of noise isolation. In this DAC example, we will be changing the output from 0V to V<sub>REFP</sub> (using V<sub>REFN</sub>=0V) and then falling back to 0V in steps of 10ms. This DAC program will basically output a sawtooth waveform. We will be using BIAS = 0 i.e. settling time of 1us. You can connect an Oscilloscope or a Multimeter between P0.26 and GND to check the changing analog output. Since the output is buffered you can drive an LED from A<sub>OUT</sub> but it won&#8217;t glow until it reaches its forward bias voltage of around 1.7 Volts. So, keep this in mind when checking for analog output using an LED. Also, I have used Timer0 for generating delay(Alternatively this can be using DMA Timer itself). You can check my <a href="https://www.ocfreaks.com/lpc1768-timer-programming-tutorial/" target="_blank">previous LPC1768 timer tutorial</a>.</p>
<p style="margin-bottom:0px;"><img decoding="async" style="margin-bottom:0px" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc1768-tutorial/lpc1768_lpc1769_dac_eg.png" width="545px" height="280px" alt="LPC1768 LPC1769 DAC Example Schematic" /></p>
<p style="text-align:center;">[Note: <strong>V<sub>SSA</sub></strong> and <strong>GND</strong> will be common for most development boards.]</p>
<p><strong><br />
C/C++ Source Code:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera - www.ocfreaks.com
LPC1768 DAC Example 1 Source Code using KEIL ARM
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License : GPL.*/

#include &lt;lpc17xx.h&gt;

void initTimer0(void);
void delayMS(unsigned int milliseconds);

int main(void)
{
	//SystemInit(); //gets called by Startup code before main(), sets CCLK = 100Mhz
	initTimer0();
	LPC_PINCON->PINSEL1 |= (1<<21); //Select AOUT function for P0.26 , bits[21:20] = [10] 
	unsigned int value=0; //Binary value used for Digital To Analog Conversion
	while(1)
	{
		if(value > 1023) value=0; //For 10-bit DAC max-value is 2^10 - 1 = 1023
		LPC_DAC->DACR = (value<<6);
		delayMS(10);
		value++;
	}
}

void initTimer0(void)
{
	//Refer: https://www.ocfreaks.com/lpc1768-timer-programming-tutorial/
	//Assuming that PLL0 has been setup with CCLK = 60Mhz
	//using default PCLK = 25 which is configure by startup code
	LPC_TIM0->CTCR = 0x0;
	LPC_TIM0->PR = 25000-1; //25000 clock cycles @25Mhz PCLK = 1 ms
	LPC_TIM0->TCR = 0x02; //Reset Timer
}

void delayMS(unsigned int milliseconds) //Using Timer0
{
	LPC_TIM0->TCR = 0x02; //Reset Timer
	LPC_TIM0->TCR = 0x01; //Enable timer
	while(LPC_TIM0->TC < milliseconds); //wait until timer counter reaches the desired delay
	LPC_TIM0->TCR = 0x00; //Disable timer
}
</code></pre>
<div class="highlight"><strong>KEIL ARM uV5 Project for LPC176x DAC example on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/DAC" target="_blank">LPC1768 DAC 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/DAC" 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-dac-programming-tutorial/">LPC1768 DAC Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/lpc1768-dac-programming-tutorial/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2999</post-id>	</item>
		<item>
		<title>LPC1768 ADC Programming Tutorial</title>
		<link>https://www.ocfreaks.com/lpc1768-adc-programming-tutorial/</link>
					<comments>https://www.ocfreaks.com/lpc1768-adc-programming-tutorial/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Sat, 14 Oct 2017 13:41:12 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[lpc1768]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=2962</guid>

					<description><![CDATA[<p>In this tutorial we will go through ARM Cortex-M3 LPC1768 ADC programming tutorial. Basically we convert an Analog signal to its Digital version which is useful when interfacing analog sensors. We will also see LPC176x an ADC Example. This also applies to LPC1769 Microcontroller.</p>
<p>The post <a href="https://www.ocfreaks.com/lpc1768-adc-programming-tutorial/">LPC1768 ADC Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="introleft">Hi folks, in this tutorial we will go through ARM Cortex-M3 LPC1768 ADC programming tutorial. Basically we convert an Analog signal to its Digital version. We will also see LPC176x ADC Interfacing Example. This also applies to LPC1769 Microcontroller.</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="#ADC_Block"><span>ADC in ARM LPC176x</span></a></li>
<li class="toc_text"><a href="#ADC_Regs"><span>LPC176x ADC Registers</span></a></li>
<li class="toc_text"><a href="#ADC_Modes"><span>LPC1768 ADC Modes &#038; Programming</span></a></li>
<li class="toc_text"><a href="#ADC_Examples"><span>LPC1768/LPC1769 ADC Example</span></a></li>
</ol>
</div>
</div>
<h2 class="shead" id="ADC_Block">ADC in ARM LPC176x</h2>
<p>Analog to Digital Conversion is used when want to interface an external analog signal or when interfacing analog sensors, like for example a temperature sensor. The ADC block in ARM Cortex-M3 LPC1768 Microcontroller is based on <a href="http://en.wikipedia.org/wiki/Successive_approximation_ADC">Successive Approximation(SAR)</a> conversion method. LPC1768 ADC Module uses 12-bit SAR having a conversion rate of 200 kHz. The Measurement range if from V<sub>REFN</sub> to V<sub>REFP</sub>, or commonly from 0V to ~3V. Maximum of 8 multiplexed inputs can be used for ADC.</p>
<h4>Pins relating to ADC Module of LPC1768/LPC1769 :</h4>
<p><center></p>
<table>
<tr>
<th><strong>Pin</strong></th>
<th><strong>Description</strong></th>
</tr>
<tr>
<td><strong>AD0.0 to AD0.7</strong> (P0.23/24/25/26, P1.30/31,  P0.3/2) </td>
<td>Analog input pins. <br /><strong>Note from Datasheet:</strong> &#8220;If ADC is used, signal levels on analog input pins must not be above the level of V<sub>DDA</sub> at any time. Otherwise, A/D converter readings will be invalid. If the A/D converter is not used in an application then the pins associated with A/D inputs can be used as 5V tolerant digital IO pins.&#8221; </td>
</tr>
<tr>
<td><strong>V<sub>REFP</sub>, V<sub>REFN</sub></strong></td>
<td>These reference voltage pins used for ADC and DAC.</td>
</tr>
<tr>
<td><strong>V<sub>DDA</sub>, V<sub>SSA</sub></strong></td>
<td>V<sub>DDA</sub> is Analog Power pin and V<sub>SSA</sub> is Ground pin used to power the ADC module. </td>
</tr>
</table>
<p></center></p>
<div class="special sp_blue notestar"><strong></strong>Analog Power Pin i.e V<sub>DDA</sub> must be properly isolated/decoupled from V<sub>CC</sub>, at bare minimum using a ferrite bead and a decoupling capacitor, to suppress noise present on V<sub>CC</sub> rail and also to suppress MCU&#8217;s switching noise which can be induced on the V<sub>CC</sub> rail.</div>
<h2 class="shead" id="ADC_Regs">LPC176x ADC Registers</h2>
<p>Lets see registers which are used for ADC programming.</p>
<div class="highlight">
<strong>1) <span class="doc_ref">ADCR</span> &#8211; A/D Control Register : </strong>This is the main control register for AD0.</p>
<ol>
<li><strong>Bits[7:0] &#8211; SEL:</strong> Bit &#8216;x'(in this group) is used to select pin A0.x in case of AD0.</li>
<li><strong>Bits[15:8] &#8211; CLKDIV: </strong>ADC Peripheral clock i.e. PCLK_ADC0 is divided by CLKDIV+1 to get the ADC clock. Note that ADC clock speed must be <= 13Mhz! As per datasheet user must program the smallest value in this field which yields a clock speed of 4.5 MHz or a bit less.</li>
<li><strong>Bit[16] &#8211; BURST:</strong> Set to 1 for doing repeated conversions, else 0 for software controlled conversions. Note: START bits must be set to 000 when BURST=1 or conversions will not start.  Refer user manual for detailed info.</li>
<li><strong>Bit[21] &#8211; PDN :</strong> Set it to 1 for powering up the ADC and making it operational. Set it to 0 for bringing it in powerdown mode.</li>
<li><strong>Bits[26:24] &#8211; START: </strong>These bits are used to control the start of ADC conversion when BURST (bit 16) is set to 0. 000 = No start , 001 = Start the conversion now, for other values refer LPC17xx User Manual.
<li><strong>Bit[27] &#8211; EDGE: </strong>Set this bit to 1 to start the conversion on falling edge of the selected CAP/MAT signal and set this bit to 0 to start the conversion on rising edge of the selected signal. (Note: This bit is of used only in the case when the START contains a value between 010 to 111 as shown above.)</li>
<li>Other bits are reserved.</li>
</ol>
<p><strong>2) <span class="doc_ref">ADGDR</span> &#8211; A/D Global Data Register :</strong> Contains the ADC’s flags and the result of the most recent A/D conversion.	</p>
<ol>
<li><strong>Bits[15:4] &#8211; RESULT:</strong> When DONE bit = 1, these bits give a binary fraction which represents the voltage on the pin AD0.x, in range V<sub>REFP</sub> &#038; V<sub>REFN</sub>. Value of 0x0 indicates that voltage on the given pin was less than, equal to or greater than V<sub>REFN</sub>. And a value of 0xFFF means that the input voltage was close to, equal to or greater than the V<sub>REFP</sub>.</li>
<li><strong>Bits[26:24] &#8211; CHN: </strong>Represents the channel from which RESULT bits were converted. 000= channel 0, 001= channel 1 and so on.</li>
<li><strong>Bit[30] &#8211; OVERRUN:</strong> In burst mode this bit is 1 in case of an Overrun i.e. the result of previous conversion being lost(overwritten). This bit will be cleared after reading ADGDR.</li>
<li><strong>Bit[31] &#8211; DONE:</strong> When ADC conversion completes this bit is 1. When this register(ADGDR) is read and ADCR is written, this bit gets cleared i.e. set to 0. If ADCR is written while a conversion is in progress then this bit is set and a new conversion is started.</li>
<li>Other bits are reserved.</li>
</ol>
<p><strong>4) <span class="doc_ref">ADDR0 to ADDR7</span> &#8211; A/D Data registers :</strong> This register contains the result of the most recent conversion completed on the corresponding channel [0 to 7]. Its structure is same as ADGDR except Bits[26:24] are not used/reserved.</p>
<p><strong>5) <span class="doc_ref">ADSTAT</span> &#8211; A/D Status register :</strong> This register contains DONE and OVERRUN flags for all of the A/D channels along with A/D interrupt flag.</p>
<ol>
<li><strong>Bits[7:0] &#8211; DONE[7 to 0]:</strong> Here xth bit mirrors DONEx status flag from the result register for A/D channel x.</li>
<li><strong>Bits[15:8] &#8211; OVERRUN[7 to 0]:</strong> Even here the xth bit mirrors OVERRUNx status flag from the result register for A/D channel x </li>
<li><strong>Bit 16 &#8211; ADINT:</strong> This bit represents the A/D interrupt flag. It is 1 when any of the individual A/D channel DONE flags is asserted and enabled to contribute to the A/D interrupt via the ADINTEN(given below) register.</li>
<li>Other bits are reserved.</li>
</ol>
</div>
<h2 class="shead" id="ADC_Modes">LPC1768 ADC Modes, Setup and Programming</h2>
<h4>ADC modes in LPC1768 &#038; LPC1769: </h4>
<ol>
<li><strong>Software controlled mode :</strong> In Software mode only one conversion will be done at a time. To perform another conversion you will need to re-initiate the process. In software mode, only 1 bit in the SEL field of ADCR can be 1 i.e. only 1 Channel(i.e. Pin) can be selected for conversion at a time. Hence conversions can be done only any channel but one at a time.</li>
<li><strong>Hardware or Burst mode :</strong> In Hardware or Burst mode, conversions are performed continuously on the selected channels in round-robin fashion. Since the conversions cannot be controlled by software, Overrun may occur in this mode. Overrun is the case when a previous conversion result is replaced by new conversion result without previous result being read i.e. the conversion is lost. Usually an interrupt is used in Burst mode to get the latest conversion results. This interrupt is triggered when conversion in one of the selected channel ends.</li>
</ol>
<h4>1A. Setting up and configuring ADC Module for software controlled mode</h4>
<p>First, lets define some values which will help us in setting up ADCR register to configure &#038; Initialize ADC block.</p>
<pre><code class="language-cpp">
#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)  
 
#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) | PowerUP)
//SCM = Software Controlled Mode
</code></pre>
<p>Now we assign ADCR_SETUP to ADCR along with channel selection information to select channels as required. Finally we assign(by ORing) START_NOW to ADCR to start the conversion process as shown:</p>
<pre><code class="language-cpp">
LPC_SC->PCONP |= ADC_CLK_EN; //Enable ADC clock
LPC_ADC->ADCR =  ADCR_SETUP_SCM | SEL_AD0_0; 
LPC_ADC->ADCR |= START_CNV;

//==OR==
LPC_SC->PCONP |= ADC_CLK_EN; //Enable ADC clock
LPC_ADC->ADCR =  ADCR_SETUP | SEL_AD0_0 | START_CNV; 
</code></pre>
<h4>1B. Fetching the conversion result in software controlled mode :</h4>
<p>In software controlled mode we continuously monitor bit 31 in the corresponding channel data register ADDR. If bit 31 changes to 1 from 0, it means that current conversion has been completed and the result is ready. For example, if we are using channel 0 of AD0 then we monitor for changes in bit 31 as follows :</p>
<pre><code class="language-cpp">
while((LPC_ADC->ADDR0 & ADC_DONE) == 0); //this loop will end when bit 31 of AD0DR6 changes to 1.
</code></pre>
<p>After this we extract the result which is stored in ADDR bits 4 to 15. Here we right shift ADDR by 6 places and force all other unrelated bits to 0 by using a 12-bit mask value of 0xFFF. 0xFFF is a mask containing 1's in bit locations 0 to 11 and rest 0's. In our case with ADDR0 being used, it can be done as follows :</p>
<pre><code class="language-cpp">
result = (LPC_ADC->ADDR0>>4) & 0xFFF;
</code></pre>
<h4>2A. Setting up and configuring ADC Module for Burst mode </h4>
<p>Configuring ADC Module is similar to what was done in software controlled mode except here we use the CLKS bits and don't use the START bits in ADCR. ADC_DONE is also not applicable since we are using an ISR which gets triggered when a conversion completes on any of the enabled channels. Additionally, we define the following constants:</p>
<pre><code class="language-cpp"> 
#define SEL_AD0_1 (0x2) //Select Channel AD0.1

#define BURST_ON  (1<<16) // 1 for on and 0 for off

#define ADCR_SETUP_BURST ((CLKDIV<<8) | BURST_ON | PWRUP)
</code></pre>
<p>We configure and setup the ADC module in a similar manner(as shown above) as follows :</p>
<pre><code class="language-cpp">
LPC_SC->PCONP |= ADC_CLK_EN; //Enable ADC clock
LPC_ADC->ADCR =  ADCR_SETUP_BURST | SEL_AD0_0 | SEL_AD0_1; 
</code></pre>
<p>Note that in this case we can select multiple channels for conversion when setting up AD0CR. START bits are not applicable here since the conversions starts as soon we setup AD0CR register.</p>
<h4>2B. Fetching the conversion result in Burst mode :</h4>
<p>In Burst mode we use an ISR which triggers at the completion of a conversion in any one of the channel. Now, we just need to find the Channel for which the conversion was done. For this we fetch the channel number from ADGDR which also stores the conversion result. Bits [26:24] in ADGDR contain the channel number. Hence, we shift it 24 places and use a 3-bit mask value of 0x7 as shown below:</p>
<pre><code class="language-cpp">
unsigned long ADGDR_Read = LPC_ADC->ADGDR;
int channel = (ADGDR_Read>>24) & 0x7; //Extract Channel Number
</code></pre>
<p>After knowing the Channel number, we have 2 options to fetch the conversion result from. Either we can fetch it from ADGDR or from ADDRx of the corresponding channel. Lets use ADGDR for extracting the conversion result as follows:</p>
<pre><code class="language-cpp">
int currentResult = (ADGDR_Read>>4) & 0xFFF; //Extract Conversion Result
</code></pre>
<h2 class="shead" id="ADC_Examples">ARM Cortex-M3 LPC1768/LPC1769 ADC Example</h2>
<p>Note that in this case no input protection nor filtering was required. But, when Interfacing external analog signals it is recommended to use some form of input protection.</p>
<h4>Interfacing Potentiometer using ADC on LPC176x</h4>
<p>This example performs Analog to Digital conversion in Software Controlled Mode. Here we use P0.23 as analog input for measuring the voltage. P0.23 corresponds to Channel 0 of AD0 i.e. AD0.0. For testing I had used a 10K potentiometer for ADC Interfacing and connected the middle leg to P0.23 of my LPC1768 development board. You can also use a 5K potentiometer for this ADC Example. Make sure your board V<sub>REFP</sub>, V<sub>REFN</sub>, V<sub>DDA</sub> & V<sub>SSA</sub> connections. These connections will be generally present on most LPC176x development boards. If not you can hook it up to V<sub>CC</sub> and GND respectively using decoupling capacitors and ferrite beads to reduce noise. Schematic for this example is as shown below:</p>
<p><img fetchpriority="high" decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc1768-tutorial/lpc_arm_adc_interfacing_sch.png" width="498" height="304" alt="Schematic for ADC interfacing on ARM MCU LPC176x" /></p>
<p><strong>C/C++ Source Code :</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera - www.ocfreaks.com
LPC1768/LPC1769 ADC Interfacing Example 1 Source Code using KEIL ARM
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License : GPL.*/

#include &lt;lpc17xx.h&gt;
#include &lt;stdio.h&gt;
#include "ocf_lpc176x_lib.h" //contains uart, timer & fputc to retarget printf  

#define VREF       3.3 //Reference Voltage at VREFP pin, given VREFN = 0V(GND)
#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)

int main(void)
{
	//SystemInit(); //Gets called by Startup code, sets CCLK=100Mhz, PCLK=25Mhz
	initUART0(); //Initialize UART0 for uart_printf() - both defined in tmr_uart_printf.cpp
	initTimer0(); //For delayMS() - both defined in tmr_uart_printf.cpp

	LPC_SC->PCONP |= ADC_CLK_EN; //Enable ADC clock
	LPC_ADC->ADCR =  ADCR_SETUP_SCM | SEL_AD0_0;
	LPC_PINCON->PINSEL1 |= (1<<14) ; //select AD0.0 for P0.23
	int result = 0;
	float volts = 0;
	
	printf("OCFreaks.com LPC176x ADC Tutorial Example 1.\nSoftware Controlled ADC Mode on AD0.0 Channel.\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
		
		volts = (result*VREF)/4096.0; //Convert result to Voltage
		
		printf("AD0.0 = %dmV\n" , (int)(volts*1000)); //Display milli-volts
		
		delayMS(500); //Slowing down Updates to 2 Updates per second
	}
	
	//return 0; //This won't execute
}

</code></pre>
<p><strong>Serial Output :</strong></p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc1768-tutorial/adc_interfacing_eg.png" width="549px" height="322px" alt="ADC Interfacing Example Screenshot" /></p>
<div class="special sp_blue noteinfo"><span class="code_var">ocf_lpc176x_lib.h</span> header used in the source also contains code for <strong>retargeting printf()</strong>. Check <a href="https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/" target="_blank">how to retarget printf() using UART tutorial</a> for more.</div>
<div class="highlight"><strong>KEIL ARM uV5 Project for example given above on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/ADC/Example_1" target="_blank">LPC176x ADC Interfacing 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/ADC/Example_1" 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-adc-programming-tutorial/">LPC1768 ADC Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/lpc1768-adc-programming-tutorial/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2962</post-id>	</item>
		<item>
		<title>LPC1768 UART Programming Tutorial</title>
		<link>https://www.ocfreaks.com/lpc1768-uart-programming-tutorial/</link>
					<comments>https://www.ocfreaks.com/lpc1768-uart-programming-tutorial/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Thu, 28 Sep 2017 20:12:07 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[lpc1768]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=2906</guid>

					<description><![CDATA[<p>In this discussion we will go through ARM Cortex-M3 LP1768 UART programming Tutorial. It is also applicable to for other MCUs of LPC17xx family like LPC1769.</p>
<p>The post <a href="https://www.ocfreaks.com/lpc1768-uart-programming-tutorial/">LPC1768 UART Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="tocpostimage">In this discussion we will go through ARM Cortex-M3 LP1768 UART programming Tutorial. It is also applicable to for other MCUs of LPC17xx family like LPC1769. If you are new to UART, you can go through the basic UART tutorial which I&#8217;ve posted @ <a href="https://www.ocfreaks.com/uart-tutorial-basics/">Basic Uart Tutorial</a>.</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="#UART_Block"><span>LPC1768 UART Block</span></a></li>
<li class="toc_text"><a href="#UART_Registers"><span>LPC176x UART Registers</span></a></li>
<li class="toc_text"><a href="#Baud_Calc"><span>UART Baud Rate Calculation</span></a></li>
<li class="toc_text"><a href="#Config_Init"><span>How to Configure and Initialize UART</span></a></li>
<li class="toc_text"><a href="#UART_Connections"><span>Connections between MCU and PC or Laptop</span></a></li>
<li class="toc_text"><a href="#UART_Examples"><span>UART Examples</span></a></li>
<ol class="toc_list">
<li class="toc_text"><a href="#Example_1"><span>LPC1768 UART Example 1</span></a></li>
<li class="toc_text"><a href="#Example_2"><span>LPC1768 UART Example 2</span></a></li>
</ol>
</ol>
</div>
</div>
<h4>UART basics revisited</h4>
<p>Uart uses TxD(Transmit) Pin for sending Data and RxD(Receive) Pin to get data. UART sends &#038; receives data in form of chunks or packets. These chunks or packets are also referred to as ‘Frames’. While sending Data, LSB(i.e. Data Bit 0) is transmitted First and MSB is transmitted Last. The structure of a UART Packet/Frame using 1 stop bit is as shown below:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/uart_packet_format.png" alt="Uart Packet Frame Format Structure" width="320px" height="140px" /></p>
<p>Here is an example of single Packet/Frame using 8 data bits, even parity and 1 stop bit:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/uart_packet_example.png" alt="Example of a single UART data Packet Frame" width="500px" height="175px" /></p>
<h2 class="shead" id="UART_Block">LPC1768 UART Block</h2>
<p>Now, Lets start with the main Tutorial. ARM Cortex-M3 LPC176x has 4 UART blocks which are UART0 to UART3. UART0/2/3 are identical. UART1 additionally supports Full modem control handshaking &#038; RS-485. Refer Datasheet for more info. After reset UART0 &#038; UART1 are enabled by default. TxD and RxD pins for these blocks are mapped on multiple pins.</p>
<table class="aligncenter" style="margin-bottom:20px">
<tr>
<td>Pins:</td>
<td><strong>TxD</strong></td>
<td><strong>RxD</strong></td>
</tr>
<tr>
<td>UART0</td>
<td> P0.2</td>
<td> P0.3</td>
</tr>
<tr>
<td>UART1</td>
<td> P0.15/P2.0</td>
<td> P0.16/P2.1</td>
</tr>
<tr>
<td>UART2</td>
<td> P0.10/P2.8</td>
<td> P0.11/P2.9</td>
</tr>
<tr>
<td>UART3</td>
<td> P0.0/P0.25/P4.28</td>
<td> P0.1/P0.26/P4.29</td>
</tr>
</table>
<p  style="margin-bottom:0px;">All UART blocks internally have a 16-byte FIFO (First In First Out) structure to hold data. Each byte in this FIFO represents a character which was sent or received <strong>in order</strong>. All blocks also contain 2 registers each, for data access and assembly as given below:</p>
<ul>
<li><strong>Tx has THR(Transmit Holding Register) and TSR(Transmit Shift Register)</strong> &#8211; When Tx Data is written to THR, it is then transferred to TSR which assembles the Transmit data.</li>
<li><strong>Similarly Rx has RSR(Receive Shift Register) and RBR(Receive Buffer Register)</strong> &#8211; When Data is Received at the Rx Pin, it is first assembled in RSR and then transferred into Rx FIFO which can be then accessed using RBR.</li>
</ul>
<div class="special sp_red noteinfo"> UART Pins on LPC176x are 5V tolerant. But I would recommend using 3.3v for UART communication. Hence, if you have RS232 to serial TTL module make sure it has MAX3232 =OR= if you are using FTDI&#8217;s FT232R based USB to serial TTL module make sure it is configured for 3.3v I/O.
</div>
<h2 class="shead" id="UART_Registers">LPC176x UART Registers used in programming</h2>
<p>Before we can use these pins to transfer data, first we need to configure and initialize the UART block in our LPC176x microcontroller. But before doing that, lets go through some of the important registers:</p>
<div class="highlight">
<h4><strong>Data Related Registers </strong></h4>
<p><strong>1) UxRBR &#8211; Receiver Buffer Register:</strong> This register contains the top most byte(8-bit data chunk) in the Rx FIFO i.e the oldest received data in FIFO. Before reading from UxRBR, the DLAB(Divisor Latch Access) bit in U0LCR register must be 0. As mentioned in user manual &#8220;The right approach for fetching the valid pair of received byte and its status bits is first to read the content of the U0LSR register, and then to read a byte from the U0RBR.&#8221;</p>
<p><strong>2) UxTHR &#8211; Transmit Holding Register:</strong> U0THR contains the top most byte in Tx FIFO and in this case its the newest(latest) transmitted data. As in the case with U0RBR , we must set DLAB=0 to access UxTHR for write operation.</p>
<h4><strong> Baud Rate Setup related registers </strong></h4>
<p><strong>1) UxDLL and UxDLM &#8211; Divisor Latch registers:</strong> Both of them hold 8-bit values. These register together form a 16-bit divisor value which is used in baud rate generation. UxDLM holds the upper 8-bits and U0DLL holds the lower 8-bits and the formation is &#8220;<strong>[U0DLM:U0DLL]</strong>&#8220;. Since these form a divisor value and division by zero is invalid, the starting value for U0DLL is 0x01 (and not 0x00). <strong>Please keep this in mind while doing baud-rate calculations. In order to access and use these registers properly, DLAB bit in UxLCR must be first set to 1</strong>. </p>
<p><strong>2) UxFDR &#8211; Fractional Divider Register :</strong> It is used to set the prescale value for baud rate generation. The input clock is the PCLK and output is the desired clock defined by this register. This register actually holds to different 4-bit values (a divisor and a multiplier) for prescaling which are:</p>
<ol>
<li><strong>Bit [3 to 0] &#8211; DIVADDVAL:</strong> This is the prescale divisor value. If this value if 0 then fractional baud rate generator wont have any effect on Uart Baud rate.</li>
<li><strong>Bit [7 to 4] &#8211; MULVAL:</strong> This is prescale multiplier value. Even if fractional baud rate generator is not used the value in this register must be more than or equal to 1 else UART0 will not operate properly.</li>
<li>Other Bits reserved.</li>
</ol>
<p>Remark from User-manual:&#8221; <strong>If the fractional divider is active (DIVADDVAL > 0) and DLM = 0, the value of the DLL register must be 2 or greater!</strong>&#8221;</p>
<h4><strong>Control and Status Registers</strong></h4>
<p><strong>1) UxFCR &#8211; FIFO Control Register: </strong>Used to control Rx/Tx FIFO operations.</p>
<ol>
<li><strong>Bit 0 &#8211; FIFO Enable:</strong> 1 to Enable both Rx and Tx FIFOs and 0 to disable.</li>
<li><strong>Bit 1 &#8211; Rx FIFO Reset:</strong> Writing a 1 will clear and reset Rx FIFO.</li>
<li><strong>Bit 2 &#8211; Tx FIFO Reset:</strong> Writing a 1 will clear and reset Tx FIFO.</li>
<li><strong>Bits [7 to 6]</strong>:</strong> Used to determine that how many Rx FIFO characters must be written before an interrupt is activated.</li>
<li>Others bits are reserved.</li>
</ol>
<p><strong>2) UxLCR &#8211; Line Control Register :</strong> Used to configure the UART block (i.e the data format used in transmission).</p>
<ol>
<li><strong>Bit [1 to 0] &#8211; Word Length Select:</strong> Used to select the length of an individual data chunk. [00] for 5 bit character length. Similarly [01] , [10] , [11] for 6 , 7 , 8 bit character lengths respectively.</li>
<li><strong>Bit 2 &#8211; Stop bit select:</strong>  0 for using 1 stop bit and 1 for using 2 stop bits.</li>
<li><strong>Bit 3 &#8211; Parity Enable:</strong> 0 to disabled Partiy generation &#038; checking and 1 to enable it.</li>
<li><strong>Bit [5 to 4] &#8211; Parity Select:</strong> [00] to Odd-parity , [01] for Even-parity , [10] for forced &#8220;1&#8221;(Mark) parity  and [11] for forced &#8220;0&#8221;(Space) parity.</li>
<li><strong>Bit 6 &#8211; Break Control:</strong> 0 to disable break transmission and 1 to enable it. TxD pin will be forced to logic 0 when this bit is 1!</li>
<li><strong>Bit 7 &#8211; Divisior Latch Access bit:</strong> 0 to disable access to divisor latches and 1 to enable access.</li>
</ol>
<p><strong>3) UxLSR &#8211; Line Status Register:</strong> used to read the status of Rx and Tx blocks. Bits 1 to 4 get cleared after reading UxLSR.</p>
<ol>
<li><strong>Bit 0 &#8211; Receiver Data Ready(RDR):</strong> 0 means UxRBR is empty(i.e Rx FIFO is empty) and 1 means UxRBR contains valid data.</li>
<li><strong>Bit 1 &#8211; Overrun Error(OE):</strong> 1 means Overrun has occured, 0 otherwise. Overrun is the condition when RSR(Receive Shift Register) has new character assembled but the RBR FIFO is full and the new assembled character was eventually lost since no data is written into FIFO when its full.</li>
<li><strong>Bit 2 &#8211; Parity Error(PE):</strong> 1 means a parity error has occured else not. When the value of the parity bit in the recieved character is in wrong state then a parity error occurs.</li>
<li><strong>Bit 3 &#8211; Framing Error(FE):</strong> 1 means that a framing error has taken place else not. Framing error occurs when the stop bit of a received character is zero.</li>
<li><strong>Bit 4 &#8211; Break Interrupt:</strong> 1 means that it has occured else not. A Break Interrupt occurs when the RxD line is pulled low (i.e all 0s) i.e held in spacing state for 1 full character after which Rx Block goes into Idle state. Rx Block gets back to active state when RxD pin is pulled high (i.e all 1s) i.e held in marking state for 1 full character.</li>
<li><strong>Bit 5 &#8211; Transmit Holding Register Empty(THRE):</strong> 0 means UxTHR has valid data and 1 means its empty.</li>
<li><strong>Bit 6 &#8211; Transmitter Empty(TEMT):</strong> 0 means UxTHR and/or UxRSR has valid data and 1 means that both UxTHR and UxRSR are empty.</li>
<li><strong>Bit 7 &#8211; Error in RX FIFO(RXFE):</strong> 0 means that UxRBR has no Rx Errors or Rx FIFO is disabled(i.e 0th bit in U0FCR is 0) and 1 means that UxRBR has at-least one error.	<strong>Note:</strong> This bit is cleared only if UxLSR is read and there are no other subsequent errors in Rx FIFO, else this bit will stay 1</li>
</ol>
<p><strong>4) UxTER &#8211; Transmit Enable Register: </strong>This register is used to enable UART transmission. When bit-7 (i.e TXEN) is set to 1 Tx block will be enabled and will keep on transmitting data as soon as its ready. If bit-7 is set to 0 then Tx will stop transmission. Other bits are reserved.</p>
<h4><strong> Interrupt Related Registers</strong></h4>
<p><strong>1) UxIER &#8211; Interrupt Enable Register:</strong> Set a bit to 0 to disable and 1 to enable the corresponding interrupt. Other bits are reserved.</p>
<ol>
<li><strong>Bit 0</strong> &#8211; RBR Interrupt Enable </li>
<li><strong>Bit 1 </strong>&#8211; THRE Interrupt Enable</li>
<li><strong>Bit 2</strong> &#8211; RX Line Status Interrupt Enable</li>
<li><strong>Bit 8</strong> &#8211; ATEOInt (End of Auto Baud Interrupt) Enable</li>
<li><strong>Bit 9</strong> &#8211; ATBOInt (Auto Baud Time-Out Interrupt) Enable </li>
</ol>
<p><strong>2) UxIIR &#8211; Interrupt Identification Register:</strong> This register is organized as follows:</p>
<ol>
<li><strong>Bit 0 &#8211; Interrupt Pending :</strong> 0 means at-least one interrupt is pending, 1 means no interrupts are pending. Note: This bit is ACTIVE LOW!</li>
<li><strong>Bits [3 to 1] &#8211; Interrupt Identification :</strong> [011] implies Receive Line Status(RLS) , [010] implies Receive Data Available(RDA) , 110 implies Character Time-out Indicator(CTI) , [001] implies THRE Interrupt.</li>
<li><strong>Bits [7 to 6] &#8211; FIFO Enable.</strong></li>
<li><strong>Bit 8 &#8211; ABEOInt :</strong> 1 means Auto Baud Interrupt has successfully ended and 0 otherwise.</li>
<li><strong>Bit 9 &#8211; ABTOInt :</strong> 1 means Auto Baud Interrupt has Timed-out.</li>
<li>All others bits are reserved.</li>
</ol>
</div>
<h2 class="shead" id="Baud_Calc">UART Baud Rate Calculations</h2>
<div class="special sp_blue notestar">
<h4>The main formula for calculating baud rate is given as: </h4>
<div class="equation" style="font-size:14px;">Baud</sub> =</p>
<div class="fraction"><span class="fup">PCLK in Hertz</span><span class="bar">/</span><span class="fdn">16 x (256xDLM + DLL) x (1 + DIVADDVAL/MULVAL)</span></div>
</div>
<p>Where DIVADDVAL &#038; MULVAL are part of &#8220;Fractional Rate Divider&#8221; or &#8220;Baud-Prescaler&#8221; which is used in Baud-Rate generation. This &#8220;Fractional Divider&#8221; is only active when DIVADDVAL > 0. This formula is pretty common for LPC ARM micro-controllers.</p>
<p><strong>which can be further simplified to :</strong></p>
<div class="equation" style="font-size:14px;">Baud</sub> =</p>
<div class="fraction"><span class="fup">MULVAL</span><span class="bar">/</span><span class="fdn">MULVAL + DIVADDVAL</span></div>
<p>X</p>
<div class="fraction"><span class="fup">PCLK in Hertz</span><span class="bar">/</span><span class="fdn">16 x (256xDLM + DLL)</span></div>
</div>
<p style="margin-bottom:0px">with following conditions strictly applied:</p>
<ul style="margin-bottom:5px">
<li>0 < MULVAL <= 15 
<li>0 <= DIVADDVAL <= 14 - if DIVADDVAL > 0 &#038; DLM = 0 then, DLL must be >= 2 
<li>DIVADDVAL < MULVAL</li>
</ul>
<p>Where PCLK is the Peripheral Clock value in Hz , DLM and DLL are the divisor registers which we saw earlier and finally DIVADDVAL and MULVAL are part of the Fractional baudrate generator register.</p>
<p>As it can been seen this formula has 2 prominent parts which are: A <strong>Base value</strong> and a <strong>Fraction Part(Prescaler) </strong> i.e:</p>
<div class="equation">BaudRate = [ Fraction Part (Prescaler) ] x [ Base ]</div>
<p>This Fraction Part i.e. the Fractional Divider or the &#8220;Baud Rate Prescaler&#8221; can be used to scale down or keep the base value as it is (when disabled). Hence, its very useful for fine-tuning and getting the baudrate as accurate as possible.  </p>
</div>
<div class="special sp_red notestar"> <strong>Note</strong>: In real world there are very less chances that you will get the actual baudrate same as the desired baudrate. In most cases the actual baudrate will drift a little above or below the desired baud and also, as the desired baudrate increases this drift or error will also increase &#8211; this is because of the equation itself and the limitations on MULVAL , DIVADDVAL! For e.g. if the desired baud rate is 115200 and depends on the variables you may get a bauds like 114300, 115470, 116050 .. and so on. But in almost all cases it will work as required if the error is not significant. A small amount of error in actual baudrate is generally tolerable in most systems which must be <strong><1.1% (relative error)</strong>.</div>
<p><strong>Now we know the formula, how we do actually start ?</strong></p>
<h4>1) The Dirty and Simplest Method: </h4>
<p>The quickest and also the dirtiest(accuracy wise) method without using any algorithm or fine-tuning is to set DLM=0 and disable the Fractional Divider. In this case MULVAL=1 and DIVADDVAL=0 which makes the Fraction Part(FP) = 1. Now we are left with only 1 unknown in the equation which is UxDLL and hence we simplify the equation and solve for UxDLL.</p>
<div class="equation">UxDLL</sub> =</p>
<div class="fraction"><span class="fup">PCLK in Hertz</span><span class="bar">/</span><span class="fdn">16 x Desired-BaudRate</span></div>
</div>
<p>In my opinion, if possible, you must stay away from above method as it works only for particular bauds &#038; specific PCLK value and moreover computed UxDLL might get out of range i.e. > 255 in which case you have to start increasing DLM and recompute a new value for DLL.</p>
<h4>2) A better Method/Algorithm (Recommended): </h4>
<p>In these method we again start with DLM=0 , DIVADDVAL=0(i.e. Fractional divider disabled) and MULVAL=1 and get an initial value for DLM. If you are lucky you will get a very close baudrate to the desired one. If not then we perform some fine-tuning using DLM, MULVAL and DIVADDVAL and get a new value for DLM. There is on one single method to perform fine-tuning and one can also make an algorithm for computing the best match given the desired baudrate and PCLK. The fine-tuning method or Algorithm which I have given below is a basic one suitable for beginners(in my opinion though). A more invloved Iterative Algorithm is given on Page 324(Rev 4.1) of the user manual.</p>
<div class="highlight">
<h4>Example: PCLK = 25 Mhz and Required Baud Rate is 115200 bauds.</h4>
<p>Lets start with<strong> DLM = 0 , DIVADDVAL = 0 and MULVAL = 1<br />
We have PCLK = 25 Mhz = 25 x 10<sup>6</sup> Hz</strong></p>
<p>So the equation now gets simplified and we can find DLL.</p>
<p>We get <strong>UxDLL  = 13.56</strong>, since it must be an integer we round it to <strong>14</strong>. With <strong>UxDLL = 14</strong> our actual baud rate will be <strong>= 111607.14</strong> with a error of 3592.86(magnitude) which gives a relative error of <strong>3.11%</strong>. Since its greater than 1.1% error specification we cannot use this. Now all we have to do is to get this error as low as possible. This can be done by multiplying it by a suitable fraction defined using MULVAL and DIVADDVAL &#8211; as given in equation. But since MULVAL &#038; DIVADDVAL can be maximum 15 &#038; 14 receptively, we don&#8217;t have much control over the Fraction Part(FP) value.</p>
<p>First lets compute the Required Fraction Part(FP) value given by <strong>FP<sub>required</sub> = [Desired Baud / Actual Baud Rate]</strong>. In our case its <strong>FP<sub>required</sub> = 1.032</strong>. Note that this is the required &#8220;Baud Prescaler&#8221; value that needs to be multiplied by Base value we got above to bring back it to ~115200. Now we have a problem &#8211; the max value for the Fractional part is 1(When Fractional Divider is disabled), but in this case we need an upscaling value which is not possible. Only downscaling is possible(when Fractional Divider is Enabled). So what do we do now? Well, a few approaches can be used. One of the simple approach is to decrease the computed DLL value so that our final baudrate overshoots i.e. we get a positive error. So, then we can try to scale it down using Fractional Part (i.e. MULVAL and DIVADDVAL) to get near to desired baud rate.</p>
<p>Lets set <strong>UxDLL = 12</strong>. We now get new baud rate <strong>= 130208.33</strong> with error = +15008.33 from 115200. Now, we have <strong>FP<sub>required</sub> = 0.8847</strong>. We must try to get Fractional Part of equation as close as possible to 0.8847. The closest possible Fraction to 0.8847 is <strong>FP = 0.8823</strong> which is when <strong>MULVAL=15 and DIVADDVAL=2</strong>. So, multiplying that with computed baud we get: <strong>[Base] x [Fraction Part(FP)] = 130208.33 x 0.8823 = 114882.8 ~ 114882</strong> which is pretty bang on with an error of 318(magnitude) i.e. <strong>0.27%</strong> Relative Error that is well with in 1.1% spec. Hence, we can use the following settings:</p>
<p><strong>PCLK = 25 MHz<br />
U0DLL = 12<br />
U0DLM = 0<br />
MULVAL = 15<br />
DIVADDVAL = 2</strong>
</div>
<div class="special sp_blue noteinfo">Some of the standard Baud rates that can be used are: 2400, 4800, 7200, 9600, 14400, 19200, 28800, 38400, 57600, 115200, 230400, etc..  </div>
<h2 class="shead" id="Config_Init">How to Configure and Initialize UART</h2>
<p>Once you know how UART communication works, configuring and initializing UART is pretty straight forward. In Source Code Examples for this tutorial we will use UART0 with following configuration:</p>
<ul>
<li>BaudRate = 115200 (with PCLK=25Mhz)</li>
<li>Data Length = 8 bits</li>
<li>No Parity Bit</li>
<li>and 1 Stop Bit</li>
</ul>
<p><strong>Note: Its your responsibility to make it sure that configuration is same on both the communicating ends.</strong></p>
<p>As seen in example above: in order to get 115200(114882 actually) bauds at 25Mhz PCLK we must use the following settings for baud generation :</p>
<div class="highlight">
<strong>U0DLL = 12 ; U0DLM = 0 ; MULVAL = 15 ; DIVADDVAL = 2</strong>
</div>
<p>Now, lets write a function &#8220;<strong>InitUART0()</strong>&#8221; which we can use initialize and configure UART0:</p>
<pre><code class="language-cpp">
#define MULVAL      14
#define DIVADDVAL   2
#define Ux_FIFO_EN  (1<<0)
#define Rx_FIFO_RST (1<<1)
#define Tx_FIFO_RST (1<<2)
#define DLAB_BIT    (1<<7)
void InitUART0(void)
{
	LPC_PINCON->PINSEL0 |= (1<<4) | (1<<6); //Select TXD0 and RXD0 function for P0.2 &#038; P0.3!
	//LPC_SC->PCONP |= 1<<3; //Power up UART0 block. By Default it is enabled after RESET.

	LPC_UART0->LCR = 3 | DLAB_BIT ; /* 8 bits, no Parity, 1 Stop bit & DLAB set to 1  */
	LPC_UART0->DLL = 12;
	LPC_UART0->DLM = 0;
	
	//LPC_UART0->IER |= ..; //Edit this if want you to use UART interrupts
	LPC_UART0->FCR |= Ux_FIFO_EN | Rx_FIFO_RST | Tx_FIFO_RST;
	LPC_UART0->FDR = (MULVAL<<4) | DIVADDVAL; /* MULVAL=15(bits - 7:4) , DIVADDVAL=2(bits - 3:0)  */
	LPC_UART0->LCR &= ~(DLAB_BIT);
	//Now since we have applied DLL and DLM we now lock or freeze those valuse by diabling DLAB i.e DLAB=0 
	//Baud= ~115200(114882). Now we can perform UART communication!
}
</code></pre>
<p>Once this is done you are now ready to transfer data using U0RBR and U0THR registers.</p>
<h2 class="shead" id="UART_Connections">Connections between MCU and PC or Laptop</h2>
<p>Here we can have 2 possible scenarios.</p>
<ol style="margin-bottom:0px;">
<li>Your PC/Laptop(older ones) already has a serial port. In this case you will need a RS232 to TTL converter.</li>
<li>Your PC/Laptop doesn&#8217;t have a serial port and you are using USB to Serial converter(FTDI ones, etc..).</li>
</ol>
<div class="highlight">If you are using a separate converter then in both cases the TTL side of the converter have to use a minimum of 3 pins for basic UART communication which are: TxD, RxD and GND. Connect your MCU RxD to TxD of converter and MCU TxD to RxD of converter. Finally connect GND on both sides. Make sure you module supports 3.3v voltage-levels.</div>
<p>Please refer to the connection diagrams &#038; terminal software configuration(and COM ports) as given in <a href="https://www.ocfreaks.com/uart-tutorial-basics/">Basic Uart Tutorial</a>.</p>
<p>Here is a configuration screenshot for  terminal software PuTTYtel which we will be using for examples :<br />
<img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/puttytel_serial_config.png" alt="PuTTYtel UART,Serial Config" width="452px" height="343px" /></p>
<p><strong>Note</strong>: You can get PuTTYtel from <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html">Here</a>. Direct download link: <a href="http://the.earth.li/~sgtatham/putty/latest/x86/puttytel.exe">Here</a>. You can also use other similar terminal software as well.</p>
<h2 class="shead" id="UART_Examples">LPC1768 UART Programming Examples</h2>
<p>Now its time to actually use UART in real life! Lets do some communication between your LPC1768(or similar MCU like LPC1769) MCU and PC/Laptop. Before we get into actual examples for LPC1768, first lets define 2 functions which will be used to Read and Write Data from UART block. The code is based on CMSIS which is the Base library for ARM Cortex Micrcontrollers.</p>
<h4>U0Read() &#8211; Read Data from UART0:</h4>
<pre><code class="language-cpp">
#define RDR (1<<0) //Receiver Data Ready
char U0Read(void)
{
	while(!(LPC_UART0->LSR & RDR)); //wait until any data arrives in Rx FIFO
	return LPC_UART0->RBR; 
}
</code></pre>
<h4>U0Write() &#8211; Write Data to UART0:</h4>
<pre><code class="language-cpp">
#define THRE (1<<5) //Transmit Holding Register Empty
void U0Write(char data)
{
	while(!(LPC_UART0->LSR & THRE)); //wait till the THR is empty
	//now we can write to the Tx FIFO
	LPC_UART0->THR = data;
}
</code></pre>
<h4 id="Example_1">LPC1768 UART Example 1</h4>
<p>This demo will print &#8220;Hello from LPC1768!&#8221; on a new line in Serial Terminal repeatedly. The code given below uses Carriage-Return + Line-Feed (i.e. CR+LF) as New-Line(Enter or &#8220;\n&#8221;) character. If you are using Terminal on Linux or MacOS to interfacing LPC176x then only use Line-Feed(LF) character for New-Line. </p>
<pre><code class="language-cpp">
/*(C) Umang Gajera - www.ocfreaks.com
More Embedded tutorials @ www.ocfreaks.com/cat/embedded
LPC1768 Basic UART Example 1 Source Code.
License : GPL.*/

#include &lt;lpc17xx.h&gt;

#define THRE        (1<<5) //Transmit Holding Register Empty
#define MULVAL      15
#define DIVADDVAL   2
#define Ux_FIFO_EN  (1<<0)
#define Rx_FIFO_RST (1<<1)
#define Tx_FIFO_RST (1<<2)
#define DLAB_BIT    (1<<7)
#define LINE_FEED   0x0A //LF, For Linux, MAC and Windows Terminals  
#define CARRIAGE_RETURN 0x0D //CR, For Windows Terminals (CR+LF).

void initUART0(void);
void U0Write(char data);

int main(void)
{
	//SystemInit(); //This already gets called by CMSIS Startup Code.
	char msg[] = { 'H','e','l','l','o',' ','f','r','o','m',' ','L','P','C','1','7','6','8','\0' }; 
	int count=0;
	 
	initUART0();
	
	while(1)	
	{
		while( msg[count]!='\0' )
		{
			U0Write(msg[count]);
			count++;
		}
		//Send NEW Line Character(s) i.e. "\n"
		U0Write(CARRIAGE_RETURN); //Comment this for Linux or MacOS
		U0Write(LINE_FEED); //Windows uses CR+LF for newline.
		count=0; // reset counter		
	}
	//return 0; //This won't execute normally
}

void U0Write(char txData)
{
	while(!(LPC_UART0->LSR & THRE)); //wait until THR is empty
	//now we can write to Tx FIFO
	LPC_UART0->THR = txData;
}

void initUART0(void)
{
	/*Assuming CCLK = 100Mhz and PCLK = 25Mhz!*/
	LPC_PINCON->PINSEL0 |= (1<<4) | (1<<6); //Select TXD0 and RXD0 function for P0.2 &#038; P0.3!
	//LPC_SC->PCONP |= 1<<3; //Power up UART0 block. By Default it is enabled after RESET.

	LPC_UART0->LCR = 3 | DLAB_BIT ; /* 8 bits, no Parity, 1 Stop bit & DLAB set to 1  */
	LPC_UART0->DLL = 12;
	LPC_UART0->DLM = 0;
	
	//LPC_UART0->IER |= ..; //Edit this if want you to use UART interrupts
	LPC_UART0->FCR |= Ux_FIFO_EN | Rx_FIFO_RST | Tx_FIFO_RST;
	LPC_UART0->FDR = (MULVAL<<4) | DIVADDVAL; /* MULVAL=15(bits - 7:4) , DIVADDVAL=2(bits - 3:0)  */
	LPC_UART0->LCR &= ~(DLAB_BIT);
	//Now since we have applied DLL and DLM we now lock or freeze those valuse by diabling DLAB i.e DLAB=0 
	//Baud= ~115200(114882). Now we can perform UART communication!
}
</code></pre>
<div class="highlight"><strong>KEIL ARM uV5 Project for Example #1 on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/UART/Example_1" target="_blank">Example 1</a> [Successfully tested on Keil uV5.23], <strong>Download Project Zip</strong> @ <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/UART/Example_1" target="_blank">Example_1.Zip</a>. You can find the HEX file inside objects folder.</div>
<h4 id="Example_2">LPC1768 UART Example 2</h4>
<p>In this example you will see the characters that you type on your keyboard i.e. we echo back the characters(data) received by MCU. Serial Terminals only displays the character that it receives via serial Port. When you type a character it is directly sent to the other side via serial port. Hence, in order for us to see the character which we typed, we need to send back the same character. This is what the program below does. Whenever MCU receives a character from the RXD0 pin, it will send the same character back to PC via the TXD0 Pin and it gets displayed in Terminal.</p>
<p>Here is a <strong>snippet</strong> of Example 2: (Full source code given is in KEIL ARM project files &#8211; attached below)</p>
<pre><code class="language-cpp">
/*(C) Umang Gajera - www.ocfreaks.com
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
LPC1768 Basic UART Example 2 Source Code.
License: GPL.*/

#include &lt;lpc17xx.h&gt;

#define RDR         (1<<0) //Receiver Data Ready
#define THRE        (1<<5) //Transmit Holding Register Empty
#define MULVAL      15
#define DIVADDVAL   2
#define Ux_FIFO_EN  (1<<0)
#define Rx_FIFO_RST (1<<1)
#define Tx_FIFO_RST (1<<2)
#define DLAB_BIT    (1<<7)
#define LINE_FEED   0x0A //LF, For Linux, MAC and Windows Terminals  
#define CARRIAGE_RETURN 0x0D //CR, For Windows Terminals (CR+LF).
#define ENTER       CARRIAGE_RETURN //Ascii value/code for Enter is 0x0D i.e. CR

void initUART0(void);
char U0Read(void);
void U0Write(char data);

int main(void)
{
	initUART0();
	char data = 0;
	
	while(1)		
	{
		data = U0Read(); //Read Data from Rx
		if(data == ENTER) //Check if user pressed Enter key
		{
			//Send NEW Line Character(s) i.e. "\n"
			U0Write(CARRIAGE_RETURN); //Comment this for Linux or MacOS
			U0Write(LINE_FEED); //Windows uses CR+LF for newline.
		}
		else
		{
			U0Write(data); //Tx Read Data back
		}
	}
	//return 0; //Normally this won't execute
}

char U0Read(void)
{
	while(!(LPC_UART0->LSR & RDR)); //wait until data arrives in Rx FIFO
	return LPC_UART0->RBR;
}
</code></pre>
<div class="highlight"><strong>KEIL ARM uV5 Project for Example #2 on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/UART/Example_2" target="_blank">Example 1</a> [Successfully tested on Keil uV5.23], <strong>Download Project Zip</strong> @ <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/UART/Example_2" target="_blank">Example_2.Zip</a>. You can find the HEX file inside objects folder.</div>
<p>The post <a href="https://www.ocfreaks.com/lpc1768-uart-programming-tutorial/">LPC1768 UART Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/lpc1768-uart-programming-tutorial/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2906</post-id>	</item>
		<item>
		<title>LPC1768 PWM Programming Tutorial</title>
		<link>https://www.ocfreaks.com/lpc1768-pwm-programming-tutorial/</link>
					<comments>https://www.ocfreaks.com/lpc1768-pwm-programming-tutorial/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Thu, 21 Sep 2017 17:07:59 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[lpc1768]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=2876</guid>

					<description><![CDATA[<p>This discussion will guide you through ARM Cortex-M3 LPC1768 PWM programming Tutorial. It is also applicable for LPC1769. I&#8217;ll be covering Single Edge PWM along with examples like how to use to control Motors like Servos and dimming an LED. I assume you are comfortable with Timers and its usage in ARM Cortex-M3 based LPC176x [&#8230;]</p>
<p>The post <a href="https://www.ocfreaks.com/lpc1768-pwm-programming-tutorial/">LPC1768 PWM Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="tocpostimage"> This discussion will guide you through ARM Cortex-M3 LPC1768 PWM programming Tutorial. It is also applicable for LPC1769. I&#8217;ll be covering Single Edge PWM along with examples like how to use to control Motors like Servos and dimming an LED. I assume you are comfortable with Timers and its usage in ARM Cortex-M3 based LPC176x micro-controllers since PWM block is basically a Timer.</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="#PWM_Module"><span>ARM Cortex-M3 LPC1768 PWM Module</span></a></li>
<ol class="toc_list">
<li class="toc_text"><a href="#PWM_timing_diagram"><span>PWM Timing Diagram Example</span></a></li>
</ol>
<li class="toc_text"><a href="#PWM_Registers"><span>PWM Registers</span></a></li>
<li class="toc_text"><a href="#PWM_Configuration"><span>Configuring PWM Block</span></a></li>
<ol class="toc_list">
<li class="toc_text"><a href="#PWM_Prescaler_formula"><span>PWM Prescaler Calculations</span></a></li>
</ol>
<li class="toc_text"><a href="#LPC1768_PWM_Examples"><span>LPC1768 PWM Examples</span></a></li>
<ol class="toc_list">
<li class="toc_text"><a href="#Servo_Control_Example"><span>LPC1768 PWM Example: Servo Control</span></a></li>
<li class="toc_text"><a href="#LED_Dimming_Example"><span>LPC1768 PWM Example: LED Dimming</span></a></li>
</ol>
</ol>
</div>
</div>
<h4> Pulse Width Modulation Basics: </h4>
<p>I&#8217;ve have posted a <a href="https://www.ocfreaks.com/pulse-width-modulation-pwm-tutorial/">Beginner PWM tutorial</a>. If you are new to PWM please have a look there. A Diagram that sums it up is given below. It shows Single Edge PWM with T-ON, T-OFF &#038; Period. Duty Cycle is simply T-ON Divided by Period.</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/pwm_basics.png" alt="PWM timing showing Ton, Toff and Period" width="425px" height="180px" /></p>
<h2 class="shead" id="PWM_Module">ARM Cortex-M3 LPC1768 PWM Module</h2>
<p>These MCUs Contains a single PWM Module called PWM1 and supports 2 types of PWM:<br />
<strong>1) Single Edge PWM</strong> &#8211; Pulse starts with new Period i.e Pulse is always at the beginning<br />
<strong>2) Double Edge PWM</strong> &#8211; Pulse can be present anywhere within the Period</p>
<p>A PWM block, similar to a Timer block, has a Timer Counter and an associated Prescale Register along with Match Registers. These work exactly the same way as in the case of Timers. I&#8217;ve explained them in the introduction part of the <a href="https://www.ocfreaks.com/lpc1768-timer-programming-tutorial/">LPC1768 Timer tutorial</a> . Match Registers 1 to 6 (except 0) are pinned on LPC176x i.e. the corresponding outputs are given to actual Pins on LPC176x MCU. The PWM function must be selected for these Pins, using PINSELx Register, to get the PWM output. These pins are:</p>
<table class="aligncenter" style="margin-bottom:15px;">
<tr>
<td> <strong>Output</strong></td>
<td> PWM1.1</td>
<td>PWM1.2</td>
<td>PWM1.3</td>
<td>PWM1.4</td>
<td>PWM1.5</td>
<td>PWM1.6</td>
</tr>
<tr>
<td><strong>Pin Name</strong></td>
<td>P1.18<br />P2.0</td>
<td>P1.20<br />P2.1<br />P3.25</td>
<td>P1.21<br />P2.2<br />P3.26</td>
<td>P1.23<br />P2.3</td>
<td>P1.24<br />P2.4</td>
<td>P1.26<br />P2.5</td>
</tr>
</table>
<p></center></p>
<div class="special sp_blue noteinfo"><strong>Note :</strong> PWM1.1 output corresponds to PWM Match Register 1 i.e PWM1MR1 , PWM1.2 output corresponds to PWM1MR2 , and so on. Also Match Register 0 i.e PWM1MR0 is NOT pinned because it is used to generate the PWM Period. P3.25 and P3.26 are only available on 100 pin LQFP package.</div>
<p>There are 7 match registers inside the PWM1 block. The first Match register PWM1MR0 is used to generate PWM period and hence we are left with 6 Match Registers PWM1MR1 to PWM1MR6 to generate 6 Single Edge PWM signals or 3 Double Edge PWM signals. Double edge PWM uses 2 match registers hence we can get only 3 double edge outputs.</p>
<div class="highlight">
<strong>PWM Rules &#8211;</strong> The User Manual mentions Rules for using Single Edge and Double Edge PWM on page 524 . The Rules for Single Edged PWM are as:</p>
<ul style="margin-bottom:10px">
<li>1) All single edged PWM outputs will go high at the beginning of a PWM cycle unless their match value is 0.</li>
<li>2) Each PWM output will go low when its match value is reached. <strong>Note:</strong> If no match occurs i.e Match value is greater than Period then the output will remain high!</li>
</ul>
</div>
<p id="PWM_timing_diagram">Consider that our PWM Period duration is 5 milliseconds and TC increments every 1 millisecond using appropriate prescale value. We set PWM1MR0 to 5 i.e. <strong>5 ticks of PWM TC</strong>. We have PWM1MR1 = 2 and PWM1MR2 = 4. Whenever the value in TC matches the value in any of the match register, its corresponding output it set to low until the start of next PWM cycle as shown in PWM Timing Diagram below:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/lpc_pwm_timing_diagram.png" alt="LPC Microcontroller PWM Module Timing Diagram" width="525px" height="325px" /></p>
<p>For Double Edge Rules you can refer the User Manual <strong>Pg. 524</strong>.</p>
<div class="special sp_red noteinfo"><strong>Note:</strong> The last 6 Match Registers i.e PWM1MR1 to PWM1MR6 have an associated PIN from which we get the PWM outputs. The PWM block controls the output of these pins depending on the value in its corresponding Match Register. For Single Edged PWM these Pins are set to High by default when a new Period starts i.e when TC is reset as per the PWM Rules given above.</div>
<h2 class="shead" id="PWM_Registers">Registers used in LPC176x PWM Programming</h2>
<p>Now lets have a look at some important Registers:</p>
<div class="highlight">
<strong>1) <span class="doc_ref">PWM1TCR</span> &#8211; PWM Timer Control Register:</strong> This register is used to control the Timer Counter inside the PWM block. Only Bits: 0, 1  &#038; 3 are used rest are reserverd.</p>
<ul>
<li><strong>Bit 0 :</strong> When 1 both PWM Timer counter and PWM Prescale counter are enabled. When 0 both are disabled.</li>
<li><strong>Bit 1 :</strong> When set to 1 it will reset Reset both Timer and Prescale counter of PWM block (at next edge of PCLK).</li>
<li><strong>Bit 3 :</strong> Enables PWM mode i.e the PWM outputs.</li>
<li>Other Bits : Reserved.</li>
</ul>
<p><strong>2) <span class="doc_ref">PWM1PR</span> &#8211; PWM Prescale Register:</strong> PWMPR is used to control the resolution of the PWM outputs. The Timer Counter(TC) will increment every PWMPR+1 Peripheral Clock Cycles (PCLK).</p>
<p><strong>3) <span class="doc_ref">PWM1MR0</span> &#8211; PWM1MR6 (Match Registers):</strong> These are the seven Match registers as explained above which contain <strong>Pulse Width Values i.e the Number of PWM1TC Ticks</strong>.</p>
<p><strong>4) <span class="doc_ref">PWM1MCR</span> &#8211; PWM Match Control Registers:</strong> The PWM Match Control Register is used to specify what operations can be done when the value in a particular Match register equals the value in TC. For each Match Register we have 3 options : Either generate an Interrupt , or Reset the TC , or Stop .. which stops the counters and disables PWM. Hence this register is divided into group of 3 bits. The first 3 bits are for Match Register 0 i.e PWMMR0 , next 3 for PWMMR1 , and so on.</p>
<ul>
<li><strong>1) Bit 0 :</strong> Interrupt on PWM1MR0 Match &#8211; If set to 1 then it will generate an Interrupt else disable if set to 0.</li>
<li><strong>2) Bit 1 :</strong> Reset on PWM1MR0 Match &#8211; If set to 1 it will reset the PWM Timer Counter i.e. PWM1TC else disabled if set to 0.</li>
<li><strong>3) Bit 2 :</strong> Stop on PWM1MR0 Match &#8211; If this bit is set 1 then both PWM1TC and PWM1PC will be stopped &#038; disable the Counters.</li>
<li><strong>*)</strong> Similarly {Bits 3,4,5} for PWM1MR1 , {Bits 6,7,8} for PWM1MR2 , {Bits 9,10,11} for PWM1MR3 ,{Bits 12,13,14} for PWM1MR4 ,{Bits 15,16,17} for PWM1MR5 , {Bits 18,19,20} for PWM1MR6.</li>
</ul>
<p><strong>5) <span class="doc_ref">PWM1IR</span> &#8211; PWM Interrupt Register:</strong> If an interrupt is generated by any of the Match Register then the corresponding bit in PWM1IR will be set high. Writing a 1 to the corresponding location will clear that interrupt.</p>
<ul>
<li><strong>1) Bits 0,1,2,3</strong> are for PWM1MR0, PWM1MR1, PWM1MR2, PWM1MR3 respectively and </li>
<li><strong>2) Bits 8,9,10</strong> are for PWM1MR4 , PWM1MR5 , PWM1MR6 respectively. Other bits are reserved.</li>
</ul>
<p><strong>6) <span class="doc_ref">PWMLER</span> &#8211; Load Enable Register:</strong> The PWM Load Enable Register is used to control the way Match Registers are updated when PWM generation is active. When PWM mode is active and we apply new values to the Match Registers the new values won&#8217;t get applied immediately. Instead what happens is that the value is written to a &#8220;Shadow Register&#8221; .. it can be thought of as a duplicate Match Register. Each Match Register has a corresponding Shadow Register. The value in this Shadow Register is transferred to the actual Match Register when: PWM1TC is reset (i.e at the beginning of the next period) and the corresponding Bit in PWM1LER is 1.</p>
<p>Hence only when these 2 conditions are satisfied the value is copied to Match Register. Bit &#8216;x&#8217; in PWM1LER corresponds to match Register &#8216;x&#8217;. I.e Bit 0 is for PWM1MR0 , Bit 1 for PWM1MR1 , .. and so on. Using PWM1LER will be covered in the examples section.</p>
<p><strong>7) <span class="doc_ref">PWM1PCR</span> &#8211; PWM Control Register:</strong> This register is used for Selecting between Single Edged &#038; Double Edged outputs and also to Enable/Disable the 6 PWM outputs which go to their corresponding Pins. </p>
<ul style="margin-bottom:0px">
<li>1) <strong>Bits 2 to 6</strong> are used to select between Single or Double Edge mode for PWM 2,3,4,5,6 outputs. If <strong>Bit 2</strong> is set to 1 then PWM1.2(i.e the one corresponding to PWM1MR2) output is double edged else if set 0 then its Single Edged. Similarly <strong>Bit x</strong> for PWM1.x correspondingly.
</li>
<li>2)<strong> Bits 9 to 14</strong> are used to Enable/Disable PWM outputs. If <strong>Bit 9</strong>is set to 1 then PWM1.1 output is enabled , else disabled if set to 0. Similarly remaining bits for PWM1.x correspondingly.
</li>
</ul>
</div>
<h2 class="shead" id="PWM_Configuration">Configuring and Initializing PWM Block</h2>
<p>Now, lets see how to use PWM block. Configuring PWM module is very much similar to Configuring Timer except, additionally, we need to enable the outputs and select PWM functions for the corresponding PIN on which PWM output will be available. But first we need to do some basic Math Calculations for defining the Period time, the resolution using a prescale value and then Pulse Widths. For this First we need to define the resolution of our PWM signal. PWM resolution is the minimum time delay that can used to increase or decrease the pulse width. More smaller the increment more fine will be the resolution. PWM Resolution is set using an appropriate Prescale Value. The calculation for PWM Prescaler is the same which I had shown in the <a href="https://www.ocfreaks.com/lpc1768-timer-programming-tutorial/">Timer Tutorial</a>, here it is once again:</p>
<div class="special sp_blue noteinfo" id="PWM_Prescaler_formula">
<h4>LPC1768 PWM Prescale (PWM1PR) Calculations:</h4>
<p>The general formula for <strong>PWM Resolution</strong> at X Mhz PCLK(CCLK) and a given value for prescale (PR) is as given below:</p>
<div class="equation">PWM<sub>RES</sub> =</p>
<div class="fraction"><span class="fup">PR+1</span><span class="bar">/</span><span class="fdn">PCLK<sub>Hz</sub></sup></span></div>
<p> =</p>
<div class="fraction"><span class="fup">PR+1</span><span class="bar">/</span><span class="fdn">X * 10<sup>6</sup></span></div>
<p>Seconds</p></div>
<p>Hence, we get the <strong>Formula for Prescaler (PR) for required PWM resolution (PWM<sub>RES</sub> in Secs)</strong> at given <strong>PCLK(in Hz)</strong> frequency as:</p>
<div class="equation">PR = (PCLK<sub>Hz</sub> * PWM<sub>RES</sub>) &#8211; 1</div>
<div class="equation">PR = ((X * 10<sup>6</sup>) * PWM<sub>RES</sub>) &#8211; 1</div>
<p>Note that here, the PWM Resolution is also the time delay required to increment PWM TC by 1.</p>
<p>Hence, Prescaler value for 1 micro-second resolution i.e. 1us time delay at 25 Mhz PCLK(CCLK) is,</p>
<div class="equation">PR<sub>1us</sub> = (25Mhz * 1uS) -1 = (25*10<sup>6</sup> * 10<sup>-6</sup>) -1 = 24</div>
<p>Prescale for 1 mS (milli-second) resolution at 25Mhz PCLK(CCLK) is,</p>
<div class="equation">PR<sub>1ms</sub> = (25Mhz * 1ms) -1 = (25*10<sup>6</sup> * 10<sup>-3</sup>) -1 = 24999</div>
<p><strong>Note: </strong>The calculations for <strong>LPC1769</strong> are same except it operates at <strong>120Mhz(max CCLK)</strong>. Hence <strong>default PCLK</strong> will be <strong>30Mhz</strong>.</p>
</div>
<div class="highlight">
Now , After we&#8217;ve worked out the resolution we want .. we can now Configure &#038; Initialize the PWM device as per the following steps:</p>
<ol style="margin-bottom:0px">
<li>Select the PWM function for the PIN on which you need the PWM output using applicable <span class="code_var">LPC_PINCON->PINSELx</span> register.</li>
<li>Select Single Edge or Double Edge Mode using <span class="code_var">LPC_PWM1->PCR</span>. By default its Single Edge Mode.</li>
<li>Assign the Calculated value to <span class="code_var">LPC_PWM1->PR</span>.</li>
<li>Set the Value for PWM Period in <span class="code_var">LPC_PWM1->MR0</span>.</li>
<li>Set the Values for other Match Registers i.e the Pulse Widths.</li>
<li>Set appropriate bit values in <span class="code_var">LPC_PWM1->MCR</span> .. like for e.g. resetting PWM1TC for PWMMR0 match and optionally generate interrupts if required</li>
<li>Set Load Enable Bits for the Match Registers that you&#8217;ve used. This is important!</li>
<li>Then Enable PWM outputs using <span class="code_var">LPC_PWM1->PCR</span>.</li>
<li>Now Reset PWM Timer using <span class="code_var">LPC_PWM1->TCR</span>.</li>
<li>Finally, Enable Timer Counter and PWM Mode using <span class="code_var">LPC_PWM1->TCR</span>.</li>
</ol>
</div>
<p><strong>Example :</strong></p>
<pre><code class="language-cpp">
//Select PWM Function Using appropriate PINSEL register
LPC_PWM1->PCR = ... ; //Select PWM type - By default its Single Edged
LPC_PWM1->PR = ... ; //assign calculated PR value 
LPC_PWM1->MR0 = ... ; //Assign Period Duration
LPC_PWM1->MRx = ... ; //Assign pulse duration i.e widths for other Match Regs.. x=1 to 6
LPC_PWM1->MCR = (1<<1) | ... ; //Reset PWM1TC on PWMMR0 match &#038; Other conditions
LPC_PWM1->LER = (1<<1) | ... ; //update MR0 and other Match Registers
LPC_PWM1->PCR = ... ; //enable PWM outputs as required
LPC_PWM1->TCR = (1<<1) ; //Reset PWM TC &#038; PR

//Now , the final moment - enable PWM TC
LPC_PWM1->PWM1TCR = (1<<0) | (1<<3); //enable counters and PWM Mode
//Done!
</code></pre>
<h4>Updating Match Registers i.e. the Pulse Width</h4>
<p>Once PWM is initialized, you can update any of the Match Registers at anytime using PWMLER. This can be done as follows:</p>
<pre><code class="language-cpp">
LPC_PWM1->MR1 = 50; //Update Pulse Width
LPC_PWM1->LER = (1<<1); //set the corresponding bit to 1
</code></pre>
<p>When you want to update Multiple Match Registers then this can be done as follows:</p>
<pre><code class="language-cpp">
LPC_PWM1->MR1 = 50;
LPC_PWM1->MR2 = 68;
LPC_PWM1->MR3 = 20;

LPC_PWM1->LER = (1<<1) | (1<<2) | (1<<3); //Update Load Enable bit for all MRs together</code></pre>
<h2 class="shead" id="LPC1768_PWM_Examples">Some Real World PWM Examples with sample code</h2>
<p>Below I have given LPC1768 PWM Examples. For LCP1769 just change the PWM Prescale from 24 to 29 and Timer Prescale from 24999 to 29999.</p>
<h4 id="Servo_Control_Example">LPC1768 PWM Example 1: Servo Control</h4>
<p>In this LPC1768 PWM Example we will sweep a servo from 1000us to 2000us pulse widths, back and forth in steps. The period is set to 20ms(20000us) which is common for servos. PWM1.1 output is selected and will be available on Pin P1.18. In the C++ code given below, I have also used Timer0 which is used by <span class="code_var">delayMS(..)</span> function to generate delay before we update PWM1MR1 register with new value. <strong>Warning:</strong> Double check all connections when connecting the motor or it will damage your board.</p>
<p><strong>Source Code for Example 1:</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera - www.ocfreaks.com
More Embedded tutorials @ www.ocfreaks.com/cat/embedded
LPC1768 PWM Tutorial Example 1 - Simple RC Servo Control - KEIL uV5 ARM.
License: GPL */

#include &lt;LPC17xx.h&gt;
#define PWMPRESCALE (25-1) //25 PCLK cycles to increment TC by 1 i.e. 1 Micro-second

void initPWM(void);
void updatePulseWidth(unsigned int pulseWidth);
void delayMS(unsigned int milliseconds);
void initTimer0(void);

int main(void)
{
	//SystemInit(); //gets called by Startup code before main()
	initTimer0(); //Initialize Timer
	initPWM(); //Initialize PWM
	
	int pulseWidths[] = {1000,1250,1500,1750,2000};
	const int numPulseWidths = 5;
	int count=1;
	int dir=0; //direction, 0 = Increasing, 1 = Decreasing 

	while(1)
	{
		updatePulseWidth(pulseWidths[count]); //Update Servo Pulse Width
		delayMS(1000); //Wait for servo to reach the new position

		if(count == (numPulseWidths-1) || count == 0)
		{
			dir = !dir; //Toggle direction if we have reached count limit
		}
		
		if(dir) count--;
		else count++;
	}
  //return 0; //normally this won't execute ever
}

void initPWM(void)
{
	/*Assuming that PLL0 has been setup with CCLK = 100Mhz and PCLK = 25Mhz.*/

	LPC_PINCON->PINSEL3 |= (1<<5); //Select PWM1.1 output for Pin1.18
	LPC_PWM1->PCR = 0x0; //Select Single Edge PWM - by default its single Edged so this line can be removed
	LPC_PWM1->PR = PWMPRESCALE; //1 micro-second resolution
	LPC_PWM1->MR0 = 20000; //20000us = 20ms period duration
	LPC_PWM1->MR1 = 1250; //1ms - default pulse duration i.e. width
	LPC_PWM1->MCR = (1<<1); //Reset PWM TC on PWM1MR0 match
	LPC_PWM1->LER = (1<<1) | (1<<0); //update values in MR0 and MR1
	LPC_PWM1->PCR = (1<<9); //enable PWM 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!
	//Now you can get the PWM output on Pin P1.18
}

void updatePulseWidth(unsigned int pulseWidth)
{
	LPC_PWM1->MR1 = pulseWidth; //Update MR1 with new value
	LPC_PWM1->LER = (1<<1); //Load the MR1 new value at start of next cycle
}


void delayMS(unsigned int milliseconds) //Using Timer0
{
	LPC_TIM0->TCR = 0x02; //Reset Timer
	LPC_TIM0->TCR = 0x01; //Enable timer

	while(LPC_TIM0->TC < milliseconds); //wait until timer counter reaches the desired delay

	LPC_TIM0->TCR = 0x00; //Disable timer
}

void initTimer0(void) //To setup Timer0 used delayMS() function
{
	/*Assuming that PLL0 has been setup with CCLK = 100Mhz and PCLK = 25Mhz.*/

	LPC_TIM0->CTCR = 0x0;
	LPC_TIM0->PR = 25000-1; //Increment TC at every 24999+1 clock cycles
	//25000 clock cycles @25Mhz = 1 mS

	LPC_TIM0->TCR = 0x02; //Reset Timer
}
</code></pre>
<div class="highlight"><strong>KEIL uV5 Project for Example #1 on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/PWM/Example_1" target="_blank">PWM Example 1 Source</a> [Successfully tested on Keil uV5.23], <strong>Download Project Zip</strong> @ <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/PWM/Example_1" target="_blank">Example_1.Zip</a></div>
<h4 id="LED_Dimming_Example">LPC1768 PWM Example 2: LED Dimming</h4>
<p>This example is similar to Example 1, except here we reduce the PWM Period to 1ms and Duty-cycle will vary from 0%(LED OFF) to 100%(Brightest). Connect the LED anode to P1.18 and cathode to GND using a suitable resistor (like >330 Ohms).</p>
<p><strong>Source code for Example 2</strong></p>
<pre><code class="language-cpp">
/*(C) Umang Gajera - www.ocfreaks.com
More Embedded tutorials @ www.ocfreaks.com/cat/embedded
LPC1768 PWM Tutorial Example 2 - LED Dimming using PWM - KEIL uV5 ARM.
License: GPL.
*/

#include &lt;LPC17xx.h&gt;
#define PWMPRESCALE (25-1) //25 PCLK cycles to increment TC by 1 i.e. 1 Micro-second

void initPWM(void);
void updatePulseWidth(unsigned int pulseWidth);
void delayMS(unsigned int milliseconds);
void initTimer0(void);

int main(void)
{
	//SystemInit(); //gets called by Startup code before main()
	initTimer0(); //Initialize Timer
	initPWM(); //Initialize PWM
	
	int pulseWidths[] = {0,250,500,750,1000}; //Pulse Widths for varying LED Brightness
	const int numPulseWidths = 5;
	int count=1;
	int dir=0; //direction, 0 = Increasing, 1 = Decreasing 

	while(1)
	{
		updatePulseWidth(pulseWidths[count]); //Update LED Pulse Width
		delayMS(1000); 

		if(count == (numPulseWidths-1) || count == 0)
		{
			dir = !dir; //Toggle direction if we have reached count limit
		}
		
		if(dir) count--;
		else count++;
	}
  //return 0; //normally this won't execute ever
}

void initPWM(void)
{
	/*Assuming that PLL0 has been setup with CCLK = 100Mhz and PCLK = 25Mhz.*/

	LPC_PINCON->PINSEL3 |= (1<<5); //Select PWM1.1 output for Pin1.18
	LPC_PWM1->PCR = 0x0; //Select Single Edge PWM - by default its single Edged so this line can be removed
	LPC_PWM1->PR = PWMPRESCALE; //1 micro-second resolution
	LPC_PWM1->MR0 = 1000; //1000us = 1ms period duration
	LPC_PWM1->MR1 = 250; //250us - default pulse duration i.e. width
	LPC_PWM1->MCR = (1<<1); //Reset PWM TC on PWM1MR0 match
	LPC_PWM1->LER = (1<<1) | (1<<0); //update values in MR0 and MR1
	LPC_PWM1->PCR = (1<<9); //enable PWM 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!
	//Now you can get the PWM output on Pin P1.18
}

void updatePulseWidth(unsigned int pulseWidth)
{
	LPC_PWM1->MR1 = pulseWidth; //Update MR1 with new value
	LPC_PWM1->LER = (1<<1); //Load the MR1 new value at start of next cycle
}


void delayMS(unsigned int milliseconds) //Using Timer0
{
	LPC_TIM0->TCR = 0x02; //Reset Timer
	LPC_TIM0->TCR = 0x01; //Enable timer

	while(LPC_TIM0->TC < milliseconds); //wait until timer counter reaches the desired delay

	LPC_TIM0->TCR = 0x00; //Disable timer
}

void initTimer0(void) //To setup Timer0 used delayMS() function
{
	/*Assuming that PLL0 has been setup with CCLK = 100Mhz and PCLK = 25Mhz.*/

	LPC_TIM0->CTCR = 0x0;
	LPC_TIM0->PR = 25000-1; //Increment TC at every 24999+1 clock cycles
	//25000 clock cycles @25Mhz = 1 mS

	LPC_TIM0->TCR = 0x02; //Reset Timer
}
</code></pre>
<div class="highlight"><strong>KEIL uV5 Project for Example #2 on GitHub @</strong> <a href="https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/PWM/Example_2" target="_blank">PWM Example 2 Source</a> [Successfully tested on Keil uV5.23], <strong>Download Project Zip</strong> @ <a href="https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/OCFreaks/LPC1768-Tutorial-Examples/tree/master/PWM/Example_2" target="_blank">Example_2.Zip</a></div>
<p>The post <a href="https://www.ocfreaks.com/lpc1768-pwm-programming-tutorial/">LPC1768 PWM Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/lpc1768-pwm-programming-tutorial/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2876</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 21:42:19 by W3 Total Cache
-->