Difference between revisions of "Embedded Programming Tips and Tricks"

From EEVblog Electronics Resource Wiki
Jump to: navigation, search
(Fast Division)
m (Reverted edits by 199.87.154.255 (talk) to last revision by 58.28.158.238)
 
(14 intermediate revisions by 2 users not shown)
Line 1: Line 1:
==Fast Division==
+
=Fast Division=
 
On microcontrollers without a divide instruction very fast division can be done by bit shifting a variable right.<br>
 
On microcontrollers without a divide instruction very fast division can be done by bit shifting a variable right.<br>
 
Each shift does a divide by two.<br>
 
Each shift does a divide by two.<br>
Line 19: Line 19:
 
Also be sure the variable size is large enough to store the multiplied value.<br>
 
Also be sure the variable size is large enough to store the multiplied value.<br>
  
===Timed Events Using Interrupts===
+
=Repeating Code Using Interrupts=
  
When writing embedded code you will quite often need to trigger code at a regular interval. (for example flashing an led)  
+
When writing embedded code you will quite often need to trigger code at a regular interval. (for example flashing an led)<br>
 
Over your entire project there maybe many different code segments you wish to execute at different rates.
 
Over your entire project there maybe many different code segments you wish to execute at different rates.
 
To do this it can be useful to dedicate one of the microcontrollers hardware timers to perform all these timing tasks.
 
To do this it can be useful to dedicate one of the microcontrollers hardware timers to perform all these timing tasks.
Line 30: Line 30:
 
Such a system might look like this
 
Such a system might look like this
  
==AVR==
+
===AVR===
 
<pre>
 
<pre>
  
uint16_t clk1000ms=1;
+
#define off 0
uint16_t clk100ms=1;
+
#define on 1
uint8_t clk10ms=1;
 
  
 +
volatile uint16_t clk1000ms=1; // initializing them to 1 insures there is an initial delay cycle when
 +
volatile uint16_t clk100ms=1;  // the code first starts, otherwise they would all happen at
 +
volatile uint8_t clk10ms=1;    // once during first run.
  
 
ISR (TIMER0_OVF_vect)
 
ISR (TIMER0_OVF_vect)
 
{
 
{
if (clk1000ms!=0)  
+
if (clk1000ms!=off)  
 
{
 
{
 
clk1000ms++;
 
clk1000ms++;
if (clk1000ms>=10001) clk1000ms=0;
+
if (clk1000ms>=10001) clk1000ms=off;
 
}
 
}
if (clk100ms!=0)  
+
if (clk100ms!=off)  
 
{
 
{
 
clk100ms++;
 
clk100ms++;
if (clk100ms>=1001) clk500ms=0;
+
if (clk100ms>=1001) clk100ms=off;
 
}
 
}
if (clk10ms!=0)  
+
if (clk10ms!=off)  
 
{
 
{
 
clk10ms++;
 
clk10ms++;
if (clk10ms>=101) clk10ms=0;
+
if (clk10ms>=101) clk10ms=off;
 
}
 
}
 
// Timer clock is 1mhz, timer is 8bit.
 
// Timer clock is 1mhz, timer is 8bit.
Line 64: Line 66:
 
{
 
{
 
 
if (clk1000ms==0)
+
if (clk1000ms==off)
 
{
 
{
 
// put code here to run every second
 
// put code here to run every second
  
clk1000ms = 1;
+
clk1000ms = on;
 
}
 
}
if (clk100ms==0)
+
if (clk100ms==off)
 
{
 
{
 
// put code here to run 10 times a second
 
// put code here to run 10 times a second
  
clk100ms = 1;
+
clk100ms = on;
 
}
 
}
if (clk10ms==0)
+
if (clk10ms==off)
 
{
 
{
 
// put code here to run 100 times a second
 
// put code here to run 100 times a second
  
clk10ms = 1;
+
clk10ms = on;
 
}
 
}
 
 
 
}
 
}
 
</pre>
 
</pre>

Latest revision as of 17:39, 17 June 2016

Fast Division[edit]

On microcontrollers without a divide instruction very fast division can be done by bit shifting a variable right.
Each shift does a divide by two.

For example

 Y = Y >> 1;  (Will result in a divide by 2)

or

 X = X >> 4;  (Will result in a divide by 16)

By adding a multiplication you can achieve a limited number of other divisions.

For example

 Z = Z * 3;
Z = Z >> 4; (div 16)

Will result in a division of 5.33 (16/3 = 5.33)

Be sure to do the multiply first, otherwise bits will be lost.
Also be sure the variable size is large enough to store the multiplied value.

Repeating Code Using Interrupts[edit]

When writing embedded code you will quite often need to trigger code at a regular interval. (for example flashing an led)
Over your entire project there maybe many different code segments you wish to execute at different rates. To do this it can be useful to dedicate one of the microcontrollers hardware timers to perform all these timing tasks.

Since it's bad practice to put lots of code inside an interrupt handler the best approach is to just set flags and then test these flags inside your main program loop.


Such a system might look like this

AVR[edit]


#define off 0
#define on 1

volatile uint16_t clk1000ms=1; // initializing them to 1 insures there is an initial delay cycle when
volatile uint16_t clk100ms=1;  // the code first starts, otherwise they would all happen at
volatile uint8_t clk10ms=1;    // once during first run.

ISR (TIMER0_OVF_vect)
{		
	if (clk1000ms!=off) 
	{
		clk1000ms++;
		if (clk1000ms>=10001) clk1000ms=off;
	}
	if (clk100ms!=off) 
	{
		clk100ms++;
		if (clk100ms>=1001) clk100ms=off;
	}
	if (clk10ms!=off) 
	{
		clk10ms++;
		if (clk10ms>=101) clk10ms=off;
	}
	// Timer clock is 1mhz, timer is 8bit.
	// Now we set the timer register to 156 so it takes 100 timer clocks to overflow.
 	// This will mean the interrupt code executes at 1mhz/100 = 10000Hz		
	TCNT0 = 156;	
}

void main(void)
{
	
	if (clk1000ms==off)
	{	
		// put code here to run every second

		clk1000ms = on;
	}	
	if (clk100ms==off)
	{
		// put code here to run 10 times a second

		clk100ms = on;
	}
	if (clk10ms==off)
	{
		// put code here to run 100 times a second

		clk10ms = on;
	}
	
}