fix(xod-client-electron): bundle popular Arduino libraries into desktop IDE

...so that nodes can #include LiquidCrystal and Servo
This commit is contained in:
Victor Nakoryakov
2017-08-08 17:52:17 +03:00
parent 93bb437104
commit dbd3d6be8d
36 changed files with 3241 additions and 11 deletions

View File

@@ -11,20 +11,45 @@ import * as Utils from './utils';
//
// =============================================================================
export const composeCommand = (sketchFilePath, fqbn, packagesDir, buildDir, builderToolDir) => {
export const composeCommand = (
sketchFilePath,
fqbn,
packagesDir,
librariesDir,
buildDir,
builderToolDir
) => {
const builderExecFileName = (Utils.isWindows) ? 'arduino-builder.exe' : 'arduino-builder';
const builderExec = path.join(builderToolDir, builderExecFileName);
const builderHardware = path.join(builderToolDir, 'hardware');
const builderTools = path.join(builderToolDir, 'tools');
return `"${builderExec}" -hardware="${builderHardware}" -hardware="${packagesDir}" -tools="${builderTools}" -tools="${packagesDir}" -fqbn="${fqbn}" -build-path="${buildDir}" "${sketchFilePath}"`;
return [
`"${builderExec}"`,
`-hardware="${builderHardware}"`,
`-hardware="${packagesDir}"`,
`-libraries="${librariesDir}"`,
`-tools="${builderTools}"`,
`-tools="${packagesDir}"`,
`-fqbn="${fqbn}"`,
`-build-path="${buildDir}"`,
`"${sketchFilePath}"`,
].join(' ');
};
// :: Path -> FQBN -> Path -> Path -> PortName -> Promise { exitCode, stdout, stderr } Error
// :: Path -> FQBN -> Path -> Path -> Path -> PortName -> Promise { exitCode, stdout, stderr } Error
export const build = R.curry(
(sketchFilePath, fqbn, packagesDir, buildDir, builderToolDir) => {
const cmd = composeCommand(sketchFilePath, fqbn, packagesDir, buildDir, builderToolDir);
(sketchFilePath, fqbn, packagesDir, librariesDir, buildDir, builderToolDir) => {
const cmd = composeCommand(
sketchFilePath,
fqbn,
packagesDir,
librariesDir,
buildDir,
builderToolDir
);
return fse.ensureDir(buildDir)
.then(() => cpp.exec(cmd))
.then(Utils.normalizeChildProcessResult);

View File

@@ -137,10 +137,10 @@ export const upload = R.curry(
}
);
// :: Path -> FQBN -> Path -> Path -> PortName -> Promise { exitCode, stdout, stderr } Error
// :: Path -> FQBN -> Path -> Path -> Path -> PortName -> Promise { exitCode, stdout, stderr } Error
export const buildAndUpload = R.curry(
(sketchFilePath, fqbn, packagesDir, buildDir, portName, builderToolDir) =>
build(sketchFilePath, fqbn, packagesDir, buildDir, builderToolDir)
(sketchFilePath, fqbn, packagesDir, librariesDir, buildDir, portName, builderToolDir) =>
build(sketchFilePath, fqbn, packagesDir, librariesDir, buildDir, builderToolDir)
.then((res) => {
if (res.exitCode !== 0) {
return Promise.reject(Object.assign(new Error(res.stderr), res));

View File

@@ -9,6 +9,7 @@ describe('Builder', () => {
it('composeCommand() returns correct command', () => {
const sketch = path.normalize('/tmp/test.cpp');
const packagesDir = path.normalize('/xod/packages/');
const librariesDir = path.normalize('/xod/libraries/');
const artifacts = path.normalize('/xod/artifacts/');
const builderDir = path.normalize('/xod/arduino-builder/');
@@ -16,6 +17,7 @@ describe('Builder', () => {
sketch,
'arduino:avr:uno',
packagesDir,
librariesDir,
artifacts,
builderDir
);
@@ -24,6 +26,6 @@ describe('Builder', () => {
const hardwareA = path.normalize('/xod/arduino-builder/hardware');
const toolsA = path.normalize('/xod/arduino-builder/tools');
assert.strictEqual(cmd, `"${execCmd}" -hardware="${hardwareA}" -hardware="${packagesDir}" -tools="${toolsA}" -tools="${packagesDir}" -fqbn="arduino:avr:uno" -build-path="${artifacts}" "${sketch}"`);
assert.strictEqual(cmd, `"${execCmd}" -hardware="${hardwareA}" -hardware="${packagesDir}" -libraries="${librariesDir}" -tools="${toolsA}" -tools="${packagesDir}" -fqbn="arduino:avr:uno" -build-path="${artifacts}" "${sketch}"`);
});
});

View File

@@ -0,0 +1,25 @@
= Liquid Crystal Library for Arduino =
This library allows an Arduino board to control LiquidCrystal displays (LCDs) based on the Hitachi HD44780 (or a compatible) chipset, which is found on most text-based LCDs.
For more information about this library please visit us at
http://www.arduino.cc/en/Reference/LiquidCrystal
== License ==
Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved.
Copyright (c) 2010 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

View File

@@ -0,0 +1,74 @@
/*
LiquidCrystal Library - Autoscroll
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch demonstrates the use of the autoscroll()
and noAutoscroll() functions to make new text scroll or not.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalAutoscroll
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
}
void loop() {
// set the cursor to (0,0):
lcd.setCursor(0, 0);
// print from 0 to 9:
for (int thisChar = 0; thisChar < 10; thisChar++) {
lcd.print(thisChar);
delay(500);
}
// set the cursor to (16,1):
lcd.setCursor(16, 1);
// set the display to automatically scroll:
lcd.autoscroll();
// print from 0 to 9:
for (int thisChar = 0; thisChar < 10; thisChar++) {
lcd.print(thisChar);
delay(500);
}
// turn off automatic scrolling
lcd.noAutoscroll();
// clear screen for the next loop:
lcd.clear();
}

View File

@@ -0,0 +1,61 @@
/*
LiquidCrystal Library - Blink
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch prints "Hello World!" to the LCD and makes the
cursor block blink.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalBlink
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("hello, world!");
}
void loop() {
// Turn off the blinking cursor:
lcd.noBlink();
delay(3000);
// Turn on the blinking cursor:
lcd.blink();
delay(3000);
}

View File

@@ -0,0 +1,61 @@
/*
LiquidCrystal Library - Cursor
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch prints "Hello World!" to the LCD and
uses the cursor() and noCursor() methods to turn
on and off the cursor.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalCursor
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("hello, world!");
}
void loop() {
// Turn off the cursor:
lcd.noCursor();
delay(500);
// Turn on the cursor:
lcd.cursor();
delay(500);
}

View File

@@ -0,0 +1,140 @@
/*
LiquidCrystal Library - Custom Characters
Demonstrates how to add custom characters on an LCD display.
The LiquidCrystal library works with all LCD displays that are
compatible with the Hitachi HD44780 driver. There are many of
them out there, and you can usually tell them by the 16-pin interface.
This sketch prints "I <heart> Arduino!" and a little dancing man
to the LCD.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K potentiometer:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
* 10K poterntiometer on pin A0
created 21 Mar 2011
by Tom Igoe
modified 11 Nov 2013
by Scott Fitzgerald
Based on Adafruit's example at
https://github.com/adafruit/SPI_VFD/blob/master/examples/createChar/createChar.pde
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystal
Also useful:
http://icontexto.com/charactercreator/
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
// make some custom characters:
byte heart[8] = {
0b00000,
0b01010,
0b11111,
0b11111,
0b11111,
0b01110,
0b00100,
0b00000
};
byte smiley[8] = {
0b00000,
0b00000,
0b01010,
0b00000,
0b00000,
0b10001,
0b01110,
0b00000
};
byte frownie[8] = {
0b00000,
0b00000,
0b01010,
0b00000,
0b00000,
0b00000,
0b01110,
0b10001
};
byte armsDown[8] = {
0b00100,
0b01010,
0b00100,
0b00100,
0b01110,
0b10101,
0b00100,
0b01010
};
byte armsUp[8] = {
0b00100,
0b01010,
0b00100,
0b10101,
0b01110,
0b00100,
0b00100,
0b01010
};
void setup() {
// initialize LCD and set up the number of columns and rows:
lcd.begin(16, 2);
// create a new character
lcd.createChar(0, heart);
// create a new character
lcd.createChar(1, smiley);
// create a new character
lcd.createChar(2, frownie);
// create a new character
lcd.createChar(3, armsDown);
// create a new character
lcd.createChar(4, armsUp);
// Print a message to the lcd.
lcd.print("I ");
lcd.write(byte(0)); // when calling lcd.write() '0' must be cast as a byte
lcd.print(" Arduino! ");
lcd.write((byte) 1);
}
void loop() {
// read the potentiometer on A0:
int sensorReading = analogRead(A0);
// map the result to 200 - 1000:
int delayTime = map(sensorReading, 0, 1023, 200, 1000);
// set the cursor to the bottom row, 5th position:
lcd.setCursor(4, 1);
// draw the little man, arms down:
lcd.write(3);
delay(delayTime);
lcd.setCursor(4, 1);
// draw him arms up:
lcd.write(4);
delay(delayTime);
}

View File

@@ -0,0 +1,61 @@
/*
LiquidCrystal Library - display() and noDisplay()
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch prints "Hello World!" to the LCD and uses the
display() and noDisplay() functions to turn on and off
the display.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalDisplay
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("hello, world!");
}
void loop() {
// Turn off the display:
lcd.noDisplay();
delay(500);
// Turn on the display:
lcd.display();
delay(500);
}

View File

@@ -0,0 +1,60 @@
/*
LiquidCrystal Library - Hello World
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch prints "Hello World!" to the LCD
and shows the time.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* LCD VSS pin to ground
* LCD VCC pin to 5V
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystal
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("hello, world!");
}
void loop() {
// set the cursor to column 0, line 1
// (note: line 1 is the second row, since counting begins with 0):
lcd.setCursor(0, 1);
// print the number of seconds since reset:
lcd.print(millis() / 1000);
}

View File

@@ -0,0 +1,86 @@
/*
LiquidCrystal Library - scrollDisplayLeft() and scrollDisplayRight()
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch prints "Hello World!" to the LCD and uses the
scrollDisplayLeft() and scrollDisplayRight() methods to scroll
the text.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalScroll
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("hello, world!");
delay(1000);
}
void loop() {
// scroll 13 positions (string length) to the left
// to move it offscreen left:
for (int positionCounter = 0; positionCounter < 13; positionCounter++) {
// scroll one position left:
lcd.scrollDisplayLeft();
// wait a bit:
delay(150);
}
// scroll 29 positions (string length + display length) to the right
// to move it offscreen right:
for (int positionCounter = 0; positionCounter < 29; positionCounter++) {
// scroll one position right:
lcd.scrollDisplayRight();
// wait a bit:
delay(150);
}
// scroll 16 positions (display length + string length) to the left
// to move it back to center:
for (int positionCounter = 0; positionCounter < 16; positionCounter++) {
// scroll one position left:
lcd.scrollDisplayLeft();
// wait a bit:
delay(150);
}
// delay at the end of the full loop:
delay(1000);
}

View File

@@ -0,0 +1,64 @@
/*
LiquidCrystal Library - Serial Input
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch displays text sent over the serial port
(e.g. from the Serial Monitor) on an attached LCD.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalSerial
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// initialize the serial communications:
Serial.begin(9600);
}
void loop() {
// when characters arrive over the serial port...
if (Serial.available()) {
// wait a bit for the entire message to arrive
delay(100);
// clear the screen
lcd.clear();
// read all the available characters
while (Serial.available() > 0) {
// display each character to the LCD
lcd.write(Serial.read());
}
}
}

View File

@@ -0,0 +1,86 @@
/*
LiquidCrystal Library - TextDirection
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch demonstrates how to use leftToRight() and rightToLeft()
to move the cursor.
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalTextDirection
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int thisChar = 'a';
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// turn on the cursor:
lcd.cursor();
}
void loop() {
// reverse directions at 'm':
if (thisChar == 'm') {
// go right for the next letter
lcd.rightToLeft();
}
// reverse again at 's':
if (thisChar == 's') {
// go left for the next letter
lcd.leftToRight();
}
// reset at 'z':
if (thisChar > 'z') {
// go to (0,0):
lcd.home();
// start again at 0
thisChar = 'a';
}
// print the character
lcd.write(thisChar);
// wait a second:
delay(1000);
// increment the letter:
thisChar++;
}

View File

@@ -0,0 +1,72 @@
/*
LiquidCrystal Library - setCursor
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch prints to all the positions of the LCD using the
setCursor() method:
The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystalSetCursor
*/
// include the library code:
#include <LiquidCrystal.h>
// these constants won't change. But you can change the size of
// your LCD using them:
const int numRows = 2;
const int numCols = 16;
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(numCols, numRows);
}
void loop() {
// loop from ASCII 'a' to ASCII 'z':
for (int thisLetter = 'a'; thisLetter <= 'z'; thisLetter++) {
// loop over the columns:
for (int thisRow = 0; thisRow < numRows; thisRow++) {
// loop over the rows:
for (int thisCol = 0; thisCol < numCols; thisCol++) {
// set the cursor position:
lcd.setCursor(thisCol, thisRow);
// print the letter:
lcd.write(thisLetter);
delay(200);
}
}
}
}

View File

@@ -0,0 +1,38 @@
#######################################
# Syntax Coloring Map For LiquidCrystal
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
LiquidCrystal KEYWORD1 LiquidCrystal
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
clear KEYWORD2
home KEYWORD2
print KEYWORD2
setCursor KEYWORD2
cursor KEYWORD2
noCursor KEYWORD2
blink KEYWORD2
noBlink KEYWORD2
display KEYWORD2
noDisplay KEYWORD2
autoscroll KEYWORD2
noAutoscroll KEYWORD2
leftToRight KEYWORD2
rightToLeft KEYWORD2
scrollDisplayLeft KEYWORD2
scrollDisplayRight KEYWORD2
createChar KEYWORD2
setRowOffsets KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View File

@@ -0,0 +1,9 @@
name=LiquidCrystal
version=1.0.4
author=Arduino, Adafruit
maintainer=Arduino <info@arduino.cc>
sentence=Allows communication with alphanumerical liquid crystal displays (LCDs). For all Arduino boards.
paragraph=This library allows an Arduino board to control LiquidCrystal displays (LCDs) based on the Hitachi HD44780 (or a compatible) chipset, which is found on most text-based LCDs. The library works with in either 4 or 8 bit mode (i.e. using 4 or 8 data lines in addition to the rs, enable, and, optionally, the rw control lines).
category=Display
url=http://www.arduino.cc/en/Reference/LiquidCrystal
architectures=*

View File

@@ -0,0 +1,326 @@
#include "LiquidCrystal.h"
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Arduino.h"
// When the display powers up, it is configured as follows:
//
// 1. Display clear
// 2. Function set:
// DL = 1; 8-bit interface data
// N = 0; 1-line display
// F = 0; 5x8 dot character font
// 3. Display on/off control:
// D = 0; Display off
// C = 0; Cursor off
// B = 0; Blinking off
// 4. Entry mode set:
// I/D = 1; Increment by 1
// S = 0; No shift
//
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
// can't assume that its in that state when a sketch starts (and the
// LiquidCrystal constructor is called).
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
}
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
init(0, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
}
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
{
init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
}
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
{
init(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
}
void LiquidCrystal::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
_rs_pin = rs;
_rw_pin = rw;
_enable_pin = enable;
_data_pins[0] = d0;
_data_pins[1] = d1;
_data_pins[2] = d2;
_data_pins[3] = d3;
_data_pins[4] = d4;
_data_pins[5] = d5;
_data_pins[6] = d6;
_data_pins[7] = d7;
if (fourbitmode)
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
else
_displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
begin(16, 1);
}
void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
if (lines > 1) {
_displayfunction |= LCD_2LINE;
}
_numlines = lines;
setRowOffsets(0x00, 0x40, 0x00 + cols, 0x40 + cols);
// for some 1 line displays you can select a 10 pixel high font
if ((dotsize != LCD_5x8DOTS) && (lines == 1)) {
_displayfunction |= LCD_5x10DOTS;
}
pinMode(_rs_pin, OUTPUT);
// we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
if (_rw_pin != 255) {
pinMode(_rw_pin, OUTPUT);
}
pinMode(_enable_pin, OUTPUT);
// Do these once, instead of every time a character is drawn for speed reasons.
for (int i=0; i<((_displayfunction & LCD_8BITMODE) ? 8 : 4); ++i)
{
pinMode(_data_pins[i], OUTPUT);
}
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
// according to datasheet, we need at least 40ms after power rises above 2.7V
// before sending commands. Arduino can turn on way before 4.5V so we'll wait 50
delayMicroseconds(50000);
// Now we pull both RS and R/W low to begin commands
digitalWrite(_rs_pin, LOW);
digitalWrite(_enable_pin, LOW);
if (_rw_pin != 255) {
digitalWrite(_rw_pin, LOW);
}
//put the LCD into 4 bit or 8 bit mode
if (! (_displayfunction & LCD_8BITMODE)) {
// this is according to the hitachi HD44780 datasheet
// figure 24, pg 46
// we start in 8bit mode, try to set 4 bit mode
write4bits(0x03);
delayMicroseconds(4500); // wait min 4.1ms
// second try
write4bits(0x03);
delayMicroseconds(4500); // wait min 4.1ms
// third go!
write4bits(0x03);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02);
} else {
// this is according to the hitachi HD44780 datasheet
// page 45 figure 23
// Send function set command sequence
command(LCD_FUNCTIONSET | _displayfunction);
delayMicroseconds(4500); // wait more than 4.1ms
// second try
command(LCD_FUNCTIONSET | _displayfunction);
delayMicroseconds(150);
// third go
command(LCD_FUNCTIONSET | _displayfunction);
}
// finally, set # lines, font size, etc.
command(LCD_FUNCTIONSET | _displayfunction);
// turn the display on with no cursor or blinking default
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
display();
// clear it off
clear();
// Initialize to default text direction (for romance languages)
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
// set the entry mode
command(LCD_ENTRYMODESET | _displaymode);
}
void LiquidCrystal::setRowOffsets(int row0, int row1, int row2, int row3)
{
_row_offsets[0] = row0;
_row_offsets[1] = row1;
_row_offsets[2] = row2;
_row_offsets[3] = row3;
}
/********** high level commands, for the user! */
void LiquidCrystal::clear()
{
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
}
void LiquidCrystal::home()
{
command(LCD_RETURNHOME); // set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
}
void LiquidCrystal::setCursor(uint8_t col, uint8_t row)
{
const size_t max_lines = sizeof(_row_offsets) / sizeof(*_row_offsets);
if ( row >= max_lines ) {
row = max_lines - 1; // we count rows starting w/0
}
if ( row >= _numlines ) {
row = _numlines - 1; // we count rows starting w/0
}
command(LCD_SETDDRAMADDR | (col + _row_offsets[row]));
}
// Turn the display on/off (quickly)
void LiquidCrystal::noDisplay() {
_displaycontrol &= ~LCD_DISPLAYON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal::display() {
_displaycontrol |= LCD_DISPLAYON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// Turns the underline cursor on/off
void LiquidCrystal::noCursor() {
_displaycontrol &= ~LCD_CURSORON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal::cursor() {
_displaycontrol |= LCD_CURSORON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// Turn on and off the blinking cursor
void LiquidCrystal::noBlink() {
_displaycontrol &= ~LCD_BLINKON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal::blink() {
_displaycontrol |= LCD_BLINKON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// These commands scroll the display without changing the RAM
void LiquidCrystal::scrollDisplayLeft(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void LiquidCrystal::scrollDisplayRight(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}
// This is for text that flows Left to Right
void LiquidCrystal::leftToRight(void) {
_displaymode |= LCD_ENTRYLEFT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This is for text that flows Right to Left
void LiquidCrystal::rightToLeft(void) {
_displaymode &= ~LCD_ENTRYLEFT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This will 'right justify' text from the cursor
void LiquidCrystal::autoscroll(void) {
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This will 'left justify' text from the cursor
void LiquidCrystal::noAutoscroll(void) {
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
command(LCD_ENTRYMODESET | _displaymode);
}
// Allows us to fill the first 8 CGRAM locations
// with custom characters
void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) {
location &= 0x7; // we only have 8 locations 0-7
command(LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++) {
write(charmap[i]);
}
}
/*********** mid level commands, for sending data/cmds */
inline void LiquidCrystal::command(uint8_t value) {
send(value, LOW);
}
inline size_t LiquidCrystal::write(uint8_t value) {
send(value, HIGH);
return 1; // assume sucess
}
/************ low level data pushing commands **********/
// write either command or data, with automatic 4/8-bit selection
void LiquidCrystal::send(uint8_t value, uint8_t mode) {
digitalWrite(_rs_pin, mode);
// if there is a RW pin indicated, set it low to Write
if (_rw_pin != 255) {
digitalWrite(_rw_pin, LOW);
}
if (_displayfunction & LCD_8BITMODE) {
write8bits(value);
} else {
write4bits(value>>4);
write4bits(value);
}
}
void LiquidCrystal::pulseEnable(void) {
digitalWrite(_enable_pin, LOW);
delayMicroseconds(1);
digitalWrite(_enable_pin, HIGH);
delayMicroseconds(1); // enable pulse must be >450ns
digitalWrite(_enable_pin, LOW);
delayMicroseconds(100); // commands need > 37us to settle
}
void LiquidCrystal::write4bits(uint8_t value) {
for (int i = 0; i < 4; i++) {
digitalWrite(_data_pins[i], (value >> i) & 0x01);
}
pulseEnable();
}
void LiquidCrystal::write8bits(uint8_t value) {
for (int i = 0; i < 8; i++) {
digitalWrite(_data_pins[i], (value >> i) & 0x01);
}
pulseEnable();
}

View File

@@ -0,0 +1,108 @@
#ifndef LiquidCrystal_h
#define LiquidCrystal_h
#include <inttypes.h>
#include "Print.h"
// commands
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// flags for display entry mode
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// flags for display on/off control
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// flags for display/cursor shift
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// flags for function set
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
class LiquidCrystal : public Print {
public:
LiquidCrystal(uint8_t rs, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3);
LiquidCrystal(uint8_t rs, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3);
void init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
void clear();
void home();
void noDisplay();
void display();
void noBlink();
void blink();
void noCursor();
void cursor();
void scrollDisplayLeft();
void scrollDisplayRight();
void leftToRight();
void rightToLeft();
void autoscroll();
void noAutoscroll();
void setRowOffsets(int row1, int row2, int row3, int row4);
void createChar(uint8_t, uint8_t[]);
void setCursor(uint8_t, uint8_t);
virtual size_t write(uint8_t);
void command(uint8_t);
using Print::write;
private:
void send(uint8_t, uint8_t);
void write4bits(uint8_t);
void write8bits(uint8_t);
void pulseEnable();
uint8_t _rs_pin; // LOW: command. HIGH: character.
uint8_t _rw_pin; // LOW: write to LCD. HIGH: read from LCD.
uint8_t _enable_pin; // activated by a HIGH pulse.
uint8_t _data_pins[8];
uint8_t _displayfunction;
uint8_t _displaycontrol;
uint8_t _displaymode;
uint8_t _initialized;
uint8_t _numlines;
uint8_t _row_offsets[4];
};
#endif

View File

@@ -0,0 +1,25 @@
= Servo Library for Arduino =
This library allows an Arduino board to control RC (hobby) servo motors.
For more information about this library please visit us at
http://www.arduino.cc/en/Reference/Servo
== License ==
Copyright (c) 2013 Arduino LLC. All right reserved.
Copyright (c) 2009 Michael Margolis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

View File

@@ -0,0 +1,27 @@
/*
Controlling a servo position using a potentiometer (variable resistor)
by Michal Rinott <http://people.interaction-ivrea.it/m.rinott>
modified on 8 Nov 2013
by Scott Fitzgerald
http://www.arduino.cc/en/Tutorial/Knob
*/
#include <Servo.h>
Servo myservo; // create servo object to control a servo
int potpin = 0; // analog pin used to connect the potentiometer
int val; // variable to read the value from the analog pin
void setup() {
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}
void loop() {
val = analogRead(potpin); // reads the value of the potentiometer (value between 0 and 1023)
val = map(val, 0, 1023, 0, 180); // scale it to use it with the servo (value between 0 and 180)
myservo.write(val); // sets the servo position according to the scaled value
delay(15); // waits for the servo to get there
}

View File

@@ -0,0 +1,32 @@
/* Sweep
by BARRAGAN <http://barraganstudio.com>
This example code is in the public domain.
modified 8 Nov 2013
by Scott Fitzgerald
http://www.arduino.cc/en/Tutorial/Sweep
*/
#include <Servo.h>
Servo myservo; // create servo object to control a servo
// twelve servo objects can be created on most boards
int pos = 0; // variable to store the servo position
void setup() {
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}
void loop() {
for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
// in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
}

View File

@@ -0,0 +1,24 @@
#######################################
# Syntax Coloring Map Servo
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
Servo KEYWORD1 Servo
#######################################
# Methods and Functions (KEYWORD2)
#######################################
attach KEYWORD2
detach KEYWORD2
write KEYWORD2
read KEYWORD2
attached KEYWORD2
writeMicroseconds KEYWORD2
readMicroseconds KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View File

@@ -0,0 +1,9 @@
name=Servo
version=1.1.2
author=Michael Margolis, Arduino
maintainer=Arduino <info@arduino.cc>
sentence=Allows Arduino/Genuino boards to control a variety of servo motors.
paragraph=This library can control a great number of servos.<br />It makes careful use of timers: the library can control 12 servos using only 1 timer.<br />On the Arduino Due you can control up to 60 servos.<br />
category=Device Control
url=http://www.arduino.cc/en/Reference/Servo
architectures=avr,sam,samd,nrf52,stm32f4

View File

@@ -0,0 +1,119 @@
/*
Servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
Copyright (c) 2009 Michael Margolis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
A servo is activated by creating an instance of the Servo class passing
the desired pin to the attach() method.
The servos are pulsed in the background using the value most recently
written using the write() method.
Note that analogWrite of PWM on pins associated with the timer are
disabled when the first servo is attached.
Timers are seized as needed in groups of 12 servos - 24 servos use two
timers, 48 servos will use four.
The sequence used to sieze timers is defined in timers.h
The methods are:
Servo - Class for manipulating servo motors connected to Arduino pins.
attach(pin ) - Attaches a servo motor to an i/o pin.
attach(pin, min, max ) - Attaches to a pin setting min and max values in microseconds
default min is 544, max is 2400
write() - Sets the servo angle in degrees. (invalid angle that is valid as pulse in microseconds is treated as microseconds)
writeMicroseconds() - Sets the servo pulse width in microseconds
read() - Gets the last written servo pulse width as an angle between 0 and 180.
readMicroseconds() - Gets the last written servo pulse width in microseconds. (was read_us() in first release)
attached() - Returns true if there is a servo attached.
detach() - Stops an attached servos from pulsing its i/o pin.
*/
#ifndef Servo_h
#define Servo_h
#include <inttypes.h>
/*
* Defines for 16 bit timers used with Servo library
*
* If _useTimerX is defined then TimerX is a 16 bit timer on the current board
* timer16_Sequence_t enumerates the sequence that the timers should be allocated
* _Nbr_16timers indicates how many 16 bit timers are available.
*/
// Architecture specific include
#if defined(ARDUINO_ARCH_AVR)
#include "avr/ServoTimers.h"
#elif defined(ARDUINO_ARCH_SAM)
#include "sam/ServoTimers.h"
#elif defined(ARDUINO_ARCH_SAMD)
#include "samd/ServoTimers.h"
#elif defined(ARDUINO_ARCH_STM32F4)
#include "stm32f4/ServoTimers.h"
#elif defined(ARDUINO_ARCH_NRF52)
#include "nrf52/ServoTimers.h"
#else
#error "This library only supports boards with an AVR, SAM, SAMD, NRF52 or STM32F4 processor."
#endif
#define Servo_VERSION 2 // software version of this library
#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo
#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo
#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached
#define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds
#define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer
#define MAX_SERVOS (_Nbr_16timers * SERVOS_PER_TIMER)
#define INVALID_SERVO 255 // flag indicating an invalid servo index
#if !defined(ARDUINO_ARCH_STM32F4)
typedef struct {
uint8_t nbr :6 ; // a pin number from 0 to 63
uint8_t isActive :1 ; // true if this channel is enabled, pin not pulsed if false
} ServoPin_t ;
typedef struct {
ServoPin_t Pin;
volatile unsigned int ticks;
} servo_t;
class Servo
{
public:
Servo();
uint8_t attach(int pin); // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure
uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes.
void detach();
void write(int value); // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds
void writeMicroseconds(int value); // Write pulse width in microseconds
int read(); // returns current pulse width as an angle between 0 and 180 degrees
int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release)
bool attached(); // return true if this servo is attached, otherwise false
private:
uint8_t servoIndex; // index into the channel data for this servo
int8_t min; // minimum is this value times 4 added to MIN_PULSE_WIDTH
int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH
};
#endif
#endif

View File

@@ -0,0 +1,318 @@
/*
Servo.cpp - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
Copyright (c) 2009 Michael Margolis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(ARDUINO_ARCH_AVR)
#include <avr/interrupt.h>
#include <Arduino.h>
#include "Servo.h"
#define usToTicks(_us) (( clockCyclesPerMicrosecond()* _us) / 8) // converts microseconds to tick (assumes prescale of 8) // 12 Aug 2009
#define ticksToUs(_ticks) (( (unsigned)_ticks * 8)/ clockCyclesPerMicrosecond() ) // converts from ticks back to microseconds
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays // 12 August 2009
//#define NBR_TIMERS (MAX_SERVOS / SERVOS_PER_TIMER)
static servo_t servos[MAX_SERVOS]; // static array of servo structures
static volatile int8_t Channel[_Nbr_16timers ]; // counter for the servo being pulsed for each timer (or -1 if refresh interval)
uint8_t ServoCount = 0; // the total number of attached servos
// convenience macros
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
#define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % SERVOS_PER_TIMER) // returns the index of the servo on this timer
#define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel
#define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel
#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo
#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo
/************ static functions common to all instances ***********************/
static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA)
{
if( Channel[timer] < 0 )
*TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer
else{
if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && SERVO(timer,Channel[timer]).Pin.isActive == true )
digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,LOW); // pulse this channel low if activated
}
Channel[timer]++; // increment to the next channel
if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) {
*OCRnA = *TCNTn + SERVO(timer,Channel[timer]).ticks;
if(SERVO(timer,Channel[timer]).Pin.isActive == true) // check if activated
digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high
}
else {
// finished all channels so wait for the refresh period to expire before starting over
if( ((unsigned)*TCNTn) + 4 < usToTicks(REFRESH_INTERVAL) ) // allow a few ticks to ensure the next OCR1A not missed
*OCRnA = (unsigned int)usToTicks(REFRESH_INTERVAL);
else
*OCRnA = *TCNTn + 4; // at least REFRESH_INTERVAL has elapsed
Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
}
}
#ifndef WIRING // Wiring pre-defines signal handlers so don't define any if compiling for the Wiring platform
// Interrupt handlers for Arduino
#if defined(_useTimer1)
SIGNAL (TIMER1_COMPA_vect)
{
handle_interrupts(_timer1, &TCNT1, &OCR1A);
}
#endif
#if defined(_useTimer3)
SIGNAL (TIMER3_COMPA_vect)
{
handle_interrupts(_timer3, &TCNT3, &OCR3A);
}
#endif
#if defined(_useTimer4)
SIGNAL (TIMER4_COMPA_vect)
{
handle_interrupts(_timer4, &TCNT4, &OCR4A);
}
#endif
#if defined(_useTimer5)
SIGNAL (TIMER5_COMPA_vect)
{
handle_interrupts(_timer5, &TCNT5, &OCR5A);
}
#endif
#elif defined WIRING
// Interrupt handlers for Wiring
#if defined(_useTimer1)
void Timer1Service()
{
handle_interrupts(_timer1, &TCNT1, &OCR1A);
}
#endif
#if defined(_useTimer3)
void Timer3Service()
{
handle_interrupts(_timer3, &TCNT3, &OCR3A);
}
#endif
#endif
static void initISR(timer16_Sequence_t timer)
{
#if defined (_useTimer1)
if(timer == _timer1) {
TCCR1A = 0; // normal counting mode
TCCR1B = _BV(CS11); // set prescaler of 8
TCNT1 = 0; // clear the timer count
#if defined(__AVR_ATmega8__)|| defined(__AVR_ATmega128__)
TIFR |= _BV(OCF1A); // clear any pending interrupts;
TIMSK |= _BV(OCIE1A) ; // enable the output compare interrupt
#else
// here if not ATmega8 or ATmega128
TIFR1 |= _BV(OCF1A); // clear any pending interrupts;
TIMSK1 |= _BV(OCIE1A) ; // enable the output compare interrupt
#endif
#if defined(WIRING)
timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service);
#endif
}
#endif
#if defined (_useTimer3)
if(timer == _timer3) {
TCCR3A = 0; // normal counting mode
TCCR3B = _BV(CS31); // set prescaler of 8
TCNT3 = 0; // clear the timer count
#if defined(__AVR_ATmega128__)
TIFR |= _BV(OCF3A); // clear any pending interrupts;
ETIMSK |= _BV(OCIE3A); // enable the output compare interrupt
#else
TIFR3 = _BV(OCF3A); // clear any pending interrupts;
TIMSK3 = _BV(OCIE3A) ; // enable the output compare interrupt
#endif
#if defined(WIRING)
timerAttach(TIMER3OUTCOMPAREA_INT, Timer3Service); // for Wiring platform only
#endif
}
#endif
#if defined (_useTimer4)
if(timer == _timer4) {
TCCR4A = 0; // normal counting mode
TCCR4B = _BV(CS41); // set prescaler of 8
TCNT4 = 0; // clear the timer count
TIFR4 = _BV(OCF4A); // clear any pending interrupts;
TIMSK4 = _BV(OCIE4A) ; // enable the output compare interrupt
}
#endif
#if defined (_useTimer5)
if(timer == _timer5) {
TCCR5A = 0; // normal counting mode
TCCR5B = _BV(CS51); // set prescaler of 8
TCNT5 = 0; // clear the timer count
TIFR5 = _BV(OCF5A); // clear any pending interrupts;
TIMSK5 = _BV(OCIE5A) ; // enable the output compare interrupt
}
#endif
}
static void finISR(timer16_Sequence_t timer)
{
//disable use of the given timer
#if defined WIRING // Wiring
if(timer == _timer1) {
#if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
TIMSK1 &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt
#else
TIMSK &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt
#endif
timerDetach(TIMER1OUTCOMPAREA_INT);
}
else if(timer == _timer3) {
#if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
TIMSK3 &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt
#else
ETIMSK &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt
#endif
timerDetach(TIMER3OUTCOMPAREA_INT);
}
#else
//For arduino - in future: call here to a currently undefined function to reset the timer
(void) timer; // squash "unused parameter 'timer' [-Wunused-parameter]" warning
#endif
}
static boolean isTimerActive(timer16_Sequence_t timer)
{
// returns true if any servo is active on this timer
for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) {
if(SERVO(timer,channel).Pin.isActive == true)
return true;
}
return false;
}
/****************** end of static functions ******************************/
Servo::Servo()
{
if( ServoCount < MAX_SERVOS) {
this->servoIndex = ServoCount++; // assign a servo index to this instance
servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // store default values - 12 Aug 2009
}
else
this->servoIndex = INVALID_SERVO ; // too many servos
}
uint8_t Servo::attach(int pin)
{
return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
}
uint8_t Servo::attach(int pin, int min, int max)
{
if(this->servoIndex < MAX_SERVOS ) {
pinMode( pin, OUTPUT) ; // set servo pin to output
servos[this->servoIndex].Pin.nbr = pin;
// todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128
this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS
this->max = (MAX_PULSE_WIDTH - max)/4;
// initialize the timer if it has not already been initialized
timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
if(isTimerActive(timer) == false)
initISR(timer);
servos[this->servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive
}
return this->servoIndex ;
}
void Servo::detach()
{
servos[this->servoIndex].Pin.isActive = false;
timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
if(isTimerActive(timer) == false) {
finISR(timer);
}
}
void Servo::write(int value)
{
if(value < MIN_PULSE_WIDTH)
{ // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
if(value < 0) value = 0;
if(value > 180) value = 180;
value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX());
}
this->writeMicroseconds(value);
}
void Servo::writeMicroseconds(int value)
{
// calculate and store the values for the given channel
byte channel = this->servoIndex;
if( (channel < MAX_SERVOS) ) // ensure channel is valid
{
if( value < SERVO_MIN() ) // ensure pulse width is valid
value = SERVO_MIN();
else if( value > SERVO_MAX() )
value = SERVO_MAX();
value = value - TRIM_DURATION;
value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009
uint8_t oldSREG = SREG;
cli();
servos[channel].ticks = value;
SREG = oldSREG;
}
}
int Servo::read() // return the value as degrees
{
return map( this->readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180);
}
int Servo::readMicroseconds()
{
unsigned int pulsewidth;
if( this->servoIndex != INVALID_SERVO )
pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION ; // 12 aug 2009
else
pulsewidth = 0;
return pulsewidth;
}
bool Servo::attached()
{
return servos[this->servoIndex].Pin.isActive ;
}
#endif // ARDUINO_ARCH_AVR

View File

@@ -0,0 +1,59 @@
/*
Servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
Copyright (c) 2009 Michael Margolis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Defines for 16 bit timers used with Servo library
*
* If _useTimerX is defined then TimerX is a 16 bit timer on the current board
* timer16_Sequence_t enumerates the sequence that the timers should be allocated
* _Nbr_16timers indicates how many 16 bit timers are available.
*/
/**
* AVR Only definitions
* --------------------
*/
// Say which 16 bit timers can be used and in what order
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define _useTimer5
#define _useTimer1
#define _useTimer3
#define _useTimer4
typedef enum { _timer5, _timer1, _timer3, _timer4, _Nbr_16timers } timer16_Sequence_t;
#elif defined(__AVR_ATmega32U4__)
#define _useTimer1
typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t;
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define _useTimer3
#define _useTimer1
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t;
#elif defined(__AVR_ATmega128__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega2561__)
#define _useTimer3
#define _useTimer1
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t;
#else // everything else
#define _useTimer1
typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t;
#endif

View File

@@ -0,0 +1,134 @@
/*
Copyright (c) 2016 Arduino. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(ARDUINO_ARCH_NRF52)
#include <Arduino.h>
#include <Servo.h>
static servo_t servos[MAX_SERVOS]; // static array of servo structures
uint8_t ServoCount = 0; // the total number of attached servos
uint32_t group_pins[3][NRF_PWM_CHANNEL_COUNT]={{NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED}, {NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED}, {NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED}};
static uint16_t seq_values[3][NRF_PWM_CHANNEL_COUNT]={{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
Servo::Servo()
{
if (ServoCount < MAX_SERVOS) {
this->servoIndex = ServoCount++; // assign a servo index to this instance
} else {
this->servoIndex = INVALID_SERVO; // too many servos
}
}
uint8_t Servo::attach(int pin)
{
return this->attach(pin, 0, 2500);
}
uint8_t Servo::attach(int pin, int min, int max)
{
int servo_min, servo_max;
if (this->servoIndex < MAX_SERVOS) {
pinMode(pin, OUTPUT); // set servo pin to output
servos[this->servoIndex].Pin.nbr = pin;
if(min < servo_min) min = servo_min;
if (max > servo_max) max = servo_max;
this->min = min;
this->max = max;
servos[this->servoIndex].Pin.isActive = true;
}
return this->servoIndex;
}
void Servo::detach()
{
servos[this->servoIndex].Pin.isActive = false;
}
void Servo::write(int value)
{
if (value < 0)
value = 0;
else if (value > 180)
value = 180;
value = map(value, 0, 180, MIN_PULSE, MAX_PULSE);
writeMicroseconds(value);
}
void Servo::writeMicroseconds(int value)
{
uint8_t channel, instance;
uint8_t pin = servos[this->servoIndex].Pin.nbr;
//instance of pwm module is MSB - look at VWariant.h
instance=(g_APinDescription[pin].ulPWMChannel & 0xF0)/16;
//index of pwm channel is LSB - look at VWariant.h
channel=g_APinDescription[pin].ulPWMChannel & 0x0F;
group_pins[instance][channel]=g_APinDescription[pin].ulPin;
NRF_PWM_Type * PWMInstance = instance == 0 ? NRF_PWM0 : (instance == 1 ? NRF_PWM1 : NRF_PWM2);
//configure pwm instance and enable it
seq_values[instance][channel]= value | 0x8000;
nrf_pwm_sequence_t const seq={
seq_values[instance],
NRF_PWM_VALUES_LENGTH(seq_values),
0,
0
};
nrf_pwm_pins_set(PWMInstance, group_pins[instance]);
nrf_pwm_enable(PWMInstance);
nrf_pwm_configure(PWMInstance, NRF_PWM_CLK_125kHz, NRF_PWM_MODE_UP, 2500); // 20ms - 50Hz
nrf_pwm_decoder_set(PWMInstance, NRF_PWM_LOAD_INDIVIDUAL, NRF_PWM_STEP_AUTO);
nrf_pwm_sequence_set(PWMInstance, 0, &seq);
nrf_pwm_loop_set(PWMInstance, 0UL);
nrf_pwm_task_trigger(PWMInstance, NRF_PWM_TASK_SEQSTART0);
}
int Servo::read() // return the value as degrees
{
return map(readMicroseconds(), MIN_PULSE, MAX_PULSE, 0, 180);
}
int Servo::readMicroseconds()
{
uint8_t channel, instance;
uint8_t pin=servos[this->servoIndex].Pin.nbr;
instance=(g_APinDescription[pin].ulPWMChannel & 0xF0)/16;
channel=g_APinDescription[pin].ulPWMChannel & 0x0F;
// remove the 16th bit we added before
return seq_values[instance][channel] & 0x7FFF;
}
bool Servo::attached()
{
return servos[this->servoIndex].Pin.isActive;
}
#endif // ARDUINO_ARCH_NRF52

View File

@@ -0,0 +1,38 @@
/*
Copyright (c) 2016 Arduino. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* NRF52 doesn't use timer, but pwm. This file include definitions to keep
* compatibility with the Servo library standards.
*/
#ifndef __SERVO_TIMERS_H__
#define __SERVO_TIMERS_H__
/**
* NRF52 Only definitions
* ---------------------
*/
#define MIN_PULSE 55
#define MAX_PULSE 284
// define one timer in order to have MAX_SERVOS = 12
typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t;
#endif // __SERVO_TIMERS_H__

View File

@@ -0,0 +1,283 @@
/*
Copyright (c) 2013 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(ARDUINO_ARCH_SAM)
#include <Arduino.h>
#include <Servo.h>
#define usToTicks(_us) (( clockCyclesPerMicrosecond() * _us) / 32) // converts microseconds to tick
#define ticksToUs(_ticks) (( (unsigned)_ticks * 32)/ clockCyclesPerMicrosecond() ) // converts from ticks back to microseconds
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays
static servo_t servos[MAX_SERVOS]; // static array of servo structures
uint8_t ServoCount = 0; // the total number of attached servos
static volatile int8_t Channel[_Nbr_16timers ]; // counter for the servo being pulsed for each timer (or -1 if refresh interval)
// convenience macros
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
#define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % SERVOS_PER_TIMER) // returns the index of the servo on this timer
#define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel
#define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel
#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo
#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo
/************ static functions common to all instances ***********************/
//------------------------------------------------------------------------------
/// Interrupt handler for the TC0 channel 1.
//------------------------------------------------------------------------------
void Servo_Handler(timer16_Sequence_t timer, Tc *pTc, uint8_t channel);
#if defined (_useTimer1)
void HANDLER_FOR_TIMER1(void) {
Servo_Handler(_timer1, TC_FOR_TIMER1, CHANNEL_FOR_TIMER1);
}
#endif
#if defined (_useTimer2)
void HANDLER_FOR_TIMER2(void) {
Servo_Handler(_timer2, TC_FOR_TIMER2, CHANNEL_FOR_TIMER2);
}
#endif
#if defined (_useTimer3)
void HANDLER_FOR_TIMER3(void) {
Servo_Handler(_timer3, TC_FOR_TIMER3, CHANNEL_FOR_TIMER3);
}
#endif
#if defined (_useTimer4)
void HANDLER_FOR_TIMER4(void) {
Servo_Handler(_timer4, TC_FOR_TIMER4, CHANNEL_FOR_TIMER4);
}
#endif
#if defined (_useTimer5)
void HANDLER_FOR_TIMER5(void) {
Servo_Handler(_timer5, TC_FOR_TIMER5, CHANNEL_FOR_TIMER5);
}
#endif
void Servo_Handler(timer16_Sequence_t timer, Tc *tc, uint8_t channel)
{
// clear interrupt
tc->TC_CHANNEL[channel].TC_SR;
if (Channel[timer] < 0) {
tc->TC_CHANNEL[channel].TC_CCR |= TC_CCR_SWTRG; // channel set to -1 indicated that refresh interval completed so reset the timer
} else {
if (SERVO_INDEX(timer,Channel[timer]) < ServoCount && SERVO(timer,Channel[timer]).Pin.isActive == true) {
digitalWrite(SERVO(timer,Channel[timer]).Pin.nbr, LOW); // pulse this channel low if activated
}
}
Channel[timer]++; // increment to the next channel
if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) {
tc->TC_CHANNEL[channel].TC_RA = tc->TC_CHANNEL[channel].TC_CV + SERVO(timer,Channel[timer]).ticks;
if(SERVO(timer,Channel[timer]).Pin.isActive == true) { // check if activated
digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high
}
}
else {
// finished all channels so wait for the refresh period to expire before starting over
if( (tc->TC_CHANNEL[channel].TC_CV) + 4 < usToTicks(REFRESH_INTERVAL) ) { // allow a few ticks to ensure the next OCR1A not missed
tc->TC_CHANNEL[channel].TC_RA = (unsigned int)usToTicks(REFRESH_INTERVAL);
}
else {
tc->TC_CHANNEL[channel].TC_RA = tc->TC_CHANNEL[channel].TC_CV + 4; // at least REFRESH_INTERVAL has elapsed
}
Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
}
}
static void _initISR(Tc *tc, uint32_t channel, uint32_t id, IRQn_Type irqn)
{
pmc_enable_periph_clk(id);
TC_Configure(tc, channel,
TC_CMR_TCCLKS_TIMER_CLOCK3 | // MCK/32
TC_CMR_WAVE | // Waveform mode
TC_CMR_WAVSEL_UP_RC ); // Counter running up and reset when equals to RC
/* 84MHz, MCK/32, for 1.5ms: 3937 */
TC_SetRA(tc, channel, 2625); // 1ms
/* Configure and enable interrupt */
NVIC_EnableIRQ(irqn);
// TC_IER_CPAS: RA Compare
tc->TC_CHANNEL[channel].TC_IER = TC_IER_CPAS;
// Enables the timer clock and performs a software reset to start the counting
TC_Start(tc, channel);
}
static void initISR(timer16_Sequence_t timer)
{
#if defined (_useTimer1)
if (timer == _timer1)
_initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1);
#endif
#if defined (_useTimer2)
if (timer == _timer2)
_initISR(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2, ID_TC_FOR_TIMER2, IRQn_FOR_TIMER2);
#endif
#if defined (_useTimer3)
if (timer == _timer3)
_initISR(TC_FOR_TIMER3, CHANNEL_FOR_TIMER3, ID_TC_FOR_TIMER3, IRQn_FOR_TIMER3);
#endif
#if defined (_useTimer4)
if (timer == _timer4)
_initISR(TC_FOR_TIMER4, CHANNEL_FOR_TIMER4, ID_TC_FOR_TIMER4, IRQn_FOR_TIMER4);
#endif
#if defined (_useTimer5)
if (timer == _timer5)
_initISR(TC_FOR_TIMER5, CHANNEL_FOR_TIMER5, ID_TC_FOR_TIMER5, IRQn_FOR_TIMER5);
#endif
}
static void finISR(timer16_Sequence_t timer)
{
#if defined (_useTimer1)
TC_Stop(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1);
#endif
#if defined (_useTimer2)
TC_Stop(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2);
#endif
#if defined (_useTimer3)
TC_Stop(TC_FOR_TIMER3, CHANNEL_FOR_TIMER3);
#endif
#if defined (_useTimer4)
TC_Stop(TC_FOR_TIMER4, CHANNEL_FOR_TIMER4);
#endif
#if defined (_useTimer5)
TC_Stop(TC_FOR_TIMER5, CHANNEL_FOR_TIMER5);
#endif
}
static boolean isTimerActive(timer16_Sequence_t timer)
{
// returns true if any servo is active on this timer
for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) {
if(SERVO(timer,channel).Pin.isActive == true)
return true;
}
return false;
}
/****************** end of static functions ******************************/
Servo::Servo()
{
if (ServoCount < MAX_SERVOS) {
this->servoIndex = ServoCount++; // assign a servo index to this instance
servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // store default values
} else {
this->servoIndex = INVALID_SERVO; // too many servos
}
}
uint8_t Servo::attach(int pin)
{
return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
}
uint8_t Servo::attach(int pin, int min, int max)
{
timer16_Sequence_t timer;
if (this->servoIndex < MAX_SERVOS) {
pinMode(pin, OUTPUT); // set servo pin to output
servos[this->servoIndex].Pin.nbr = pin;
// todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128
this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS
this->max = (MAX_PULSE_WIDTH - max)/4;
// initialize the timer if it has not already been initialized
timer = SERVO_INDEX_TO_TIMER(servoIndex);
if (isTimerActive(timer) == false) {
initISR(timer);
}
servos[this->servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive
}
return this->servoIndex;
}
void Servo::detach()
{
timer16_Sequence_t timer;
servos[this->servoIndex].Pin.isActive = false;
timer = SERVO_INDEX_TO_TIMER(servoIndex);
if(isTimerActive(timer) == false) {
finISR(timer);
}
}
void Servo::write(int value)
{
// treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
if (value < MIN_PULSE_WIDTH)
{
if (value < 0)
value = 0;
else if (value > 180)
value = 180;
value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX());
}
writeMicroseconds(value);
}
void Servo::writeMicroseconds(int value)
{
// calculate and store the values for the given channel
byte channel = this->servoIndex;
if( (channel < MAX_SERVOS) ) // ensure channel is valid
{
if (value < SERVO_MIN()) // ensure pulse width is valid
value = SERVO_MIN();
else if (value > SERVO_MAX())
value = SERVO_MAX();
value = value - TRIM_DURATION;
value = usToTicks(value); // convert to ticks after compensating for interrupt overhead
servos[channel].ticks = value;
}
}
int Servo::read() // return the value as degrees
{
return map(readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180);
}
int Servo::readMicroseconds()
{
unsigned int pulsewidth;
if (this->servoIndex != INVALID_SERVO)
pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION;
else
pulsewidth = 0;
return pulsewidth;
}
bool Servo::attached()
{
return servos[this->servoIndex].Pin.isActive;
}
#endif // ARDUINO_ARCH_SAM

View File

@@ -0,0 +1,88 @@
/*
Copyright (c) 2013 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Defines for 16 bit timers used with Servo library
*
* If _useTimerX is defined then TimerX is a 16 bit timer on the current board
* timer16_Sequence_t enumerates the sequence that the timers should be allocated
* _Nbr_16timers indicates how many 16 bit timers are available.
*/
/**
* SAM Only definitions
* --------------------
*/
// For SAM3X:
#define _useTimer1
#define _useTimer2
#define _useTimer3
#define _useTimer4
#define _useTimer5
/*
TC0, chan 0 => TC0_Handler
TC0, chan 1 => TC1_Handler
TC0, chan 2 => TC2_Handler
TC1, chan 0 => TC3_Handler
TC1, chan 1 => TC4_Handler
TC1, chan 2 => TC5_Handler
TC2, chan 0 => TC6_Handler
TC2, chan 1 => TC7_Handler
TC2, chan 2 => TC8_Handler
*/
#if defined (_useTimer1)
#define TC_FOR_TIMER1 TC1
#define CHANNEL_FOR_TIMER1 0
#define ID_TC_FOR_TIMER1 ID_TC3
#define IRQn_FOR_TIMER1 TC3_IRQn
#define HANDLER_FOR_TIMER1 TC3_Handler
#endif
#if defined (_useTimer2)
#define TC_FOR_TIMER2 TC1
#define CHANNEL_FOR_TIMER2 1
#define ID_TC_FOR_TIMER2 ID_TC4
#define IRQn_FOR_TIMER2 TC4_IRQn
#define HANDLER_FOR_TIMER2 TC4_Handler
#endif
#if defined (_useTimer3)
#define TC_FOR_TIMER3 TC1
#define CHANNEL_FOR_TIMER3 2
#define ID_TC_FOR_TIMER3 ID_TC5
#define IRQn_FOR_TIMER3 TC5_IRQn
#define HANDLER_FOR_TIMER3 TC5_Handler
#endif
#if defined (_useTimer4)
#define TC_FOR_TIMER4 TC0
#define CHANNEL_FOR_TIMER4 2
#define ID_TC_FOR_TIMER4 ID_TC2
#define IRQn_FOR_TIMER4 TC2_IRQn
#define HANDLER_FOR_TIMER4 TC2_Handler
#endif
#if defined (_useTimer5)
#define TC_FOR_TIMER5 TC0
#define CHANNEL_FOR_TIMER5 0
#define ID_TC_FOR_TIMER5 ID_TC0
#define IRQn_FOR_TIMER5 TC0_IRQn
#define HANDLER_FOR_TIMER5 TC0_Handler
#endif
typedef enum { _timer1, _timer2, _timer3, _timer4, _timer5, _Nbr_16timers } timer16_Sequence_t ;

View File

@@ -0,0 +1,297 @@
/*
Copyright (c) 2015 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(ARDUINO_ARCH_SAMD)
#include <Arduino.h>
#include <Servo.h>
#define usToTicks(_us) ((clockCyclesPerMicrosecond() * _us) / 16) // converts microseconds to tick
#define ticksToUs(_ticks) (((unsigned) _ticks * 16) / clockCyclesPerMicrosecond()) // converts from ticks back to microseconds
#define TRIM_DURATION 5 // compensation ticks to trim adjust for digitalWrite delays
static servo_t servos[MAX_SERVOS]; // static array of servo structures
uint8_t ServoCount = 0; // the total number of attached servos
static volatile int8_t currentServoIndex[_Nbr_16timers]; // index for the servo being pulsed for each timer (or -1 if refresh interval)
// convenience macros
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
#define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % SERVOS_PER_TIMER) // returns the index of the servo on this timer
#define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel
#define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel
#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo
#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY);
/************ static functions common to all instances ***********************/
void Servo_Handler(timer16_Sequence_t timer, Tc *pTc, uint8_t channel, uint8_t intFlag);
#if defined (_useTimer1)
void HANDLER_FOR_TIMER1(void) {
Servo_Handler(_timer1, TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, INTFLAG_BIT_FOR_TIMER_1);
}
#endif
#if defined (_useTimer2)
void HANDLER_FOR_TIMER2(void) {
Servo_Handler(_timer2, TC_FOR_TIMER2, CHANNEL_FOR_TIMER2, INTFLAG_BIT_FOR_TIMER_2);
}
#endif
void Servo_Handler(timer16_Sequence_t timer, Tc *tc, uint8_t channel, uint8_t intFlag)
{
if (currentServoIndex[timer] < 0) {
tc->COUNT16.COUNT.reg = (uint16_t) 0;
WAIT_TC16_REGS_SYNC(tc)
} else {
if (SERVO_INDEX(timer, currentServoIndex[timer]) < ServoCount && SERVO(timer, currentServoIndex[timer]).Pin.isActive == true) {
digitalWrite(SERVO(timer, currentServoIndex[timer]).Pin.nbr, LOW); // pulse this channel low if activated
}
}
// Select the next servo controlled by this timer
currentServoIndex[timer]++;
if (SERVO_INDEX(timer, currentServoIndex[timer]) < ServoCount && currentServoIndex[timer] < SERVOS_PER_TIMER) {
if (SERVO(timer, currentServoIndex[timer]).Pin.isActive == true) { // check if activated
digitalWrite(SERVO(timer, currentServoIndex[timer]).Pin.nbr, HIGH); // it's an active channel so pulse it high
}
// Get the counter value
uint16_t tcCounterValue = tc->COUNT16.COUNT.reg;
WAIT_TC16_REGS_SYNC(tc)
tc->COUNT16.CC[channel].reg = (uint16_t) (tcCounterValue + SERVO(timer, currentServoIndex[timer]).ticks);
WAIT_TC16_REGS_SYNC(tc)
}
else {
// finished all channels so wait for the refresh period to expire before starting over
// Get the counter value
uint16_t tcCounterValue = tc->COUNT16.COUNT.reg;
WAIT_TC16_REGS_SYNC(tc)
if (tcCounterValue + 4UL < usToTicks(REFRESH_INTERVAL)) { // allow a few ticks to ensure the next OCR1A not missed
tc->COUNT16.CC[channel].reg = (uint16_t) usToTicks(REFRESH_INTERVAL);
}
else {
tc->COUNT16.CC[channel].reg = (uint16_t) (tcCounterValue + 4UL); // at least REFRESH_INTERVAL has elapsed
}
WAIT_TC16_REGS_SYNC(tc)
currentServoIndex[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
}
// Clear the interrupt
tc->COUNT16.INTFLAG.reg = intFlag;
}
static inline void resetTC (Tc* TCx)
{
// Disable TCx
TCx->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
WAIT_TC16_REGS_SYNC(TCx)
// Reset TCx
TCx->COUNT16.CTRLA.reg = TC_CTRLA_SWRST;
WAIT_TC16_REGS_SYNC(TCx)
while (TCx->COUNT16.CTRLA.bit.SWRST);
}
static void _initISR(Tc *tc, uint8_t channel, uint32_t id, IRQn_Type irqn, uint8_t gcmForTimer, uint8_t intEnableBit)
{
// Enable GCLK for timer 1 (timer counter input clock)
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(gcmForTimer));
while (GCLK->STATUS.bit.SYNCBUSY);
// Reset the timer
// TODO this is not the right thing to do if more than one channel per timer is used by the Servo library
resetTC(tc);
// Set timer counter mode to 16 bits
tc->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
// Set timer counter mode as normal PWM
tc->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_NPWM;
// Set the prescaler factor to GCLK_TC/16. At nominal 48MHz GCLK_TC this is 3000 ticks per millisecond
tc->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV16;
// Count up
tc->COUNT16.CTRLBCLR.bit.DIR = 1;
WAIT_TC16_REGS_SYNC(tc)
// First interrupt request after 1 ms
tc->COUNT16.CC[channel].reg = (uint16_t) usToTicks(1000UL);
WAIT_TC16_REGS_SYNC(tc)
// Configure interrupt request
// TODO this should be changed if more than one channel per timer is used by the Servo library
NVIC_DisableIRQ(irqn);
NVIC_ClearPendingIRQ(irqn);
NVIC_SetPriority(irqn, 0);
NVIC_EnableIRQ(irqn);
// Enable the match channel interrupt request
tc->COUNT16.INTENSET.reg = intEnableBit;
// Enable the timer and start it
tc->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;
WAIT_TC16_REGS_SYNC(tc)
}
static void initISR(timer16_Sequence_t timer)
{
#if defined (_useTimer1)
if (timer == _timer1)
_initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1, GCM_FOR_TIMER_1, INTENSET_BIT_FOR_TIMER_1);
#endif
#if defined (_useTimer2)
if (timer == _timer2)
_initISR(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2, ID_TC_FOR_TIMER2, IRQn_FOR_TIMER2, GCM_FOR_TIMER_2, INTENSET_BIT_FOR_TIMER_2);
#endif
}
static void finISR(timer16_Sequence_t timer)
{
#if defined (_useTimer1)
// Disable the match channel interrupt request
TC_FOR_TIMER1->COUNT16.INTENCLR.reg = INTENCLR_BIT_FOR_TIMER_1;
#endif
#if defined (_useTimer2)
// Disable the match channel interrupt request
TC_FOR_TIMER2->COUNT16.INTENCLR.reg = INTENCLR_BIT_FOR_TIMER_2;
#endif
}
static boolean isTimerActive(timer16_Sequence_t timer)
{
// returns true if any servo is active on this timer
for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) {
if(SERVO(timer,channel).Pin.isActive == true)
return true;
}
return false;
}
/****************** end of static functions ******************************/
Servo::Servo()
{
if (ServoCount < MAX_SERVOS) {
this->servoIndex = ServoCount++; // assign a servo index to this instance
servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // store default values
} else {
this->servoIndex = INVALID_SERVO; // too many servos
}
}
uint8_t Servo::attach(int pin)
{
return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
}
uint8_t Servo::attach(int pin, int min, int max)
{
timer16_Sequence_t timer;
if (this->servoIndex < MAX_SERVOS) {
pinMode(pin, OUTPUT); // set servo pin to output
servos[this->servoIndex].Pin.nbr = pin;
// todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128
this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS
this->max = (MAX_PULSE_WIDTH - max)/4;
// initialize the timer if it has not already been initialized
timer = SERVO_INDEX_TO_TIMER(servoIndex);
if (isTimerActive(timer) == false) {
initISR(timer);
}
servos[this->servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive
}
return this->servoIndex;
}
void Servo::detach()
{
timer16_Sequence_t timer;
servos[this->servoIndex].Pin.isActive = false;
timer = SERVO_INDEX_TO_TIMER(servoIndex);
if(isTimerActive(timer) == false) {
finISR(timer);
}
}
void Servo::write(int value)
{
// treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
if (value < MIN_PULSE_WIDTH)
{
if (value < 0)
value = 0;
else if (value > 180)
value = 180;
value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX());
}
writeMicroseconds(value);
}
void Servo::writeMicroseconds(int value)
{
// calculate and store the values for the given channel
byte channel = this->servoIndex;
if( (channel < MAX_SERVOS) ) // ensure channel is valid
{
if (value < SERVO_MIN()) // ensure pulse width is valid
value = SERVO_MIN();
else if (value > SERVO_MAX())
value = SERVO_MAX();
value = value - TRIM_DURATION;
value = usToTicks(value); // convert to ticks after compensating for interrupt overhead
servos[channel].ticks = value;
}
}
int Servo::read() // return the value as degrees
{
return map(readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180);
}
int Servo::readMicroseconds()
{
unsigned int pulsewidth;
if (this->servoIndex != INVALID_SERVO)
pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION;
else
pulsewidth = 0;
return pulsewidth;
}
bool Servo::attached()
{
return servos[this->servoIndex].Pin.isActive;
}
#endif // ARDUINO_ARCH_SAMD

View File

@@ -0,0 +1,71 @@
/*
Copyright (c) 2015 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Defines for 16 bit timers used with Servo library
*
* If _useTimerX is defined then TimerX is a 16 bit timer on the current board
* timer16_Sequence_t enumerates the sequence that the timers should be allocated
* _Nbr_16timers indicates how many 16 bit timers are available.
*/
#ifndef __SERVO_TIMERS_H__
#define __SERVO_TIMERS_H__
/**
* SAMD Only definitions
* ---------------------
*/
// For SAMD:
#define _useTimer1
//#define _useTimer2 // <- TODO do not activate until the code in Servo.cpp has been changed in order
// to manage more than one channel per timer on the SAMD architecture
#if defined (_useTimer1)
#define TC_FOR_TIMER1 TC4
#define CHANNEL_FOR_TIMER1 0
#define INTENSET_BIT_FOR_TIMER_1 TC_INTENSET_MC0
#define INTENCLR_BIT_FOR_TIMER_1 TC_INTENCLR_MC0
#define INTFLAG_BIT_FOR_TIMER_1 TC_INTFLAG_MC0
#define ID_TC_FOR_TIMER1 ID_TC4
#define IRQn_FOR_TIMER1 TC4_IRQn
#define HANDLER_FOR_TIMER1 TC4_Handler
#define GCM_FOR_TIMER_1 GCM_TC4_TC5
#endif
#if defined (_useTimer2)
#define TC_FOR_TIMER2 TC4
#define CHANNEL_FOR_TIMER2 1
#define INTENSET_BIT_FOR_TIMER_2 TC_INTENSET_MC1
#define INTENCLR_BIT_FOR_TIMER_2 TC_INTENCLR_MC1
#define ID_TC_FOR_TIMER2 ID_TC4
#define IRQn_FOR_TIMER2 TC4_IRQn
#define HANDLER_FOR_TIMER2 TC4_Handler
#define GCM_FOR_TIMER_2 GCM_TC4_TC5
#endif
typedef enum {
#if defined (_useTimer1)
_timer1,
#endif
#if defined (_useTimer2)
_timer2,
#endif
_Nbr_16timers } timer16_Sequence_t;
#endif // __SERVO_TIMERS_H__

View File

@@ -0,0 +1,194 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010, LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
#if defined(ARDUINO_ARCH_STM32F4)
#include "ServoTimers.h"
#include "boards.h"
#include "io.h"
#include "pwm.h"
#include "math.h"
// 20 millisecond period config. For a 1-based prescaler,
//
// (prescaler * overflow / CYC_MSEC) msec = 1 timer cycle = 20 msec
// => prescaler * overflow = 20 * CYC_MSEC
//
// This picks the smallest prescaler that allows an overflow < 2^16.
#define MAX_OVERFLOW ((1 << 16) - 1)
#define CYC_MSEC (1000 * CYCLES_PER_MICROSECOND)
#define TAU_MSEC 20
#define TAU_USEC (TAU_MSEC * 1000)
#define TAU_CYC (TAU_MSEC * CYC_MSEC)
#define SERVO_PRESCALER (TAU_CYC / MAX_OVERFLOW + 1)
#define SERVO_OVERFLOW ((uint16)round((double)TAU_CYC / SERVO_PRESCALER))
// Unit conversions
#define US_TO_COMPARE(us) ((uint16)map((us), 0, TAU_USEC, 0, SERVO_OVERFLOW))
#define COMPARE_TO_US(c) ((uint32)map((c), 0, SERVO_OVERFLOW, 0, TAU_USEC))
#define ANGLE_TO_US(a) ((uint16)(map((a), this->minAngle, this->maxAngle, \
this->minPW, this->maxPW)))
#define US_TO_ANGLE(us) ((int16)(map((us), this->minPW, this->maxPW, \
this->minAngle, this->maxAngle)))
Servo::Servo() {
this->resetFields();
}
bool Servo::attach(uint8 pin, uint16 minPW, uint16 maxPW, int16 minAngle, int16 maxAngle)
{
// SerialUSB.begin(115200);
// SerialUSB.println(MAX_OVERFLOW);
timer_dev *tdev = PIN_MAP[pin].timer_device;
analogWriteResolution(16);
int prescaler = 6;
int overflow = 65400;
int minPW_correction = 300;
int maxPW_correction = 300;
pinMode(pin, OUTPUT);
if (tdev == NULL) {
// don't reset any fields or ASSERT(0), to keep driving any
// previously attach()ed servo.
return false;
}
if ( (tdev == TIMER1) || (tdev == TIMER8) || (tdev == TIMER10) || (tdev == TIMER11))
{
prescaler = 54;
overflow = 65400;
minPW_correction = 40;
maxPW_correction = 50;
}
if ( (tdev == TIMER2) || (tdev == TIMER3) || (tdev == TIMER4) || (tdev == TIMER5) )
{
prescaler = 6;
overflow = 64285;
minPW_correction = 370;
maxPW_correction = 350;
}
if ( (tdev == TIMER6) || (tdev == TIMER7) )
{
prescaler = 6;
overflow = 65400;
minPW_correction = 0;
maxPW_correction = 0;
}
if ( (tdev == TIMER9) || (tdev == TIMER12) || (tdev == TIMER13) || (tdev == TIMER14) )
{
prescaler = 6;
overflow = 65400;
minPW_correction = 30;
maxPW_correction = 0;
}
if (this->attached()) {
this->detach();
}
this->pin = pin;
this->minPW = (minPW + minPW_correction);
this->maxPW = (maxPW + maxPW_correction);
this->minAngle = minAngle;
this->maxAngle = maxAngle;
timer_pause(tdev);
timer_set_prescaler(tdev, prescaler); // prescaler is 1-based
timer_set_reload(tdev, overflow);
timer_generate_update(tdev);
timer_resume(tdev);
return true;
}
bool Servo::detach() {
if (!this->attached()) {
return false;
}
timer_dev *tdev = PIN_MAP[this->pin].timer_device;
uint8 tchan = PIN_MAP[this->pin].timer_channel;
timer_set_mode(tdev, tchan, TIMER_DISABLED);
this->resetFields();
return true;
}
void Servo::write(int degrees) {
degrees = constrain(degrees, this->minAngle, this->maxAngle);
this->writeMicroseconds(ANGLE_TO_US(degrees));
}
int Servo::read() const {
int a = US_TO_ANGLE(this->readMicroseconds());
// map() round-trips in a weird way we mostly correct for here;
// the round-trip is still sometimes off-by-one for write(1) and
// write(179).
return a == this->minAngle || a == this->maxAngle ? a : a + 1;
}
void Servo::writeMicroseconds(uint16 pulseWidth) {
if (!this->attached()) {
ASSERT(0);
return;
}
pulseWidth = constrain(pulseWidth, this->minPW, this->maxPW);
analogWrite(this->pin, US_TO_COMPARE(pulseWidth));
}
uint16 Servo::readMicroseconds() const {
if (!this->attached()) {
ASSERT(0);
return 0;
}
stm32_pin_info pin_info = PIN_MAP[this->pin];
uint16 compare = timer_get_compare(pin_info.timer_device,
pin_info.timer_channel);
return COMPARE_TO_US(compare);
}
void Servo::resetFields(void) {
this->pin = NOT_ATTACHED;
this->minAngle = MIN_ANGLE;
this->maxAngle = MAX_ANGLE;
this->minPW = MIN_PULSE_WIDTH;
this->maxPW = MAX_PULSE_WIDTH;
}
#endif

View File

@@ -0,0 +1,207 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010, LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
/*
* Arduino srl - www.arduino.org
* 2017 Feb 23: Edited by Francesco Alessi (alfran) - francesco@arduino.org
*/
#ifndef _SERVO_H_
#define _SERVO_H_
#include "types.h"
#include "timer.h"
#include "wiring.h" /* hack for IDE compile */
/*
* Note on Arduino compatibility:
*
* In the Arduino implementation, PWM is done "by hand" in the sense
* that timer channels are hijacked in groups and an ISR is set which
* toggles Servo::attach()ed pins using digitalWrite().
*
* While this scheme allows any pin to drive a servo, it chews up
* cycles and complicates the programmer's notion of when a particular
* timer channel will be in use.
*
* This implementation only allows Servo instances to attach() to pins
* that already have a timer channel associated with them, and just
* uses pwmWrite() to drive the wave.
*
* This introduces an incompatibility: while the Arduino
* implementation of attach() returns the affected channel on success
* and 0 on failure, this one returns true on success and false on
* failure.
*
* RC Servos expect a pulse every 20ms. Since periods are set for
* entire timers, rather than individual channels, attach()ing a Servo
* to a pin can interfere with other pins associated with the same
* timer. As always, your board's pin map is your friend.
*/
// Pin number of unattached pins
#define NOT_ATTACHED (-1)
#define _Nbr_16timers 14 // mumber of STM32F469 Timers
#define SERVOS_PER_TIMER 4 // Number of timer channels
// Default min/max pulse widths (in microseconds) and angles (in
// degrees). Values chosen for Arduino compatibility. These values
// are part of the public API; DO NOT CHANGE THEM.
#define MIN_ANGLE 0
#define MAX_ANGLE 180
#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo
#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo
/** Class for interfacing with RC servomotors. */
class Servo {
public:
/**
* @brief Construct a new Servo instance.
*
* The new instance will not be attached to any pin.
*/
Servo();
/**
* @brief Associate this instance with a servomotor whose input is
* connected to pin.
*
* If this instance is already attached to a pin, it will be
* detached before being attached to the new pin. This function
* doesn't detach any interrupt attached with the pin's timer
* channel.
*
* @param pin Pin connected to the servo pulse wave input. This
* pin must be capable of PWM output.
*
* @param minPulseWidth Minimum pulse width to write to pin, in
* microseconds. This will be associated
* with a minAngle degree angle. Defaults to
* SERVO_DEFAULT_MIN_PW = 544.
*
* @param maxPulseWidth Maximum pulse width to write to pin, in
* microseconds. This will be associated
* with a maxAngle degree angle. Defaults to
* SERVO_DEFAULT_MAX_PW = 2400.
*
* @param minAngle Target angle (in degrees) associated with
* minPulseWidth. Defaults to
* SERVO_DEFAULT_MIN_ANGLE = 0.
*
* @param maxAngle Target angle (in degrees) associated with
* maxPulseWidth. Defaults to
* SERVO_DEFAULT_MAX_ANGLE = 180.
*
* @sideeffect May set pinMode(pin, PWM).
*
* @return true if successful, false when pin doesn't support PWM.
*/
bool attach(uint8 pin,
uint16 minPulseWidth=MIN_PULSE_WIDTH,
uint16 maxPulseWidth=MAX_PULSE_WIDTH,
int16 minAngle=MIN_ANGLE,
int16 maxAngle=MAX_ANGLE);
/**
* @brief Stop driving the servo pulse train.
*
* If not currently attached to a motor, this function has no effect.
*
* @return true if this call did anything, false otherwise.
*/
bool detach();
/**
* @brief Set the servomotor target angle.
*
* @param angle Target angle, in degrees. If the target angle is
* outside the range specified at attach() time, it
* will be clamped to lie in that range.
*
* @see Servo::attach()
*/
void write(int angle);
/**
* @brief Set the pulse width, in microseconds.
*
* @param pulseWidth Pulse width to send to the servomotor, in
* microseconds. If outside of the range
* specified at attach() time, it is clamped to
* lie in that range.
*
* @see Servo::attach()
*/
void writeMicroseconds(uint16 pulseWidth);
/**
* Get the servomotor's target angle, in degrees. This will
* lie inside the range specified at attach() time.
*
* @see Servo::attach()
*/
int read() const;
/**
* Get the current pulse width, in microseconds. This will
* lie within the range specified at attach() time.
*
* @see Servo::attach()
*/
uint16 readMicroseconds() const;
/**
* @brief Check if this instance is attached to a servo.
* @return true if this instance is attached to a servo, false otherwise.
* @see Servo::attachedPin()
*/
bool attached() const { return this->pin != NOT_ATTACHED; }
/**
* @brief Get the pin this instance is attached to.
* @return Pin number if currently attached to a pin, NOT_ATTACHED
* otherwise.
* @see Servo::attach()
*/
int attachedPin() const { return this->pin; }
private:
int16 pin;
uint16 minPW;
uint16 maxPW;
int16 minAngle;
int16 maxAngle;
void resetFields(void);
};
#endif /* _SERVO_H_ */

View File

@@ -66,6 +66,7 @@
"productName": "XOD IDE",
"buildDependenciesFromSource": true,
"extraResources": [
"arduino-libraries",
{
"from": "arduino-builders/${os}",
"to": "arduino-builder"

View File

@@ -18,7 +18,7 @@ import { errorToPlainObject, IS_DEV } from './utils';
// =============================================================================
//
// Calculated constants
// Computed paths
//
// =============================================================================
const arduinoPackagesPath = resolve(app.getPath('userData'), 'packages');
@@ -27,10 +27,16 @@ const arduinoBuilderPlatformMap = {
linux: 'linux',
darwin: 'mac',
};
const arduinoBuilderPath = (IS_DEV) ?
resolve(app.getAppPath(), 'arduino-builders', arduinoBuilderPlatformMap[os.platform()]) :
resolve(process.resourcesPath, 'arduino-builder');
const arduinoLibrariesPath = resolve(
IS_DEV ? app.getAppPath() : process.resourcesPath,
'arduino-libraries'
);
// =============================================================================
//
// Utils
@@ -138,7 +144,7 @@ export const uploadToArduino = (pab, port, code) => {
return writeFile(sketchFile, code, 'utf8')
.then(({ path }) => xad.buildAndUpload(
path, pab, arduinoPackagesPath, buildDir, port, arduinoBuilderPath
path, pab, arduinoPackagesPath, arduinoLibrariesPath, buildDir, port, arduinoBuilderPath
))
.then(tapP(clearTmp))
.catch(