distributed*real.time*control systems - ulisboa · pdf filebasic*digital*input*–...
TRANSCRIPT
Bibliography
• ATMEGA 328 Datasheet.• arduino.cc• Book: – “Arduino Cookbook”, 2nd Ed.– Michael Margolis– O’Reilly, 2012
2
Basic Digital Output -‐ Driving LED’s• Caution!
– Source/Sink limits– 40mA at 5Vcc
• Howmuch current passes through the LED’s ?
8
const int led1 = 7; // LED1 connected to digital pin 7const int led2 = 8; // LED2 connected to digital pin 8const int rate = 500; // Delay in ms to commute ledsint counter = 0; // loop counter
void setup(){// enable output on the led1 pinpinMode(led1, OUTPUT); // enable output on the led2 pinpinMode(led2, OUTPUT);// initialize serial comms to hostSerial.begin(9600); }
void loop(){Serial.println(++counter); // print rate to serial monitordigitalWrite(led1, HIGH); // set the LED1 ondigitalWrite(led2, HIGH); // set the LED2 offdelay(rate); // wait duration digitalWrite(led1, LOW); // set the LED1 offdigitalWrite(led2, LOW); // set the LED2 ondelay(rate);}
Basic Digital Input – Reading Switches
• Must use pull-‐ups.
9
int inputPins[] = {2,3,4,5}; // create an array of switch inputsint ledPins[] = {10,11,12,13}; // create array of output LEDs
void setup() {for(int index = 0; index < 4; index++) {pinMode(ledPins[index], OUTPUT); // LED as outputpinMode(inputPins[index], INPUT); // pushbutton as input digitalWrite(inputPins[index],HIGH); // enable pull-‐ups
}}
void loop() {for(int index = 0; index < 4; index++) {int val = digitalRead(inputPins[index]); // read input value// check if the switch is pressed if (val == LOW) {// turn LED on if switch is presseddigitalWrite(ledPins[index], HIGH);
}else {// turn LED offdigitalWrite(ledPins[index], LOW);
}}
}
Digital Inputs – Switch Debouncing
10
// debounce returns true if the switch in the given pin// is closed and stable
boolean debounce(int pin){boolean state;boolean previousState;// store switch statepreviousState = digitalRead(pin); for(int counter=0; counter < debounceDelay; counter++) {// wait for 1 milliseconddelay(1); // read the pinstate = digitalRead(pin); if( state != previousState) {// reset the counter if the state changescounter = 0; // and save the current statepreviousState = state;
}}// here when the switch state has been stable // longer than the debounce periodreturn state;
}
Reading Incremental Encoders• Incremental Rotary Encoders
have two quadrature channels.
• Direction of rotation can bemeasured by detecting theraising/fallingedge of onechannel and checking the value ofthe other.
11
Reading Incremental Encoders
• Polling based solution
12
const int encPinA = 4;const int encPinB = 2;const int encSPR=16; //Steps Per Revolution : Depends on HWint angle = 0; int val; int encPos = 0;boolean encALast = LOW; // remembers the previous statevoid setup() {pinMode(encPinA, INPUT);pinMode(encPinB, INPUT);digitalWrite(encPinA, HIGH); //enable pull upsdigitalWrite(encPinB, HIGH);Serial.begin (9600);
}void loop() {boolean encA = digitalRead(encPinA);if ((encALast == HIGH) && (encA == LOW)) {(digitalRead(encPinB) == LOW ? encPos-‐-‐ : encPos++);angle=(encPos%encSPR)*360/encSPR;Serial.print (encoderPos);Serial.print (" ");Serial.println (angle);
}encoderALast = encoderA;
}
Reading Incremental Encoders• Interrupt Based Solution
• An Interrupt Service Routine (ISR) can associated to a falling edge on encoder channelA.
• Notes:
– Only one ISR can run at a time.– ISR cannot have paramenters nor return values.– Variables that are changed in ISRs must be
marked volatile.– Code in the ISR should be as fast as possible.– Serial data received while in the ISR may be lost. – In Arduino UNO you can attach interrupts to Pins
2 and 3.– Function millis() do not increment while in an
ISR.– Function delay() does not work inside and ISR.– Function delayMicroseconds() does not use
conters so it works.
13
const int encoderPinA = 2;const int encoderPinB = 4;int Pos, oldPos;volatile int encoderPos = 0; //maychange at any time
void doEncoder() { //ISR for FALLING edge on channel Aif (digitalRead(encoderPinA) == digitalRead(encoderPinB))encoderPos++; // count up if both encoder pins are the same
elseencoderPos-‐-‐; // count down if pins are different
}void setup() {pinMode(encoderPinA, INPUT);pinMode(encoderPinB, INPUT);digitalWrite(encoderPinA, HIGH);digitalWrite(encoderPinB, HIGH); Serial.begin(9600);attachInterrupt( digitalPinToInterrupt( encoderPinA ),
doEncoder, FALLING); }void loop() {noInterrupts(); //disable interruptsPos = encoderPos; //critical sectioninterrupts(); //enable interruptsif(Pos != oldPos) {Serial.println(Pos,DEC);oldPos = Pos; }
delay(1000);}
Reading Pulse Width Signal• Some sensors communicate
output via Pulse Width Duration.
• Arduino has a function (pulseIn()) to read pulse durations.
• Example: Parallax PING))) Sonar.
14
const int pingPin = 5;void setup() {Serial.begin(9600);
}void loop() {int cm = ping(pingPin) ;Serial.println(cm);delay(500);
}int ping(int pingPin) {long duration, cm;// The PING))) is triggered by a HIGH pulse of 2 or more usec.pinMode(pingPin, OUTPUT);digitalWrite(pingPin, LOW); delayMicroseconds(2); digitalWrite(pingPin, HIGH); delayMicroseconds(5);digitalWrite(pingPin, LOW); pinMode(pingPin, INPUT);duration = pulseIn(pingPin, HIGH);// speed of sound 29 usec per centimeter.cm = duration/29/2;return cm ;
}
Analog Input• ARDUINO UNO ATMEL 328 ADC
Characteristics
– 10-‐bit Resolution (0x000 – 0x3FF)
– 0.5 LSB Integral Non-‐linearity
– ± 2 LSB Absolute Accuracy
– 13 -‐ 260 μs Conversion Time
– Up to 76.9 kSPS (Up to 15 kSPS atMaximum Resolution)
– 6 Multiplexed Single Ended Input Channels
– Temperature Sensor Input Channel
– 0 -‐ VCC ADC Input Voltage Range
– Selectable 1.1V ADC ReferenceVoltage
– Voltage Range Externally Selectable
• Free Running or Single Conversion Mode
• Interrupt on ADC Conversion Complete
• Sleep Mode Noise Canceler
• The ADC is optimized for analog signals with an output impedance of approximately 10 kΩ or less.
15
Analog Input Example• Light depedent LED
blinking.• Analog Read returns
values between 0 (min) and 1024 (max).
16
const int ledPin = 13; // LED connected to digital pin 13const int sensorPin = 0; // connect sensor to analog input 0
// the next two lines set the min and max delay between blinksconst int minDuration = 100; // minimumwait betweenblinksconst int maxDuration= 1000; // maximum wait between blinks
void setup(){pinMode(ledPin, OUTPUT); // enable output on the led pinSerial.begin(9600); // initialize Serial}
void loop(){int rate = analogRead(sensorPin); // read the analog input//scales the blink rate between the min and max valuesrate = map(rate, 200, 800, minDuration, maxDuration); rate = constrain(rate, minDuration,maxDuration); // saturateSerial.println(rate); // print rate to serial monitordigitalWrite(ledPin, HIGH); // set the LED ondelay(rate); // wait duration dependent on light leveldigitalWrite(ledPin, LOW); // set the LED offdelay(rate);}
Measuring Voltages
• If voltages are in therange [0 … 5]V, they can be measured directly.
• Otherwise we needvoltage dividers.
• Question: How to measure negative voltages ?
17
Analog Output via PWM• AnalogOutput can be
emulated via Pulse WidthModulation.
• Arduino functionanalogWrite(pin, value) generates a PWM signal withfrequency~500Hz and dutycycle proportional to value.
• 0 <= value <= 255
• pin = 3,5,6,9,10,11
18
Modulate LED Brightness via PWM
• Fade LED brightness in and out.
19
const int firstLed= 3; const int secondLed = 5;const int thirdLed = 6;
int brightness = 0;int increment = 1;
void setup() { // pins driven by analogWrite do not need to be declared as outputs}
void loop() {if(brightness > 255) { increment = -‐1; // count down after reaching 255
}else if(brightness < 1) {increment = 1; // count up after dropping back down to 0
}brightness = brightness + increment; // write the brightness value to the LEDsanalogWrite(firstLed, brightness);analogWrite(secondLed, brightness);analogWrite(thirdLed, brightness );delay(10); // mean 2.55 secs to fade up or down
}
Generating Frequencies
• Example: Playing Tones
20
const int speakerPin = 9; // connect speaker to pin 9const int pitchPin = 0; // frequency of the toneconst int durationPin = 1; // duration of the tone
void setup(){}
void loop(){int sensor0Reading = analogRead(pitchPin); // frequencyint sensor1Reading = analogRead(durationPin); // duration// map the analog readings to a meaningful rangeint frequency = map(sensor0Reading, 0, 1023, 100,5000);int duration = map(sensor1Reading, 0, 1023, 100,1000); tone(speakerPin, frequency, duration); // play the tonedelay(duration); //wait for the tone to finish
}
Driving High Power Devices• Arduino PINs can
source/sink 40 mA atmost.
• To drive more than 40mA:
– Use amplification(transistors, opamps, etc). Check datasheets.
– Use multiple pins (limitedto 400mA if USB power).
21
Drive a DC Motor in a Single Direction
• When the motor does not need to reverse direction, a simple PWM drive is as follows:
22
Drive a DC motor in both directions• To drive a DC motor in both
directions we need what istypically called a H-‐Bridge.
• Solutions:
– make a H-‐bridge withdiscrete components.
– Buy an IC with H-‐bridges.
– Buy a motor shield for arduino.
23
Drive a DC motor in both directions
• Example with the L239 H-‐Bridge.
24
const int enPin = 5; // H-‐Bridge enable pinconst int in1Pin = 7; // H-‐Bridge input pinsconst int in2Pin = 4;void setup() {Serial.begin(9600);pinMode(in1Pin, OUTPUT); pinMode(in2Pin, OUTPUT);Serial.println("Speed (0-‐9) or + -‐ to set direction");
}void loop() {if ( Serial.available()) {char ch = Serial.read();if(isDigit(ch)) // is ch a number? {int speed = map(ch, '0', '9', 0, 255);analogWrite(enPin, speed);
}else if (ch == '+') { //Rotate CWdigitalWrite(in1Pin,LOW); digitalWrite(in2Pin,HIGH);
}else if (ch == '-‐') { //Rotate CCWdigitalWrite(in1Pin,HIGH); digitalWrite(in2Pin,LOW);
}else {Serial.print("Unexpected character "); Serial.println(ch);
}}
}
Hobbyist Servo Motors• HobbyistServo Motors use a
potentiometer attached to a DC motor shaft to performposition control.
• The position reference iscommanded byPulse PositionModulation PPM and is notthe same as the analogWrite() PWM signal.
• One can use the Servo libraryto implement the PPM signals.
25
Drive a Hobby Servo• External powermay be
required. Do not forget to connect the Grounds.
• The Servo libraryuses Timer 1, thus disables PWM on pins 9 and 10.
26
#include <Servo.h>
Servo myservo; // create servo object to control a servoint angle = 0; // variable to store the servo position
void setup() {myservo.attach(9,1000,2000); //Servo on pin 9. //Minimal position corresponds to 1000microsec. //Maximal position corresponds to 2000microsec.//These values may need to be adjusted,// depending on the servo model.
}
void loop(){for(angle = 0; angle < 180; angle += 1) { myservo.write(angle); delay(20);
}for(angle = 180; angle >= 1; angle -‐= 1) {myservo.write(angle); delay(20);
}}
Devices with Different Voltage Levels• Do not connect the ARDUINO to
devices with other voltage levels. Thismay damage the I/O ports.
• One way to prevent damage is to use opto-‐couplers.
• Example: control a TRS camerashutter.
27
//TAKE 20 PICTURES AND EXITint focus = 4; //optocoupler attached to focusint shutter = 3; //optocoupler attached to shutterlong exposure = 250; //exposure time in millisecondslong interval = 10000; //time between shots, in millisecondsvoid setup() {pinMode(focus, OUTPUT);pinMode(shutter, OUTPUT);for (int i=0; i<20; i++) //camera will take 20 pictures {takePicture(exposure); //takes picturedelay(interval); //wait to take the next picture
}}void loop() { //NO LOOP}void takePicture(long exposureTime){int wakeup = 10; //camera take time to wake up and focus//adjust this to suit your cameradigitalWrite(focus, HIGH); //wake the camera and focusdelay(wakeup); //wait for it to wake up and focusdigitalWrite(shutter, HIGH); //open the shutterdelay(exposureTime); //wait for the exposure timedigitalWrite(shutter, LOW); //release shutterdigitalWrite(focus, LOW); //release the focus
}