mirror of
https://github.com/digistump/DigistumpArduino.git
synced 2025-04-28 07:39:02 -07:00
Compare commits
No commits in common. "master" and "v1.5.8A" have entirely different histories.
22
README.md
22
README.md
@ -1,23 +1,19 @@
|
|||||||
DigistumpArduino
|
DigistumpArduino
|
||||||
================
|
================
|
||||||
|
|
||||||
Files to add Digistump support (Digispark, Pro, DigiX) to Arduino 1.6.X (1.6.4+)
|
Files to add Digistump support (Digispark, Pro, DigiX) to Arduino 1.5.X (1.5.7+)
|
||||||
|
|
||||||
**These files are designed for install via the Arduino Boards Manager:**
|
|
||||||
|
|
||||||
Board manager URL: http://digistump.com/package_digistump_index.json
|
**Binary downloads of the bundled IDE can be found here:**
|
||||||
|
|
||||||
**Full Install Instructions:**
|
To manually install:
|
||||||
|
|
||||||
Digispark: http://digistump.com/wiki/digispark/tutorials/connecting
|
Place digistump folder inside the Arduino /hardware folder.
|
||||||
|
|
||||||
Digispark Pro: http://digistump.com/wiki/digispark/tutorials/connectingpro
|
To compile tools for other platforms or from scratch use:
|
||||||
|
|
||||||
DigiX: http://digistump.com/wiki/digix/tutorials/software
|
|
||||||
|
|
||||||
**To compile:**
|
|
||||||
|
|
||||||
Micronucleus is the only executable in these packages that is pre-compiled:
|
|
||||||
|
|
||||||
Micronucleus: https://github.com/micronucleus/micronucleus/tree/80419704f68bf0783c5de63a6a4b9d89b45235c7
|
Micronucleus: https://github.com/micronucleus/micronucleus/tree/80419704f68bf0783c5de63a6a4b9d89b45235c7
|
||||||
Dependencies: libusb and possibly lib32stdc on linux - (on ubuntu get it by issuing: apt-get install lib32stdc++6)
|
|
||||||
|
AVR-Dummy: https://github.com/digistump/avr-dummy
|
||||||
|
|
||||||
|
ld from a more recent install of avr-gcc then Arduino uses
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
#include <new.h>
|
|
||||||
|
|
||||||
void * operator new(size_t size)
|
|
||||||
{
|
|
||||||
return malloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator delete(void * ptr)
|
|
||||||
{
|
|
||||||
free(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);};
|
|
||||||
void __cxa_guard_release (__guard *g) {*(char *)g = 1;};
|
|
||||||
void __cxa_guard_abort (__guard *) {};
|
|
||||||
|
|
||||||
void __cxa_pure_virtual(void) {};
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
|||||||
/* Header to define new/delete operators as they aren't provided by avr-gcc by default
|
|
||||||
Taken from http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=59453
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef NEW_H
|
|
||||||
#define NEW_H
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
void * operator new(size_t size);
|
|
||||||
void operator delete(void * ptr);
|
|
||||||
|
|
||||||
__extension__ typedef int __guard __attribute__((mode (__DI__)));
|
|
||||||
|
|
||||||
extern "C" int __cxa_guard_acquire(__guard *);
|
|
||||||
extern "C" void __cxa_guard_release (__guard *);
|
|
||||||
extern "C" void __cxa_guard_abort (__guard *);
|
|
||||||
|
|
||||||
extern "C" void __cxa_pure_virtual(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
|||||||
#include <DigiCDC.h>
|
|
||||||
void setup() {
|
|
||||||
// initialize the digital pin as an output.
|
|
||||||
SerialUSB.begin();
|
|
||||||
pinMode(1,OUTPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the loop routine runs over and over again forever:
|
|
||||||
void loop() {
|
|
||||||
|
|
||||||
//turns led on and off based on sending 0 or 1 from serial terminal
|
|
||||||
if (SerialUSB.available()) {
|
|
||||||
char input = SerialUSB.read();
|
|
||||||
if(input == '0')
|
|
||||||
digitalWrite(1,LOW);
|
|
||||||
else if(input == '1')
|
|
||||||
digitalWrite(1,HIGH);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialUSB.delay(100); // keep usb alive // can alos use SerialUSB.refresh();
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
#include <DigiCDC.h>
|
|
||||||
void setup() {
|
|
||||||
// initialize the digital pin as an output.
|
|
||||||
SerialUSB.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
// the loop routine runs over and over again forever:
|
|
||||||
void loop() {
|
|
||||||
|
|
||||||
if (SerialUSB.available()) {
|
|
||||||
SerialUSB.write(SerialUSB.read());
|
|
||||||
}
|
|
||||||
|
|
||||||
//SerialUSB.delay(10);
|
|
||||||
/*
|
|
||||||
if you don't call a SerialUSB function (write, print, read, available, etc)
|
|
||||||
every 10ms or less then you must throw in some SerialUSB.refresh();
|
|
||||||
for the USB to keep alive - also replace your delays - ie. delay(100);
|
|
||||||
with SerialUSB.delays ie. SerialUSB.delay(100);
|
|
||||||
*/
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
#include <DigiCDC.h>
|
|
||||||
void setup() {
|
|
||||||
// initialize the digital pin as an output.
|
|
||||||
SerialUSB.begin();
|
|
||||||
/*
|
|
||||||
remember the SerialUSB starts as soon as you call begin
|
|
||||||
and doesn't restart the board when you open the serial monitor
|
|
||||||
(like the uno does) - so if you print to it and you don't
|
|
||||||
have a serial monitor open that text is lost.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
// the loop routine runs over and over again forever:
|
|
||||||
void loop() {
|
|
||||||
|
|
||||||
SerialUSB.println(F("TEST!")); //wrap your strings in F() to save ram!
|
|
||||||
|
|
||||||
//SerialUSB.delay(10);
|
|
||||||
/*
|
|
||||||
if you don't call a SerialUSB function (write, print, read, available, etc)
|
|
||||||
every 10ms or less then you must throw in some SerialUSB.refresh();
|
|
||||||
for the USB to keep alive - also replace your delays - ie. delay(100);
|
|
||||||
with SerialUSB.delays ie. SerialUSB.delay(100);
|
|
||||||
*/
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
# Auto detect text files and perform LF normalization
|
|
||||||
* text=auto
|
|
||||||
|
|
||||||
# Custom for Visual Studio
|
|
||||||
*.cs diff=csharp
|
|
||||||
*.sln merge=union
|
|
||||||
*.csproj merge=union
|
|
||||||
*.vbproj merge=union
|
|
||||||
*.fsproj merge=union
|
|
||||||
*.dbproj merge=union
|
|
||||||
|
|
||||||
# Standard to msysgit
|
|
||||||
*.doc diff=astextplain
|
|
||||||
*.DOC diff=astextplain
|
|
||||||
*.docx diff=astextplain
|
|
||||||
*.DOCX diff=astextplain
|
|
||||||
*.dot diff=astextplain
|
|
||||||
*.DOT diff=astextplain
|
|
||||||
*.pdf diff=astextplain
|
|
||||||
*.PDF diff=astextplain
|
|
||||||
*.rtf diff=astextplain
|
|
||||||
*.RTF diff=astextplain
|
|
215
digistump-avr/libraries/DigisparkIRLib/.gitignore
vendored
215
digistump-avr/libraries/DigisparkIRLib/.gitignore
vendored
@ -1,215 +0,0 @@
|
|||||||
#################
|
|
||||||
## Eclipse
|
|
||||||
#################
|
|
||||||
|
|
||||||
*.pydevproject
|
|
||||||
.project
|
|
||||||
.metadata
|
|
||||||
bin/
|
|
||||||
tmp/
|
|
||||||
*.tmp
|
|
||||||
*.bak
|
|
||||||
*.swp
|
|
||||||
*~.nib
|
|
||||||
local.properties
|
|
||||||
.classpath
|
|
||||||
.settings/
|
|
||||||
.loadpath
|
|
||||||
|
|
||||||
# External tool builders
|
|
||||||
.externalToolBuilders/
|
|
||||||
|
|
||||||
# Locally stored "Eclipse launch configurations"
|
|
||||||
*.launch
|
|
||||||
|
|
||||||
# CDT-specific
|
|
||||||
.cproject
|
|
||||||
|
|
||||||
# PDT-specific
|
|
||||||
.buildpath
|
|
||||||
|
|
||||||
|
|
||||||
#################
|
|
||||||
## Visual Studio
|
|
||||||
#################
|
|
||||||
|
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
|
||||||
## files generated by popular Visual Studio add-ons.
|
|
||||||
|
|
||||||
# User-specific files
|
|
||||||
*.suo
|
|
||||||
*.user
|
|
||||||
*.sln.docstates
|
|
||||||
|
|
||||||
# Build results
|
|
||||||
|
|
||||||
[Dd]ebug/
|
|
||||||
[Rr]elease/
|
|
||||||
x64/
|
|
||||||
build/
|
|
||||||
[Bb]in/
|
|
||||||
[Oo]bj/
|
|
||||||
|
|
||||||
# MSTest test Results
|
|
||||||
[Tt]est[Rr]esult*/
|
|
||||||
[Bb]uild[Ll]og.*
|
|
||||||
|
|
||||||
*_i.c
|
|
||||||
*_p.c
|
|
||||||
*.ilk
|
|
||||||
*.meta
|
|
||||||
*.obj
|
|
||||||
*.pch
|
|
||||||
*.pdb
|
|
||||||
*.pgc
|
|
||||||
*.pgd
|
|
||||||
*.rsp
|
|
||||||
*.sbr
|
|
||||||
*.tlb
|
|
||||||
*.tli
|
|
||||||
*.tlh
|
|
||||||
*.tmp
|
|
||||||
*.tmp_proj
|
|
||||||
*.log
|
|
||||||
*.vspscc
|
|
||||||
*.vssscc
|
|
||||||
.builds
|
|
||||||
*.pidb
|
|
||||||
*.log
|
|
||||||
*.scc
|
|
||||||
|
|
||||||
# Visual C++ cache files
|
|
||||||
ipch/
|
|
||||||
*.aps
|
|
||||||
*.ncb
|
|
||||||
*.opensdf
|
|
||||||
*.sdf
|
|
||||||
*.cachefile
|
|
||||||
|
|
||||||
# Visual Studio profiler
|
|
||||||
*.psess
|
|
||||||
*.vsp
|
|
||||||
*.vspx
|
|
||||||
|
|
||||||
# Guidance Automation Toolkit
|
|
||||||
*.gpState
|
|
||||||
|
|
||||||
# ReSharper is a .NET coding add-in
|
|
||||||
_ReSharper*/
|
|
||||||
*.[Rr]e[Ss]harper
|
|
||||||
|
|
||||||
# TeamCity is a build add-in
|
|
||||||
_TeamCity*
|
|
||||||
|
|
||||||
# DotCover is a Code Coverage Tool
|
|
||||||
*.dotCover
|
|
||||||
|
|
||||||
# NCrunch
|
|
||||||
*.ncrunch*
|
|
||||||
.*crunch*.local.xml
|
|
||||||
|
|
||||||
# Installshield output folder
|
|
||||||
[Ee]xpress/
|
|
||||||
|
|
||||||
# DocProject is a documentation generator add-in
|
|
||||||
DocProject/buildhelp/
|
|
||||||
DocProject/Help/*.HxT
|
|
||||||
DocProject/Help/*.HxC
|
|
||||||
DocProject/Help/*.hhc
|
|
||||||
DocProject/Help/*.hhk
|
|
||||||
DocProject/Help/*.hhp
|
|
||||||
DocProject/Help/Html2
|
|
||||||
DocProject/Help/html
|
|
||||||
|
|
||||||
# Click-Once directory
|
|
||||||
publish/
|
|
||||||
|
|
||||||
# Publish Web Output
|
|
||||||
*.Publish.xml
|
|
||||||
*.pubxml
|
|
||||||
|
|
||||||
# NuGet Packages Directory
|
|
||||||
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
|
|
||||||
#packages/
|
|
||||||
|
|
||||||
# Windows Azure Build Output
|
|
||||||
csx
|
|
||||||
*.build.csdef
|
|
||||||
|
|
||||||
# Windows Store app package directory
|
|
||||||
AppPackages/
|
|
||||||
|
|
||||||
# Others
|
|
||||||
sql/
|
|
||||||
*.Cache
|
|
||||||
ClientBin/
|
|
||||||
[Ss]tyle[Cc]op.*
|
|
||||||
~$*
|
|
||||||
*~
|
|
||||||
*.dbmdl
|
|
||||||
*.[Pp]ublish.xml
|
|
||||||
*.pfx
|
|
||||||
*.publishsettings
|
|
||||||
|
|
||||||
# RIA/Silverlight projects
|
|
||||||
Generated_Code/
|
|
||||||
|
|
||||||
# Backup & report files from converting an old project file to a newer
|
|
||||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
|
||||||
_UpgradeReport_Files/
|
|
||||||
Backup*/
|
|
||||||
UpgradeLog*.XML
|
|
||||||
UpgradeLog*.htm
|
|
||||||
|
|
||||||
# SQL Server files
|
|
||||||
App_Data/*.mdf
|
|
||||||
App_Data/*.ldf
|
|
||||||
|
|
||||||
#############
|
|
||||||
## Windows detritus
|
|
||||||
#############
|
|
||||||
|
|
||||||
# Windows image file caches
|
|
||||||
Thumbs.db
|
|
||||||
ehthumbs.db
|
|
||||||
|
|
||||||
# Folder config file
|
|
||||||
Desktop.ini
|
|
||||||
|
|
||||||
# Recycle Bin used on file shares
|
|
||||||
$RECYCLE.BIN/
|
|
||||||
|
|
||||||
# Mac crap
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
|
|
||||||
#############
|
|
||||||
## Python
|
|
||||||
#############
|
|
||||||
|
|
||||||
*.py[co]
|
|
||||||
|
|
||||||
# Packages
|
|
||||||
*.egg
|
|
||||||
*.egg-info
|
|
||||||
dist/
|
|
||||||
build/
|
|
||||||
eggs/
|
|
||||||
parts/
|
|
||||||
var/
|
|
||||||
sdist/
|
|
||||||
develop-eggs/
|
|
||||||
.installed.cfg
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
.coverage
|
|
||||||
.tox
|
|
||||||
|
|
||||||
#Translations
|
|
||||||
*.mo
|
|
||||||
|
|
||||||
#Mr Developer
|
|
||||||
.mr.developer.cfg
|
|
@ -1,16 +0,0 @@
|
|||||||
Change Log for IRLib – an Arduino library for infrared encoding and decoding
|
|
||||||
Copyright 2013 by Chris Young http://cyborg5.com
|
|
||||||
|
|
||||||
April 2013 Version 1.1 Constructor of IRsendBase now initializes output
|
|
||||||
pin and forces it low immediately.
|
|
||||||
|
|
||||||
New IRrecv::No_Output() method initializes output
|
|
||||||
pin and forces it low. Use this in sketches which
|
|
||||||
receive only by the have output hardware connected.
|
|
||||||
|
|
||||||
Added examples IRservo and IRserial_remote
|
|
||||||
|
|
||||||
February 2013 Version 1.0a Removed debugging test switch which was accidentally
|
|
||||||
left on in file "IRLib.h"
|
|
||||||
|
|
||||||
January 2013 Version 1.0 Initial Release
|
|
@ -1,988 +0,0 @@
|
|||||||
/* IRLib.cpp from IRLib – an Arduino library for infrared encoding and decoding
|
|
||||||
* Version 1.1 April 2013
|
|
||||||
* Copyright 2013 by Chris Young http://cyborg5.com
|
|
||||||
*
|
|
||||||
* Port to Digispark (size optimization) August 2013
|
|
||||||
* by RC Navy http://p.loussouarn.free.fr
|
|
||||||
*
|
|
||||||
* This library is a major rewrite of IRemote by Ken Shirriff which was covered by
|
|
||||||
* GNU LESSER GENERAL PUBLIC LICENSE which as I read it allows me to make modified versions.
|
|
||||||
* That same license applies to this modified version. See his original copyright below.
|
|
||||||
* The latest Ken Shirriff code can be found at https://github.com/shirriff/Arduino-IRremote
|
|
||||||
* My purpose was to reorganize the code to make it easier to add or remove protocols.
|
|
||||||
* As a result I have separated the act of receiving a set of raw timing codes from the act of decoding them
|
|
||||||
* by making them separate classes. That way the receiving aspect can be more black box and implementers
|
|
||||||
* of decoders and senders can just deal with the decoding of protocols.
|
|
||||||
* Also added provisions to make the classes base classes that could be extended with new protocols
|
|
||||||
* which would not require recompiling of the original library nor understanding of its detailed contents.
|
|
||||||
* Some of the changes were made to reduce code size such as unnecessary use of long versus bool.
|
|
||||||
* Some changes were just my weird programming style. Also extended debugging information added.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* IRremote
|
|
||||||
* Version 0.1 July, 2009
|
|
||||||
* Copyright 2009 Ken Shirriff
|
|
||||||
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com
|
|
||||||
*
|
|
||||||
* Interrupt code based on NECIRrcv by Joe Knapp
|
|
||||||
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
|
|
||||||
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "IRLib.h"
|
|
||||||
#include "IRLibMatch.h"
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns a pointer to a flash stored string that is the name of the protocol received.
|
|
||||||
*/
|
|
||||||
#if defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
|
||||||
const char *Pnames(IRTYPES Type) {
|
|
||||||
return(NULL);
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
const __FlashStringHelper *Pnames(IRTYPES Type) {
|
|
||||||
if(Type>LAST_PROTOCOL) Type=UNKNOWN;
|
|
||||||
const __FlashStringHelper *Names[LAST_PROTOCOL+1]={F("Unknown"),
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NEC)
|
|
||||||
F("NEC")
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL)
|
|
||||||
,
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_SONY)
|
|
||||||
F("Sony")
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL)
|
|
||||||
,
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC5)
|
|
||||||
F("RC5")
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL)
|
|
||||||
,
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC6)
|
|
||||||
F("RC6")
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL)
|
|
||||||
,
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_PANASONIC_OLD)
|
|
||||||
F("Panasonic Old")
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL)
|
|
||||||
,
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_JVC)
|
|
||||||
F("JVC")
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL)
|
|
||||||
,
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NECX)
|
|
||||||
F("NECx")
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL)
|
|
||||||
,
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_HASH_CODE)
|
|
||||||
F("Hash Code")
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
#if defined(ALL_IR_PROTOCOL)
|
|
||||||
return Names[Type];
|
|
||||||
#else
|
|
||||||
return Names[!!Type];
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define RC5_T1 889
|
|
||||||
#define RC5_RPT_LENGTH 46000
|
|
||||||
|
|
||||||
#define RC6_HDR_MARK 2666
|
|
||||||
#define RC6_HDR_SPACE 889
|
|
||||||
#define RC6_T1 444
|
|
||||||
|
|
||||||
#ifdef USE_IR_SEND
|
|
||||||
|
|
||||||
#define TOPBIT 0x80000000
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The IRsend classes contain a series of methods for sending various protocols.
|
|
||||||
* Each of these begin by calling enableIROut(int kHz) to set the carrier frequency.
|
|
||||||
* It then calls mark(int usec) and space(inc usec) to transmit marks and
|
|
||||||
* spaces of varying length of microseconds however the protocol defines.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Most of the protocols have a header consisting of a mark/space of a particular length followed by
|
|
||||||
* a series of variable length mark/space signals. Depending on the protocol they very the links of the
|
|
||||||
* mark or the space to indicate a data bit of "0" or "1". Most also end with a stop bit of "1".
|
|
||||||
* The basic structure of the sending and decoding these protocols led to lots of redundant code.
|
|
||||||
* Therefore I have implemented generic sending and decoding routines. You just need to pass a bunch of customized
|
|
||||||
* parameters and it does the work. This reduces compiled code size with only minor speed degradation.
|
|
||||||
* You may be able to implement additional protocols by simply passing the proper values to these generic routines.
|
|
||||||
* The decoding routines do not encode stop bits. So you have to tell this routine whether or not to send one.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void IRsendBase::sendGeneric(unsigned long data, int Num_Bits, int Head_Mark, int Head_Space, int Mark_One, int Mark_Zero, int Space_One, int Space_Zero, int mHz, bool Use_Stop) {
|
|
||||||
data = data << (32 - Num_Bits);
|
|
||||||
enableIROut(mHz);
|
|
||||||
//Some protocols do not send a header when sending repeat codes. So we pass a zero value to indicate skipping this.
|
|
||||||
if(Head_Mark) mark(Head_Mark);
|
|
||||||
if(Head_Space) space(Head_Space);
|
|
||||||
for (int i = 0; i <Num_Bits; i++) {
|
|
||||||
if (data & TOPBIT) {
|
|
||||||
mark(Mark_One); space(Space_One);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mark(Mark_Zero); space(Space_Zero);
|
|
||||||
}
|
|
||||||
data <<= 1;
|
|
||||||
}
|
|
||||||
if (Use_Stop) mark(Mark_One); space(0) ; //stop bit of "1"
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NEC)
|
|
||||||
void IRsendNEC::send(unsigned long data)
|
|
||||||
{
|
|
||||||
ATTEMPT_MESSAGE(F("sending NEC"));
|
|
||||||
if (data==REPEAT) {
|
|
||||||
mark (564* 16); space (564*4); mark(564);space (96000);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sendGeneric(data,32, 564*16, 564*8, 564, 564, 564*3, 564, 38, true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_SONY)
|
|
||||||
/*
|
|
||||||
* Sony is backwards from most protocols. It uses a variable length mark and a fixed length space rather than
|
|
||||||
* a fixed mark and a variable space. Our generic send will still work. According to the protocol you must send
|
|
||||||
* Sony commands at least three times so we automatically do it here.
|
|
||||||
*/
|
|
||||||
void IRsendSony::send(unsigned long data, int nbits) {
|
|
||||||
for(int i=0; i<3;i++)
|
|
||||||
sendGeneric(data,nbits, 600*4, 600, 600*2, 600, 600, 600, 40, false);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NECX)
|
|
||||||
/*
|
|
||||||
* This next section of send routines were added by Chris Young. They all use the generic send.
|
|
||||||
*/
|
|
||||||
void IRsendNECx::send(unsigned long data)
|
|
||||||
{
|
|
||||||
sendGeneric(data,32, 564*8, 564*8, 564, 564, 564*3, 564, 38, true);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_PANASONIC_OLD)
|
|
||||||
void IRsendPanasonic_Old::send(unsigned long data)
|
|
||||||
{
|
|
||||||
sendGeneric(data,22, 833*4, 833*4, 833, 833, 833*3, 833,57, true);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_JVC)
|
|
||||||
/*
|
|
||||||
* JVC omits the Mark/space header on repeat sending. Therefore we multiply it by 0 if it's a repeat.
|
|
||||||
* The only device I had to test this protocol was an old JVC VCR. It would only work if at least
|
|
||||||
* 2 frames are sent separated by 45us of "space". Therefore you should call this routine once with
|
|
||||||
* "First=true"and it will send a first frame followed by one repeat frame. If First== false,
|
|
||||||
* it will only send a single repeat frame.
|
|
||||||
*/
|
|
||||||
void IRsendJVC::send(unsigned long data, bool First)
|
|
||||||
{
|
|
||||||
sendGeneric(data, 16,525*16*First, 525*8*First, 525, 525,525*3, 525, 38, true);
|
|
||||||
delayMicroseconds(45);
|
|
||||||
if(First) sendGeneric(data, 16,0,0, 525, 525,525*3, 525, 38, true);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The remaining protocols require special treatment. They were in the original IRremote library.
|
|
||||||
*/
|
|
||||||
void IRsendRaw::send(unsigned int buf[], int len, int hz)
|
|
||||||
{
|
|
||||||
enableIROut(hz);
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
if (i & 1) {
|
|
||||||
space(buf[i]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mark(buf[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
space(0); // Just to be sure
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* The RC5 protocol uses a phase encoding of data bits. A space/mark pair indicates "1"
|
|
||||||
* and a mark/space indicates a "0". It begins with a single "1" bit which is not encoded
|
|
||||||
* in the data. The high order data bit is a toggle bit that indicates individual
|
|
||||||
* keypresses. You must toggle this bit yourself when sending data.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void IRsendRC5::send(unsigned long data)
|
|
||||||
{
|
|
||||||
enableIROut(36);
|
|
||||||
data = data << (32 - 13);
|
|
||||||
mark(RC5_T1); // First start bit
|
|
||||||
//Note: Original IRremote library incorrectly assumed second bit was always a "1"
|
|
||||||
//bit patterns from this decoder are not backward compatible with patterns produced
|
|
||||||
//by original library. Ucomment the following two lines to maintain backward compatibility.
|
|
||||||
//space(RC5_T1); // Second start bit
|
|
||||||
//mark(RC5_T1); // Second start bit
|
|
||||||
for (int i = 0; i < 13; i++) {
|
|
||||||
if (data & TOPBIT) {
|
|
||||||
space(RC5_T1); mark(RC5_T1);// 1 is space, then mark
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mark(RC5_T1); space(RC5_T1);// 0 is mark, then space
|
|
||||||
}
|
|
||||||
data <<= 1;
|
|
||||||
}
|
|
||||||
space(0); // Turn off at end
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The RC6 protocol also phase encodes databits although the phasing is opposite of RC5.
|
|
||||||
*/
|
|
||||||
void IRsendRC6::send(unsigned long data, int nbits)
|
|
||||||
{
|
|
||||||
enableIROut(36);
|
|
||||||
data = data << (32 - nbits);
|
|
||||||
mark(RC6_HDR_MARK); space(RC6_HDR_SPACE);
|
|
||||||
mark(RC6_T1); space(RC6_T1);// start bit "1"
|
|
||||||
int t;
|
|
||||||
for (int i = 0; i < nbits; i++) {
|
|
||||||
if (i == 3) {
|
|
||||||
t = 2 * RC6_T1; // double-wide trailer bit
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
t = RC6_T1;
|
|
||||||
}
|
|
||||||
if (data & TOPBIT) {
|
|
||||||
mark(t); space(t);//"1" is a Mark/space
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
space(t); mark(t);//"0" is a space/Mark
|
|
||||||
}
|
|
||||||
data <<= 1;
|
|
||||||
}
|
|
||||||
space(0); // Turn off at end
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* This method can be used to send any of the supported types except for raw and hash code.
|
|
||||||
* There is no hash code send possible. You can call sendRaw directly if necessary.
|
|
||||||
*/
|
|
||||||
void IRsend::send(IRTYPES Type, unsigned long data, int nbits) {
|
|
||||||
switch(Type) {
|
|
||||||
case NEC: IRsendNEC::send(data); break;
|
|
||||||
case SONY: IRsendSony::send(data,nbits); break;
|
|
||||||
case RC5: IRsendRC5::send(data); break;
|
|
||||||
case RC6: IRsendRC6::send(data,nbits); break;
|
|
||||||
case PANASONIC_OLD: IRsendPanasonic_Old::send(data); break;
|
|
||||||
case NECX: IRsendNECx::send(data); break;
|
|
||||||
case JVC: IRsendJVC::send(data,(bool)nbits); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Although I tried to keep all of the interrupt handling code at the bottom of this file
|
|
||||||
* so you didn't have to mess with it if you didn't want to, I needed to move this definition
|
|
||||||
* forwarded so it could be used by IRdecodeBase constructor.
|
|
||||||
*/
|
|
||||||
// receiver states
|
|
||||||
enum rcvstate_t {STATE_UNKNOWN, STATE_IDLE, STATE_MARK, STATE_SPACE, STATE_STOP};
|
|
||||||
// information for the interrupt handler
|
|
||||||
typedef struct {
|
|
||||||
uint8_t recvpin; // pin for IR data from detector
|
|
||||||
rcvstate_t rcvstate; // state machine
|
|
||||||
uint8_t blinkflag; // TRUE to enable blinking of pin 13 on IR processing
|
|
||||||
unsigned int timer; // state timer, counts 50uS ticks.
|
|
||||||
unsigned int rawbuf[RAWBUF]; // raw data
|
|
||||||
uint8_t rawlen; // counter of entries in rawbuf
|
|
||||||
}
|
|
||||||
irparams_t;
|
|
||||||
volatile irparams_t irparams;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We've chosen to separate the decoding routines from the receiving routines to isolate
|
|
||||||
* the technical hardware and interrupt portion of the code which should never need modification
|
|
||||||
* from the protocol decoding portion that will likely be extended and modified.
|
|
||||||
*/
|
|
||||||
IRdecodeBase::IRdecodeBase(void) {
|
|
||||||
rawbuf=(volatile unsigned int*)irparams.rawbuf;
|
|
||||||
Reset();
|
|
||||||
};
|
|
||||||
/*
|
|
||||||
* Normally the decoder uses irparams.rawbuf but if you want to resume receiving while
|
|
||||||
* still decoding you can define a separate buffer and pass the address here.
|
|
||||||
* Then IRrecv::GetResults will copy the raw values from its buffer to yours allowing you to
|
|
||||||
* call IRrecv::resume immediately before you call decode.
|
|
||||||
*/
|
|
||||||
void IRdecodeBase::UseExtnBuf(void *P){
|
|
||||||
rawbuf=(volatile unsigned int*)P;
|
|
||||||
};
|
|
||||||
/*
|
|
||||||
* Copies rawbuf and rawlen from one decoder to another. See IRhashdecode example
|
|
||||||
* for usage.
|
|
||||||
*/
|
|
||||||
void IRdecodeBase::copyBuf (IRdecodeBase *source){
|
|
||||||
memcpy((void *)rawbuf,(const void *)source->rawbuf,sizeof(irparams.rawbuf));
|
|
||||||
rawlen=source->rawlen;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This routine is actually quite useful. See the Samsung36 sketch in the examples
|
|
||||||
*/
|
|
||||||
bool IRdecodeBase::decode(void) {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
void IRdecodeBase::Reset(void) {
|
|
||||||
decode_type= UNKNOWN;
|
|
||||||
value=0;
|
|
||||||
bits=0;
|
|
||||||
rawlen=0;
|
|
||||||
};
|
|
||||||
/*
|
|
||||||
* This method dumps useful information about the decoded values.
|
|
||||||
*/
|
|
||||||
void IRdecodeBase::DumpResults(void) {
|
|
||||||
int i;
|
|
||||||
if(decode_type<=LAST_PROTOCOL){
|
|
||||||
Serial.print(F("Decoded ")); Serial.print(Pnames(decode_type));
|
|
||||||
Serial.print(F(": Value:")); Serial.print(value, HEX);
|
|
||||||
};
|
|
||||||
#ifdef DETAILLED_DUMP
|
|
||||||
Serial.print(F(" (")); Serial.print(bits, DEC); Serial.println(F(" bits)"));
|
|
||||||
Serial.print(F("Raw samples(")); Serial.print(rawlen, DEC);
|
|
||||||
Serial.print(F("): Gap:")); Serial.println(Interval_uSec(0), DEC);
|
|
||||||
Serial.print(F(" Head: m")); Serial.print(Interval_uSec(1), DEC);
|
|
||||||
Serial.print(F(" s")); Serial.println(Interval_uSec(2), DEC);
|
|
||||||
int LowSpace= 32767; int LowMark= 32767;
|
|
||||||
int HiSpace=0; int HiMark= 0;
|
|
||||||
for (i = 3; i < rawlen; i++) {
|
|
||||||
int interval= Interval_uSec(i);
|
|
||||||
if (i % 2) {
|
|
||||||
LowMark=min(LowMark, interval); HiMark=max(HiMark, interval);
|
|
||||||
Serial.print(i/2-1,DEC); Serial.print(F(":m"));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(interval>0)LowSpace=min(LowSpace, interval); HiSpace=max (HiSpace, interval);
|
|
||||||
Serial.print(F(" s"));
|
|
||||||
}
|
|
||||||
Serial.print(interval, DEC);
|
|
||||||
int j=i-1;
|
|
||||||
if ((j % 2)==1)Serial.print(F("\t"));
|
|
||||||
if ((j % 4)==1)Serial.print(F("\t "));
|
|
||||||
if ((j % 8)==1)Serial.println();
|
|
||||||
if ((j % 32)==1)Serial.println();
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
Serial.print(F("Mark min:")); Serial.print(LowMark,DEC);Serial.print(F("\t max:")); Serial.println(HiMark,DEC);
|
|
||||||
Serial.print(F("Space min:")); Serial.print(LowSpace,DEC);Serial.print(F("\t max:")); Serial.println(HiSpace,DEC);
|
|
||||||
#endif
|
|
||||||
Serial.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This handy little routine converts ticks from rawbuf[index] into uSec intervals adjusting for the
|
|
||||||
* Mark/space bias.
|
|
||||||
*/
|
|
||||||
unsigned long IRdecodeBase::Interval_uSec(int index)
|
|
||||||
{
|
|
||||||
return rawbuf[index]*USECPERTICK+( (index%2)?-MARK_EXCESS: MARK_EXCESS);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Again we use a generic routine because most protocols have the same basic structure. However we need to
|
|
||||||
* indicate whether or not the protocol varies the length of the mark or the space to indicate a "0" or "1".
|
|
||||||
* If "Mark_One" is zero. We assume that the length of the space varies. If "Mark_One" is not zero then
|
|
||||||
* we assume that the length of Mark varies and the value passed as "Space_Zero" is ignored.
|
|
||||||
* When using variable length Mark, assumes Head_Space==Space_One. If it doesn't, you need a specialized decoder.
|
|
||||||
*/
|
|
||||||
bool IRdecodeBase::decodeGeneric(/*int*/int8_t Raw_Count, int Head_Mark,int Head_Space, int Mark_One, int Mark_Zero, int Space_One,int Space_Zero) {
|
|
||||||
// If raw samples count or head mark are zero then don't perform these tests.
|
|
||||||
// Some protocols need to do custom header work.
|
|
||||||
long data = 0; /*int*/int8_t Max; /*int*/int8_t offset;
|
|
||||||
if (Raw_Count) {if (rawlen != Raw_Count) return RAW_COUNT_ERROR;}
|
|
||||||
if (Head_Mark) {if (!MATCH_MARK(rawbuf[1],Head_Mark)) return HEADER_MARK_ERROR;}
|
|
||||||
if (Head_Space) {if (!MATCH_SPACE(rawbuf[2],Head_Space)) return HEADER_SPACE_ERROR;}
|
|
||||||
|
|
||||||
if (Mark_One) {//Length of a mark indicates data "0" or "1". Space_Zero is ignored.
|
|
||||||
offset=2;//skip initial gap plus header Mark.
|
|
||||||
Max=rawlen;
|
|
||||||
while (offset < Max) {
|
|
||||||
if (!MATCH_SPACE(rawbuf[offset], Space_One)) return DATA_SPACE_ERROR;
|
|
||||||
offset++;
|
|
||||||
if (MATCH_MARK(rawbuf[offset], Mark_One)) {
|
|
||||||
data = (data << 1) | 1;
|
|
||||||
}
|
|
||||||
else if (MATCH_MARK(rawbuf[offset], Mark_Zero)) {
|
|
||||||
data <<= 1;
|
|
||||||
}
|
|
||||||
else return DATA_MARK_ERROR;
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
bits = (offset - 1) / 2;
|
|
||||||
}
|
|
||||||
else {//Mark_One was 0 therefore length of a space indicates data "0" or "1".
|
|
||||||
Max=rawlen-1; //ignore stop bit
|
|
||||||
offset=3;//skip initial gap plus two header items
|
|
||||||
while (offset < Max) {
|
|
||||||
if (!MATCH_MARK (rawbuf[offset],Mark_Zero)) return DATA_MARK_ERROR;
|
|
||||||
offset++;
|
|
||||||
if (MATCH_SPACE(rawbuf[offset],Space_One)) {
|
|
||||||
data = (data << 1) | 1;
|
|
||||||
}
|
|
||||||
else if (MATCH_SPACE (rawbuf[offset],Space_Zero)) {
|
|
||||||
data <<= 1;
|
|
||||||
}
|
|
||||||
else return DATA_SPACE_ERROR;
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
bits = (offset - 1) / 2 -1;//didn't encode stop bit
|
|
||||||
}
|
|
||||||
// Success
|
|
||||||
value = data;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This routine has been modified significantly from the original IRremote.
|
|
||||||
* It assumes you've already called IRrecvBase::GetResults and it was true.
|
|
||||||
* The purpose of GetResults is to determine if a complete set of signals
|
|
||||||
* has been received. It then copies the raw data into your decode_results
|
|
||||||
* structure. By moving the test for completion and the copying of the buffer
|
|
||||||
* outside of this "decode" method you can use the individual decode
|
|
||||||
* methods or make your own custom "decode" without checking for
|
|
||||||
* protocols you don't use.
|
|
||||||
* Note: Don't forget to call IRrecvBase::resume(); after decoding is complete.
|
|
||||||
*/
|
|
||||||
bool IRdecode::decode(void) {
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NEC)
|
|
||||||
if (IRdecodeNEC::decode()) return true;
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_SONY)
|
|
||||||
if (IRdecodeSony::decode()) return true;
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC5)
|
|
||||||
if (IRdecodeRC5::decode()) return true;
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC6)
|
|
||||||
if (IRdecodeRC6::decode()) return true;
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_PANASONIC_OLD)
|
|
||||||
if (IRdecodePanasonic_Old::decode()) return true;
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NECX)
|
|
||||||
if (IRdecodeNECx::decode()) return true;
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_JVC)
|
|
||||||
if (IRdecodeJVC::decode()) return true;
|
|
||||||
#endif
|
|
||||||
//Deliberately did not add hash code decoding. If you get decode_type==UNKNOWN and
|
|
||||||
// you want to know a hash code you can call IRhash::decode() yourself.
|
|
||||||
// BTW This is another reason we separated IRrecv from IRdecode.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NEC)
|
|
||||||
#define NEC_RPT_SPACE 2250
|
|
||||||
bool IRdecodeNEC::decode(void) {
|
|
||||||
ATTEMPT_MESSAGE(F("NEC"));
|
|
||||||
// Check for repeat
|
|
||||||
if (rawlen == 4 && MATCH_SPACE(rawbuf[2], NEC_RPT_SPACE) &&
|
|
||||||
MATCH_MARK(rawbuf[3],564)) {
|
|
||||||
bits = 0;
|
|
||||||
value = REPEAT;
|
|
||||||
decode_type = NEC;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if(!decodeGeneric(68, 564*16, 564*8, 0, 564, 564*3, 564)) return false;
|
|
||||||
decode_type = NEC;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_SONY)
|
|
||||||
// According to http://www.hifi-remote.com/johnsfine/DecodeIR.html#Sony8
|
|
||||||
// Sony protocol can only be 8, 12, 15, or 20 bits in length.
|
|
||||||
bool IRdecodeSony::decode(void) {
|
|
||||||
ATTEMPT_MESSAGE(F("Sony"));
|
|
||||||
if(rawlen!=2*8+2 && rawlen!=2*12+2 && rawlen!=2*15+2 && rawlen!=2*20+2) return RAW_COUNT_ERROR;
|
|
||||||
if(!decodeGeneric(0, 600*4, 600, 600*2, 600, 600,0)) return false;
|
|
||||||
decode_type = SONY;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The next several decoders were added by Chris Young. They illustrate some of the special cases
|
|
||||||
* that can come up when decoding using the generic decoder.
|
|
||||||
*/
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_PANASONIC_OLD)
|
|
||||||
/*
|
|
||||||
* A very good source for protocol information is… http://www.hifi-remote.com/johnsfine/DecodeIR.html
|
|
||||||
* I used that information to understand what they call the "Panasonic old" protocol which is used by
|
|
||||||
* Scientific Atlanta cable boxes. That website uses a very strange notation called IRP notation.
|
|
||||||
* For this protocol, the notation was:
|
|
||||||
* {57.6k,833}<1,-1|1,-3>(4,-4,D:5,F:6,~D:5,~F:6,1,-???)+
|
|
||||||
* This indicates that the frequency is 57.6, the base length for the pulse is 833
|
|
||||||
* The first part of the <x,-x|x,-x> section tells you what a "0" is and the second part
|
|
||||||
* tells you what a "1" is. That means "0" is 833 on, 833 off while an "1" is 833 on
|
|
||||||
* followed by 833*3=2499 off. The section in parentheses tells you what data gets sent.
|
|
||||||
* The protocol begins with header consisting of 4*833 on and 4*833 off. The other items
|
|
||||||
* describe what the remaining data bits are.
|
|
||||||
* It reads as 5 device bits followed by 6 function bits. You then repeat those bits complemented.
|
|
||||||
* It concludes with a single "1" bit followed by and an undetermined amount of blank space.
|
|
||||||
* This makes the entire protocol 5+6+5+6= 22 bits long since we don't encode the stop bit.
|
|
||||||
* The "+" at the end means you only need to send it once and it can repeat as many times as you want.
|
|
||||||
*/
|
|
||||||
bool IRdecodePanasonic_Old::decode(void) {
|
|
||||||
ATTEMPT_MESSAGE(F("Panasonic_Old"));
|
|
||||||
if(!decodeGeneric(48,833*4,833*4,0,833,833*3,833)) return false;
|
|
||||||
/*
|
|
||||||
* The protocol spec says that the first 11 bits described the device and function.
|
|
||||||
* The next 11 bits are the same thing only it is the logical Bitwise complement.
|
|
||||||
* Many protocols have such check features in their definition but our code typically doesn't
|
|
||||||
* perform these checks. For example NEC's least significant 8 bits are the complement of
|
|
||||||
* of the next more significant 8 bits. While it's probably not necessary to error check this,
|
|
||||||
* here is some sample code to show you how.
|
|
||||||
*/
|
|
||||||
long S1= (value & 0x0007ff); // 00 0000 0000 0111 1111 1111 //00000 000000 11111 111111
|
|
||||||
long S2= (value & 0x3ff800)>> 11; // 11 1111 1111 1000 0000 0000 //11111 111111 00000 000000
|
|
||||||
S2= (~S2) & 0x0007ff;
|
|
||||||
if (S1!=S2) {REJECTION_MESSAGE(F("inverted bit redundancy")); return false;};
|
|
||||||
// Success
|
|
||||||
decode_type = PANASONIC_OLD;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NECX)
|
|
||||||
bool IRdecodeNECx::decode(void) {
|
|
||||||
ATTEMPT_MESSAGE(F("NECx"));
|
|
||||||
if(!decodeGeneric(68,564*8,564*8,0,564,564*3,564)) return false;
|
|
||||||
decode_type = NECX;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_JVC)
|
|
||||||
// JVC does not send any header if there is a repeat.
|
|
||||||
bool IRdecodeJVC::decode(void) {
|
|
||||||
ATTEMPT_MESSAGE(F("JVC"));
|
|
||||||
if(!decodeGeneric(36,525*16,525*8,0,525,525*3,525))
|
|
||||||
{
|
|
||||||
ATTEMPT_MESSAGE(F("JVC Repeat"));
|
|
||||||
if (rawlen==34)
|
|
||||||
{
|
|
||||||
if(!decodeGeneric(0,525,0,0,525,525*3,525))
|
|
||||||
{REJECTION_MESSAGE(F("JVC repeat failed generic")); return false;}
|
|
||||||
else {
|
|
||||||
//If this is a repeat code then IRdecodeBase::decode fails to add the most significant bit
|
|
||||||
if (MATCH_SPACE(rawbuf[4],(525*3)))
|
|
||||||
{
|
|
||||||
value |= 0x8000;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!MATCH_SPACE(rawbuf[4],525)) return DATA_SPACE_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bits++;
|
|
||||||
}
|
|
||||||
else return RAW_COUNT_ERROR;
|
|
||||||
}
|
|
||||||
decode_type =JVC;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC5) || (MY_IR_PROTOCOL == PROTO_RC6)
|
|
||||||
/*
|
|
||||||
* The remaining protocols from the original IRremote library require special handling
|
|
||||||
* This routine gets one undecoded level at a time from the raw buffer.
|
|
||||||
* The RC5/6 decoding is easier if the data is broken into time intervals.
|
|
||||||
* E.g. if the buffer has MARK for 2 time intervals and SPACE for 1,
|
|
||||||
* successive calls to getRClevel will return MARK, MARK, SPACE.
|
|
||||||
* offset and used are updated to keep track of the current position.
|
|
||||||
* t1 is the time interval for a single bit in microseconds.
|
|
||||||
* Returns ERROR if the measured time interval is not a multiple of t1.
|
|
||||||
*/
|
|
||||||
IRdecodeRC::RCLevel IRdecodeRC::getRClevel(int *offset, int *used, int t1) {
|
|
||||||
if (*offset >= rawlen) {
|
|
||||||
// After end of recorded buffer, assume SPACE.
|
|
||||||
return SPACE;
|
|
||||||
}
|
|
||||||
int width = rawbuf[*offset];
|
|
||||||
IRdecodeRC::RCLevel val;
|
|
||||||
if ((*offset) % 2) val=MARK; else val=SPACE;
|
|
||||||
int correction = (val == MARK) ? MARK_EXCESS : - MARK_EXCESS;
|
|
||||||
|
|
||||||
int avail;
|
|
||||||
if (MATCH(width, t1 + correction)) {
|
|
||||||
avail = 1;
|
|
||||||
}
|
|
||||||
else if (MATCH(width, 2*t1 + correction)) {
|
|
||||||
avail = 2;
|
|
||||||
}
|
|
||||||
else if (MATCH(width, 3*t1 + correction)) {
|
|
||||||
avail = 3;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return ERROR;
|
|
||||||
}
|
|
||||||
(*used)++;
|
|
||||||
if (*used >= avail) {
|
|
||||||
*used = 0;
|
|
||||||
(*offset)++;
|
|
||||||
}
|
|
||||||
#ifdef DEBUG
|
|
||||||
if (val == MARK) Serial.println("MARK"); else Serial.println("SPACE");
|
|
||||||
#endif
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MIN_RC5_SAMPLES 11
|
|
||||||
#define MIN_RC6_SAMPLES 1
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC5)
|
|
||||||
bool IRdecodeRC5::decode(void) {
|
|
||||||
ATTEMPT_MESSAGE(F("RC5"));
|
|
||||||
if (rawlen < MIN_RC5_SAMPLES + 2) return RAW_COUNT_ERROR;
|
|
||||||
int offset = 1; // Skip gap space
|
|
||||||
long data = 0;
|
|
||||||
int used = 0;
|
|
||||||
// Get start bits
|
|
||||||
if (getRClevel(&offset, &used, RC5_T1) != MARK) return HEADER_MARK_ERROR;
|
|
||||||
//Note: Original IRremote library incorrectly assumed second bit was always a "1"
|
|
||||||
//bit patterns from this decoder are not backward compatible with patterns produced
|
|
||||||
//by original library. Ucomment the following two lines to maintain backward compatibility.
|
|
||||||
//if (getRClevel(&offset, &used, RC5_T1) != SPACE) return HEADER_SPACE_ERROR;
|
|
||||||
//if (getRClevel(&offset, &used, RC5_T1) != MARK) return HEADER_MARK_ERROR;
|
|
||||||
int nbits;
|
|
||||||
for (nbits = 0; offset < rawlen; nbits++) {
|
|
||||||
RCLevel levelA = getRClevel(&offset, &used, RC5_T1);
|
|
||||||
RCLevel levelB = getRClevel(&offset, &used, RC5_T1);
|
|
||||||
if (levelA == SPACE && levelB == MARK) {
|
|
||||||
// 1 bit
|
|
||||||
data = (data << 1) | 1;
|
|
||||||
}
|
|
||||||
else if (levelA == MARK && levelB == SPACE) {
|
|
||||||
// zero bit
|
|
||||||
data <<= 1;
|
|
||||||
}
|
|
||||||
else return DATA_MARK_ERROR;
|
|
||||||
}
|
|
||||||
// Success
|
|
||||||
bits = 13;
|
|
||||||
value = data;
|
|
||||||
decode_type = RC5;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC6)
|
|
||||||
bool IRdecodeRC6::decode(void) {
|
|
||||||
ATTEMPT_MESSAGE(F("RC6"));
|
|
||||||
if (rawlen < MIN_RC6_SAMPLES) return RAW_COUNT_ERROR;
|
|
||||||
// Initial mark
|
|
||||||
if (!MATCH_MARK(rawbuf[1], RC6_HDR_MARK)) return HEADER_MARK_ERROR;
|
|
||||||
if (!MATCH_SPACE(rawbuf[2], RC6_HDR_SPACE)) return HEADER_SPACE_ERROR;
|
|
||||||
int offset=3;//Skip gap and header
|
|
||||||
long data = 0;
|
|
||||||
int used = 0;
|
|
||||||
// Get start bit (1)
|
|
||||||
if (getRClevel(&offset, &used, RC6_T1) != MARK) return DATA_MARK_ERROR;
|
|
||||||
if (getRClevel(&offset, &used, RC6_T1) != SPACE) return DATA_SPACE_ERROR;
|
|
||||||
int nbits;
|
|
||||||
for (nbits = 0; offset < rawlen; nbits++) {
|
|
||||||
RCLevel levelA, levelB; // Next two levels
|
|
||||||
levelA = getRClevel(&offset, &used, RC6_T1);
|
|
||||||
if (nbits == 3) {
|
|
||||||
// T bit is double wide; make sure second half matches
|
|
||||||
if (levelA != getRClevel(&offset, &used, RC6_T1)) return TRAILER_BIT_ERROR;
|
|
||||||
}
|
|
||||||
levelB = getRClevel(&offset, &used, RC6_T1);
|
|
||||||
if (nbits == 3) {
|
|
||||||
// T bit is double wide; make sure second half matches
|
|
||||||
if (levelB != getRClevel(&offset, &used, RC6_T1)) return TRAILER_BIT_ERROR;
|
|
||||||
}
|
|
||||||
if (levelA == MARK && levelB == SPACE) { // reversed compared to RC5
|
|
||||||
// 1 bit
|
|
||||||
data = (data << 1) | 1;
|
|
||||||
}
|
|
||||||
else if (levelA == SPACE && levelB == MARK) {
|
|
||||||
// zero bit
|
|
||||||
data <<= 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return DATA_MARK_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Success
|
|
||||||
bits = nbits;
|
|
||||||
value = data;
|
|
||||||
decode_type = RC6;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) //|| (MY_IR_PROTOCOL == HASH_CODE)
|
|
||||||
/*
|
|
||||||
* This Hash decoder is based on IRhashcode
|
|
||||||
* Copyright 2010 Ken Shirriff
|
|
||||||
* For details see http://www.arcfn.com/2010/01/using-arbitrary-remotes-with-arduino.html
|
|
||||||
* Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param
|
|
||||||
* Converts the raw code values into a 32-bit hash code.
|
|
||||||
* Hopefully this code is unique for each button.
|
|
||||||
*/
|
|
||||||
#define FNV_PRIME_32 16777619
|
|
||||||
#define FNV_BASIS_32 2166136261
|
|
||||||
// Compare two tick values, returning 0 if newval is shorter,
|
|
||||||
// 1 if newval is equal, and 2 if newval is longer
|
|
||||||
int IRdecodeHash::compare(unsigned int oldval, unsigned int newval) {
|
|
||||||
if (newval < oldval * .8) return 0;
|
|
||||||
if (oldval < newval * .8) return 2;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IRdecodeHash::decode(void) {
|
|
||||||
hash = FNV_BASIS_32;
|
|
||||||
for (int i = 1; i+2 < rawlen; i++) {
|
|
||||||
hash = (hash * FNV_PRIME_32) ^ compare(rawbuf[i], rawbuf[i+2]);
|
|
||||||
}
|
|
||||||
//note: does not set decode_type=HASH_CODE nor "value" because you might not want to.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This section is all related to interrupt handling and hardware issues. It has nothing to do with IR protocols.
|
|
||||||
* You need not understand this is all you're doing is adding new protocols or improving the decoding and sending
|
|
||||||
* of protocols.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Provides ISR
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
// defines for setting and clearing register bits
|
|
||||||
#ifndef cbi
|
|
||||||
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
|
||||||
#endif
|
|
||||||
#ifndef sbi
|
|
||||||
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
|
|
||||||
#endif
|
|
||||||
#define CLKFUDGE 5 // fudge factor for clock interrupt overhead
|
|
||||||
#ifdef F_CPU
|
|
||||||
#define SYSCLOCK F_CPU // main Arduino clock
|
|
||||||
#else
|
|
||||||
#define SYSCLOCK 16000000 // main Arduino clock
|
|
||||||
#endif
|
|
||||||
#define PRESCALE 8 // timer clock prescale
|
|
||||||
#define CLKSPERUSEC (SYSCLOCK/PRESCALE/1000000) // timer clocks per microsecond
|
|
||||||
|
|
||||||
#include <IRLibTimer.h>
|
|
||||||
|
|
||||||
|
|
||||||
IRrecv::IRrecv(int recvpin)
|
|
||||||
{
|
|
||||||
irparams.recvpin = recvpin;
|
|
||||||
irparams.blinkflag = 0;
|
|
||||||
}
|
|
||||||
/* If your hardware is set up to do both output and input but your particular sketch
|
|
||||||
* doesn't do any output, this method will ensure that your output pin is low
|
|
||||||
* and doesn't turn on your IR LED or any output circuit.
|
|
||||||
*/
|
|
||||||
void IRrecv::No_Output (void) {
|
|
||||||
pinMode(TIMER_PWM_PIN, OUTPUT);
|
|
||||||
digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRrecv::enableIRIn() {
|
|
||||||
// setup pulse clock timer interrupt
|
|
||||||
cli();
|
|
||||||
TIMER_CONFIG_NORMAL();
|
|
||||||
TIMER_ENABLE_INTR;
|
|
||||||
TIMER_RESET;
|
|
||||||
sei();
|
|
||||||
// initialize state machine variables
|
|
||||||
irparams.rcvstate = STATE_IDLE;
|
|
||||||
irparams.rawlen = 0;
|
|
||||||
// set pin modes
|
|
||||||
pinMode(irparams.recvpin, INPUT);
|
|
||||||
}
|
|
||||||
// enable/disable blinking of pin 13 on IR processing
|
|
||||||
void IRrecv::blink13(int blinkflag)
|
|
||||||
{
|
|
||||||
irparams.blinkflag = blinkflag;
|
|
||||||
if (blinkflag)
|
|
||||||
pinMode(BLINKLED, OUTPUT);
|
|
||||||
}
|
|
||||||
void IRrecv::resume() {
|
|
||||||
irparams.rcvstate = STATE_IDLE;
|
|
||||||
irparams.rawlen = 0;
|
|
||||||
}
|
|
||||||
bool IRrecv::GetResults(IRdecodeBase *decoder) {
|
|
||||||
if (irparams.rcvstate != STATE_STOP) return false;
|
|
||||||
decoder->Reset();//clear out any old values.
|
|
||||||
decoder->rawlen = (unsigned int)irparams.rawlen;
|
|
||||||
//By copying the entire array we could call IRrecv::resume immediately while decoding
|
|
||||||
//is still in progress.
|
|
||||||
if(decoder->rawbuf != irparams.rawbuf)
|
|
||||||
memcpy((void *)decoder->rawbuf,(const void *)irparams.rawbuf,sizeof(irparams.rawbuf));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#define _GAP 5000 // Minimum map between transmissions
|
|
||||||
#define GAP_TICKS (_GAP/USECPERTICK)
|
|
||||||
|
|
||||||
// TIMER2 interrupt code to collect raw data.
|
|
||||||
// Widths of alternating SPACE, MARK are recorded in rawbuf.
|
|
||||||
// Recorded in ticks of 50 microseconds.
|
|
||||||
// rawlen counts the number of entries recorded so far.
|
|
||||||
// First entry is the SPACE between transmissions.
|
|
||||||
// As soon as a SPACE gets long, ready is set, state switches to IDLE, timing of SPACE continues.
|
|
||||||
// As soon as first MARK arrives, gap width is recorded, ready is cleared, and new logging starts
|
|
||||||
ISR(TIMER_INTR_NAME)
|
|
||||||
{
|
|
||||||
TIMER_RESET;
|
|
||||||
enum irdata_t {IR_MARK=0, IR_SPACE=1};
|
|
||||||
irdata_t irdata = (irdata_t)digitalRead(irparams.recvpin);
|
|
||||||
irparams.timer++; // One more 50us tick
|
|
||||||
if (irparams.rawlen >= RAWBUF) {
|
|
||||||
// Buffer overflow
|
|
||||||
irparams.rcvstate = STATE_STOP;
|
|
||||||
}
|
|
||||||
switch(irparams.rcvstate) {
|
|
||||||
case STATE_IDLE: // In the middle of a gap
|
|
||||||
if (irdata == IR_MARK) {
|
|
||||||
if (irparams.timer < GAP_TICKS) {
|
|
||||||
// Not big enough to be a gap.
|
|
||||||
irparams.timer = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// gap just ended, record duration and start recording transmission
|
|
||||||
irparams.rawlen = 0;
|
|
||||||
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
|
|
||||||
irparams.timer = 0;
|
|
||||||
irparams.rcvstate = STATE_MARK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case STATE_MARK: // timing MARK
|
|
||||||
if (irdata == IR_SPACE) { // MARK ended, record time
|
|
||||||
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
|
|
||||||
irparams.timer = 0;
|
|
||||||
irparams.rcvstate = STATE_SPACE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case STATE_SPACE: // timing SPACE
|
|
||||||
if (irdata == IR_MARK) { // SPACE just ended, record it
|
|
||||||
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
|
|
||||||
irparams.timer = 0;
|
|
||||||
irparams.rcvstate = STATE_MARK;
|
|
||||||
}
|
|
||||||
else { // SPACE
|
|
||||||
if (irparams.timer > GAP_TICKS) {
|
|
||||||
// big SPACE, indicates gap between codes
|
|
||||||
// Mark current code as ready for processing
|
|
||||||
// Switch to STOP
|
|
||||||
// Don't reset timer; keep counting space width
|
|
||||||
irparams.rcvstate = STATE_STOP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case STATE_STOP: // waiting, measuring gap
|
|
||||||
if (irdata == IR_MARK) { // reset gap timer
|
|
||||||
irparams.timer = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (irparams.blinkflag) {
|
|
||||||
if (irdata == IR_MARK) {
|
|
||||||
BLINKLED_ON(); // turn pin 13 LED on
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
BLINKLED_OFF(); // turn pin 13 LED off
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_IR_SEND
|
|
||||||
IRsendBase::IRsendBase () {
|
|
||||||
pinMode(TIMER_PWM_PIN, OUTPUT);
|
|
||||||
digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRsendBase::enableIROut(int khz) {
|
|
||||||
// Enables IR output. The khz value controls the modulation frequency in kilohertz.
|
|
||||||
// The IR output will be on pin 3 (OC2B).
|
|
||||||
// This routine is designed for 36-40KHz; if you use it for other values, it's up to you
|
|
||||||
// to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.)
|
|
||||||
// TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B
|
|
||||||
// controlling the duty cycle.
|
|
||||||
// There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A)
|
|
||||||
// To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin.
|
|
||||||
// A few hours staring at the ATmega documentation and this will all make sense.
|
|
||||||
// See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details.
|
|
||||||
|
|
||||||
// Disable the Timer2 Interrupt (which is used for receiving IR)
|
|
||||||
TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt
|
|
||||||
pinMode(TIMER_PWM_PIN, OUTPUT);
|
|
||||||
digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low
|
|
||||||
TIMER_CONFIG_KHZ(khz);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRsendBase::mark(int time) {
|
|
||||||
TIMER_ENABLE_PWM;
|
|
||||||
delayMicroseconds(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRsendBase::space(int time) {
|
|
||||||
TIMER_DISABLE_PWM;
|
|
||||||
delayMicroseconds(time);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Various debugging routines
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
int MATCH(int measured, int desired) {
|
|
||||||
Serial.print("Testing: "); Serial.print(TICKS_LOW(desired), DEC);
|
|
||||||
Serial.print(" <= "); Serial.print(measured, DEC); Serial.print(" <= "); Serial.println(TICKS_HIGH(desired), DEC);
|
|
||||||
return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);
|
|
||||||
}
|
|
||||||
|
|
||||||
int MATCH_MARK(int measured_ticks, int desired_us) {
|
|
||||||
Serial.print("Testing mark "); Serial.print(measured_ticks * USECPERTICK, DEC); Serial.print(" vs "); Serial.print(desired_us, DEC); Serial.print(": ");
|
|
||||||
Serial.print(TICKS_LOW(desired_us + MARK_EXCESS), DEC); Serial.print(" <= "); Serial.print(measured_ticks, DEC);
|
|
||||||
Serial.print(" <= "); Serial.println(TICKS_HIGH(desired_us + MARK_EXCESS), DEC);
|
|
||||||
return measured_ticks >= TICKS_LOW(desired_us + MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
int MATCH_SPACE(int measured_ticks, int desired_us) {
|
|
||||||
Serial.print("Testing space "); Serial.print(measured_ticks * USECPERTICK, DEC); Serial.print(" vs "); Serial.print(desired_us, DEC); Serial.print(": ");
|
|
||||||
Serial.print(TICKS_LOW(desired_us - MARK_EXCESS), DEC); Serial.print(" <= "); Serial.print(measured_ticks, DEC);
|
|
||||||
Serial.print(" <= "); Serial.println(TICKS_HIGH(desired_us - MARK_EXCESS), DEC);
|
|
||||||
return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef TRACE
|
|
||||||
void ATTEMPT_MESSAGE(const __FlashStringHelper * s) {Serial.print(F("Attempting ")); Serial.print(s); Serial.println(F(" decode:"));};
|
|
||||||
byte REJECTION_MESSAGE(const __FlashStringHelper * s) { Serial.print(F(" Protocol failed because ")); Serial.print(s); Serial.println(F(" wrong.")); return false;};
|
|
||||||
#endif
|
|
@ -1,318 +0,0 @@
|
|||||||
/* IRLib.h from IRLib an Arduino library for infrared encoding and decoding
|
|
||||||
* Version 1.1 April 2013
|
|
||||||
* Copyright 2013 by Chris Young http://cyborg5.com
|
|
||||||
*
|
|
||||||
* Port to Digispark (size optimization) August 2013
|
|
||||||
* by RC Navy http://p.loussouarn.free.fr
|
|
||||||
*
|
|
||||||
* This library is a major rewrite of IRemote by Ken Shirriff which was covered by
|
|
||||||
* GNU LESSER GENERAL PUBLIC LICENSE which as I read it allows me to make modified versions.
|
|
||||||
* That same license applies to this modified version. See his original copyright below.
|
|
||||||
* The latest Ken Shirriff code can be found at https://github.com/shirriff/Arduino-IRremote
|
|
||||||
* My purpose was to reorganize the code to make it easier to add or remove protocols.
|
|
||||||
* As a result I have separated the act of receiving a set of raw timing codes from the act of decoding them
|
|
||||||
* by making them separate classes. That way the receiving aspect can be more black box and implementers
|
|
||||||
* of decoders and senders can just deal with the decoding of protocols.
|
|
||||||
* Also added provisions to make the classes base classes that could be extended with new protocols
|
|
||||||
* which would not require recompiling of the original library nor understanding of its detailed contents.
|
|
||||||
* Some of the changes were made to reduce code size such as unnecessary use of long versus bool.
|
|
||||||
* Some changes were just my weird programming style. Also extended debugging information added.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* IRremote
|
|
||||||
* Version 0.1 July, 2009
|
|
||||||
* Copyright 2009 Ken Shirriff
|
|
||||||
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com
|
|
||||||
*
|
|
||||||
* Interrupt code based on NECIRrcv by Joe Knapp
|
|
||||||
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
|
|
||||||
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef IRLib_h
|
|
||||||
#define IRLib_h
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
// The following are compile-time library options.
|
|
||||||
// If you change them, recompile the library.
|
|
||||||
// If DEBUG is defined, a lot of debugging output will be printed during decoding.
|
|
||||||
// If TRACE is defined, some debugging information about the decode will be printed
|
|
||||||
// TEST must be defined for the IRtest unittests to work. It will make some
|
|
||||||
// methods virtual, which will be slightly slower, which is why it is optional.
|
|
||||||
// If DETAILLED_DUMP is defined the dump informations are more detailled
|
|
||||||
// If ALL_IR_PROTOCOL is defined, it allows to discover the protocol used by the IR transmitter (eg, with an arduino UNO)
|
|
||||||
// Once the protocol used by the IR transmitter discovered, set MY_IR_PROTOCOL to PROTO_xxxx and comment ALL_IR_PROTOCOL
|
|
||||||
// this will reduce dramatically the size of the sketch
|
|
||||||
// #define DEBUG
|
|
||||||
// #define TRACE
|
|
||||||
// #define TEST
|
|
||||||
|
|
||||||
//#define USE_IR_SEND
|
|
||||||
//#define DETAILLED_DUMP
|
|
||||||
//#define ALL_IR_PROTOCOL
|
|
||||||
#define MY_IR_PROTOCOL PROTO_NEC /* Set Here the protocol you want to use among the following ones */
|
|
||||||
|
|
||||||
// Only used for testing; can remove virtual for shorter code
|
|
||||||
#ifdef TEST
|
|
||||||
#define VIRTUAL virtual
|
|
||||||
#else
|
|
||||||
#define VIRTUAL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define RAWBUF 70//100 // Length of raw duration buffer
|
|
||||||
#define USE_TIMER1 1 //should be "1" for timer 1, should be "0" for timer 2
|
|
||||||
|
|
||||||
/* Use one of the protocol in the list below if you want to support a single one */
|
|
||||||
#define PROTO_UNKNOWN 0
|
|
||||||
#define PROTO_NEC 1
|
|
||||||
#define PROTO_SONY 2
|
|
||||||
#define PROTO_RC5 3
|
|
||||||
#define PROTO_RC6 4
|
|
||||||
#define PROTO_PANASONIC_OLD 5
|
|
||||||
#define PROTO_JVC 6
|
|
||||||
#define PROTO_NECX 7
|
|
||||||
#define PROTO_HASH_CODE 8
|
|
||||||
|
|
||||||
enum IRTYPES {UNKNOWN, NEC, SONY, RC5, RC6, PANASONIC_OLD, JVC, NECX, HASH_CODE, LAST_PROTOCOL=HASH_CODE};
|
|
||||||
|
|
||||||
#if defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
|
||||||
const char *Pnames(IRTYPES Type); //Returns a character string that is name of protocol.
|
|
||||||
#else
|
|
||||||
const __FlashStringHelper *Pnames(IRTYPES Type); //Returns a character string that is name of protocol.
|
|
||||||
#endif
|
|
||||||
// Base class for decoding raw results
|
|
||||||
class IRdecodeBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
IRdecodeBase(void);
|
|
||||||
IRTYPES decode_type; // NEC, SONY, RC5, UNKNOWN etc.
|
|
||||||
unsigned long value; // Decoded value
|
|
||||||
int bits; // Number of bits in decoded value
|
|
||||||
volatile unsigned int *rawbuf; // Raw intervals in .5 us ticks
|
|
||||||
/*int*/uint8_t rawlen; // Number of records in rawbuf.
|
|
||||||
virtual void Reset(void); // Initializes the decoder
|
|
||||||
virtual bool decode(void); // This base routine always returns false override with your routine
|
|
||||||
bool decodeGeneric(/*int*/int8_t Raw_Count,int Head_Mark,int Head_Space, int Mark_One, int Mark_Zero, int Space_One,int Space_Zero);
|
|
||||||
unsigned long Interval_uSec(int index);
|
|
||||||
virtual void DumpResults (void);
|
|
||||||
void UseExtnBuf(void *P); //Normally uses same rawbuf as IRrecv. Use this to define your own buffer.
|
|
||||||
void copyBuf (IRdecodeBase *source);//copies rawbuf and rawlen from one decoder to another
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_HASH_CODE)
|
|
||||||
class IRdecodeHash: public virtual IRdecodeBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
unsigned long hash;
|
|
||||||
virtual bool decode(void);//made virtual in case you want to substitute your own hash code
|
|
||||||
protected:
|
|
||||||
int compare(unsigned int oldval, unsigned int newval);//used by decodeHash
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NEC)
|
|
||||||
class IRdecodeNEC: public virtual IRdecodeBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual bool decode(void);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_SONY)
|
|
||||||
class IRdecodeSony: public virtual IRdecodeBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual bool decode(void);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC5) || (MY_IR_PROTOCOL == PROTO_RC6)
|
|
||||||
class IRdecodeRC: public virtual IRdecodeBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum RCLevel {MARK, SPACE, ERROR};//used by decoders for RC5/RC6
|
|
||||||
// These are called by decode
|
|
||||||
RCLevel getRClevel(int *offset, int *used, int t1);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC5)
|
|
||||||
class IRdecodeRC5: public virtual IRdecodeRC
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual bool decode(void);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC6)
|
|
||||||
class IRdecodeRC6: public virtual IRdecodeRC
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual bool decode(void);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_PANASONIC_OLD)
|
|
||||||
class IRdecodePanasonic_Old: public virtual IRdecodeBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual bool decode(void);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_JVC)
|
|
||||||
class IRdecodeJVC: public virtual IRdecodeBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual bool decode(void);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NECX)
|
|
||||||
class IRdecodeNECx: public virtual IRdecodeBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual bool decode(void);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// main class for decoding all supported protocols
|
|
||||||
class IRdecode:
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NEC)
|
|
||||||
public virtual IRdecodeNEC
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL)
|
|
||||||
,
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_SONY)
|
|
||||||
public virtual IRdecodeSony
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL)
|
|
||||||
,
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC5)
|
|
||||||
public virtual IRdecodeRC5
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL)
|
|
||||||
,
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC6)
|
|
||||||
public virtual IRdecodeRC6
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL)
|
|
||||||
,
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_PANASONIC_OLD)
|
|
||||||
public virtual IRdecodePanasonic_Old
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL)
|
|
||||||
,
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_JVC)
|
|
||||||
public virtual IRdecodeJVC
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL)
|
|
||||||
,
|
|
||||||
#endif
|
|
||||||
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NECX)
|
|
||||||
public virtual IRdecodeNECx
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual bool decode(void); // Calls each decode routine individually
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef USE_IR_SEND
|
|
||||||
//Base class for sending signals
|
|
||||||
class IRsendBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
IRsendBase() ;
|
|
||||||
void sendGeneric(unsigned long data, int Num_Bits, int Head_Mark, int Head_Space, int Mark_One, int Mark_Zero, int Space_One, int Space_Zero, int mHz, bool Stop_Bits);
|
|
||||||
protected:
|
|
||||||
void enableIROut(int khz);
|
|
||||||
VIRTUAL void mark(int usec);
|
|
||||||
VIRTUAL void space(int usec);
|
|
||||||
};
|
|
||||||
|
|
||||||
class IRsendNEC: public virtual IRsendBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void send(unsigned long data);
|
|
||||||
};
|
|
||||||
|
|
||||||
class IRsendSony: public virtual IRsendBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void send(unsigned long data, int nbits);
|
|
||||||
};
|
|
||||||
|
|
||||||
class IRsendRaw: public virtual IRsendBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void send(unsigned int buf[], int len, int hz);
|
|
||||||
};
|
|
||||||
|
|
||||||
class IRsendRC5: public virtual IRsendBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void send(unsigned long data);
|
|
||||||
};
|
|
||||||
|
|
||||||
class IRsendRC6: public virtual IRsendBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void send(unsigned long data, int nbits);
|
|
||||||
};
|
|
||||||
|
|
||||||
class IRsendPanasonic_Old: public virtual IRsendBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void send(unsigned long data);
|
|
||||||
};
|
|
||||||
|
|
||||||
class IRsendJVC: public virtual IRsendBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void send(unsigned long data, bool First);
|
|
||||||
};
|
|
||||||
|
|
||||||
class IRsendNECx: public virtual IRsendBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void send(unsigned long data);
|
|
||||||
};
|
|
||||||
|
|
||||||
class IRsend:
|
|
||||||
public virtual IRsendNEC,
|
|
||||||
public virtual IRsendSony,
|
|
||||||
public virtual IRsendRaw,
|
|
||||||
public virtual IRsendRC5,
|
|
||||||
public virtual IRsendRC6,
|
|
||||||
public virtual IRsendPanasonic_Old,
|
|
||||||
public virtual IRsendJVC,
|
|
||||||
public virtual IRsendNECx
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void send(IRTYPES Type, unsigned long data, int nbits);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// main class for receiving IR
|
|
||||||
class IRrecv
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
IRrecv(int recvpin);
|
|
||||||
void No_Output(void);
|
|
||||||
void blink13(int blinkflag);
|
|
||||||
bool GetResults(IRdecodeBase *decoder);
|
|
||||||
void enableIRIn();
|
|
||||||
void resume();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Some useful constants
|
|
||||||
// Decoded value for NEC when a repeat code is received
|
|
||||||
#define REPEAT 0xffffffff
|
|
||||||
|
|
||||||
|
|
||||||
#endif //IRLib_h
|
|
@ -1,83 +0,0 @@
|
|||||||
/* IRLibMatch.h from IRLib – an Arduino library for infrared encoding and decoding
|
|
||||||
* Version 1.0 January 2013
|
|
||||||
* Copyright 2013 by Chris Young http://cyborg5.com
|
|
||||||
*
|
|
||||||
* This library is a major rewrite of IRemote by Ken Shirriff which was covered by
|
|
||||||
* GNU LESSER GENERAL PUBLIC LICENSE which as I read it allows me to make modified versions.
|
|
||||||
* That same license applies to this modified version. See his original copyright below.
|
|
||||||
* The latest Ken Shirriff code can be found at https://github.com/shirriff/Arduino-IRremote
|
|
||||||
* My purpose was to reorganize the code to make it easier to add or remove protocols.
|
|
||||||
* As a result I have separated the act of receiving a set of raw timing codes from the act of decoding them
|
|
||||||
* by making them separate classes. That way the receiving aspect can be more black box and implementers
|
|
||||||
* of decoders and senders can just deal with the decoding of protocols.
|
|
||||||
* Also added provisions to make the classes base classes that could be extended with new protocols
|
|
||||||
* which would not require recompiling of the original library nor understanding of its detailed contents.
|
|
||||||
* Some of the changes were made to reduce code size such as unnecessary use of long versus bool.
|
|
||||||
* Some changes were just my weird programming style. Also extended debugging information added.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* IRremote
|
|
||||||
* Version 0.1 July, 2009
|
|
||||||
* Copyright 2009 Ken Shirriff
|
|
||||||
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com
|
|
||||||
*
|
|
||||||
* Interrupt code based on NECIRrcv by Joe Knapp
|
|
||||||
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
|
|
||||||
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef IRLibMatch_h
|
|
||||||
#define IRLibMatch_h
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is some miscellaneous definition that is needed by the decoding routines.
|
|
||||||
* You need not include this file unless you are creating custom decode routines
|
|
||||||
* which will require these macros and definitions. Even if you include it, you probably
|
|
||||||
* don't need to be intimately familiar with the internal details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Marks tend to be 100us too long, and spaces 100us too short
|
|
||||||
// when received due to sensor lag.
|
|
||||||
#define MARK_EXCESS 100
|
|
||||||
#define USECPERTICK 50 // microseconds per clock interrupt tick
|
|
||||||
#if 0
|
|
||||||
#define TOLERANCE 25 // percent tolerance in measurements
|
|
||||||
#define TICKS_LOW(us) (int) (((us)*(1.0 - TOLERANCE/100.)/USECPERTICK))
|
|
||||||
#define TICKS_HIGH(us) (int) (((us)*(1.0 + TOLERANCE/100.)/USECPERTICK + 1))
|
|
||||||
#else
|
|
||||||
#define TICKS_LOW(us) (((us) - (us>>2))/USECPERTICK)
|
|
||||||
#define TICKS_HIGH(us) (((us) + (us>>2))/USECPERTICK)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
int MATCH(int measured, int desired);
|
|
||||||
int MATCH_MARK(int measured_ticks, int desired_us);
|
|
||||||
int MATCH_SPACE(int measured_ticks, int desired_us);
|
|
||||||
#else
|
|
||||||
#define MATCH(measured_ticks, desired_us) ((measured_ticks) >= TICKS_LOW(desired_us) && (measured_ticks) <= TICKS_HIGH(desired_us))
|
|
||||||
#define MATCH_MARK(measured_ticks, desired_us) MATCH(measured_ticks, (desired_us) + MARK_EXCESS)
|
|
||||||
#define MATCH_SPACE(measured_ticks, desired_us) MATCH((measured_ticks), (desired_us) - MARK_EXCESS)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef TRACE
|
|
||||||
void ATTEMPT_MESSAGE(const __FlashStringHelper * s);
|
|
||||||
byte REJECTION_MESSAGE(const __FlashStringHelper * s);
|
|
||||||
#define RAW_COUNT_ERROR REJECTION_MESSAGE(F("number of raw samples"));
|
|
||||||
#define HEADER_MARK_ERROR REJECTION_MESSAGE(F("header mark"));
|
|
||||||
#define HEADER_SPACE_ERROR REJECTION_MESSAGE(F("header space"));
|
|
||||||
#define DATA_MARK_ERROR REJECTION_MESSAGE(F("data mark"));
|
|
||||||
#define DATA_SPACE_ERROR REJECTION_MESSAGE(F("data space"));
|
|
||||||
#define TRAILER_BIT_ERROR REJECTION_MESSAGE(F("RC5/RC6 trailer bit length"));
|
|
||||||
#else
|
|
||||||
#define ATTEMPT_MESSAGE(s)
|
|
||||||
#define REJECTION_MESSAGE(s) false
|
|
||||||
#define RAW_COUNT_ERROR false
|
|
||||||
#define HEADER_MARK_ERROR false
|
|
||||||
#define HEADER_SPACE_ERROR false
|
|
||||||
#define DATA_MARK_ERROR false
|
|
||||||
#define DATA_SPACE_ERROR false
|
|
||||||
#define TRAILER_BIT_ERROR false
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif //IRLibMatch_h
|
|
@ -1,380 +0,0 @@
|
|||||||
/* IRLibTimer.h from IRLib – an Arduino library for infrared encoding and decoding
|
|
||||||
* Version 1.0 January 2013
|
|
||||||
* Copyright 2013 by Chris Young http://cyborg5.com
|
|
||||||
*
|
|
||||||
* This library is a major rewrite of IRemote by Ken Shirriff which was covered by
|
|
||||||
* GNU LESSER GENERAL PUBLIC LICENSE which as I read it allows me to make modified versions.
|
|
||||||
* That same license applies to this modified version. See his original copyright below.
|
|
||||||
* The latest Ken Shirriff code can be found at https://github.com/shirriff/Arduino-IRremote
|
|
||||||
* My purpose was to reorganize the code to make it easier to add or remove protocols.
|
|
||||||
* As a result I have separated the act of receiving a set of raw timing codes from the act of decoding them
|
|
||||||
* by making them separate classes. That way the receiving aspect can be more black box and implementers
|
|
||||||
* of decoders and senders can just deal with the decoding of protocols.
|
|
||||||
* Also added provisions to make the classes base classes that could be extended with new protocols
|
|
||||||
* which would not require recompiling of the original library nor understanding of its detailed contents.
|
|
||||||
* Some of the changes were made to reduce code size such as unnecessary use of long versus bool.
|
|
||||||
* Some changes were just my weird programming style. Also extended debugging information added.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* IRremote
|
|
||||||
* Version 0.1 July, 2009
|
|
||||||
* Copyright 2009 Ken Shirriff
|
|
||||||
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com
|
|
||||||
*
|
|
||||||
* Interrupt code based on NECIRrcv by Joe Knapp
|
|
||||||
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
|
|
||||||
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
|
|
||||||
*/
|
|
||||||
/* This file defines which timer you wish to use. Different versions of Arduino and related boards
|
|
||||||
* have different timers available to them. For various reasons you might want to use something other than
|
|
||||||
* timer 2. Some boards do not have timer 2. This attempts to detect which type of board you are using.
|
|
||||||
* You need uncomment wish to use on your board. You probably will not need to include this in your
|
|
||||||
* program unless you want to see which timer is being used and which board has been detected.
|
|
||||||
* This information came from an alternative fork of the original Ken Shirriff library found here
|
|
||||||
* https://github.com/TKJElectronics/Arduino-IRremote
|
|
||||||
*/
|
|
||||||
#ifndef IRLibTimer_h
|
|
||||||
#define IRLibTimer_h
|
|
||||||
|
|
||||||
#if defined(ARDUINO) && ARDUINO >= 100
|
|
||||||
#include "Arduino.h"
|
|
||||||
#else
|
|
||||||
#include "WProgram.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef F_CPU
|
|
||||||
#define SYSCLOCK F_CPU // main Arduino clock
|
|
||||||
#else
|
|
||||||
#define SYSCLOCK 16000000 // main Arduino clock
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Arduino Mega
|
|
||||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
|
||||||
//#define IR_USE_TIMER1 // tx = pin 11
|
|
||||||
#define IR_USE_TIMER2 // tx = pin 9
|
|
||||||
//#define IR_USE_TIMER3 // tx = pin 5
|
|
||||||
//#define IR_USE_TIMER4 // tx = pin 6
|
|
||||||
//#define IR_USE_TIMER5 // tx = pin 46
|
|
||||||
|
|
||||||
// Teensy 1.0
|
|
||||||
#elif defined(__AVR_AT90USB162__)
|
|
||||||
#define IR_USE_TIMER1 // tx = pin 17
|
|
||||||
|
|
||||||
// Teensy 2.0 versus Leonardo
|
|
||||||
// These boards use the same chip but the pinouts are different.
|
|
||||||
#elif defined(__AVR_ATmega32U4__)
|
|
||||||
#ifdef CORE_TEENSY
|
|
||||||
// it's Teensy 2.0
|
|
||||||
//#define IR_USE_TIMER1 // tx = pin 14
|
|
||||||
//#define IR_USE_TIMER3 // tx = pin 9
|
|
||||||
#define IR_USE_TIMER4_HS // tx = pin 10
|
|
||||||
#else
|
|
||||||
// it's probably Leonardo
|
|
||||||
#define IR_USE_TIMER1 // tx = pin 9
|
|
||||||
//#define IR_USE_TIMER3 // tx = pin 5
|
|
||||||
//#define IR_USE_TIMER4_HS // tx = pin 13
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Teensy++ 1.0 & 2.0
|
|
||||||
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
|
||||||
//#define IR_USE_TIMER1 // tx = pin 25
|
|
||||||
#define IR_USE_TIMER2 // tx = pin 1
|
|
||||||
//#define IR_USE_TIMER3 // tx = pin 16
|
|
||||||
|
|
||||||
// Sanguino
|
|
||||||
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
|
||||||
//#define IR_USE_TIMER1 // tx = pin 13
|
|
||||||
#define IR_USE_TIMER2 // tx = pin 14
|
|
||||||
|
|
||||||
// Tested with ATtiny85, presumably works with ATtiny45, possibly with ATtiny25
|
|
||||||
// The attiny core uses Timer 0 for millis() etc., so using timer 1 is advisable
|
|
||||||
// for IR out. Pin 4 also conveniently is not used in any role for ISP.
|
|
||||||
// The Arduino-tiny core uses Timer 1 for millis(), so using timer 0 is advisable
|
|
||||||
// for IR out. Pin 0 is used by default for IR out in the Tinyspark IR shield, but
|
|
||||||
// is not usable for PWM waveforms where the frequency, not just the duty cycle,
|
|
||||||
// needs to be controlled.
|
|
||||||
#elif defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
|
||||||
// #define IR_USE_TIMER1_TINY // tx = pin 4 (OC1B)
|
|
||||||
#define IR_USE_TIMER0 // tx = pin 1 (OC0B)
|
|
||||||
// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc
|
|
||||||
#else
|
|
||||||
//#define IR_USE_TIMER1 // tx = pin 9
|
|
||||||
#define IR_USE_TIMER2 // tx = pin 3
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// defines for timer0 (8 bits). Tested on ATtiny85, may also work on other
|
|
||||||
// processors, but most of them use Timer 0 to keep system time
|
|
||||||
#if defined(IR_USE_TIMER0)
|
|
||||||
#define TIMER_RESET
|
|
||||||
#define TIMER_ENABLE_PWM (TCCR0A |= _BV(COM0B1))
|
|
||||||
#define TIMER_DISABLE_PWM (TCCR0A &= ~(_BV(COM0B1)))
|
|
||||||
#define TIMER_ENABLE_INTR (TIMSK = _BV(OCIE0A))
|
|
||||||
#define TIMER_DISABLE_INTR (TIMSK = 0)
|
|
||||||
#define TIMER_INTR_NAME TIMER0_COMPA_vect
|
|
||||||
#define TIMER_CONFIG_KHZ(val) ({ \
|
|
||||||
const uint8_t pwmval = SYSCLOCK / 2000 / (val); \
|
|
||||||
TCCR0A = _BV(WGM00); \
|
|
||||||
TCCR0B = _BV(WGM02) | _BV(CS00); \
|
|
||||||
OCR0A = pwmval; \
|
|
||||||
OCR0B = pwmval / 3; \
|
|
||||||
})
|
|
||||||
#define TIMER_COUNT_TOP (SYSCLOCK * USECPERTICK / 1000000)
|
|
||||||
#if (TIMER_COUNT_TOP < 256)
|
|
||||||
#define TIMER_CONFIG_NORMAL() ({ \
|
|
||||||
TCCR0A = _BV(WGM01); \
|
|
||||||
TCCR0B = _BV(CS00); \
|
|
||||||
OCR0A = TIMER_COUNT_TOP; \
|
|
||||||
TCNT0 = 0; \
|
|
||||||
})
|
|
||||||
#else
|
|
||||||
#define TIMER_CONFIG_NORMAL() ({ \
|
|
||||||
TCCR0A = _BV(WGM01); \
|
|
||||||
TCCR0B = _BV(CS01); \
|
|
||||||
OCR0A = TIMER_COUNT_TOP / 8; \
|
|
||||||
TCNT0 = 0; \
|
|
||||||
})
|
|
||||||
#endif
|
|
||||||
#if defined(CORE_OC0A_PIN)
|
|
||||||
#define TIMER_PWM_PIN CORE_OC0B_PIN
|
|
||||||
#else
|
|
||||||
#define TIMER_PWM_PIN 1 /* Attiny core */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// defines for timer2 (8 bits)
|
|
||||||
#elif defined(IR_USE_TIMER2)
|
|
||||||
#define TIMER_RESET
|
|
||||||
#define TIMER_ENABLE_PWM (TCCR2A |= _BV(COM2B1))
|
|
||||||
#define TIMER_DISABLE_PWM (TCCR2A &= ~(_BV(COM2B1)))
|
|
||||||
#define TIMER_ENABLE_INTR (TIMSK2 = _BV(OCIE2A))
|
|
||||||
#define TIMER_DISABLE_INTR (TIMSK2 = 0)
|
|
||||||
#define TIMER_INTR_NAME TIMER2_COMPA_vect
|
|
||||||
#define TIMER_CONFIG_KHZ(val) ({ \
|
|
||||||
const uint8_t pwmval = SYSCLOCK / 2000 / (val); \
|
|
||||||
TCCR2A = _BV(WGM20); \
|
|
||||||
TCCR2B = _BV(WGM22) | _BV(CS20); \
|
|
||||||
OCR2A = pwmval; \
|
|
||||||
OCR2B = pwmval / 3; \
|
|
||||||
})
|
|
||||||
#define TIMER_COUNT_TOP (SYSCLOCK * USECPERTICK / 1000000)
|
|
||||||
#if (TIMER_COUNT_TOP < 256)
|
|
||||||
#define TIMER_CONFIG_NORMAL() ({ \
|
|
||||||
TCCR2A = _BV(WGM21); \
|
|
||||||
TCCR2B = _BV(CS20); \
|
|
||||||
OCR2A = TIMER_COUNT_TOP; \
|
|
||||||
TCNT2 = 0; \
|
|
||||||
})
|
|
||||||
#else
|
|
||||||
#define TIMER_CONFIG_NORMAL() ({ \
|
|
||||||
TCCR2A = _BV(WGM21); \
|
|
||||||
TCCR2B = _BV(CS21); \
|
|
||||||
OCR2A = TIMER_COUNT_TOP / 8; \
|
|
||||||
TCNT2 = 0; \
|
|
||||||
})
|
|
||||||
#endif
|
|
||||||
#if defined(CORE_OC2B_PIN)
|
|
||||||
#define TIMER_PWM_PIN CORE_OC2B_PIN /* Teensy */
|
|
||||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
|
||||||
#define TIMER_PWM_PIN 9 /* Arduino Mega */
|
|
||||||
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
|
||||||
#define TIMER_PWM_PIN 14 /* Sanguino */
|
|
||||||
#else
|
|
||||||
#define TIMER_PWM_PIN 3 /* Arduino Duemilanove, Diecimila, LilyPad, etc */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// defines for timer1 (16 bits)
|
|
||||||
#elif defined(IR_USE_TIMER1)
|
|
||||||
#define TIMER_RESET
|
|
||||||
#define TIMER_ENABLE_PWM (TCCR1A |= _BV(COM1A1))
|
|
||||||
#define TIMER_DISABLE_PWM (TCCR1A &= ~(_BV(COM1A1)))
|
|
||||||
#define TIMER_ENABLE_INTR (TIMSK1 = _BV(OCIE1A))
|
|
||||||
#define TIMER_DISABLE_INTR (TIMSK1 = 0)
|
|
||||||
#define TIMER_INTR_NAME TIMER1_COMPA_vect
|
|
||||||
#define TIMER_CONFIG_KHZ(val) ({ \
|
|
||||||
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
|
|
||||||
TCCR1A = _BV(WGM11); \
|
|
||||||
TCCR1B = _BV(WGM13) | _BV(CS10); \
|
|
||||||
ICR1 = pwmval; \
|
|
||||||
OCR1A = pwmval / 3; \
|
|
||||||
})
|
|
||||||
#define TIMER_CONFIG_NORMAL() ({ \
|
|
||||||
TCCR1A = 0; \
|
|
||||||
TCCR1B = _BV(WGM12) | _BV(CS10); \
|
|
||||||
OCR1A = SYSCLOCK * USECPERTICK / 1000000; \
|
|
||||||
TCNT1 = 0; \
|
|
||||||
})
|
|
||||||
#if defined(CORE_OC1A_PIN)
|
|
||||||
#define TIMER_PWM_PIN CORE_OC1A_PIN /* Teensy */
|
|
||||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
|
||||||
#define TIMER_PWM_PIN 11 /* Arduino Mega */
|
|
||||||
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
|
||||||
#define TIMER_PWM_PIN 13 /* Sanguino */
|
|
||||||
#else
|
|
||||||
#define TIMER_PWM_PIN 9 /* Arduino Duemilanove, Diecimila, LilyPad, etc */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// defines for timer3 (16 bits)
|
|
||||||
#elif defined(IR_USE_TIMER3)
|
|
||||||
#define TIMER_RESET
|
|
||||||
#define TIMER_ENABLE_PWM (TCCR3A |= _BV(COM3A1))
|
|
||||||
#define TIMER_DISABLE_PWM (TCCR3A &= ~(_BV(COM3A1)))
|
|
||||||
#define TIMER_ENABLE_INTR (TIMSK3 = _BV(OCIE3A))
|
|
||||||
#define TIMER_DISABLE_INTR (TIMSK3 = 0)
|
|
||||||
#define TIMER_INTR_NAME TIMER3_COMPA_vect
|
|
||||||
#define TIMER_CONFIG_KHZ(val) ({ \
|
|
||||||
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
|
|
||||||
TCCR3A = _BV(WGM31); \
|
|
||||||
TCCR3B = _BV(WGM33) | _BV(CS30); \
|
|
||||||
ICR3 = pwmval; \
|
|
||||||
OCR3A = pwmval / 3; \
|
|
||||||
})
|
|
||||||
#define TIMER_CONFIG_NORMAL() ({ \
|
|
||||||
TCCR3A = 0; \
|
|
||||||
TCCR3B = _BV(WGM32) | _BV(CS30); \
|
|
||||||
OCR3A = SYSCLOCK * USECPERTICK / 1000000; \
|
|
||||||
TCNT3 = 0; \
|
|
||||||
})
|
|
||||||
#if defined(CORE_OC3A_PIN)
|
|
||||||
#define TIMER_PWM_PIN CORE_OC3A_PIN /* Teensy */
|
|
||||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
|
||||||
#define TIMER_PWM_PIN 5 /* Arduino Mega */
|
|
||||||
#elif defined(__AVR_ATmega32U4__)
|
|
||||||
#define TIMER_PWM_PIN 5 /* Arduino Leonardo note already checked for Teensy */
|
|
||||||
#else
|
|
||||||
#error "Please add OC3A pin number here\n"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// defines for timer4 (10 bits, high speed option)
|
|
||||||
#elif defined(IR_USE_TIMER4_HS)
|
|
||||||
#define TIMER_RESET
|
|
||||||
#define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A1))
|
|
||||||
#define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A1)))
|
|
||||||
#define TIMER_ENABLE_INTR (TIMSK4 = _BV(TOIE4))
|
|
||||||
#define TIMER_DISABLE_INTR (TIMSK4 = 0)
|
|
||||||
#define TIMER_INTR_NAME TIMER4_OVF_vect
|
|
||||||
#define TIMER_CONFIG_KHZ(val) ({ \
|
|
||||||
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
|
|
||||||
TCCR4A = (1<<PWM4A); \
|
|
||||||
TCCR4B = _BV(CS40); \
|
|
||||||
TCCR4C = 0; \
|
|
||||||
TCCR4D = (1<<WGM40); \
|
|
||||||
TCCR4E = 0; \
|
|
||||||
TC4H = pwmval >> 8; \
|
|
||||||
OCR4C = pwmval; \
|
|
||||||
TC4H = (pwmval / 3) >> 8; \
|
|
||||||
OCR4A = (pwmval / 3) & 255; \
|
|
||||||
})
|
|
||||||
#define TIMER_CONFIG_NORMAL() ({ \
|
|
||||||
TCCR4A = 0; \
|
|
||||||
TCCR4B = _BV(CS40); \
|
|
||||||
TCCR4C = 0; \
|
|
||||||
TCCR4D = 0; \
|
|
||||||
TCCR4E = 0; \
|
|
||||||
TC4H = (SYSCLOCK * USECPERTICK / 1000000) >> 8; \
|
|
||||||
OCR4C = (SYSCLOCK * USECPERTICK / 1000000) & 255; \
|
|
||||||
TC4H = 0; \
|
|
||||||
TCNT4 = 0; \
|
|
||||||
})
|
|
||||||
#if defined(CORE_OC4A_PIN)
|
|
||||||
#define TIMER_PWM_PIN CORE_OC4A_PIN /* Teensy */
|
|
||||||
#elif defined(__AVR_ATmega32U4__)
|
|
||||||
#define TIMER_PWM_PIN 13 /*Leonardo*/
|
|
||||||
#else
|
|
||||||
#error "Please add OC4A pin number here\n"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// defines for timer4 (16 bits)
|
|
||||||
#elif defined(IR_USE_TIMER4)
|
|
||||||
#define TIMER_RESET
|
|
||||||
#define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A1))
|
|
||||||
#define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A1)))
|
|
||||||
#define TIMER_ENABLE_INTR (TIMSK4 = _BV(OCIE4A))
|
|
||||||
#define TIMER_DISABLE_INTR (TIMSK4 = 0)
|
|
||||||
#define TIMER_INTR_NAME TIMER4_COMPA_vect
|
|
||||||
#define TIMER_CONFIG_KHZ(val) ({ \
|
|
||||||
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
|
|
||||||
TCCR4A = _BV(WGM41); \
|
|
||||||
TCCR4B = _BV(WGM43) | _BV(CS40); \
|
|
||||||
ICR4 = pwmval; \
|
|
||||||
OCR4A = pwmval / 3; \
|
|
||||||
})
|
|
||||||
#define TIMER_CONFIG_NORMAL() ({ \
|
|
||||||
TCCR4A = 0; \
|
|
||||||
TCCR4B = _BV(WGM42) | _BV(CS40); \
|
|
||||||
OCR4A = SYSCLOCK * USECPERTICK / 1000000; \
|
|
||||||
TCNT4 = 0; \
|
|
||||||
})
|
|
||||||
#if defined(CORE_OC4A_PIN)
|
|
||||||
#define TIMER_PWM_PIN CORE_OC4A_PIN
|
|
||||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
|
||||||
#define TIMER_PWM_PIN 6 /* Arduino Mega */
|
|
||||||
#else
|
|
||||||
#error "Please add OC4A pin number here\n"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// defines for timer5 (16 bits)
|
|
||||||
#elif defined(IR_USE_TIMER5)
|
|
||||||
#define TIMER_RESET
|
|
||||||
#define TIMER_ENABLE_PWM (TCCR5A |= _BV(COM5A1))
|
|
||||||
#define TIMER_DISABLE_PWM (TCCR5A &= ~(_BV(COM5A1)))
|
|
||||||
#define TIMER_ENABLE_INTR (TIMSK5 = _BV(OCIE5A))
|
|
||||||
#define TIMER_DISABLE_INTR (TIMSK5 = 0)
|
|
||||||
#define TIMER_INTR_NAME TIMER5_COMPA_vect
|
|
||||||
#define TIMER_CONFIG_KHZ(val) ({ \
|
|
||||||
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
|
|
||||||
TCCR5A = _BV(WGM51); \
|
|
||||||
TCCR5B = _BV(WGM53) | _BV(CS50); \
|
|
||||||
ICR5 = pwmval; \
|
|
||||||
OCR5A = pwmval / 3; \
|
|
||||||
})
|
|
||||||
#define TIMER_CONFIG_NORMAL() ({ \
|
|
||||||
TCCR5A = 0; \
|
|
||||||
TCCR5B = _BV(WGM52) | _BV(CS50); \
|
|
||||||
OCR5A = SYSCLOCK * USECPERTICK / 1000000; \
|
|
||||||
TCNT5 = 0; \
|
|
||||||
})
|
|
||||||
#if defined(CORE_OC5A_PIN)
|
|
||||||
#define TIMER_PWM_PIN CORE_OC5A_PIN
|
|
||||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
|
||||||
#define TIMER_PWM_PIN 46 /* Arduino Mega */
|
|
||||||
#else
|
|
||||||
#error "Please add OC5A pin number here\n"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#else // unknown timer
|
|
||||||
#error "Internal code configuration error, no known IR_USE_TIMER# defined\n"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// defines for blinking the LED
|
|
||||||
#if defined(CORE_LED0_PIN)
|
|
||||||
#define BLINKLED CORE_LED0_PIN
|
|
||||||
#define BLINKLED_ON() (digitalWrite(CORE_LED0_PIN, HIGH))
|
|
||||||
#define BLINKLED_OFF() (digitalWrite(CORE_LED0_PIN, LOW))
|
|
||||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
|
||||||
#define BLINKLED 13
|
|
||||||
#define BLINKLED_ON() (PORTB |= B10000000)
|
|
||||||
#define BLINKLED_OFF() (PORTB &= B01111111)
|
|
||||||
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
|
||||||
#define BLINKLED 0
|
|
||||||
#define BLINKLED_ON() (PORTD |= B00000001)
|
|
||||||
#define BLINKLED_OFF() (PORTD &= B11111110)
|
|
||||||
#elif defined(__AVR_ATmega32U4__) && defined(IR_USE_TIMER4_HS)
|
|
||||||
//Leonardo not teensy. When using Timer4 output is on 13. Therefore disabling blink LED
|
|
||||||
//You can add an LED elsewhere if you want
|
|
||||||
#define BLINKLED 1
|
|
||||||
#define BLINKLED_ON() (digitalWrite(BLINKLED, HIGH))
|
|
||||||
#define BLINKLED_OFF() (digitalWrite(BLINKLED, LOW))
|
|
||||||
#else
|
|
||||||
#define BLINKLED 13
|
|
||||||
#define BLINKLED_ON() (PORTB |= B00100000)
|
|
||||||
#define BLINKLED_OFF() (PORTB &= B11011111)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif //IRLibTimer_h
|
|
Binary file not shown.
@ -1,70 +0,0 @@
|
|||||||
IRLib – an Arduino library for infrared encoding and decoding
|
|
||||||
Version 1.1 april 2013
|
|
||||||
Copyright 2013 by Chris Young http://cyborg5.com
|
|
||||||
|
|
||||||
This library is a major rewrite of IRemote by Ken Shirriff which was covered
|
|
||||||
by GNU LESSER GENERAL PUBLIC LICENSE which as I read it allows me to make
|
|
||||||
modified versions. That same license applies to this modified version. See
|
|
||||||
his original copyright below.
|
|
||||||
|
|
||||||
The latest Ken Shirriff code can be found at
|
|
||||||
https://github.com/shirriff/Arduino-IRremote
|
|
||||||
|
|
||||||
My purpose was to reorganize the code to make it easier to add or remove
|
|
||||||
protocols. As a result I have separated the act of receiving a set of raw timing
|
|
||||||
codes from the act of decoding them by making them separate classes. That way
|
|
||||||
the receiving aspect can be more black box and implementers of decoders and
|
|
||||||
senders can just deal with the decoding of protocols.
|
|
||||||
|
|
||||||
Also added provisions to make the classes base classes that could be extended
|
|
||||||
with new protocols which would not require recompiling of the original library nor
|
|
||||||
understanding of its detailed contents. Some of the changes were made to reduce
|
|
||||||
code size such as unnecessary use of long versus bool. Some changes were just my
|
|
||||||
weird programming style. Also extended debugging information added.
|
|
||||||
|
|
||||||
IRremote
|
|
||||||
Version 0.1 July, 2009
|
|
||||||
Copyright 2009 Ken Shirriff
|
|
||||||
For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm
|
|
||||||
http://arcfn.com
|
|
||||||
|
|
||||||
Interrupt code based on NECIRrcv by Joe Knapp
|
|
||||||
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
|
|
||||||
Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
|
|
||||||
|
|
||||||
****************************************************
|
|
||||||
The package contains:
|
|
||||||
IRLib.cpp Code for the library written in object C++
|
|
||||||
IRLib.h Header file which you will include in your sketch
|
|
||||||
IRLibMatch.h Match macros used internally. Need not include this unless you implement
|
|
||||||
your own protocols
|
|
||||||
iRLibTimer.h Attempts to detect type of Arduino board and allows you to modify which
|
|
||||||
interrupt timer you will use. Defaults to timer 2 as did the original KS
|
|
||||||
library. Alternate board and timer information based on a fork of the
|
|
||||||
original KS library. That for can be found here.
|
|
||||||
https://github.com/TKJElectronics/Arduino-IRremote
|
|
||||||
|
|
||||||
Note: there is no "IRremoteInt.h" header as in the original library. Those values were
|
|
||||||
moved elsewhere.
|
|
||||||
|
|
||||||
The examples directory contains:
|
|
||||||
IRhashdecode Demonstrates hash decoder.
|
|
||||||
IRrecord Recording incoming signal and play it back when a character is sent
|
|
||||||
through the serial console. By using the console you no longer need
|
|
||||||
to wire up a pushbutton to run this code.
|
|
||||||
IRrecvDump Receives a code, attempts to decode it, produces well formatted
|
|
||||||
output of the results using the new "dump" method.
|
|
||||||
IRsendDemo Simplistic demo to send a Sony DVD power signal every time a
|
|
||||||
character is received from the serial monitor.
|
|
||||||
IRsendJVC Demonstrates sending a code using JVC protocol which is tricky.
|
|
||||||
Samsung36 Demonstrates how to expand the library without recompiling it.
|
|
||||||
Also demonstrates how to handle codes that are longer than 32 bits.
|
|
||||||
IRservo Demonstrates controlling a servo motor using an IR remote
|
|
||||||
IRserial_remote Demonstrates a Python application that runs on your PC and sends
|
|
||||||
serial data to Arduino which in turn sends IR remote signals.
|
|
||||||
Note: I did not port any of the other demo sketches although I may add IRTest later.
|
|
||||||
****************************************************
|
|
||||||
The library handles the following protocols:
|
|
||||||
NEC, Sony, RC5, RC6, Raw all of which were supported in the KS version.
|
|
||||||
Additionally added Panasonic_Old, JVC, NECx.
|
|
||||||
Also added KS hash code routines which he released separately.
|
|
@ -1,84 +0,0 @@
|
|||||||
#include <IRLib.h> // In {path_of_installation}/Digispark-Arduino-1.0.x/libraries/DigisparkIRLib/IRLib.h, set MY_PROTOCOL to NEC, SONY, RC5 to find the one used by your own IR Remote Control
|
|
||||||
#include <DigiUSB.h> // In {path_of_installation}/Digispark-Arduino-1.0.x/libraries/DigisparkUSB/DigiUSB.h, RING_BUFFER_SIZE shall be set to 32
|
|
||||||
/*
|
|
||||||
_____ ____ __ _ ____ _ _ _ _
|
|
||||||
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
|
|
||||||
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
|
|
||||||
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
|
|
||||||
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|
|
||||||
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2013
|
|
||||||
|
|
||||||
http://p.loussouarn.free.fr
|
|
||||||
|
|
||||||
*************************************************
|
|
||||||
* Optimized <IRLib> library Dump Demo *
|
|
||||||
*************************************************
|
|
||||||
|
|
||||||
This sketch allows you to discover the protocol used by your own IR Remote Control and the code of each key when pressed.
|
|
||||||
You will see the decoded key codes in the DigiUSB console.
|
|
||||||
|
|
||||||
IMPORTANT:
|
|
||||||
=========
|
|
||||||
- In {path_of_installation}/Digispark-Arduino-1.0.x/libraries/DigisparkIRLib/IRLib.h, set MY_PROTOCOL to NEC, SONY, RC5 to find the protocol used by your own IR Remote Control
|
|
||||||
- In {path_of_installation}/Digispark-Arduino-1.0.x/libraries/DigisparkUSB/DigiUSB.h, RING_BUFFER_SIZE shall be set to 32
|
|
||||||
|
|
||||||
Sensor wiring: (Warning: the wiring may vary depending of the model of IR sensor)
|
|
||||||
=============
|
|
||||||
.-------.
|
|
||||||
| ___ |
|
|
||||||
| / \ | InfraRed
|
|
||||||
| \___/ | Sensor
|
|
||||||
| |
|
|
||||||
'+--+--+'
|
|
||||||
| | | 100
|
|
||||||
P5 <----' | '--+---###--- +5V
|
|
||||||
| |
|
|
||||||
| '==='4.7uF
|
|
||||||
| |
|
|
||||||
'--+--'
|
|
||||||
|
|
|
||||||
GND
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define LED_PIN 1
|
|
||||||
#define IR_RX_PIN 5
|
|
||||||
|
|
||||||
#define BUTTON_OFF 0xF740BF //Set here the OFF code for the built-in LED when determined
|
|
||||||
#define BUTTON_ON 0xF7C03F //Set here the ON code for the built-in LED when determined
|
|
||||||
|
|
||||||
IRrecv My_Receiver(IR_RX_PIN);//Receive on pin IR_RX_PIN
|
|
||||||
IRdecode My_Decoder;
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
My_Receiver.enableIRIn(); // Start the receiver
|
|
||||||
pinMode(LED_PIN, OUTPUT);
|
|
||||||
DigiUSB.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
if(My_Receiver.GetResults(&My_Decoder))
|
|
||||||
{
|
|
||||||
My_Decoder.decode();
|
|
||||||
switch(My_Decoder.value)
|
|
||||||
{
|
|
||||||
case BUTTON_OFF:
|
|
||||||
digitalWrite(LED_PIN, LOW);
|
|
||||||
break;
|
|
||||||
case BUTTON_ON:
|
|
||||||
digitalWrite(LED_PIN, HIGH);
|
|
||||||
break;
|
|
||||||
default:break;
|
|
||||||
}
|
|
||||||
My_Receiver.resume();
|
|
||||||
DigiUSB.println(My_Decoder.value, HEX);
|
|
||||||
}
|
|
||||||
if(DigiUSB.available())
|
|
||||||
{
|
|
||||||
DigiUSB.read();
|
|
||||||
}
|
|
||||||
DigiUSB.refresh();
|
|
||||||
}
|
|
||||||
|
|
@ -1,201 +0,0 @@
|
|||||||
#include <TinySoftPwm.h>
|
|
||||||
#include <IRLib.h>
|
|
||||||
/*
|
|
||||||
_____ ____ __ _ ____ _ _ _ _
|
|
||||||
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
|
|
||||||
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
|
|
||||||
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
|
|
||||||
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|
|
||||||
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2013
|
|
||||||
|
|
||||||
http://p.loussouarn.free.fr
|
|
||||||
|
|
||||||
*************************************************
|
|
||||||
* Optimized <IRLib> library Controller Demo *
|
|
||||||
*************************************************
|
|
||||||
|
|
||||||
This sketch allows you to use the Digispark as an IR RGB Controller.
|
|
||||||
This sketch is designed to used low cost 24 keys IR Remote Control for RGB strip LED,
|
|
||||||
but you can adapt it to your own IR Remote Control.
|
|
||||||
|
|
||||||
Sensor wiring: (Warning: the wiring may vary depending of the model of IR sensor)
|
|
||||||
=============
|
|
||||||
.-------.
|
|
||||||
| ___ |
|
|
||||||
| / \ | InfraRed
|
|
||||||
| \___/ | Sensor
|
|
||||||
| |
|
|
||||||
'+--+--+'
|
|
||||||
| | | 100
|
|
||||||
P5 <----' | '--+---###--- +5V
|
|
||||||
| |
|
|
||||||
| '==='4.7uF
|
|
||||||
| |
|
|
||||||
'--+--'
|
|
||||||
|
|
|
||||||
GND
|
|
||||||
|
|
||||||
/* P0, P1 and P2 shall be declared in Digispark-Arduino-1.0.x/libraries/TinySoftPwm.h */
|
|
||||||
#define LED_GREEN_PIN 0
|
|
||||||
#define LED_RED_PIN 1
|
|
||||||
#define LED_BLUE_PIN 2
|
|
||||||
|
|
||||||
#define IR_RX_PIN 5
|
|
||||||
|
|
||||||
#define CODE_OFF 0xF740BF
|
|
||||||
#define CODE_ON 0xF7C03F
|
|
||||||
#define CODE_BRIGHT_MINUS 0xF7807F
|
|
||||||
#define CODE_BRIGHT_PLUS 0xF700FF
|
|
||||||
|
|
||||||
#define CODE_FLASH 0xF7D02F
|
|
||||||
#define CODE_STROBE 0xF7F00F
|
|
||||||
#define CODE_FADE 0xF7C837
|
|
||||||
#define CODE_SMOOTH 0xF7E817
|
|
||||||
|
|
||||||
#define CODE_RED 0xF720DF
|
|
||||||
#define CODE_GREEN 0xF7A05F
|
|
||||||
#define CODE_BLUE 0xF7609F
|
|
||||||
#define CODE_WHITE 0xF7E01F
|
|
||||||
|
|
||||||
#define CODE_ORANGE 0xF710EF
|
|
||||||
#define CODE_ORANGE_LIGTH 0xF730CF
|
|
||||||
#define CODE_BROWN 0xF708F7
|
|
||||||
#define CODE_YELLOW 0xF728D7
|
|
||||||
|
|
||||||
#define CODE_GREEN_LIGTH 0xF7906F
|
|
||||||
#define CODE_GREEN_BLUE1 0xF7B04F
|
|
||||||
#define CODE_GREEN_BLUE2 0xF78877
|
|
||||||
#define CODE_GREEN_BLUE3 0xF7A857
|
|
||||||
|
|
||||||
#define CODE_BLUE_LIGTH 0xF750AF
|
|
||||||
#define CODE_PURPLE_DARK 0xF7708F
|
|
||||||
#define CODE_PURPLE_LIGTH 0xF748B7
|
|
||||||
#define CODE_PINK 0xF76897
|
|
||||||
|
|
||||||
#define BRIGTH_STEP 10
|
|
||||||
#define CODE_REPEAT 0xFFFFFFFF
|
|
||||||
|
|
||||||
IRrecv My_Receiver(IR_RX_PIN);//Receive on pin IR_RX_PIN
|
|
||||||
IRdecode My_Decoder;
|
|
||||||
|
|
||||||
uint8_t PwmRed=0, PwmGreen=0, PwmBlue=0;
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
My_Receiver.enableIRIn(); // Start the receiver
|
|
||||||
pinMode(LED_RED_PIN, OUTPUT);
|
|
||||||
TinySoftPwm_begin(255,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
static uint32_t StartUs=micros(), LastIrCode=0;
|
|
||||||
|
|
||||||
if(My_Receiver.GetResults(&My_Decoder))
|
|
||||||
{
|
|
||||||
My_Decoder.decode();
|
|
||||||
if(My_Decoder.value==REPEAT && LastIrCode)
|
|
||||||
{
|
|
||||||
My_Decoder.value=LastIrCode;
|
|
||||||
}
|
|
||||||
switch(My_Decoder.value)
|
|
||||||
{
|
|
||||||
case CODE_BRIGHT_MINUS:
|
|
||||||
Tune(&PwmRed, -BRIGTH_STEP);
|
|
||||||
Tune(&PwmGreen, -BRIGTH_STEP);
|
|
||||||
Tune(&PwmBlue, -BRIGTH_STEP);
|
|
||||||
LastIrCode=CODE_BRIGHT_MINUS;
|
|
||||||
break;
|
|
||||||
case CODE_BRIGHT_PLUS:
|
|
||||||
if(PwmRed) Tune(&PwmRed, BRIGTH_STEP);
|
|
||||||
if(PwmGreen) Tune(&PwmGreen, BRIGTH_STEP);
|
|
||||||
if(PwmBlue) Tune(&PwmBlue, BRIGTH_STEP);
|
|
||||||
LastIrCode=CODE_BRIGHT_PLUS;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LastIrCode=0; /* No repeat for the following codes */
|
|
||||||
switch(My_Decoder.value)
|
|
||||||
{
|
|
||||||
case CODE_OFF:
|
|
||||||
RGB(0x00, 0x00, 0x00);
|
|
||||||
break;
|
|
||||||
case CODE_ON:
|
|
||||||
RGB(0x7A, 0x00, 0xBF);
|
|
||||||
break;
|
|
||||||
case CODE_RED: RGB(0xFF, 0x00, 0x00);break;
|
|
||||||
case CODE_GREEN: RGB(0x00, 0xFF, 0x00);break;
|
|
||||||
case CODE_BLUE: RGB(0x00, 0x00, 0xFF);break;
|
|
||||||
case CODE_WHITE: RGB(0xFF, 0xFF, 0xFF);break;
|
|
||||||
|
|
||||||
case CODE_ORANGE: RGB(0xFF, 0x7F, 0x00); break;
|
|
||||||
case CODE_ORANGE_LIGTH: RGB(0xFF, 0xAA, 0x00); break;
|
|
||||||
case CODE_BROWN: RGB(0xFF, 0xD4, 0x00); break;
|
|
||||||
case CODE_YELLOW: RGB(0xFF, 0xFF, 0x00); break;
|
|
||||||
|
|
||||||
case CODE_GREEN_LIGTH: RGB(0x00, 0xFF, 0xAA); break;
|
|
||||||
case CODE_GREEN_BLUE1: RGB(0x00, 0xFF, 0xFF); break;
|
|
||||||
case CODE_GREEN_BLUE2: RGB(0x00, 0xAA, 0xFF); break;
|
|
||||||
case CODE_GREEN_BLUE3: RGB(0x00, 0x55, 0xFF); break;
|
|
||||||
|
|
||||||
case CODE_BLUE_LIGTH: RGB(0x00, 0x00, 0x80); break;
|
|
||||||
case CODE_PURPLE_DARK: RGB(0x3F, 0x00, 0x80); break;
|
|
||||||
case CODE_PURPLE_LIGTH: RGB(0x7A, 0x00, 0xBF); break;
|
|
||||||
case CODE_PINK: RGB(0xFF, 0x00, 0xFF); break;
|
|
||||||
|
|
||||||
case CODE_FLASH: /* to be implemented */break;
|
|
||||||
case CODE_STROBE: /* to be implemented */break;
|
|
||||||
case CODE_FADE: /* to be implemented */break;
|
|
||||||
case CODE_SMOOTH: /* to be implemented */break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
My_Receiver.resume();
|
|
||||||
TinySoftPwm_analogWrite(LED_RED_PIN, GammaCorrection(PwmRed));
|
|
||||||
TinySoftPwm_analogWrite(LED_GREEN_PIN, GammaCorrection(PwmGreen));
|
|
||||||
TinySoftPwm_analogWrite(LED_BLUE_PIN, GammaCorrection(PwmBlue));
|
|
||||||
}
|
|
||||||
/***********************************************************/
|
|
||||||
/* Call TinySoftPwm_process() with a period of 60 us */
|
|
||||||
/* The PWM frequency = 255 x 60 # 15 ms -> F # 65Hz */
|
|
||||||
/* 255 is the first argument passed to TinySoftPwm_begin() */
|
|
||||||
/***********************************************************/
|
|
||||||
if((micros() - StartUs) >= 60)
|
|
||||||
{
|
|
||||||
/* We arrived here every 60 microseconds */
|
|
||||||
StartUs=micros();
|
|
||||||
TinySoftPwm_process(); /* This function shall be called periodically (like here, based on micros(), or in a timer ISR) */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RGB(uint8_t Red, uint8_t Green, uint8_t Blue)
|
|
||||||
{
|
|
||||||
PwmRed=Red;
|
|
||||||
PwmGreen=Green;
|
|
||||||
PwmBlue=Blue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t GammaCorrection(uint8_t Pwm)
|
|
||||||
{
|
|
||||||
return((Pwm*Pwm)>>8);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tune(uint8_t* Color, int8_t Offset)
|
|
||||||
{
|
|
||||||
if (Offset > 0) {
|
|
||||||
if ( *Color + Offset <= 255) {
|
|
||||||
*Color += Offset;
|
|
||||||
} else {
|
|
||||||
*Color = 255;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (*Color + Offset >= 0) {
|
|
||||||
*Color += Offset;
|
|
||||||
} else {
|
|
||||||
// *Color = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
|||||||
/* Example program for from IRLib – an Arduino library for infrared encoding and decoding
|
|
||||||
* Version 1.0 January 2013
|
|
||||||
* Copyright 2013 by Chris Young http://cyborg5.com
|
|
||||||
* Based on original example sketch for IRremote library
|
|
||||||
* Version 0.11 September, 2009
|
|
||||||
* Copyright 2009 Ken Shirriff
|
|
||||||
* http://arcfn.com
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* IRhashdecode - decode an arbitrary IR code.
|
|
||||||
* Instead of decoding using a standard encoding scheme
|
|
||||||
* (e.g. Sony, NEC, RC5), the code is hashed to a 32-bit value.
|
|
||||||
* This should produce a unique 32-bit number however that number cannot be used
|
|
||||||
* to retransmit the same code. This is just a quick and dirty way to detect a unique code
|
|
||||||
* for controlling a device when you don't really care what protocol or values
|
|
||||||
* are being sent.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <IRLib.h>
|
|
||||||
|
|
||||||
int RECV_PIN = 11;
|
|
||||||
IRrecv My_Receiver(RECV_PIN);
|
|
||||||
IRdecode My_Decoder;
|
|
||||||
IRdecodeHash My_Hash_Decoder;
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
My_Receiver.enableIRIn(); // Start the receiver
|
|
||||||
Serial.begin(9600);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
if (My_Receiver.GetResults(&My_Decoder)) {//Puts results in My_Decoder
|
|
||||||
//Restart the receiver so it can be capturing another code
|
|
||||||
//while we are working on decoding this one.
|
|
||||||
My_Receiver.resume();
|
|
||||||
My_Hash_Decoder.copyBuf(&My_Decoder);//copy the results to the hash decoder
|
|
||||||
My_Decoder.decode();
|
|
||||||
Serial.print("real decode type:");
|
|
||||||
Serial.print(Pnames(My_Decoder.decode_type));
|
|
||||||
Serial.print(" value: 0x");
|
|
||||||
Serial.print(My_Decoder.value, HEX);
|
|
||||||
My_Hash_Decoder.decode();
|
|
||||||
Serial.print(", hash decode: 0x");
|
|
||||||
Serial.println(My_Hash_Decoder.hash, HEX); // Do something interesting with this value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,130 +0,0 @@
|
|||||||
/* Example program for from IRLib – an Arduino library for infrared encoding and decoding
|
|
||||||
* Version 1.0 January 2013
|
|
||||||
* Copyright 2013 by Chris Young http://cyborg5.com
|
|
||||||
* Based on original example sketch for IRremote library
|
|
||||||
* Version 0.11 September, 2009
|
|
||||||
* Copyright 2009 Ken Shirriff
|
|
||||||
* http://arcfn.com
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* IRrecord: record and play back IR signals
|
|
||||||
* An IR detector/demodulator must be connected to the input RECV_PIN.
|
|
||||||
* An IR LED must be connected to the output PWM pin 3.
|
|
||||||
* Unlike the original version of this demo sketch, you need not hook up a pushbutton
|
|
||||||
* Simply send any character from the serial screen to send the recorded code.
|
|
||||||
* Also demonstrates how to use toggle bits which must be controlled outside
|
|
||||||
* the library routines.
|
|
||||||
* The logic is:
|
|
||||||
* If an IR code is received, record it.
|
|
||||||
* If A serial character is received, send the IR code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <IRLib.h>
|
|
||||||
|
|
||||||
int RECV_PIN = 11;
|
|
||||||
|
|
||||||
IRrecv My_Receiver(RECV_PIN);
|
|
||||||
IRdecode My_Decoder;
|
|
||||||
IRsend My_Sender;
|
|
||||||
/*
|
|
||||||
* Because this version of the library separated the receiver from the decoder,
|
|
||||||
* technically you would not need to "store" the code outside the decoder object
|
|
||||||
* for this overly simple example. All of the details would remain in the object.
|
|
||||||
* However we are going to go ahead and store them just to show you how.
|
|
||||||
*/
|
|
||||||
// Storage for the recorded code
|
|
||||||
IRTYPES codeType; // The type of code
|
|
||||||
unsigned long codeValue; // The data bits if type is not raw
|
|
||||||
int codeBits; // The length of the code in bits
|
|
||||||
// These values are only stored if it's an unknown type and we are going to use
|
|
||||||
// raw codes to resend the information.
|
|
||||||
unsigned int rawCodes[RAWBUF]; // The durations if raw
|
|
||||||
int rawCount; //The number of interval samples
|
|
||||||
|
|
||||||
bool GotOne, GotNew;
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
GotOne=false; GotNew=false;
|
|
||||||
codeType=UNKNOWN;
|
|
||||||
codeValue=0;
|
|
||||||
Serial.begin(9600);
|
|
||||||
Serial.println(F("Send a code from your remote and we will record it."));
|
|
||||||
Serial.println(F("Type any character and press enter. We will send the recorded code."));
|
|
||||||
My_Receiver.enableIRIn(); // Start the receiver
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stores the code for later playback
|
|
||||||
void storeCode(void) {
|
|
||||||
GotNew=true;
|
|
||||||
codeType = My_Decoder.decode_type;
|
|
||||||
if (codeType == UNKNOWN) {
|
|
||||||
Serial.println("Received unknown code, saving as raw");
|
|
||||||
// To store raw codes:
|
|
||||||
// Drop first value (gap)
|
|
||||||
// Convert from ticks to microseconds
|
|
||||||
// Tweak marks shorter, and spaces longer to cancel out IR receiver distortion
|
|
||||||
rawCount = My_Decoder.rawlen-1;
|
|
||||||
for (int i = 1; i <=rawCount; i++) {
|
|
||||||
rawCodes[i - 1] = My_Decoder.Interval_uSec(i);//Converts to microseconds and adjusts for Mark/space
|
|
||||||
};
|
|
||||||
My_Decoder.DumpResults();
|
|
||||||
codeType=UNKNOWN;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Serial.print(F("Received "));
|
|
||||||
Serial.print(Pnames(codeType));
|
|
||||||
if (My_Decoder.value == REPEAT) {
|
|
||||||
// Don't record a NEC repeat value as that's useless.
|
|
||||||
Serial.println("repeat; ignoring.");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
codeValue = My_Decoder.value;
|
|
||||||
codeBits = My_Decoder.bits;
|
|
||||||
}
|
|
||||||
Serial.print(F(" Value:0x"));
|
|
||||||
Serial.println(My_Decoder.value, HEX);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void sendCode(int repeat) {
|
|
||||||
if(codeType== UNKNOWN) {
|
|
||||||
// Assume 38 KHz
|
|
||||||
My_Sender.IRsendRaw::send(rawCodes,rawCount,38);
|
|
||||||
Serial.println("Sent raw");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if( !GotNew ) {//We've already sent this so handle toggle bits
|
|
||||||
if (codeType == RC5) {
|
|
||||||
codeValue ^= 0x0800;
|
|
||||||
}
|
|
||||||
else if (codeType == RC6) {
|
|
||||||
codeValue ^= 0x10000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GotNew=false;
|
|
||||||
My_Sender.send(codeType,codeValue,codeBits);
|
|
||||||
Serial.print(F("Sent "));
|
|
||||||
Serial.print(Pnames(codeType));
|
|
||||||
Serial.print(F(" Value:0x"));
|
|
||||||
Serial.println(codeValue, HEX);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
if (Serial.read() != -1) {
|
|
||||||
if(GotOne) {
|
|
||||||
sendCode(0);
|
|
||||||
My_Receiver.enableIRIn(); // Re-enable receiver
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (My_Receiver.GetResults(&My_Decoder)) {
|
|
||||||
//Restart the receiver so it can be capturing another code
|
|
||||||
//while we are working on decoding this one.
|
|
||||||
if(My_Decoder.decode()) {
|
|
||||||
GotOne=true;
|
|
||||||
storeCode();
|
|
||||||
}
|
|
||||||
delay(500);
|
|
||||||
My_Receiver.resume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
|||||||
/* Example program for from IRLib – an Arduino library for infrared encoding and decoding
|
|
||||||
* Version 1.0 January 2013
|
|
||||||
* Copyright 2013 by Chris Young http://cyborg5.com
|
|
||||||
* Based on original example sketch for IRremote library
|
|
||||||
* Version 0.11 September, 2009
|
|
||||||
* Copyright 2009 Ken Shirriff
|
|
||||||
* http://arcfn.com
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* IRLib: IRrecvDump - dump details of IR codes with IRrecv
|
|
||||||
* An IR detector/demodulator must be connected to the input RECV_PIN.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <IRLib.h>
|
|
||||||
|
|
||||||
int RECV_PIN = 11;
|
|
||||||
|
|
||||||
IRrecv My_Receiver(RECV_PIN);
|
|
||||||
|
|
||||||
IRdecode My_Decoder;
|
|
||||||
unsigned int Buffer[RAWBUF];
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Serial.begin(9600);
|
|
||||||
My_Receiver.enableIRIn(); // Start the receiver
|
|
||||||
My_Decoder.UseExtnBuf(Buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
if (My_Receiver.GetResults(&My_Decoder)) {
|
|
||||||
//Restart the receiver so it can be capturing another code
|
|
||||||
//while we are working on decoding this one.
|
|
||||||
My_Receiver.resume();
|
|
||||||
My_Decoder.decode();
|
|
||||||
My_Decoder.DumpResults();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
|||||||
/* Example program for from IRLib – an Arduino library for infrared encoding and decoding
|
|
||||||
* Version 1.0 January 2013
|
|
||||||
* Copyright 2013 by Chris Young http://cyborg5.com
|
|
||||||
* Based on original example sketch for IRremote library
|
|
||||||
* Version 0.11 September, 2009
|
|
||||||
* Copyright 2009 Ken Shirriff
|
|
||||||
* http://arcfn.com
|
|
||||||
*/
|
|
||||||
#include <IRLib.h>
|
|
||||||
|
|
||||||
IRsend My_Sender;
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Serial.begin(9600);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
if (Serial.read() != -1) {
|
|
||||||
//send a code every time a character is received from the serial port
|
|
||||||
//Sony DVD power A8BCA
|
|
||||||
My_Sender.send(SONY,0xa8bca, 20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
|||||||
/* Example program for from IRLib – an Arduino library for infrared encoding and decoding
|
|
||||||
* Version 1.0 January 2013
|
|
||||||
* Copyright 2013 by Chris Young http://cyborg5.com
|
|
||||||
* Based on original example sketch for IRremote library
|
|
||||||
* Version 0.11 September, 2009
|
|
||||||
* Copyright 2009 Ken Shirriff
|
|
||||||
* http://arcfn.com
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* JVC sends repeat codes that are identical to the regular JVC codes
|
|
||||||
* however they have no header. Therefore there is an additional parameter
|
|
||||||
* that tells you whether or not to send as an original code or as a repeat.
|
|
||||||
*
|
|
||||||
* The only device I had to test this protocol was an old JVC VCR. It would only work if at least
|
|
||||||
* 2 frames are sent separated by 45us of "space". All JVC is the same bit length so we use
|
|
||||||
* the third parameter as a to tell it whether or not to send the header.
|
|
||||||
* Once with the third parameter "1" then delay about 50 microseconds and send again
|
|
||||||
* with the third parameter "0".
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <IRLib.h>
|
|
||||||
|
|
||||||
IRsend My_Sender;
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Serial.begin(9600);
|
|
||||||
}
|
|
||||||
|
|
||||||
//send a code every time a character is received from the serial port
|
|
||||||
void loop() {
|
|
||||||
if (Serial.read() != -1) {
|
|
||||||
My_Sender.send(JVC,0xc2d0,1); delayMicroseconds (50);
|
|
||||||
My_Sender.send(JVC,0xc2d0,0); delayMicroseconds (50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
|||||||
#include <IRLib.h>
|
|
||||||
|
|
||||||
IRsend My_Sender;
|
|
||||||
|
|
||||||
int protocol;
|
|
||||||
long code;
|
|
||||||
int bits;
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(9600);
|
|
||||||
}
|
|
||||||
|
|
||||||
long parseHex (void) {
|
|
||||||
long Value=0; char C;delay(100);
|
|
||||||
while (Serial.available()>0) {
|
|
||||||
C= tolower(Serial.read());
|
|
||||||
if ((C>='0')&&(C<='9'))
|
|
||||||
C=C-'0';
|
|
||||||
else
|
|
||||||
if ((C>='a') && (C<='f'))
|
|
||||||
C=C-'a'+10;
|
|
||||||
else
|
|
||||||
return Value;
|
|
||||||
Value= C+(Value<<4);
|
|
||||||
};
|
|
||||||
return Value;
|
|
||||||
}
|
|
||||||
void parseDelimiter () {
|
|
||||||
char C;
|
|
||||||
while(Serial.available()>0) {
|
|
||||||
C=tolower(Serial.peek());
|
|
||||||
if( (C>='0') && (C<='9') )return;
|
|
||||||
if( (C>='a') && (C<='f') )return;
|
|
||||||
C=Serial.read();//throwaway delimiters
|
|
||||||
delay (5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// enum IRTYPES {UNKNOWN, NEC, SONY, RC5, RC6, PANASONIC_OLD, JVC, NECX, HASH_CODE, LAST_PROTOCOL=HASH_CODE};
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
if (Serial.available ()>0) {
|
|
||||||
protocol = Serial.parseInt (); parseDelimiter();
|
|
||||||
code = parseHex (); parseDelimiter();
|
|
||||||
bits = Serial.parseInt (); parseDelimiter();
|
|
||||||
/* Serial.print("Prot:"); Serial.print(protocol);
|
|
||||||
Serial.print(" Code:"); Serial.print(code,HEX);
|
|
||||||
Serial.print(" Bits:"); Serial.println(bits);
|
|
||||||
*/
|
|
||||||
My_Sender.send(IRTYPES(protocol), code, bits);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,133 +0,0 @@
|
|||||||
# IRLib demo script
|
|
||||||
# version 1.0 by Chris Young http://tech.cyborg5.com/irlib/
|
|
||||||
# Displays a "Virtual remote" on your screen. Clicking on the
|
|
||||||
# buttons sends serial datato the Arduino which in turn
|
|
||||||
# since IR signals to a cable box in TV.
|
|
||||||
|
|
||||||
# Import all of the necessary pieces of code
|
|
||||||
import serial, sys, pygame, pygame.mixer
|
|
||||||
from pygame.locals import *
|
|
||||||
|
|
||||||
# You will have to edit this to the proper port and speed
|
|
||||||
ser = serial.Serial('COM4', 9600)
|
|
||||||
|
|
||||||
pygame.init()
|
|
||||||
# Established screen size, size of buttons and position
|
|
||||||
size = width, height = 400, 768
|
|
||||||
button_size=54; button_offset=71
|
|
||||||
button_x1=65;button_y1=39
|
|
||||||
max_rows=10; max_columns=4
|
|
||||||
|
|
||||||
# Specify a font. I'm using Arial narrow bold from my Windows
|
|
||||||
# font folder. However the default font shown below also works.
|
|
||||||
myfont =pygame.font.Font ("c:/windows/fonts/ARIALNB.TTF",30)
|
|
||||||
#myfont=pygame.font.Font(None,36)
|
|
||||||
|
|
||||||
# These are the text labels that will appear on each button
|
|
||||||
label_text=("TVp", "CBp", "P^", "Pv",\
|
|
||||||
"<<", ">", ">>", "->",\
|
|
||||||
"Rec", "=", "s", "<-",\
|
|
||||||
"Gd", "^", "Fav", "Inf",\
|
|
||||||
|
|
||||||
"<", "sel", ">", "Lis",\
|
|
||||||
"ret", "v", "Prv", "Mnu",\
|
|
||||||
"1", "2", "3", "Ch+",\
|
|
||||||
|
|
||||||
"4", "5", "6", "Ch-",\
|
|
||||||
"7", "8", "9", "Vol+",\
|
|
||||||
"Pip", "0", "Mut", "Vol-",\
|
|
||||||
)
|
|
||||||
# Each of these 40 strings of text correspond to the
|
|
||||||
# protocol in code which will be sent over the USB serial
|
|
||||||
# to the Arduino. The first number is the protocol number.
|
|
||||||
# See the defined protocols in "IRLib.h"for the
|
|
||||||
# enum IRTYPES at about line 50. This example uses
|
|
||||||
# protocol 3 which is "RC5" used by my Magnavox TV
|
|
||||||
# and protocol 5 "PANASONIC_OLD" used by my Scientific
|
|
||||||
# Atlantic SA 8300 DVR. The protocol number is followed by
|
|
||||||
# the hex code to be transmitted. That is followed by the
|
|
||||||
# number of bits. Note that the PANASONIC_OLD protocol
|
|
||||||
# does not need the number of bits specified so they are omitted.
|
|
||||||
IR_Codes= ("3,180c,13","5,37c107","5,36d924","5,37d904",\
|
|
||||||
"5,37291a","5,37990c","5,36293a","5,36b129",\
|
|
||||||
"5,375914","5,374117","5,365934","5,37c906",\
|
|
||||||
"5,36c127","5,36812f","5,37f101","5,36213b",\
|
|
||||||
|
|
||||||
"5,37810f","5,366133","5,364137","5,36c926",\
|
|
||||||
"5,366932","5,37a10b","5,36e123","5,373918",\
|
|
||||||
"5,36113d","5,37111d","5,36912d","5,377111",\
|
|
||||||
|
|
||||||
"5,37910d","5,365135","5,375115","5,36f121",\
|
|
||||||
"5,36d125","5,37d105","5,363139","3,1810,13",\
|
|
||||||
"5,37b908","5,373119","3,180d,13","3,1811,13",\
|
|
||||||
)
|
|
||||||
# This function gets called to shut everything down
|
|
||||||
def Finished():
|
|
||||||
pygame.quit()
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
# Gets the button index based on mouse position. Returned
|
|
||||||
# value is from 0 to 39 (number of buttons-1)
|
|
||||||
# Returns -1 if you are not over a button.
|
|
||||||
def ComputeButton():
|
|
||||||
mx,my=pygame.mouse.get_pos()
|
|
||||||
mx=mx-button_x1
|
|
||||||
my=my-button_y1
|
|
||||||
bx=mx/button_offset; by=my/button_offset
|
|
||||||
if bx<0 or bx>=max_columns:return -1
|
|
||||||
if by<0 or by> max_rows:return -1
|
|
||||||
if (mx%button_offset)>button_size:return -1
|
|
||||||
if (my%button_offset)>button_size:return -1
|
|
||||||
return bx+by*max_columns
|
|
||||||
|
|
||||||
# Blits the button text from button number "i"
|
|
||||||
# onto the specified layer using the specified color.
|
|
||||||
def Show_Text(i,Layer,color=(0,0,0)):
|
|
||||||
t=label_text[i]
|
|
||||||
label = myfont.render (t,1,color)
|
|
||||||
labelpos= label.get_rect()
|
|
||||||
labelpos.centerx=button_x1+button_size/2+i%max_columns*button_offset
|
|
||||||
labelpos.centery=button_y1+button_size/2+i/max_columns*button_offset
|
|
||||||
Layer.blit(label,labelpos)
|
|
||||||
|
|
||||||
# Create the screen and load the background image.
|
|
||||||
screen = pygame.display.set_mode(size)
|
|
||||||
bg = pygame.image.load("remotebg.png")
|
|
||||||
|
|
||||||
# Blit black text labels onto the background image
|
|
||||||
for i in range (max_rows*max_columns):
|
|
||||||
Show_Text(i, bg)
|
|
||||||
# Copy the background to the display
|
|
||||||
screen.blit(bg,(0,0))
|
|
||||||
pygame.display.flip()
|
|
||||||
|
|
||||||
# Load the clicking sound
|
|
||||||
Click=pygame.mixer.Sound("click.wav")
|
|
||||||
|
|
||||||
# Used to detect when the mouse hovers over a different button
|
|
||||||
previous=-1
|
|
||||||
|
|
||||||
while 1:
|
|
||||||
for event in pygame.event.get():
|
|
||||||
if event.type == pygame.QUIT:
|
|
||||||
Finished()
|
|
||||||
elif event.type == KEYDOWN and event.key == K_ESCAPE:
|
|
||||||
Finished ()
|
|
||||||
elif event.type == MOUSEBUTTONDOWN:
|
|
||||||
i=ComputeButton() #which button did we click
|
|
||||||
if i>=0:
|
|
||||||
Click.play() #play the sound
|
|
||||||
ser.write(IR_Codes[i]) #send the codes
|
|
||||||
elif event.type==MOUSEMOTION:
|
|
||||||
i=ComputeButton() #which button are we over
|
|
||||||
if i!=previous: #difference in the last one?
|
|
||||||
if i>=0: #turn it red
|
|
||||||
Show_Text(i,screen,(255,0,0))
|
|
||||||
else: #or put it back the way it was
|
|
||||||
screen.blit(bg,(0,0))
|
|
||||||
previous=i
|
|
||||||
pygame.display.flip() #update the display
|
|
||||||
# That's all folks
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
|||||||
//POV-Ray source to generate the background image for IRserial_remote
|
|
||||||
// create rectangular areas with rounded corners for use as
|
|
||||||
// buttons and background objects.
|
|
||||||
|
|
||||||
// Render at 1024x768 then crop 312 pixels from each side
|
|
||||||
// leaving 400x768 final image.
|
|
||||||
#declare Area=15; //size of area lights
|
|
||||||
#declare CR=0.1; //corner radius
|
|
||||||
#declare ER= 0.5; //edge radius
|
|
||||||
#declare CX= 3; //width from corner to corner
|
|
||||||
#declare CY= 7.75; //height from corner to corner
|
|
||||||
#declare BZ=-ER; //Z offset for buttons
|
|
||||||
|
|
||||||
plane {z,0 pigment{rgb<0.8,0.85,1>*0.8}}//background
|
|
||||||
|
|
||||||
#macro Thing (ER,CR,CX,CY,T)
|
|
||||||
#local Corner=
|
|
||||||
union {
|
|
||||||
torus {CR,ER rotate x*90}
|
|
||||||
cylinder {ER*z,-ER*z,CR}
|
|
||||||
}
|
|
||||||
union {
|
|
||||||
object{Corner translate< CX,CY,0>}
|
|
||||||
object{Corner translate<-CX,CY,0>}
|
|
||||||
object{Corner translate< CX,-CY,0>}
|
|
||||||
object{Corner translate<-CX,-CY,0>}
|
|
||||||
cylinder{CY*y,-CY*y,ER translate<-CX-CR,0,0>}
|
|
||||||
cylinder{CY*y,-CY*y,ER translate< CX+CR,0,0>}
|
|
||||||
cylinder{CX*x,-CX*x,ER translate<0,-CY-CR,0>}
|
|
||||||
cylinder{CX*x,-CX*x,ER translate<0, CY+CR,0>}
|
|
||||||
box{<-CX,-CY-CR,-ER><CX,CY+CR,ER>}
|
|
||||||
box{<-CX-CR,-CY,-ER><CX+CR,CY,ER>}
|
|
||||||
texture {T}
|
|
||||||
}
|
|
||||||
#end
|
|
||||||
|
|
||||||
#declare BX= 0.4; #declare BY=BX;//size of the buttons
|
|
||||||
#declare White_Texture=texture{pigment{rgb 1}finish {ambient 0.3}}
|
|
||||||
#declare Blue_Texture=texture{pigment {rgb<0.85,0.9 ,1>}}
|
|
||||||
|
|
||||||
object {Thing(ER,CR,CX,CY, White_Texture)}//main object
|
|
||||||
//loop through the buttons
|
|
||||||
#declare R=-4.5;
|
|
||||||
#while (R<5.5)
|
|
||||||
#declare C=-1.5;
|
|
||||||
#while (C<=1.5)
|
|
||||||
object{Thing(0.1,0.2,(BX*0.8),(BY*0.8), Blue_Texture)
|
|
||||||
translate <C*BX*4,R*BY*4,BZ>
|
|
||||||
}
|
|
||||||
#declare C=C+1;
|
|
||||||
#end
|
|
||||||
#declare R=R+1;
|
|
||||||
#end
|
|
||||||
|
|
||||||
|
|
||||||
light_source{<50,50,-100>*5 color 0.8
|
|
||||||
#if (Area)area_light x*Area,y*Area,9,9#end
|
|
||||||
}
|
|
||||||
light_source{<0,0,-400>*3 rgb 1}
|
|
||||||
|
|
||||||
camera{orthographic location <0,0,-120> look_at <0,0,0> angle 11 }
|
|
||||||
//That's all folks!
|
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 48 KiB |
@ -1,68 +0,0 @@
|
|||||||
/* Example program for from IRLib – an Arduino library for infrared encoding and decoding
|
|
||||||
* Version 1.1 April 2013 by Chris Young http://cyborg5.com
|
|
||||||
* "IRservo" Control a servo using an IR remote
|
|
||||||
*/
|
|
||||||
#include <IRLib.h>
|
|
||||||
#include <Servo.h>
|
|
||||||
// You will have to set these values depending on the protocol
|
|
||||||
// and remote codes that you are using. These are from my Sony DVD/VCR
|
|
||||||
#define MY_PROTOCOL SONY
|
|
||||||
#define RIGHT_ARROW 0x86bca //Move several clockwise
|
|
||||||
#define LEFT_ARROW 0x46bca //Move servo counterclockwise
|
|
||||||
#define SELECT_BUTTON 0xd0bca //Center the servo
|
|
||||||
#define UP_ARROW 0x42bca //Increased number of degrees servo moves
|
|
||||||
#define DOWN_ARROW 0xc2bca //Decrease number of degrees servo moves
|
|
||||||
#define BUTTON_0 0x90bca //Pushing buttons 0-9 moves to fix positions
|
|
||||||
#define BUTTON_1 0x00bca // each 20 degrees greater
|
|
||||||
#define BUTTON_2 0x80bca
|
|
||||||
#define BUTTON_3 0x40bca
|
|
||||||
#define BUTTON_4 0xc0bca
|
|
||||||
#define BUTTON_5 0x20bca
|
|
||||||
#define BUTTON_6 0xa0bca
|
|
||||||
#define BUTTON_7 0x60bca
|
|
||||||
#define BUTTON_8 0xe0bca
|
|
||||||
#define BUTTON_9 0x10bca
|
|
||||||
|
|
||||||
IRrecv My_Receiver(11);//Receive on pin 11
|
|
||||||
IRdecode My_Decoder;
|
|
||||||
Servo My_Servo; // create servo object to control a servo
|
|
||||||
int pos; // variable to store the servo position
|
|
||||||
int Speed; // Number of degrees to move each time a left/right button is pressed
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
My_Receiver.No_Output();//Turn off any unused IR LED output circuit
|
|
||||||
My_Servo.attach(9); // attaches the servo on pin 9 to the servo object
|
|
||||||
pos = 90; // start at midpoint 90 degrees
|
|
||||||
Speed = 3; // servo moves 3 degrees each time left/right is pushed
|
|
||||||
My_Servo.write(pos); // Set initial position
|
|
||||||
My_Receiver.enableIRIn(); // Start the receiver
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
if (My_Receiver.GetResults(&My_Decoder)) {
|
|
||||||
My_Decoder.decode();
|
|
||||||
if(My_Decoder.decode_type==MY_PROTOCOL) {
|
|
||||||
switch(My_Decoder.value) {
|
|
||||||
case LEFT_ARROW: pos=min(180,pos+Speed); break;
|
|
||||||
case RIGHT_ARROW: pos=max(0,pos-Speed); break;
|
|
||||||
case SELECT_BUTTON: pos=90; break;
|
|
||||||
case UP_ARROW: Speed=min(10, Speed+1); break;
|
|
||||||
case DOWN_ARROW: Speed=max(1, Speed-1); break;
|
|
||||||
case BUTTON_0: pos=0*20; break;
|
|
||||||
case BUTTON_1: pos=1*20; break;
|
|
||||||
case BUTTON_2: pos=2*20; break;
|
|
||||||
case BUTTON_3: pos=3*20; break;
|
|
||||||
case BUTTON_4: pos=4*20; break;
|
|
||||||
case BUTTON_5: pos=5*20; break;
|
|
||||||
case BUTTON_6: pos=6*20; break;
|
|
||||||
case BUTTON_7: pos=7*20; break;
|
|
||||||
case BUTTON_8: pos=8*20; break;
|
|
||||||
case BUTTON_9: pos=9*20; break;
|
|
||||||
}
|
|
||||||
My_Servo.write(pos); // tell servo to go to position in variable 'pos'
|
|
||||||
}
|
|
||||||
My_Receiver.resume();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,120 +0,0 @@
|
|||||||
/* Example program for from IRLib – an Arduino library for infrared encoding and decoding
|
|
||||||
* Version 1.0 January 2013
|
|
||||||
* Copyright 2013 by Chris Young http://cyborg5.com
|
|
||||||
* Based on original example sketch for IRremote library
|
|
||||||
* Version 0.11 September, 2009
|
|
||||||
* Copyright 2009 Ken Shirriff
|
|
||||||
* http://arcfn.com
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* This example demonstrates how to extend this library to add a new protocol
|
|
||||||
* without actually modifying or recompiling the library itself. It implements a 36 bit
|
|
||||||
* Samsung protocol that is used on a Blu-ray player that I own.
|
|
||||||
* Because a 36 bit value will not fit in the value field (only 32 bits) we have to create
|
|
||||||
* a second value field.
|
|
||||||
*/
|
|
||||||
#include <IRLib.h>
|
|
||||||
#include <IRLibMatch.h>
|
|
||||||
|
|
||||||
int RECV_PIN = 11;
|
|
||||||
|
|
||||||
IRrecv My_Receiver(RECV_PIN);
|
|
||||||
#define SAMSUNG36 (LAST_PROTOCOL+1) //Unfortunately cannot extend an enum. This is the best we can do.
|
|
||||||
|
|
||||||
/*Is the value in this if statement is "1" then we will extend the base decoder.
|
|
||||||
*The result is this will only decode Samsung 36 and no others.
|
|
||||||
*If the value is "0" we will extend the all-inclusive decoder.
|
|
||||||
*Try changing this value and note the effect on code size when compiling.
|
|
||||||
*/
|
|
||||||
#if(1)
|
|
||||||
#define MY_BASE IRdecodeBase
|
|
||||||
#else
|
|
||||||
#define MY_BASE IRdecode
|
|
||||||
#endif
|
|
||||||
class IRdecodeSamsung36: public virtual MY_BASE{
|
|
||||||
public:
|
|
||||||
bool decode(void);
|
|
||||||
unsigned int value2;
|
|
||||||
void Reset(void);
|
|
||||||
void DumpResults(void);
|
|
||||||
private:
|
|
||||||
bool GetBit(void);
|
|
||||||
int offset;
|
|
||||||
unsigned long data;
|
|
||||||
};
|
|
||||||
void IRdecodeSamsung36::Reset(void) {
|
|
||||||
MY_BASE::Reset();//respect your parents
|
|
||||||
value2=0;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool IRdecodeSamsung36::GetBit(void) {
|
|
||||||
if (!MATCH_MARK (rawbuf[offset],500)) return DATA_MARK_ERROR;
|
|
||||||
offset++;
|
|
||||||
if (MATCH_SPACE(rawbuf[offset],1500)) {
|
|
||||||
data = (data << 1) | 1;
|
|
||||||
}
|
|
||||||
else if (MATCH_SPACE (rawbuf[offset],500)) {
|
|
||||||
data <<= 1;
|
|
||||||
}
|
|
||||||
else return DATA_SPACE_ERROR;
|
|
||||||
offset++;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
/*
|
|
||||||
* According to http://www.hifi-remote.com/johnsfine/DecodeIR.html#Samsung36
|
|
||||||
* The IRP notation for this protocol is:
|
|
||||||
* {38k,500}<1,-1|1,-3>(9,-9,D:8,S:8,1,-9,E:4,F:8,-68u,~F:8,1,-118)+
|
|
||||||
* This means it uses 38k frequency. Base timing is multiples of 500.
|
|
||||||
* A "0" is mark(500) space(500). A "1" is mark (500) space(1500)
|
|
||||||
* The header is mark(4500) space(4500).
|
|
||||||
* The header is followed by 16 bits (8 device, 8 sub device)
|
|
||||||
* This is followed by a mark(500) space(4500).
|
|
||||||
* This is followed by 12 more bits (4+8)
|
|
||||||
* This is followed by 68us ofspace. Followed by eight more bits
|
|
||||||
* and a final stop bit.
|
|
||||||
*/
|
|
||||||
bool IRdecodeSamsung36::decode(void) {
|
|
||||||
if(MY_BASE::decode()) return true;
|
|
||||||
ATTEMPT_MESSAGE(F("Samsung36"));
|
|
||||||
if (rawlen != 78) return RAW_COUNT_ERROR;
|
|
||||||
if (!MATCH_MARK(rawbuf[1],4500)) return HEADER_MARK_ERROR;
|
|
||||||
if (!MATCH_SPACE(rawbuf[2],4500)) return HEADER_SPACE_ERROR;
|
|
||||||
offset=3; data=0;
|
|
||||||
//Get first 18 bits
|
|
||||||
while (offset < 16*2+2) if(!GetBit()) return false;
|
|
||||||
//Skip middle header
|
|
||||||
if (!MATCH_MARK(rawbuf[offset],500)) return DATA_MARK_ERROR;
|
|
||||||
offset++;
|
|
||||||
if (!MATCH_SPACE(rawbuf[offset],4500)) return DATA_SPACE_ERROR;
|
|
||||||
//save first 18 bits in "value" and reset data
|
|
||||||
offset++; value=data; data=0;
|
|
||||||
rawbuf[62]=(rawbuf[62]*USECPERTICK-68)/USECPERTICK;
|
|
||||||
while(offset<77)if(!GetBit()) return false;
|
|
||||||
bits =36;//set bit length
|
|
||||||
value2 = data;//put remaining bits in value2
|
|
||||||
decode_type= static_cast<IRTYPES>SAMSUNG36;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
void IRdecodeSamsung36::DumpResults(void){
|
|
||||||
if(decode_type==SAMSUNG36) {
|
|
||||||
Serial.print(F("Decoded Samsung36: Value1:")); Serial.print(value, HEX);
|
|
||||||
Serial.print(F(": Value2:")); Serial.print(value2, HEX);
|
|
||||||
};
|
|
||||||
MY_BASE::DumpResults();
|
|
||||||
};
|
|
||||||
IRdecodeSamsung36 My_Decoder;
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Serial.begin(9600);
|
|
||||||
My_Receiver.enableIRIn(); // Start the receiver
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
if (My_Receiver.GetResults(&My_Decoder)) {
|
|
||||||
My_Decoder.decode();
|
|
||||||
My_Decoder.DumpResults();
|
|
||||||
My_Receiver.resume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
|||||||
CHANGES
|
|
||||||
|
|
||||||
|
|
||||||
2015-01-10 (nb)
|
|
||||||
|
|
||||||
Fixed and improved initialization. New and improved printing of text. Updated texts.
|
|
||||||
|
|
||||||
- Fixed initialization commands.
|
|
||||||
- Implemented ssd1306_init more efficiently.
|
|
||||||
- New functions ssd1306_send_command_start, ssd1306_send_command_stop.
|
|
||||||
- Improved ssd1306_setpos, more efficient.
|
|
||||||
- Reimplemented function ssd1306_char_f6x8 as improved ssd1306_char_font6x8 printing single characters only, added new ssd1306_string_font6x8 for printing strings.
|
|
||||||
- The font8x16 functions and data moved to another file until properly implemented.
|
|
||||||
- Added to the Make file ssd1306xled8x16 file.
|
|
||||||
- Updated testing text displayed on the screen.
|
|
||||||
|
|
||||||
|
|
||||||
2015-01-10 (nb)
|
|
||||||
|
|
||||||
Changed default pins for display, now PB0=SCL and PB1=SDA. Source code reformatting, improvements, edited comments.
|
|
||||||
|
|
||||||
- Changed default pins for connecting to the display for consistency with the built-in TWI interface, they are now PB0=SCL and PB1=SDA.
|
|
||||||
- Source code, removed redundant initializations of variables.
|
|
||||||
- Source code reformatting, edited comments.
|
|
||||||
|
|
||||||
|
|
||||||
2015-01-10 (nb)
|
|
||||||
|
|
||||||
Fixed some warnings, variables renamed. The font16x16/Chinese stuff moved to other folders.
|
|
||||||
|
|
||||||
- Font variable ssd1306xled_font8X16 renamed to ssd1306xled_font8x16 for consistency. TODO: rename "ssd1306xled_font8x16" file as well.
|
|
||||||
- Fixed ssd1306_draw_bmp prototype: added "const" to bitmap so it wont't generate warning.
|
|
||||||
- Files related to font 16x16 (Chinese) moved to different folders: font16x16cn.h.
|
|
||||||
- Functions and other code related to font 16x16 (Chinese) moved to different folders.
|
|
||||||
- Source code reformatting, edited comments.
|
|
||||||
|
|
||||||
|
|
||||||
2014-10-26 (gs)
|
|
||||||
|
|
||||||
Make project compile on gcc-avr - turn static images to consts, and rename include of font16x16cn.h
|
|
||||||
|
|
||||||
|
|
||||||
2014-08-13 (nb)
|
|
||||||
|
|
||||||
More files added to the repository.
|
|
||||||
|
|
||||||
|
|
||||||
2014-08-11 (nb)
|
|
||||||
|
|
||||||
Files added to the repository.
|
|
||||||
|
|
||||||
|
|
@ -1,246 +0,0 @@
|
|||||||
/*
|
|
||||||
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
|
|
||||||
*
|
|
||||||
* @created: 2014-08-12
|
|
||||||
* @author: Neven Boyanov
|
|
||||||
*
|
|
||||||
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <avr/io.h>
|
|
||||||
|
|
||||||
#include <avr/pgmspace.h>
|
|
||||||
|
|
||||||
#include "DigisparkOLED.h"
|
|
||||||
#include "font6x8.h"
|
|
||||||
|
|
||||||
#ifndef _nofont_8x16 // tBUG Optional removal to save code space
|
|
||||||
#include "font8x16.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Some code based on "IIC_wtihout_ACK" by http://www.14blog.com/archives/1358
|
|
||||||
|
|
||||||
const uint8_t ssd1306_init_sequence [] PROGMEM = { // Initialization Sequence
|
|
||||||
0xAE, // Display OFF (sleep mode)
|
|
||||||
0x20, 0b00, // Set Memory Addressing Mode
|
|
||||||
// 00=Horizontal Addressing Mode; 01=Vertical Addressing Mode;
|
|
||||||
// 10=Page Addressing Mode (RESET); 11=Invalid
|
|
||||||
0xB0, // Set Page Start Address for Page Addressing Mode, 0-7
|
|
||||||
0xC8, // Set COM Output Scan Direction
|
|
||||||
0x00, // ---set low column address
|
|
||||||
0x10, // ---set high column address
|
|
||||||
0x40, // --set start line address
|
|
||||||
0x81, 0x3F, // Set contrast control register
|
|
||||||
0xA1, // Set Segment Re-map. A0=address mapped; A1=address 127 mapped.
|
|
||||||
0xA6, // Set display mode. A6=Normal; A7=Inverse
|
|
||||||
0xA8, 0x3F, // Set multiplex ratio(1 to 64)
|
|
||||||
0xA4, // Output RAM to Display
|
|
||||||
// 0xA4=Output follows RAM content; 0xA5,Output ignores RAM content
|
|
||||||
0xD3, 0x00, // Set display offset. 00 = no offset
|
|
||||||
0xD5, // --set display clock divide ratio/oscillator frequency
|
|
||||||
0xF0, // --set divide ratio
|
|
||||||
0xD9, 0x22, // Set pre-charge period
|
|
||||||
0xDA, 0x12, // Set com pins hardware configuration
|
|
||||||
0xDB, // --set vcomh
|
|
||||||
0x20, // 0x20,0.77xVcc
|
|
||||||
0x8D, 0x14, // Set DC-DC enable
|
|
||||||
0xAF // Display ON in normal mode
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t oledFont, oledX, oledY = 0;
|
|
||||||
|
|
||||||
// Program: 5248 bytes
|
|
||||||
|
|
||||||
SSD1306Device::SSD1306Device(void){}
|
|
||||||
|
|
||||||
|
|
||||||
void SSD1306Device::begin(void)
|
|
||||||
{
|
|
||||||
Wire.begin();
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < sizeof (ssd1306_init_sequence); i++) {
|
|
||||||
ssd1306_send_command(pgm_read_byte(&ssd1306_init_sequence[i]));
|
|
||||||
}
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SSD1306Device::setFont(uint8_t font)
|
|
||||||
{
|
|
||||||
oledFont = font;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSD1306Device::ssd1306_send_command_start(void) {
|
|
||||||
Wire.beginTransmission(SSD1306);
|
|
||||||
Wire.write(0x00); // write command
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSD1306Device::ssd1306_send_command_stop(void) {
|
|
||||||
Wire.endTransmission();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSD1306Device::ssd1306_send_data_byte(uint8_t byte)
|
|
||||||
{
|
|
||||||
if(Wire.writeAvailable()){
|
|
||||||
ssd1306_send_data_stop();
|
|
||||||
ssd1306_send_data_start();
|
|
||||||
}
|
|
||||||
Wire.write(byte);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSD1306Device::ssd1306_send_command(uint8_t command)
|
|
||||||
{
|
|
||||||
ssd1306_send_command_start();
|
|
||||||
Wire.write(command);
|
|
||||||
ssd1306_send_command_stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSD1306Device::ssd1306_send_data_start(void)
|
|
||||||
{
|
|
||||||
Wire.beginTransmission(SSD1306);
|
|
||||||
Wire.write(0x40); //write data
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSD1306Device::ssd1306_send_data_stop(void)
|
|
||||||
{
|
|
||||||
Wire.endTransmission();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSD1306Device::setCursor(uint8_t x, uint8_t y)
|
|
||||||
{
|
|
||||||
ssd1306_send_command_start();
|
|
||||||
Wire.write(0xb0 + y);
|
|
||||||
Wire.write(((x & 0xf0) >> 4) | 0x10); // | 0x10
|
|
||||||
Wire.write((x & 0x0f) | 0x01); // | 0x01
|
|
||||||
ssd1306_send_command_stop();
|
|
||||||
oledX = x;
|
|
||||||
oledY = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSD1306Device::clear(void)
|
|
||||||
{
|
|
||||||
fill(0x00);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSD1306Device::fill(uint8_t fill)
|
|
||||||
{
|
|
||||||
uint8_t m,n;
|
|
||||||
for (m = 0; m < 8; m++)
|
|
||||||
{
|
|
||||||
ssd1306_send_command(0xb0 + m); // page0 - page1
|
|
||||||
ssd1306_send_command(0x00); // low column start address
|
|
||||||
ssd1306_send_command(0x10); // high column start address
|
|
||||||
ssd1306_send_data_start();
|
|
||||||
for (n = 0; n < 128; n++)
|
|
||||||
{
|
|
||||||
ssd1306_send_data_byte(fill);
|
|
||||||
}
|
|
||||||
ssd1306_send_data_stop();
|
|
||||||
}
|
|
||||||
setCursor(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t SSD1306Device::write(byte c) {
|
|
||||||
uint8_t i = 0;
|
|
||||||
uint8_t ci = c - 32;
|
|
||||||
if(c == '\r')
|
|
||||||
return 1;
|
|
||||||
if(c == '\n'){
|
|
||||||
if(oledFont == FONT6X8) { // tBUG
|
|
||||||
oledY++;
|
|
||||||
// if ( oledY > 7) // tBUG
|
|
||||||
// oledY = 7;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
oledY+=2; //tBUG Large Font up by two
|
|
||||||
if ( oledY > 6) // tBUG
|
|
||||||
oledY = 6;
|
|
||||||
}
|
|
||||||
setCursor(0, oledY);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(oledFont == FONT6X8){
|
|
||||||
if (oledX > 122)
|
|
||||||
{
|
|
||||||
oledX = 0;
|
|
||||||
oledY++;
|
|
||||||
if ( oledY > 7) // tBUG
|
|
||||||
oledY = 7;
|
|
||||||
setCursor(oledX, oledY);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssd1306_send_data_start();
|
|
||||||
for (i= 0; i < 6; i++)
|
|
||||||
{
|
|
||||||
ssd1306_send_data_byte(pgm_read_byte(&ssd1306xled_font6x8[ci * 6 + i]));
|
|
||||||
}
|
|
||||||
ssd1306_send_data_stop();
|
|
||||||
setCursor(oledX+6, oledY);
|
|
||||||
}
|
|
||||||
#ifndef _nofont_8x16 // tBUG
|
|
||||||
else{
|
|
||||||
if (oledX > 120)
|
|
||||||
{
|
|
||||||
oledX = 0;
|
|
||||||
oledY+=2; //tBUG Large Font up by two
|
|
||||||
// oledY++;
|
|
||||||
if ( oledY > 6) // tBUG
|
|
||||||
oledY = 6;
|
|
||||||
setCursor(oledX, oledY);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssd1306_send_data_start();
|
|
||||||
for (i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
Wire.write(pgm_read_byte(&ssd1306xled_font8x16[ci * 16 + i]));
|
|
||||||
}
|
|
||||||
ssd1306_send_data_stop();
|
|
||||||
setCursor(oledX, oledY + 1);
|
|
||||||
ssd1306_send_data_start();
|
|
||||||
for (i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
Wire.write(pgm_read_byte(&ssd1306xled_font8x16[ci * 16 + i + 8]));
|
|
||||||
}
|
|
||||||
ssd1306_send_data_stop();
|
|
||||||
setCursor(oledX + 8, oledY - 1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SSD1306Device::bitmap(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[])
|
|
||||||
{
|
|
||||||
uint16_t j = 0;
|
|
||||||
uint8_t y, x;
|
|
||||||
// if (y1 % 8 == 0) y = y1 / 8; // else y = y1 / 8 + 1; // tBUG :: this does nothing as y is initialized below
|
|
||||||
// THIS PARAM rule on y makes any adjustment here WRONG //usage oled.bitmap(START X IN PIXELS, START Y IN ROWS OF 8 PIXELS, END X IN PIXELS, END Y IN ROWS OF 8 PIXELS, IMAGE ARRAY);
|
|
||||||
for (y = y0; y < y1; y++)
|
|
||||||
{
|
|
||||||
setCursor(x0,y);
|
|
||||||
ssd1306_send_data_start();
|
|
||||||
for (x = x0; x < x1; x++)
|
|
||||||
{
|
|
||||||
ssd1306_send_data_byte(pgm_read_byte(&bitmap[j++]));
|
|
||||||
}
|
|
||||||
ssd1306_send_data_stop();
|
|
||||||
}
|
|
||||||
setCursor(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SSD1306Device oled;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
|
|
||||||
*
|
|
||||||
* @created: 2014-08-12
|
|
||||||
* @author: Neven Boyanov
|
|
||||||
*
|
|
||||||
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <Wire.h>
|
|
||||||
// #include <avr/pgmspace.h>
|
|
||||||
// #include <avr/interrupt.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
|
|
||||||
#ifndef DIGISPARKOLED_H
|
|
||||||
#define DIGISPARKOLED_H
|
|
||||||
|
|
||||||
// #define _nofont_8x16 //tBUG
|
|
||||||
#ifndef _nofont_8x16 //tBUG
|
|
||||||
#define FONT8X16 1
|
|
||||||
#endif
|
|
||||||
#define FONT6X8 0
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#ifndef SSD1306
|
|
||||||
#define SSD1306 0x3C // Slave address
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
class SSD1306Device: public Print {
|
|
||||||
|
|
||||||
public:
|
|
||||||
SSD1306Device(void);
|
|
||||||
void begin(void);
|
|
||||||
void setFont(uint8_t font);
|
|
||||||
void ssd1306_send_command(uint8_t command);
|
|
||||||
void ssd1306_send_data_byte(uint8_t byte);
|
|
||||||
void ssd1306_send_data_start(void);
|
|
||||||
void ssd1306_send_data_stop(void);
|
|
||||||
void setCursor(uint8_t x, uint8_t y);
|
|
||||||
void fill(uint8_t fill);
|
|
||||||
void clear(void);
|
|
||||||
void bitmap(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[]);
|
|
||||||
void ssd1306_send_command_start(void);
|
|
||||||
void ssd1306_send_command_stop(void);
|
|
||||||
void ssd1306_char_f8x16(uint8_t x, uint8_t y, const char ch[]);
|
|
||||||
virtual size_t write(byte c);
|
|
||||||
using Print::write;
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
extern SSD1306Device oled;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,11 +0,0 @@
|
|||||||
Overhauled to support Wire library, print library, and generally be more "Arduino friendly" - renamed DigiOLED to avoid confussion - 1/14/2015 by Erik Kettenburg/Digistump
|
|
||||||
|
|
||||||
Ported to Arduino CPP and working on DigiStump Pro 1/11/15 by defragster
|
|
||||||
|
|
||||||
SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
|
|
||||||
|
|
||||||
SSD1306xLED is a C library for working with the SSD1306 display driver to control dot matrix OLED/PLED 128x64 displays. It is intended to be used with the Tinusaur board but should also work with any other board based on ATtiny85 or similar microcontroller.
|
|
||||||
|
|
||||||
SSD1306xLED is written in plain C and does not require any additional libraries to function except those that come with the WinAVR SDK.
|
|
||||||
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
|||||||
RESEARCH
|
|
||||||
|
|
||||||
|
|
||||||
SSD1306
|
|
||||||
http://www.solomon-systech.com/en/product/display-ic/oled-driver-controller/ssd1306/
|
|
||||||
SSD1306 is a single-chip CMOS OLED/PLED driver with controller for organic / polymer light emitting diode dot-matrix graphic display system. It consists of 128 segments and 64 commons. This IC is designed for Common Cathode type OLED panel.
|
|
||||||
|
|
||||||
|
|
||||||
---- SSD1306 Datasheets ----
|
|
||||||
|
|
||||||
https://www.adafruit.com/datasheets/SSD1306.pdf
|
|
||||||
|
|
||||||
http://www.crystalfontz.com/controllers/Solomon_Systech_SSD1306_v1.1_April_2008.pdf
|
|
||||||
|
|
||||||
|
|
||||||
---- Other SSD1306 Libraries ----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---- Projects ----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---- Other References ----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
|||||||
TODO
|
|
||||||
|
|
||||||
|
|
||||||
- Implement power saving mode
|
|
||||||
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
|||||||
#include <DigisparkOLED.h>
|
|
||||||
#include <Wire.h>
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#include "img0_128x64c1.h"
|
|
||||||
#include "digistump_128x64c1.h"
|
|
||||||
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
// put your setup code here, to run once:
|
|
||||||
|
|
||||||
oled.begin();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
|
|
||||||
// put your main code here, to run repeatedly:
|
|
||||||
oled.fill(0xFF); //fill screen with color
|
|
||||||
delay(1000);
|
|
||||||
oled.clear(); //all black
|
|
||||||
delay(1000);
|
|
||||||
//usage: oled.setCursor(X IN PIXELS, Y IN ROWS OF 8 PIXELS STARTING WITH 0);
|
|
||||||
oled.setCursor(0, 0); //top left
|
|
||||||
oled.setFont(FONT8X16);
|
|
||||||
oled.print(F("DIGISTUMP")); //wrap strings in F() to save RAM!
|
|
||||||
oled.setFont(FONT6X8);
|
|
||||||
oled.print(F(" OLED!"));
|
|
||||||
oled.setCursor(0, 2); //two rows down because the 8x16 font takes two rows of 8
|
|
||||||
oled.println(F("test")); //println will move the cursor 8 or 16 pixels down (based on the front) and back to X=0
|
|
||||||
oled.print(F("test test test test test")); //lines auto wrap
|
|
||||||
|
|
||||||
delay(3000);
|
|
||||||
//usage oled.bitmap(START X IN PIXELS, START Y IN ROWS OF 8 PIXELS, END X IN PIXELS, END Y IN ROWS OF 8 PIXELS, IMAGE ARRAY);
|
|
||||||
oled.bitmap(0, 0, 128, 8, img0_128x64c1);
|
|
||||||
delay(3000);
|
|
||||||
oled.bitmap(0, 0, 128, 8, digistumplogo);
|
|
||||||
delay(3000);
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// File generated by LCD Assistant
|
|
||||||
// http://en.radzio.dxp.pl/bitmap_converter/
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#include <avr/pgmspace.h>
|
|
||||||
|
|
||||||
|
|
||||||
const uint8_t digistumplogo [] PROGMEM = {
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xF0, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
|
|
||||||
0xE0, 0xE0, 0xE0, 0xE0, 0xF0, 0xF8, 0xF8, 0xFC, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0xE0, 0xF0, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xBF, 0xDF, 0xFF,
|
|
||||||
0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x0F, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C,
|
|
||||||
0xFC, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC,
|
|
||||||
0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC, 0xFC,
|
|
||||||
0xFC, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x3F, 0xBF, 0x9F, 0xDF, 0xEF, 0xEF, 0xF7, 0xF7, 0xFB, 0xFD, 0xFD, 0xFE, 0xFF, 0x7F, 0x7F, 0x7F,
|
|
||||||
0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x0F, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C,
|
|
||||||
0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0x3C, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0x3F, 0x3F, 0x03, 0x03, 0x03, 0x03, 0x3F, 0x3F, 0x3F, 0x3F, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C,
|
|
||||||
0x3C, 0x3C, 0xFC, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C,
|
|
||||||
0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC, 0xFC,
|
|
||||||
0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC, 0xFC, 0xFC,
|
|
||||||
0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x1E,
|
|
||||||
0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0xFE, 0xFE, 0xE0, 0xE0, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0x00, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
|
|
||||||
0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
|
|
||||||
0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F,
|
|
||||||
0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F,
|
|
||||||
0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E,
|
|
||||||
0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E,
|
|
||||||
0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0xFF, 0xFF, 0xFF,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E,
|
|
||||||
0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F,
|
|
||||||
0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
||||||
};
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// File generated by LCD Assistant
|
|
||||||
// http://en.radzio.dxp.pl/bitmap_converter/
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#include <avr/pgmspace.h>
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
const uint8_t img0_128x64c1 [] PROGMEM = {
|
|
||||||
|
|
||||||
0x00,0x03,0x05,0x09,0x11,0xFF,0x11,0x89,0x05,0xC3,0x00,0xE0,0x00,0xF0,0x00,0xF8,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x28,0xFF,0x11,0xAA,0x44,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x01,0x38,0x44,0x82,0x92,
|
|
||||||
0x92,0x74,0x01,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x44,0xFF,0x01,0x7D,
|
|
||||||
0x7D,0x7D,0x01,0x7D,0x7D,0x7D,0x7D,0x01,0x7D,0x7D,0x7D,0x7D,0x7D,0x01,0xFF,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,
|
|
||||||
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x3F,0x03,0x03,
|
|
||||||
0xF3,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x01,0xF1,0x11,0x61,0x81,0x01,0x01,0x01,
|
|
||||||
0x81,0x61,0x11,0xF1,0x01,0x01,0x01,0x01,0x41,0x41,0xF1,0x01,0x01,0x01,0x01,0x01,
|
|
||||||
0xC1,0x21,0x11,0x11,0x11,0x11,0x21,0xC1,0x01,0x01,0x01,0x01,0x41,0x41,0xF1,0x01,
|
|
||||||
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x11,0x11,0x11,0x11,0x11,0xD3,0x33,
|
|
||||||
0x03,0x03,0x3F,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xE0,0x00,0x00,
|
|
||||||
0x7F,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x7F,0x00,0x00,0x01,0x06,0x18,0x06,
|
|
||||||
0x01,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x40,0x40,0x7F,0x40,0x40,0x00,0x00,0x00,
|
|
||||||
0x1F,0x20,0x40,0x40,0x40,0x40,0x20,0x1F,0x00,0x00,0x00,0x00,0x40,0x40,0x7F,0x40,
|
|
||||||
0x40,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x40,0x30,0x0C,0x03,0x00,0x00,
|
|
||||||
0x00,0x00,0xE0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x06,0x06,
|
|
||||||
0x06,0x06,0x04,0x04,0x04,0x84,0x44,0x44,0x44,0x84,0x04,0x04,0x84,0x44,0x44,0x44,
|
|
||||||
0x84,0x04,0x04,0x04,0x84,0xC4,0x04,0x04,0x04,0x04,0x84,0x44,0x44,0x44,0x84,0x04,
|
|
||||||
0x04,0x04,0x04,0x04,0x84,0x44,0x44,0x44,0x84,0x04,0x04,0x04,0x04,0x04,0x84,0x44,
|
|
||||||
0x44,0x44,0x84,0x04,0x04,0x84,0x44,0x44,0x44,0x84,0x04,0x04,0x04,0x04,0x06,0x06,
|
|
||||||
0x06,0x06,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x10,0x18,0x14,0x12,0x11,0x00,0x00,0x0F,0x10,0x10,0x10,
|
|
||||||
0x0F,0x00,0x00,0x00,0x10,0x1F,0x10,0x00,0x00,0x00,0x08,0x10,0x12,0x12,0x0D,0x00,
|
|
||||||
0x00,0x18,0x00,0x00,0x0D,0x12,0x12,0x12,0x0D,0x00,0x00,0x18,0x00,0x00,0x10,0x18,
|
|
||||||
0x14,0x12,0x11,0x00,0x00,0x10,0x18,0x14,0x12,0x11,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,
|
|
||||||
0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x7F,0x03,0x0C,0x30,0x0C,0x03,0x7F,0x00,0x00,0x38,0x54,0x54,0x58,0x00,0x00,
|
|
||||||
0x7C,0x04,0x04,0x78,0x00,0x00,0x3C,0x40,0x40,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xAA,0xAA,0xAA,
|
|
||||||
0x28,0x08,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x03,0x0C,0x30,0x0C,0x03,0x7F,
|
|
||||||
0x00,0x00,0x26,0x49,0x49,0x49,0x32,0x00,0x00,0x7F,0x02,0x04,0x08,0x10,0x7F,0x00,
|
|
||||||
};
|
|
@ -1,113 +0,0 @@
|
|||||||
/*
|
|
||||||
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
|
|
||||||
*
|
|
||||||
* @created: 2014-08-12
|
|
||||||
* @author: Neven Boyanov
|
|
||||||
*
|
|
||||||
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#include <avr/pgmspace.h>
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/* Standard ASCII 6x8 font */
|
|
||||||
const uint8_t ssd1306xled_font6x8 [] PROGMEM = {
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
|
|
||||||
0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
|
|
||||||
0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // "
|
|
||||||
0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // #
|
|
||||||
0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $
|
|
||||||
0x00, 0x62, 0x64, 0x08, 0x13, 0x23, // %
|
|
||||||
0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // &
|
|
||||||
0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // '
|
|
||||||
0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // (
|
|
||||||
0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // )
|
|
||||||
0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // *
|
|
||||||
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // +
|
|
||||||
0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // ,
|
|
||||||
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // -
|
|
||||||
0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // .
|
|
||||||
0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // /
|
|
||||||
0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
|
|
||||||
0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1
|
|
||||||
0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2
|
|
||||||
0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3
|
|
||||||
0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4
|
|
||||||
0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5
|
|
||||||
0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
|
|
||||||
0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7
|
|
||||||
0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8
|
|
||||||
0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9
|
|
||||||
0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // :
|
|
||||||
0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ;
|
|
||||||
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // <
|
|
||||||
0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // =
|
|
||||||
0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // >
|
|
||||||
0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ?
|
|
||||||
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @
|
|
||||||
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A
|
|
||||||
0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B
|
|
||||||
0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C
|
|
||||||
0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D
|
|
||||||
0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E
|
|
||||||
0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F
|
|
||||||
0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G
|
|
||||||
0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H
|
|
||||||
0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I
|
|
||||||
0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J
|
|
||||||
0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K
|
|
||||||
0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L
|
|
||||||
0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
|
|
||||||
0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N
|
|
||||||
0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O
|
|
||||||
0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P
|
|
||||||
0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
|
|
||||||
0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R
|
|
||||||
0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S
|
|
||||||
0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T
|
|
||||||
0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U
|
|
||||||
0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V
|
|
||||||
0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W
|
|
||||||
0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X
|
|
||||||
0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y
|
|
||||||
0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z
|
|
||||||
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [
|
|
||||||
0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55, // 55
|
|
||||||
0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ]
|
|
||||||
0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
|
|
||||||
0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _
|
|
||||||
0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // '
|
|
||||||
0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a
|
|
||||||
0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b
|
|
||||||
0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c
|
|
||||||
0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d
|
|
||||||
0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e
|
|
||||||
0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f
|
|
||||||
0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
|
|
||||||
0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h
|
|
||||||
0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i
|
|
||||||
0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j
|
|
||||||
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k
|
|
||||||
0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l
|
|
||||||
0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m
|
|
||||||
0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n
|
|
||||||
0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o
|
|
||||||
0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p
|
|
||||||
0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q
|
|
||||||
0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r
|
|
||||||
0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s
|
|
||||||
0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t
|
|
||||||
0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u
|
|
||||||
0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v
|
|
||||||
0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w
|
|
||||||
0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x
|
|
||||||
0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y
|
|
||||||
0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, // z
|
|
||||||
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, // horiz lines
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
|
|
||||||
*
|
|
||||||
* @created: 2014-08-12
|
|
||||||
* @author: Neven Boyanov
|
|
||||||
*
|
|
||||||
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#include <avr/pgmspace.h>
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/* Standard ASCII 8x16 font */
|
|
||||||
const uint8_t ssd1306xled_font8x16 [] PROGMEM = {
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 0
|
|
||||||
0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00, // ! 1
|
|
||||||
0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // " 2
|
|
||||||
0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00, // # 3
|
|
||||||
0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00, // $ 4
|
|
||||||
0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00, // % 5
|
|
||||||
0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10, // & 6
|
|
||||||
0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ' 7
|
|
||||||
0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00, // ( 8
|
|
||||||
0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00, // ) 9
|
|
||||||
0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00, // * 10
|
|
||||||
0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00, // + 11
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00, // , 12
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01, // - 13
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00, // . 14
|
|
||||||
0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00, // / 15
|
|
||||||
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00, // 0 16
|
|
||||||
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // 1 17
|
|
||||||
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00, // 2 18
|
|
||||||
0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00, // 3 19
|
|
||||||
0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00, // 4 20
|
|
||||||
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00, // 5 21
|
|
||||||
0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00, // 6 22
|
|
||||||
0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00, // 7 23
|
|
||||||
0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00, // 8 24
|
|
||||||
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00, // 9 25
|
|
||||||
0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00, // : 26
|
|
||||||
0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00, // ; 27
|
|
||||||
0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00, // < 28
|
|
||||||
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00, // = 29
|
|
||||||
0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00, // > 30
|
|
||||||
0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00, // ? 31
|
|
||||||
0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00, // @ 32
|
|
||||||
0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20, // A 33
|
|
||||||
0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00, // B 34
|
|
||||||
0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00, // C 35
|
|
||||||
0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00, // D 36
|
|
||||||
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00, // E 37
|
|
||||||
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00, // F 38
|
|
||||||
0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00, // G 39
|
|
||||||
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20, // H 40
|
|
||||||
0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // I 41
|
|
||||||
0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00, // J 42
|
|
||||||
0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00, // K 43
|
|
||||||
0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00, // L 44
|
|
||||||
0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00, // M 45
|
|
||||||
0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00, // N 46
|
|
||||||
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00, // O 47
|
|
||||||
0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00, // P 48
|
|
||||||
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00, // Q 49
|
|
||||||
0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20, // R 50
|
|
||||||
0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00, // S 51
|
|
||||||
0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00, // T 52
|
|
||||||
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00, // U 53
|
|
||||||
0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00, // V 54
|
|
||||||
0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00, // W 55
|
|
||||||
0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20, // X 56
|
|
||||||
0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00, // Y 57
|
|
||||||
0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00, // Z 58
|
|
||||||
0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00, // [ 59
|
|
||||||
0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00, // \ 60
|
|
||||||
0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00, // ] 61
|
|
||||||
0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ^ 62
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, // _ 63
|
|
||||||
0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ` 64
|
|
||||||
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20, // a 65
|
|
||||||
0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00, // b 66
|
|
||||||
0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00, // c 67
|
|
||||||
0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20, // d 68
|
|
||||||
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00, // e 69
|
|
||||||
0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // f 70
|
|
||||||
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00, // g 71
|
|
||||||
0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20, // h 72
|
|
||||||
0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // i 73
|
|
||||||
0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00, // j 74
|
|
||||||
0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00, // k 75
|
|
||||||
0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // l 76
|
|
||||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F, // m 77
|
|
||||||
0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20, // n 78
|
|
||||||
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00, // o 79
|
|
||||||
0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00, // p 80
|
|
||||||
0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80, // q 81
|
|
||||||
0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00, // r 82
|
|
||||||
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00, // s 83
|
|
||||||
0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00, // t 84
|
|
||||||
0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20, // u 85
|
|
||||||
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00, // v 86
|
|
||||||
0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00, // w 87
|
|
||||||
0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00, // x 88
|
|
||||||
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00, // y 89
|
|
||||||
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00, // z 90
|
|
||||||
0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40, // { 91
|
|
||||||
0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00, // | 92
|
|
||||||
0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00, // } 93
|
|
||||||
0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ~ 94
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
@ -1,115 +0,0 @@
|
|||||||
#include <RcSeq.h>
|
|
||||||
#include <TinyPinChange.h>
|
|
||||||
#include <SoftRcPulseIn.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
IMPORTANT:
|
|
||||||
For this sketch to compile, RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT and RC_SEQ_WITH_SHORT_ACTION_SUPPORT shall be defined
|
|
||||||
in PathOfTheLibraries/(Digispark)RcSeq/RcSeq.h and RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT shall be commented.
|
|
||||||
|
|
||||||
This sketch demonstrates how to easily use a 3 positions switch on a channel of a RC Transmitter with <RcSeq> library.
|
|
||||||
1) If the switch is at the MIDDLE position, a LED will be OFF
|
|
||||||
2) If the switch is at the DOWN position, a LED will be ON
|
|
||||||
2) If the switch is at the UP position, a LED will blink
|
|
||||||
|
|
||||||
This sketch can be extended to a rotactor (up to 8 positions)
|
|
||||||
|
|
||||||
RC Navy (2013)
|
|
||||||
http://p.loussouarn.free.fr
|
|
||||||
|
|
||||||
|
|
||||||
WIRING A TRANSMITTER SIDE WIRING AT RECEIVER SIDE
|
|
||||||
|
|
||||||
.------+-------------> +
|
|
||||||
| |
|
|
||||||
/ | # .-------------------------.
|
|
||||||
| UP o # 4.7K | |
|
|
||||||
| \ # | ARDUINO or ATTINY |
|
|
||||||
3 positions | \ | | | R
|
|
||||||
switch < MIDDLE o o---+-------------> To Tx Channel Rx Channel->|RC_CHANNEL_PIN LED_PIN >----###---|>|----|GND
|
|
||||||
| C | | | LED
|
|
||||||
| # | Sketch |
|
|
||||||
| DOWN o # 4.7K '-------------------------' External or
|
|
||||||
\ | # Built-in LED
|
|
||||||
| |
|
|
||||||
'------+-------------> -
|
|
||||||
|
|
||||||
.------------.------------------------.--------------.
|
|
||||||
| Switch Pos | Pulse Width Range (us) | Action |
|
|
||||||
+------------+------------------------+--------------+
|
|
||||||
| UP | 1000 -> 1270 | LED Blinking |
|
|
||||||
+------------+------------------------+--------------+
|
|
||||||
| MIDDLE | 1360 -> 1630 | LED OFF |
|
|
||||||
+------------+------------------------+--------------+
|
|
||||||
| DOWN | 1720 -> 1990 | LED ON |
|
|
||||||
'------------'------------------------'--------------'
|
|
||||||
|
|
||||||
Note:
|
|
||||||
====
|
|
||||||
<RcSeq> computes automatically the valid pulse width range for each position of the switch.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* Channel Declaration */
|
|
||||||
enum {RC_CHANNEL=0, RC_CHANNEL_NB}; /* Here, as there is a single channel, we could used a simple "#define RC_CHANNEL 0" rather an enumeration */
|
|
||||||
|
|
||||||
#define RC_CHANNEL_PIN 0 // Choose here the pin
|
|
||||||
#define LED_PIN 1 // Choose here the pin
|
|
||||||
|
|
||||||
enum {SW_POS_DOWN=0, SW_POS_MIDDLE, SW_POS_UP, SW_POS_NB}; /* Switch has 3 positions: Down, Middle and Up (For a rotactor with more positions, add positions here) */
|
|
||||||
|
|
||||||
boolean BlinkCmd=false;
|
|
||||||
boolean LedState=false;
|
|
||||||
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
RcSeq_Init();
|
|
||||||
|
|
||||||
RcSeq_DeclareSignal(RC_CHANNEL, RC_CHANNEL_PIN); /* RC_CHANNEL Channel is assigned to RC_CHANNEL_PIN pin */
|
|
||||||
|
|
||||||
RcSeq_DeclareMultiPosSwitch(RC_CHANNEL, 1000, 2000, SW_POS_NB); /* Tells to <RcSeq> that the RC_CHANNEL channel has SW_POS_NB positions distributed between 1000 and 2000 us */
|
|
||||||
|
|
||||||
RcSeq_DeclareCommandAndShortAction(RC_CHANNEL, SW_POS_DOWN, ActionSwPosDown); /* Action assigned to DOWN position */
|
|
||||||
RcSeq_DeclareCommandAndShortAction(RC_CHANNEL, SW_POS_MIDDLE, ActionSwPosMiddle); /* Action assigned to MIDDLE position */
|
|
||||||
RcSeq_DeclareCommandAndShortAction(RC_CHANNEL, SW_POS_UP, ActionSwPosUp); /* Action assigned to UP position */
|
|
||||||
|
|
||||||
pinMode(LED_PIN, OUTPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
static uint32_t StartMs=millis();
|
|
||||||
|
|
||||||
/* Refresh RcSeq (mandatory) */
|
|
||||||
RcSeq_Refresh();
|
|
||||||
|
|
||||||
/* Blink Management */
|
|
||||||
if( (BlinkCmd==true) && (millis() - StartMs >= 250UL) )
|
|
||||||
{
|
|
||||||
StartMs=millis();
|
|
||||||
LedState=!LedState;
|
|
||||||
digitalWrite(LED_PIN, LedState);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionSwPosUp() /* This function will be called when the switch is in UP position */
|
|
||||||
{
|
|
||||||
BlinkCmd=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionSwPosMiddle() /* This function will be called when the switch is in MIDDLE position */
|
|
||||||
{
|
|
||||||
BlinkCmd=false;
|
|
||||||
LedState=false;
|
|
||||||
digitalWrite(LED_PIN, LedState);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionSwPosDown() /* This function will be called when the switch is in DOWN position */
|
|
||||||
{
|
|
||||||
BlinkCmd=false;
|
|
||||||
LedState=true;
|
|
||||||
digitalWrite(LED_PIN, LedState);
|
|
||||||
}
|
|
||||||
|
|
@ -1,307 +0,0 @@
|
|||||||
/*
|
|
||||||
This sketch illustrates 2 new features of the <RcSeq> library (since the V2.1 version):
|
|
||||||
1) the "control" capability: it's a function passed as argument to the RcSeq_DeclareCommandAndSequence() method.
|
|
||||||
It is used to check if a sequence can be launched or not, depending of specific condition
|
|
||||||
It is also used to inform the sequence is finished: this can be used to memorize in EEPROM the sequence id.
|
|
||||||
Like that, at the next start-up the position of the servos can be restored according to the last position of the sequence.
|
|
||||||
2) the "timeout" capability:
|
|
||||||
The RcSeq_Timeout() method can be used to check if the command signal remains constant (HIGH or LOW).
|
|
||||||
It's then possible to launch the sequence based on the static state of the command pin rather than a Rc Pulse width.
|
|
||||||
In practice, it's possible to use both manners to launch a sequence as done in the sketch below.
|
|
||||||
|
|
||||||
THE SKETCH:
|
|
||||||
==========
|
|
||||||
In this sketch, the first declared sequence opens the 2 doors with the help of 2 servos (1 per door).
|
|
||||||
The second declared sequence closes the 2 doors with the help of 2 servos (1 per door).
|
|
||||||
The 2 doors cannot open or close simultaneously with the same speed since there is a nosing secured to the right door.
|
|
||||||
This nosing forces to open and close the doors using sequences.
|
|
||||||
|
|
||||||
Opening <- -> Opening
|
|
||||||
. .
|
|
||||||
. .
|
|
||||||
. .
|
|
||||||
. .
|
|
||||||
. .
|
|
||||||
. .
|
|
||||||
. .
|
|
||||||
__ nosing -> .------. __
|
|
||||||
/ \----------------'---. '----------------/ \
|
|
||||||
\__/-------------------''-------------------\__/
|
|
||||||
Left door Right door
|
|
||||||
TOP VIEW
|
|
||||||
|
|
||||||
The opening sequence is like hereafter:
|
|
||||||
======================================
|
|
||||||
1) The servo assigned to the right door starts
|
|
||||||
2) Once rigth door slightly opened, the servo assigned to the left door starts, whilst the servo assigned to the right door resumes its travel
|
|
||||||
3) Once the 2 servos reached 90°, the 2 doors stop; the opening sequence is finished
|
|
||||||
|
|
||||||
The closing sequence is like hereafter:
|
|
||||||
======================================
|
|
||||||
1) The 2 servos assigned to the left and right doors start together but the left servo rotates more quickly than the right servo.
|
|
||||||
2) As a consequence, the left door is closed berfore the right door
|
|
||||||
3) Once the 2 servos reached 90°, the 2 doors stop; the closing sequence is finished
|
|
||||||
|
|
||||||
The sequences of this sketch can be launched either a RC channel either a regular ON/OFF switch:
|
|
||||||
===============================================================================================
|
|
||||||
A) Command from a RC channel:
|
|
||||||
------------------------- _______________
|
|
||||||
V _______________ | __ |
|
|
||||||
| __________ | ARDUINO: |________| / \ Left |
|
|
||||||
| | | | | | \__/ Servo |
|
|
||||||
| | RC |CH | UNO | |_______________|
|
|
||||||
'-+ Receiver |----| MEGA | _______________
|
|
||||||
| | | Digispark | | __ |
|
|
||||||
|__________| | Digispark pro |________| / \ Right |
|
|
||||||
|_______________| | \__/ Servo |
|
|
||||||
|_______________|
|
|
||||||
|
|
||||||
B) Command from a ON/OFF switch:
|
|
||||||
---------------------------- _______________
|
|
||||||
_______________ | __ |
|
|
||||||
| ARDUINO: |________| / \ Left |
|
|
||||||
| | | \__/ Servo |
|
|
||||||
| UNO | |_______________|
|
|
||||||
.----| MEGA | _______________
|
|
||||||
| | Digispark | | __ |
|
|
||||||
ON/OFF Switch \ | Digispark pro |________| / \ Right |
|
|
||||||
| |_______________| | \__/ Servo |
|
|
||||||
-+- |_______________|
|
|
||||||
GND
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*************************************************/
|
|
||||||
/* STEP #1: Include the required libraries */
|
|
||||||
/*************************************************/
|
|
||||||
#include <RcSeq.h>
|
|
||||||
#include <TinyPinChange.h>
|
|
||||||
#include <SoftRcPulseIn.h>
|
|
||||||
#include <SoftRcPulseOut.h>
|
|
||||||
#include <EEPROM.h>
|
|
||||||
|
|
||||||
/*****************************************************************/
|
|
||||||
/* STEP #2: Enumeration of the RC Signals used in the sequence */
|
|
||||||
/*****************************************************************/
|
|
||||||
enum {RC_SIGNAL = 0, SIGNAL_NB}; /* Here, a single RC signal is used */
|
|
||||||
|
|
||||||
/******************************************************************/
|
|
||||||
/* STEP #3: Enumeration of the different position of the RC stick */
|
|
||||||
/******************************************************************/
|
|
||||||
enum {RC_PULSE_LEVEL_MINUS_1 = 0, RC_PULSE_LEVEL_PLUS_1, RC_PULSE_NB};
|
|
||||||
|
|
||||||
/*****************************************************************/
|
|
||||||
/* STEP #4: Enumeration of the servos used in the sequences */
|
|
||||||
/*****************************************************************/
|
|
||||||
enum {DOOR_SERVO_LEFT = 0, DOOR_SERVO_RIGHT, SERVO_NB}; /* In this sketch, 2 servos are declared */
|
|
||||||
|
|
||||||
/***************************************************/
|
|
||||||
/* STEP #5: Digital pin assignment for Command */
|
|
||||||
/***************************************************/
|
|
||||||
#define COMMAND_PIN 2 /* This pin can be connected to a channel of a RC Receiver or to a regular ON/OFF switch (switch wired between pin and Ground) */
|
|
||||||
|
|
||||||
/**************************************************/
|
|
||||||
/* STEP #6: Digital Pins assignment for Servos */
|
|
||||||
/**************************************************/
|
|
||||||
#define DOOR_SERVO_LEFT_PIN 3
|
|
||||||
#define DOOR_SERVO_RIGHT_PIN 4
|
|
||||||
|
|
||||||
/*************************************************************************************/
|
|
||||||
/* STEP #7: Declaration of the angle of the servos for the different motions (in °) */
|
|
||||||
/*************************************************************************************/
|
|
||||||
#define DOOR_SERVO_OPENED_LEFT_POS 135 /* position of the left Servo when left door is opened */
|
|
||||||
#define DOOR_SERVO_CLOSED_LEFT_POS 45 /* position of the left Servo when left door is closed */
|
|
||||||
|
|
||||||
#define DOOR_SERVO_OPENED_RIGHT_POS 45 /* position of the right Servo when right door is opened */
|
|
||||||
#define DOOR_SERVO_CLOSED_RIGHT_POS 135 /* position of the right Servo when right door is closed */
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************************************************************************/
|
|
||||||
/* STEP #8: Do a temporal diagram showing the start up and the duration of each motions of each servo */
|
|
||||||
/***************************************************************************************************************************************/
|
|
||||||
/*
|
|
||||||
1) OPENING MOTION OF THE DOORS
|
|
||||||
===========================
|
|
||||||
All the start up values (time stamp) have as reference the moment of the sequence startup order (t=0).
|
|
||||||
|
|
||||||
1.1 MOTION OF THE LEFT DOOR SERVO FOR OPENING
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
Order <---OPENING_DURATION_LEFT_MS--->
|
|
||||||
|-----------------------------|--------------------------------|-->Time Axis
|
|
||||||
0 OPENING_START_LEFT_MS
|
|
||||||
|
|
||||||
1.2 MOTION OF THE RIGHT DOOR SERVO FOR OPENING
|
|
||||||
==========================================
|
|
||||||
|
|
||||||
Order <--------OPENING_DURATION_RIGHT_MS------->
|
|
||||||
|-------------------|------------------------------------------|-->Time Axis
|
|
||||||
0 OPENING_START_RIGHT_MS
|
|
||||||
|
|
||||||
|
|
||||||
2) CLOSING MOTION OF THE DOORS
|
|
||||||
===========================
|
|
||||||
All the start up values (time stamp) have as reference the moment of the sequence startup order (t=0).
|
|
||||||
|
|
||||||
2.1 MOTION OF THE LEFT DOOR SERVO FOR CLOSING
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
Order <---CLOSING_DURATION_LEFT_MS--->
|
|
||||||
|-------------------|--------------------------------|------------>Time Axis
|
|
||||||
0 CLOSING_START_LEFT_MS
|
|
||||||
|
|
||||||
2.2 MOTION OF THE RIGTH DOOR SERVO FOR CLOSING
|
|
||||||
==========================================
|
|
||||||
|
|
||||||
Order <--------CLOSING_DURATION_RIGHT_MS------->
|
|
||||||
|-------------------|------------------------------------------|-->Time Axis
|
|
||||||
0 CLOSING_START_RIGHT_MS
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**************************************************************************************************************************************************/
|
|
||||||
/* STEP #9: With the help of the temporal diagram, declare start up time, the motion duration of servo and optional delay */
|
|
||||||
/**************************************************************************************************************************************************/
|
|
||||||
/* Tune below all the motion duration. Do not forget to add a trailer 'UL' for each value to force them in Unsigned Long type */
|
|
||||||
#define OPENING_START_LEFT_MS 500UL //This means the left servo motion will be delayed of 500ms AFTER the order
|
|
||||||
#define OPENING_DURATION_LEFT_MS 2500UL //The left door motion ends after 500+2500=3s, as the right door
|
|
||||||
|
|
||||||
#define OPENING_START_RIGHT_MS 0UL //Immediate start
|
|
||||||
#define OPENING_DURATION_RIGHT_MS 3000UL //The right door motion ends after 3s
|
|
||||||
|
|
||||||
#define CLOSING_START_LEFT_MS 0UL //Immediate start
|
|
||||||
#define CLOSING_DURATION_LEFT_MS 3000UL //The left door will be closed BEFORE the right door
|
|
||||||
|
|
||||||
#define CLOSING_START_RIGHT_MS 0UL //Immediate start
|
|
||||||
#define CLOSING_DURATION_RIGHT_MS 4000UL //The right door will be closed AFTER the left door
|
|
||||||
|
|
||||||
/********************************************************************************************************************/
|
|
||||||
/* STEP #10: Declare here the percentage of motion to be performed at half speed for servo start up and stop */
|
|
||||||
/********************************************************************************************************************/
|
|
||||||
#define START_STOP_PER_CENT 5 /* Percentage of motion performed at half-speed for starting and stopping the servos (Soft start et Soft stop) */
|
|
||||||
|
|
||||||
/************************************************************************************************************/
|
|
||||||
/* STEP #11: Use a "const SequenceSt_t" structure table to declare the servo sequence */
|
|
||||||
/* For each table entry, arguments are: */
|
|
||||||
/* - Servo Index */
|
|
||||||
/* - Initial Servo Position in ° */
|
|
||||||
/* - Final Servo Position in ° */
|
|
||||||
/* - Motion Start Time Stamp in ms */
|
|
||||||
/* - Motion duration in ms between initial and final position */
|
|
||||||
/* - Percentage of motion performed at half speed for servo start and servo stop (Soft start and Soft stop) */
|
|
||||||
/************************************************************************************************************/
|
|
||||||
/* Table describing the motions of the 2 servos for opening the 2 doors */
|
|
||||||
const SequenceSt_t OpeningSequence[] PROGMEM = {/* Servo Id , Initial Angle , Final Angle , Delay after order , Motion Duration , Percentage at half speed */
|
|
||||||
/* 1st Servo */ MOTION_WITH_SOFT_START_AND_STOP(DOOR_SERVO_LEFT, DOOR_SERVO_CLOSED_LEFT_POS, DOOR_SERVO_OPENED_LEFT_POS, OPENING_START_LEFT_MS, OPENING_DURATION_LEFT_MS, START_STOP_PER_CENT)
|
|
||||||
/* 2nd Servo */ MOTION_WITH_SOFT_START_AND_STOP(DOOR_SERVO_RIGHT, DOOR_SERVO_CLOSED_RIGHT_POS, DOOR_SERVO_OPENED_RIGHT_POS, OPENING_START_RIGHT_MS, OPENING_DURATION_RIGHT_MS, START_STOP_PER_CENT)
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Table describing the motions of the 2 servos for closing the 2 doors */
|
|
||||||
const SequenceSt_t ClosingSequence[] PROGMEM = {/* Servo Id , Initial Angle , Final Angle , Delai after order , Motion Duration , Percentage at half speed */
|
|
||||||
/* 1st Servo */ MOTION_WITH_SOFT_START_AND_STOP(DOOR_SERVO_LEFT, DOOR_SERVO_OPENED_LEFT_POS, DOOR_SERVO_CLOSED_LEFT_POS, CLOSING_START_LEFT_MS, CLOSING_DURATION_LEFT_MS, START_STOP_PER_CENT)
|
|
||||||
/* 2nd Servo */ MOTION_WITH_SOFT_START_AND_STOP(DOOR_SERVO_RIGHT, DOOR_SERVO_OPENED_RIGHT_POS, DOOR_SERVO_CLOSED_RIGHT_POS, CLOSING_START_RIGHT_MS, CLOSING_DURATION_RIGHT_MS, START_STOP_PER_CENT)
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {COMMAND_OPEN = 0, COMMAND_CLOSE};
|
|
||||||
|
|
||||||
/* GLOBAL VARIABLES */
|
|
||||||
uint8_t LastExecutedSeqIdx;
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
|
|
||||||
#if !defined(__AVR_ATtiny24__) && !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(__AVR_ATtiny25__) && !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny167__)
|
|
||||||
Serial.begin(9600);
|
|
||||||
Serial.print(F("RcSeq library V"));Serial.print(RcSeq_LibTextVersionRevision());Serial.println(F(" demo: advanced doors sequences"));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/***************************************************************************/
|
|
||||||
/* STEP #12: Init <RcSeq> library */
|
|
||||||
/***************************************************************************/
|
|
||||||
RcSeq_Init();
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
/* STEP #13: declare the servo command signals with their digital pin number */
|
|
||||||
/****************************************************************************************/
|
|
||||||
RcSeq_DeclareSignal(RC_SIGNAL, COMMAND_PIN);
|
|
||||||
|
|
||||||
/******************************************************************************************/
|
|
||||||
/* STEP #14: declare a stick assigned to the RC signal having RC_PULSE_NB positions */
|
|
||||||
/******************************************************************************************/
|
|
||||||
RcSeq_DeclareStick(RC_SIGNAL, 1000, 2000, RC_PULSE_NB);
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
/* STEP #15: declare the servo command signals with their digital pin number */
|
|
||||||
/****************************************************************************************/
|
|
||||||
RcSeq_DeclareServo(DOOR_SERVO_LEFT, DOOR_SERVO_LEFT_PIN);
|
|
||||||
RcSeq_DeclareServo(DOOR_SERVO_RIGHT, DOOR_SERVO_RIGHT_PIN);
|
|
||||||
|
|
||||||
/*******************************************************************************************************/
|
|
||||||
/* STEP #16: declare the sequence assigned to specific position of the stick assigned to the RC signal */
|
|
||||||
/*******************************************************************************************************/
|
|
||||||
RcSeq_DeclareCommandAndSequence(RC_SIGNAL, RC_PULSE_LEVEL_MINUS_1, RC_SEQUENCE(OpeningSequence), Control); // Declare a sequence triggered by a RC pulse Level Minus 1 (stick at extreme position during at least 250 ms)
|
|
||||||
RcSeq_DeclareCommandAndSequence(RC_SIGNAL, RC_PULSE_LEVEL_PLUS_1, RC_SEQUENCE(ClosingSequence), Control); // Declare a sequence triggered by a RC pulse Level Plus 1 (stick at extreme position during at least 250 ms)
|
|
||||||
|
|
||||||
/*******************************************************************************************/
|
|
||||||
/* STEP #17: Initialize the position of the servos according to the last finished sequence */
|
|
||||||
/*******************************************************************************************/
|
|
||||||
LastExecutedSeqIdx = EEPROM.read(0);
|
|
||||||
if (LastExecutedSeqIdx == COMMAND_OPEN)
|
|
||||||
{
|
|
||||||
RcSeq_ServoWrite(DOOR_SERVO_LEFT, DOOR_SERVO_OPENED_LEFT_POS);
|
|
||||||
RcSeq_ServoWrite(DOOR_SERVO_RIGHT, DOOR_SERVO_OPENED_RIGHT_POS);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RcSeq_ServoWrite(DOOR_SERVO_LEFT, DOOR_SERVO_CLOSED_LEFT_POS);
|
|
||||||
RcSeq_ServoWrite(DOOR_SERVO_RIGHT, DOOR_SERVO_CLOSED_RIGHT_POS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
uint8_t RcSignalPinState;
|
|
||||||
/****************************************************************************************************************/
|
|
||||||
/* STEP #18: call the refresh function inside the loop() to catch RC commands and to manage the servo positions */
|
|
||||||
/****************************************************************************************************************/
|
|
||||||
RcSeq_Refresh();
|
|
||||||
|
|
||||||
/*********************************************************************************************************/
|
|
||||||
/* STEP #19: optionally, allow launching the Sequences ou Actions on Timeout (cmd with a regular switch) */
|
|
||||||
/*********************************************************************************************************/
|
|
||||||
if (RcSeq_SignalTimeout(RC_SIGNAL, 250, &RcSignalPinState))
|
|
||||||
{
|
|
||||||
/* Launch the"OpeningSequence" sequence if a LOW level is present during at least 250ms: this allows testing the sequence of servo without using a RC set, just using a regular switch */
|
|
||||||
if((LastExecutedSeqIdx == COMMAND_CLOSE) && (RcSignalPinState == LOW))
|
|
||||||
{
|
|
||||||
RcSeq_LaunchSequence(OpeningSequence);
|
|
||||||
}
|
|
||||||
/* Launch the"ClosingSequence" sequence if a HIGH level is present during at least 250ms: this allows testing the sequence of servo without using a RC set, just using a regular switch */
|
|
||||||
if((LastExecutedSeqIdx == COMMAND_OPEN) && (RcSignalPinState == HIGH))
|
|
||||||
{
|
|
||||||
RcSeq_LaunchSequence(ClosingSequence);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The Control() fonction is automatically called by the RcSeq library */
|
|
||||||
uint8_t Control(uint8_t Action, uint8_t SeqIdx)
|
|
||||||
{
|
|
||||||
uint8_t Ret = 0;
|
|
||||||
#if !defined(__AVR_ATtiny24__) && !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(__AVR_ATtiny25__) && !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny167__)
|
|
||||||
Serial.print("Action=");Serial.print(Action);Serial.print(" SeqIdx=");Serial.println(SeqIdx);
|
|
||||||
#endif
|
|
||||||
switch(Action)
|
|
||||||
{
|
|
||||||
case RC_SEQ_START_CONDITION: /* RcSeq asks if the conditions are met to launch the sequence SeqIdx */
|
|
||||||
/* Put here a condition to allow RcSeq launching the sequence SeqIdx (Put Ret=1 if no specific condition) */
|
|
||||||
Ret = (SeqIdx != LastExecutedSeqIdx); /* Allows RcSeq launching the sequence if the sequence to launch is different from the last one */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RC_SEQ_END_OF_SEQ: /* RcSeq informs the sequence SeqIdx is finished */
|
|
||||||
/* We memorize the last finished sequence id in EEPROM memory. Like that, at next power-up, we will know how to position the servos ( done in the Setup() ) */
|
|
||||||
EEPROM.write(0, SeqIdx);
|
|
||||||
LastExecutedSeqIdx = SeqIdx;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return(Ret);
|
|
||||||
}
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
|||||||
RcSeq library
|
|
||||||
=============
|
|
||||||
|
|
||||||
**RcSeq** is an asynchronous library for ATmega328P (**UNO**), ATmega2560 (**MEGA**), ATtiny84, ATtiny85 (**Digispark**) and ATtiny167 (**Digispark pro**) to easily create **servo's sequences** and/or to execute **short actions** from RC commands, from a digital input, or from a launch function called in the sketch.
|
|
||||||
|
|
||||||
The **A**pplication **P**rogramming **I**nterface (**API**) makes **RcSeq** library very easy to use.
|
|
||||||
|
|
||||||
Some definitions:
|
|
||||||
----------------
|
|
||||||
|
|
||||||
* **Sequence**: is used to sequence one or several servos (sequence is defined in a structure in the user's sketch to be performed when the RC command rises). The Sequence table (structure) may contain some servo motions and some short actions to call at a predefined time. For each servo, start angle, end angle and speed are tunable.
|
|
||||||
|
|
||||||
* **Short Action**: is used to perform a quick action (action is a short function defined in the user's sketch to be called when the RC command rises). The duration must be less than 20ms to not disturb the servo commands.
|
|
||||||
|
|
||||||
Some examples of use cases:
|
|
||||||
--------------------------
|
|
||||||
* **A landing gear retract:**
|
|
||||||
* Lock, door and leg servos sequenced with a single RC channel
|
|
||||||
* from a predefined position of the stick on the transmitter
|
|
||||||
* from the 2 positions "Aux Channel" of the transmitter
|
|
||||||
|
|
||||||
* **Navigation lights for aircraft:**
|
|
||||||
* Anticollision, beacon, landing lights commanded:
|
|
||||||
* from predefined positions of the stick on the transmitter
|
|
||||||
* from push-buttons in place of the stick potentiometer
|
|
||||||
|
|
||||||
|
|
||||||
* **Multi-switch:**
|
|
||||||
* Up to 8 digital pins driven from a single RC channel
|
|
||||||
* using the stick of the transmitter
|
|
||||||
* using 8 push-buttons in place of the stick potentiometer
|
|
||||||
|
|
||||||
* **Zodiac animation:**
|
|
||||||
* A pneumatic Zodiac dropped at sea and lifted back to the deck of a ship. Drop and lift sequences commanded:
|
|
||||||
* from predefined positions of the stick on the transmitter
|
|
||||||
* from a regular ON/OFF switch (for demo on table without RC set)
|
|
||||||
|
|
||||||
* **Animatronics sequences:**
|
|
||||||
|
|
||||||
* leg motion,
|
|
||||||
* mouth motion,
|
|
||||||
* eyes motion,
|
|
||||||
* etc.
|
|
||||||
|
|
||||||
Triggers:
|
|
||||||
--------
|
|
||||||
|
|
||||||
**Sequences** and **short actions** can be trigged by:
|
|
||||||
|
|
||||||
* a RC signal (eg: RC receiver output)
|
|
||||||
|
|
||||||
* from one or several **predefined positions of a stick** of the transmitter
|
|
||||||
|
|
||||||
* from one or several **push-button** (keyboard) replacing a a stick of the transmitter. (**RcSeq** assumes Push-Buttons associated Pulse duration are equidistant).
|
|
||||||
|
|
||||||
* from **Custom Keyboard** replacing a stick of the the transmitter. (The pulse durations can be defined independently for each Push-Button).
|
|
||||||
|
|
||||||
* from **Multi position switch** (2 pos switch, 3 pos switch, or more, eg. rotactor) replacing a stick of the the transmitter.
|
|
||||||
|
|
||||||
* a regular ON/OFF switch (no RC set required).
|
|
||||||
|
|
||||||
* a launch function call in the sketch.
|
|
||||||
|
|
||||||
API/methods:
|
|
||||||
-----------
|
|
||||||
* RcSeq_Init()
|
|
||||||
* RcSeq_DeclareSignal()
|
|
||||||
* RcSeq_DeclareStick()
|
|
||||||
* RcSeq_DeclareKeyboard()
|
|
||||||
* RcSeq_DeclareCustomKeyboard()
|
|
||||||
* RcSeq_DeclareMultiPosSwitch()
|
|
||||||
* RcSeq_SignalTimeout()
|
|
||||||
* RcSeq_DeclareServo()
|
|
||||||
* RcSeq_DeclareCommandAndSequence()
|
|
||||||
* RcSeq_DeclareCommandAndShortAction()
|
|
||||||
* RcSeq_LaunchSequence()
|
|
||||||
* RcSeq_LaunchShortAction()
|
|
||||||
* RcSeq_Refresh()
|
|
||||||
* RcSeq_LibVersion()
|
|
||||||
* RcSeq_LibRevision()
|
|
||||||
* RcSeq_LibTextVersionRevision()
|
|
||||||
|
|
||||||
Macros and constants:
|
|
||||||
--------------------
|
|
||||||
* const SequenceSt_t
|
|
||||||
* const KeyMap_t
|
|
||||||
* RC_SEQUENCE()
|
|
||||||
* RC_CUSTOM_KEYBOARD()
|
|
||||||
* SHORT_ACTION_TO_PERFORM()
|
|
||||||
* MOTION_WITH_SOFT_START_AND_STOP()
|
|
||||||
* MOTION_WITHOUT_SOFT_START_AND_STOP()
|
|
||||||
* CENTER_VALUE_US
|
|
||||||
* RC_SEQ_START_CONDITION
|
|
||||||
* RC_SEQ_END_OF_SEQ
|
|
||||||
|
|
||||||
Design considerations:
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
The **RcSeq** library requires 3 other libraries written by the same author:
|
|
||||||
|
|
||||||
1. **TinyPinChange**: a library to catch asynchronously the input change using Pin Change Interruption capability of the AVR microcontroller.
|
|
||||||
|
|
||||||
2. **SoftRcPulseIn**: a library to catch asynchronously the input pulses using **TinyPinChange** library.
|
|
||||||
|
|
||||||
3. **SoftRcPulseOut**: a library mainly based on the **SoftwareServo** library, but with a better pulse generation to limit jitter and with some other enhancements.
|
|
||||||
|
|
||||||
CAUTION:
|
|
||||||
-------
|
|
||||||
The end user shall also use asynchronous programmation method in the loop() function (no blocking functions such as delay() or pulseIn()).
|
|
||||||
|
|
||||||
Contact
|
|
||||||
-------
|
|
||||||
|
|
||||||
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).
|
|
||||||
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
|||||||
SoftRcPulseIn library
|
|
||||||
======================
|
|
||||||
|
|
||||||
**SoftRcPulseIn** is an asynchronous library designed to read RC pulse signals. It is a non-blocking version of arduino **pulseIn()** function.
|
|
||||||
|
|
||||||
Some examples of use cases:
|
|
||||||
-------------------------
|
|
||||||
* **RC Servo/ESC/Brushless Controller**
|
|
||||||
* **Multi-switch (RC Channel to digital outputs converter)** (look at **RcSeq** library)
|
|
||||||
* **Servo sequencer** (look at **RcSeq** library which uses **SoftRcPulseOut** library)
|
|
||||||
* **RC Robot using wheels with modified Servo to support 360° rotation**
|
|
||||||
* **RC pulse stretcher** (in conjunction with **SoftRcPulseOut** library)
|
|
||||||
|
|
||||||
Supported Arduinos:
|
|
||||||
------------------
|
|
||||||
* **ATmega328 (UNO)**
|
|
||||||
* **ATmega2560 (MEGA)**
|
|
||||||
* **ATtiny84 (Standalone)**
|
|
||||||
* **ATtiny85 (Standalone or Digispark)**
|
|
||||||
* **ATtiny167 (Digispark pro)**
|
|
||||||
|
|
||||||
Tip and Tricks:
|
|
||||||
--------------
|
|
||||||
Develop your project on an arduino UNO or MEGA, and then shrink it by loading the sketch in an ATtiny or Digispark (pro).
|
|
||||||
|
|
||||||
API/methods:
|
|
||||||
-----------
|
|
||||||
* attach()
|
|
||||||
* available()
|
|
||||||
* width_us()
|
|
||||||
* timeout()
|
|
||||||
* LibVersion()
|
|
||||||
* LibRevision()
|
|
||||||
* LibTextVersionRevision()
|
|
||||||
|
|
||||||
Design considerations:
|
|
||||||
---------------------
|
|
||||||
The **SoftRcPulseIn** library relies the **TinyPinChange** library. This one shall be included in the sketch as well.
|
|
||||||
|
|
||||||
On the arduino MEGA, as all the pins do not support "pin change interrupt", only the following pins are supported:
|
|
||||||
|
|
||||||
* 10 -> 15
|
|
||||||
* 50 -> 53
|
|
||||||
* A8 -> A15
|
|
||||||
|
|
||||||
On other devices (ATmega328, ATtiny84, ATtiny85 and ATtiny167), all the pins are usable.
|
|
||||||
|
|
||||||
Contact
|
|
||||||
-------
|
|
||||||
|
|
||||||
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
_____ ____ __ _ ____ _ _ _ _
|
|
||||||
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
|
|
||||||
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
|
|
||||||
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
|
|
||||||
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|
|
||||||
|_| |_| \____/ |_| \__| |_| |_| \__/ |_| 2013
|
|
||||||
|
|
||||||
http://p.loussouarn.free.fr
|
|
||||||
|
|
||||||
*******************************************
|
|
||||||
* Digispark RC Debug Demo with 1 I/O *
|
|
||||||
*******************************************
|
|
||||||
|
|
||||||
This sketch demonstrates how to display received RC pulse width with a Digispark in the serial console of the arduino IDE.
|
|
||||||
by using a bi-directional serial port using a single I/O.
|
|
||||||
This approach allows to use the built-in Serial Console of the arduino IDE.
|
|
||||||
Please, note this solution requires a native RS232 port (rare today) or a RS232/USB adapter on the development PC.
|
|
||||||
|
|
||||||
To display properly the outputs in the IDE serial console, you have to:
|
|
||||||
- in the arduino IDE, select "Tools->Board->Digispark 16.0mhz - NO USB (Tiny core)"
|
|
||||||
- in the arduino IDE, select the right serial port in "Tools->Serial Port" and select the port where the debug cable is connected to.
|
|
||||||
- in the serial console, set the right baud rate (38400 in this sketch)
|
|
||||||
|
|
||||||
In this sketch, only Tx capabilty of SoftSerial is used.
|
|
||||||
|
|
||||||
Hardware Wiring:
|
|
||||||
===============
|
|
||||||
SERIAL SINGLE I/O
|
|
||||||
DEBUGGING CABLE
|
|
||||||
___________________/\__________________
|
|
||||||
/ \
|
|
||||||
____
|
|
||||||
.--------. | \
|
|
||||||
| GND |--------------------------------+---o5 \
|
|
||||||
| | 47K | | 9o |
|
|
||||||
| | .--###--' | o4 |
|
|
||||||
| DEBUG | 4.7K | | 8o |
|
|
||||||
| TX_RX |-------------------###--+--|<|------o3 | ---> To regular RS232 SubD 9 pins Male of PC
|
|
||||||
| PIN | ^ | 1N4148 | 7o | or to RS232/USB adapter
|
|
||||||
| | | '-----------o2 |
|
|
||||||
'--------' | | 6o |
|
|
||||||
ATtiny85 Single | o1 /
|
|
||||||
(Digispark) I/O |____/
|
|
||||||
SubD 9 pins
|
|
||||||
Female
|
|
||||||
*/
|
|
||||||
#include <TinyPinChange.h>
|
|
||||||
#include <SoftRcPulseIn.h>
|
|
||||||
#include <SoftSerial.h>
|
|
||||||
|
|
||||||
#define RX_AUX_GEAR_PIN 0 //Choose here the pin for the RC signal
|
|
||||||
#define DEBUG_TX_RX_PIN 1 //Adjust here your Tx/Rx debug pin (Do NOT work on Digispark PIN 5: choose another PIN)
|
|
||||||
|
|
||||||
#define SERIAL_BAUD_RATE 57600 //Adjust rate here
|
|
||||||
|
|
||||||
SoftRcPulseIn RxAuxGear; //Choose a name for your RC channel signal
|
|
||||||
|
|
||||||
SoftSerial MyDbgSerial(DEBUG_TX_RX_PIN, DEBUG_TX_RX_PIN, true); //true allows to connect to a regular RS232 without RS232 line driver
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
RxAuxGear.attach(RX_AUX_GEAR_PIN);
|
|
||||||
|
|
||||||
MyDbgSerial.begin(SERIAL_BAUD_RATE); //Do NOT forget to setup your terminal at same baud rate (eg: arduino IDE serial monitor)
|
|
||||||
MyDbgSerial.txMode(); //Before sending a message, switch to txMode
|
|
||||||
MyDbgSerial.print(F("SoftRcPulseIn lib V"));MyDbgSerial.print(SoftRcPulseIn::LibTextVersionRevision());MyDbgSerial.println(F(" demo"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
if(RxAuxGear.available())
|
|
||||||
{
|
|
||||||
MyDbgSerial.print(F("Pulse="));MyDbgSerial.println(RxAuxGear.width_us()); // Display Rx Pulse Width (in us)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
|||||||
SoftRcPulseOut library
|
|
||||||
======================
|
|
||||||
|
|
||||||
**SoftRcPulseOut** is pseudo-asynchronous library designed to generate RC pulse signals. RC pulse signals are intended to command servos, **E**lectronic **S**peed **C**ontrollers (**ESC**), Brushless Controllers and any devices expecting such a command signal.
|
|
||||||
|
|
||||||
Some examples of use cases:
|
|
||||||
-------------------------
|
|
||||||
* **Servo/ESC/Brushless Controller tester**
|
|
||||||
* **Servo sequencer** (look at RcSeq library which uses _SoftRcPulseOut_)
|
|
||||||
* **Robot wheels using modified Servo to support 360° rotation**
|
|
||||||
* **RC pulse stretcher** (in conjunction with **SoftRcPulseIn** library)
|
|
||||||
|
|
||||||
Supported Arduinos:
|
|
||||||
------------------
|
|
||||||
* **ATmega368 (UNO)**
|
|
||||||
* **ATmega2560 (MEGA)**
|
|
||||||
* **ATtiny84 (Standalone)**
|
|
||||||
* **ATtiny85 (Standalone or Digispark)**
|
|
||||||
* **ATtiny167 (Digispark pro)**
|
|
||||||
|
|
||||||
Tip and Tricks:
|
|
||||||
--------------
|
|
||||||
Develop your project on an arduino UNO or MEGA, and then shrink it by loading the sketch in an ATtiny or Digispark (pro).
|
|
||||||
|
|
||||||
API/methods:
|
|
||||||
-----------
|
|
||||||
* The **SoftRcPulseOut** library uses the same API as the regular **SoftwareServo** library:
|
|
||||||
* attach()
|
|
||||||
* attached()
|
|
||||||
* detach()
|
|
||||||
* write()
|
|
||||||
* read()
|
|
||||||
* setMinimumPulse()
|
|
||||||
* setMaximumPulse()
|
|
||||||
* refresh()
|
|
||||||
|
|
||||||
* Two additional methods allow using µs rather than angle in ° :
|
|
||||||
* write_us()
|
|
||||||
* read_us()
|
|
||||||
|
|
||||||
* Methods for version management:
|
|
||||||
* LibVersion
|
|
||||||
* LibRevision
|
|
||||||
* LibTextVersionRevision
|
|
||||||
|
|
||||||
* Synchronization:
|
|
||||||
* By giving **_1_** or **_true_** as optional argument for the **SoftRcPulseOut::refresh()** method, the pulses are refreshed immediately (without waiting for the usual 20ms).
|
|
||||||
|
|
||||||
* the **SoftRcPulseOut::refresh()** method returns **_1_** or **_true_** when the pulses have been refreshed. Testing this return value provides a 20ms timer.
|
|
||||||
|
|
||||||
Design considerations:
|
|
||||||
---------------------
|
|
||||||
The **SoftRcPulseOut** library relies on a 8 bit timer. This allows using it even on little MCU (such as ATtiny85) which do not have any 16 bit timer.
|
|
||||||
|
|
||||||
Whereas a 8 bit timer is used for pulse generation, the jitter is limited by using anticipated interrupt masking.
|
|
||||||
|
|
||||||
Interrups are only masked during rising and falling edges of the pulse signals.
|
|
||||||
|
|
||||||
CAUTION:
|
|
||||||
-------
|
|
||||||
The end user shall also use asynchronous programmation method in the loop() function (not too long blocking functions such as delay(1000): the **SoftRcPulseOut::refresh()** method shall be called at least every 50ms).
|
|
||||||
|
|
||||||
Contact
|
|
||||||
-------
|
|
||||||
|
|
||||||
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).
|
|
||||||
|
|
@ -1,229 +0,0 @@
|
|||||||
#include "SoftRcPulseOut.h"
|
|
||||||
/*
|
|
||||||
Update 01/03/2013: add support for Digispark (http://digistump.com): automatic Timer selection (RC Navy: p.loussouarn.free.fr)
|
|
||||||
Update 19/08/2014: usage with write_us and read_us fixed
|
|
||||||
|
|
||||||
English: by RC Navy (2012)
|
|
||||||
=======
|
|
||||||
<SoftRcPulseOut>: a library mainly based on the <SoftwareServo> library, but with a better pulse generation to limit jitter.
|
|
||||||
It supports the same methods as <SoftwareServo>.
|
|
||||||
It also support Pulse Width order given in microseconds. The current Pulse Width can also be read in microseconds.
|
|
||||||
The refresh method can admit an optionnal argument (force). If SoftRcPulseOut::refresh(1) is called, the refresh is forced even if 20 ms are not elapsed.
|
|
||||||
The refresh() method returns 1 if refresh done (can be used for synchro and/or for 20ms timer).
|
|
||||||
http://p.loussouarn.free.fr
|
|
||||||
|
|
||||||
Francais: par RC Navy (2012)
|
|
||||||
========
|
|
||||||
<SoftRcPulseOut>: une librairie majoritairement basee sur la librairie <SoftwareServo>, mais avec une meilleure generation des impulsions pour limiter la gigue.
|
|
||||||
Elle supporte les memes methodes que <SoftwareServo>.
|
|
||||||
Elle supporte egalement une consigne de largeur d'impulsion passee en microseconde. La largeur de l'impulsion courante peut egalement etre lue en microseconde.
|
|
||||||
La methode refresh peut admettre un parametre optionnel (force). Si SoftRcPulseOut::resfresh(1) est appelee, le refresh est force meme si 20 ms ne se sont pas ecoulee.
|
|
||||||
La methode refresh() retourne 1 si refresh effectue (peut etre utilise pour synhro et/ou 20ms timer).
|
|
||||||
http://p.loussouarn.free.fr
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Automatic Timer selection (at compilation time) */
|
|
||||||
#ifndef TIMER_TO_USE_FOR_MILLIS //This symbol is not defined arduino standard core and is defined in core_build_options.h in DigiStump version
|
|
||||||
#define SOFT_RC_PULSE_OUT_TCNT TCNT0 //For arduino standard core of UNO/MEGA, etc
|
|
||||||
#else
|
|
||||||
#if (TIMER_TO_USE_FOR_MILLIS==1)
|
|
||||||
#define SOFT_RC_PULSE_OUT_TCNT TCNT1 //For example for ATtiny85
|
|
||||||
#else
|
|
||||||
#define SOFT_RC_PULSE_OUT_TCNT TCNT0 //For example for ATtiny84 and ATtiny167
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SoftRcPulseOut *SoftRcPulseOut::first;
|
|
||||||
|
|
||||||
#define NO_ANGLE (0xff)
|
|
||||||
|
|
||||||
SoftRcPulseOut::SoftRcPulseOut() : pin(0), angle(NO_ANGLE), pulse0(0), min16(34), max16(150), next(0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void SoftRcPulseOut::setMinimumPulse(uint16_t t)
|
|
||||||
{
|
|
||||||
min16 = t / 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoftRcPulseOut::setMaximumPulse(uint16_t t)
|
|
||||||
{
|
|
||||||
max16 = t / 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t SoftRcPulseOut::attach(int pinArg)
|
|
||||||
{
|
|
||||||
pin = pinArg;
|
|
||||||
angle = NO_ANGLE;
|
|
||||||
pulse0 = 0;
|
|
||||||
next = first;
|
|
||||||
first = this;
|
|
||||||
digitalWrite(pin, LOW);
|
|
||||||
pinMode(pin, OUTPUT);
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoftRcPulseOut::detach()
|
|
||||||
{
|
|
||||||
for ( SoftRcPulseOut **p = &first; *p != 0; p = &((*p)->next) )
|
|
||||||
{
|
|
||||||
if ( *p == this )
|
|
||||||
{
|
|
||||||
*p = this->next;
|
|
||||||
this->next = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoftRcPulseOut::write(int angleArg)
|
|
||||||
{
|
|
||||||
if ( angleArg < 0) angleArg = 0;
|
|
||||||
if ( angleArg > 180) angleArg = 180;
|
|
||||||
angle = angleArg;
|
|
||||||
// bleh, have to use longs to prevent overflow, could be tricky if always a 16MHz clock, but not true
|
|
||||||
// That 64L on the end is the TCNT0 prescaler, it will need to change if the clock's prescaler changes,
|
|
||||||
// but then there will likely be an overflow problem, so it will have to be handled by a human.
|
|
||||||
#ifdef MS_TIMER_TICK_EVERY_X_CYCLES
|
|
||||||
pulse0 = (min16 * 16L * clockCyclesPerMicrosecond() + (max16 - min16) * (16L * clockCyclesPerMicrosecond()) * angle / 180L) / MS_TIMER_TICK_EVERY_X_CYCLES;
|
|
||||||
#else
|
|
||||||
pulse0 = (min16 * 16L * clockCyclesPerMicrosecond() + (max16 - min16) * (16L * clockCyclesPerMicrosecond()) * angle / 180L) / 64L;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoftRcPulseOut::write_us(uint16_t PulseWidth_us)
|
|
||||||
{
|
|
||||||
if ( PulseWidth_us < (min16 * 16)) PulseWidth_us = (min16 * 16);
|
|
||||||
if ( PulseWidth_us > (max16 * 16)) PulseWidth_us = (max16 * 16);
|
|
||||||
#ifdef MS_TIMER_TICK_EVERY_X_CYCLES
|
|
||||||
pulse0 = (PulseWidth_us * clockCyclesPerMicrosecond()) / MS_TIMER_TICK_EVERY_X_CYCLES;
|
|
||||||
#else
|
|
||||||
pulse0 = (PulseWidth_us * clockCyclesPerMicrosecond()) / 64L;
|
|
||||||
#endif
|
|
||||||
angle = map(PulseWidth_us, min16 * 16, max16 * 16, 0, 180);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t SoftRcPulseOut::read()
|
|
||||||
{
|
|
||||||
return angle;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t SoftRcPulseOut::read_us()
|
|
||||||
{
|
|
||||||
#ifdef MS_TIMER_TICK_EVERY_X_CYCLES
|
|
||||||
return((pulse0 * MS_TIMER_TICK_EVERY_X_CYCLES) / clockCyclesPerMicrosecond());
|
|
||||||
#else
|
|
||||||
return((pulse0 * 64L) / clockCyclesPerMicrosecond());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t SoftRcPulseOut::attached()
|
|
||||||
{
|
|
||||||
for ( SoftRcPulseOut *p = first; p != 0; p = p->next )
|
|
||||||
{
|
|
||||||
if ( p == this) return (1);
|
|
||||||
}
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t SoftRcPulseOut::refresh(bool force /* = false */)
|
|
||||||
{
|
|
||||||
uint8_t RefreshDone = 0;
|
|
||||||
uint8_t count = 0, i = 0;
|
|
||||||
uint16_t base = 0;
|
|
||||||
SoftRcPulseOut *p;
|
|
||||||
static uint32_t lastRefresh = 0;
|
|
||||||
uint32_t m = millis();
|
|
||||||
|
|
||||||
if(!force)
|
|
||||||
{
|
|
||||||
// if we haven't wrapped millis, and 20ms have not passed, then don't do anything
|
|
||||||
if ( (m - lastRefresh) < 20UL ) return(RefreshDone);
|
|
||||||
}
|
|
||||||
RefreshDone = 1; //Ok: Refresh will be performed
|
|
||||||
lastRefresh = m;
|
|
||||||
|
|
||||||
for ( p = first; p != 0; p = p->next ) if ( p->pulse0 ) count++;
|
|
||||||
if ( count == 0 ) return(RefreshDone);
|
|
||||||
|
|
||||||
// gather all the SoftRcPulseOuts in an array
|
|
||||||
SoftRcPulseOut *s[count];
|
|
||||||
for ( p = first; p != 0; p = p->next ) if ( p->pulse0) s[i++] = p;
|
|
||||||
|
|
||||||
// bubblesort the SoftRcPulseOuts by pulse time, ascending order
|
|
||||||
s[0]->ItMasked = 0;
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
uint8_t moved = 0;
|
|
||||||
for ( i = 1; i < count; i++ )
|
|
||||||
{
|
|
||||||
s[i]->ItMasked = 0;
|
|
||||||
if ( s[i]->pulse0 < s[i - 1]->pulse0 )
|
|
||||||
{
|
|
||||||
SoftRcPulseOut *t = s[i];
|
|
||||||
s[i] = s[i - 1];
|
|
||||||
s[i - 1] = t;
|
|
||||||
moved = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( !moved ) break;
|
|
||||||
}
|
|
||||||
for ( i = 1; i < count; i++ )
|
|
||||||
{
|
|
||||||
if ( abs(s[i]->pulse0 - s[i - 1]->pulse0) <= 5)
|
|
||||||
{
|
|
||||||
s[i]->ItMasked = 1; /* 2 consecutive Pulses are close each other, so do not unmask interrupts between Pulses */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// turn on all the pins
|
|
||||||
// Note the timing error here... when you have many SoftwareServos going, the
|
|
||||||
// ones at the front will get a pulse that is a few microseconds too long.
|
|
||||||
// Figure about 4uS/SoftRcPulseOut after them. This could be compensated, but I feel
|
|
||||||
// it is within the margin of error of software SoftRcPulseOuts that could catch
|
|
||||||
// an extra interrupt handler at any time.
|
|
||||||
noInterrupts();
|
|
||||||
for ( i = 0; i < count; i++ ) digitalWrite( s[i]->pin, 1);
|
|
||||||
interrupts();
|
|
||||||
|
|
||||||
uint8_t start = SOFT_RC_PULSE_OUT_TCNT;
|
|
||||||
uint8_t now = start;
|
|
||||||
uint8_t last = now;
|
|
||||||
|
|
||||||
// Now wait for each pin's time in turn..
|
|
||||||
for ( i = 0; i < count; i++ )
|
|
||||||
{
|
|
||||||
uint16_t go = start + s[i]->pulse0;
|
|
||||||
#ifndef MS_TIMER_TICK_EVERY_X_CYCLES
|
|
||||||
uint16_t it = go - 4; /* 4 Ticks is OK for UNO @ 16MHz with default prescaler*/ /* Mask Interruptions just before setting down the pin */
|
|
||||||
#else
|
|
||||||
uint16_t it = go - max(4, (256 / MS_TIMER_TICK_EVERY_X_CYCLES)); /* 4 Ticks is OK for UNO @ 16MHz */ /* Mask Interruptions just before setting down the pin */
|
|
||||||
#endif
|
|
||||||
// loop until we reach or pass 'go' time: this is a blocking loop (max 2400us) except for non masked ISR (between edges)
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
now = SOFT_RC_PULSE_OUT_TCNT;
|
|
||||||
if ( now < last ) base += 256;
|
|
||||||
last = now;
|
|
||||||
if( !s[i]->ItMasked )
|
|
||||||
{
|
|
||||||
if( base + now > it)
|
|
||||||
{
|
|
||||||
noInterrupts();
|
|
||||||
s[i]->ItMasked = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( base + now > go )
|
|
||||||
{
|
|
||||||
digitalWrite( s[i]->pin, 0);
|
|
||||||
if( (i + 1) < count )
|
|
||||||
{
|
|
||||||
if( !s[i + 1]->ItMasked )
|
|
||||||
{
|
|
||||||
interrupts();
|
|
||||||
}
|
|
||||||
}else interrupts();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(RefreshDone);
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
#ifndef SoftRcPulseOut_h
|
|
||||||
#define SoftRcPulseOut_h
|
|
||||||
|
|
||||||
/*
|
|
||||||
Update 01/03/2013: add support for Digispark (http://digistump.com): automatic Timer selection (RC Navy: p.loussouarn.free.fr)
|
|
||||||
Update 19/08/2014: usage with write_us and read_us fixed and optimized for highest resolution
|
|
||||||
|
|
||||||
English: by RC Navy (2012)
|
|
||||||
=======
|
|
||||||
<SoftRcPulseOut>: a library mainly based on the <SoftwareServo> library, but with a better pulse generation to limit jitter.
|
|
||||||
It supports the same methods as <SoftwareServo>.
|
|
||||||
It also support Pulse Width order given in microseconds. The current Pulse Width can also be read in microseconds.
|
|
||||||
The refresh method can admit an optionnal argument (force). If SoftRcPulseOut::refresh(1) is called, the refresh is forced even if 20 ms are not elapsed.
|
|
||||||
The refresh() method returns 1 if refresh done (can be used for synchro and/or for 20ms timer).
|
|
||||||
http://p.loussouarn.free.fr
|
|
||||||
|
|
||||||
Francais: par RC Navy (2012)
|
|
||||||
========
|
|
||||||
<SoftRcPulseOut>: une librairie majoritairement basee sur la librairie <SoftwareServo>, mais avec une meilleure generation des impulsions pour limiter la gigue.
|
|
||||||
Elle supporte les memes methodes que <SoftwareServo>.
|
|
||||||
Elle supporte egalement une consigne de largeur d'impulsion passee en microseconde. La largeur de l'impulsion courante peut egalement etre lue en microseconde.
|
|
||||||
La methode refresh peut admettre un parametre optionnel (force). Si SoftRcPulseOut::resfresh(1) est appelee, le refresh est force meme si 20 ms ne se sont pas ecoulee.
|
|
||||||
La methode refresh() retourne 1 si refresh effectue (peut etre utilise pour synhro et/ou 20ms timer).
|
|
||||||
http://p.loussouarn.free.fr
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(ARDUINO) && ARDUINO >= 100
|
|
||||||
#include "Arduino.h"
|
|
||||||
#else
|
|
||||||
#include "WProgram.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
class SoftRcPulseOut
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
boolean ItMasked;
|
|
||||||
uint8_t pin;
|
|
||||||
uint8_t angle; // in degrees
|
|
||||||
uint16_t pulse0; // pulse width in TCNT0 counts
|
|
||||||
uint8_t min16; // minimum pulse, 16uS units (default is 34)
|
|
||||||
uint8_t max16; // maximum pulse, 16uS units, 0-4ms range (default is 150)
|
|
||||||
class SoftRcPulseOut *next;
|
|
||||||
static SoftRcPulseOut *first;
|
|
||||||
public:
|
|
||||||
SoftRcPulseOut();
|
|
||||||
uint8_t attach(int); // attach to a pin, sets pinMode, returns 0 on failure, won't
|
|
||||||
// position the servo until a subsequent write() happens
|
|
||||||
void detach();
|
|
||||||
void write(int); // specify the angle in degrees, 0 to 180
|
|
||||||
void write_us(uint16_t); // specify the angle in microseconds, 500 to 2500
|
|
||||||
uint8_t read(); // return the current angle
|
|
||||||
uint16_t read_us(); // return the current pulse with in microseconds
|
|
||||||
uint8_t attached();
|
|
||||||
void setMinimumPulse(uint16_t); // pulse length for 0 degrees in microseconds, 540uS default
|
|
||||||
void setMaximumPulse(uint16_t); // pulse length for 180 degrees in microseconds, 2400uS default
|
|
||||||
static uint8_t refresh(bool force = false);// must be called at least every 50ms or so to keep servo alive
|
|
||||||
// you can call more often, it won't happen more than once every 20ms
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Methodes en Francais English native methods */
|
|
||||||
#define attache attach
|
|
||||||
#define detache detach
|
|
||||||
#define ecrit write
|
|
||||||
#define ecrit_us write_us
|
|
||||||
#define lit read
|
|
||||||
#define lit_us read_us
|
|
||||||
#define estAttache attached
|
|
||||||
#define definitImpulsionMinimum setMinimumPulse
|
|
||||||
#define definitImpulsionMaximum setMaximumPulse
|
|
||||||
#define rafraichit refresh
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,37 +0,0 @@
|
|||||||
// SweepNoDelay
|
|
||||||
// by RC Navy (http://p.loussouarn.free.fr/arduino/arduino.html>)
|
|
||||||
// This sketch can work with ATtiny and Arduino UNO, MEGA, etc...
|
|
||||||
// This example code is in the public domain.
|
|
||||||
|
|
||||||
#include <SoftRcPulseOut.h>
|
|
||||||
|
|
||||||
SoftRcPulseOut myservo; // create servo object to control a servo
|
|
||||||
// a maximum of eight servo objects can be created
|
|
||||||
#define SERVO_PIN 0
|
|
||||||
|
|
||||||
#define UP_DIRECTION +1
|
|
||||||
#define DOWN_DIRECTION -1
|
|
||||||
|
|
||||||
#define POS_MIN 0
|
|
||||||
#define POS_MAX 180
|
|
||||||
|
|
||||||
int pos = POS_MIN; // variable to store the servo position
|
|
||||||
int step = UP_DIRECTION;
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
myservo.attach(SERVO_PIN); // attaches the servo on pin defined by SERVO_PIN to the servo object
|
|
||||||
myservo.write(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
if (SoftRcPulseOut::refresh()) // refresh() returns 1 every 20ms (after pulse update)
|
|
||||||
{
|
|
||||||
// We arrive here every 20ms
|
|
||||||
pos += step;
|
|
||||||
if(pos >= POS_MAX) step = DOWN_DIRECTION; //180 degrees reached -> Change direction
|
|
||||||
if(pos <= POS_MIN) step = UP_DIRECTION; // 0 degrees reached -> Change direction
|
|
||||||
myservo.write(pos);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
#######################################
|
|
||||||
# Syntax Coloring Map SoftRcPulseOut
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
#######################################
|
|
||||||
# Datatypes (KEYWORD1)
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
SoftRcPulseOut KEYWORD1
|
|
||||||
|
|
||||||
#######################################
|
|
||||||
# Methods and Functions (KEYWORD2)
|
|
||||||
#######################################
|
|
||||||
attach KEYWORD2
|
|
||||||
attache KEYWORD2
|
|
||||||
detach KEYWORD2
|
|
||||||
detache KEYWORD2
|
|
||||||
write KEYWORD2
|
|
||||||
ecrit KEYWORD2
|
|
||||||
write_us KEYWORD2
|
|
||||||
ecrit_us KEYWORD2
|
|
||||||
read KEYWORD2
|
|
||||||
lit KEYWORD2
|
|
||||||
read_us KEYWORD2
|
|
||||||
lit_us KEYWORD2
|
|
||||||
attached KEYWORD2
|
|
||||||
estAttache KEYWORD2
|
|
||||||
setMinimumPulse KEYWORD2
|
|
||||||
definitImpulsionMinimum KEYWORD2
|
|
||||||
setMaximumPulse KEYWORD2
|
|
||||||
definitImpulsionMaximum KEYWORD2
|
|
||||||
refresh KEYWORD2
|
|
||||||
rafraichit KEYWORD2
|
|
||||||
|
|
||||||
#######################################
|
|
||||||
# Constants (LITERAL1)
|
|
||||||
#######################################
|
|
@ -1,64 +0,0 @@
|
|||||||
SoftSerial library
|
|
||||||
==================
|
|
||||||
|
|
||||||
The **SoftSerial** library is exactly the same as the **SoftwareSerial** library but used with the **TinyPinChange** library which allows to share
|
|
||||||
the "Pin Change Interrupt" Vector.
|
|
||||||
|
|
||||||
**SoftwareSerial** monopolizes the Pin Change Interrupt Vector and do not allow sharing.
|
|
||||||
|
|
||||||
With **SoftSerial**, it's possible. Don't forget to #include **TinyPinChange** in your sketch!
|
|
||||||
|
|
||||||
Additionally, for small devices such as **ATtiny85** (Digispark), it's possible to declare **the same pin for TX and RX**.
|
|
||||||
Data direction is set by using the new **txMode()** and **rxMode()** methods.
|
|
||||||
|
|
||||||
Some examples of use cases:
|
|
||||||
-------------------------
|
|
||||||
* **half-duplex bi-directional serial port on a single wire for debuging purpose**
|
|
||||||
* **half-duplex serial port to interface with Bluetooth module**
|
|
||||||
* **half-duplex serial port to interconnect an arduino with another one**
|
|
||||||
|
|
||||||
Supported Arduinos:
|
|
||||||
------------------
|
|
||||||
* **ATmega368 (UNO)**
|
|
||||||
* **ATmega2560 (MEGA)**
|
|
||||||
* **ATtiny84 (Standalone)**
|
|
||||||
* **ATtiny85 (Standalone or Digispark)**
|
|
||||||
* **ATtiny167 (Digispark pro)**
|
|
||||||
|
|
||||||
Tip and Tricks:
|
|
||||||
--------------
|
|
||||||
Develop your project on an arduino UNO or MEGA, and then shrink it by loading the sketch in an ATtiny or Digispark (pro).
|
|
||||||
|
|
||||||
API/methods:
|
|
||||||
-----------
|
|
||||||
* The **SoftSerial** library uses the same API as the regular **SoftwareSerial** library:
|
|
||||||
* begin()
|
|
||||||
* end()
|
|
||||||
* available()
|
|
||||||
* read()
|
|
||||||
* listen()
|
|
||||||
* isListening()
|
|
||||||
* overflow()
|
|
||||||
* flush()
|
|
||||||
|
|
||||||
* Two additional methods are used to manage the serial port on a single pin:
|
|
||||||
* txMode()
|
|
||||||
* rxMode()
|
|
||||||
|
|
||||||
Design considerations:
|
|
||||||
---------------------
|
|
||||||
The **SoftSerial** library relies the **TinyPinChange** library **for the RX pin**. This one shall be included in the sketch as well.
|
|
||||||
|
|
||||||
On the arduino MEGA, as all the pins do not support "pin change interrupt", only the following pins are supported **for the RX pin**:
|
|
||||||
|
|
||||||
* 10 -> 15
|
|
||||||
* 50 -> 53
|
|
||||||
* A8 -> A15
|
|
||||||
|
|
||||||
On other devices (ATmega328, ATtiny84, ATtiny85 and ATtiny167), all the pins are usable.
|
|
||||||
|
|
||||||
Contact
|
|
||||||
-------
|
|
||||||
|
|
||||||
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
|||||||
TinyPinChange library
|
|
||||||
=====================
|
|
||||||
|
|
||||||
**TinyPinChange** is an asynchronous (interrupt-driven) library designed to detect event (rising or falling edege) on pins.
|
|
||||||
|
|
||||||
Very often in the arduino world, users complain about conflicts between libraries.
|
|
||||||
|
|
||||||
This **TinyPinChange** library allows to share the "pin change interrupt" vector for several "clients".
|
|
||||||
|
|
||||||
For example, it's possible to use the **SoftRcPulseIn** library whilst using the **SoftSerial** library: both libraries rely on the **TinyPinChange** library.
|
|
||||||
|
|
||||||
Some examples of use cases:
|
|
||||||
-------------------------
|
|
||||||
* **Event detector** (on pins)
|
|
||||||
* **Frequency meter**
|
|
||||||
* **Pulse width meter**
|
|
||||||
* **Tachometer**
|
|
||||||
* **Duty cycle measurement**
|
|
||||||
* **Software serial port** (see **SoftSerial** library which relies on TinyPinChange)
|
|
||||||
|
|
||||||
Supported Arduinos:
|
|
||||||
------------------
|
|
||||||
* **ATmega368 (UNO)**
|
|
||||||
* **ATmega2560 (MEGA)**
|
|
||||||
* **ATtiny84 (Standalone)**
|
|
||||||
* **ATtiny85 (Standalone or Digispark)**
|
|
||||||
* **ATtiny167 (Digispark pro)**
|
|
||||||
|
|
||||||
Tip and Tricks:
|
|
||||||
--------------
|
|
||||||
Develop your project on an arduino UNO or MEGA, and then shrink it by loading the sketch in an ATtiny or Digispark (pro).
|
|
||||||
|
|
||||||
API/methods:
|
|
||||||
-----------
|
|
||||||
* TinyPinChange_Init()
|
|
||||||
* TinyPinChange_RegisterIsr()
|
|
||||||
* TinyPinChange_EnablePin()
|
|
||||||
* TinyPinChange_DisablePin()
|
|
||||||
* TinyPinChange_GetPortEvent()
|
|
||||||
* TinyPinChange_GetCurPortSt()
|
|
||||||
* TinyPinChange_PinToMsk()
|
|
||||||
* TinyPinChange_Edge()
|
|
||||||
* TinyPinChange_RisingEdge
|
|
||||||
* TinyPinChange_FallingEdge
|
|
||||||
|
|
||||||
Design considerations:
|
|
||||||
---------------------
|
|
||||||
On the arduino MEGA, as all the pins do not support "pin change interrupt", only the following pins are supported:
|
|
||||||
|
|
||||||
* 10 -> 15
|
|
||||||
* 50 -> 53
|
|
||||||
* A8 -> A15
|
|
||||||
|
|
||||||
On other devices (ATmega328, ATtiny84, ATtiny85 and ATtiny167), all the pins are usable.
|
|
||||||
|
|
||||||
Contact
|
|
||||||
-------
|
|
||||||
|
|
||||||
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).
|
|
||||||
|
|
@ -1,184 +0,0 @@
|
|||||||
/********************************************************************************/
|
|
||||||
/* PROJECT: All based on ATtinyX5, ATtinyX4, Atiny167, ATmega328P, ATmega2560 */
|
|
||||||
/* MODULE: TinyPinChange */
|
|
||||||
/* VERSION: 1.2 (20/12/2014) */
|
|
||||||
/* DATE: 30/01/2011 */
|
|
||||||
/* TARGET: ATtinyX5, ATtinyX4, ATtiny167, ATmega328P, ATmega2560 */
|
|
||||||
/* COMPILER: WinAvr, avr-gcc, avr-g++ */
|
|
||||||
/* IDE: ARDUINO, AVR Studio 4 */
|
|
||||||
/* PROGRAMER: AVR-JTAG-ICE MKII, ARDUINO IDE */
|
|
||||||
/* AUTHOR: P.LOUSSOUARN (P.Loussouarn: http://p.loussouarn.free.fr) */
|
|
||||||
/********************************************************************************/
|
|
||||||
#include <TinyPinChange.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
MACROS
|
|
||||||
*************************************************************************/
|
|
||||||
|
|
||||||
#define PIN_CHANGE_HANDLER_MAX_NB 3 /* ISR max number Pin Change ISR can handle per port */
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
GLOBAL VARIABLES
|
|
||||||
*************************************************************************/
|
|
||||||
struct PinChangeStruct
|
|
||||||
{
|
|
||||||
void (*Isr[PIN_CHANGE_HANDLER_MAX_NB])(void);
|
|
||||||
uint8_t LoadedIsrNb;
|
|
||||||
uint8_t Event;
|
|
||||||
uint8_t PinPrev;
|
|
||||||
uint8_t PinCur;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PinChangePortStruct
|
|
||||||
{
|
|
||||||
PinChangeStruct Port[PIN_CHG_PORT_NB];
|
|
||||||
};
|
|
||||||
|
|
||||||
static volatile struct PinChangePortStruct PinChange;
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
INTERRUPT SUB-ROUTINE
|
|
||||||
*************************************************************************/
|
|
||||||
#define DECLARE_PIN_CHANGE_ISR(VirtualPortIdx) \
|
|
||||||
ISR(PCINT##VirtualPortIdx##_vect) \
|
|
||||||
{ \
|
|
||||||
uint8_t Idx; \
|
|
||||||
PinChange.Port[VirtualPortIdx].PinCur = (PC_PIN##VirtualPortIdx) & (PC_PCMSK##VirtualPortIdx); \
|
|
||||||
PinChange.Port[VirtualPortIdx].Event = PinChange.Port[VirtualPortIdx].PinPrev ^ PinChange.Port[VirtualPortIdx].PinCur; \
|
|
||||||
PinChange.Port[VirtualPortIdx].PinPrev = PinChange.Port[VirtualPortIdx].PinCur; \
|
|
||||||
for(Idx = 0; Idx < PinChange.Port[VirtualPortIdx].LoadedIsrNb; Idx++) \
|
|
||||||
{ \
|
|
||||||
PinChange.Port[VirtualPortIdx].Isr[Idx](); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
DECLARE_PIN_CHANGE_ISR(0)
|
|
||||||
|
|
||||||
#if defined(__AVR_ATtinyX4__) || defined(__AVR_ATtiny167__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega2560__)
|
|
||||||
DECLARE_PIN_CHANGE_ISR(1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega2560__)
|
|
||||||
DECLARE_PIN_CHANGE_ISR(2)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
PUBLIC FUNCTIONS
|
|
||||||
*************************************************************************/
|
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
PinChange Initialization Function
|
|
||||||
Input:
|
|
||||||
Void
|
|
||||||
Output:
|
|
||||||
Void
|
|
||||||
*********************************************************************/
|
|
||||||
void TinyPinChange_Init(void)
|
|
||||||
{
|
|
||||||
/* ATtinyX5, ATtiny167, ATtinyX4, UNO, MEGA */
|
|
||||||
PinChange.Port[0].PinCur = PC_PIN0 & PC_PCMSK0;//PINB for ATtinyX5, UNO or MEGA, PINA for ATtinyX4 or ATtiny167
|
|
||||||
PinChange.Port[0].PinPrev = PinChange.Port[0].PinCur;
|
|
||||||
#if defined(__AVR_ATtinyX4__) || defined(__AVR_ATtiny167__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega2560__)
|
|
||||||
/* ATtinyX4, ATtiny167, UNO or MEGA */
|
|
||||||
PinChange.Port[1].PinCur = PC_PIN1 & PC_PCMSK1;//PINB for for ATtinyX4 or ATtiny167, PINC for UNO, PINJ for MEGA
|
|
||||||
PinChange.Port[1].PinPrev = PinChange.Port[1].PinCur;
|
|
||||||
#endif
|
|
||||||
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega2560__)
|
|
||||||
/* UNO or MEGA */
|
|
||||||
PinChange.Port[2].PinCur = PC_PIN2 & PC_PCMSK2;//PIND for UNO, PINK for MEGA
|
|
||||||
PinChange.Port[2].PinPrev = PinChange.Port[2].PinCur;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
PinChange RegisterIsr Function
|
|
||||||
Input:
|
|
||||||
Pointer on a PinChange Function
|
|
||||||
Output:
|
|
||||||
The associated VirtualPortIdx (0 to 2)
|
|
||||||
< 0 in case of failure
|
|
||||||
*********************************************************************/
|
|
||||||
int8_t TinyPinChange_RegisterIsr(uint8_t Pin, void(*Isr)(void))
|
|
||||||
{
|
|
||||||
int8_t IsrIdx, PortIdx, AlreadyLoaded = 0;
|
|
||||||
|
|
||||||
PortIdx = DigitalPinToPortIdx(Pin);
|
|
||||||
|
|
||||||
for(IsrIdx = 0; IsrIdx < PIN_CHANGE_HANDLER_MAX_NB; IsrIdx++)
|
|
||||||
{
|
|
||||||
if(PinChange.Port[PortIdx].Isr[IsrIdx] == Isr)
|
|
||||||
{
|
|
||||||
AlreadyLoaded = 1;
|
|
||||||
break; /* Already loaded */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!AlreadyLoaded)
|
|
||||||
{
|
|
||||||
if(PinChange.Port[PortIdx].LoadedIsrNb < PIN_CHANGE_HANDLER_MAX_NB)
|
|
||||||
{
|
|
||||||
/* Not aready loaded: load it */
|
|
||||||
PinChange.Port[PortIdx].Isr[PinChange.Port[PortIdx].LoadedIsrNb] = Isr;
|
|
||||||
PinChange.Port[PortIdx].LoadedIsrNb++;
|
|
||||||
}
|
|
||||||
else PortIdx = -1; /* Failure */
|
|
||||||
}
|
|
||||||
return(PortIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
PinChange Enable Pin Function
|
|
||||||
Input:
|
|
||||||
Pin: the Pin
|
|
||||||
Output:
|
|
||||||
Void
|
|
||||||
*********************************************************************/
|
|
||||||
void TinyPinChange_EnablePin(uint8_t Pin)
|
|
||||||
{
|
|
||||||
if(digitalPinToPCICR(Pin))
|
|
||||||
{
|
|
||||||
*digitalPinToPCICR(Pin) |= _BV(digitalPinToPCICRbit(Pin));
|
|
||||||
*digitalPinToPCMSK(Pin) |= _BV(digitalPinToPCMSKbit(Pin));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
PinChange Disable Pin Function
|
|
||||||
Input:
|
|
||||||
Pin: the Pin
|
|
||||||
Output:
|
|
||||||
Void
|
|
||||||
*********************************************************************/
|
|
||||||
void TinyPinChange_DisablePin(uint8_t Pin)
|
|
||||||
{
|
|
||||||
if(digitalPinToPCICR(Pin))
|
|
||||||
{
|
|
||||||
*digitalPinToPCMSK(Pin) &= (_BV(digitalPinToPCMSKbit(Pin)) ^ 0xFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
PinChange GetPortEvent Function
|
|
||||||
Input:
|
|
||||||
VirtualPortIdx: Index of the Port
|
|
||||||
Output:
|
|
||||||
The bits which have changed in the port
|
|
||||||
*********************************************************************/
|
|
||||||
uint8_t TinyPinChange_GetPortEvent(uint8_t VirtualPortIdx)
|
|
||||||
{
|
|
||||||
return(PinChange.Port[VirtualPortIdx].Event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
PinChange GetCurPortSt Function
|
|
||||||
Input:
|
|
||||||
VirtualPortIdx: Index of the Port
|
|
||||||
Output:
|
|
||||||
Current Status of the port
|
|
||||||
*********************************************************************/
|
|
||||||
uint8_t TinyPinChange_GetCurPortSt(uint8_t VirtualPortIdx)
|
|
||||||
{
|
|
||||||
return(PinChange.Port[VirtualPortIdx].PinCur);
|
|
||||||
}
|
|
@ -1,116 +0,0 @@
|
|||||||
#ifndef TINY_PIN_CHANGE_H
|
|
||||||
#define TINY_PIN_CHANGE_H 1
|
|
||||||
|
|
||||||
/*
|
|
||||||
* <TinyPinChange>, a library for Pin Change Interrupt by RC Navy (2012)
|
|
||||||
* Supported devices: ATmega238P (UNO), ATmega2560 (MEGA), ATtiny84, ATtiny85, ATtiny167
|
|
||||||
*
|
|
||||||
* http://p.loussouarn.free.fr
|
|
||||||
* 20/04/2014: Support for MEGA added
|
|
||||||
* 22/12/2014: Support for ATtiny167 added
|
|
||||||
* Methods TinyPinChange_Edge(), TinyPinChange_RisingEdge(), TinyPinChange_FallingEdge() added
|
|
||||||
* TinyPinChange_GetPinEvent() replaced with TinyPinChange_GetPortEvent()
|
|
||||||
* TinyPinChange_GetPinCurSt() replaced with TinyPinChange_GetCurPortSt()
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(ARDUINO) && ARDUINO >= 100
|
|
||||||
#include "Arduino.h"
|
|
||||||
#else
|
|
||||||
#include "WProgram.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#ifdef __AVR_ATtinyX5__
|
|
||||||
#undef __AVR_ATtinyX5__
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
|
||||||
#define __AVR_ATtinyX5__
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __AVR_ATtinyX4__
|
|
||||||
#undef __AVR_ATtinyX4__
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
|
|
||||||
#define __AVR_ATtinyX4__
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __AVR_ATtinyX5__
|
|
||||||
/* ATtinyX5 */
|
|
||||||
#define PIN_CHG_PORT_NB 1
|
|
||||||
#define DigitalPinToPortIdx(p) 0
|
|
||||||
#define PC_PIN0 PINB
|
|
||||||
#define PC_PCMSK0 PCMSK
|
|
||||||
#else
|
|
||||||
#ifdef __AVR_ATtinyX4__
|
|
||||||
/* ATtinyX4 */
|
|
||||||
#define PIN_CHG_PORT_NB 2
|
|
||||||
#define DigitalPinToPortIdx(p) (((p) <= 7) ? (0) : (((p) <= 10) ? (1) : (0)))
|
|
||||||
#define PC_PIN0 PINA
|
|
||||||
#define PC_PCMSK0 PCMSK0
|
|
||||||
#define PC_PIN1 PINB
|
|
||||||
#define PC_PCMSK1 PCMSK1
|
|
||||||
#else
|
|
||||||
#if defined(__AVR_ATmega2560__)
|
|
||||||
/* MEGA */
|
|
||||||
#define PIN_CHG_PORT_NB 3
|
|
||||||
#define DigitalPinToPortIdx(p) ((((p) >= A8) && ((p) <= A15)) ? (2) : ((((p) >= 50) && ((p) <= 53)) ? (0) : ((((p) >= 10) && ((p) <= 13)) ? (0) : (1))))
|
|
||||||
#define PC_PIN0 PINB
|
|
||||||
#define PC_PCMSK0 PCMSK0
|
|
||||||
#define PC_PIN1 PINJ
|
|
||||||
#define PC_PCMSK1 PCMSK1
|
|
||||||
#define PC_PIN2 PINK
|
|
||||||
#define PC_PCMSK2 PCMSK2
|
|
||||||
#else
|
|
||||||
#if defined(__AVR_ATtiny167__)
|
|
||||||
/* ATtiny167 */
|
|
||||||
#define PIN_CHG_PORT_NB 2
|
|
||||||
#define DigitalPinToPortIdx(p) (((p) >= 5 && (p) <= 12) ? (0) : (1))
|
|
||||||
#define PC_PIN0 PINA
|
|
||||||
#define PC_PCMSK0 PCMSK0
|
|
||||||
#define PC_PIN1 PINB
|
|
||||||
#define PC_PCMSK1 PCMSK1
|
|
||||||
#else
|
|
||||||
/* UNO */
|
|
||||||
#define PIN_CHG_PORT_NB 3
|
|
||||||
#define DigitalPinToPortIdx(p) (((p) <= 7) ? (2) : (((p) <= 13) ? (0) : (((p) <= 21) ? (1) : (0))))
|
|
||||||
#define PC_PIN0 PINB
|
|
||||||
#define PC_PCMSK0 PCMSK0
|
|
||||||
#define PC_PIN1 PINC
|
|
||||||
#define PC_PCMSK1 PCMSK1
|
|
||||||
#define PC_PIN2 PIND
|
|
||||||
#define PC_PCMSK2 PCMSK2
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void TinyPinChange_Init(void);
|
|
||||||
int8_t TinyPinChange_RegisterIsr(uint8_t Pin, void(*Isr)(void));
|
|
||||||
void TinyPinChange_EnablePin(uint8_t Pin);
|
|
||||||
void TinyPinChange_DisablePin(uint8_t Pin);
|
|
||||||
uint8_t TinyPinChange_GetPortEvent(uint8_t VirtualPortIdx);
|
|
||||||
uint8_t TinyPinChange_GetCurPortSt(uint8_t VirtualPortIdx);
|
|
||||||
#define TinyPinChange_PinToMsk(Pin) _BV(digitalPinToPCMSKbit(Pin))
|
|
||||||
#define TinyPinChange_Edge(VirtualPortIdx, Pin) ( TinyPinChange_GetPortEvent((VirtualPortIdx)) & TinyPinChange_PinToMsk((Pin)) )
|
|
||||||
#define TinyPinChange_RisingEdge(VirtualPortIdx, Pin) ( TinyPinChange_GetPortEvent((VirtualPortIdx)) & TinyPinChange_PinToMsk((Pin)) & TinyPinChange_GetCurPortSt((VirtualPortIdx)) )
|
|
||||||
#define TinyPinChange_FallingEdge(VirtualPortIdx, Pin) ( TinyPinChange_GetPortEvent((VirtualPortIdx)) & TinyPinChange_PinToMsk((Pin)) & (TinyPinChange_GetCurPortSt((VirtualPortIdx) ^ 0xFF)) )
|
|
||||||
|
|
||||||
/*******************************************************/
|
|
||||||
/* Application Programming Interface (API) en Francais */
|
|
||||||
/*******************************************************/
|
|
||||||
|
|
||||||
/* Methodes en Francais English native methods */
|
|
||||||
#define TinyPinChange_EnregistreFonctionInterruption TinyPinChange_RegisterIsr
|
|
||||||
#define TinyPinChange_ActiveBroche TinyPinChange_EnablePin
|
|
||||||
#define TinyPinChange_DesactiveBroche TinyPinChange_DisablePin
|
|
||||||
#define TinyPinChange_RetourneEvenemenPort TinyPinChange_GetPortEvent
|
|
||||||
#define TinyPinChange_RetourneEtatCourantPort TinyPinChange_GetCurPortSt
|
|
||||||
#define TinyPinChange_MasqueDeBroche TinyPinChange_PinToMsk
|
|
||||||
#define TinyPinChange_Front TinyPinChange_Edge
|
|
||||||
#define TinyPinChange_FrontMontant TinyPinChange_RisingEdge
|
|
||||||
#define TinyPinChange_FrontDescendant TinyPinChange_FallingEdge
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,158 +0,0 @@
|
|||||||
/*
|
|
||||||
_____ ____ __ _ ____ _ _ _ _
|
|
||||||
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
|
|
||||||
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
|
|
||||||
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
|
|
||||||
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|
|
||||||
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2013/2014
|
|
||||||
|
|
||||||
http://p.loussouarn.free.fr
|
|
||||||
|
|
||||||
*******************************************************
|
|
||||||
* <TinyPinChange> library Demo *
|
|
||||||
* with debugging capabilities using *
|
|
||||||
* <SoftSerial> object as single wire serial interface *
|
|
||||||
*******************************************************
|
|
||||||
|
|
||||||
This sketch demonstrates how to use <TinyPinChange> library.
|
|
||||||
It counts all the FALLING edges on 2 different pins.
|
|
||||||
/!\CAUTION/!\: as <TinyPinChange> library can be shared (and it is with SoftSerial in this sketch) , the user shall test if the changes are related to the declared pins.
|
|
||||||
|
|
||||||
Trick: By connecting Pin#1 to Pin#0 or to Pin#5 through a 1K resistor, you can generate transitions for testing purpose.
|
|
||||||
Output results are sent to a software serial.
|
|
||||||
|
|
||||||
And the great thing is: using a <SoftSerial> object as a bi-directionnal software serial port (half-duplex) on a single pin to communicate with the outside world!
|
|
||||||
|
|
||||||
To display the sketch results on a PC (in a Terminal):
|
|
||||||
1) Build the "Serial One Wire Debug Cable" and plug it to the regular RS232 port as depicted below,
|
|
||||||
2) Open your favorite Terminal at 38400,n,8,1: HyperTerminal, Teraterm (Windows) or Minicom, GtkTerm (Linux) and CoolTerm (MAC) does the trick.
|
|
||||||
3) You can also use the Serial Monitor of the arduino IDE: Tools->Serial Port and select your RS232 port (may be an USB virtual port), Rate=38400.
|
|
||||||
4) To enable the display, type 1, to disable, type 0 in the Terminal/Monitor.
|
|
||||||
|
|
||||||
SERIAL ONE WIRE
|
|
||||||
DEBUGGING CABLE
|
|
||||||
_______________ ________________
|
|
||||||
/ \___/\___/ \
|
|
||||||
____
|
|
||||||
.--------. | \
|
|
||||||
| GND |--------------------------------+---o5 \
|
|
||||||
| | 47K | | 9o |
|
|
||||||
| | .--###--' | o4 |
|
|
||||||
| DEBUG | 4.7K | | 8o |
|
|
||||||
| TX_RX |-------------------###--+--|<|------o3 | ---> To regular RS232 SubD 9 pins Male of PC or Serial/USB adapter
|
|
||||||
| PIN | ^ | 1N4148 | 7o |
|
|
||||||
| | | '-----------o2 |
|
|
||||||
'--------' | | 6o |
|
|
||||||
ATtiny85 Single | o1 /
|
|
||||||
(Digispark) I/O |____/
|
|
||||||
SubD 9 pins
|
|
||||||
Female
|
|
||||||
*/
|
|
||||||
#include <TinyPinChange.h>
|
|
||||||
#include <SoftSerial.h>
|
|
||||||
|
|
||||||
#define LED_PIN 1
|
|
||||||
|
|
||||||
#define DEBUG_TX_RX_PIN 2
|
|
||||||
|
|
||||||
#define FIRST_INPUT 0
|
|
||||||
#define SECOND_INPUT 5
|
|
||||||
|
|
||||||
volatile uint16_t FirstInputChangeCount = 0; /* Volatile since the variable will be updated in interruption */
|
|
||||||
volatile uint16_t SecondInputChangeCount = 0; /* Volatile since the variable will be updated in interruption */
|
|
||||||
|
|
||||||
SoftSerial MySerial(DEBUG_TX_RX_PIN, DEBUG_TX_RX_PIN, true); /* Tx/Rx on a single Pin !!! (Pin#2) */
|
|
||||||
|
|
||||||
uint8_t VirtualPortNb;
|
|
||||||
uint8_t VirtualPortNb_;
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
TinyPinChange_Init();
|
|
||||||
|
|
||||||
MySerial.begin(57600); /* Trick: use a "high" data rate (less time wasted in ISR and for transmitting each character) */
|
|
||||||
|
|
||||||
VirtualPortNb = TinyPinChange_RegisterIsr(FIRST_INPUT, InterruptFunctionToCall);
|
|
||||||
VirtualPortNb_ = TinyPinChange_RegisterIsr(SECOND_INPUT, InterruptFunctionToCall);
|
|
||||||
|
|
||||||
/* Enable Pin Change for each pin */
|
|
||||||
TinyPinChange_EnablePin(FIRST_INPUT);
|
|
||||||
TinyPinChange_EnablePin(SECOND_INPUT);
|
|
||||||
|
|
||||||
MySerial.txMode();
|
|
||||||
MySerial.println(F("\n*** Tiny PinChange Demo (Falling Edge) ***"));
|
|
||||||
MySerial.print(F("Pin "));MySerial.print((int)FIRST_INPUT);
|
|
||||||
MySerial.print(F(" is part of virtual port "));MySerial.println((int)VirtualPortNb);
|
|
||||||
|
|
||||||
MySerial.print(F("Pin "));MySerial.print((int)SECOND_INPUT);
|
|
||||||
MySerial.print(F(" is part of virtual port "));MySerial.println((int)VirtualPortNb_);
|
|
||||||
|
|
||||||
MySerial.println(F("As you can see, virtual port is always port 0 for ATtiny85"));
|
|
||||||
MySerial.println(F("Remember <TinyPinChange> is also designed for UNO, MEGA, ATtiny84 and ATtiny167 ;-)"));
|
|
||||||
MySerial.println(F("Type 1 to start display, 0 to stop display"));
|
|
||||||
|
|
||||||
pinMode(LED_PIN, OUTPUT);
|
|
||||||
|
|
||||||
MySerial.rxMode(); /* Switch to Rx Mode */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Function called in interruption in case of change on pins */
|
|
||||||
void InterruptFunctionToCall(void)
|
|
||||||
{
|
|
||||||
if(TinyPinChange_FallingEdge(VirtualPortNb, FIRST_INPUT)) /* Check for FIRST_INPUT Rising Edge */
|
|
||||||
{
|
|
||||||
FirstInputChangeCount++; /* Only Falling edges are counted */
|
|
||||||
}
|
|
||||||
|
|
||||||
if(TinyPinChange_FallingEdge(VirtualPortNb_, SECOND_INPUT)) /* Check for SECOND_INPUT Rising Edge */
|
|
||||||
{
|
|
||||||
SecondInputChangeCount++; /* Only Falling edges are counted */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
static boolean State = HIGH, DisplayEnabled = true;
|
|
||||||
static uint32_t LedStartMs = millis(), DisplayStartMs = millis();
|
|
||||||
uint16_t LocalFirstInputChangeCount;
|
|
||||||
uint16_t LocalSecondInputChangeCount;
|
|
||||||
|
|
||||||
/* Blink the built-in LED */
|
|
||||||
if(millis() - LedStartMs >= 500UL)
|
|
||||||
{
|
|
||||||
LedStartMs = millis();
|
|
||||||
digitalWrite(LED_PIN, State);
|
|
||||||
State = !State; /* State will be inverted at the next digitalWrite() */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get command from single wire SoftSerial */
|
|
||||||
if(MySerial.available())
|
|
||||||
{
|
|
||||||
switch(MySerial.read())
|
|
||||||
{
|
|
||||||
case '0':
|
|
||||||
DisplayEnabled = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '1':
|
|
||||||
DisplayEnabled = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Diplay Transition numbers every second */
|
|
||||||
if((millis() - DisplayStartMs >= 1000UL) && DisplayEnabled)
|
|
||||||
{
|
|
||||||
DisplayStartMs = millis();
|
|
||||||
noInterrupts(); /* Mandatory since counters are 16 bits */
|
|
||||||
LocalFirstInputChangeCount = FirstInputChangeCount;
|
|
||||||
LocalSecondInputChangeCount = SecondInputChangeCount;
|
|
||||||
interrupts();
|
|
||||||
MySerial.txMode();
|
|
||||||
MySerial.print(F("FirstInputChangeCount="));MySerial.println(LocalFirstInputChangeCount);
|
|
||||||
MySerial.print(F("SecondInputChangeCount="));MySerial.println(LocalSecondInputChangeCount);
|
|
||||||
MySerial.rxMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,158 +0,0 @@
|
|||||||
/*
|
|
||||||
_____ ____ __ _ ____ _ _ _ _
|
|
||||||
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
|
|
||||||
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
|
|
||||||
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
|
|
||||||
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|
|
||||||
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2013/2014
|
|
||||||
|
|
||||||
http://p.loussouarn.free.fr
|
|
||||||
|
|
||||||
*******************************************************
|
|
||||||
* <TinyPinChange> library Demo *
|
|
||||||
* with debugging capabilities using *
|
|
||||||
* <SoftSerial> object as single wire serial interface *
|
|
||||||
*******************************************************
|
|
||||||
|
|
||||||
This sketch demonstrates how to use <TinyPinChange> library.
|
|
||||||
It counts all the RISING edges on 2 different pins.
|
|
||||||
/!\CAUTION/!\: as <TinyPinChange> library can be shared (and it is with SoftSerial in this sketch) , the user shall test if the changes are related to the declared pins.
|
|
||||||
|
|
||||||
Trick: By connecting Pin#1 to Pin#0 or to Pin#5 through a 1K resistor, you can generate transitions for testing purpose.
|
|
||||||
Output results are sent to a software serial.
|
|
||||||
|
|
||||||
And the great thing is: using a <SoftSerial> object as a bi-directionnal software serial port (half-duplex) on a single pin to communicate with the outside world!
|
|
||||||
|
|
||||||
To display the sketch results on a PC (in a Terminal):
|
|
||||||
1) Build the "Serial One Wire Debug Cable" and plug it to the regular RS232 port as depicted below,
|
|
||||||
2) Open your favorite Terminal at 38400,n,8,1: HyperTerminal, Teraterm (Windows) or Minicom, GtkTerm (Linux) and CoolTerm (MAC) does the trick.
|
|
||||||
3) You can also use the Serial Monitor of the arduino IDE: Tools->Serial Port and select your RS232 port (may be an USB virtual port), Rate=38400.
|
|
||||||
4) To enable the display, type 1, to disable, type 0 in the Terminal/Monitor.
|
|
||||||
|
|
||||||
SERIAL ONE WIRE
|
|
||||||
DEBUGGING CABLE
|
|
||||||
_______________ ________________
|
|
||||||
/ \___/\___/ \
|
|
||||||
____
|
|
||||||
.--------. | \
|
|
||||||
| GND |--------------------------------+---o5 \
|
|
||||||
| | 47K | | 9o |
|
|
||||||
| | .--###--' | o4 |
|
|
||||||
| DEBUG | 4.7K | | 8o |
|
|
||||||
| TX_RX |-------------------###--+--|<|------o3 | ---> To regular RS232 SubD 9 pins Male of PC or Serial/USB adapter
|
|
||||||
| PIN | ^ | 1N4148 | 7o |
|
|
||||||
| | | '-----------o2 |
|
|
||||||
'--------' | | 6o |
|
|
||||||
ATtiny85 Single | o1 /
|
|
||||||
(Digispark) I/O |____/
|
|
||||||
SubD 9 pins
|
|
||||||
Female
|
|
||||||
*/
|
|
||||||
#include <TinyPinChange.h>
|
|
||||||
#include <SoftSerial.h>
|
|
||||||
|
|
||||||
#define LED_PIN 1
|
|
||||||
|
|
||||||
#define DEBUG_TX_RX_PIN 2
|
|
||||||
|
|
||||||
#define FIRST_INPUT 0
|
|
||||||
#define SECOND_INPUT 5
|
|
||||||
|
|
||||||
volatile uint16_t FirstInputChangeCount = 0; /* Volatile since the variable will be updated in interruption */
|
|
||||||
volatile uint16_t SecondInputChangeCount = 0; /* Volatile since the variable will be updated in interruption */
|
|
||||||
|
|
||||||
SoftSerial MySerial(DEBUG_TX_RX_PIN, DEBUG_TX_RX_PIN, true); /* Tx/Rx on a single Pin !!! (Pin#2) */
|
|
||||||
|
|
||||||
uint8_t VirtualPortNb;
|
|
||||||
uint8_t VirtualPortNb_;
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
TinyPinChange_Init();
|
|
||||||
|
|
||||||
MySerial.begin(57600); /* Trick: use a "high" data rate (less time wasted in ISR and for transmitting each character) */
|
|
||||||
|
|
||||||
VirtualPortNb = TinyPinChange_RegisterIsr(FIRST_INPUT, InterruptFunctionToCall);
|
|
||||||
VirtualPortNb_ = TinyPinChange_RegisterIsr(SECOND_INPUT, InterruptFunctionToCall);
|
|
||||||
|
|
||||||
/* Enable Pin Change for each pin */
|
|
||||||
TinyPinChange_EnablePin(FIRST_INPUT);
|
|
||||||
TinyPinChange_EnablePin(SECOND_INPUT);
|
|
||||||
|
|
||||||
MySerial.txMode();
|
|
||||||
MySerial.println(F("\n*** Tiny PinChange Demo (Rising Edge) ***"));
|
|
||||||
MySerial.print(F("Pin "));MySerial.print((int)FIRST_INPUT);
|
|
||||||
MySerial.print(F(" is part of virtual port "));MySerial.println((int)VirtualPortNb);
|
|
||||||
|
|
||||||
MySerial.print(F("Pin "));MySerial.print((int)SECOND_INPUT);
|
|
||||||
MySerial.print(F(" is part of virtual port "));MySerial.println((int)VirtualPortNb_);
|
|
||||||
|
|
||||||
MySerial.println(F("As you can see, virtual port is always port 0 for ATtiny85"));
|
|
||||||
MySerial.println(F("Remember <TinyPinChange> is also designed for UNO, MEGA, ATtiny84 and ATtiny167 ;-)"));
|
|
||||||
MySerial.println(F("Type 1 to start display, 0 to stop display"));
|
|
||||||
|
|
||||||
pinMode(LED_PIN, OUTPUT);
|
|
||||||
|
|
||||||
MySerial.rxMode(); /* Switch to Rx Mode */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Function called in interruption in case of change on pins */
|
|
||||||
void InterruptFunctionToCall(void)
|
|
||||||
{
|
|
||||||
if(TinyPinChange_RisingEdge(VirtualPortNb, FIRST_INPUT)) /* Check for FIRST_INPUT Rising Edge */
|
|
||||||
{
|
|
||||||
FirstInputChangeCount++; /* Only Rising edges are counted */
|
|
||||||
}
|
|
||||||
|
|
||||||
if(TinyPinChange_RisingEdge(VirtualPortNb_, SECOND_INPUT)) /* Check for SECOND_INPUT Rising Edge */
|
|
||||||
{
|
|
||||||
SecondInputChangeCount++; /* Only Rising edges are counted */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
static boolean State = HIGH, DisplayEnabled = true;
|
|
||||||
static uint32_t LedStartMs = millis(), DisplayStartMs = millis();
|
|
||||||
uint16_t LocalFirstInputChangeCount;
|
|
||||||
uint16_t LocalSecondInputChangeCount;
|
|
||||||
|
|
||||||
/* Blink the built-in LED */
|
|
||||||
if(millis() - LedStartMs >= 500UL)
|
|
||||||
{
|
|
||||||
LedStartMs = millis();
|
|
||||||
digitalWrite(LED_PIN, State);
|
|
||||||
State = !State; /* State will be inverted at the next digitalWrite() */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get command from single wire SoftSerial */
|
|
||||||
if(MySerial.available())
|
|
||||||
{
|
|
||||||
switch(MySerial.read())
|
|
||||||
{
|
|
||||||
case '0':
|
|
||||||
DisplayEnabled = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '1':
|
|
||||||
DisplayEnabled = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Diplay Transition numbers every second */
|
|
||||||
if((millis() - DisplayStartMs >= 1000UL) && DisplayEnabled)
|
|
||||||
{
|
|
||||||
DisplayStartMs = millis();
|
|
||||||
noInterrupts(); /* Mandatory since counters are 16 bits */
|
|
||||||
LocalFirstInputChangeCount = FirstInputChangeCount;
|
|
||||||
LocalSecondInputChangeCount = SecondInputChangeCount;
|
|
||||||
interrupts();
|
|
||||||
MySerial.txMode();
|
|
||||||
MySerial.print(F("FirstInputChangeCount="));MySerial.println(LocalFirstInputChangeCount);
|
|
||||||
MySerial.print(F("SecondInputChangeCount="));MySerial.println(LocalSecondInputChangeCount);
|
|
||||||
MySerial.rxMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,440 +0,0 @@
|
|||||||
/*
|
|
||||||
_____ ____ __ _ ____ _ _ _ _
|
|
||||||
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
|
|
||||||
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
|
|
||||||
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
|
|
||||||
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|
|
||||||
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2013/2014
|
|
||||||
|
|
||||||
http://p.loussouarn.free.fr
|
|
||||||
|
|
||||||
*******************************************************
|
|
||||||
* <TinyPinChange> library Demo *
|
|
||||||
* with display capabilities using *
|
|
||||||
* <SoftSerial> object as single wire serial interface *
|
|
||||||
*******************************************************
|
|
||||||
|
|
||||||
This "Tiny RC Scope" sketch demonstrates how to use <TinyPinChange> and <SoftSerial> libraries.
|
|
||||||
"Tiny RC Scope" acts as a simple real time ASCII oscilloscope for displaying one RC Channel in the serial console.
|
|
||||||
The displayed measurement (in µs) are: pulse width and RC period.
|
|
||||||
|
|
||||||
Trick: By connecting Pin#1 to Pin#0, through a 1K resistor, you can measure the RC Signal provided by the built-in RC generator for testing purpose.
|
|
||||||
Output results are sent to a software serial port. If a real RC signal is connected to Pin0, the trace is displayed in real time in the terminal.
|
|
||||||
|
|
||||||
And the great thing is: using a <SoftSerial> object as a bi-directionnal software serial port (half-duplex) on a single pin to communicate with the outside world!
|
|
||||||
|
|
||||||
To display the sketch results on a PC (in a Terminal):
|
|
||||||
1) Build the "Serial One Wire Debug Cable" and plug it to the regular RS232 port as depicted below.
|
|
||||||
2) Open your favorite Terminal at 57600,n,8,1: HyperTerminal, Teraterm (Windows) or Minicom, GtkTerm (Linux) and CoolTerm (MAC) does the trick.
|
|
||||||
3) You can also use the Serial Monitor of the arduino IDE: Tools->Serial Port and select your RS232 port (may be an USB virtual port), Rate=57600.
|
|
||||||
4) To test "Tiny RC Scope", connect Pin1 to Pin0, and look at the Terminal (57600,n,8,1) connected to Pin2 through a debug cable ()
|
|
||||||
5) The wave form should be displayed in the Terminal,
|
|
||||||
6) Type - to decrease the pulse width (-10us),
|
|
||||||
7) Type + to increase the pulse width (+10us),
|
|
||||||
8) Type m to set the pulse width to its minimum (500us),
|
|
||||||
9) Type n or N to set the pulse width to its Neutral value (1500us),
|
|
||||||
10) Type M to set the pulse width to its Maximum (2500us),
|
|
||||||
11) To measure real RC signals, disconnect the Pin1 from Pin0 and connect a RC receiver output to Pin0,
|
|
||||||
12) The Terminal will display in real time the pulse width of the connected RC channel.
|
|
||||||
13) If the channel is not connected, a flat line is displayed.
|
|
||||||
|
|
||||||
SERIAL ONE WIRE
|
|
||||||
DEBUGGING CABLE
|
|
||||||
_______________ ________________
|
|
||||||
/ \___/\___/ \
|
|
||||||
____
|
|
||||||
.--------. | \
|
|
||||||
| GND |--------------------------------+---o5 \
|
|
||||||
| | 47K | | 9o |
|
|
||||||
| | .--###--' | o4 |
|
|
||||||
| DEBUG | 4.7K | | 8o |
|
|
||||||
| TX_RX |-------------------###--+--|<|------o3 | ---> To regular RS232 SubD 9 pins Male of PC or Serial/USB adapter
|
|
||||||
| PIN | ^ | 1N4148 | 7o |
|
|
||||||
| | | '-----------o2 |
|
|
||||||
'--------' | | 6o |
|
|
||||||
ATtiny85 Single | o1 /
|
|
||||||
(Digispark) I/O |____/
|
|
||||||
(pro) SubD 9 pins
|
|
||||||
Female
|
|
||||||
*/
|
|
||||||
#include <TinyPinChange.h>
|
|
||||||
#include <SoftSerial.h>
|
|
||||||
|
|
||||||
#define RC_CHANNEL_PIN 0 /* RC Channel is connected to pin 0 */
|
|
||||||
#define RC_GEN_PIN 1 /* Pin used as internal RC generator for test purpose */
|
|
||||||
|
|
||||||
#define RC_PINS_MSK (_BV(RC_CHANNEL_PIN) | _BV(RC_GEN_PIN))
|
|
||||||
|
|
||||||
#define DEBUG_TX_RX_PIN 2
|
|
||||||
|
|
||||||
#define DEF_TEST_RC_CH_WIDTH_US 1500 /* This value can be change via the Terminal */
|
|
||||||
#define TEST_RC_PERIOD_US 20000
|
|
||||||
|
|
||||||
#define PULSE_MAX_US 2500
|
|
||||||
#define PULSE_MIN_US 500
|
|
||||||
#define STEP_US 10
|
|
||||||
|
|
||||||
#define ERR_MARGIN_US 150
|
|
||||||
|
|
||||||
#define SERIAL_BAUD_RATE 57600 /* 57600 is the maximum for Receiving commands from the serial port: 1 char -> #200us */
|
|
||||||
SoftSerial MySerial(DEBUG_TX_RX_PIN, DEBUG_TX_RX_PIN, true); /* Tx/Rx on a single Pin !!! (Pin#2) */
|
|
||||||
|
|
||||||
#define ONE_CHAR_TX_TIME_US 200 /* @ 57600 bauds */
|
|
||||||
|
|
||||||
enum {PULSE_SRC_INTERNAL, PULSE_SRC_EXTERNAL};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t RisingStartUs;
|
|
||||||
uint32_t RcWidth_us;
|
|
||||||
uint32_t LastRxPulseMs;
|
|
||||||
boolean FallingEdgeFound;
|
|
||||||
}RcChSt_t;
|
|
||||||
|
|
||||||
volatile RcChSt_t Ch; /* volatile, since value are used in ISR and in the loop() */
|
|
||||||
volatile uint32_t RcPeriod_us = TEST_RC_PERIOD_US;
|
|
||||||
uint32_t TestRcWidth_us = DEF_TEST_RC_CH_WIDTH_US;
|
|
||||||
|
|
||||||
/* The different states of the display state machine */
|
|
||||||
enum {DISP_COMPUTE, DISP_FIRST_LINE, DISP_PREP_SEC_LINE, DISP_SECOND_LINE, DISP_PREP_THIRD_LINE, DISP_THIRD_LINE, DISP_WAIT};
|
|
||||||
|
|
||||||
#define LINE_LEN 38
|
|
||||||
|
|
||||||
typedef struct{
|
|
||||||
char Line[LINE_LEN];
|
|
||||||
uint8_t Idx;
|
|
||||||
uint8_t State;
|
|
||||||
uint8_t HighNb;
|
|
||||||
}DispSt_t;
|
|
||||||
|
|
||||||
static DispSt_t Disp;
|
|
||||||
|
|
||||||
volatile uint8_t IntRcSynch = 0;
|
|
||||||
uint8_t VirtualPortIdx;
|
|
||||||
/*
|
|
||||||
RC Signal
|
|
||||||
____ ____
|
|
||||||
_| |____________________________| |_
|
|
||||||
<---->
|
|
||||||
Width_us
|
|
||||||
<-------------------------------->
|
|
||||||
Period_us
|
|
||||||
*/
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
TinyPinChange_Init();
|
|
||||||
|
|
||||||
MySerial.begin(SERIAL_BAUD_RATE); /* Trick: use a "high" data rate (less time wasted in ISR and for transmitting each character) */
|
|
||||||
|
|
||||||
Disp.State = DISP_COMPUTE;
|
|
||||||
|
|
||||||
VirtualPortIdx = TinyPinChange_RegisterIsr(RC_CHANNEL_PIN, InterruptFunctionToCall); /* As all pins are on the same port, a single ISR is needed */
|
|
||||||
pinMode(RC_CHANNEL_PIN, INPUT);
|
|
||||||
digitalWrite(RC_CHANNEL_PIN, HIGH); /* Enable Pull-up to avoid floating inputs in case of nothing connected to them */
|
|
||||||
TinyPinChange_EnablePin(RC_CHANNEL_PIN);
|
|
||||||
|
|
||||||
Ch.RcWidth_us = 0;
|
|
||||||
Ch.FallingEdgeFound = 0;
|
|
||||||
|
|
||||||
MySerial.txMode();
|
|
||||||
MySerial.println(F("\n -- Tiny RC Scope V1.0 (C) RC Navy 2014 --\n"));
|
|
||||||
MySerial.rxMode(); /* Switch to Rx Mode */
|
|
||||||
|
|
||||||
pinMode(RC_GEN_PIN, OUTPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
uint32_t RcGeneStartUs = micros();
|
|
||||||
static uint32_t ProcessStartUs = micros();
|
|
||||||
static uint32_t DisplayStartMs = millis();
|
|
||||||
uint32_t ProcessDurationUs;
|
|
||||||
uint32_t HalfRemaingLowUs;
|
|
||||||
char RxChar;
|
|
||||||
|
|
||||||
/* Blink the built-in LED (Built-in RC Signal generator) */
|
|
||||||
if(IsInternalRcSrc())
|
|
||||||
{
|
|
||||||
RcGeneStartUs = micros();
|
|
||||||
digitalWrite(RC_GEN_PIN, HIGH);
|
|
||||||
while(micros() - RcGeneStartUs < TestRcWidth_us);
|
|
||||||
digitalWrite(RC_GEN_PIN, LOW);
|
|
||||||
}
|
|
||||||
/********************/
|
|
||||||
/* Start of process */
|
|
||||||
/********************/
|
|
||||||
ProcessStartUs = micros();
|
|
||||||
DisplayRcMeasurement(5000U);/* Gives 5000 us to display a part of the trace */
|
|
||||||
/* Get command from single wire SoftSerial (to tune the built-in generator) */
|
|
||||||
if(MySerial.available() > 0)
|
|
||||||
{
|
|
||||||
RxChar = MySerial.read();MySerial.txMode();MySerial.println("");MySerial.rxMode(); /* Carriage return after the echo */
|
|
||||||
switch(RxChar)
|
|
||||||
{
|
|
||||||
case '-': /* Decrease Built-in RC Pulse */
|
|
||||||
if((TestRcWidth_us - STEP_US) >= PULSE_MIN_US)
|
|
||||||
{
|
|
||||||
TestRcWidth_us -= STEP_US;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '+': /* Increase Built-in RC Pulse */
|
|
||||||
if(TestRcWidth_us + STEP_US <= PULSE_MAX_US)
|
|
||||||
{
|
|
||||||
TestRcWidth_us += STEP_US;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'm': /* Set Built-in RC Pulse o min value: 500 */
|
|
||||||
TestRcWidth_us = PULSE_MIN_US;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'N': /* Set Built-in RC Pulse to Neutral: 1500 */
|
|
||||||
case 'n':
|
|
||||||
TestRcWidth_us = DEF_TEST_RC_CH_WIDTH_US;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'M': /* Set Built-in RC Pulse to Max value: 2500 */
|
|
||||||
TestRcWidth_us = PULSE_MAX_US;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
/* Ignore */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/********************/
|
|
||||||
/* End of process */
|
|
||||||
/********************/
|
|
||||||
ProcessDurationUs = micros() - ProcessStartUs; //Compute how many us took the previous instructions
|
|
||||||
if(IsInternalRcSrc())
|
|
||||||
{
|
|
||||||
HalfRemaingLowUs = TEST_RC_PERIOD_US - (ProcessDurationUs + TestRcWidth_us + 100UL);
|
|
||||||
RcGeneStartUs = micros();
|
|
||||||
while((micros() - RcGeneStartUs) < HalfRemaingLowUs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
RC Signal
|
|
||||||
____ ____
|
|
||||||
_| |____________________________| |_
|
|
||||||
<---->
|
|
||||||
Width_us
|
|
||||||
<-------------------------------->
|
|
||||||
Period_us
|
|
||||||
<-------------------->
|
|
||||||
Display is processed here
|
|
||||||
|
|
||||||
Explanation: the display of the trace is performed just after the falling edge of the RC pulse
|
|
||||||
As the duration between 2 pulses is too short to display the full trace, the trace is displayed part by part.
|
|
||||||
A full trace is composed of around 100 characters:
|
|
||||||
At 57600 bauds, one character takes (1/57600) * 10 = 174 us. As there are some overhead, it is closer than 200us.
|
|
||||||
So, the full trace takes 100 x 200 = 20000 us = 20 ms. It's impossible to display the full trace between 2 consecutive pulses.
|
|
||||||
DisplayRcMeasurement() function is the very tricky part of this sketch: it has as argument an amount of time and exits before
|
|
||||||
it exceeds it. A state machine is used to memorize where the display was arrived.
|
|
||||||
*/
|
|
||||||
uint8_t DisplayRcMeasurement(uint16_t FreetimeUs)
|
|
||||||
{
|
|
||||||
static uint32_t LocalRcWidth_us;
|
|
||||||
static uint32_t LocalRcPeriod_us;
|
|
||||||
static uint32_t StartWaitMs;
|
|
||||||
char *Ptr;
|
|
||||||
|
|
||||||
uint32_t ProcessStart_us;
|
|
||||||
uint32_t Elapsed_us;
|
|
||||||
uint8_t StartIdx, Idx;
|
|
||||||
uint8_t Ret = 0;
|
|
||||||
|
|
||||||
switch(Disp.State)
|
|
||||||
{
|
|
||||||
case DISP_COMPUTE:
|
|
||||||
DispCompute:
|
|
||||||
if(Ch.FallingEdgeFound)
|
|
||||||
{
|
|
||||||
DispComputeNoSignal:
|
|
||||||
ProcessStart_us = micros();
|
|
||||||
Ch.FallingEdgeFound = 0;
|
|
||||||
noInterrupts(); /* Mandatory since RcWidth_us and RcPeriod_us are 32 bits */
|
|
||||||
LocalRcWidth_us = Ch.RcWidth_us;
|
|
||||||
LocalRcPeriod_us = RcPeriod_us;
|
|
||||||
interrupts();
|
|
||||||
|
|
||||||
if(LocalRcWidth_us < (PULSE_MIN_US - ERR_MARGIN_US) || LocalRcWidth_us > (PULSE_MAX_US + ERR_MARGIN_US)) LocalRcWidth_us = 0; /* Out of Range */
|
|
||||||
Disp.HighNb = (LocalRcWidth_us + 50UL) / 100;
|
|
||||||
strcpy_P(Disp.Line, PSTR("Ch(P0)__"));
|
|
||||||
if(LocalRcWidth_us)
|
|
||||||
{
|
|
||||||
Ptr = Disp.Line + 8;
|
|
||||||
for(Idx = 0; Idx < Disp.HighNb; Idx++) *Ptr++='_';*Ptr++='\n';*Ptr=0;
|
|
||||||
}
|
|
||||||
else Disp.Line[6] = 0;
|
|
||||||
Elapsed_us = micros() - ProcessStart_us;
|
|
||||||
FreetimeUs -= (uint16_t)Elapsed_us;
|
|
||||||
Disp.Idx=0;
|
|
||||||
Disp.State = DISP_FIRST_LINE;
|
|
||||||
if(FreetimeUs >= ONE_CHAR_TX_TIME_US)
|
|
||||||
{
|
|
||||||
goto DispFirstLine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(millis() - StartWaitMs >= 1000UL)
|
|
||||||
{
|
|
||||||
LocalRcWidth_us = 0;
|
|
||||||
goto DispComputeNoSignal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DISP_PREP_SEC_LINE:
|
|
||||||
DispPrepSecLine:
|
|
||||||
/* Prepare second line */
|
|
||||||
ProcessStart_us = micros();
|
|
||||||
if(LocalRcWidth_us)
|
|
||||||
{
|
|
||||||
strcpy_P(Disp.Line, PSTR("_____/"));
|
|
||||||
for(Idx = 0; Idx < (2 + Disp.HighNb); Idx++) Disp.Line[6 + Idx] = ' ';
|
|
||||||
itoa(LocalRcWidth_us, Disp.Line + 6, 10);StartIdx = 9; if(LocalRcWidth_us >= 1000) StartIdx++;Disp.Line[StartIdx++] = 'u';Disp.Line[StartIdx++] = 's';
|
|
||||||
StartIdx = 6 + 2 + Disp.HighNb;Disp.Line[StartIdx++] = '\\';
|
|
||||||
}
|
|
||||||
else StartIdx = 0;
|
|
||||||
for(Idx = 0; (StartIdx + Idx ) < (LINE_LEN - 2); Idx++) Disp.Line[StartIdx + Idx] = '_';Disp.Line[StartIdx + Idx] = '\n';Disp.Line[++StartIdx + Idx] = 0;
|
|
||||||
Elapsed_us = micros() - ProcessStart_us;
|
|
||||||
FreetimeUs -= (uint16_t)Elapsed_us;
|
|
||||||
Disp.Idx=0;
|
|
||||||
Disp.State = DISP_SECOND_LINE;
|
|
||||||
if(FreetimeUs >= ONE_CHAR_TX_TIME_US)
|
|
||||||
{
|
|
||||||
goto DispSecondLine;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DISP_PREP_THIRD_LINE:
|
|
||||||
DispPrepThirdLine:
|
|
||||||
/* Prepare third line */
|
|
||||||
ProcessStart_us = micros();
|
|
||||||
strcpy_P(Disp.Line, PSTR(" RC Period: "));
|
|
||||||
if(LocalRcWidth_us)
|
|
||||||
{
|
|
||||||
itoa(LocalRcPeriod_us, Disp.Line + 20, 10);
|
|
||||||
strcat_P(Disp.Line, PSTR("us"));
|
|
||||||
}
|
|
||||||
else strcat_P(Disp.Line, PSTR("???"));
|
|
||||||
Elapsed_us = micros() - ProcessStart_us;
|
|
||||||
FreetimeUs -= (uint16_t)Elapsed_us;
|
|
||||||
Disp.Idx=0;
|
|
||||||
Disp.State = DISP_THIRD_LINE;
|
|
||||||
if(FreetimeUs >= ONE_CHAR_TX_TIME_US)
|
|
||||||
{
|
|
||||||
goto DispThirdLine;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DISP_FIRST_LINE:
|
|
||||||
case DISP_SECOND_LINE:
|
|
||||||
case DISP_THIRD_LINE:
|
|
||||||
DispFirstLine:
|
|
||||||
DispSecondLine:
|
|
||||||
DispThirdLine:
|
|
||||||
ProcessStart_us = micros();
|
|
||||||
MySerial.txMode();
|
|
||||||
while(1)
|
|
||||||
{
|
|
||||||
if(Disp.Line[Disp.Idx])
|
|
||||||
{
|
|
||||||
MySerial.print(Disp.Line[Disp.Idx++]);
|
|
||||||
if (micros() - ProcessStart_us >= (FreetimeUs - ONE_CHAR_TX_TIME_US))
|
|
||||||
{
|
|
||||||
MySerial.rxMode();
|
|
||||||
break; /* exit while(1) and stay in the current state */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch(Disp.State)
|
|
||||||
{
|
|
||||||
case DISP_FIRST_LINE:
|
|
||||||
/* First line is fully displayed */
|
|
||||||
Disp.State = DISP_PREP_SEC_LINE;
|
|
||||||
if(FreetimeUs - Elapsed_us >= 200)
|
|
||||||
{
|
|
||||||
FreetimeUs -= (uint16_t)Elapsed_us;
|
|
||||||
goto DispPrepSecLine;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Not enough time: just change state */
|
|
||||||
MySerial.rxMode();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DISP_SECOND_LINE:
|
|
||||||
/* Second line is fully displayed */
|
|
||||||
Disp.State = DISP_PREP_THIRD_LINE;
|
|
||||||
if(FreetimeUs - Elapsed_us >= 200)
|
|
||||||
{
|
|
||||||
FreetimeUs -= (uint16_t)Elapsed_us;
|
|
||||||
goto DispPrepThirdLine;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Not enough time: just change state */
|
|
||||||
MySerial.rxMode();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DISP_THIRD_LINE:
|
|
||||||
/* Third line is fully displayed */
|
|
||||||
MySerial.print('\n');
|
|
||||||
StartWaitMs = millis();
|
|
||||||
Disp.State = DISP_WAIT;
|
|
||||||
MySerial.rxMode();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break; /* exit while(1) */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DISP_WAIT:
|
|
||||||
if(millis() - StartWaitMs >= 500UL) Disp.State = DISP_COMPUTE; /* Give some time to enter commands via the terminal (in internal source mode) */
|
|
||||||
else Ch.FallingEdgeFound = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return(Ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The following function checks if the received signal is the image of the one of the built-in RC generator */
|
|
||||||
uint8_t IsInternalRcSrc()
|
|
||||||
{
|
|
||||||
uint8_t Ret;
|
|
||||||
static uint32_t SampleStartMs = millis();
|
|
||||||
if(millis() - Ch.LastRxPulseMs >= 300UL) IntRcSynch = 100; /* Kick off Internal RC generator */
|
|
||||||
Ret = (IntRcSynch >= 100);
|
|
||||||
if(millis() - SampleStartMs >= 10UL)
|
|
||||||
{
|
|
||||||
SampleStartMs = millis();
|
|
||||||
IntRcSynch = 99;
|
|
||||||
}
|
|
||||||
return(Ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Function called in interruption in case of change on RC pins: pulse width and RC period measurement */
|
|
||||||
void InterruptFunctionToCall(void)
|
|
||||||
{
|
|
||||||
if(TinyPinChange_RisingEdge(VirtualPortIdx, RC_CHANNEL_PIN)) /* Check for RC Channel rising edge */
|
|
||||||
{
|
|
||||||
RcPeriod_us = micros() - Ch.RisingStartUs;
|
|
||||||
Ch.RisingStartUs = micros();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Ch.RcWidth_us = micros() - Ch.RisingStartUs;
|
|
||||||
Ch.FallingEdgeFound = true;
|
|
||||||
Ch.LastRxPulseMs = millis();
|
|
||||||
if(!(PINB & RC_PINS_MSK)) /* Check if RC_CHANNEL_PIN and RC_GEN_PIN are both to 0 */
|
|
||||||
{
|
|
||||||
if(IntRcSynch < 100) IntRcSynch++; /* if IntRcSynch reaches 100, it means the RC source is internal (synchronized) */
|
|
||||||
}else IntRcSynch = 0; /* Not synchronized */
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
TinySoftPwm library
|
|
||||||
===================
|
|
||||||
|
|
||||||
**TinySoftPwm** is a library designed to generate PWM signals by software.
|
|
||||||
|
|
||||||
Some examples of use cases:
|
|
||||||
-------------------------
|
|
||||||
* **RGB strip LED Controller**
|
|
||||||
* **DC Motor controller**
|
|
||||||
* **Digital to Analog converter**
|
|
||||||
|
|
||||||
Supported Arduinos:
|
|
||||||
------------------
|
|
||||||
* **ATtiny85 (Standalone or Digispark)** (up to 6 software PWM supported)
|
|
||||||
* **ATtiny167 (Digispark pro)** (up to 13 software PWM supported)
|
|
||||||
|
|
||||||
API/methods:
|
|
||||||
-----------
|
|
||||||
* TinySoftPwm_begin()
|
|
||||||
* TinySoftPwm_analogWrite()
|
|
||||||
* TinySoftPwm_process()
|
|
||||||
|
|
||||||
|
|
||||||
Design considerations:
|
|
||||||
---------------------
|
|
||||||
In order to reduce **program** and **RAM** memories, PWM pins shall be declared in the **TinySoftPwm.h** file. All the required amount of **program** and **RAM** memories are allocated at compilation time.
|
|
||||||
|
|
||||||
The **TinySoftPwm_process()** method shall be called periodically:
|
|
||||||
|
|
||||||
* using micros() in the loop(): in this case, asynchronous programmation shall be used: no call to blocking functions such as delay() is permitted.
|
|
||||||
* or better using periodic interruption.
|
|
||||||
|
|
||||||
In order to reduce the memory footprint (programm and RAM), try to use the PWM on pins which are part of the same port: PORTA or PORTB.
|
|
||||||
|
|
||||||
Contact
|
|
||||||
-------
|
|
||||||
|
|
||||||
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).
|
|
||||||
|
|
@ -1,299 +0,0 @@
|
|||||||
// a Tiny optimized Software PWM Manager (all pins must be part of the same port)
|
|
||||||
// Only resources RAM/Program Memory of used pins are declared in the code at compilation time.
|
|
||||||
// based largely on Atmel's AVR136: Low-Jitter Multi-Channel Software PWM Application Note:
|
|
||||||
// http://www.atmel.com/dyn/resources/prod_documents/doc8020.pdf
|
|
||||||
// RC Navy 2013-2015
|
|
||||||
// http://p.loussouarn.free.fr
|
|
||||||
// 11/01/2015: Multi port support added for ATtiny167
|
|
||||||
|
|
||||||
#include <TinySoftPwm.h>
|
|
||||||
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX == 0)
|
|
||||||
#error At least one PWM pin shall be declared in TinySoftPwm.h
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(TINY_SOFT_PWM_DDR1) && defined(TINY_SOFT_PWM_DDR0)
|
|
||||||
#define TINY_SOFT_PWM_DECLARE_PIN(Pin) do{ \
|
|
||||||
if(digitalPinToPortIdx(Pin)) \
|
|
||||||
{ \
|
|
||||||
TINY_SOFT_PWM_DDR1 |= (1 << digitalPinToPortBit(Pin)); \
|
|
||||||
Port1_PwmMask |= (1 << digitalPinToPortBit(Pin)); \
|
|
||||||
} \
|
|
||||||
else \
|
|
||||||
{ \
|
|
||||||
TINY_SOFT_PWM_DDR0 |= (1 << digitalPinToPortBit(Pin)); \
|
|
||||||
Port0_PwmMask |= (1 << digitalPinToPortBit(Pin)); \
|
|
||||||
} \
|
|
||||||
}while(0)
|
|
||||||
|
|
||||||
#define TINY_SOFT_PWM_CLEAR_PIN(RamIdx) GET_PWM_PIN_PORT(RamIdx) \
|
|
||||||
? (Port1_PwmTo1 &= GET_PWM_INV_MSK(RamIdx)) \
|
|
||||||
: (Port0_PwmTo1 &= GET_PWM_INV_MSK(RamIdx))
|
|
||||||
#else
|
|
||||||
#if defined(TINY_SOFT_PWM_DDR1)
|
|
||||||
#define TINY_SOFT_PWM_DECLARE_PIN(Pin) TINY_SOFT_PWM_DDR1 |= (1 << digitalPinToPortBit(Pin)); Port1_PwmMask |= (1 << digitalPinToPortBit(Pin))
|
|
||||||
#define TINY_SOFT_PWM_CLEAR_PIN(RamIdx) Port1_PwmTo1 &= GET_PWM_INV_MSK(RamIdx)
|
|
||||||
#else
|
|
||||||
#define TINY_SOFT_PWM_DECLARE_PIN(Pin) TINY_SOFT_PWM_DDR0 |= (1 << digitalPinToPortBit(Pin)); Port0_PwmMask |= (1 << digitalPinToPortBit(Pin))
|
|
||||||
#define TINY_SOFT_PWM_CLEAR_PIN(RamIdx) Port0_PwmTo1 &= GET_PWM_INV_MSK(RamIdx)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define GET_PWM_PIN_ID(RamIdx) ((uint8_t)pgm_read_byte(&PwmPin[(RamIdx)].Id))
|
|
||||||
#define GET_PWM_PIN_PORT(RamIdx) ((uint8_t)pgm_read_byte(&PwmPin[(RamIdx)].Port))
|
|
||||||
#define GET_PWM_INV_MSK(RamIdx) ((uint8_t)pgm_read_byte(&PwmPin[(RamIdx)].InvMsk))
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t Id;
|
|
||||||
uint8_t Port;
|
|
||||||
uint8_t InvMsk;
|
|
||||||
}SoftPwmPinSt_t;
|
|
||||||
|
|
||||||
const SoftPwmPinSt_t PwmPin[] PROGMEM ={
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN0 == 1)
|
|
||||||
{0, digitalPinToPortIdx(0), ~(1 << digitalPinToPortBit(0))},
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN1 == 1)
|
|
||||||
{1, digitalPinToPortIdx(1), ~(1 << digitalPinToPortBit(1))},
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN2 == 1)
|
|
||||||
{2, digitalPinToPortIdx(2), ~(1 << digitalPinToPortBit(2))},
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN3 == 1)
|
|
||||||
{3, digitalPinToPortIdx(3), ~(1 << digitalPinToPortBit(3))},
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN4 == 1)
|
|
||||||
{4, digitalPinToPortIdx(4), ~(1 << digitalPinToPortBit(4))},
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN5 == 1)
|
|
||||||
{5, digitalPinToPortIdx(5), ~(1 << digitalPinToPortBit(5))},
|
|
||||||
#endif
|
|
||||||
#if defined (__AVR_ATtiny167__)
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN6 == 1)
|
|
||||||
{6, digitalPinToPortIdx(6), ~(1 << digitalPinToPortBit(6))},
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN7 == 1)
|
|
||||||
{7, digitalPinToPortIdx(7), ~(1 << digitalPinToPortBit(7))},
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN8 == 1)
|
|
||||||
{8, digitalPinToPortIdx(8), ~(1 << digitalPinToPortBit(8))},
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN9 == 1)
|
|
||||||
{9, digitalPinToPortIdx(9), ~(1 << digitalPinToPortBit(9))},
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN10 == 1)
|
|
||||||
{10, digitalPinToPortIdx(10), ~(1 << digitalPinToPortBit(10))},
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN11 == 1)
|
|
||||||
{11, digitalPinToPortIdx(11), ~(1 << digitalPinToPortBit(11))},
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN12 == 1)
|
|
||||||
{12, digitalPinToPortIdx(12), ~(1 << digitalPinToPortBit(12))},
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
static uint8_t Compare[TINY_SOFT_PWM_CH_MAX];
|
|
||||||
volatile uint8_t PwmOrder[TINY_SOFT_PWM_CH_MAX];
|
|
||||||
#ifdef TINY_SOFT_PWM_PORT0
|
|
||||||
static uint8_t Port0_PwmMask = 0;
|
|
||||||
volatile uint8_t Port0_PwmTo1 = 0x00;
|
|
||||||
volatile uint8_t Port0_PwmTo0 = 0xFF;
|
|
||||||
#endif
|
|
||||||
#ifdef TINY_SOFT_PWM_PORT1
|
|
||||||
static uint8_t Port1_PwmMask = 0;
|
|
||||||
volatile uint8_t Port1_PwmTo1 = 0x00;
|
|
||||||
volatile uint8_t Port1_PwmTo0 = 0xFF;
|
|
||||||
#endif
|
|
||||||
static uint8_t _TickMax = 255;
|
|
||||||
|
|
||||||
static uint8_t PwmToPwmMax(uint8_t Pwm);
|
|
||||||
|
|
||||||
void TinySoftPwm_begin(uint8_t TickMax, uint8_t PwmInit)
|
|
||||||
{
|
|
||||||
uint8_t oldSREG = SREG;
|
|
||||||
cli();
|
|
||||||
// set the direction of the used ports and update PortPwmMask
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN0 == 1)
|
|
||||||
TINY_SOFT_PWM_DECLARE_PIN(0);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN1 == 1)
|
|
||||||
TINY_SOFT_PWM_DECLARE_PIN(1);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN2 == 1)
|
|
||||||
TINY_SOFT_PWM_DECLARE_PIN(2);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN3 == 1)
|
|
||||||
TINY_SOFT_PWM_DECLARE_PIN(3);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN4 == 1)
|
|
||||||
TINY_SOFT_PWM_DECLARE_PIN(4);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN5 == 1)
|
|
||||||
TINY_SOFT_PWM_DECLARE_PIN(5);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN6 == 1)
|
|
||||||
TINY_SOFT_PWM_DECLARE_PIN(6);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN7 == 1)
|
|
||||||
TINY_SOFT_PWM_DECLARE_PIN(7);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN8 == 1)
|
|
||||||
TINY_SOFT_PWM_DECLARE_PIN(8);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN9 == 1)
|
|
||||||
TINY_SOFT_PWM_DECLARE_PIN(9);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN10 == 1)
|
|
||||||
TINY_SOFT_PWM_DECLARE_PIN(10);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN11 == 1)
|
|
||||||
TINY_SOFT_PWM_DECLARE_PIN(11);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_USES_PIN12 == 1)
|
|
||||||
TINY_SOFT_PWM_DECLARE_PIN(12);
|
|
||||||
#endif
|
|
||||||
_TickMax = TickMax;
|
|
||||||
#ifdef TINY_SOFT_PWM_PORT0
|
|
||||||
Port0_PwmTo1 = Port0_PwmMask;
|
|
||||||
#endif
|
|
||||||
#ifdef TINY_SOFT_PWM_PORT1
|
|
||||||
Port1_PwmTo1 = Port1_PwmMask;
|
|
||||||
#endif
|
|
||||||
// initialise all channels
|
|
||||||
for(uint8_t i = 0; i < TINY_SOFT_PWM_CH_MAX; i++)
|
|
||||||
{
|
|
||||||
Compare[i] = PwmToPwmMax(PwmInit); // set default PWM values
|
|
||||||
PwmOrder[i] = Compare[i]; // set default PWM values
|
|
||||||
}
|
|
||||||
SREG = oldSREG;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TinySoftPwm_analogWrite(uint8_t Pin, uint8_t Pwm)
|
|
||||||
{
|
|
||||||
uint8_t RamIdx;
|
|
||||||
|
|
||||||
for(RamIdx = 0; RamIdx < TINY_SOFT_PWM_CH_MAX; RamIdx++)
|
|
||||||
{
|
|
||||||
if(GET_PWM_PIN_ID(RamIdx) == Pin) break;
|
|
||||||
}
|
|
||||||
if(RamIdx < TINY_SOFT_PWM_CH_MAX)
|
|
||||||
{
|
|
||||||
PwmOrder[RamIdx] = PwmToPwmMax(Pwm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t PwmToPwmMax(uint8_t Pwm)
|
|
||||||
{
|
|
||||||
uint16_t Pwm16;
|
|
||||||
Pwm16 = map(Pwm, 0, 255, 0, _TickMax);
|
|
||||||
Pwm16 = constrain(Pwm16, 0, _TickMax);
|
|
||||||
return((uint8_t)Pwm16);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TinySoftPwm_process(void)
|
|
||||||
{
|
|
||||||
static uint8_t OvfCount=0xFF;
|
|
||||||
|
|
||||||
#ifdef TINY_SOFT_PWM_PORT0
|
|
||||||
Port0_PwmTo0 = (~Port0_PwmTo1) ^ Port0_PwmMask;
|
|
||||||
TINY_SOFT_PWM_PORT0 |= Port0_PwmTo1; // update ONLY used outputs to 1 without disturbing the others
|
|
||||||
TINY_SOFT_PWM_PORT0 &= Port0_PwmTo0; // update ONLY used outputs to 0 without disturbing the others
|
|
||||||
#endif
|
|
||||||
#ifdef TINY_SOFT_PWM_PORT1
|
|
||||||
Port1_PwmTo0 = (~Port1_PwmTo1) ^ Port1_PwmMask;
|
|
||||||
TINY_SOFT_PWM_PORT1 |= Port1_PwmTo1; // update ONLY used outputs to 1 without disturbing the others
|
|
||||||
TINY_SOFT_PWM_PORT1 &= Port1_PwmTo0; // update ONLY used outputs to 0 without disturbing the others
|
|
||||||
#endif
|
|
||||||
if(++OvfCount == _TickMax)
|
|
||||||
{ // increment modulo 256 counter and update
|
|
||||||
// the compare values only when counter = 0.
|
|
||||||
OvfCount=0;
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 1)
|
|
||||||
Compare[0] = PwmOrder[0]; // verbose code for speed
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 2)
|
|
||||||
Compare[1] = PwmOrder[1];
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 3)
|
|
||||||
Compare[2] = PwmOrder[2];
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 4)
|
|
||||||
Compare[3] = PwmOrder[3];
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 5)
|
|
||||||
Compare[4] = PwmOrder[4];
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 6)
|
|
||||||
Compare[5] = PwmOrder[5];
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 7)
|
|
||||||
Compare[6] = PwmOrder[6]; // verbose code for speed
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 8)
|
|
||||||
Compare[7] = PwmOrder[7];
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 9)
|
|
||||||
Compare[8] = PwmOrder[8];
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 10)
|
|
||||||
Compare[9] = PwmOrder[9];
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 11)
|
|
||||||
Compare[10] = PwmOrder[10];
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 12)
|
|
||||||
Compare[11] = PwmOrder[11];
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 13)
|
|
||||||
Compare[12] = PwmOrder[12];
|
|
||||||
#endif
|
|
||||||
#ifdef TINY_SOFT_PWM_PORT0
|
|
||||||
Port0_PwmTo1 = Port0_PwmMask; // set all port used pins high
|
|
||||||
#endif
|
|
||||||
#ifdef TINY_SOFT_PWM_PORT1
|
|
||||||
Port1_PwmTo1 = Port1_PwmMask; // set all port used pins high
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
// clear port pin on compare match (executed on next interrupt)
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 1)
|
|
||||||
if(Compare[0] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(0);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 2)
|
|
||||||
if(Compare[1] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(1);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 3)
|
|
||||||
if(Compare[2] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(2);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 4)
|
|
||||||
if(Compare[3] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(3);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 5)
|
|
||||||
if(Compare[4] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(4);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 6)
|
|
||||||
if(Compare[5] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(5);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 7)
|
|
||||||
if(Compare[6] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(6);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 8)
|
|
||||||
if(Compare[7] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(7);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 9)
|
|
||||||
if(Compare[8] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(8);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 10)
|
|
||||||
if(Compare[9] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(9);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 11)
|
|
||||||
if(Compare[10] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(10);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 12)
|
|
||||||
if(Compare[11] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(11);
|
|
||||||
#endif
|
|
||||||
#if (TINY_SOFT_PWM_CH_MAX >= 13)
|
|
||||||
if(Compare[12] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(12);
|
|
||||||
#endif
|
|
||||||
}
|
|
@ -1,192 +0,0 @@
|
|||||||
#ifndef TinySoftPwm_h
|
|
||||||
#define TinySoftPwm_h
|
|
||||||
|
|
||||||
// a Tiny optimized Software PWM Manager (all pins must be part of the same port)
|
|
||||||
// Only resources RAM/Program Memory of used pins are declared in the code at compilation time.
|
|
||||||
// based largely on Atmel's AVR136: Low-Jitter Multi-Channel Software PWM Application Note:
|
|
||||||
// http://www.atmel.com/dyn/resources/prod_documents/doc8020.pdf
|
|
||||||
// RC Navy 2013-2015
|
|
||||||
// http://p.loussouarn.free.fr
|
|
||||||
// 11/01/2015: Automated multi port support (at compilation time) added for ATtiny167
|
|
||||||
|
|
||||||
#if defined(ARDUINO) && ARDUINO >= 100
|
|
||||||
#include "Arduino.h"
|
|
||||||
#else
|
|
||||||
#include "WProgram.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
/*************************************************/
|
|
||||||
/* Define here the PIN to use with Tiny Soft PWM */
|
|
||||||
/* Unused Pin(s) SHALL be commented */
|
|
||||||
/*************************************************/
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN0
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN1
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN2
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN3 /* /!\ used for USB on DigiSpark (pro): do not use it for PWM if DigiUSB or SerialCDC are also used /!\ */
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN4 /* /!\ used for USB on DigiSpark (pro): do not use it for PWM if DigiUSB or SerialCDC are also used /!\ */
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN5
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN6
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN7
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN8
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN9
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN10
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN11
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN12
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************/
|
|
||||||
/* Do NOT modify below: it's used to optimize RAM and Program size */
|
|
||||||
/*******************************************************************/
|
|
||||||
#if defined (__AVR_ATtiny85__)
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN6
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN7
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN8
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN9
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN10
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN11
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN12
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TINY_SOFT_PWM_USES_PIN0
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN0
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN0 1
|
|
||||||
#else
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN0 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TINY_SOFT_PWM_USES_PIN1
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN1
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN1 1
|
|
||||||
#else
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN1 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TINY_SOFT_PWM_USES_PIN2
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN2
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN2 1
|
|
||||||
#else
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN2 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TINY_SOFT_PWM_USES_PIN3
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN3
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN3 1
|
|
||||||
#else
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN3 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TINY_SOFT_PWM_USES_PIN4
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN4
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN4 1
|
|
||||||
#else
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN4 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TINY_SOFT_PWM_USES_PIN5
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN5
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN5 1
|
|
||||||
#else
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN5 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TINY_SOFT_PWM_USES_PIN6
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN6
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN6 1
|
|
||||||
#else
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN6 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TINY_SOFT_PWM_USES_PIN7
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN7
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN7 1
|
|
||||||
#else
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN7 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TINY_SOFT_PWM_USES_PIN8
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN8
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN8 1
|
|
||||||
#else
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN8 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TINY_SOFT_PWM_USES_PIN9
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN9
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN9 1
|
|
||||||
#else
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN9 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TINY_SOFT_PWM_USES_PIN10
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN10
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN10 1
|
|
||||||
#else
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN10 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TINY_SOFT_PWM_USES_PIN11
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN11
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN11 1
|
|
||||||
#else
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN11 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TINY_SOFT_PWM_USES_PIN12
|
|
||||||
#undef TINY_SOFT_PWM_USES_PIN12
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN12 1
|
|
||||||
#else
|
|
||||||
#define TINY_SOFT_PWM_USES_PIN12 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#define TINY_SOFT_PWM_CH_MAX (TINY_SOFT_PWM_USES_PIN0 + TINY_SOFT_PWM_USES_PIN1 + TINY_SOFT_PWM_USES_PIN2 + \
|
|
||||||
TINY_SOFT_PWM_USES_PIN3 + TINY_SOFT_PWM_USES_PIN4 + TINY_SOFT_PWM_USES_PIN5 + \
|
|
||||||
TINY_SOFT_PWM_USES_PIN6 + TINY_SOFT_PWM_USES_PIN7 + TINY_SOFT_PWM_USES_PIN8 + \
|
|
||||||
TINY_SOFT_PWM_USES_PIN9 + TINY_SOFT_PWM_USES_PIN10+ TINY_SOFT_PWM_USES_PIN11+ \
|
|
||||||
TINY_SOFT_PWM_USES_PIN12)
|
|
||||||
|
|
||||||
|
|
||||||
#if defined (__AVR_ATtiny85__)
|
|
||||||
#define TINY_SOFT_PWM_USES_PORT0 0
|
|
||||||
#define TINY_SOFT_PWM_USES_PORT1 1
|
|
||||||
#ifndef digitalPinToPortIdx
|
|
||||||
#define digitalPinToPortIdx(p) 1
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#if defined (__AVR_ATtiny167__)
|
|
||||||
#define TINY_SOFT_PWM_USES_PORT0 (TINY_SOFT_PWM_USES_PIN5 || TINY_SOFT_PWM_USES_PIN6 || TINY_SOFT_PWM_USES_PIN7 || \
|
|
||||||
TINY_SOFT_PWM_USES_PIN8 || TINY_SOFT_PWM_USES_PIN9 || TINY_SOFT_PWM_USES_PIN10 || \
|
|
||||||
TINY_SOFT_PWM_USES_PIN11 || TINY_SOFT_PWM_USES_PIN12)
|
|
||||||
#define TINY_SOFT_PWM_USES_PORT1 (TINY_SOFT_PWM_USES_PIN0 || TINY_SOFT_PWM_USES_PIN1 || TINY_SOFT_PWM_USES_PIN2 || \
|
|
||||||
TINY_SOFT_PWM_USES_PIN3 || TINY_SOFT_PWM_USES_PIN4)
|
|
||||||
|
|
||||||
#ifndef digitalPinToPortIdx
|
|
||||||
#define digitalPinToPortIdx(p) (((p) >= 5 && (p) <= 12) ? (0) : (1))
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (TINY_SOFT_PWM_USES_PORT0 == 1)
|
|
||||||
#undef TINY_SOFT_PWM_USES_PORT0
|
|
||||||
#define TINY_SOFT_PWM_PORT0 PORTA
|
|
||||||
#define TINY_SOFT_PWM_DDR0 DDRA
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (TINY_SOFT_PWM_USES_PORT1 == 1)
|
|
||||||
#undef TINY_SOFT_PWM_USES_PORT1
|
|
||||||
#define TINY_SOFT_PWM_PORT1 PORTB
|
|
||||||
#define TINY_SOFT_PWM_DDR1 DDRB
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef digitalPinToPortBit
|
|
||||||
#define digitalPinToPortBit(p) digitalPinToPCMSKbit(p)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Public Function Prototypes */
|
|
||||||
void TinySoftPwm_begin(uint8_t TickMax, uint8_t PwmInit);
|
|
||||||
void TinySoftPwm_analogWrite(uint8_t Pin, uint8_t Pwm);
|
|
||||||
void TinySoftPwm_process(void);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,75 +0,0 @@
|
|||||||
#include <TinySoftPwm.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
_____ ____ __ _ ____ _ _ _ _
|
|
||||||
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
|
|
||||||
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
|
|
||||||
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
|
|
||||||
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|
|
||||||
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2015
|
|
||||||
|
|
||||||
http://p.loussouarn.free.fr
|
|
||||||
|
|
||||||
****************************************
|
|
||||||
* <TinySoftPwm> library Demo *
|
|
||||||
****************************************
|
|
||||||
|
|
||||||
This sketch generates simultaneously PWM signals on 13 pins (Pin 0 to pin 12 of the Digispark pro).
|
|
||||||
It also increases the luminosity of the built-in LED of the Digispark whilst the duty cycle remains constant for all other pins.
|
|
||||||
When the luminosity reaches its maximum, the luminosity decreases.
|
|
||||||
When the luminosity reaches its minimum, the luminosity increases, and so on...
|
|
||||||
|
|
||||||
Note:
|
|
||||||
====
|
|
||||||
Declare the Pin(s) used in "librarie/TinySoftPwm/TinySoftPwm.h"
|
|
||||||
In this sketch, #define TINY_SOFT_PWM_USES_PINO to TINY_SOFT_PWM_USES_PIN12 must be enabled (not commented) since it uses the first 13 pins of the DigiSpark pro.
|
|
||||||
|
|
||||||
In this basic example, TinySoftPwm_process() is called periodically using micros(), but it is recommanded to call it from a timer ISR
|
|
||||||
to ensure a better periodicity.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define BUILT_IN_LED_PIN 1 /* Digispark Model A (Rev2) built-in LED pin number (Change it to 2 for Model B) */
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
TinySoftPwm_begin(255, 0); /* 255 x TinySoftPwm_process() calls before overlap (Frequency tuning), 0 = PWM init for all declared pins */
|
|
||||||
for(uint8_t PinIdx = 0; PinIdx <= 12; PinIdx++)
|
|
||||||
{
|
|
||||||
TinySoftPwm_analogWrite(PinIdx, (PinIdx + 1) * 19); /* Low to high duty cycle for pin 0 to 12 */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
static uint32_t StartUs = micros();
|
|
||||||
static uint32_t StartMs = millis();
|
|
||||||
static uint8_t Pwm = 0;
|
|
||||||
static int8_t Dir = 1;
|
|
||||||
|
|
||||||
/***********************************************************/
|
|
||||||
/* Call TinySoftPwm_process() with a period of 40 us */
|
|
||||||
/* The PWM frequency = 255 x 40 # 10.2 ms -> F # 100Hz */
|
|
||||||
/* 255 is the first argument passed to TinySoftPwm_begin() */
|
|
||||||
/***********************************************************/
|
|
||||||
if((micros() - StartUs) >= 40)
|
|
||||||
{
|
|
||||||
/* We arrived here every 40 microseconds */
|
|
||||||
StartUs = micros();
|
|
||||||
TinySoftPwm_process(); /* This function shall be called periodically (like here, based on micros(), or in a timer ISR) */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************/
|
|
||||||
/* Increment/decrement PWM on LED Pin with a period of 10 ms */
|
|
||||||
/*************************************************************/
|
|
||||||
if((millis() - StartMs) >= 10)
|
|
||||||
{
|
|
||||||
/* We arrived here every 10 milliseconds */
|
|
||||||
StartMs = millis();
|
|
||||||
Pwm += Dir; /* increment or decrement PWM depending of sign of Dir */
|
|
||||||
TinySoftPwm_analogWrite(BUILT_IN_LED_PIN, Pwm); /* Update built-in LED for Digispark */
|
|
||||||
if(Pwm == 255) Dir = -1; /* if PWM reaches the maximum: change direction */
|
|
||||||
if(Pwm == 0) Dir = +1; /* if PWM reaches the minimum: change direction */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
|||||||
|
|
||||||
void setup() {
|
|
||||||
//If prompted for a pairing code it is 1234, 12345, or 000000
|
|
||||||
Serial.begin(9600);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the loop routine runs over and over again forever:
|
|
||||||
void loop() {
|
|
||||||
if (Serial.available()) {
|
|
||||||
Serial.write(Serial.read());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
void setup() {
|
|
||||||
// put your setup code here, to run once:
|
|
||||||
Serial.begin(9600); //open connection to bt/ble module
|
|
||||||
botInit(); //setup the pins for the bot
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
|
|
||||||
if(Serial.available()){
|
|
||||||
|
|
||||||
char input = Serial.read();
|
|
||||||
|
|
||||||
//route based on input
|
|
||||||
|
|
||||||
if(input == 'f'){
|
|
||||||
botForward(255);
|
|
||||||
}
|
|
||||||
else if(input == 'b'){
|
|
||||||
botReverse(255);
|
|
||||||
}
|
|
||||||
else if(input == 'r'){
|
|
||||||
botRight(255);
|
|
||||||
}
|
|
||||||
else if(input == 'l'){
|
|
||||||
botLeft(255);
|
|
||||||
}
|
|
||||||
else if(input == 's'){
|
|
||||||
botStop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void botForward(int botSpeed){
|
|
||||||
digitalWrite(2, HIGH);
|
|
||||||
digitalWrite(5, HIGH);
|
|
||||||
analogWrite(0, 255 - botSpeed);
|
|
||||||
analogWrite(1, 255 - botSpeed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void botReverse(int botSpeed){
|
|
||||||
digitalWrite(2, LOW);
|
|
||||||
digitalWrite(5, LOW);
|
|
||||||
analogWrite(0, botSpeed);
|
|
||||||
analogWrite(1, botSpeed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void botRight(int botSpeed){
|
|
||||||
digitalWrite(2, LOW);
|
|
||||||
digitalWrite(5, HIGH);
|
|
||||||
analogWrite(0, 0);
|
|
||||||
analogWrite(1, 255 - botSpeed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void botHardRight(int botSpeed){
|
|
||||||
digitalWrite(2, LOW);
|
|
||||||
digitalWrite(5, HIGH);
|
|
||||||
analogWrite(0, botSpeed);
|
|
||||||
analogWrite(1, 255 - botSpeed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void botLeft(int botSpeed){
|
|
||||||
digitalWrite(2, HIGH);
|
|
||||||
digitalWrite(5, LOW);
|
|
||||||
analogWrite(0, 255 - botSpeed);
|
|
||||||
analogWrite(1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void botHardLeft(int botSpeed){
|
|
||||||
digitalWrite(2, HIGH);
|
|
||||||
digitalWrite(5, LOW);
|
|
||||||
analogWrite(0, 255 - botSpeed);
|
|
||||||
analogWrite(1, botSpeed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void botStop(){
|
|
||||||
digitalWrite(2,LOW);
|
|
||||||
digitalWrite(5,LOW);
|
|
||||||
analogWrite(0,0);
|
|
||||||
analogWrite(1,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void botInit(){
|
|
||||||
pinMode(0,OUTPUT);
|
|
||||||
pinMode(1,OUTPUT);
|
|
||||||
pinMode(2,OUTPUT);
|
|
||||||
pinMode(5,OUTPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1 +0,0 @@
|
|||||||
//This file allows the Digispark_Examples to appear in the File > Examples menu and fixes the Invalid library warning in Arduino IDE 1.6.6+
|
|
@ -1,105 +0,0 @@
|
|||||||
#include <SPI.h>
|
|
||||||
#include "nRF24L01.h"
|
|
||||||
#include "RF24.h"
|
|
||||||
|
|
||||||
//THESE MUST BE SET! CHANGE ADDRESS AS YOU UPLOAD TO EACH NODE!
|
|
||||||
#define TOTAL_NODES 3 //TOTAL NUMBER OF NODES IN MESH
|
|
||||||
#define NODE_ADDRESS 0 //the sero indexed address of this node - nodes must be numbered 0 thru TOTAL_NODES-1 //also note 255 is broadcast address
|
|
||||||
|
|
||||||
//hold the seuqnce numbers to avoid repeating the same messages
|
|
||||||
uint8_t sequence[TOTAL_NODES];
|
|
||||||
|
|
||||||
//setup radio module
|
|
||||||
RF24 radio(9,12);
|
|
||||||
|
|
||||||
//message format - adjust data as needed - the rest is madatory for this mesh to work
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
char toAddress;
|
|
||||||
char fromAddress;
|
|
||||||
char fromSequence;
|
|
||||||
long data;
|
|
||||||
} msg;
|
|
||||||
|
|
||||||
//don't change! read is same for all nodes, write is automatically calculated here
|
|
||||||
const uint64_t writePipe = 0xF0F0F0F00LL + NODE_ADDRESS;
|
|
||||||
const uint64_t readPipe = 0xF0F0F0F0D2LL;
|
|
||||||
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
// put your setup code here, to run once:
|
|
||||||
radio.begin();
|
|
||||||
radio.setDataRate(RF24_250KBPS); //lowest speed = most range
|
|
||||||
radio.setAutoAck(false); //this is a mesh so we don't want ACKs!
|
|
||||||
radio.setRetries(15, 15);
|
|
||||||
radio.setPayloadSize(sizeof(msg));
|
|
||||||
radio.openWritingPipe(writePipe);
|
|
||||||
radio.openReadingPipe(1, readPipe);
|
|
||||||
radio.startListening();
|
|
||||||
}
|
|
||||||
|
|
||||||
long now = 0;
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(readAndRepeat()){ //will repeat messages as needed and return false unless there is packet for this node - CALL FREQUENTLY!
|
|
||||||
//if this does not return false then we have a packet for THIS node!
|
|
||||||
//msg.fromAddress is the node that sent it
|
|
||||||
//msg.data is the data itself
|
|
||||||
//Do something with it!
|
|
||||||
//For example display packets coming to this node on a LCD:
|
|
||||||
/*
|
|
||||||
NOTE: TO USE THIS ADD THE LCD INCLUDES AND SETUP ROUTINE FROM THE DigisparkLCD example
|
|
||||||
lcd.clear();
|
|
||||||
lcd.print("From: ");
|
|
||||||
lcd.println(msg.fromAddress);
|
|
||||||
lcd.print("Value: ");
|
|
||||||
lcd.println(msg.data);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
if(millis() - now > 10000){ //send a packet from this node to the mesh every 10 seconds but wait in a non-blocking way so that we can still run this loop and repeat things
|
|
||||||
now = millis(); //set now to millis so we wait another 10 seconds before sending again
|
|
||||||
//sendToMesh(To_Address,Data_To_Send);
|
|
||||||
//sendToMesh(0, analogRead(A5)); //send to node 0 the analog read value of pin 5 - could also send a temp sensor value, etc ,etc
|
|
||||||
//sendToMesh(255, analogRead(A5)); //send to all nodes (255 is the broadcast address) the analog read value of pin 5
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void sendToMesh(uint8_t toAddress, long data){
|
|
||||||
if(sequence[NODE_ADDRESS]<255)
|
|
||||||
sequence[NODE_ADDRESS]++; //increment sequence count for this device
|
|
||||||
else
|
|
||||||
sequence[NODE_ADDRESS] = 0; //set to zero if last was 255 so we don't overflow - logic for read is built to handle this too
|
|
||||||
|
|
||||||
msg.toAddress = toAddress; //set the address of the destination node
|
|
||||||
msg.fromAddress = NODE_ADDRESS; //set the from as this node - of course
|
|
||||||
msg.fromSequence = sequence[NODE_ADDRESS]; //set it to the sequence number we just implemented which should be greater than any the nodes have received
|
|
||||||
radio.stopListening(); //turn of recv so we can transmit
|
|
||||||
radio.write(&msg, sizeof(msg));
|
|
||||||
radio.startListening(); //turn recv back on
|
|
||||||
}
|
|
||||||
|
|
||||||
bool readAndRepeat(){
|
|
||||||
if(radio.read(&msg, sizeof(msg))){ //if we have incoming data
|
|
||||||
if(msg.fromAddress!=NODE_ADDRESS){ //make sure this node didn't send it
|
|
||||||
if(sequence[msg.fromAddress] < msg.fromSequence || (sequence[msg.fromAddress] == 255 && msg.fromSequence == 0)){ //make sure we haven't already repeated it or received it
|
|
||||||
//increment sequence for that address so we don't repeat it twice from this node or receive it twice
|
|
||||||
sequence[msg.fromAddress] = msg.fromSequence;
|
|
||||||
if(msg.toAddress==NODE_ADDRESS){ //is it for this node? if so return true so we can use it!
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//otherwise repeat it - send it back out
|
|
||||||
radio.write(&msg, sizeof(msg));
|
|
||||||
if(msg.toAddress == 255){ //it was a broadcast so return true so we do something with it
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
@ -1,157 +0,0 @@
|
|||||||
#include <Wire.h>
|
|
||||||
#include <DigiKeyboard.h>
|
|
||||||
#define ADXL345 (0x53) //address of Accelerometer
|
|
||||||
#define ADXL345_X (0x32) //register for X value from Accelerometer
|
|
||||||
#define ADXL345_Y (0x34) //register for Y value from Accelerometer
|
|
||||||
#define ADXL345_Z (0x36) //register for Z value from Accelerometer
|
|
||||||
#define HMC5883 (0x1E) //address of Magnetometer
|
|
||||||
#define ITG3200 (0x68) //address of Gyro
|
|
||||||
int16_t magX = 0; //X value from Magnetometer
|
|
||||||
int16_t magY = 0; //Y value from Magnetometer
|
|
||||||
int16_t magZ = 0; //Z value from Magnetometer
|
|
||||||
int gyroHX = 0; //HX value from Gyro
|
|
||||||
int gyroHY = 0; //HY value from Gyro
|
|
||||||
int gyroHZ = 0; //HZ value from Gyro
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Wire.begin();
|
|
||||||
|
|
||||||
initAccelerometer();
|
|
||||||
|
|
||||||
initMagnetometer();
|
|
||||||
|
|
||||||
initGyro();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
|
|
||||||
DigiKeyboard.println(readAccelerometer(ADXL345_X));
|
|
||||||
DigiKeyboard.println(readAccelerometer(ADXL345_Y));
|
|
||||||
DigiKeyboard.println(readAccelerometer(ADXL345_Z));
|
|
||||||
DigiKeyboard.delay(1000);
|
|
||||||
readMagnetometer();
|
|
||||||
DigiKeyboard.println(magX);
|
|
||||||
DigiKeyboard.println(magY);
|
|
||||||
DigiKeyboard.println(magZ);
|
|
||||||
DigiKeyboard.println(getHeading());
|
|
||||||
DigiKeyboard.delay(1000);
|
|
||||||
readGyro();
|
|
||||||
DigiKeyboard.println(gyroHX);
|
|
||||||
DigiKeyboard.println(gyroHY);
|
|
||||||
DigiKeyboard.println(gyroHZ);
|
|
||||||
DigiKeyboard.delay(1000);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void initGyro(){
|
|
||||||
writeRegister(ITG3200, 0x3E, 0x00); //enable
|
|
||||||
writeRegister(ITG3200, 0x15, 0x07); // EB, 50, 80, 7F, DE, 23, 20, FF
|
|
||||||
writeRegister(ITG3200, 0x16, 0x1E); // +/- 2000 dgrs/sec, 1KHz, 1E, 19
|
|
||||||
writeRegister(ITG3200, 0x17, 0x00);
|
|
||||||
}
|
|
||||||
|
|
||||||
void readGyro(){
|
|
||||||
Wire.beginTransmission(ITG3200);
|
|
||||||
Wire.write(0x1B); //format x y z temp
|
|
||||||
Wire.endTransmission();
|
|
||||||
Wire.requestFrom(ITG3200, (byte)8);
|
|
||||||
|
|
||||||
// Wait around until enough data is available
|
|
||||||
while (Wire.available() < 8);
|
|
||||||
uint8_t lo = Wire.read();
|
|
||||||
uint8_t hi = Wire.read();
|
|
||||||
//throw out first two - don't seem accurate
|
|
||||||
//gyroTemp = (lo << 8) | hi; // temperature
|
|
||||||
//gyroTemp = ((double) (gyroTemp + 13200)) / 280;
|
|
||||||
lo = Wire.read();
|
|
||||||
hi = Wire.read();
|
|
||||||
gyroHX = (((lo << 8) | hi) + 120 )/ 14.375;
|
|
||||||
lo = Wire.read();
|
|
||||||
hi = Wire.read();
|
|
||||||
gyroHY = (((lo << 8) | hi) + 20 )/ 14.375;
|
|
||||||
lo = Wire.read();
|
|
||||||
hi = Wire.read();
|
|
||||||
gyroHZ = (((lo << 8) | hi) + 93 )/ 14.375;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void initMagnetometer(){
|
|
||||||
writeRegister(HMC5883, 0x02, 0x00); //enable
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void readMagnetometer(){
|
|
||||||
Wire.beginTransmission(HMC5883);
|
|
||||||
Wire.write(0x03); //format X_H_M
|
|
||||||
Wire.endTransmission();
|
|
||||||
Wire.requestFrom(HMC5883, (byte)6);
|
|
||||||
|
|
||||||
// Wait around until enough data is available
|
|
||||||
while (Wire.available() < 6);
|
|
||||||
|
|
||||||
// Note high before low (different than accel)
|
|
||||||
uint8_t hi = Wire.read();
|
|
||||||
uint8_t lo = Wire.read();
|
|
||||||
// Shift values to create properly formed integer (low byte first)
|
|
||||||
magX = (int16_t)(hi | ((int16_t)lo << 8));
|
|
||||||
// Note high before low (different than accel)
|
|
||||||
hi = Wire.read();
|
|
||||||
lo = Wire.read();
|
|
||||||
// Shift values to create properly formed integer (low byte first)
|
|
||||||
magY = (int16_t)(hi | ((int16_t)lo << 8));
|
|
||||||
// Note high before low (different than accel)
|
|
||||||
hi = Wire.read();
|
|
||||||
lo = Wire.read();
|
|
||||||
// Shift values to create properly formed integer (low byte first)
|
|
||||||
magZ = (int16_t)(hi | ((int16_t)lo << 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
void initAccelerometer(){
|
|
||||||
//if(readRegister(ADXL345,0x00) != 0xE5)
|
|
||||||
writeRegister(ADXL345, 0x2D, 0x08); //power up and enable measurements
|
|
||||||
writeRegister(ADXL345, 0x31, 0x01);//set range to +/-4G
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t readAccelerometer(uint8_t reg){
|
|
||||||
Wire.beginTransmission(ADXL345);
|
|
||||||
Wire.write(reg);
|
|
||||||
Wire.endTransmission();
|
|
||||||
Wire.requestFrom(ADXL345, 2);
|
|
||||||
return (uint16_t)(Wire.read() | (Wire.read() << 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t readRegister(uint8_t address, uint8_t reg){
|
|
||||||
Wire.beginTransmission(address);
|
|
||||||
Wire.write(reg);
|
|
||||||
Wire.endTransmission();
|
|
||||||
Wire.requestFrom(address, 1);
|
|
||||||
return Wire.read();
|
|
||||||
}
|
|
||||||
void writeRegister(uint8_t address, uint8_t reg, uint8_t val){
|
|
||||||
Wire.beginTransmission(address);
|
|
||||||
Wire.write(reg);
|
|
||||||
Wire.write(val);
|
|
||||||
Wire.endTransmission();
|
|
||||||
}
|
|
||||||
|
|
||||||
float getHeading(){
|
|
||||||
// Hold the module so that Z is pointing 'up' and you can measure the heading with x&y
|
|
||||||
// Calculate heading when the magnetometer is level, then correct for signs of axis.
|
|
||||||
float heading = atan2(magY, magX);
|
|
||||||
// Correct for when signs are reversed.
|
|
||||||
if(heading < 0)
|
|
||||||
heading += 2*PI;
|
|
||||||
// Check for wrap due to addition of declination.
|
|
||||||
if(heading > 2*PI)
|
|
||||||
heading -= 2*PI;
|
|
||||||
// Convert radians to degrees for readability.
|
|
||||||
heading = heading * 180/M_PI;
|
|
||||||
return heading;
|
|
||||||
}
|
|
@ -1,146 +0,0 @@
|
|||||||
/*
|
|
||||||
EEPROM.h - EEPROM library
|
|
||||||
Original Copyright (c) 2006 David A. Mellis. All right reserved.
|
|
||||||
New version by Christopher Andrews 2015.
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef EEPROM_h
|
|
||||||
#define EEPROM_h
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <avr/eeprom.h>
|
|
||||||
#include <avr/io.h>
|
|
||||||
|
|
||||||
/***
|
|
||||||
EERef class.
|
|
||||||
|
|
||||||
This object references an EEPROM cell.
|
|
||||||
Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM.
|
|
||||||
This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell.
|
|
||||||
***/
|
|
||||||
|
|
||||||
struct EERef{
|
|
||||||
|
|
||||||
EERef( const int index )
|
|
||||||
: index( index ) {}
|
|
||||||
|
|
||||||
//Access/read members.
|
|
||||||
uint8_t operator*() const { return eeprom_read_byte( (uint8_t*) index ); }
|
|
||||||
operator const uint8_t() const { return **this; }
|
|
||||||
|
|
||||||
//Assignment/write members.
|
|
||||||
EERef &operator=( const EERef &ref ) { return *this = *ref; }
|
|
||||||
EERef &operator=( uint8_t in ) { return eeprom_write_byte( (uint8_t*) index, in ), *this; }
|
|
||||||
EERef &operator +=( uint8_t in ) { return *this = **this + in; }
|
|
||||||
EERef &operator -=( uint8_t in ) { return *this = **this - in; }
|
|
||||||
EERef &operator *=( uint8_t in ) { return *this = **this * in; }
|
|
||||||
EERef &operator /=( uint8_t in ) { return *this = **this / in; }
|
|
||||||
EERef &operator ^=( uint8_t in ) { return *this = **this ^ in; }
|
|
||||||
EERef &operator %=( uint8_t in ) { return *this = **this % in; }
|
|
||||||
EERef &operator &=( uint8_t in ) { return *this = **this & in; }
|
|
||||||
EERef &operator |=( uint8_t in ) { return *this = **this | in; }
|
|
||||||
EERef &operator <<=( uint8_t in ) { return *this = **this << in; }
|
|
||||||
EERef &operator >>=( uint8_t in ) { return *this = **this >> in; }
|
|
||||||
|
|
||||||
EERef &update( uint8_t in ) { return in != *this ? *this = in : *this; }
|
|
||||||
|
|
||||||
/** Prefix increment/decrement **/
|
|
||||||
EERef& operator++() { return *this += 1; }
|
|
||||||
EERef& operator--() { return *this -= 1; }
|
|
||||||
|
|
||||||
/** Postfix increment/decrement **/
|
|
||||||
uint8_t operator++ (int){
|
|
||||||
uint8_t ret = **this;
|
|
||||||
return ++(*this), ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t operator-- (int){
|
|
||||||
uint8_t ret = **this;
|
|
||||||
return --(*this), ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int index; //Index of current EEPROM cell.
|
|
||||||
};
|
|
||||||
|
|
||||||
/***
|
|
||||||
EEPtr class.
|
|
||||||
|
|
||||||
This object is a bidirectional pointer to EEPROM cells represented by EERef objects.
|
|
||||||
Just like a normal pointer type, this can be dereferenced and repositioned using
|
|
||||||
increment/decrement operators.
|
|
||||||
***/
|
|
||||||
|
|
||||||
struct EEPtr{
|
|
||||||
|
|
||||||
EEPtr( const int index )
|
|
||||||
: index( index ) {}
|
|
||||||
|
|
||||||
operator const int() const { return index; }
|
|
||||||
EEPtr &operator=( int in ) { return index = in, *this; }
|
|
||||||
|
|
||||||
//Iterator functionality.
|
|
||||||
bool operator!=( const EEPtr &ptr ) { return index != ptr.index; }
|
|
||||||
EERef operator*() { return index; }
|
|
||||||
|
|
||||||
/** Prefix & Postfix increment/decrement **/
|
|
||||||
EEPtr& operator++() { return ++index, *this; }
|
|
||||||
EEPtr& operator--() { return --index, *this; }
|
|
||||||
EEPtr operator++ (int) { return index++; }
|
|
||||||
EEPtr operator-- (int) { return index--; }
|
|
||||||
|
|
||||||
int index; //Index of current EEPROM cell.
|
|
||||||
};
|
|
||||||
|
|
||||||
/***
|
|
||||||
EEPROMClass class.
|
|
||||||
|
|
||||||
This object represents the entire EEPROM space.
|
|
||||||
It wraps the functionality of EEPtr and EERef into a basic interface.
|
|
||||||
This class is also 100% backwards compatible with earlier Arduino core releases.
|
|
||||||
***/
|
|
||||||
|
|
||||||
struct EEPROMClass{
|
|
||||||
|
|
||||||
//Basic user access methods.
|
|
||||||
EERef operator[]( const int idx ) { return idx; }
|
|
||||||
uint8_t read( int idx ) { return EERef( idx ); }
|
|
||||||
void write( int idx, uint8_t val ) { (EERef( idx )) = val; }
|
|
||||||
void update( int idx, uint8_t val ) { EERef( idx ).update( val ); }
|
|
||||||
|
|
||||||
//STL and C++11 iteration capability.
|
|
||||||
EEPtr begin() { return 0x00; }
|
|
||||||
EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid.
|
|
||||||
uint16_t length() { return E2END + 1; }
|
|
||||||
|
|
||||||
//Functionality to 'get' and 'put' objects to and from EEPROM.
|
|
||||||
template< typename T > T &get( int idx, T &t ){
|
|
||||||
EEPtr e = idx;
|
|
||||||
uint8_t *ptr = (uint8_t*) &t;
|
|
||||||
for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e;
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T > const T &put( int idx, const T &t ){
|
|
||||||
EEPtr e = idx;
|
|
||||||
const uint8_t *ptr = (const uint8_t*) &t;
|
|
||||||
for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ );
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static EEPROMClass EEPROM;
|
|
||||||
#endif
|
|
@ -1,139 +0,0 @@
|
|||||||
## **EEPROM Library V2.0** for Arduino
|
|
||||||
|
|
||||||
**Written by:** _Christopher Andrews_.
|
|
||||||
|
|
||||||
### **What is the EEPROM library.**
|
|
||||||
|
|
||||||
Th EEPROM library provides an easy to use interface to interact with the internal non-volatile storage found in AVR based Arduino boards. This library will work on many AVR devices like ATtiny and ATmega chips.
|
|
||||||
|
|
||||||
### **How to use it**
|
|
||||||
The EEPROM library is included in your IDE download. To add its functionality to your sketch you'll need to reference the library header file. You do this by adding an include directive to the top of your sketch.
|
|
||||||
|
|
||||||
```Arduino
|
|
||||||
#include <EEPROM.h>
|
|
||||||
|
|
||||||
void setup(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
The library provides a global variable named `EEPROM`, you use this variable to access the library functions. The methods provided in the EEPROM class are listed below.
|
|
||||||
|
|
||||||
You can view all the examples [here](examples/).
|
|
||||||
|
|
||||||
### **Library functions**
|
|
||||||
|
|
||||||
#### **`EEPROM.read( address )`** [[_example_]](examples/eeprom_read/eeprom_read.ino)
|
|
||||||
|
|
||||||
This function allows you to read a single byte of data from the eeprom.
|
|
||||||
Its only parameter is an `int` which should be set to the address you wish to read.
|
|
||||||
|
|
||||||
The function returns an `unsigned char` containing the value read.
|
|
||||||
|
|
||||||
#### **`EEPROM.write( address, value )`** [[_example_]](examples/eeprom_write/eeprom_write.ino)
|
|
||||||
|
|
||||||
The `write()` method allows you to write a single byte of data to the EEPROM.
|
|
||||||
Two parameters are needed. The first is an `int` containing the address that is to be written, and the second is a the data to be written (`unsigned char`).
|
|
||||||
|
|
||||||
This function does not return any value.
|
|
||||||
|
|
||||||
#### **`EEPROM.update( address, value )`** [[_example_]](examples/eeprom_update/eeprom_update.ino)
|
|
||||||
|
|
||||||
This function is similar to `EEPROM.write()` however this method will only write data if the cell contents pointed to by `address` is different to `value`. This method can help prevent unnecessary wear on the EEPROM cells.
|
|
||||||
|
|
||||||
This function does not return any value.
|
|
||||||
|
|
||||||
#### **`EEPROM.get( address, object )`** [[_example_]](examples/eeprom_get/eeprom_get.ino)
|
|
||||||
|
|
||||||
This function will retrieve any object from the EEPROM.
|
|
||||||
Two parameters are needed to call this function. The first is an `int` containing the address that is to be written, and the second is the object you would like to read.
|
|
||||||
|
|
||||||
This function returns a reference to the `object` passed in. It does not need to be used and is only returned for conveience.
|
|
||||||
|
|
||||||
#### **`EEPROM.put( address, object )`** [[_example_]](examples/eeprom_put/eeprom_put.ino)
|
|
||||||
|
|
||||||
This function will write any object to the EEPROM.
|
|
||||||
Two parameters are needed to call this function. The first is an `int` containing the address that is to be written, and the second is the object you would like to write.
|
|
||||||
|
|
||||||
This function uses the _update_ method to write its data, and therefore only rewrites changed cells.
|
|
||||||
|
|
||||||
This function returns a reference to the `object` passed in. It does not need to be used and is only returned for conveience.
|
|
||||||
|
|
||||||
#### **Subscript operator: `EEPROM[address]`** [[_example_]](examples/eeprom_crc/eeprom_crc.ino)
|
|
||||||
|
|
||||||
This operator allows using the identifier `EEPROM` like an array.
|
|
||||||
EEPROM cells can be read _and_ **_written_** directly using this method.
|
|
||||||
|
|
||||||
This operator returns a reference to the EEPROM cell.
|
|
||||||
|
|
||||||
```c++
|
|
||||||
unsigned char val;
|
|
||||||
|
|
||||||
//Read first EEPROM cell.
|
|
||||||
val = EEPROM[ 0 ];
|
|
||||||
|
|
||||||
//Write first EEPROM cell.
|
|
||||||
EEPROM[ 0 ] = val;
|
|
||||||
|
|
||||||
//Compare contents
|
|
||||||
if( val == EEPROM[ 0 ] ){
|
|
||||||
//Do something...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### **`EEPROM.length()`**
|
|
||||||
|
|
||||||
This function returns an `unsigned int` containing the number of cells in the EEPROM.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Advanced features**
|
|
||||||
|
|
||||||
This library uses a component based approach to provide its functionality. This means you can also use these components to design a customized approach. Two background classes are available for use: `EERef` & `EEPtr`.
|
|
||||||
|
|
||||||
#### **`EERef` class**
|
|
||||||
|
|
||||||
This object references an EEPROM cell.
|
|
||||||
Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM.
|
|
||||||
This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell.
|
|
||||||
|
|
||||||
```C++
|
|
||||||
EERef ref = EEPROM[ 10 ]; //Create a reference to 11th cell.
|
|
||||||
|
|
||||||
ref = 4; //write to EEPROM cell.
|
|
||||||
|
|
||||||
unsigned char val = ref; //Read referenced cell.
|
|
||||||
```
|
|
||||||
|
|
||||||
#### **`EEPtr` class**
|
|
||||||
|
|
||||||
This object is a bidirectional pointer to EEPROM cells represented by `EERef` objects.
|
|
||||||
Just like a normal pointer type, this type can be dereferenced and repositioned using
|
|
||||||
increment/decrement operators.
|
|
||||||
|
|
||||||
```C++
|
|
||||||
EEPtr ptr = 10; //Create a pointer to 11th cell.
|
|
||||||
|
|
||||||
*ptr = 4; //dereference and write to EEPROM cell.
|
|
||||||
|
|
||||||
unsigned char val = *ptr; //dereference and read.
|
|
||||||
|
|
||||||
ptr++; //Move to next EEPROM cell.
|
|
||||||
```
|
|
||||||
|
|
||||||
#### **`EEPROM.begin()`**
|
|
||||||
|
|
||||||
This function returns an `EEPtr` pointing to the first cell in the EEPROM.
|
|
||||||
This is useful for STL objects, custom iteration and C++11 style ranged for loops.
|
|
||||||
|
|
||||||
#### **`EEPROM.end()`**
|
|
||||||
|
|
||||||
This function returns an `EEPtr` pointing at the location after the last EEPROM cell.
|
|
||||||
Used with `begin()` to provide custom iteration.
|
|
||||||
|
|
||||||
**Note:** The `EEPtr` returned is invalid as it is out of range. Infact the hardware causes wrapping of the address (overflow) and `EEPROM.end()` actually references the first EEPROM cell.
|
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* EEPROM Clear
|
|
||||||
*
|
|
||||||
* Sets all of the bytes of the EEPROM to 0.
|
|
||||||
* Please see eeprom_iteration for a more in depth
|
|
||||||
* look at how to traverse the EEPROM.
|
|
||||||
*
|
|
||||||
* This example code is in the public domain.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <EEPROM.h>
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
|
|
||||||
/***
|
|
||||||
Iterate through each byte of the EEPROM storage.
|
|
||||||
|
|
||||||
Larger AVR processors have larger EEPROM sizes, E.g:
|
|
||||||
- Arduno Duemilanove: 512b EEPROM storage.
|
|
||||||
- Arduino Uno: 1kb EEPROM storage.
|
|
||||||
- Arduino Mega: 4kb EEPROM storage.
|
|
||||||
|
|
||||||
Rather than hard-coding the length, you should use the pre-provided length function.
|
|
||||||
This will make your code portable to all AVR processors.
|
|
||||||
***/
|
|
||||||
|
|
||||||
for ( int i = 0 ; i < EEPROM.length() ; i++ )
|
|
||||||
EEPROM.write(i, 0);
|
|
||||||
|
|
||||||
// turn the LED on when we're done
|
|
||||||
digitalWrite(13, HIGH);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop(){ /** Empty loop. **/ }
|
|
@ -1,50 +0,0 @@
|
|||||||
/***
|
|
||||||
Written by Christopher Andrews.
|
|
||||||
CRC algorithm generated by pycrc, MIT licence ( https://github.com/tpircher/pycrc ).
|
|
||||||
|
|
||||||
A CRC is a simple way of checking whether data has changed or become corrupted.
|
|
||||||
This example calculates a CRC value directly on the EEPROM values.
|
|
||||||
The purpose of this example is to highlight how the EEPROM object can be used just like an array.
|
|
||||||
***/
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <EEPROM.h>
|
|
||||||
|
|
||||||
void setup(){
|
|
||||||
|
|
||||||
//Start serial
|
|
||||||
Serial.begin(9600);
|
|
||||||
while (!Serial) {
|
|
||||||
; // wait for serial port to connect. Needed for Leonardo only
|
|
||||||
}
|
|
||||||
|
|
||||||
//Print length of data to run CRC on.
|
|
||||||
Serial.print( "EEPROM length: " );
|
|
||||||
Serial.println( EEPROM.length() );
|
|
||||||
|
|
||||||
//Print the result of calling eeprom_crc()
|
|
||||||
Serial.print( "CRC32 of EEPROM data: 0x" );
|
|
||||||
Serial.println( eeprom_crc(), HEX );
|
|
||||||
Serial.print( "\n\nDone!" );
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop(){ /* Empty loop */ }
|
|
||||||
|
|
||||||
unsigned long eeprom_crc( void ){
|
|
||||||
|
|
||||||
const unsigned long crc_table[16] = {
|
|
||||||
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
|
|
||||||
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
|
|
||||||
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
|
|
||||||
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned long crc = ~0L;
|
|
||||||
|
|
||||||
for( int index = 0 ; index < EEPROM.length() ; ++index ){
|
|
||||||
crc = crc_table[( crc ^ EEPROM[index] ) & 0x0f] ^ (crc >> 4);
|
|
||||||
crc = crc_table[( crc ^ ( EEPROM[index] >> 4 )) & 0x0f] ^ (crc >> 4);
|
|
||||||
crc = ~crc;
|
|
||||||
}
|
|
||||||
return crc;
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
/***
|
|
||||||
eeprom_get example.
|
|
||||||
|
|
||||||
This shows how to use the EEPROM.get() method.
|
|
||||||
|
|
||||||
To pre-set the EEPROM data, run the example sketch eeprom_put.
|
|
||||||
This sketch will run without it, however, the values shown
|
|
||||||
will be shown from what ever is already on the EEPROM.
|
|
||||||
|
|
||||||
This may cause the serial object to print out a large string
|
|
||||||
of garbage if there is no null character inside one of the strings
|
|
||||||
loaded.
|
|
||||||
|
|
||||||
Written by Christopher Andrews 2015
|
|
||||||
Released under MIT licence.
|
|
||||||
***/
|
|
||||||
|
|
||||||
#include <EEPROM.h>
|
|
||||||
|
|
||||||
void setup(){
|
|
||||||
|
|
||||||
float f = 0.00f; //Variable to store data read from EEPROM.
|
|
||||||
int eeAddress = 0; //EEPROM address to start reading from
|
|
||||||
|
|
||||||
Serial.begin( 9600 );
|
|
||||||
while (!Serial) {
|
|
||||||
; // wait for serial port to connect. Needed for Leonardo only
|
|
||||||
}
|
|
||||||
Serial.print( "Read float from EEPROM: " );
|
|
||||||
|
|
||||||
//Get the float data from the EEPROM at position 'eeAddress'
|
|
||||||
EEPROM.get( eeAddress, f );
|
|
||||||
Serial.println( f, 3 ); //This may print 'ovf, nan' if the data inside the EEPROM is not a valid float.
|
|
||||||
|
|
||||||
/***
|
|
||||||
As get also returns a reference to 'f', you can use it inline.
|
|
||||||
E.g: Serial.print( EEPROM.get( eeAddress, f ) );
|
|
||||||
***/
|
|
||||||
|
|
||||||
/***
|
|
||||||
Get can be used with custom structures too.
|
|
||||||
I have separated this into an extra function.
|
|
||||||
***/
|
|
||||||
|
|
||||||
secondTest(); //Run the next test.
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MyObject{
|
|
||||||
float field1;
|
|
||||||
byte field2;
|
|
||||||
char name[10];
|
|
||||||
};
|
|
||||||
|
|
||||||
void secondTest(){
|
|
||||||
int eeAddress = sizeof(float); //Move address to the next byte after float 'f'.
|
|
||||||
|
|
||||||
MyObject customVar; //Variable to store custom object read from EEPROM.
|
|
||||||
EEPROM.get( eeAddress, customVar );
|
|
||||||
|
|
||||||
Serial.println( "Read custom object from EEPROM: " );
|
|
||||||
Serial.println( customVar.field1 );
|
|
||||||
Serial.println( customVar.field2 );
|
|
||||||
Serial.println( customVar.name );
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop(){ /* Empty loop */ }
|
|
@ -1,57 +0,0 @@
|
|||||||
/***
|
|
||||||
eeprom_iteration example.
|
|
||||||
|
|
||||||
A set of example snippets highlighting the
|
|
||||||
simplest methods for traversing the EEPROM.
|
|
||||||
|
|
||||||
Running this sketch is not necessary, this is
|
|
||||||
simply highlighting certain programming methods.
|
|
||||||
|
|
||||||
Written by Christopher Andrews 2015
|
|
||||||
Released under MIT licence.
|
|
||||||
***/
|
|
||||||
|
|
||||||
#include <EEPROM.h>
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
|
|
||||||
/***
|
|
||||||
Iterate the EEPROM using a for loop.
|
|
||||||
***/
|
|
||||||
|
|
||||||
for( int index = 0 ; index < EEPROM.length() ; index++ ){
|
|
||||||
|
|
||||||
//Add one to each cell in the EEPROM
|
|
||||||
EEPROM[ index ] += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
Iterate the EEPROM using a while loop.
|
|
||||||
***/
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
while( index < EEPROM.length() ){
|
|
||||||
|
|
||||||
//Add one to each cell in the EEPROM
|
|
||||||
EEPROM[ index ] += 1;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
Iterate the EEPROM using a do-while loop.
|
|
||||||
***/
|
|
||||||
|
|
||||||
int idx = 0; //Used 'idx' to avoid name conflict with 'index' above.
|
|
||||||
|
|
||||||
do{
|
|
||||||
|
|
||||||
//Add one to each cell in the EEPROM
|
|
||||||
EEPROM[ idx ] += 1;
|
|
||||||
idx++;
|
|
||||||
}while( idx < EEPROM.length() );
|
|
||||||
|
|
||||||
|
|
||||||
} //End of setup function.
|
|
||||||
|
|
||||||
void loop(){}
|
|
@ -1,56 +0,0 @@
|
|||||||
/***
|
|
||||||
eeprom_put example.
|
|
||||||
|
|
||||||
This shows how to use the EEPROM.put() method.
|
|
||||||
Also, this sketch will pre-set the EEPROM data for the
|
|
||||||
example sketch eeprom_get.
|
|
||||||
|
|
||||||
Note, unlike the single byte version EEPROM.write(),
|
|
||||||
the put method will use update semantics. As in a byte
|
|
||||||
will only be written to the EEPROM if the data is actually
|
|
||||||
different.
|
|
||||||
|
|
||||||
Written by Christopher Andrews 2015
|
|
||||||
Released under MIT licence.
|
|
||||||
***/
|
|
||||||
|
|
||||||
#include <EEPROM.h>
|
|
||||||
|
|
||||||
struct MyObject{
|
|
||||||
float field1;
|
|
||||||
byte field2;
|
|
||||||
char name[10];
|
|
||||||
};
|
|
||||||
|
|
||||||
void setup(){
|
|
||||||
|
|
||||||
Serial.begin(9600);
|
|
||||||
while (!Serial) {
|
|
||||||
; // wait for serial port to connect. Needed for Leonardo only
|
|
||||||
}
|
|
||||||
|
|
||||||
float f = 123.456f; //Variable to store in EEPROM.
|
|
||||||
int eeAddress = 0; //Location we want the data to be put.
|
|
||||||
|
|
||||||
|
|
||||||
//One simple call, with the address first and the object second.
|
|
||||||
EEPROM.put( eeAddress, f );
|
|
||||||
|
|
||||||
Serial.println("Written float data type!");
|
|
||||||
|
|
||||||
/** Put is designed for use with custom structures also. **/
|
|
||||||
|
|
||||||
//Data to store.
|
|
||||||
MyObject customVar = {
|
|
||||||
3.14f,
|
|
||||||
65,
|
|
||||||
"Working!"
|
|
||||||
};
|
|
||||||
|
|
||||||
eeAddress += sizeof(float); //Move address to the next byte after float 'f'.
|
|
||||||
|
|
||||||
EEPROM.put( eeAddress, customVar );
|
|
||||||
Serial.print( "Written custom data type! \n\nView the example sketch eeprom_get to see how you can retrieve the values!" );
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop(){ /* Empty loop */ }
|
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* EEPROM Read
|
|
||||||
*
|
|
||||||
* Reads the value of each byte of the EEPROM and prints it
|
|
||||||
* to the computer.
|
|
||||||
* This example code is in the public domain.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <EEPROM.h>
|
|
||||||
|
|
||||||
// start reading from the first byte (address 0) of the EEPROM
|
|
||||||
int address = 0;
|
|
||||||
byte value;
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
// initialize serial and wait for port to open:
|
|
||||||
Serial.begin(9600);
|
|
||||||
while (!Serial) {
|
|
||||||
; // wait for serial port to connect. Needed for Leonardo only
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
// read a byte from the current address of the EEPROM
|
|
||||||
value = EEPROM.read(address);
|
|
||||||
|
|
||||||
Serial.print(address);
|
|
||||||
Serial.print("\t");
|
|
||||||
Serial.print(value, DEC);
|
|
||||||
Serial.println();
|
|
||||||
|
|
||||||
/***
|
|
||||||
Advance to the next address, when at the end restart at the beginning.
|
|
||||||
|
|
||||||
Larger AVR processors have larger EEPROM sizes, E.g:
|
|
||||||
- Arduno Duemilanove: 512b EEPROM storage.
|
|
||||||
- Arduino Uno: 1kb EEPROM storage.
|
|
||||||
- Arduino Mega: 4kb EEPROM storage.
|
|
||||||
|
|
||||||
Rather than hard-coding the length, you should use the pre-provided length function.
|
|
||||||
This will make your code portable to all AVR processors.
|
|
||||||
***/
|
|
||||||
address = address + 1;
|
|
||||||
if(address == EEPROM.length())
|
|
||||||
address = 0;
|
|
||||||
|
|
||||||
/***
|
|
||||||
As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an
|
|
||||||
EEPROM address is also doable by a bitwise and of the length - 1.
|
|
||||||
|
|
||||||
++address &= EEPROM.length() - 1;
|
|
||||||
***/
|
|
||||||
|
|
||||||
delay(500);
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
/***
|
|
||||||
EEPROM Update method
|
|
||||||
|
|
||||||
Stores values read from analog input 0 into the EEPROM.
|
|
||||||
These values will stay in the EEPROM when the board is
|
|
||||||
turned off and may be retrieved later by another sketch.
|
|
||||||
|
|
||||||
If a value has not changed in the EEPROM, it is not overwritten
|
|
||||||
which would reduce the life span of the EEPROM unnecessarily.
|
|
||||||
|
|
||||||
Released using MIT licence.
|
|
||||||
***/
|
|
||||||
|
|
||||||
#include <EEPROM.h>
|
|
||||||
|
|
||||||
/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/
|
|
||||||
int address = 0;
|
|
||||||
|
|
||||||
void setup(){ /** EMpty setup **/ }
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
/***
|
|
||||||
need to divide by 4 because analog inputs range from
|
|
||||||
0 to 1023 and each byte of the EEPROM can only hold a
|
|
||||||
value from 0 to 255.
|
|
||||||
***/
|
|
||||||
int val = analogRead(0) / 4;
|
|
||||||
|
|
||||||
/***
|
|
||||||
Update the particular EEPROM cell.
|
|
||||||
these values will remain there when the board is
|
|
||||||
turned off.
|
|
||||||
***/
|
|
||||||
EEPROM.update(address, val);
|
|
||||||
|
|
||||||
/***
|
|
||||||
The function EEPROM.update(address, val) is equivalent to the following:
|
|
||||||
|
|
||||||
if( EEPROM.read(address) != val ){
|
|
||||||
EEPROM.write(address, val);
|
|
||||||
}
|
|
||||||
***/
|
|
||||||
|
|
||||||
|
|
||||||
/***
|
|
||||||
Advance to the next address, when at the end restart at the beginning.
|
|
||||||
|
|
||||||
Larger AVR processors have larger EEPROM sizes, E.g:
|
|
||||||
- Arduno Duemilanove: 512b EEPROM storage.
|
|
||||||
- Arduino Uno: 1kb EEPROM storage.
|
|
||||||
- Arduino Mega: 4kb EEPROM storage.
|
|
||||||
|
|
||||||
Rather than hard-coding the length, you should use the pre-provided length function.
|
|
||||||
This will make your code portable to all AVR processors.
|
|
||||||
***/
|
|
||||||
address = address + 1;
|
|
||||||
if(address == EEPROM.length())
|
|
||||||
address = 0;
|
|
||||||
|
|
||||||
/***
|
|
||||||
As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an
|
|
||||||
EEPROM address is also doable by a bitwise and of the length - 1.
|
|
||||||
|
|
||||||
++address &= EEPROM.length() - 1;
|
|
||||||
***/
|
|
||||||
|
|
||||||
delay(100);
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* EEPROM Write
|
|
||||||
*
|
|
||||||
* Stores values read from analog input 0 into the EEPROM.
|
|
||||||
* These values will stay in the EEPROM when the board is
|
|
||||||
* turned off and may be retrieved later by another sketch.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <EEPROM.h>
|
|
||||||
|
|
||||||
/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/
|
|
||||||
int addr = 0;
|
|
||||||
|
|
||||||
void setup(){ /** Empty setup. **/}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
/***
|
|
||||||
Need to divide by 4 because analog inputs range from
|
|
||||||
0 to 1023 and each byte of the EEPROM can only hold a
|
|
||||||
value from 0 to 255.
|
|
||||||
***/
|
|
||||||
|
|
||||||
int val = analogRead(0) / 4;
|
|
||||||
|
|
||||||
/***
|
|
||||||
Write the value to the appropriate byte of the EEPROM.
|
|
||||||
these values will remain there when the board is
|
|
||||||
turned off.
|
|
||||||
***/
|
|
||||||
|
|
||||||
EEPROM.write(addr, val);
|
|
||||||
|
|
||||||
/***
|
|
||||||
Advance to the next address, when at the end restart at the beginning.
|
|
||||||
|
|
||||||
Larger AVR processors have larger EEPROM sizes, E.g:
|
|
||||||
- Arduno Duemilanove: 512b EEPROM storage.
|
|
||||||
- Arduino Uno: 1kb EEPROM storage.
|
|
||||||
- Arduino Mega: 4kb EEPROM storage.
|
|
||||||
|
|
||||||
Rather than hard-coding the length, you should use the pre-provided length function.
|
|
||||||
This will make your code portable to all AVR processors.
|
|
||||||
***/
|
|
||||||
addr = addr + 1;
|
|
||||||
if(addr == EEPROM.length())
|
|
||||||
addr = 0;
|
|
||||||
|
|
||||||
/***
|
|
||||||
As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an
|
|
||||||
EEPROM address is also doable by a bitwise and of the length - 1.
|
|
||||||
|
|
||||||
++addr &= EEPROM.length() - 1;
|
|
||||||
***/
|
|
||||||
|
|
||||||
|
|
||||||
delay(100);
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
name=EEPROM
|
|
||||||
version=2.0
|
|
||||||
author=Arduino, Christopher Andrews
|
|
||||||
maintainer=Arduino <info@arduino.cc>
|
|
||||||
sentence=Enables reading and writing to the permanent board storage. For all Arduino boards BUT Arduino DUE.
|
|
||||||
paragraph=
|
|
||||||
url=http://www.arduino.cc/en/Reference/EEPROM
|
|
||||||
architectures=avr
|
|
||||||
|
|
@ -1,201 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
|
|
||||||
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
|
|
||||||
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
|
|
||||||
* Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
|
|
||||||
* SPI Master library for arduino.
|
|
||||||
*
|
|
||||||
* This file is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of either the GNU General Public License version 2
|
|
||||||
* or the GNU Lesser General Public License version 2.1, both as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "SPI.h"
|
|
||||||
|
|
||||||
SPIClass SPI;
|
|
||||||
|
|
||||||
uint8_t SPIClass::initialized = 0;
|
|
||||||
uint8_t SPIClass::interruptMode = 0;
|
|
||||||
uint8_t SPIClass::interruptMask = 0;
|
|
||||||
uint8_t SPIClass::interruptSave = 0;
|
|
||||||
#ifdef SPI_TRANSACTION_MISMATCH_LED
|
|
||||||
uint8_t SPIClass::inTransactionFlag = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void SPIClass::begin()
|
|
||||||
{
|
|
||||||
uint8_t sreg = SREG;
|
|
||||||
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
|
|
||||||
if (!initialized) {
|
|
||||||
// Set SS to high so a connected chip will be "deselected" by default
|
|
||||||
uint8_t port = digitalPinToPort(SS);
|
|
||||||
uint8_t bit = digitalPinToBitMask(SS);
|
|
||||||
volatile uint8_t *reg = portModeRegister(port);
|
|
||||||
|
|
||||||
// if the SS pin is not already configured as an output
|
|
||||||
// then set it high (to enable the internal pull-up resistor)
|
|
||||||
if(!(*reg & bit)){
|
|
||||||
digitalWrite(SS, HIGH);
|
|
||||||
}
|
|
||||||
|
|
||||||
// When the SS pin is set as OUTPUT, it can be used as
|
|
||||||
// a general purpose output port (it doesn't influence
|
|
||||||
// SPI operations).
|
|
||||||
pinMode(SS, OUTPUT);
|
|
||||||
|
|
||||||
// Warning: if the SS pin ever becomes a LOW INPUT then SPI
|
|
||||||
// automatically switches to Slave, so the data direction of
|
|
||||||
// the SS pin MUST be kept as OUTPUT.
|
|
||||||
SPCR |= _BV(MSTR);
|
|
||||||
SPCR |= _BV(SPE);
|
|
||||||
|
|
||||||
// Set direction register for SCK and MOSI pin.
|
|
||||||
// MISO pin automatically overrides to INPUT.
|
|
||||||
// By doing this AFTER enabling SPI, we avoid accidentally
|
|
||||||
// clocking in a single bit since the lines go directly
|
|
||||||
// from "input" to SPI control.
|
|
||||||
// http://code.google.com/p/arduino/issues/detail?id=888
|
|
||||||
pinMode(SCK, OUTPUT);
|
|
||||||
pinMode(MOSI, OUTPUT);
|
|
||||||
}
|
|
||||||
initialized++; // reference count
|
|
||||||
SREG = sreg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SPIClass::end() {
|
|
||||||
uint8_t sreg = SREG;
|
|
||||||
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
|
|
||||||
// Decrease the reference counter
|
|
||||||
if (initialized)
|
|
||||||
initialized--;
|
|
||||||
// If there are no more references disable SPI
|
|
||||||
if (!initialized) {
|
|
||||||
SPCR &= ~_BV(SPE);
|
|
||||||
interruptMode = 0;
|
|
||||||
#ifdef SPI_TRANSACTION_MISMATCH_LED
|
|
||||||
inTransactionFlag = 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
SREG = sreg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// mapping of interrupt numbers to bits within SPI_AVR_EIMSK
|
|
||||||
#if defined(__AVR_ATmega32U4__)
|
|
||||||
#define SPI_INT0_MASK (1<<INT0)
|
|
||||||
#define SPI_INT1_MASK (1<<INT1)
|
|
||||||
#define SPI_INT2_MASK (1<<INT2)
|
|
||||||
#define SPI_INT3_MASK (1<<INT3)
|
|
||||||
#define SPI_INT4_MASK (1<<INT6)
|
|
||||||
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
|
||||||
#define SPI_INT0_MASK (1<<INT0)
|
|
||||||
#define SPI_INT1_MASK (1<<INT1)
|
|
||||||
#define SPI_INT2_MASK (1<<INT2)
|
|
||||||
#define SPI_INT3_MASK (1<<INT3)
|
|
||||||
#define SPI_INT4_MASK (1<<INT4)
|
|
||||||
#define SPI_INT5_MASK (1<<INT5)
|
|
||||||
#define SPI_INT6_MASK (1<<INT6)
|
|
||||||
#define SPI_INT7_MASK (1<<INT7)
|
|
||||||
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
|
|
||||||
#define SPI_INT0_MASK (1<<INT4)
|
|
||||||
#define SPI_INT1_MASK (1<<INT5)
|
|
||||||
#define SPI_INT2_MASK (1<<INT0)
|
|
||||||
#define SPI_INT3_MASK (1<<INT1)
|
|
||||||
#define SPI_INT4_MASK (1<<INT2)
|
|
||||||
#define SPI_INT5_MASK (1<<INT3)
|
|
||||||
#define SPI_INT6_MASK (1<<INT6)
|
|
||||||
#define SPI_INT7_MASK (1<<INT7)
|
|
||||||
#else
|
|
||||||
#ifdef INT0
|
|
||||||
#define SPI_INT0_MASK (1<<INT0)
|
|
||||||
#endif
|
|
||||||
#ifdef INT1
|
|
||||||
#define SPI_INT1_MASK (1<<INT1)
|
|
||||||
#endif
|
|
||||||
#ifdef INT2
|
|
||||||
#define SPI_INT2_MASK (1<<INT2)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void SPIClass::usingInterrupt(uint8_t interruptNumber)
|
|
||||||
{
|
|
||||||
uint8_t mask = 0;
|
|
||||||
uint8_t sreg = SREG;
|
|
||||||
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
|
|
||||||
switch (interruptNumber) {
|
|
||||||
#ifdef SPI_INT0_MASK
|
|
||||||
case 0: mask = SPI_INT0_MASK; break;
|
|
||||||
#endif
|
|
||||||
#ifdef SPI_INT1_MASK
|
|
||||||
case 1: mask = SPI_INT1_MASK; break;
|
|
||||||
#endif
|
|
||||||
#ifdef SPI_INT2_MASK
|
|
||||||
case 2: mask = SPI_INT2_MASK; break;
|
|
||||||
#endif
|
|
||||||
#ifdef SPI_INT3_MASK
|
|
||||||
case 3: mask = SPI_INT3_MASK; break;
|
|
||||||
#endif
|
|
||||||
#ifdef SPI_INT4_MASK
|
|
||||||
case 4: mask = SPI_INT4_MASK; break;
|
|
||||||
#endif
|
|
||||||
#ifdef SPI_INT5_MASK
|
|
||||||
case 5: mask = SPI_INT5_MASK; break;
|
|
||||||
#endif
|
|
||||||
#ifdef SPI_INT6_MASK
|
|
||||||
case 6: mask = SPI_INT6_MASK; break;
|
|
||||||
#endif
|
|
||||||
#ifdef SPI_INT7_MASK
|
|
||||||
case 7: mask = SPI_INT7_MASK; break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
interruptMode = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
interruptMask |= mask;
|
|
||||||
if (!interruptMode)
|
|
||||||
interruptMode = 1;
|
|
||||||
SREG = sreg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
|
|
||||||
{
|
|
||||||
// Once in mode 2 we can't go back to 0 without a proper reference count
|
|
||||||
if (interruptMode == 2)
|
|
||||||
return;
|
|
||||||
uint8_t mask = 0;
|
|
||||||
uint8_t sreg = SREG;
|
|
||||||
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
|
|
||||||
switch (interruptNumber) {
|
|
||||||
#ifdef SPI_INT0_MASK
|
|
||||||
case 0: mask = SPI_INT0_MASK; break;
|
|
||||||
#endif
|
|
||||||
#ifdef SPI_INT1_MASK
|
|
||||||
case 1: mask = SPI_INT1_MASK; break;
|
|
||||||
#endif
|
|
||||||
#ifdef SPI_INT2_MASK
|
|
||||||
case 2: mask = SPI_INT2_MASK; break;
|
|
||||||
#endif
|
|
||||||
#ifdef SPI_INT3_MASK
|
|
||||||
case 3: mask = SPI_INT3_MASK; break;
|
|
||||||
#endif
|
|
||||||
#ifdef SPI_INT4_MASK
|
|
||||||
case 4: mask = SPI_INT4_MASK; break;
|
|
||||||
#endif
|
|
||||||
#ifdef SPI_INT5_MASK
|
|
||||||
case 5: mask = SPI_INT5_MASK; break;
|
|
||||||
#endif
|
|
||||||
#ifdef SPI_INT6_MASK
|
|
||||||
case 6: mask = SPI_INT6_MASK; break;
|
|
||||||
#endif
|
|
||||||
#ifdef SPI_INT7_MASK
|
|
||||||
case 7: mask = SPI_INT7_MASK; break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
// this case can't be reached
|
|
||||||
}
|
|
||||||
interruptMask &= ~mask;
|
|
||||||
if (!interruptMask)
|
|
||||||
interruptMode = 0;
|
|
||||||
SREG = sreg;
|
|
||||||
}
|
|
@ -1,324 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
|
|
||||||
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
|
|
||||||
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
|
|
||||||
* Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
|
|
||||||
* SPI Master library for arduino.
|
|
||||||
*
|
|
||||||
* This file is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of either the GNU General Public License version 2
|
|
||||||
* or the GNU Lesser General Public License version 2.1, both as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SPI_H_INCLUDED
|
|
||||||
#define _SPI_H_INCLUDED
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(),
|
|
||||||
// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode)
|
|
||||||
#define SPI_HAS_TRANSACTION 1
|
|
||||||
|
|
||||||
// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method
|
|
||||||
#define SPI_HAS_NOTUSINGINTERRUPT 1
|
|
||||||
|
|
||||||
// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version.
|
|
||||||
// This way when there is a bug fix you can check this define to alert users
|
|
||||||
// of your code if it uses better version of this library.
|
|
||||||
// This also implies everything that SPI_HAS_TRANSACTION as documented above is
|
|
||||||
// available too.
|
|
||||||
#define SPI_ATOMIC_VERSION 1
|
|
||||||
|
|
||||||
// Uncomment this line to add detection of mismatched begin/end transactions.
|
|
||||||
// A mismatch occurs if other libraries fail to use SPI.endTransaction() for
|
|
||||||
// each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn
|
|
||||||
// on if any mismatch is ever detected.
|
|
||||||
//#define SPI_TRANSACTION_MISMATCH_LED 5
|
|
||||||
|
|
||||||
#ifndef LSBFIRST
|
|
||||||
#define LSBFIRST 0
|
|
||||||
#endif
|
|
||||||
#ifndef MSBFIRST
|
|
||||||
#define MSBFIRST 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SPI_CLOCK_DIV4 0x00
|
|
||||||
#define SPI_CLOCK_DIV16 0x01
|
|
||||||
#define SPI_CLOCK_DIV64 0x02
|
|
||||||
#define SPI_CLOCK_DIV128 0x03
|
|
||||||
#define SPI_CLOCK_DIV2 0x04
|
|
||||||
#define SPI_CLOCK_DIV8 0x05
|
|
||||||
#define SPI_CLOCK_DIV32 0x06
|
|
||||||
|
|
||||||
#define SPI_MODE0 0x00
|
|
||||||
#define SPI_MODE1 0x04
|
|
||||||
#define SPI_MODE2 0x08
|
|
||||||
#define SPI_MODE3 0x0C
|
|
||||||
|
|
||||||
#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
|
|
||||||
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
|
|
||||||
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
|
|
||||||
|
|
||||||
// define SPI_AVR_EIMSK for AVR boards with external interrupt pins
|
|
||||||
#if defined(EIMSK)
|
|
||||||
#define SPI_AVR_EIMSK EIMSK
|
|
||||||
#elif defined(GICR)
|
|
||||||
#define SPI_AVR_EIMSK GICR
|
|
||||||
#elif defined(GIMSK)
|
|
||||||
#define SPI_AVR_EIMSK GIMSK
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class SPISettings {
|
|
||||||
public:
|
|
||||||
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
|
|
||||||
if (__builtin_constant_p(clock)) {
|
|
||||||
init_AlwaysInline(clock, bitOrder, dataMode);
|
|
||||||
} else {
|
|
||||||
init_MightInline(clock, bitOrder, dataMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SPISettings() {
|
|
||||||
init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
|
|
||||||
init_AlwaysInline(clock, bitOrder, dataMode);
|
|
||||||
}
|
|
||||||
void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
|
|
||||||
__attribute__((__always_inline__)) {
|
|
||||||
// Clock settings are defined as follows. Note that this shows SPI2X
|
|
||||||
// inverted, so the bits form increasing numbers. Also note that
|
|
||||||
// fosc/64 appears twice
|
|
||||||
// SPR1 SPR0 ~SPI2X Freq
|
|
||||||
// 0 0 0 fosc/2
|
|
||||||
// 0 0 1 fosc/4
|
|
||||||
// 0 1 0 fosc/8
|
|
||||||
// 0 1 1 fosc/16
|
|
||||||
// 1 0 0 fosc/32
|
|
||||||
// 1 0 1 fosc/64
|
|
||||||
// 1 1 0 fosc/64
|
|
||||||
// 1 1 1 fosc/128
|
|
||||||
|
|
||||||
// We find the fastest clock that is less than or equal to the
|
|
||||||
// given clock rate. The clock divider that results in clock_setting
|
|
||||||
// is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the
|
|
||||||
// slowest (128 == 2 ^^ 7, so clock_div = 6).
|
|
||||||
uint8_t clockDiv;
|
|
||||||
|
|
||||||
// When the clock is known at compiletime, use this if-then-else
|
|
||||||
// cascade, which the compiler knows how to completely optimize
|
|
||||||
// away. When clock is not known, use a loop instead, which generates
|
|
||||||
// shorter code.
|
|
||||||
if (__builtin_constant_p(clock)) {
|
|
||||||
if (clock >= F_CPU / 2) {
|
|
||||||
clockDiv = 0;
|
|
||||||
} else if (clock >= F_CPU / 4) {
|
|
||||||
clockDiv = 1;
|
|
||||||
} else if (clock >= F_CPU / 8) {
|
|
||||||
clockDiv = 2;
|
|
||||||
} else if (clock >= F_CPU / 16) {
|
|
||||||
clockDiv = 3;
|
|
||||||
} else if (clock >= F_CPU / 32) {
|
|
||||||
clockDiv = 4;
|
|
||||||
} else if (clock >= F_CPU / 64) {
|
|
||||||
clockDiv = 5;
|
|
||||||
} else {
|
|
||||||
clockDiv = 6;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uint32_t clockSetting = F_CPU / 2;
|
|
||||||
clockDiv = 0;
|
|
||||||
while (clockDiv < 6 && clock < clockSetting) {
|
|
||||||
clockSetting /= 2;
|
|
||||||
clockDiv++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compensate for the duplicate fosc/64
|
|
||||||
if (clockDiv == 6)
|
|
||||||
clockDiv = 7;
|
|
||||||
|
|
||||||
// Invert the SPI2X bit
|
|
||||||
clockDiv ^= 0x1;
|
|
||||||
|
|
||||||
// Pack into the SPISettings class
|
|
||||||
spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
|
|
||||||
(dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK);
|
|
||||||
spsr = clockDiv & SPI_2XCLOCK_MASK;
|
|
||||||
}
|
|
||||||
uint8_t spcr;
|
|
||||||
uint8_t spsr;
|
|
||||||
friend class SPIClass;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class SPIClass {
|
|
||||||
public:
|
|
||||||
// Initialize the SPI library
|
|
||||||
static void begin();
|
|
||||||
|
|
||||||
// If SPI is used from within an interrupt, this function registers
|
|
||||||
// that interrupt with the SPI library, so beginTransaction() can
|
|
||||||
// prevent conflicts. The input interruptNumber is the number used
|
|
||||||
// with attachInterrupt. If SPI is used from a different interrupt
|
|
||||||
// (eg, a timer), interruptNumber should be 255.
|
|
||||||
static void usingInterrupt(uint8_t interruptNumber);
|
|
||||||
// And this does the opposite.
|
|
||||||
static void notUsingInterrupt(uint8_t interruptNumber);
|
|
||||||
// Note: the usingInterrupt and notUsingInterrupt functions should
|
|
||||||
// not to be called from ISR context or inside a transaction.
|
|
||||||
// For details see:
|
|
||||||
// https://github.com/arduino/Arduino/pull/2381
|
|
||||||
// https://github.com/arduino/Arduino/pull/2449
|
|
||||||
|
|
||||||
// Before using SPI.transfer() or asserting chip select pins,
|
|
||||||
// this function is used to gain exclusive access to the SPI bus
|
|
||||||
// and configure the correct settings.
|
|
||||||
inline static void beginTransaction(SPISettings settings) {
|
|
||||||
if (interruptMode > 0) {
|
|
||||||
uint8_t sreg = SREG;
|
|
||||||
noInterrupts();
|
|
||||||
|
|
||||||
#ifdef SPI_AVR_EIMSK
|
|
||||||
if (interruptMode == 1) {
|
|
||||||
interruptSave = SPI_AVR_EIMSK;
|
|
||||||
SPI_AVR_EIMSK &= ~interruptMask;
|
|
||||||
SREG = sreg;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
interruptSave = sreg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SPI_TRANSACTION_MISMATCH_LED
|
|
||||||
if (inTransactionFlag) {
|
|
||||||
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
|
|
||||||
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
|
|
||||||
}
|
|
||||||
inTransactionFlag = 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SPCR = settings.spcr;
|
|
||||||
SPSR = settings.spsr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write to the SPI bus (MOSI pin) and also receive (MISO pin)
|
|
||||||
inline static uint8_t transfer(uint8_t data) {
|
|
||||||
SPDR = data;
|
|
||||||
/*
|
|
||||||
* The following NOP introduces a small delay that can prevent the wait
|
|
||||||
* loop form iterating when running at the maximum speed. This gives
|
|
||||||
* about 10% more speed, even if it seems counter-intuitive. At lower
|
|
||||||
* speeds it is unnoticed.
|
|
||||||
*/
|
|
||||||
asm volatile("nop");
|
|
||||||
while (!(SPSR & _BV(SPIF))) ; // wait
|
|
||||||
return SPDR;
|
|
||||||
}
|
|
||||||
inline static uint16_t transfer16(uint16_t data) {
|
|
||||||
union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out;
|
|
||||||
in.val = data;
|
|
||||||
if (!(SPCR & _BV(DORD))) {
|
|
||||||
SPDR = in.msb;
|
|
||||||
asm volatile("nop"); // See transfer(uint8_t) function
|
|
||||||
while (!(SPSR & _BV(SPIF))) ;
|
|
||||||
out.msb = SPDR;
|
|
||||||
SPDR = in.lsb;
|
|
||||||
asm volatile("nop");
|
|
||||||
while (!(SPSR & _BV(SPIF))) ;
|
|
||||||
out.lsb = SPDR;
|
|
||||||
} else {
|
|
||||||
SPDR = in.lsb;
|
|
||||||
asm volatile("nop");
|
|
||||||
while (!(SPSR & _BV(SPIF))) ;
|
|
||||||
out.lsb = SPDR;
|
|
||||||
SPDR = in.msb;
|
|
||||||
asm volatile("nop");
|
|
||||||
while (!(SPSR & _BV(SPIF))) ;
|
|
||||||
out.msb = SPDR;
|
|
||||||
}
|
|
||||||
return out.val;
|
|
||||||
}
|
|
||||||
inline static void transfer(void *buf, size_t count) {
|
|
||||||
if (count == 0) return;
|
|
||||||
uint8_t *p = (uint8_t *)buf;
|
|
||||||
SPDR = *p;
|
|
||||||
while (--count > 0) {
|
|
||||||
uint8_t out = *(p + 1);
|
|
||||||
while (!(SPSR & _BV(SPIF))) ;
|
|
||||||
uint8_t in = SPDR;
|
|
||||||
SPDR = out;
|
|
||||||
*p++ = in;
|
|
||||||
}
|
|
||||||
while (!(SPSR & _BV(SPIF))) ;
|
|
||||||
*p = SPDR;
|
|
||||||
}
|
|
||||||
// After performing a group of transfers and releasing the chip select
|
|
||||||
// signal, this function allows others to access the SPI bus
|
|
||||||
inline static void endTransaction(void) {
|
|
||||||
#ifdef SPI_TRANSACTION_MISMATCH_LED
|
|
||||||
if (!inTransactionFlag) {
|
|
||||||
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
|
|
||||||
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
|
|
||||||
}
|
|
||||||
inTransactionFlag = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (interruptMode > 0) {
|
|
||||||
#ifdef SPI_AVR_EIMSK
|
|
||||||
uint8_t sreg = SREG;
|
|
||||||
#endif
|
|
||||||
noInterrupts();
|
|
||||||
#ifdef SPI_AVR_EIMSK
|
|
||||||
if (interruptMode == 1) {
|
|
||||||
SPI_AVR_EIMSK = interruptSave;
|
|
||||||
SREG = sreg;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
SREG = interruptSave;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable the SPI bus
|
|
||||||
static void end();
|
|
||||||
|
|
||||||
// This function is deprecated. New applications should use
|
|
||||||
// beginTransaction() to configure SPI settings.
|
|
||||||
inline static void setBitOrder(uint8_t bitOrder) {
|
|
||||||
if (bitOrder == LSBFIRST) SPCR |= _BV(DORD);
|
|
||||||
else SPCR &= ~(_BV(DORD));
|
|
||||||
}
|
|
||||||
// This function is deprecated. New applications should use
|
|
||||||
// beginTransaction() to configure SPI settings.
|
|
||||||
inline static void setDataMode(uint8_t dataMode) {
|
|
||||||
SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
|
|
||||||
}
|
|
||||||
// This function is deprecated. New applications should use
|
|
||||||
// beginTransaction() to configure SPI settings.
|
|
||||||
inline static void setClockDivider(uint8_t clockDiv) {
|
|
||||||
SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK);
|
|
||||||
SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK);
|
|
||||||
}
|
|
||||||
// These undocumented functions should not be used. SPI.transfer()
|
|
||||||
// polls the hardware flag which is automatically cleared as the
|
|
||||||
// AVR responds to SPI's interrupt
|
|
||||||
inline static void attachInterrupt() { SPCR |= _BV(SPIE); }
|
|
||||||
inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static uint8_t initialized;
|
|
||||||
static uint8_t interruptMode; // 0=none, 1=mask, 2=global
|
|
||||||
static uint8_t interruptMask; // which interrupts to mask
|
|
||||||
static uint8_t interruptSave; // temp storage, to restore state
|
|
||||||
#ifdef SPI_TRANSACTION_MISMATCH_LED
|
|
||||||
static uint8_t inTransactionFlag;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
extern SPIClass SPI;
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,10 +0,0 @@
|
|||||||
name=SPI
|
|
||||||
version=1.0
|
|
||||||
author=Arduino
|
|
||||||
maintainer=Arduino <info@arduino.cc>
|
|
||||||
sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. For all Arduino boards, BUT Arduino DUE.
|
|
||||||
paragraph=
|
|
||||||
category=Communication
|
|
||||||
url=http://www.arduino.cc/en/Reference/SPI
|
|
||||||
architectures=avr
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
|||||||
TinyWireM
|
|
||||||
=========
|
|
||||||
|
|
||||||
ATtiny (e.g. Adafruit Trinket, Gemma) I2C library, adapted from BroHogan's code on Arduino Playground: http://playground.arduino.cc/Code/USIi2c
|
|
||||||
|
|
||||||
Minor changes for consistency with the Arduino 1.0 Wire library (e.g. uses write() instead of send()). Buffer size slightly increased for Adafruit_LEDBackpack use.
|
|
||||||
|
|
||||||
On the Trinket boards, pin #0 is SDA (I2C data), pin #2 is SCK (I2C clock).
|
|
@ -1,9 +0,0 @@
|
|||||||
name=TinyWireM
|
|
||||||
version=1.0.0
|
|
||||||
author=Adafruit
|
|
||||||
maintainer=Adafruit <info@adafruit.com>
|
|
||||||
sentence=I2C library for Trinket and Gemma, adapted from BroHogan's code on Arduino Playground
|
|
||||||
paragraph=I2C library for Trinket and Gemma, adapted from BroHogan's code on Arduino Playground
|
|
||||||
category=Signal Input/Output
|
|
||||||
url=https://github.com/adafruit/TinyWireM
|
|
||||||
architectures=*
|
|
@ -1,5 +0,0 @@
|
|||||||
micronucleusprog.name=Micronucleus
|
|
||||||
micronucleusprog.communication=usb
|
|
||||||
micronucleusprog.protocol=micronucleus
|
|
||||||
micronucleusprog.program.tool={runtime.tools.micronucleus.path}/micronucleus
|
|
||||||
micronucleusprog.program.extra_params=-Pusb
|
|
@ -1 +0,0 @@
|
|||||||
//This file allows the DigiXBetaBonus sketches to appear in the File > Examples menu and fixes the Invalid library warning in Arduino IDE 1.6.6+
|
|
@ -1,203 +0,0 @@
|
|||||||
/*
|
|
||||||
EEPROM.h - EEPROM library for the Digistump DigiX
|
|
||||||
|
|
||||||
This is mostly the merger of the stock Arduino EEPROM library, original
|
|
||||||
Copyright (c) 2006 David A. Mellis/Christopher Andrews 2015 (LGPL 2.1) with a
|
|
||||||
few functions from Dennis Schweer (Inglorious Engineer)'s Extensive TWI/I2C
|
|
||||||
EEPROM Library for 24LCxxx devices v0.4.1 (CC-BY-SA), as distributed with the
|
|
||||||
DigiX core.
|
|
||||||
|
|
||||||
Merging work by SukkoPera <software@sukkology.net>, 2016.
|
|
||||||
|
|
||||||
The basic idea is to create a library that is interface-compatible with
|
|
||||||
Arduino's stock library that is used on non-Due boards, to achieve
|
|
||||||
compatibility at source level, so that the usual EEPROM.write()/read()/get()
|
|
||||||
/put() calls can be used.
|
|
||||||
|
|
||||||
I'm not really sure of what license the resulting code should be released
|
|
||||||
under, so I'm leaving the LGPL 2.1, as most of the code here actually came
|
|
||||||
under that license, and the rest is pretty basic stuff, but let me know if I
|
|
||||||
should change that.
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef EEPROM_h
|
|
||||||
#define EEPROM_h
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <Wire.h>
|
|
||||||
|
|
||||||
static const int DIGIX_EEPROM_ADDR = 0x50;
|
|
||||||
|
|
||||||
static const int E2END = 0xFFF;
|
|
||||||
|
|
||||||
/***
|
|
||||||
EERef class.
|
|
||||||
|
|
||||||
This object references an EEPROM cell.
|
|
||||||
Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM.
|
|
||||||
This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell.
|
|
||||||
***/
|
|
||||||
|
|
||||||
struct EERef{
|
|
||||||
private:
|
|
||||||
void extEEPROMwrite(int EEPROM_addr, int addr, byte data)
|
|
||||||
{
|
|
||||||
Wire.beginTransmission(EEPROM_addr); //Start transmission to EEPROM
|
|
||||||
Wire.write(highByte(addr)); // send high byte of address
|
|
||||||
Wire.write(lowByte(addr)); // send low byte of address
|
|
||||||
Wire.write((byte) data); // send data
|
|
||||||
Wire.endTransmission(true); // stop transmitting
|
|
||||||
delay(6); // wait for a successful write
|
|
||||||
}
|
|
||||||
|
|
||||||
byte extEEPROMread(int EEPROM_addr, int addr) const
|
|
||||||
{
|
|
||||||
Wire.beginTransmission(EEPROM_addr); //Start transmission to EEPROM
|
|
||||||
Wire.write(highByte(addr)); // send high byte of address
|
|
||||||
Wire.write(lowByte(addr)); // send low byte of address
|
|
||||||
Wire.endTransmission(true); // stop transmitting
|
|
||||||
Wire.requestFrom(EEPROM_addr, 0x01, true); // request 1 byte form the device attached to EEPROM_addr
|
|
||||||
byte data_out = 64;
|
|
||||||
// read that byte
|
|
||||||
while(Wire.available() == 0) {} // wait for data
|
|
||||||
data_out = Wire.read(); //read single byte
|
|
||||||
return data_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
EERef( const int index )
|
|
||||||
: index( index ) {}
|
|
||||||
|
|
||||||
//Access/read members.
|
|
||||||
uint8_t operator*() const { return extEEPROMread( DIGIX_EEPROM_ADDR, index ); }
|
|
||||||
operator const uint8_t() const { return **this; }
|
|
||||||
|
|
||||||
//Assignment/write members.
|
|
||||||
EERef &operator=( const EERef &ref ) { return *this = *ref; }
|
|
||||||
EERef &operator=( uint8_t in ) { return extEEPROMwrite( DIGIX_EEPROM_ADDR, index, in ), *this; }
|
|
||||||
EERef &operator +=( uint8_t in ) { return *this = **this + in; }
|
|
||||||
EERef &operator -=( uint8_t in ) { return *this = **this - in; }
|
|
||||||
EERef &operator *=( uint8_t in ) { return *this = **this * in; }
|
|
||||||
EERef &operator /=( uint8_t in ) { return *this = **this / in; }
|
|
||||||
EERef &operator ^=( uint8_t in ) { return *this = **this ^ in; }
|
|
||||||
EERef &operator %=( uint8_t in ) { return *this = **this % in; }
|
|
||||||
EERef &operator &=( uint8_t in ) { return *this = **this & in; }
|
|
||||||
EERef &operator |=( uint8_t in ) { return *this = **this | in; }
|
|
||||||
EERef &operator <<=( uint8_t in ) { return *this = **this << in; }
|
|
||||||
EERef &operator >>=( uint8_t in ) { return *this = **this >> in; }
|
|
||||||
|
|
||||||
EERef &update( uint8_t in ) { return in != *this ? *this = in : *this; }
|
|
||||||
|
|
||||||
/** Prefix increment/decrement **/
|
|
||||||
EERef& operator++() { return *this += 1; }
|
|
||||||
EERef& operator--() { return *this -= 1; }
|
|
||||||
|
|
||||||
/** Postfix increment/decrement **/
|
|
||||||
uint8_t operator++ (int){
|
|
||||||
uint8_t ret = **this;
|
|
||||||
return ++(*this), ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t operator-- (int){
|
|
||||||
uint8_t ret = **this;
|
|
||||||
return --(*this), ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int index; //Index of current EEPROM cell.
|
|
||||||
};
|
|
||||||
|
|
||||||
/***
|
|
||||||
EEPtr class.
|
|
||||||
|
|
||||||
This object is a bidirectional pointer to EEPROM cells represented by EERef objects.
|
|
||||||
Just like a normal pointer type, this can be dereferenced and repositioned using
|
|
||||||
increment/decrement operators.
|
|
||||||
***/
|
|
||||||
|
|
||||||
struct EEPtr{
|
|
||||||
|
|
||||||
EEPtr( const int index )
|
|
||||||
: index( index ) {}
|
|
||||||
|
|
||||||
operator const int() const { return index; }
|
|
||||||
EEPtr &operator=( int in ) { return index = in, *this; }
|
|
||||||
|
|
||||||
//Iterator functionality.
|
|
||||||
bool operator!=( const EEPtr &ptr ) { return index != ptr.index; }
|
|
||||||
EERef operator*() { return index; }
|
|
||||||
|
|
||||||
/** Prefix & Postfix increment/decrement **/
|
|
||||||
EEPtr& operator++() { return ++index, *this; }
|
|
||||||
EEPtr& operator--() { return --index, *this; }
|
|
||||||
EEPtr operator++ (int) { return index++; }
|
|
||||||
EEPtr operator-- (int) { return index--; }
|
|
||||||
|
|
||||||
int index; //Index of current EEPROM cell.
|
|
||||||
};
|
|
||||||
|
|
||||||
/***
|
|
||||||
EEPROMClass class.
|
|
||||||
|
|
||||||
This object represents the entire EEPROM space.
|
|
||||||
It wraps the functionality of EEPtr and EERef into a basic interface.
|
|
||||||
This class is also 100% backwards compatible with earlier Arduino core releases.
|
|
||||||
***/
|
|
||||||
|
|
||||||
struct EEPROMClass{
|
|
||||||
boolean inited;
|
|
||||||
|
|
||||||
// c'tor
|
|
||||||
EEPROMClass () { inited = false; }
|
|
||||||
|
|
||||||
// Check if the i2c library was initialized, and do it if not.
|
|
||||||
// FIXME: What happens if the sketch has already called Wire.begin() on its
|
|
||||||
// own?
|
|
||||||
void checkInited () { if (!inited) { Wire.begin(); inited = true; } }
|
|
||||||
|
|
||||||
//Basic user access methods.
|
|
||||||
EERef operator[]( const int idx ) { return idx; }
|
|
||||||
uint8_t read( int idx ) { checkInited (); return EERef( idx ); }
|
|
||||||
void write( int idx, uint8_t val ) { checkInited (); (EERef( idx )) = val; }
|
|
||||||
void update( int idx, uint8_t val ) { checkInited (); EERef( idx ).update( val ); }
|
|
||||||
|
|
||||||
//STL and C++11 iteration capability.
|
|
||||||
EEPtr begin() { return 0x00; }
|
|
||||||
EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid.
|
|
||||||
uint16_t length() { return E2END + 1; }
|
|
||||||
|
|
||||||
//Functionality to 'get' and 'put' objects to and from EEPROM.
|
|
||||||
template< typename T > T &get( int idx, T &t ){
|
|
||||||
checkInited ();
|
|
||||||
|
|
||||||
EEPtr e = idx;
|
|
||||||
uint8_t *ptr = (uint8_t*) &t;
|
|
||||||
for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e;
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T > const T &put( int idx, const T &t ){
|
|
||||||
checkInited ();
|
|
||||||
|
|
||||||
EEPtr e = idx;
|
|
||||||
const uint8_t *ptr = (const uint8_t*) &t;
|
|
||||||
for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ );
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static EEPROMClass EEPROM;
|
|
||||||
#endif
|
|
@ -62,46 +62,4 @@ digispark-pro64.build.core=pro
|
|||||||
digispark-pro64.build.variant=pro64buffer
|
digispark-pro64.build.variant=pro64buffer
|
||||||
digispark-pro64.upload.wait_for_upload_port = false
|
digispark-pro64.upload.wait_for_upload_port = false
|
||||||
digispark-pro64.upload.use_1200bps_touch = false
|
digispark-pro64.upload.use_1200bps_touch = false
|
||||||
digispark-pro64.upload.disable_flushing = false
|
digispark-pro64.upload.disable_flushing = false
|
||||||
|
|
||||||
digispark-tiny16.name=Digispark (16mhz - No USB)
|
|
||||||
digispark-tiny16.upload.using=micronucleusprog
|
|
||||||
digispark-tiny16.upload.protocol=usb
|
|
||||||
digispark-tiny16.upload.tool=micronucleus
|
|
||||||
digispark-tiny16.upload.maximum_size=6012
|
|
||||||
digispark-tiny16.build.mcu=attiny85
|
|
||||||
digispark-tiny16.build.f_cpu=16000000L
|
|
||||||
digispark-tiny16.build.board=AVR_DIGISPARK
|
|
||||||
digispark-tiny16.build.core=tiny
|
|
||||||
digispark-tiny16.build.variant=digispark
|
|
||||||
digispark-tiny16.upload.wait_for_upload_port = false
|
|
||||||
digispark-tiny16.upload.use_1200bps_touch = false
|
|
||||||
digispark-tiny16.upload.disable_flushing = false
|
|
||||||
|
|
||||||
digispark-tiny8.name=Digispark (8mhz - No USB)
|
|
||||||
digispark-tiny8.upload.using=micronucleusprog
|
|
||||||
digispark-tiny8.upload.protocol=usb
|
|
||||||
digispark-tiny8.upload.tool=micronucleus
|
|
||||||
digispark-tiny8.upload.maximum_size=6012
|
|
||||||
digispark-tiny8.build.mcu=attiny85
|
|
||||||
digispark-tiny8.build.f_cpu=8000000L
|
|
||||||
digispark-tiny8.build.board=AVR_DIGISPARK
|
|
||||||
digispark-tiny8.build.core=tiny
|
|
||||||
digispark-tiny8.build.variant=digispark
|
|
||||||
digispark-tiny8.upload.wait_for_upload_port = false
|
|
||||||
digispark-tiny8.upload.use_1200bps_touch = false
|
|
||||||
digispark-tiny8.upload.disable_flushing = false
|
|
||||||
|
|
||||||
digispark-tiny1.name=Digispark (1mhz - No USB)
|
|
||||||
digispark-tiny1.upload.using=micronucleusprog
|
|
||||||
digispark-tiny1.upload.protocol=usb
|
|
||||||
digispark-tiny1.upload.tool=micronucleus
|
|
||||||
digispark-tiny1.upload.maximum_size=6012
|
|
||||||
digispark-tiny1.build.mcu=attiny85
|
|
||||||
digispark-tiny1.build.f_cpu=1000000L
|
|
||||||
digispark-tiny1.build.board=AVR_DIGISPARK
|
|
||||||
digispark-tiny1.build.core=tiny
|
|
||||||
digispark-tiny1.build.variant=digispark
|
|
||||||
digispark-tiny1.upload.wait_for_upload_port = false
|
|
||||||
digispark-tiny1.upload.use_1200bps_touch = false
|
|
||||||
digispark-tiny1.upload.disable_flushing = false
|
|
@ -103,11 +103,6 @@ int digitalRead(uint8_t);
|
|||||||
int analogRead(uint8_t);
|
int analogRead(uint8_t);
|
||||||
void analogReference(uint8_t mode);
|
void analogReference(uint8_t mode);
|
||||||
void analogWrite(uint8_t, int);
|
void analogWrite(uint8_t, int);
|
||||||
void pwmWrite(uint8_t, int);
|
|
||||||
void pwmConnect(uint8_t);
|
|
||||||
void pwmDisconnect(uint8_t);
|
|
||||||
void pwmReset(void);
|
|
||||||
|
|
||||||
|
|
||||||
unsigned long millis(void);
|
unsigned long millis(void);
|
||||||
unsigned long micros(void);
|
unsigned long micros(void);
|
||||||
@ -165,9 +160,6 @@ extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
|
|||||||
#define TIMER1B 4
|
#define TIMER1B 4
|
||||||
#define TIMER1D 5
|
#define TIMER1D 5
|
||||||
|
|
||||||
#define CHANNELA 3 //TIMER1A
|
|
||||||
#define CHANNELB 4 //TIMER1B
|
|
||||||
|
|
||||||
#include "pins_arduino.h"
|
#include "pins_arduino.h"
|
||||||
|
|
||||||
#ifndef USE_SOFTWARE_SERIAL
|
#ifndef USE_SOFTWARE_SERIAL
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user