added updated tinypinchange and associated libraries to support PRO

This commit is contained in:
Erik Tylek Kettenburg 2014-12-23 13:07:19 -08:00
parent d5fa60a1ec
commit e09b5f479b
71 changed files with 4062 additions and 331 deletions

View File

@ -0,0 +1,22 @@
# 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

View File

@ -0,0 +1,215 @@
#################
## 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

View File

@ -0,0 +1,16 @@
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

View File

@ -0,0 +1,988 @@
/* 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

View File

@ -0,0 +1,318 @@
/* 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

View File

@ -0,0 +1,83 @@
/* 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

View File

@ -0,0 +1,380 @@
/* 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

View File

@ -0,0 +1,70 @@
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.

View File

@ -0,0 +1,84 @@
#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();
}

View File

@ -0,0 +1,201 @@
#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;
}
}
}

View File

@ -0,0 +1,48 @@
/* 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
}
}

View File

@ -0,0 +1,130 @@
/* 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();
}
}

View File

@ -0,0 +1,39 @@
/* 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();
}
}

View File

@ -0,0 +1,25 @@
/* 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);
}
}

View File

@ -0,0 +1,37 @@
/* 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);
}
}

View File

@ -0,0 +1,50 @@
#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);
}
}

View File

@ -0,0 +1,133 @@
# 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

View File

@ -0,0 +1,62 @@
//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.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -0,0 +1,68 @@
/* 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();
}
}

View File

@ -0,0 +1,120 @@
/* 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();
}
}

View File

@ -19,6 +19,7 @@ IMPORTANT:
For this sketch, which is using <DigiUSB> library: For this sketch, which is using <DigiUSB> library:
1) Comment "#define RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT" in "arduino-1.xx\libraries\RcSeq.h". 1) Comment "#define RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT" in "arduino-1.xx\libraries\RcSeq.h".
This will disable the code to manage incoming RC pulses and save some flash memory. This will disable the code to manage incoming RC pulses and save some flash memory.
RC_SEQ_WITH_SHORT_ACTION_SUPPORT and RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT shall be defined
2) Replace #define RING_BUFFER_SIZE 128 with #define RING_BUFFER_SIZE 32 in "arduino-1.xx\libraries\DigisparkUSB\DigiUSB.h". 2) Replace #define RING_BUFFER_SIZE 128 with #define RING_BUFFER_SIZE 32 in "arduino-1.xx\libraries\DigisparkUSB\DigiUSB.h".
3) The sequence will be launch by sending "g" character through USB link (using Digiterm or Digi Monitor). 3) The sequence will be launch by sending "g" character through USB link (using Digiterm or Digi Monitor).
To check all the sequence is performed asynchronously, you can send 't' to toggle the LED during servo motion! To check all the sequence is performed asynchronously, you can send 't' to toggle the LED during servo motion!

View File

@ -0,0 +1,115 @@
#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);
}

View File

@ -1,12 +1,15 @@
#include <RcSeq.h> #include <RcSeq.h>
#include <TinyPinChange.h> #include <TinyPinChange.h>
#include <SoftRcPulseIn.h> #include <SoftRcPulseIn.h>
#include <SoftRcPulseOut.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 transform a proportionnal RC channel into 5 digital commands with an ATtiny85. This sketch demonstrates how to easily transform a proportionnal RC channel into 5 digital commands with an ATtiny85.
RC Navy (2013) RC Navy (2013)
http://P.loussouarn.free.fr http://p.loussouarn.free.fr
COMMMAND OF 5 digital outputs from 5 push button replacing a potentiometer in the RC transmitter: COMMMAND OF 5 digital outputs from 5 push button replacing a potentiometer in the RC transmitter:
================================================================================================ ================================================================================================
@ -87,12 +90,21 @@ KeyMap_t CustomKeyboard[] PROGMEM ={ {CENTER_VALUE_US(1100,TOLERANCE)}, /* PUSH_
//============================================================================================== //==============================================================================================
/* Trick: a macro to write a single time the ToggleAction#() function */ /* Trick: a macro to write a single time the ToggleAction#() function */
#define DECLARE_TOGGLE_ACTION(Idx) \ #define DECLARE_TOGGLE_ACTION(Idx) \
void ToggleAction##Idx(void) \ void ToggleAction##Idx(void) \
{ \ { \
static boolean Etat=HIGH; \ static uint32_t StartMs=millis(); \
digitalWrite(Idx, Etat); \ static boolean Etat=HIGH; \
Etat=!Etat; \ \
/* Since version 2.0 of the <RcSeq> library, */ \
/* for reactivity reasons, inter-command delay */ \
/* shall be managed in the user sketch. */ \
if(millis() - StartMs >= 500UL) \
{ \
StartMs=millis(); \
digitalWrite(Idx, Etat); \
Etat=!Etat; \
} \
} }
/* Declaration of the actions using the DECLARE_TOGGLE_ACTION(Idx) macro with Idx = The number of the action and the pin number (The ##Idx will be automatically replaced with the Idx value */ /* Declaration of the actions using the DECLARE_TOGGLE_ACTION(Idx) macro with Idx = The number of the action and the pin number (The ##Idx will be automatically replaced with the Idx value */

View File

@ -1,4 +1,16 @@
#include <RcSeq.h>
#include <TinyPinChange.h> /* Ne pas oublier d'inclure la librairie <TinyPinChange> qui est utilisee par la librairie <RcSeq> */
#include <SoftRcPulseIn.h> /* Ne pas oublier d'inclure la librairie <SoftRcPulseIn> qui est utilisee par la librairie <RcSeq> */
#include <SoftRcPulseOut.h> /* Ne pas oublier d'inclure la librairie <SoftRcPulseOut> qui est utilisee par la librairie <RcSeq> */
/* /*
IMPORTANT:
Pour compiler ce sketch, RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT, RC_SEQ_WITH_SHORT_ACTION_SUPPORT et RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
doivent etre definis dans ChemainDesLibraires/(Digispark)RcSeq/RcSeq.h.
RC Navy 2013
http://p.loussouarn.free.fr
Ce sketch de demo de la librairie RcSeq montre comment configurer tres facilement la commande d'actions ou de sequences de servo predefinies. Ce sketch de demo de la librairie RcSeq montre comment configurer tres facilement la commande d'actions ou de sequences de servo predefinies.
La commande peut etre: La commande peut etre:
- un manche de l'emetteur RC avec possibilité de definir jusqu'a 8 positions "actives" (le nombre de position doit etre pair: neutre au milieu) - un manche de l'emetteur RC avec possibilité de definir jusqu'a 8 positions "actives" (le nombre de position doit etre pair: neutre au milieu)
@ -8,10 +20,6 @@ La commande peut etre:
(la largeur d'impulsion pour chaque bouton-poussoir est define dans une table, une tolerance est egalement prevue) (la largeur d'impulsion pour chaque bouton-poussoir est define dans une table, une tolerance est egalement prevue)
Les 3 exemples sont traites dans ce sketch de demo. Les 3 exemples sont traites dans ce sketch de demo.
*/ */
#include <RcSeq.h>
#include <TinyPinChange.h> /* Ne pas oublier d'inclure la librairie <TinyPinChange> qui est utilisee par la librairie <RcSeq> */
#include <SoftRcPulseIn.h> /* Ne pas oublier d'inclure la librairie <SoftRcPulseIn> qui est utilisee par la librairie <RcSeq> */
#include <SoftRcPulseOut.h> /* Ne pas oublier d'inclure la librairie <SoftRcPulseOut> qui est utilisee par la librairie <RcSeq> */
enum {RC_VOIE1, RC_VOIE2, RC_VOIE3, NBR_VOIES_RC}; /* Declaration des voies */ enum {RC_VOIE1, RC_VOIE2, RC_VOIE3, NBR_VOIES_RC}; /* Declaration des voies */
@ -134,7 +142,13 @@ void loop()
/* Action associee au BP1 de la VOIE1 ou au manche position basse de la VOIE2 ou au BP_MAISON1 de la VOIE3 */ /* Action associee au BP1 de la VOIE1 ou au manche position basse de la VOIE2 ou au BP_MAISON1 de la VOIE3 */
void InverseLed(void) void InverseLed(void)
{ {
static boolean Etat=HIGH; /* static, pour conserver l'etat entre 2 appels de la fonction */ static uint32_t DebutMs=millis(); /* static, pour conserver l'etat entre 2 appels de la fonction */
static boolean Etat=HIGH; /* static, pour conserver l'etat entre 2 appels de la fonction */
if(millis() - DebutMs >= 500UL) /* Depuis RcSeq V2.0, la tempo inter-commande doit etre geree dans le sketch utilisateur */
{
DebutMs=millis();
digitalWrite(LED, Etat); digitalWrite(LED, Etat);
Etat=!Etat; /* AU prochain appel de InverseLed(), l'etat de la LED sera inverse */ Etat=!Etat; /* Au prochain appel de InverseLed(), l'etat de la LED sera inverse */
}
} }

View File

@ -1,7 +1,15 @@
#include <RcSeq.h> #include <RcSeq.h>
#include <TinyPinChange.h> /* Ne pas oublier d'inclure la librairie <TinyPinChange> qui est utilisee par la librairie <RcSeq> */ #include <TinyPinChange.h> /* Ne pas oublier d'inclure la librairie <TinyPinChange> qui est utilisee par la librairie <RcSeq> */
#include <SoftRcPulseIn.h> /* Ne pas oublier d'inclure la librairie <SoftRcPulseIn> qui est utilisee par la librairie <RcSeq> */ #include <SoftRcPulseIn.h> /* Ne pas oublier d'inclure la librairie <SoftRcPulseIn> qui est utilisee par la librairie <RcSeq> */
#include <SoftRcPulseOut.h> /* Ne pas oublier d'inclure la librairie <SoftRcPulseOut> qui est utilisee par la librairie <RcSeq> */
/*
IMPORTANT:
Pour compiler ce sketch, RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT et RC_SEQ_WITH_SHORT_ACTION_SUPPORT doivent etre definie
dans ChemainDesLibraires/(Digispark)RcSeq/RcSeq.h et RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT doit etre mis en commentaire.
RC Navy 2013
http://p.loussouarn.free.fr
*/
/*================= COMMMANDE DE 8 SORTIES ON/OFF PAR 8 INTERS POUSSOIR ======================== /*================= COMMMANDE DE 8 SORTIES ON/OFF PAR 8 INTERS POUSSOIR ========================
Les 8 relais ou sont connectés aux prise n°1,2,3,4,5,6,7,8 d'un ATtiny84 Les 8 relais ou sont connectés aux prise n°1,2,3,4,5,6,7,8 d'un ATtiny84
@ -34,12 +42,20 @@ KeyMap_t ClavierMaison[] PROGMEM ={ {VALEUR_CENTRALE_US(1100,TOLERANCE)}, /* BP
//============================================================================================== //==============================================================================================
/* Astuce: une macro pour n'ecrire qu'une seule fois la fonction ActionX() */ /* Astuce: une macro pour n'ecrire qu'une seule fois la fonction ActionX() */
#define DECLARE_ACTION(Idx) \ #define DECLARE_ACTION(Idx) \
void Action##Idx(void) \ void Action##Idx(void) \
{ \ { \
static boolean Etat=HIGH; \ static uint32_t DebutMs=millis(); \
digitalWrite(Idx, Etat); \ static boolean Etat=HIGH; \
Etat=!Etat; \ /* Depuis la version 2.0 de la lib <RcSeq>, pour */ \
/* des raisons de reactivite, la tempo inter-commande */ \
/* doit etre geree dans le sketch utilisateur. */ \
if(millis() - DebutMs >= 500UL) \
{ \
DebutMs=millis(); \
digitalWrite(Idx, Etat); \
Etat=!Etat; \
} \
} }
/* Declaration des actions en utilisant la macro DECLARE_ACTION(Idx) avec Idx = le numero de l'action et de la pin (le ##Idx sera remplace automatiquement par la valeur de Idx */ /* Declaration des actions en utilisant la macro DECLARE_ACTION(Idx) avec Idx = le numero de l'action et de la pin (le ##Idx sera remplace automatiquement par la valeur de Idx */

View File

@ -11,6 +11,7 @@
3) <SoftRcPulseOut>: a library mainly based on the <SoftwareServo> library, but with a better pulse generation to limit jitter 3) <SoftRcPulseOut>: a library mainly based on the <SoftwareServo> library, but with a better pulse generation to limit jitter
RC Signals (receiver outputs) can be assigned to a control type: RC Signals (receiver outputs) can be assigned to a control type:
-Stick Positions (up to 8, but in practice, 4 is the maximum to manually discriminate each stick position) -Stick Positions (up to 8, but in practice, 4 is the maximum to manually discriminate each stick position)
-Multi position switch (2 pos switch, 3 pos switch, or more, eg. rotactor)
-Keyboard (<RcSeq> assumes Push-Buttons associated Pulse duration are equidistant) -Keyboard (<RcSeq> assumes Push-Buttons associated Pulse duration are equidistant)
-Custom Keyboard (The pulse durations can be defined independently for each Push-Button) -Custom Keyboard (The pulse durations can be defined independently for each Push-Button)
Some definitions: Some definitions:
@ -20,7 +21,7 @@
CAUTION: the end user shall also use asynchronous programmation method in the loop() function (no blocking functions such as delay() or pulseIn()). CAUTION: the end user shall also use asynchronous programmation method in the loop() function (no blocking functions such as delay() or pulseIn()).
http://p.loussouarn.free.fr http://p.loussouarn.free.fr
Francais: par RC Navy (2012) Francais: par RC Navy (2012/2013)
======== ========
<RcSeq> est une librairie asynchrone pour ATmega328P (UNO), ATtiny84 et ATtiny85 pour creer facilement des sequences de servos et/ou executer des actions depuis des commandes RC. <RcSeq> est une librairie asynchrone pour ATmega328P (UNO), ATtiny84 et ATtiny85 pour creer facilement des sequences de servos et/ou executer des actions depuis des commandes RC.
Elle peut egalement etre utilisee pour lancer des "actions courtes" (la duree doit etre inferieure a 20ms pour ne pas perturber la commande des servos) Elle peut egalement etre utilisee pour lancer des "actions courtes" (la duree doit etre inferieure a 20ms pour ne pas perturber la commande des servos)
@ -31,6 +32,7 @@
3) <SoftRcPulseOut>: une librairie majoritairement basee sur la librairie <SoftwareServo>, mais avec une meilleur generation des impulsions pour limiter la gigue 3) <SoftRcPulseOut>: une librairie majoritairement basee sur la librairie <SoftwareServo>, mais avec une meilleur generation des impulsions pour limiter la gigue
Les signaux RC (sorties du recepteur) peuvent etre associes a un type de controle: Les signaux RC (sorties du recepteur) peuvent etre associes a un type de controle:
-Positions de Manche (jusqu'a 8, mais en pratique, 4 est le maximum pour discriminer manuellement les positions du manche) -Positions de Manche (jusqu'a 8, mais en pratique, 4 est le maximum pour discriminer manuellement les positions du manche)
-Interrupteur multi-positions (interrupteur 2 pos, interrupteur 3 pos, ou plus, ex. rotacteur)
-Clavier (<RcSeq> suppose que les durees d'impulsion des Bouton-Poussoirs sont equidistantes) -Clavier (<RcSeq> suppose que les durees d'impulsion des Bouton-Poussoirs sont equidistantes)
-Clavier "Maison" (Les durees d'impulsion peuvent etre definies de manière independante pour chaque Bouton-Poussoir) -Clavier "Maison" (Les durees d'impulsion peuvent etre definies de manière independante pour chaque Bouton-Poussoir)
Quelques definitions: Quelques definitions:
@ -74,14 +76,10 @@
/************************************************************************* /*************************************************************************
MACROS MACROS
*************************************************************************/ *************************************************************************/
/* For an easy Library Version Management */
#define LIB_VERSION 1
#define LIB_REVISION 0
#define STR(s) #s #define STR(s) #s
#define MAKE_TEXT_VER_REV(Ver,Rev) (char*)(STR(Ver)"."STR(Rev)) #define MAKE_TEXT_VER_REV(Ver,Rev) (char*)(STR(Ver)"."STR(Rev))
#define LIB_TEXT_VERSION_REVISION MAKE_TEXT_VER_REV(LIB_VERSION,LIB_REVISION) /* Make Full version as a string "Ver.Rev" */ #define LIB_TEXT_VERSION_REVISION MAKE_TEXT_VER_REV(RC_SEQ_LIB_VERSION,RC_SEQ_LIB_REVISION) /* Make Full version as a string "Ver.Rev" */
/* A Set of Macros for bit manipulation */ /* A Set of Macros for bit manipulation */
#define SET_BIT(Value,BitIdx) (Value)|= (1<<(BitIdx)) #define SET_BIT(Value,BitIdx) (Value)|= (1<<(BitIdx))
@ -92,11 +90,8 @@
#define REFRESH_INTERVAL_MS 20L #define REFRESH_INTERVAL_MS 20L
/* A pulse shall be valid during XXXX_PULSE_CHECK_MS before being taken into account */ /* A pulse shall be valid during XXXX_PULSE_CHECK_MS before being taken into account */
#define STICK_PULSE_CHECK_MS 100L #define STICK_PULSE_CHECK_MS 150L
#define KBD_PULSE_CHECK_MS 10L #define KBD_PULSE_CHECK_MS 50L
/* Duration between 2 consecutive commands */
#define INTER_CMD_DURATION_MS 1000L
/* Free servo Indicator */ /* Free servo Indicator */
#define NO_SEQ_LINE 255 #define NO_SEQ_LINE 255
@ -115,11 +110,18 @@
#define PGM_READ_32(FlashAddr) pgm_read_dword(&(FlashAddr)) #define PGM_READ_32(FlashAddr) pgm_read_dword(&(FlashAddr))
/* /*
STICK TYPE: STICK TYPE: (dead zone expected at the middle)
========== ==========
Pos 0 1 2 3 Pos 0 1 2 3
|---|-|---|--|---|-|---| |---|-|---|--|---|-|---|
1000us 2000us (Typical Pulse Width values) 1000us 2000us (Typical Pulse Width values)
MULTI_POS_SW: (Middle area active as well)
============
Pos 0 1 2 3 4
|---|-|---|-|---|-|---|-|---|
1000us 2000us (Typical Pulse Width values)
*/ */
#define ACTIVE_AREA_STEP_NBR 3 #define ACTIVE_AREA_STEP_NBR 3
#define INACTIVE_AREA_STEP_NBR 1 #define INACTIVE_AREA_STEP_NBR 1
@ -156,11 +158,13 @@ typedef struct {
}RcCmdSt_t; }RcCmdSt_t;
#endif #endif
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
typedef struct { typedef struct {
SoftRcPulseOut Motor; SoftRcPulseOut Motor;
uint16_t RefreshNb; /* Used to store the number of refresh to perform during a servo motion (if not 0 -> Motion in progress) */ uint16_t RefreshNb; /* Used to store the number of refresh to perform during a servo motion (if not 0 -> Motion in progress) */
uint8_t SeqLineInProgress; uint8_t SeqLineInProgress;
}ServoSt_t; }ServoSt_t;
#endif
/************************************************************************* /*************************************************************************
GLOBAL VARIABLES GLOBAL VARIABLES
*************************************************************************/ *************************************************************************/
@ -172,11 +176,15 @@ static RcCmdSt_t RcChannel[RC_CMD_MAX_NB];
#endif #endif
#ifdef RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT #ifdef RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT
#define AsMember . #define AsMember .
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
static ServoSt_t Servo[SERVO_MAX_NB]; static ServoSt_t Servo[SERVO_MAX_NB];
#endif
static CmdSequenceSt_t CmdSequence[SEQUENCE_MAX_NB]; static CmdSequenceSt_t CmdSequence[SEQUENCE_MAX_NB];
#else #else
#define AsMember -> #define AsMember ->
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
static ServoSt_t **Servo=NULL; static ServoSt_t **Servo=NULL;
#endif
static CmdSequenceSt_t **CmdSequence=NULL; static CmdSequenceSt_t **CmdSequence=NULL;
#endif #endif
/************************************************************************* /*************************************************************************
@ -217,12 +225,12 @@ void RcSeq_Init(void)
//======================================================================================================================== //========================================================================================================================
uint8_t RcSeq_LibVersion(void) uint8_t RcSeq_LibVersion(void)
{ {
return(LIB_VERSION); return(RC_SEQ_LIB_VERSION);
} }
//======================================================================================================================== //========================================================================================================================
uint8_t RcSeq_LibRevision(void) uint8_t RcSeq_LibRevision(void)
{ {
return(LIB_REVISION); return(RC_SEQ_LIB_REVISION);
} }
//======================================================================================================================== //========================================================================================================================
char *RcSeq_LibTextVersionRevision(void) char *RcSeq_LibTextVersionRevision(void)
@ -230,6 +238,7 @@ char *RcSeq_LibTextVersionRevision(void)
return(LIB_TEXT_VERSION_REVISION); return(LIB_TEXT_VERSION_REVISION);
} }
//======================================================================================================================== //========================================================================================================================
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
void RcSeq_DeclareServo(uint8_t Idx, uint8_t DigitalPin) void RcSeq_DeclareServo(uint8_t Idx, uint8_t DigitalPin)
{ {
#ifdef RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT #ifdef RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT
@ -250,6 +259,7 @@ void RcSeq_DeclareServo(uint8_t Idx, uint8_t DigitalPin)
} }
#endif #endif
} }
#endif
//======================================================================================================================== //========================================================================================================================
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT #ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
void RcSeq_DeclareSignal(uint8_t Idx, uint8_t DigitalPin) void RcSeq_DeclareSignal(uint8_t Idx, uint8_t DigitalPin)
@ -299,6 +309,7 @@ uint32_t StartMinMs[SERVO_MAX_NB];
LoadSequenceOrShortAction(CmdIdx,Pos,(void*)Table, SequenceLength); LoadSequenceOrShortAction(CmdIdx,Pos,(void*)Table, SequenceLength);
#endif #endif
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
/* Get initial pulse width for each Servo */ /* Get initial pulse width for each Servo */
for(Idx=0;Idx<SERVO_MAX_NB;Idx++) for(Idx=0;Idx<SERVO_MAX_NB;Idx++)
{ {
@ -317,6 +328,7 @@ uint32_t StartMinMs[SERVO_MAX_NB];
} }
} }
} }
#endif
} }
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT #ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
//======================================================================================================================== //========================================================================================================================
@ -381,7 +393,8 @@ uint32_t MotionDurationMs, StartOfSeqMs, EndOfSeqMs, Pos;
uint16_t StartInDegrees, EndInDegrees; uint16_t StartInDegrees, EndInDegrees;
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT #ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
uint8_t ChIdx, CmdPos; uint8_t ChIdx;
int8_t CmdPos; /* Shall be signed */
uint32_t RcPulseWidthUs; uint32_t RcPulseWidthUs;
/* Asynchronous RC Command acquisition */ /* Asynchronous RC Command acquisition */
@ -394,11 +407,8 @@ uint32_t RcPulseWidthUs;
{ {
if(RcChannel[ChIdx].Pos.Idx!=CmdPos) if(RcChannel[ChIdx].Pos.Idx!=CmdPos)
{ {
if((millis()-RcChannel[ChIdx].Pos.StartChronoMs)>=INTER_CMD_DURATION_MS) /* Check the last command was received for at least 1 second */ RcChannel[ChIdx].Pos.Idx=CmdPos;
{ RcChannel[ChIdx].Pos.StartChronoMs=millis();
RcChannel[ChIdx].Pos.Idx=CmdPos;
RcChannel[ChIdx].Pos.StartChronoMs=millis();
}
} }
else else
{ {
@ -416,7 +426,7 @@ uint32_t RcPulseWidthUs;
} }
#endif #endif
NowMs=millis(); NowMs=millis();
if((NowMs - StartChronoInterPulseMs) >= 20L) if((NowMs - StartChronoInterPulseMs) >= 20UL)
{ {
/* We arrive here every 20 ms */ /* We arrive here every 20 ms */
/* Asynchronous Servo Sequence management */ /* Asynchronous Servo Sequence management */
@ -448,6 +458,7 @@ uint32_t RcPulseWidthUs;
continue; continue;
} }
#endif #endif
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
if(Servo[ServoIdx] AsMember RefreshNb && SeqLine!=Servo[ServoIdx] AsMember SeqLineInProgress) if(Servo[ServoIdx] AsMember RefreshNb && SeqLine!=Servo[ServoIdx] AsMember SeqLineInProgress)
{ {
continue; continue;
@ -484,9 +495,12 @@ uint32_t RcPulseWidthUs;
} }
} }
} }
#endif
} }
} }
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
SoftRcPulseOut::refresh(1); /* Force Refresh */ SoftRcPulseOut::refresh(1); /* Force Refresh */
#endif
StartChronoInterPulseMs=millis(); StartChronoInterPulseMs=millis();
} }
} }
@ -535,9 +549,9 @@ uint16_t PulseMinUs,PulseMaxUs;
{ {
switch(RcChannel[ChIdx].Type) switch(RcChannel[ChIdx].Type)
{ {
case RC_CMD_STICK: /* No break: normal */ case RC_CMD_STICK: /* No break: normal */
case RC_CMD_KEYBOARD: case RC_CMD_MULTI_POS_SW:
if(Idx<(RcChannel[ChIdx].PosNb/2)) if( (RcChannel[ChIdx].Type==RC_CMD_MULTI_POS_SW) || ((RcChannel[ChIdx].Type==RC_CMD_STICK) && (Idx<(RcChannel[ChIdx].PosNb/2))) )
{ {
PulseMinUs=RcChannel[ChIdx].PulseMinUs+KEY_MIN_VAL(Idx,RcChannel[ChIdx].StepUs); PulseMinUs=RcChannel[ChIdx].PulseMinUs+KEY_MIN_VAL(Idx,RcChannel[ChIdx].StepUs);
PulseMaxUs=RcChannel[ChIdx].PulseMinUs+KEY_MAX_VAL(Idx,RcChannel[ChIdx].StepUs); PulseMaxUs=RcChannel[ChIdx].PulseMinUs+KEY_MAX_VAL(Idx,RcChannel[ChIdx].StepUs);
@ -549,10 +563,10 @@ uint16_t PulseMinUs,PulseMaxUs;
} }
break; break;
case RC_CMD_CUSTOM: case RC_CMD_CUSTOM:
PulseMinUs=(uint16_t)PGM_READ_16(RcChannel[ChIdx].KeyMap[Idx].Min); PulseMinUs=(uint16_t)PGM_READ_16(RcChannel[ChIdx].KeyMap[Idx].Min);
PulseMaxUs=(uint16_t)PGM_READ_16(RcChannel[ChIdx].KeyMap[Idx].Max); PulseMaxUs=(uint16_t)PGM_READ_16(RcChannel[ChIdx].KeyMap[Idx].Max);
break; break;
} }
if((PulseWidthUs>=PulseMinUs) && (PulseWidthUs<=PulseMaxUs)) if((PulseWidthUs>=PulseMinUs) && (PulseWidthUs<=PulseMaxUs))
{ {

View File

@ -2,7 +2,7 @@
#define RC_SEQ_H #define RC_SEQ_H
/* /*
English: by RC Navy (2012) English: by RC Navy (2012/2013)
======= =======
<RcSeq> is an asynchronous library for ATmega328P (UNO), ATtiny84 and ATtiny85 to easily create servo's sequences and/or to execute short actions from RC commands. <RcSeq> is an asynchronous library for ATmega328P (UNO), ATtiny84 and ATtiny85 to easily create servo's sequences and/or to execute short actions from RC commands.
It can also be used to trig some short "actions" (the duration must be less than 20ms to not disturb the servo commands) It can also be used to trig some short "actions" (the duration must be less than 20ms to not disturb the servo commands)
@ -13,6 +13,7 @@
3) <SoftRcPulseOut>: a library mainly based on the <SoftwareServo> library, but with a better pulse generation to limit jitter 3) <SoftRcPulseOut>: a library mainly based on the <SoftwareServo> library, but with a better pulse generation to limit jitter
RC Signals (receiver outputs) can be assigned to a control type: RC Signals (receiver outputs) can be assigned to a control type:
-Stick Positions (up to 8, but in practice, 4 is the maximum to manually discriminate each stick position) -Stick Positions (up to 8, but in practice, 4 is the maximum to manually discriminate each stick position)
-Multi position switch (2 pos switch, 3 pos switch, or more, eg. rotactor)
-Keyboard (<RcSeq> assumes Push-Buttons associated Pulse duration are equidistant) -Keyboard (<RcSeq> assumes Push-Buttons associated Pulse duration are equidistant)
-Custom Keyboard (The pulse durations can be defined independently for each Push-Button) -Custom Keyboard (The pulse durations can be defined independently for each Push-Button)
Some definitions: Some definitions:
@ -22,7 +23,7 @@
CAUTION: the end user shall also use asynchronous programmation method in the loop() function (no blocking functions such as delay() or pulseIn()). CAUTION: the end user shall also use asynchronous programmation method in the loop() function (no blocking functions such as delay() or pulseIn()).
http://p.loussouarn.free.fr http://p.loussouarn.free.fr
Francais: par RC Navy (2012) Francais: par RC Navy (2012/2013)
======== ========
<RcSeq> est une librairie asynchrone pour ATmega328P (UNO), ATtiny84 et ATtiny85 pour creer facilement des sequences de servos et/ou executer des actions depuis des commandes RC. <RcSeq> est une librairie asynchrone pour ATmega328P (UNO), ATtiny84 et ATtiny85 pour creer facilement des sequences de servos et/ou executer des actions depuis des commandes RC.
Elle peut egalement etre utilisee pour lancer des "actions courtes" (la duree doit etre inferieure a 20ms pour ne pas perturber la commande des servos) Elle peut egalement etre utilisee pour lancer des "actions courtes" (la duree doit etre inferieure a 20ms pour ne pas perturber la commande des servos)
@ -33,6 +34,7 @@
3) <SoftRcPulseOut>: une librairie majoritairement basee sur la librairie <SoftwareServo>, mais avec une meilleur generation des impulsions pour limiter la gigue 3) <SoftRcPulseOut>: une librairie majoritairement basee sur la librairie <SoftwareServo>, mais avec une meilleur generation des impulsions pour limiter la gigue
Les signaux RC (sorties du recepteur) peuvent etre associes a un type de controle: Les signaux RC (sorties du recepteur) peuvent etre associes a un type de controle:
-Positions de Manche (jusqu'a 8, mais en pratique, 4 est le maximum pour discriminer manuellement les positions du manche) -Positions de Manche (jusqu'a 8, mais en pratique, 4 est le maximum pour discriminer manuellement les positions du manche)
-Interrupteur multi-positions (interrupteur 2 pos, interrupteur 3 pos, ou plus, ex. rotacteur)
-Clavier (<RcSeq> suppose que les durees d'impulsion des Bouton-Poussoirs sont equidistantes) -Clavier (<RcSeq> suppose que les durees d'impulsion des Bouton-Poussoirs sont equidistantes)
-Clavier "Maison" (Les durees d'impulsion peuvent etre definies de manière independante pour chaque Bouton-Poussoir) -Clavier "Maison" (Les durees d'impulsion peuvent etre definies de manière independante pour chaque Bouton-Poussoir)
Quelques definitions: Quelques definitions:
@ -45,15 +47,20 @@
/**********************************************/ /**********************************************/
/* RCSEQ LIBRARY CONFIGURATION */ /* RCSEQ LIBRARY CONFIGURATION */
/**********************************************/ /**********************************************/
//#define RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT /* Comment this line if you use <DigiUSB> library in your sketch */ #define RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT /* Comment this line if you use <DigiUSB> library in your sketch */
#define RC_SEQ_WITH_SHORT_ACTION_SUPPORT /* This allows to put call to short action in sequence table */ //#define RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT /* Uncomment this if you use <SoftRcPulseOut> library in your sketch for servos and ESC */
#define RC_SEQ_WITH_SHORT_ACTION_SUPPORT /* Uncomment this to allows to put call to short action in sequence table */
/**********************************************/ /**********************************************/
/* /!\ Do not touch below /!\ */ /* /!\ Do not touch below /!\ */
/**********************************************/ /**********************************************/
#define RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT /* Do NOT comment this line for DigiSpark */ /* For an easy Library Version Management */
#define RC_SEQ_LIB_VERSION 2
#define RC_SEQ_LIB_REVISION 0
#define RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT /* Do NOT comment this line for DigiSpark, but you can for UNO */
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT #ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
#include <TinyPinChange.h> #include <TinyPinChange.h>
@ -64,7 +71,11 @@
#ifndef RC_SEQ_WITH_SHORT_ACTION_SUPPORT #ifndef RC_SEQ_WITH_SHORT_ACTION_SUPPORT
#warning RC_SEQ_WITH_SHORT_ACTION_SUPPORT disabled: no short action possible!!! #warning RC_SEQ_WITH_SHORT_ACTION_SUPPORT disabled: no short action possible!!!
#endif #endif
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
#include <SoftRcPulseOut.h> #include <SoftRcPulseOut.h>
#else
#warning RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT disabled: no Servo/ESC command possible!!!
#endif
#if defined(ARDUINO) && ARDUINO >= 100 #if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h" #include "Arduino.h"
@ -114,7 +125,7 @@ typedef struct {
/* Macro to declare a short action (to use in "Sequence[]" structure table) */ /* Macro to declare a short action (to use in "Sequence[]" structure table) */
#define SHORT_ACTION_TO_PERFORM(ShortAction, StartActionOffsetMs) {255, 0, 0, (StartActionOffsetMs), 0L, (ShortAction)}, #define SHORT_ACTION_TO_PERFORM(ShortAction, StartActionOffsetMs) {255, 0, 0, (StartActionOffsetMs), 0L, (ShortAction)},
enum {RC_CMD_STICK=0, RC_CMD_KEYBOARD, RC_CMD_CUSTOM}; enum {RC_CMD_STICK=0, RC_CMD_MULTI_POS_SW, RC_CMD_CUSTOM};
#define RC_SEQUENCE(Sequence) Sequence, TABLE_ITEM_NBR(Sequence) #define RC_SEQUENCE(Sequence) Sequence, TABLE_ITEM_NBR(Sequence)
#define RC_CUSTOM_KEYBOARD(KeyMap) KeyMap, TABLE_ITEM_NBR(KeyMap) #define RC_CUSTOM_KEYBOARD(KeyMap) KeyMap, TABLE_ITEM_NBR(KeyMap)
@ -125,13 +136,16 @@ void RcSeq_Init(void);
uint8_t RcSeq_LibVersion(void); uint8_t RcSeq_LibVersion(void);
uint8_t RcSeq_LibRevision(void); uint8_t RcSeq_LibRevision(void);
char *RcSeq_LibTextVersionRevision(void); char *RcSeq_LibTextVersionRevision(void);
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
void RcSeq_DeclareServo(uint8_t Idx, uint8_t DigitalPin); void RcSeq_DeclareServo(uint8_t Idx, uint8_t DigitalPin);
#endif
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT #ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
void RcSeq_DeclareSignal(uint8_t Idx, uint8_t DigitalPin); void RcSeq_DeclareSignal(uint8_t Idx, uint8_t DigitalPin);
void RcSeq_DeclareKeyboardOrStickOrCustom(uint8_t ChIdx, uint8_t Type, uint16_t PulseMinUs, uint16_t PulseMaxUs, KeyMap_t *KeyMapTbl, uint8_t PosNb); void RcSeq_DeclareKeyboardOrStickOrCustom(uint8_t ChIdx, uint8_t Type, uint16_t PulseMinUs, uint16_t PulseMaxUs, KeyMap_t *KeyMapTbl, uint8_t PosNb);
void RcSeq_DeclareCustomKeyboard(uint8_t ChIdx, KeyMap_t *KeyMapTbl, uint8_t PosNb); void RcSeq_DeclareCustomKeyboard(uint8_t ChIdx, KeyMap_t *KeyMapTbl, uint8_t PosNb);
#define RcSeq_DeclareStick(ChIdx, PulseMinUs, PulseMaxUs, PosNb) RcSeq_DeclareKeyboardOrStickOrCustom(ChIdx, RC_CMD_STICK, PulseMinUs, PulseMaxUs, NULL, PosNb) #define RcSeq_DeclareStick(ChIdx, PulseMinUs, PulseMaxUs, PosNb) RcSeq_DeclareKeyboardOrStickOrCustom(ChIdx, RC_CMD_STICK, PulseMinUs, PulseMaxUs, NULL, PosNb)
#define RcSeq_DeclareKeyboard(ChIdx, PulseMinUs, PulseMaxUs, KeyNb) RcSeq_DeclareKeyboardOrStickOrCustom(ChIdx, RC_CMD_KEYBOARD, PulseMinUs, PulseMaxUs, NULL, KeyNb) #define RcSeq_DeclareMultiPosSwitch(ChIdx, PulseMinUs, PulseMaxUs, PosNb) RcSeq_DeclareKeyboardOrStickOrCustom(ChIdx, RC_CMD_MULTI_POS_SW, PulseMinUs, PulseMaxUs, NULL, PosNb)
#define RcSeq_DeclareKeyboard(ChIdx, PulseMinUs, PulseMaxUs, KeyNb) RcSeq_DeclareKeyboardOrStickOrCustom(ChIdx, RC_CMD_MULTI_POS_SW, PulseMinUs, PulseMaxUs, NULL, KeyNb)
#ifdef RC_SEQ_WITH_SHORT_ACTION_SUPPORT #ifdef RC_SEQ_WITH_SHORT_ACTION_SUPPORT
void RcSeq_DeclareCommandAndShortAction(uint8_t CmdIdx,uint8_t TypeCmd,void(*ShortAction)(void)); void RcSeq_DeclareCommandAndShortAction(uint8_t CmdIdx,uint8_t TypeCmd,void(*ShortAction)(void));
#endif #endif
@ -161,6 +175,7 @@ void RcSeq_Refresh(void);
#define RcSeq_DeclareManche RcSeq_DeclareStick #define RcSeq_DeclareManche RcSeq_DeclareStick
#define RcSeq_DeclareClavier RcSeq_DeclareKeyboard #define RcSeq_DeclareClavier RcSeq_DeclareKeyboard
#define RcSeq_DeclareClavierMaison RcSeq_DeclareCustomKeyboard #define RcSeq_DeclareClavierMaison RcSeq_DeclareCustomKeyboard
#define RcSeq_DeclareInterMultiPos RcSeq_DeclareMultiPosSwitch
#define RcSeq_DeclareCommandeEtActionCourte RcSeq_DeclareCommandAndShortAction #define RcSeq_DeclareCommandeEtActionCourte RcSeq_DeclareCommandAndShortAction
#endif #endif
#define RcSeq_DeclareCommandeEtSequence RcSeq_DeclareCommandAndSequence #define RcSeq_DeclareCommandeEtSequence RcSeq_DeclareCommandAndSequence

View File

@ -22,6 +22,8 @@ RcSeq_DeclareManche KEYWORD2
RcSeq_DeclareServo KEYWORD2 RcSeq_DeclareServo KEYWORD2
RcSeq_DeclareCustomKeyboard KEYWORD2 RcSeq_DeclareCustomKeyboard KEYWORD2
RcSeq_DeclareClavierMaison KEYWORD2 RcSeq_DeclareClavierMaison KEYWORD2
RcSeq_DeclareMultiPosSwitch KEYWORD2
RcSeq_DeclareInterMultiPos KEYWORD2
RcSeq_DeclareCommandAndSequence KEYWORD2 RcSeq_DeclareCommandAndSequence KEYWORD2
RcSeq_DeclareCommandeEtSequence KEYWORD2 RcSeq_DeclareCommandeEtSequence KEYWORD2
RcSeq_DeclareCommandAndShortAction KEYWORD2 RcSeq_DeclareCommandAndShortAction KEYWORD2

View File

@ -37,6 +37,7 @@ uint8_t Ret=0;
next = first; next = first;
first = this; first = this;
pinMode(_Pin,INPUT); pinMode(_Pin,INPUT);
digitalWrite(_Pin, HIGH);
_VirtualPortIdx=TinyPinChange_RegisterIsr(_Pin,SoftRcPulseIn::SoftRcPulseInInterrupt); _VirtualPortIdx=TinyPinChange_RegisterIsr(_Pin,SoftRcPulseIn::SoftRcPulseInInterrupt);
if(_VirtualPortIdx>=0) if(_VirtualPortIdx>=0)
{ {
@ -92,7 +93,7 @@ SoftRcPulseIn *RcPulseIn;
for ( RcPulseIn = first; RcPulseIn != 0; RcPulseIn = RcPulseIn->next ) for ( RcPulseIn = first; RcPulseIn != 0; RcPulseIn = RcPulseIn->next )
{ {
if(TinyPinChange_GetPinEvent(RcPulseIn->_VirtualPortIdx)&RcPulseIn->_PinMask) if(TinyPinChange_GetPortEvent(RcPulseIn->_VirtualPortIdx)&RcPulseIn->_PinMask)
{ {
if(digitalRead(RcPulseIn->_Pin)) if(digitalRead(RcPulseIn->_Pin))
{ {

View File

@ -0,0 +1,76 @@
/*
_____ ____ __ _ ____ _ _ _ _
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|_| |_| \____/ |_| \__| |_| |_| \__/ |_| 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)
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(38400); //Do NOT forget to setup your terminal at 38400 (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)
}
}

View File

@ -0,0 +1,184 @@
/********************************************************************************/
/* 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);
}

View File

@ -0,0 +1,116 @@
#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

View File

@ -4,7 +4,7 @@
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / / | |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
| _ / | | _ | |\ \| | | |__| | | | | | \ ' / | _ / | | _ | |\ \| | | |__| | | | | | \ ' /
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | | | | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2013 |_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2013/2014
http://p.loussouarn.free.fr http://p.loussouarn.free.fr
@ -15,7 +15,7 @@
******************************************************* *******************************************************
This sketch demonstrates how to use <TinyPinChange> library. This sketch demonstrates how to use <TinyPinChange> library.
It counts all the transitions on 2 different pins. It counts all the transitions (both 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. /!\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. Trick: By connecting Pin#1 to Pin#0 or to Pin#5 through a 1K resistor, you can generate transitions for testing purpose.
@ -58,8 +58,8 @@ To display the sketch results on a PC (in a Terminal):
#define FIRST_INPUT 0 #define FIRST_INPUT 0
#define SECOND_INPUT 5 #define SECOND_INPUT 5
volatile uint16_t FirstInputChangeCount=0; /* Volatile since the variable will be updated in interruption */ 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 */ 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) */ SoftSerial MySerial(DEBUG_TX_RX_PIN, DEBUG_TX_RX_PIN, true); /* Tx/Rx on a single Pin !!! (Pin#2) */
@ -72,15 +72,15 @@ void setup()
MySerial.begin(38400); /* Trick: use a "high" data rate (less time wasted in ISR and for transmitting each character) */ MySerial.begin(38400); /* 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(FIRST_INPUT, InterruptFunctionToCall);
VirtualPortNb_=TinyPinChange_RegisterIsr(SECOND_INPUT, InterruptFunctionToCall); VirtualPortNb_ = TinyPinChange_RegisterIsr(SECOND_INPUT, InterruptFunctionToCall);
/* Enable Pin Change for each pin */ /* Enable Pin Change for each pin */
TinyPinChange_EnablePin(FIRST_INPUT); TinyPinChange_EnablePin(FIRST_INPUT);
TinyPinChange_EnablePin(SECOND_INPUT); TinyPinChange_EnablePin(SECOND_INPUT);
MySerial.txMode(); MySerial.txMode();
MySerial.println(F("\n*** Tiny PinChange Demo ***")); MySerial.println(F("\n*** Tiny PinChange Demo (Rising AND Falling edges) ***"));
MySerial.print(F("Pin "));MySerial.print((int)FIRST_INPUT); MySerial.print(F("Pin "));MySerial.print((int)FIRST_INPUT);
MySerial.print(F(" is part of virtual port "));MySerial.println((int)VirtualPortNb); MySerial.print(F(" is part of virtual port "));MySerial.println((int)VirtualPortNb);
@ -88,7 +88,8 @@ void setup()
MySerial.print(F(" is part of virtual port "));MySerial.println((int)VirtualPortNb_); 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("As you can see, virtual port is always port 0 for ATtiny85"));
MySerial.println(F("Remember <TinyPinChange> is also designed for UNO, MEGA and ATtiny84 ;-)")); 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); pinMode(LED_PIN, OUTPUT);
@ -98,14 +99,12 @@ void setup()
/* Function called in interruption in case of change on pins */ /* Function called in interruption in case of change on pins */
void InterruptFunctionToCall(void) void InterruptFunctionToCall(void)
{ {
uint8_t PortChange; if(TinyPinChange_Edge(VirtualPortNb, FIRST_INPUT)) /* Check FIRST_INPUT has changed (falling or rising edge) */
PortChange = TinyPinChange_GetPinEvent(VirtualPortNb);
if(PortChange & TinyPinChange_PinToMsk(FIRST_INPUT)) /* Check FIRST_INPUT has changed */
{ {
FirstInputChangeCount++; /* Rising AND Falling edges are counted */ FirstInputChangeCount++; /* Rising AND Falling edges are counted */
} }
if(PortChange & TinyPinChange_PinToMsk(SECOND_INPUT)) /* Check SECOND_INPUT has changed */
if(TinyPinChange_Edge(VirtualPortNb_, SECOND_INPUT)) /* Check SECOND_INPUT has changed (falling or rising edge) */
{ {
SecondInputChangeCount++; /* Rising AND Falling edges are counted */ SecondInputChangeCount++; /* Rising AND Falling edges are counted */
} }
@ -113,17 +112,17 @@ uint8_t PortChange;
void loop() void loop()
{ {
static boolean State=HIGH, DisplayEnabled=false; static boolean State = HIGH, DisplayEnabled = true;
static uint32_t LedStartMs=millis(), DisplayStartMs=millis(); static uint32_t LedStartMs = millis(), DisplayStartMs = millis();
uint16_t LocalFirstInputChangeCount; uint16_t LocalFirstInputChangeCount;
uint16_t LocalSecondInputChangeCount; uint16_t LocalSecondInputChangeCount;
/* Blink the built-in LED */ /* Blink the built-in LED */
if(millis()-LedStartMs >= 500) if(millis() - LedStartMs >= 500)
{ {
LedStartMs=millis(); LedStartMs = millis();
digitalWrite(LED_PIN, State); digitalWrite(LED_PIN, State);
State=!State; /* State will be inverted at the next digitalWrite() */ State = !State; /* State will be inverted at the next digitalWrite() */
} }
/* Get command from single wire SoftSerial */ /* Get command from single wire SoftSerial */
@ -132,19 +131,19 @@ uint16_t LocalSecondInputChangeCount;
switch(MySerial.read()) switch(MySerial.read())
{ {
case '0': case '0':
DisplayEnabled=false; DisplayEnabled = false;
break; break;
case '1': case '1':
DisplayEnabled=true; DisplayEnabled = true;
break; break;
} }
} }
/* Diplay Transition numbers every second */ /* Diplay Transition numbers every second */
if((millis()-DisplayStartMs >= 1000) && DisplayEnabled) if((millis() - DisplayStartMs >= 1000) && DisplayEnabled)
{ {
DisplayStartMs=millis(); DisplayStartMs = millis();
noInterrupts(); /* Mandatory since counters are 16 bits */ noInterrupts(); /* Mandatory since counters are 16 bits */
LocalFirstInputChangeCount = FirstInputChangeCount; LocalFirstInputChangeCount = FirstInputChangeCount;
LocalSecondInputChangeCount = SecondInputChangeCount; LocalSecondInputChangeCount = SecondInputChangeCount;

View File

@ -0,0 +1,158 @@
/*
_____ ____ __ _ ____ _ _ _ _
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 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(38400); /* 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 >= 500)
{
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 >= 1000) && 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();
}
}

View File

@ -0,0 +1,158 @@
/*
_____ ____ __ _ ____ _ _ _ _
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 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(38400); /* 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 >= 500)
{
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 >= 1000) && 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();
}
}

View File

@ -17,12 +17,18 @@ TinyPinChange_EnablePin KEYWORD2
TinyPinChange_ActiveBroche KEYWORD2 TinyPinChange_ActiveBroche KEYWORD2
TinyPinChange_DisablePin KEYWORD2 TinyPinChange_DisablePin KEYWORD2
TinyPinChange_DesactiveBroche KEYWORD2 TinyPinChange_DesactiveBroche KEYWORD2
TinyPinChange_GetPinEvent KEYWORD2 TinyPinChange_GetPortEvent KEYWORD2
TinyPinChange_RetourneEvenemenPort KEYWORD2 TinyPinChange_RetourneEvenemenPort KEYWORD2
TinyPinChange_GetPinCurSt KEYWORD2 TinyPinChange_GetCurPortSt KEYWORD2
TinyPinChange_RetourneEtatCourantPort KEYWORD2 TinyPinChange_RetourneEtatCourantPort KEYWORD2
TinyPinChange_PinToMsk KEYWORD2 TinyPinChange_PinToMsk KEYWORD2
TinyPinChange_MasqueDeBroche KEYWORD2 TinyPinChange_MasqueDeBroche KEYWORD2
TinyPinChange_Edge KEYWORD2
TinyPinChange_Front KEYWORD2
TinyPinChange_RisingEdge KEYWORD2
TinyPinChange_FrontMontant KEYWORD2
TinyPinChange_FallingEdge KEYWORD2
TinyPinChange_FrontDescendant KEYWORD2
####################################### #######################################
# Constants (LITERAL1) # Constants (LITERAL1)

View File

@ -20,12 +20,12 @@
/* Define here the PIN to use with Tiny Soft PWM */ /* Define here the PIN to use with Tiny Soft PWM */
/* Unused Pin(s) SHALL be commented */ /* Unused Pin(s) SHALL be commented */
/*************************************************/ /*************************************************/
//#define TINY_SOFT_PWM_USES_P0 #define TINY_SOFT_PWM_USES_P0
#define TINY_SOFT_PWM_USES_P1 #define TINY_SOFT_PWM_USES_P1
#define TINY_SOFT_PWM_USES_P2 #define TINY_SOFT_PWM_USES_P2
//#define TINY_SOFT_PWM_USES_P3 /* /!\ used for USB on DigiSpark: do not use it for PWM if DigiUSB is also used /!\ */ //#define TINY_SOFT_PWM_USES_P3 /* /!\ used for USB on DigiSpark: do not use it for PWM if DigiUSB is also used /!\ */
//#define TINY_SOFT_PWM_USES_P4 /* /!\ used for USB on DigiSpark: do not use it for PWM if DigiUSB is also used /!\ */ //#define TINY_SOFT_PWM_USES_P4 /* /!\ used for USB on DigiSpark: do not use it for PWM if DigiUSB is also used /!\ */
#define TINY_SOFT_PWM_USES_P5 //#define TINY_SOFT_PWM_USES_P5

View File

@ -1,178 +0,0 @@
/****************************************************************************/
/* PROJECT: All based on ATtinyX5, ATtinyX4, ATmega328P */
/* MODULE: PinChange */
/* VERSION: 1.0 */
/* DATE: 30/01/2011 */
/* TARGET: ATtinyX5, ATtinyX4, ATmega328P */
/* COMPILER: WinAvr (avr-gcc) */
/* IDE: AVR Studio 4 */
/* PROGRAMER: AVR-JTAG-ICE MKII */
/* 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 */
/*************************************************************************
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_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || !(defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__))
DECLARE_PIN_CHANGE_ISR(1)
#endif
#if !defined(__AVR_ATtiny24__) && !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(__AVR_ATtiny25__) && !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__)
DECLARE_PIN_CHANGE_ISR(2)
#endif
/*************************************************************************
PUBLIC FUNCTIONS
*************************************************************************/
/*********************************************************************
PinChange Initialization Function
Input:
Void
Output:
Void
*********************************************************************/
void TinyPinChange_Init(void)
{
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
/* ATtinyX5 */
PinChange.Port[0].PinCur=PC_PIN0&PC_PCMSK0; //PINB,
PinChange.Port[0].PinPrev=PinChange.Port[0].PinCur;
#else
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
/* ATtinyX4 */
PinChange.Port[0].PinCur=PC_PIN0&PC_PCMSK0;//PINA;
PinChange.Port[0].PinPrev=PinChange.Port[0].PinCur;
PinChange.Port[1].PinCur=PC_PIN1&PC_PCMSK1;//PINB;
PinChange.Port[1].PinPrev=PinChange.Port[1].PinCur;
#else
/* UNO */
PinChange.Port[0].PinCur=PC_PIN0&PC_PCMSK0;//PINB;
PinChange.Port[0].PinPrev=PinChange.Port[0].PinCur;
PinChange.Port[1].PinCur=PC_PIN1&PC_PCMSK1;//PINC;
PinChange.Port[1].PinPrev=PinChange.Port[1].PinCur;
PinChange.Port[2].PinCur=PC_PIN2&PC_PCMSK2;//PIND;
PinChange.Port[2].PinPrev=PinChange.Port[2].PinCur;
#endif
#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);
}
void TinyPinChange_EnablePin(uint8_t Pin)
{
if(digitalPinToPCICR(Pin))
{
*digitalPinToPCICR(Pin) |= _BV(digitalPinToPCICRbit(Pin));
*digitalPinToPCMSK(Pin) |= _BV(digitalPinToPCMSKbit(Pin));
}
}
void TinyPinChange_DisablePin(uint8_t Pin)
{
if(digitalPinToPCICR(Pin))
{
*digitalPinToPCMSK(Pin) &= (_BV(digitalPinToPCMSKbit(Pin)) ^ 0xFF);
}
}
/*********************************************************************
PinChange GetEvent Function
Input:
Idx: Index of the Port
Output:
The bits which have been changed in the port
*********************************************************************/
uint8_t TinyPinChange_GetPinEvent(uint8_t VirtualPortIdx)
{
return(PinChange.Port[VirtualPortIdx].Event);
}
/*********************************************************************
PinChange GetPinCurSt Function
Input:
Idx: Index of the Port
Output:
Current Pin Status of the port
*********************************************************************/
uint8_t TinyPinChange_GetPinCurSt(uint8_t VirtualPortIdx)
{
return(PinChange.Port[VirtualPortIdx].PinCur);
}

View File

@ -1,67 +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 device ATmega238P (UNO), ATtiny84, ATtiny85
*
* http://p.loussouarn.free.fr
*/
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <inttypes.h>
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
/* ATtinyX5 */
#define PIN_CHG_PORT_NB 1
#define DigitalPinToPortIdx(p) 0
#define PC_PIN0 PINB
#define PC_PCMSK0 PCMSK
#else
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
/* 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
/* 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
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_GetPinEvent(uint8_t VirtualPortIdx);
uint8_t TinyPinChange_GetPinCurSt(uint8_t VirtualPortIdx);
#define TinyPinChange_PinToMsk(Pin) _BV(digitalPinToPCMSKbit(Pin))
/*******************************************************/
/* 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_GetPinEvent
#define TinyPinChange_RetourneEtatCourantPort TinyPinChange_GetPinCurSt
#define TinyPinChange_MasqueDeBroche TinyPinChange_PinToMsk
#endif