Tips and tricks (Part 24)

Previous T&T

In the same way that Google search engine is a standard de facto, its approach to programming may seriously be regarded as a standard too.

Arduino fans may know or not that the IDE uses a C++ like language and may check what Google,  now grown up to Alphabet as a company, is saying in terms of programming standards. You may or may not adhere to their principles, however reading this page helps in reviewing all components in use in a C++ program. Thanks Antony for the tip.

Enjoy

Connecting AVRISP to Arduino (Part 4)

Part 123, 4

Here is a more comprehensive description of the procedure that one should follow in order to be able to use the AVRISP MKII programmer in a mixed IDE environment without too much trouble 😉

The proposed procedure is a mix of the early procedure described in arduinoos and a good description of the problem and solution posted on the VisualMicro web site.

Context

During the installation of Arduino IDE, a USB driver is installed so that the Atmel AVRISP mk II programmer can be used as an alternative to the Arduino serial boot-loader. The programmer can also be used for “burning” a bootloader on the target MCU so that the MCU can be programmed through the USB port.

During the installation of Atmel Studio a specific USB driver will be installed: this is the Jungo driver. While you have the option of not installing the Jungo driver during the Atmel Studio installation process, but the lack of Jungo driver will prevent you from using the Atmel AVRISP mk II within the Atmel Studio environment. So let’s say that we decide to install the Jungo driver.

  • OS: Windows 7 Pro
  • Atmel Studio: rev. 6.2 SP2
  • AVRISP mkII: guenuine product
  • libusb: rev. 1.2.6.0
  • Arduino IDE: rev. 1.6.5

Problem

Having installed Atmel Studio and the the Jungo driver, the Atmel AVRISP mk II programmer will no longer work with Arduino IDE. AVRdude (one of the key applications behind the Arduino IDE) won’t work properly, because its normal USB driver has been replaced by the Jungo driver that Atmel Studio has loaded.

Solution

The idea is to allow the Jungo driver which works fine with Atmel Studio to co-exist with the Arduino IDE environment.

Note: This is a principle solution. You may retain the principle, mix it with common sense and apply it to your environment !

Arduino IDE uses the libusb0.dll USB driver. This DLL comes from a larger driver package that installs a generic USB driver which can be used by a variety of Microsoft Windows applications. This package provides drivers in two formats: stand-alone and filter. The stand-alone version is installed along with the Arduino IDE. The filter version is installed along with Atmel Studio. The filter version interfaces to Arduino IDE via the libusb0.dll driver ; it “messages” the data and forwards it along to the Jungo driver. As a consequence of installing the filter version, “upload using programmer” or “Burn bootloader” functions will not work correctly within the Arduino IDE environment.

 Procedure

Plug your Atmel AVRISP mk II programmer and check for the actual driver using the Device Manager Program (“Computer” icon, right-click “Manage” in pop-up menu).

device_manager

Download the libusb package from here. The libusb is a C library that gives applications easy access to USB devices on many different operating systems. libusb is an open source project, the code is licensed under the ​GNU Lesser General Public License version 2.1 or later. More on libsub. Unzip the downloaded file and navigate to the “libusb-win32-bin-1.2.6.0/bin folder”. Select the sub folder which fits with your processor. Plug in your AVRISP mk II. Then run “install-filter-win.exe” program, which will display the following screen:

install-filter-win_1

Press Next, and you should see your Atmel AVRISP mk II in the list:

install-filter-win_4.

Note: If the AVRISP mk II does NOT appear, it is possible that a libusb driver for it has already been installed. If necessary, go back to the previous screen and  remove the appropriate device filter.

Select the AVRISP mk II and click on “Install”.

libusb0.dll filter driver should now be installed for the AVRISP mk II. You can check for its presence in the “Windows/System32″ folder under the filename “libusb0.dll”. You can test the driver using the “testlibusb-win.exe” program (in the sub folder mentioned above):

install-filter-win_3.

Now, we have to prevent the AVRdude program from using the “libusb0.dll” file that it has already installed in its own folder, and instead use the filter version that we’ve just installed. To do this, “remove” all instances of the “libusb0.dll” files from within the “c:\program files\arduino” folder hierarchy. The best way to do this is to navigate to the “c:\programfiles\arduino” folder, and do a search for “libusb0.dll”. Once you have found them, rename them to “libusb0.dll.bak” (in case you need to cancel the operation). Once these files are “removed”, AVRdude will still look for libusb0.dll, but will only find the filter version in the “windows\system32″ folder, which the default location for drivers. Last but not least, reboot your computer in order to allow changes to take effect. At this stage, the list of devices should look like:

device_manage_2r

You should now be able to open the Atmel Studio and go to the “Tools/Device programming” menu and select the AVRISP mk II. After you click the “Apply” button you should be able to download programs to your AVR target board using the AVRISP mk II programmer. With Arduino IDE, you should be able to perform the “upload using programmer” operation successfully.

However, the “burn Bootloader” will still fail to work with Arduino IDE. The reason lies in the timing during the boot-loader burning operation. Arduino IDE performs two back-to-back access with AVRdude to the AVRispMKII.  There is a known issue with early AVRdude which fails to re-open the USB on back-to-back accesses. The issue is that AVRdude in conjunction with the USB communication library closes the USB connection and the AVRISP MkII programmer reboots, then connects to the USB bus again, during which time the “usb” device is not present in the system, hence the error message about not being able to find a USB device. Although this problem could be solved in Arduino IDE, the solution comes from the latest version of AVRdude that you can download from here. AVRdude 6.2 is capable of running back to back operations without resetting the interface. After downloading and unzipping the files, append a .bak extension to both avrdude.exe and avrdude.conf in their respective locations and copy the latest revision of both files in C:\Program Files (x86)\Arduino\hardware\tools\avr\bin and C:\Program Files (x86)\Arduino\hardware\tools\avr\etc.

You should now be able to perform all operations in Atmel Studio, Visual Studio and Arduino IDE.

Note : Burning the boot-loader could also be performed from Visual Studio (Menu “Tools” / “Device programming”). Check for board details in the board.txt file from Arduino in order to set the appropriate parameters for the target board.

HTH

Range finder (Part 2)

Part 1, 2

As in most arduinoos posts, the examples given here differ from what is usually seen and read in terms of  code efficiency  and ruggedness of applications. Early tests performed on the HC-SR04 module proved its easiness of setup and interesting results obtained from scratch. However things are changing when accuracy is concerned and headaches begin when timeout management is needed. This post should help you in solving these issues.

In theory, the minimal code as originally proposed by David A. Mellis:

/* HC-SR04 Sensor
   https://www.dealextreme.com/p/hc-sr04-ultrasonic-sensor-distance-measuring-module-133696
  
   This sketch reads a HC-SR04 ultrasonic rangefinder and returns the
   distance to the closest object in range. To do this, it sends a pulse
   to the sensor to initiate a reading, then listens for a pulse 
   to return.  The length of the returning pulse is proportional to 
   the distance of the object from the sensor.
     
   The circuit:
	* VCC connection of the sensor attached to +5V
	* GND connection of the sensor attached to ground
	* TRIG connection of the sensor attached to digital pin 2
	* ECHO connection of the sensor attached to digital pin 4
 
 
   Original code for Ping))) example was created by David A. Mellis
   Adapted for HC-SR04 by Tautvidas Sipavicius
 
   This example code is in the public domain.
 */
 
 
const int trigPin = 2;
const int echoPin = 4;
 
void setup() {
  // initialize serial communication:
  Serial.begin(9600);
}
 
void loop()
{
  // establish variables for duration of the ping, 
  // and the distance result in inches and centimeters:
  long duration, inches, cm;
 
  // The sensor is triggered by a HIGH pulse of 10 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  pinMode(trigPin, OUTPUT);
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
 
  // Read the signal from the sensor: a HIGH pulse whose
  // duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(echoPin, INPUT);
  duration = pulseIn(echoPin, HIGH);
 
  // convert the time into a distance
  inches = microsecondsToInches(duration);
  cm = microsecondsToCentimeters(duration);
  
  Serial.print(inches);
  Serial.print("in, ");
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();
  
  delay(100);
}
 
long microsecondsToInches(long microseconds)
{
  // According to Parallax's datasheet for the PING))), there are
  // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
  // second).  This gives the distance travelled by the ping, outbound
  // and return, so we divide by 2 to get the distance of the obstacle.
  // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
  return microseconds / 74 / 2;
}
 
long microsecondsToCentimeters(long microseconds)
{
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return microseconds / 29 / 2;
}

This code can be translated to something more compact which looks like:

const uint8_t _echoPinMask = (1 << PINB3);
const uint8_t _triggerPinMask = (1 << PINB4);
const uint8_t _ledPinMask = (1 << PINB5);
const uint16_t _timeout = 38000; /* in us */
const float _speedOfSound = 343.0; /* in m/s */

void setup() 
{          
	Serial.begin(115200);
	/* Set pins */
	DDRB |= (_triggerPinMask | _ledPinMask);
	DDRB &= ~_echoPinMask;
	/* Ready */
	Blink(3);
}


void loop() 
{
	/* Mark beginning of measurement */
	PORTB |= _ledPinMask;
	/* Measure distance */
	float distance = Distance();
	/* Mark end of measurement */
	PORTB &= ~_ledPinMask;
	/* Print distance */
	Serial.print(distance, 2);
	Serial.println();
	delay(500);
}

float Distance(void)
{
	/* Send one positive pulses at least 10 us long */
	PORTB |= _triggerPinMask;
	delayMicroseconds(10);
	PORTB &= ~_triggerPinMask;
	/* Wait rising edge of echo */
	while ((~PINB & _echoPinMask) == _echoPinMask);
	/* Record start time of echo pulse */
	int32_t tip = micros();
	/* Wait falling  edge of echo or timeout */
	while (((PINB & _echoPinMask) == _echoPinMask) && (micros() < _timeout));
	/* Record stop time of echo pulse */
	int32_t top = micros();
	/* Compute distance: travel time / 2 converted to seconds multiplied by speed of sound */
	float distance =  (((top - tip) >> 1) / 1000000) * _speedOfSound;
	/* Return computed distance */
	return(distance);
}


void Blink(uint8_t blinks) 
{
	for (uint8_t i = 0; i < (blinks << 1); i++) {
		PORTB ^= _ledPinMask;
		delay(200);
	}
	PORTB &= _ledPinMask;
}

What is different in this code is the use of DDRx, PORTx and PINx native instructions for sake of speed. Also, the waiting loops for detecting the rising and falling edges of the echo signal do not make use of the pulseIn() function. What the code does is:

  • Set constants in the header part of the sketch
  • Set ports as outputs (trig line and control led) or input (echo line), set the serial port for printing results
  • idle loop for measuring and printing distance from module

This code works like a charm, as long as the target stays within the 4 meters range. If not, the control led (PNB5, alias digital pin 13) will stay on for ever. The same problem occurs when the ultrasonic beam hit an irregular surface, so that the sound slips on the surface (e.g. a ball) and fails to be echoed to the module.

Too bad :-[

Next post will try to explain why and how to turn around this issue :-)

 

Engine RPM (Part 5)

Part 1, 2, 3, 4, 5

The last two posts explained how to check whether the speed of a rotating object agreed with a predefined value or not. To the cost of an additional optical sensor and a display, we may now measure any rotating speed still without contacts between the moving object and the handled measuring device.

We will firstly “stick” to principle of the adhesive piece of white paper attached to the moving part. Then we will send a light beam towards the location of this piece of paper using a Reflective Optical Sensor. This is a compact electronic component featuring a light emitting diode (aka LED) and a photo-transistor. I selected the popular TRCT5OOO from Vishay, because it is small, it has a pretty fast response time, it is sensitive and, last but not least, it is cheap.

TCRT5000

The principle of operation is simple and intuitive.

Reflective_Opto_Sensor

Case 1: The LED (on the right hand side of the component) emits a light beam at a certain angle. If the light beam does not hit any surface, it is lost in blue sky and nothing happens.

Case 2: The LED emits a light beam at a certain angle. When the light beam hits a surface, it bounces at a symmetric angle (versus the hit surface) and a part of the emitted light is directed on the photo-transistor which lets current flow across its collector/emitter junction.

In a photo-transistor, Ice (Current flowing from collector to emitter) does not depend on the base current but on the light hitting the base which is optically exposed.

Biasing the Reflective Optical Sensor is easy and requires only a pair of resistors. A 100 Ohm resistor for the led and a 10 kOhm resistor between +5V and the collector of the photo-transistor. Then take the signal at the collector and send it to any digital or analog pin.

Let’s have a look at we can see on the scope when the probe is tied down to the collector side of the optical sensor.

Here is an example of the optical sensor located 3 cm above the target:

too_high

The reflected beam is weak and produces little changes on the photo-transistor. As the signal does not cross the trigger line (half Vcc, in other words 2.5 V), no counts will be registered.

Next is an example of the optical sensor located 3 mm above the target:

too_low

We have now an excellent optical feed-back, so good that we know see some signal (higher frequencies) which relates to the light remitted by the blades of the fan. Also, the rest signal value is too low and too close from the trigger line, so that extra counts will be registered.

And now, talaaaaa ! Here comes the plot taken at the optical sensor collector side when this sensor is located at an appropriate distance:

correct

Next posts will explain how to interpret the pulses and convert them into a digital rpm value

rpm_seven_segments_display

Arduino digital pins will have no problems in detecting edges and count pulses.

More on optical sensors.

Unwanted pop ups: I should have read the terms of use…

Well, in a sense, I should have read all the terms of use from the “sweetCAPTCHA” plugin.

5.2 You acknowledge that within the sweetCAPTCHA service and/or sweetCAPTCHA API, There might be included 3rd party content which will be displayed for the purpose of user interaction. This content might include but will not be limited to ads, banners, links, search engine input fields and etc.” Ah, ah, ah ! :-]

Many thanks to the authors of  Immotion hosting [read this thread] and CIO [read this thread] who saved my time and my nerves.

Unwanted pop ups: sorry for the inconvenience

I am very sorry for the inconvenience  caused by unwanted pop ups happening while visiting this blog. I understand that some plugins are responsible for that and I am currently tracking the faulty one. A s consequence of this case, I had to deactivate all plugins thus the ugly look of most posts. Any help will be appreciated 😉

0.56″ 7-Segment Backpack (Part 1)

As far as the development of interactive applications is concerned there always is a need for displaying information in a human readable format.. Let’s start with a quick and dirty review of the available options with Arduino.

Display Usage Pros Cons
One monchrome LED* use on/of state, use blink rate, use morse code ** Cheap Limited information
One RGB LED Same as before except more combinations Pretty cheap Little more wiring
LCD display (16×2) Display 2 lines containing 16 alpha numerical characters Human readable messages, affordable Requirements for wiring and programming***
OLED display (16×2) Display 2 lines containing 16 alpha numerical characters Human readable messages, high contrast, lower power Pricey. Requirements for wiring and programming***
GLCD Display graphics as well as  alpha numerical characters (typically 128 x 64 pixels) Plot and print Costly
Grphic OLED Display graphics as well as  alpha numerical characters (typically 128 x 64 pixels) Plot and print, color version available Up to expensive

* e.g. digital pin 13 LED !

** If you are from the navy

*** Consider buying a backpack which allows serial communication (e.g. I2C) and save pins

And then come the LED displays. I say “then” and not “finally” because LED displays were among the very first types of displays used on electronics appliances, including the now looking ugly and dated alarm-clocks. LED display come in various formats, sizes and price. They can be 7 segment digits for numerical data or 14/16 segments digits for alpha-numerical data.

seven_segments

Also, take care about the wiring as LED digits can be wired with common cathode or common anode.

common_cathodecommon_anode

Driving a LED digits requires quite many ports: for a 7 segments digit require 7 data lines for each segment plus an extra one for the decimal point (marked “dp”, if applicable) and one for the common points (cathode or anode as explained before). One additional data line is necessary for each additional digit. If we take the example of the module which combines 4 digits a total of (7 + 1) + (4 * 1) lines are necessary that’s a lot compared to the available lines from an Arduino board for example.

SKU020620-1SKU020620-2

This problem can be easily solved thanks to dedicated chips which enable the driving of the digits through serial commands (SPI and/or I2C). Adafruit proposes such nice small and affordable solutions under the form or kits:

Adafruit 0.56″ 4-Digit 7-Segment Display w/I2C Backpack – White PID: 1002

1002-00

Quad Alphanumeric Display – White 0.54″ Digits w/ I2C Backpack PID: 2157

2157-03

These displays exist in various colors (Red, Green, Yellow, Blue, Orange)

Here is a simple example of use of the numerical display used for displaying the temperature reading from a TMP04 sensor with the PlainTMP library:

temp_reader

Here is the code to be used in order to achieve this type of display

/*************************************************** 
  This is a library for our I2C LED Backpacks

  Designed specifically to work with the Adafruit LED 7-Segment backpacks 
  ----> http://www.adafruit.com/products/881
  ----> http://www.adafruit.com/products/880
  ----> http://www.adafruit.com/products/879
  ----> http://www.adafruit.com/products/878

  These displays use I2C to communicate, 2 pins are required to 
  interface. There are multiple selectable I2C addresses. For backpacks
  with 2 Address Select pins: 0x70, 0x71, 0x72 or 0x73. For backpacks
  with 3 Address Select pins: 0x70 thru 0x77

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
  
  Modified by Didier Longueville for Arduinoos
  GLP v2 license
 ****************************************************/

#include <Wire.h> // Enable this line if using Arduino Uno, Mega, etc.
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
/* include libraries */
#include <PlainTMP0x.h> /* TMP0x sensors library */

Adafruit_7segment matrix = Adafruit_7segment();
PlainTMP0x TMP; /* Create an instance of the TMP object */

/* Create objects */
/* Change parameters according to hardware configuration */
const uint8_t _pin = PIND7;
volatile uint8_t *_port = &PORTD;
const uint32_t _interval = 5000;
int32_t _now, _lastTime;

void setup() 
{
	/* Initialize display */
	matrix.begin(0x70);
	/* Adjust brightness from 1 to 15 */
	matrix.setBrightness(0x01);
	/* Initialize display prior to first temperature reading */
	matrix.print(99999);
	matrix.writeDisplay();
}

void loop() 
{
	do {
		_now = millis();
	} while ((_now - _lastTime) < _interval);
	_lastTime = _now;
	/* run measurement */
	float temperature = TMP.Temperature(TMP_MOD_TMP04, _port, _pin, TMP_UNI_CELSIUS, 16);
	/* Display temperature */
	matrix.print(temperature);
	matrix.writeDisplay();

}

 

Good readings:

LEDs Are Still Popular (and Improving) after All These Years, by MAXIM DALLAS [Here]

PlainDSP plotter

PlainDSP plotter

or

From figures to pictures

Thanks to a small yet powerful piece of Processing code which plugs immediately with PlainDSP library example sketches (wave plotter and spectrum plotter). More on this application on plaindsp web site

Engine RPM (Part 4)

Part 1, 2, 3, 4, 5

In this version of the arduino stroboscope, the standard micros() function is no longer used. Instead timer 1, an accurate 16 bits counter shall be exclusively used. As a consequence of the disabled timer 0 and timer 2, no interrupts will bother the output signal except the timer 1 interrupts themselves.

Timer 1 settings is extracted from the data acquisition engine from PlainDSP which proved to be very accurate within a wide range of frequencies.

void SetTimer(float rpm) 
/* Set acquisition parameters, full options */
{
	/* Compute frequency */
	float frequency = ((rpm * 16.0) / 60.0);
	/* Disable all interrupts */
	cli();
	/* Disable timers 0 and 2 in order to improve stability */
	TIMSK0 = 0x00; /* Disable timer/counter0 */
	TIMSK2 = 0x00; /* Disable timer/counter2 */
	/* Reset Timer/Counter1 control registers and Interrupt Mask Register */
	TCCR1A = 0x00; 
	TCCR1B = 0x00; 
	TIMSK1 = 0x00; 
	/* Compute clock timer prescaler */
	uint8_t preScalers[] = {0, 3, 6, 8, 10}; /* Log2 of prescalers */	
	uint8_t timerPrescaler = 0;
	uint32_t upperCount;
	do {
		upperCount = uint32_t(F_CPU / (frequency * (1 << preScalers[timerPrescaler]))) - 1 ;
		timerPrescaler += 1;
	} while ((upperCount & 0xFFFF0000) && (timerPrescaler < 5));	
	OCR1A = uint16_t(upperCount);
	TCCR1B |=  (1 << WGM12); /* Set Clear Timer on Compare Match (CTC) Mode (Mode 4) */
	TCCR1B |= timerPrescaler; /* Set timer prescaler */
	TIMSK1 |= (1 << OCIE1B); /* Enable timer1 interrupt  */
	sei(); /* Enable all interrupts */
}

ISR(TIMER1_COMPB_vect)
/* Invoked on completion of counting (Compare mode) */
{
	_counter += 1;
	_counter &= 0x0F;
	/* Flip LED state */
	if (_counter == _onTime) {
		PORTB &= ~_ledPinMask;
	} else if (!_counter) {
		PORTB |= _ledPinMask;
	}
	_synch = 1;
}

Timer 1 provides a stable time base for a sub counter of 4 bits. In other words each flash cycle can be decomposed in 16 basic steps. The reason for this lies in the need for adjusting the phase of the stroboscope. If the rotational speed of the object to monitor is strictly equal to the flash frequency of the arduino stroboscope, chances are that the flash will no spot on the target. You could either move the led in front of the target or leave the LED where it is and adjust the phase until the flash hits the target itself.

Adjusting the phase is pretty simple. It consists in adding an extra count to the secondary counter. In trigonometric words, one more count results in 360/16= +22.5 degrees. If the target is 180° out of phase, 8 clicks on the phase button will be necessary to synchronize the light beam and the target.

Next is code section for the phase adjustment. Note that the counter is updated in a synchronized manner versus the base counter.

	_synch = 0;
	while(!_synch) ;
	if (Button()) {
		_counter += 1;
		_counter &= 0x0F;
		while(Button());
	}

A quick check with the oscilloscope shows a very stable and accurate signal. Ultimately, here comes the whole code

/*

	Accurate stroboscope,
	ATmega328 powered Arduino only
	Copyright (C) 2015 Didier Longueville

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
	
*/

const uint8_t _ledPinMask = ( 1 << PINB5); /* Defaults to digital pin 5 aka the LED pin */
const uint8_t _phaseBtnPinMask = (1 << PINB0); /* Defaults to digital pin 8 */ 
volatile uint8_t _counter = 0;
volatile uint8_t _onTime = 4; /* versus 16 */
volatile uint8_t _synch = 0;

void setup()
{
	InitStrobeLED();
	InitButton();
	SetTimer(4096.0); /* Set strobe frequency */
}

void loop()
{
	_synch = 0;
	while(!_synch) ;
	if (Button()) {
		_counter += 1;
		_counter &= 0x0F;
		while(Button());
	}
}

void SetTimer(float rpm) 
/* Set acquisition parameters, full options */
{
	/* Compute frequency */
	float frequency = ((rpm * 16.0) / 60.0);
	/* Disable all interrupts */
	cli();
	/* Disable timers 0 and 2 in order to improve stability */
	TIMSK0 = 0x00; /* Disable timer/counter0 */
	TIMSK2 = 0x00; /* Disable timer/counter2 */
	/* Reset Timer/Counter1 control registers and Interrupt Mask Register */
	TCCR1A = 0x00; 
	TCCR1B = 0x00; 
	TIMSK1 = 0x00; 
	/* Compute clock timer prescaler */
	uint8_t preScalers[] = {0, 3, 6, 8, 10}; /* Log2 of prescalers */	
	uint8_t timerPrescaler = 0;
	uint32_t upperCount;
	do {
		upperCount = uint32_t(F_CPU / (frequency * (1 << preScalers[timerPrescaler]))) - 1 ;
		timerPrescaler += 1;
	} while ((upperCount & 0xFFFF0000) && (timerPrescaler < 5));	
	OCR1A = uint16_t(upperCount);
	TCCR1B |=  (1 << WGM12); /* Set Clear Timer on Compare Match (CTC) Mode (Mode 4) */
	TCCR1B |= timerPrescaler; /* Set timer prescaler */
	TIMSK1 |= (1 << OCIE1B); /* Enable timer1 interrupt  */
	sei(); /* Enable all interrupts */
}

ISR(TIMER1_COMPB_vect)
/* Invoked on completion of counting (Compare mode) */
{
	_counter += 1;
	_counter &= 0x0F;
	/* Flip LED state */
	if (_counter == _onTime) {
		PORTB &= ~_ledPinMask;
	} else if (!_counter) {
		PORTB |= _ledPinMask;
	}
	_synch = 1;
}

void InitStrobeLED(void) 
{
	/* Make the pin an output pin */
	DDRB |= _ledPinMask;
	/* Turn the pin low */
	PORTB &= ~_ledPinMask;
}

void InitButton(void) 
{
	/* Make the pin an input pin */
	DDRB |= _phaseBtnPinMask;
	/* Bias pin */
	PORTB |= _phaseBtnPinMask;
}

uint8_t Button(void) 
{
	uint8_t res = 0;
	if ((~PINB & _phaseBtnPinMask) == _phaseBtnPinMask) {
		res = 1;
	}
	return(res);
}

 

 

 

Engine RPM (Part 3)

Part 1, 2, 3, 4, 5

Previous posts on measuring engine RPM are featuring electronic interfaces with devices that sense the engine rotation. It is sometimes impossible to connect such sensor so that other techniques must be used in order to check and adjust an engine RPM. Today, we will use a contact-less technique featuring a light beam directed toward a reflecting target attached to the rotating device. The proposed application features the stroboscopic effect, well known by those who like to go dancing in clubs. A quick search on the net will give you plenty of information related to the principle of operation and examples of use of stroboscopes. In simple words, a flash light directed toward a moving object will decompose the motion of this object in successive snapshots. If this object has a periodical motion which is synchronized with the light beam, the target will look immobile. The least change in synchronization will result in a slow motion of the spotted target clockwise or counter-clockwise.

Building a stroboscope with Arduino is quite simple as we only need a bright LED and few lines of code. It is also a good programming exercise for improving the accuracy and usability of the measurement device.

In its simplest version, the stroboscope shall be able to measure speeds with an accuracy better than 2% between 1 and 6 000 rpm which degrades down to 4% at higher frequencies. The sketch is an extrapolation of the most famous “blink” sketch using microseconds as time base. Next lines of pseudo code illustrate a full flashing cycle:

  • Turn light ON
  • Wait for next change in light state
  • Turn light OFF
  • Wait for next change in light state

And here is the full sketch:

int32_t _interval, _onTime, _offTime;
const int16_t _onTimeRatio = 10; // %
int32_t _now, _lastTime;
const uint8_t _ledPinMask = (1 << PINB5);


void setup()
{
	InitLED();
	SetTimer(4100.0);
}

void loop()
{
	PORTB |= _ledPinMask;
	do {
		_now = micros();  
	} while ((_now - _lastTime) < _onTime);
	_lastTime = _now;

	PORTB &= ~_ledPinMask;
	do {
		_now = micros();  
	} while ((_now - _lastTime) < _offTime);
	_lastTime = _now;	
}

void SetTimer(float rpm)
{
	_interval = int32_t(1000000.0 * 60.0 / rpm); // in micros	
	_onTime = ((_interval * _onTimeRatio) / 100);
	if (_onTime < 1) { /* prevent null time */
		_onTime = 1;
	}
	_offTime = (_interval - _onTime);
	_lastTime = micros();
}

void InitLED(void) 
{
	/* Make the pin an output pin */
	DDRB |= _ledPinMask;
}

 

Pretty simple. The hardware section is even simpler as it consists in a white bright led and its biasing resistor.

20150620_174840

Checking the signal on a scope gives us some information about the signal accuracy and stability.

NewFile47

Do not take the figures as absolute values as in fact they are captured from an (slightly) unstable signal. These are extreme results and the instability is mainly due to the handling of the micros() function and to the activity of both timer 1 and timer 2 under standard operating conditions. Although this version will suffice in most cases (under 6000 rpm, so as to say 100 Hz) , an advanced version of the arduino stroboscope shall be considered in the next posts.

Next is a picture illustrating the use of the arduino based stroboscope. A simple piece of white adhesive tape sticks to the blades of a fan. This is the target taht the pulsed light beam will try to hit in a synchronous manner:

20150620_194852

And here is a short video illustrating the stroboscopic effect:

From the video, you can see that the spot light “disappears”. In fact, the stroboscope looses its synchronization due to the slight slips of fan speed. If the spot light looks like it goes clockwise, the actual speed is slower than expected. If the spot light looks like it goes counter-clockwise, the actual speed is faster than expected. In next versions, we will add some extra features for adjusting the proper synchronization…

Next post on same subject