0% found this document useful (0 votes)
4 views28 pages

B57as L05

This lecture covers advanced topics in computing for engineers, including the use of the #define directive for constant values, Arduino timers, bit shifting, lookup tables, and object-oriented programming (OOP). It explains how to optimize RAM usage with constants, demonstrates timer pulse width settings, and introduces the concept of lookup tables for efficient calculations. Additionally, it provides guidance on writing libraries in Arduino, including creating header and implementation files for classes.

Uploaded by

grokking Stuff
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views28 pages

B57as L05

This lecture covers advanced topics in computing for engineers, including the use of the #define directive for constant values, Arduino timers, bit shifting, lookup tables, and object-oriented programming (OOP). It explains how to optimize RAM usage with constants, demonstrates timer pulse width settings, and introduces the concept of lookup tables for efficient calculations. Additionally, it provides guidance on writing libraries in Arduino, including creating header and implementation files for classes.

Uploaded by

grokking Stuff
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 28

Computing for Engineers

B57AS
Lecture 05
This week:
• The #define Directive
• Arduino Timers – more advanced
• Bit shift
• Lookup tables
• Object Oriented Programming (OOP)
# define
• For constant values like pin assignments that do not change during
the running of a sketch, there is an alternative to using a variable.
• #define allows you to associate a value with a name.
• Everywhere #define appears in your sketch, the value will be
substituted before the sketch is compiled.

#define kLedPin 13

• The #define directive does not use an “=” between the name and
the value.
• It does not even need a ; on the end.
• This is because it is not actually part of the C language itself; but is
called a pre-compiler directive that is run before compilation.
Using #define and const Instead of Integers

• To minimise RAM usage tell the compiler that


the value is a constant and can be optimised
// a variable, but this wastes RAM
int ledPin = 13;

// a const does not use RAM


const int ledPin = 13;

// using a #define the preprocessor


// replaces ledPin with 13
#define ledPin 13
Stepper Motor Example
#include <Stepper.h>
#define STEPS 200
What’s a class?
// create an instance of stepper class
Stepper stepper(STEPS, 8, 9, 10, 11); We’ll get to that later…
int counter = 0; // store steps number since last change of direction
int multiplier = 1; // a basic multiplier

void setup() {
stepper.setSpeed(30); // set the speed at 30 RPM
}

void loop() {
// move randomly from at least 1 step
stepper.step(multiplier);
// counting how many steps already moved
// then if we reach a whole turn, reset counter and go backward
if (counter < STEPS) counter++ ;
else {
counter = 0;
multiplier *= -1;
}
}
Setting Timer Pulse Width and Duration
/*
This sketch generates pulses within the frequency of 1 MHz using Timer1
PWM on pin 9.
*/

#include <TimerOne.h>

#define pwmRegister OCR1A // the logical pin, can be set to OCR1B


const int outPin = 9; // the physical pin

long period = 10000; // the period in microseconds


long pulseWidth = 1000; // width of a pulse in microseconds
int prescale[] = {0,1,8,64,256,1024}; // the range of prescale values

void setup() {

Serial.begin(9600);
pinMode(outPin, OUTPUT);
Timer1.initialize(period); // initialize timer1, 1000 microseconds
setPulseWidth(pulseWidth); // call our function

void loop() { }
Setting Timer Pulse Width and Duration
bool setPulseWidth(long microseconds)
{
bool ret = false;
int prescaleValue = prescale[Timer1.clockSelectBits];
// calculate time per counter tick in nanoseconds
long precision = (F_CPU / 128000) * prescaleValue ;
period = precision * ICR1 / 1000; // period in microseconds
if( microseconds < period)
{
int duty = map(microseconds, 0,period, 0,1024);
if( duty < 1)
duty = 1;
if(microseconds > 0 && duty < RESOLUTION)
{
Timer1.pwm(outPin, duty);
ret = true;
}
}
return ret;
}
Arduino Timers
• The Arduino Uno has 3 timers:
Timer0, Timer1 and Timer2.
• Timer0 is already set up to
generate a millisecond interrupt to
update the millisecond counter
reported by millis(). Timer0 has
no PWM.
• Timer1 ia a 16-bit timer (it counts
from 0 to 65,535). It’s the same
timer used by analogWrite to
controls pins 9 and 10. Timer1 has
two PWM outputs.
• Timer2 is a 8-bit timer with one
PWM output.
Bit shift – It’s all about performance
• Bitwise operators are specific operators for
bits.
• Bitwise operations are primitive actions
directly supported by the processor.
• Especially with embedded systems, using
bitwise operations can dramatically improve
performance.
• There are four operators and two bit shift
operators.
Boolean Logic & Logic Gates
Digital Logic Gate Truth Table
AND, OR, XOR, and NOT operators
AND, OR, XOR, and NOT operators
/*
* bits sketch demonstrates bitwise operators
*/
void setup() {
Serial.begin(9600);
}
void loop(){
Serial.print("3 & 1 equals "); // bitwise And 3 and 1
Serial.print(3 & 1); // print the result
Serial.print(" decimal, or in binary: ");
Serial.println(3 & 1 , BIN); // print the binary representation of the result
Serial.print("3 | 1 equals "); // bitwise Or 3 and 1
Serial.print(3 | 1 );
Serial.print(" decimal, or in binary: ");
Serial.println(3 | 1 , BIN); // print the binary representation of the result
Serial.print("3 ^ 1 equals "); // bitwise exclusive or 3 and 1
Serial.print(3 ^ 1);
Serial.print(" decimal, or in binary: ");
Serial.println(3 ^ 1 , BIN); // print the binary representation of the result

byte byteVal = 1;
int intVal = 1;
byteVal = ~byteVal; // do the bitwise negate
intVal = ~intVal;

Serial.print("~byteVal (1) equals "); // bitwise negate an 8 bit value


Serial.println(byteVal, BIN); // print the binary representation of the result
Serial.print("~intVal (1) equals "); // bitwise negate a 16 bit value
Serial.println(intVal, BIN); // print the binary representation of the result
delay(5000);
}
Lookup Tables (LUT)
• LUTs are one of the most powerful tricks in the
programming universe.
• They are arrays containing precalculated values and thus
replace heavy runtime calculations by a simpler array index
operation.
• LUTs can be precalculated and stored in a static program's
storage memory, or calculated at the program's
initialization phase (or prefetched lookup tables).
• Some functions are particularly expensive, considering the
CPU work. Trigonometric functions are one such function
that can have bad consequences as the storage space and
memory are limited in embedded systems. They are
typically prefetched in code.
Lookup Tables (LUT) Example
• Suppose we wish to create create a cosine
Look Up Table (LUT). We need to create a
small precision system.
• When calling cos(x) we can have all values of x
that we want.
• Let’s create a precalculated cosine LUT
Lookup Tables (LUT) - Example
// array of type float with special size
float cosLUT[(int) (360.0 * 1 / 0.5)];

const float DEG2RAD = 180 / PI;


const float cosinePrecision = 0.5;
const int cosinePeriod = (int) (360.0 * 1 / cosinePrecision);

void setup()

initCosineLUT(); // performs the precalculation

void loop() {
// nothing for now!
}

void initCosineLUT() {

for (int i = 0; i < cosinePeriod; i++)


{
cosLUT[i] = (float) cos(i * DEG2RAD * cosinePrecision);
}
}
Lookup Tables (LUT) - Example
To retrieve our values by accessing our LUT through another function, shown
as follows:
float myCosLut( float angle ) {

return cosLUT[ (int) (angle * i / cosinePrecision) % cosinePeriod;

angle * i / cosinePrecision gives us the angle considering the


given precision of our LUT.

We apply a modulo operation considering the cosinePeriod value to


wrap values of higher angles to the limit of our LUT, and we have our
index.

We directly return the array value corresponding to our index.


Object Oriented Programming
• The Arduino Language is a variant of C++ which
supports Object Oriented Programming (OOP).
• The main goal of OOP is to increase the encapsulation
of programs.
• Encapsulation keeps relevant things together,
something that makes C++ very suitable for writing
libraries.
• Using the OOP features of the language, for example,
we can gather together all of the state variables and
functionality for a blinking LED into a C++ class.
Classes and Methods
• OOP uses a concept called classes to aid encapsulation.
• Generally, a class is like a section of a program that includes both
variables—called member variables—and methods, which are like
functions but apply to the class.
• These functions can either be public, in which case the methods
and functions may be used by other classes, or private, in which
case the methods can be called only by other methods within the
same class.
• In C++, you tend to use more than one file, whereas an Arduino
sketch is contained in a single file.
• There are generally two files for every class: A header file, which has
the extension .h, and the implementation file (aka source file),
which has the extension .cpp.
Writing libraries
• Start by creating a folder to contain all the library files. You should
create this folder inside the libraries folder of your Arduino
documents folder.
• In Windows, your libraries folder will be in My Documents/Arduino.
• On the Mac, you will find it in your home directory,
Documents/Arduino/
• On Linux, it will be in the sketchbook directory of your home
directory.
• If there is no libraries folder in your Arduino, then create one.
• This libraries folder is where any libraries you write yourself, or any
“unofficial” contributed libraries, must be installed.
• Let’s create our own library – make a folder and call it Flasher
The Header file - Example
// An example of a header file: Flasher.h
class Flasher {

public: // all functions and variables here are accessible

// constructor – a member function of a class which


// initialises objects of a class
Flasher(int pin, int duration);

// method that takes a single argument of


// the number of times to flash
void flash(int times);

private: // variable definitions that are only accessible


// within this class

// Every time an object of class Flasher is created, it will


// have these two variables. This enables it to remember the
// pin and duration when a new Flasher object is created.
int _pin; // to remember a pin number
int _duration; // to remember a duration for flashing

}; // note the syntax requires a pair of {} and ending the semi-colon


The Header file - Example
// Put these two lines at the top of your file.
// (Use a suitable name, usually based on the file name.)
#ifndef _FLASHER_H // name of our header
#define _FLASHER_H // note the syntax use of underscore

// To cover for compatibility on older versions of Arduino


#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h” // newer boards use this
#else
#include "WProgram.h” // up to v1.0 this was the wiring header
#endif

// Place your main header code here.


class Flasher {

// statements…

}; // remember this semi-colon!

// Put this line at the end of your file.


#endif // _FLASHER_H
The Implementation or Source file - Example

• The header file has just defined what the class looks like.
• You now need a separate file that actually does the work. This is called the
implementation file and has the extension .cpp.
#include “Flasher.h”

Flasher::Flasher(int pin, int duration) // the prefix :: indicates that the methods
{ // belong to the Flasher class
// these initialise the constructor
pinMode(pin, OUTPUT); // The constructor method (Flasher) just
_pin = pin; // assigns each of its parameters to the
_duration = duration / 2; // appropriate private member variable

void Flasher::Flasher(int times) // The flash member function actually carries out
{ // the business of flashing
for(int i = 0; i < times; i++) { // loops for the appropriate number of
digitalWrite(_pin, HIGH); // times, turning the LED on and off
delay(duration); // for the appropriate delay
digitalWrite(_pin, LOW);
delay(duration);
}
}
Completing Your Library
• Define the keywords used in the library so that the Arduino
IDE can show them in the appropriate colour when users
are editing code.
• To define the keywords, you have to create a file called
keywords.txt, which goes into the Flasher directory.
• This file contains just the two following lines:
– Flasher KEYWORD1
– Flash KEYWORD2
• Class names should be a KEYWORD1 and methods should
be KEYWORD2.
Completing Your Library
• Restart the Arduino IDE, from the
Arduino IDE’s menu, select File and then
New to create a new sketch window.
• Then from the Menu, select Sketch and
the Import Library option or Add Library
option (depending on the version of the
IDE).
• The libraries above the line in the
submenu are the official libraries; below
this line are the “unofficial” contributed
libraries.
• If all has gone well, you should see
Flasher in the list.
• If Flasher is not in the list, it is very likely
that the Flasher folder is not in the
libraries folder of your sketches folder, so
go back and check.
Using Flasher.h
#include “Flasher.h”

const int kledPin = 13;


int slowDuration = 300;
int fastDuration = 100;

// instantiate a slow and fast Flasher object


Flasher slowFlasher(kledPin, slowDuration);
Flasher fastFlasher(kledPin, fastDuration);

void setup() {
// not needed in this case as the set up is done when we
// initialised the Flasher object
}

void loop()
{
slowFlasher.flash(5); // call Flasher member function
delay(1000);
fastFlasher.flash(10);
delay(2000);
}
Conclusion
• There is more to C++ and to writing libraries,
but this should get you started.
• It should also be sufficient for most of what
you are likely to do with an Arduino.
• Arduinos are small devices and the temptation
is often to overengineer solutions that could
otherwise be very simple and straightforward.
Assessment week
• When - Week 9
• Prize: 25%

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy