Compare commits

..

No commits in common. "master" and "v1.5.8B" have entirely different histories.

3656 changed files with 13294 additions and 10040 deletions

View File

@ -1,23 +1,19 @@
DigistumpArduino
================
Files to add Digistump support (Digispark, Pro, DigiX) to Arduino 1.6.X (1.6.4+)
Files to add Digistump support (Digispark, Pro, DigiX) to Arduino 1.5.X (1.5.7+)
**These files are designed for install via the Arduino Boards Manager:**
Board manager URL: http://digistump.com/package_digistump_index.json
**Binary downloads of the bundled IDE can be found here:** https://github.com/digistump/DigistumpArduino/releases/tag/v1.5.8A
**Full Install Instructions:**
To manually install:
Digispark: http://digistump.com/wiki/digispark/tutorials/connecting
Place digistump folder inside the Arduino /hardware folder.
Digispark Pro: http://digistump.com/wiki/digispark/tutorials/connectingpro
DigiX: http://digistump.com/wiki/digix/tutorials/software
**To compile:**
Micronucleus is the only executable in these packages that is pre-compiled:
To compile tools for other platforms or from scratch use:
Micronucleus: https://github.com/micronucleus/micronucleus/tree/80419704f68bf0783c5de63a6a4b9d89b45235c7
Dependencies: libusb and possibly lib32stdc on linux - (on ubuntu get it by issuing: apt-get install lib32stdc++6)
AVR-Dummy: https://github.com/digistump/avr-dummy
ld from a more recent install of avr-gcc then Arduino uses

View File

@ -1,18 +0,0 @@
#include <new.h>
void * operator new(size_t size)
{
return malloc(size);
}
void operator delete(void * ptr)
{
free(ptr);
}
int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);};
void __cxa_guard_release (__guard *g) {*(char *)g = 1;};
void __cxa_guard_abort (__guard *) {};
void __cxa_pure_virtual(void) {};

View File

@ -1,22 +0,0 @@
/* Header to define new/delete operators as they aren't provided by avr-gcc by default
Taken from http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=59453
*/
#ifndef NEW_H
#define NEW_H
#include <stdlib.h>
void * operator new(size_t size);
void operator delete(void * ptr);
__extension__ typedef int __guard __attribute__((mode (__DI__)));
extern "C" int __cxa_guard_acquire(__guard *);
extern "C" void __cxa_guard_release (__guard *);
extern "C" void __cxa_guard_abort (__guard *);
extern "C" void __cxa_pure_virtual(void);
#endif

View File

@ -1,22 +0,0 @@
#include <DigiCDC.h>
void setup() {
// initialize the digital pin as an output.
SerialUSB.begin();
pinMode(1,OUTPUT);
}
// the loop routine runs over and over again forever:
void loop() {
//turns led on and off based on sending 0 or 1 from serial terminal
if (SerialUSB.available()) {
char input = SerialUSB.read();
if(input == '0')
digitalWrite(1,LOW);
else if(input == '1')
digitalWrite(1,HIGH);
}
SerialUSB.delay(100); // keep usb alive // can alos use SerialUSB.refresh();
}

View File

@ -1,21 +0,0 @@
#include <DigiCDC.h>
void setup() {
// initialize the digital pin as an output.
SerialUSB.begin();
}
// the loop routine runs over and over again forever:
void loop() {
if (SerialUSB.available()) {
SerialUSB.write(SerialUSB.read());
}
//SerialUSB.delay(10);
/*
if you don't call a SerialUSB function (write, print, read, available, etc)
every 10ms or less then you must throw in some SerialUSB.refresh();
for the USB to keep alive - also replace your delays - ie. delay(100);
with SerialUSB.delays ie. SerialUSB.delay(100);
*/
}

View File

@ -1,25 +0,0 @@
#include <DigiCDC.h>
void setup() {
// initialize the digital pin as an output.
SerialUSB.begin();
/*
remember the SerialUSB starts as soon as you call begin
and doesn't restart the board when you open the serial monitor
(like the uno does) - so if you print to it and you don't
have a serial monitor open that text is lost.
*/
}
// the loop routine runs over and over again forever:
void loop() {
SerialUSB.println(F("TEST!")); //wrap your strings in F() to save ram!
//SerialUSB.delay(10);
/*
if you don't call a SerialUSB function (write, print, read, available, etc)
every 10ms or less then you must throw in some SerialUSB.refresh();
for the USB to keep alive - also replace your delays - ie. delay(100);
with SerialUSB.delays ie. SerialUSB.delay(100);
*/
}

View File

@ -1,22 +0,0 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

View File

@ -1,215 +0,0 @@
#################
## Eclipse
#################
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
x64/
build/
[Bb]in/
[Oo]bj/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.log
*.scc
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
*.ncrunch*
.*crunch*.local.xml
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.Publish.xml
*.pubxml
# NuGet Packages Directory
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
#packages/
# Windows Azure Build Output
csx
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.[Pp]ublish.xml
*.pfx
*.publishsettings
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
App_Data/*.mdf
App_Data/*.ldf
#############
## Windows detritus
#############
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Mac crap
.DS_Store
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist/
build/
eggs/
parts/
var/
sdist/
develop-eggs/
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg

View File

@ -1,16 +0,0 @@
Change Log for IRLib an Arduino library for infrared encoding and decoding
Copyright 2013 by Chris Young http://cyborg5.com
April 2013 Version 1.1 Constructor of IRsendBase now initializes output
pin and forces it low immediately.
New IRrecv::No_Output() method initializes output
pin and forces it low. Use this in sketches which
receive only by the have output hardware connected.
Added examples IRservo and IRserial_remote
February 2013 Version 1.0a Removed debugging test switch which was accidentally
left on in file "IRLib.h"
January 2013 Version 1.0 Initial Release

View File

@ -1,988 +0,0 @@
/* IRLib.cpp from IRLib an Arduino library for infrared encoding and decoding
* Version 1.1 April 2013
* Copyright 2013 by Chris Young http://cyborg5.com
*
* Port to Digispark (size optimization) August 2013
* by RC Navy http://p.loussouarn.free.fr
*
* This library is a major rewrite of IRemote by Ken Shirriff which was covered by
* GNU LESSER GENERAL PUBLIC LICENSE which as I read it allows me to make modified versions.
* That same license applies to this modified version. See his original copyright below.
* The latest Ken Shirriff code can be found at https://github.com/shirriff/Arduino-IRremote
* My purpose was to reorganize the code to make it easier to add or remove protocols.
* As a result I have separated the act of receiving a set of raw timing codes from the act of decoding them
* by making them separate classes. That way the receiving aspect can be more black box and implementers
* of decoders and senders can just deal with the decoding of protocols.
* Also added provisions to make the classes base classes that could be extended with new protocols
* which would not require recompiling of the original library nor understanding of its detailed contents.
* Some of the changes were made to reduce code size such as unnecessary use of long versus bool.
* Some changes were just my weird programming style. Also extended debugging information added.
*/
/*
* IRremote
* Version 0.1 July, 2009
* Copyright 2009 Ken Shirriff
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com
*
* Interrupt code based on NECIRrcv by Joe Knapp
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
*/
#include "IRLib.h"
#include "IRLibMatch.h"
#include <Arduino.h>
/*
* Returns a pointer to a flash stored string that is the name of the protocol received.
*/
#if defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
const char *Pnames(IRTYPES Type) {
return(NULL);
};
#else
const __FlashStringHelper *Pnames(IRTYPES Type) {
if(Type>LAST_PROTOCOL) Type=UNKNOWN;
const __FlashStringHelper *Names[LAST_PROTOCOL+1]={F("Unknown"),
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NEC)
F("NEC")
#endif
#if defined(ALL_IR_PROTOCOL)
,
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_SONY)
F("Sony")
#endif
#if defined(ALL_IR_PROTOCOL)
,
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC5)
F("RC5")
#endif
#if defined(ALL_IR_PROTOCOL)
,
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC6)
F("RC6")
#endif
#if defined(ALL_IR_PROTOCOL)
,
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_PANASONIC_OLD)
F("Panasonic Old")
#endif
#if defined(ALL_IR_PROTOCOL)
,
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_JVC)
F("JVC")
#endif
#if defined(ALL_IR_PROTOCOL)
,
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NECX)
F("NECx")
#endif
#if defined(ALL_IR_PROTOCOL)
,
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_HASH_CODE)
F("Hash Code")
#endif
};
#if defined(ALL_IR_PROTOCOL)
return Names[Type];
#else
return Names[!!Type];
#endif
};
#endif
#define RC5_T1 889
#define RC5_RPT_LENGTH 46000
#define RC6_HDR_MARK 2666
#define RC6_HDR_SPACE 889
#define RC6_T1 444
#ifdef USE_IR_SEND
#define TOPBIT 0x80000000
/*
* The IRsend classes contain a series of methods for sending various protocols.
* Each of these begin by calling enableIROut(int kHz) to set the carrier frequency.
* It then calls mark(int usec) and space(inc usec) to transmit marks and
* spaces of varying length of microseconds however the protocol defines.
*/
/*
* Most of the protocols have a header consisting of a mark/space of a particular length followed by
* a series of variable length mark/space signals. Depending on the protocol they very the links of the
* mark or the space to indicate a data bit of "0" or "1". Most also end with a stop bit of "1".
* The basic structure of the sending and decoding these protocols led to lots of redundant code.
* Therefore I have implemented generic sending and decoding routines. You just need to pass a bunch of customized
* parameters and it does the work. This reduces compiled code size with only minor speed degradation.
* You may be able to implement additional protocols by simply passing the proper values to these generic routines.
* The decoding routines do not encode stop bits. So you have to tell this routine whether or not to send one.
*/
void IRsendBase::sendGeneric(unsigned long data, int Num_Bits, int Head_Mark, int Head_Space, int Mark_One, int Mark_Zero, int Space_One, int Space_Zero, int mHz, bool Use_Stop) {
data = data << (32 - Num_Bits);
enableIROut(mHz);
//Some protocols do not send a header when sending repeat codes. So we pass a zero value to indicate skipping this.
if(Head_Mark) mark(Head_Mark);
if(Head_Space) space(Head_Space);
for (int i = 0; i <Num_Bits; i++) {
if (data & TOPBIT) {
mark(Mark_One); space(Space_One);
}
else {
mark(Mark_Zero); space(Space_Zero);
}
data <<= 1;
}
if (Use_Stop) mark(Mark_One); space(0) ; //stop bit of "1"
};
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NEC)
void IRsendNEC::send(unsigned long data)
{
ATTEMPT_MESSAGE(F("sending NEC"));
if (data==REPEAT) {
mark (564* 16); space (564*4); mark(564);space (96000);
}
else {
sendGeneric(data,32, 564*16, 564*8, 564, 564, 564*3, 564, 38, true);
}
};
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_SONY)
/*
* Sony is backwards from most protocols. It uses a variable length mark and a fixed length space rather than
* a fixed mark and a variable space. Our generic send will still work. According to the protocol you must send
* Sony commands at least three times so we automatically do it here.
*/
void IRsendSony::send(unsigned long data, int nbits) {
for(int i=0; i<3;i++)
sendGeneric(data,nbits, 600*4, 600, 600*2, 600, 600, 600, 40, false);
};
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NECX)
/*
* This next section of send routines were added by Chris Young. They all use the generic send.
*/
void IRsendNECx::send(unsigned long data)
{
sendGeneric(data,32, 564*8, 564*8, 564, 564, 564*3, 564, 38, true);
};
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_PANASONIC_OLD)
void IRsendPanasonic_Old::send(unsigned long data)
{
sendGeneric(data,22, 833*4, 833*4, 833, 833, 833*3, 833,57, true);
};
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_JVC)
/*
* JVC omits the Mark/space header on repeat sending. Therefore we multiply it by 0 if it's a repeat.
* The only device I had to test this protocol was an old JVC VCR. It would only work if at least
* 2 frames are sent separated by 45us of "space". Therefore you should call this routine once with
* "First=true"and it will send a first frame followed by one repeat frame. If First== false,
* it will only send a single repeat frame.
*/
void IRsendJVC::send(unsigned long data, bool First)
{
sendGeneric(data, 16,525*16*First, 525*8*First, 525, 525,525*3, 525, 38, true);
delayMicroseconds(45);
if(First) sendGeneric(data, 16,0,0, 525, 525,525*3, 525, 38, true);
}
#endif
/*
* The remaining protocols require special treatment. They were in the original IRremote library.
*/
void IRsendRaw::send(unsigned int buf[], int len, int hz)
{
enableIROut(hz);
for (int i = 0; i < len; i++) {
if (i & 1) {
space(buf[i]);
}
else {
mark(buf[i]);
}
}
space(0); // Just to be sure
}
/*
* The RC5 protocol uses a phase encoding of data bits. A space/mark pair indicates "1"
* and a mark/space indicates a "0". It begins with a single "1" bit which is not encoded
* in the data. The high order data bit is a toggle bit that indicates individual
* keypresses. You must toggle this bit yourself when sending data.
*/
void IRsendRC5::send(unsigned long data)
{
enableIROut(36);
data = data << (32 - 13);
mark(RC5_T1); // First start bit
//Note: Original IRremote library incorrectly assumed second bit was always a "1"
//bit patterns from this decoder are not backward compatible with patterns produced
//by original library. Ucomment the following two lines to maintain backward compatibility.
//space(RC5_T1); // Second start bit
//mark(RC5_T1); // Second start bit
for (int i = 0; i < 13; i++) {
if (data & TOPBIT) {
space(RC5_T1); mark(RC5_T1);// 1 is space, then mark
}
else {
mark(RC5_T1); space(RC5_T1);// 0 is mark, then space
}
data <<= 1;
}
space(0); // Turn off at end
}
/*
* The RC6 protocol also phase encodes databits although the phasing is opposite of RC5.
*/
void IRsendRC6::send(unsigned long data, int nbits)
{
enableIROut(36);
data = data << (32 - nbits);
mark(RC6_HDR_MARK); space(RC6_HDR_SPACE);
mark(RC6_T1); space(RC6_T1);// start bit "1"
int t;
for (int i = 0; i < nbits; i++) {
if (i == 3) {
t = 2 * RC6_T1; // double-wide trailer bit
}
else {
t = RC6_T1;
}
if (data & TOPBIT) {
mark(t); space(t);//"1" is a Mark/space
}
else {
space(t); mark(t);//"0" is a space/Mark
}
data <<= 1;
}
space(0); // Turn off at end
}
/*
* This method can be used to send any of the supported types except for raw and hash code.
* There is no hash code send possible. You can call sendRaw directly if necessary.
*/
void IRsend::send(IRTYPES Type, unsigned long data, int nbits) {
switch(Type) {
case NEC: IRsendNEC::send(data); break;
case SONY: IRsendSony::send(data,nbits); break;
case RC5: IRsendRC5::send(data); break;
case RC6: IRsendRC6::send(data,nbits); break;
case PANASONIC_OLD: IRsendPanasonic_Old::send(data); break;
case NECX: IRsendNECx::send(data); break;
case JVC: IRsendJVC::send(data,(bool)nbits); break;
}
}
#endif
/*
* Although I tried to keep all of the interrupt handling code at the bottom of this file
* so you didn't have to mess with it if you didn't want to, I needed to move this definition
* forwarded so it could be used by IRdecodeBase constructor.
*/
// receiver states
enum rcvstate_t {STATE_UNKNOWN, STATE_IDLE, STATE_MARK, STATE_SPACE, STATE_STOP};
// information for the interrupt handler
typedef struct {
uint8_t recvpin; // pin for IR data from detector
rcvstate_t rcvstate; // state machine
uint8_t blinkflag; // TRUE to enable blinking of pin 13 on IR processing
unsigned int timer; // state timer, counts 50uS ticks.
unsigned int rawbuf[RAWBUF]; // raw data
uint8_t rawlen; // counter of entries in rawbuf
}
irparams_t;
volatile irparams_t irparams;
/*
* We've chosen to separate the decoding routines from the receiving routines to isolate
* the technical hardware and interrupt portion of the code which should never need modification
* from the protocol decoding portion that will likely be extended and modified.
*/
IRdecodeBase::IRdecodeBase(void) {
rawbuf=(volatile unsigned int*)irparams.rawbuf;
Reset();
};
/*
* Normally the decoder uses irparams.rawbuf but if you want to resume receiving while
* still decoding you can define a separate buffer and pass the address here.
* Then IRrecv::GetResults will copy the raw values from its buffer to yours allowing you to
* call IRrecv::resume immediately before you call decode.
*/
void IRdecodeBase::UseExtnBuf(void *P){
rawbuf=(volatile unsigned int*)P;
};
/*
* Copies rawbuf and rawlen from one decoder to another. See IRhashdecode example
* for usage.
*/
void IRdecodeBase::copyBuf (IRdecodeBase *source){
memcpy((void *)rawbuf,(const void *)source->rawbuf,sizeof(irparams.rawbuf));
rawlen=source->rawlen;
};
/*
* This routine is actually quite useful. See the Samsung36 sketch in the examples
*/
bool IRdecodeBase::decode(void) {
return false;
};
void IRdecodeBase::Reset(void) {
decode_type= UNKNOWN;
value=0;
bits=0;
rawlen=0;
};
/*
* This method dumps useful information about the decoded values.
*/
void IRdecodeBase::DumpResults(void) {
int i;
if(decode_type<=LAST_PROTOCOL){
Serial.print(F("Decoded ")); Serial.print(Pnames(decode_type));
Serial.print(F(": Value:")); Serial.print(value, HEX);
};
#ifdef DETAILLED_DUMP
Serial.print(F(" (")); Serial.print(bits, DEC); Serial.println(F(" bits)"));
Serial.print(F("Raw samples(")); Serial.print(rawlen, DEC);
Serial.print(F("): Gap:")); Serial.println(Interval_uSec(0), DEC);
Serial.print(F(" Head: m")); Serial.print(Interval_uSec(1), DEC);
Serial.print(F(" s")); Serial.println(Interval_uSec(2), DEC);
int LowSpace= 32767; int LowMark= 32767;
int HiSpace=0; int HiMark= 0;
for (i = 3; i < rawlen; i++) {
int interval= Interval_uSec(i);
if (i % 2) {
LowMark=min(LowMark, interval); HiMark=max(HiMark, interval);
Serial.print(i/2-1,DEC); Serial.print(F(":m"));
}
else {
if(interval>0)LowSpace=min(LowSpace, interval); HiSpace=max (HiSpace, interval);
Serial.print(F(" s"));
}
Serial.print(interval, DEC);
int j=i-1;
if ((j % 2)==1)Serial.print(F("\t"));
if ((j % 4)==1)Serial.print(F("\t "));
if ((j % 8)==1)Serial.println();
if ((j % 32)==1)Serial.println();
}
Serial.println();
Serial.print(F("Mark min:")); Serial.print(LowMark,DEC);Serial.print(F("\t max:")); Serial.println(HiMark,DEC);
Serial.print(F("Space min:")); Serial.print(LowSpace,DEC);Serial.print(F("\t max:")); Serial.println(HiSpace,DEC);
#endif
Serial.println();
}
/*
* This handy little routine converts ticks from rawbuf[index] into uSec intervals adjusting for the
* Mark/space bias.
*/
unsigned long IRdecodeBase::Interval_uSec(int index)
{
return rawbuf[index]*USECPERTICK+( (index%2)?-MARK_EXCESS: MARK_EXCESS);
};
/*
* Again we use a generic routine because most protocols have the same basic structure. However we need to
* indicate whether or not the protocol varies the length of the mark or the space to indicate a "0" or "1".
* If "Mark_One" is zero. We assume that the length of the space varies. If "Mark_One" is not zero then
* we assume that the length of Mark varies and the value passed as "Space_Zero" is ignored.
* When using variable length Mark, assumes Head_Space==Space_One. If it doesn't, you need a specialized decoder.
*/
bool IRdecodeBase::decodeGeneric(/*int*/int8_t Raw_Count, int Head_Mark,int Head_Space, int Mark_One, int Mark_Zero, int Space_One,int Space_Zero) {
// If raw samples count or head mark are zero then don't perform these tests.
// Some protocols need to do custom header work.
long data = 0; /*int*/int8_t Max; /*int*/int8_t offset;
if (Raw_Count) {if (rawlen != Raw_Count) return RAW_COUNT_ERROR;}
if (Head_Mark) {if (!MATCH_MARK(rawbuf[1],Head_Mark)) return HEADER_MARK_ERROR;}
if (Head_Space) {if (!MATCH_SPACE(rawbuf[2],Head_Space)) return HEADER_SPACE_ERROR;}
if (Mark_One) {//Length of a mark indicates data "0" or "1". Space_Zero is ignored.
offset=2;//skip initial gap plus header Mark.
Max=rawlen;
while (offset < Max) {
if (!MATCH_SPACE(rawbuf[offset], Space_One)) return DATA_SPACE_ERROR;
offset++;
if (MATCH_MARK(rawbuf[offset], Mark_One)) {
data = (data << 1) | 1;
}
else if (MATCH_MARK(rawbuf[offset], Mark_Zero)) {
data <<= 1;
}
else return DATA_MARK_ERROR;
offset++;
}
bits = (offset - 1) / 2;
}
else {//Mark_One was 0 therefore length of a space indicates data "0" or "1".
Max=rawlen-1; //ignore stop bit
offset=3;//skip initial gap plus two header items
while (offset < Max) {
if (!MATCH_MARK (rawbuf[offset],Mark_Zero)) return DATA_MARK_ERROR;
offset++;
if (MATCH_SPACE(rawbuf[offset],Space_One)) {
data = (data << 1) | 1;
}
else if (MATCH_SPACE (rawbuf[offset],Space_Zero)) {
data <<= 1;
}
else return DATA_SPACE_ERROR;
offset++;
}
bits = (offset - 1) / 2 -1;//didn't encode stop bit
}
// Success
value = data;
return true;
}
/*
* This routine has been modified significantly from the original IRremote.
* It assumes you've already called IRrecvBase::GetResults and it was true.
* The purpose of GetResults is to determine if a complete set of signals
* has been received. It then copies the raw data into your decode_results
* structure. By moving the test for completion and the copying of the buffer
* outside of this "decode" method you can use the individual decode
* methods or make your own custom "decode" without checking for
* protocols you don't use.
* Note: Don't forget to call IRrecvBase::resume(); after decoding is complete.
*/
bool IRdecode::decode(void) {
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NEC)
if (IRdecodeNEC::decode()) return true;
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_SONY)
if (IRdecodeSony::decode()) return true;
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC5)
if (IRdecodeRC5::decode()) return true;
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC6)
if (IRdecodeRC6::decode()) return true;
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_PANASONIC_OLD)
if (IRdecodePanasonic_Old::decode()) return true;
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NECX)
if (IRdecodeNECx::decode()) return true;
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_JVC)
if (IRdecodeJVC::decode()) return true;
#endif
//Deliberately did not add hash code decoding. If you get decode_type==UNKNOWN and
// you want to know a hash code you can call IRhash::decode() yourself.
// BTW This is another reason we separated IRrecv from IRdecode.
return false;
}
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NEC)
#define NEC_RPT_SPACE 2250
bool IRdecodeNEC::decode(void) {
ATTEMPT_MESSAGE(F("NEC"));
// Check for repeat
if (rawlen == 4 && MATCH_SPACE(rawbuf[2], NEC_RPT_SPACE) &&
MATCH_MARK(rawbuf[3],564)) {
bits = 0;
value = REPEAT;
decode_type = NEC;
return true;
}
if(!decodeGeneric(68, 564*16, 564*8, 0, 564, 564*3, 564)) return false;
decode_type = NEC;
return true;
}
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_SONY)
// According to http://www.hifi-remote.com/johnsfine/DecodeIR.html#Sony8
// Sony protocol can only be 8, 12, 15, or 20 bits in length.
bool IRdecodeSony::decode(void) {
ATTEMPT_MESSAGE(F("Sony"));
if(rawlen!=2*8+2 && rawlen!=2*12+2 && rawlen!=2*15+2 && rawlen!=2*20+2) return RAW_COUNT_ERROR;
if(!decodeGeneric(0, 600*4, 600, 600*2, 600, 600,0)) return false;
decode_type = SONY;
return true;
}
#endif
/*
* The next several decoders were added by Chris Young. They illustrate some of the special cases
* that can come up when decoding using the generic decoder.
*/
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_PANASONIC_OLD)
/*
* A very good source for protocol information is http://www.hifi-remote.com/johnsfine/DecodeIR.html
* I used that information to understand what they call the "Panasonic old" protocol which is used by
* Scientific Atlanta cable boxes. That website uses a very strange notation called IRP notation.
* For this protocol, the notation was:
* {57.6k,833}<1,-1|1,-3>(4,-4,D:5,F:6,~D:5,~F:6,1,-???)+
* This indicates that the frequency is 57.6, the base length for the pulse is 833
* The first part of the <x,-x|x,-x> section tells you what a "0" is and the second part
* tells you what a "1" is. That means "0" is 833 on, 833 off while an "1" is 833 on
* followed by 833*3=2499 off. The section in parentheses tells you what data gets sent.
* The protocol begins with header consisting of 4*833 on and 4*833 off. The other items
* describe what the remaining data bits are.
* It reads as 5 device bits followed by 6 function bits. You then repeat those bits complemented.
* It concludes with a single "1" bit followed by and an undetermined amount of blank space.
* This makes the entire protocol 5+6+5+6= 22 bits long since we don't encode the stop bit.
* The "+" at the end means you only need to send it once and it can repeat as many times as you want.
*/
bool IRdecodePanasonic_Old::decode(void) {
ATTEMPT_MESSAGE(F("Panasonic_Old"));
if(!decodeGeneric(48,833*4,833*4,0,833,833*3,833)) return false;
/*
* The protocol spec says that the first 11 bits described the device and function.
* The next 11 bits are the same thing only it is the logical Bitwise complement.
* Many protocols have such check features in their definition but our code typically doesn't
* perform these checks. For example NEC's least significant 8 bits are the complement of
* of the next more significant 8 bits. While it's probably not necessary to error check this,
* here is some sample code to show you how.
*/
long S1= (value & 0x0007ff); // 00 0000 0000 0111 1111 1111 //00000 000000 11111 111111
long S2= (value & 0x3ff800)>> 11; // 11 1111 1111 1000 0000 0000 //11111 111111 00000 000000
S2= (~S2) & 0x0007ff;
if (S1!=S2) {REJECTION_MESSAGE(F("inverted bit redundancy")); return false;};
// Success
decode_type = PANASONIC_OLD;
return true;
}
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NECX)
bool IRdecodeNECx::decode(void) {
ATTEMPT_MESSAGE(F("NECx"));
if(!decodeGeneric(68,564*8,564*8,0,564,564*3,564)) return false;
decode_type = NECX;
return true;
}
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_JVC)
// JVC does not send any header if there is a repeat.
bool IRdecodeJVC::decode(void) {
ATTEMPT_MESSAGE(F("JVC"));
if(!decodeGeneric(36,525*16,525*8,0,525,525*3,525))
{
ATTEMPT_MESSAGE(F("JVC Repeat"));
if (rawlen==34)
{
if(!decodeGeneric(0,525,0,0,525,525*3,525))
{REJECTION_MESSAGE(F("JVC repeat failed generic")); return false;}
else {
//If this is a repeat code then IRdecodeBase::decode fails to add the most significant bit
if (MATCH_SPACE(rawbuf[4],(525*3)))
{
value |= 0x8000;
}
else
{
if (!MATCH_SPACE(rawbuf[4],525)) return DATA_SPACE_ERROR;
}
}
bits++;
}
else return RAW_COUNT_ERROR;
}
decode_type =JVC;
return true;
}
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC5) || (MY_IR_PROTOCOL == PROTO_RC6)
/*
* The remaining protocols from the original IRremote library require special handling
* This routine gets one undecoded level at a time from the raw buffer.
* The RC5/6 decoding is easier if the data is broken into time intervals.
* E.g. if the buffer has MARK for 2 time intervals and SPACE for 1,
* successive calls to getRClevel will return MARK, MARK, SPACE.
* offset and used are updated to keep track of the current position.
* t1 is the time interval for a single bit in microseconds.
* Returns ERROR if the measured time interval is not a multiple of t1.
*/
IRdecodeRC::RCLevel IRdecodeRC::getRClevel(int *offset, int *used, int t1) {
if (*offset >= rawlen) {
// After end of recorded buffer, assume SPACE.
return SPACE;
}
int width = rawbuf[*offset];
IRdecodeRC::RCLevel val;
if ((*offset) % 2) val=MARK; else val=SPACE;
int correction = (val == MARK) ? MARK_EXCESS : - MARK_EXCESS;
int avail;
if (MATCH(width, t1 + correction)) {
avail = 1;
}
else if (MATCH(width, 2*t1 + correction)) {
avail = 2;
}
else if (MATCH(width, 3*t1 + correction)) {
avail = 3;
}
else {
return ERROR;
}
(*used)++;
if (*used >= avail) {
*used = 0;
(*offset)++;
}
#ifdef DEBUG
if (val == MARK) Serial.println("MARK"); else Serial.println("SPACE");
#endif
return val;
}
#endif
#define MIN_RC5_SAMPLES 11
#define MIN_RC6_SAMPLES 1
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC5)
bool IRdecodeRC5::decode(void) {
ATTEMPT_MESSAGE(F("RC5"));
if (rawlen < MIN_RC5_SAMPLES + 2) return RAW_COUNT_ERROR;
int offset = 1; // Skip gap space
long data = 0;
int used = 0;
// Get start bits
if (getRClevel(&offset, &used, RC5_T1) != MARK) return HEADER_MARK_ERROR;
//Note: Original IRremote library incorrectly assumed second bit was always a "1"
//bit patterns from this decoder are not backward compatible with patterns produced
//by original library. Ucomment the following two lines to maintain backward compatibility.
//if (getRClevel(&offset, &used, RC5_T1) != SPACE) return HEADER_SPACE_ERROR;
//if (getRClevel(&offset, &used, RC5_T1) != MARK) return HEADER_MARK_ERROR;
int nbits;
for (nbits = 0; offset < rawlen; nbits++) {
RCLevel levelA = getRClevel(&offset, &used, RC5_T1);
RCLevel levelB = getRClevel(&offset, &used, RC5_T1);
if (levelA == SPACE && levelB == MARK) {
// 1 bit
data = (data << 1) | 1;
}
else if (levelA == MARK && levelB == SPACE) {
// zero bit
data <<= 1;
}
else return DATA_MARK_ERROR;
}
// Success
bits = 13;
value = data;
decode_type = RC5;
return true;
}
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC6)
bool IRdecodeRC6::decode(void) {
ATTEMPT_MESSAGE(F("RC6"));
if (rawlen < MIN_RC6_SAMPLES) return RAW_COUNT_ERROR;
// Initial mark
if (!MATCH_MARK(rawbuf[1], RC6_HDR_MARK)) return HEADER_MARK_ERROR;
if (!MATCH_SPACE(rawbuf[2], RC6_HDR_SPACE)) return HEADER_SPACE_ERROR;
int offset=3;//Skip gap and header
long data = 0;
int used = 0;
// Get start bit (1)
if (getRClevel(&offset, &used, RC6_T1) != MARK) return DATA_MARK_ERROR;
if (getRClevel(&offset, &used, RC6_T1) != SPACE) return DATA_SPACE_ERROR;
int nbits;
for (nbits = 0; offset < rawlen; nbits++) {
RCLevel levelA, levelB; // Next two levels
levelA = getRClevel(&offset, &used, RC6_T1);
if (nbits == 3) {
// T bit is double wide; make sure second half matches
if (levelA != getRClevel(&offset, &used, RC6_T1)) return TRAILER_BIT_ERROR;
}
levelB = getRClevel(&offset, &used, RC6_T1);
if (nbits == 3) {
// T bit is double wide; make sure second half matches
if (levelB != getRClevel(&offset, &used, RC6_T1)) return TRAILER_BIT_ERROR;
}
if (levelA == MARK && levelB == SPACE) { // reversed compared to RC5
// 1 bit
data = (data << 1) | 1;
}
else if (levelA == SPACE && levelB == MARK) {
// zero bit
data <<= 1;
}
else {
return DATA_MARK_ERROR;
}
}
// Success
bits = nbits;
value = data;
decode_type = RC6;
return true;
}
#endif
#if defined(ALL_IR_PROTOCOL) //|| (MY_IR_PROTOCOL == HASH_CODE)
/*
* This Hash decoder is based on IRhashcode
* Copyright 2010 Ken Shirriff
* For details see http://www.arcfn.com/2010/01/using-arbitrary-remotes-with-arduino.html
* Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param
* Converts the raw code values into a 32-bit hash code.
* Hopefully this code is unique for each button.
*/
#define FNV_PRIME_32 16777619
#define FNV_BASIS_32 2166136261
// Compare two tick values, returning 0 if newval is shorter,
// 1 if newval is equal, and 2 if newval is longer
int IRdecodeHash::compare(unsigned int oldval, unsigned int newval) {
if (newval < oldval * .8) return 0;
if (oldval < newval * .8) return 2;
return 1;
}
bool IRdecodeHash::decode(void) {
hash = FNV_BASIS_32;
for (int i = 1; i+2 < rawlen; i++) {
hash = (hash * FNV_PRIME_32) ^ compare(rawbuf[i], rawbuf[i+2]);
}
//note: does not set decode_type=HASH_CODE nor "value" because you might not want to.
return true;
}
#endif
/*
* This section is all related to interrupt handling and hardware issues. It has nothing to do with IR protocols.
* You need not understand this is all you're doing is adding new protocols or improving the decoding and sending
* of protocols.
*
*/
// Provides ISR
#include <avr/interrupt.h>
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#define CLKFUDGE 5 // fudge factor for clock interrupt overhead
#ifdef F_CPU
#define SYSCLOCK F_CPU // main Arduino clock
#else
#define SYSCLOCK 16000000 // main Arduino clock
#endif
#define PRESCALE 8 // timer clock prescale
#define CLKSPERUSEC (SYSCLOCK/PRESCALE/1000000) // timer clocks per microsecond
#include <IRLibTimer.h>
IRrecv::IRrecv(int recvpin)
{
irparams.recvpin = recvpin;
irparams.blinkflag = 0;
}
/* If your hardware is set up to do both output and input but your particular sketch
* doesn't do any output, this method will ensure that your output pin is low
* and doesn't turn on your IR LED or any output circuit.
*/
void IRrecv::No_Output (void) {
pinMode(TIMER_PWM_PIN, OUTPUT);
digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low
}
void IRrecv::enableIRIn() {
// setup pulse clock timer interrupt
cli();
TIMER_CONFIG_NORMAL();
TIMER_ENABLE_INTR;
TIMER_RESET;
sei();
// initialize state machine variables
irparams.rcvstate = STATE_IDLE;
irparams.rawlen = 0;
// set pin modes
pinMode(irparams.recvpin, INPUT);
}
// enable/disable blinking of pin 13 on IR processing
void IRrecv::blink13(int blinkflag)
{
irparams.blinkflag = blinkflag;
if (blinkflag)
pinMode(BLINKLED, OUTPUT);
}
void IRrecv::resume() {
irparams.rcvstate = STATE_IDLE;
irparams.rawlen = 0;
}
bool IRrecv::GetResults(IRdecodeBase *decoder) {
if (irparams.rcvstate != STATE_STOP) return false;
decoder->Reset();//clear out any old values.
decoder->rawlen = (unsigned int)irparams.rawlen;
//By copying the entire array we could call IRrecv::resume immediately while decoding
//is still in progress.
if(decoder->rawbuf != irparams.rawbuf)
memcpy((void *)decoder->rawbuf,(const void *)irparams.rawbuf,sizeof(irparams.rawbuf));
return true;
}
#define _GAP 5000 // Minimum map between transmissions
#define GAP_TICKS (_GAP/USECPERTICK)
// TIMER2 interrupt code to collect raw data.
// Widths of alternating SPACE, MARK are recorded in rawbuf.
// Recorded in ticks of 50 microseconds.
// rawlen counts the number of entries recorded so far.
// First entry is the SPACE between transmissions.
// As soon as a SPACE gets long, ready is set, state switches to IDLE, timing of SPACE continues.
// As soon as first MARK arrives, gap width is recorded, ready is cleared, and new logging starts
ISR(TIMER_INTR_NAME)
{
TIMER_RESET;
enum irdata_t {IR_MARK=0, IR_SPACE=1};
irdata_t irdata = (irdata_t)digitalRead(irparams.recvpin);
irparams.timer++; // One more 50us tick
if (irparams.rawlen >= RAWBUF) {
// Buffer overflow
irparams.rcvstate = STATE_STOP;
}
switch(irparams.rcvstate) {
case STATE_IDLE: // In the middle of a gap
if (irdata == IR_MARK) {
if (irparams.timer < GAP_TICKS) {
// Not big enough to be a gap.
irparams.timer = 0;
}
else {
// gap just ended, record duration and start recording transmission
irparams.rawlen = 0;
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
irparams.timer = 0;
irparams.rcvstate = STATE_MARK;
}
}
break;
case STATE_MARK: // timing MARK
if (irdata == IR_SPACE) { // MARK ended, record time
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
irparams.timer = 0;
irparams.rcvstate = STATE_SPACE;
}
break;
case STATE_SPACE: // timing SPACE
if (irdata == IR_MARK) { // SPACE just ended, record it
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
irparams.timer = 0;
irparams.rcvstate = STATE_MARK;
}
else { // SPACE
if (irparams.timer > GAP_TICKS) {
// big SPACE, indicates gap between codes
// Mark current code as ready for processing
// Switch to STOP
// Don't reset timer; keep counting space width
irparams.rcvstate = STATE_STOP;
}
}
break;
case STATE_STOP: // waiting, measuring gap
if (irdata == IR_MARK) { // reset gap timer
irparams.timer = 0;
}
break;
}
if (irparams.blinkflag) {
if (irdata == IR_MARK) {
BLINKLED_ON(); // turn pin 13 LED on
}
else {
BLINKLED_OFF(); // turn pin 13 LED off
}
}
}
#ifdef USE_IR_SEND
IRsendBase::IRsendBase () {
pinMode(TIMER_PWM_PIN, OUTPUT);
digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low
}
void IRsendBase::enableIROut(int khz) {
// Enables IR output. The khz value controls the modulation frequency in kilohertz.
// The IR output will be on pin 3 (OC2B).
// This routine is designed for 36-40KHz; if you use it for other values, it's up to you
// to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.)
// TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B
// controlling the duty cycle.
// There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A)
// To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin.
// A few hours staring at the ATmega documentation and this will all make sense.
// See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details.
// Disable the Timer2 Interrupt (which is used for receiving IR)
TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt
pinMode(TIMER_PWM_PIN, OUTPUT);
digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low
TIMER_CONFIG_KHZ(khz);
}
void IRsendBase::mark(int time) {
TIMER_ENABLE_PWM;
delayMicroseconds(time);
}
void IRsendBase::space(int time) {
TIMER_DISABLE_PWM;
delayMicroseconds(time);
}
#endif
/*
* Various debugging routines
*/
#ifdef DEBUG
int MATCH(int measured, int desired) {
Serial.print("Testing: "); Serial.print(TICKS_LOW(desired), DEC);
Serial.print(" <= "); Serial.print(measured, DEC); Serial.print(" <= "); Serial.println(TICKS_HIGH(desired), DEC);
return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);
}
int MATCH_MARK(int measured_ticks, int desired_us) {
Serial.print("Testing mark "); Serial.print(measured_ticks * USECPERTICK, DEC); Serial.print(" vs "); Serial.print(desired_us, DEC); Serial.print(": ");
Serial.print(TICKS_LOW(desired_us + MARK_EXCESS), DEC); Serial.print(" <= "); Serial.print(measured_ticks, DEC);
Serial.print(" <= "); Serial.println(TICKS_HIGH(desired_us + MARK_EXCESS), DEC);
return measured_ticks >= TICKS_LOW(desired_us + MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS);
}
int MATCH_SPACE(int measured_ticks, int desired_us) {
Serial.print("Testing space "); Serial.print(measured_ticks * USECPERTICK, DEC); Serial.print(" vs "); Serial.print(desired_us, DEC); Serial.print(": ");
Serial.print(TICKS_LOW(desired_us - MARK_EXCESS), DEC); Serial.print(" <= "); Serial.print(measured_ticks, DEC);
Serial.print(" <= "); Serial.println(TICKS_HIGH(desired_us - MARK_EXCESS), DEC);
return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS);
}
#endif
#ifdef TRACE
void ATTEMPT_MESSAGE(const __FlashStringHelper * s) {Serial.print(F("Attempting ")); Serial.print(s); Serial.println(F(" decode:"));};
byte REJECTION_MESSAGE(const __FlashStringHelper * s) { Serial.print(F(" Protocol failed because ")); Serial.print(s); Serial.println(F(" wrong.")); return false;};
#endif

View File

@ -1,318 +0,0 @@
/* IRLib.h from IRLib – an Arduino library for infrared encoding and decoding
* Version 1.1 April 2013
* Copyright 2013 by Chris Young http://cyborg5.com
*
* Port to Digispark (size optimization) August 2013
* by RC Navy http://p.loussouarn.free.fr
*
* This library is a major rewrite of IRemote by Ken Shirriff which was covered by
* GNU LESSER GENERAL PUBLIC LICENSE which as I read it allows me to make modified versions.
* That same license applies to this modified version. See his original copyright below.
* The latest Ken Shirriff code can be found at https://github.com/shirriff/Arduino-IRremote
* My purpose was to reorganize the code to make it easier to add or remove protocols.
* As a result I have separated the act of receiving a set of raw timing codes from the act of decoding them
* by making them separate classes. That way the receiving aspect can be more black box and implementers
* of decoders and senders can just deal with the decoding of protocols.
* Also added provisions to make the classes base classes that could be extended with new protocols
* which would not require recompiling of the original library nor understanding of its detailed contents.
* Some of the changes were made to reduce code size such as unnecessary use of long versus bool.
* Some changes were just my weird programming style. Also extended debugging information added.
*/
/*
* IRremote
* Version 0.1 July, 2009
* Copyright 2009 Ken Shirriff
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com
*
* Interrupt code based on NECIRrcv by Joe Knapp
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
*/
#ifndef IRLib_h
#define IRLib_h
#include <Arduino.h>
// The following are compile-time library options.
// If you change them, recompile the library.
// If DEBUG is defined, a lot of debugging output will be printed during decoding.
// If TRACE is defined, some debugging information about the decode will be printed
// TEST must be defined for the IRtest unittests to work. It will make some
// methods virtual, which will be slightly slower, which is why it is optional.
// If DETAILLED_DUMP is defined the dump informations are more detailled
// If ALL_IR_PROTOCOL is defined, it allows to discover the protocol used by the IR transmitter (eg, with an arduino UNO)
// Once the protocol used by the IR transmitter discovered, set MY_IR_PROTOCOL to PROTO_xxxx and comment ALL_IR_PROTOCOL
// this will reduce dramatically the size of the sketch
// #define DEBUG
// #define TRACE
// #define TEST
//#define USE_IR_SEND
//#define DETAILLED_DUMP
//#define ALL_IR_PROTOCOL
#define MY_IR_PROTOCOL PROTO_NEC /* Set Here the protocol you want to use among the following ones */
// Only used for testing; can remove virtual for shorter code
#ifdef TEST
#define VIRTUAL virtual
#else
#define VIRTUAL
#endif
#define RAWBUF 70//100 // Length of raw duration buffer
#define USE_TIMER1 1 //should be "1" for timer 1, should be "0" for timer 2
/* Use one of the protocol in the list below if you want to support a single one */
#define PROTO_UNKNOWN 0
#define PROTO_NEC 1
#define PROTO_SONY 2
#define PROTO_RC5 3
#define PROTO_RC6 4
#define PROTO_PANASONIC_OLD 5
#define PROTO_JVC 6
#define PROTO_NECX 7
#define PROTO_HASH_CODE 8
enum IRTYPES {UNKNOWN, NEC, SONY, RC5, RC6, PANASONIC_OLD, JVC, NECX, HASH_CODE, LAST_PROTOCOL=HASH_CODE};
#if defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
const char *Pnames(IRTYPES Type); //Returns a character string that is name of protocol.
#else
const __FlashStringHelper *Pnames(IRTYPES Type); //Returns a character string that is name of protocol.
#endif
// Base class for decoding raw results
class IRdecodeBase
{
public:
IRdecodeBase(void);
IRTYPES decode_type; // NEC, SONY, RC5, UNKNOWN etc.
unsigned long value; // Decoded value
int bits; // Number of bits in decoded value
volatile unsigned int *rawbuf; // Raw intervals in .5 us ticks
/*int*/uint8_t rawlen; // Number of records in rawbuf.
virtual void Reset(void); // Initializes the decoder
virtual bool decode(void); // This base routine always returns false override with your routine
bool decodeGeneric(/*int*/int8_t Raw_Count,int Head_Mark,int Head_Space, int Mark_One, int Mark_Zero, int Space_One,int Space_Zero);
unsigned long Interval_uSec(int index);
virtual void DumpResults (void);
void UseExtnBuf(void *P); //Normally uses same rawbuf as IRrecv. Use this to define your own buffer.
void copyBuf (IRdecodeBase *source);//copies rawbuf and rawlen from one decoder to another
};
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_HASH_CODE)
class IRdecodeHash: public virtual IRdecodeBase
{
public:
unsigned long hash;
virtual bool decode(void);//made virtual in case you want to substitute your own hash code
protected:
int compare(unsigned int oldval, unsigned int newval);//used by decodeHash
};
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NEC)
class IRdecodeNEC: public virtual IRdecodeBase
{
public:
virtual bool decode(void);
};
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_SONY)
class IRdecodeSony: public virtual IRdecodeBase
{
public:
virtual bool decode(void);
};
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC5) || (MY_IR_PROTOCOL == PROTO_RC6)
class IRdecodeRC: public virtual IRdecodeBase
{
public:
enum RCLevel {MARK, SPACE, ERROR};//used by decoders for RC5/RC6
// These are called by decode
RCLevel getRClevel(int *offset, int *used, int t1);
};
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC5)
class IRdecodeRC5: public virtual IRdecodeRC
{
public:
virtual bool decode(void);
};
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC6)
class IRdecodeRC6: public virtual IRdecodeRC
{
public:
virtual bool decode(void);
};
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_PANASONIC_OLD)
class IRdecodePanasonic_Old: public virtual IRdecodeBase
{
public:
virtual bool decode(void);
};
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_JVC)
class IRdecodeJVC: public virtual IRdecodeBase
{
public:
virtual bool decode(void);
};
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NECX)
class IRdecodeNECx: public virtual IRdecodeBase
{
public:
virtual bool decode(void);
};
#endif
// main class for decoding all supported protocols
class IRdecode:
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NEC)
public virtual IRdecodeNEC
#endif
#if defined(ALL_IR_PROTOCOL)
,
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_SONY)
public virtual IRdecodeSony
#endif
#if defined(ALL_IR_PROTOCOL)
,
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC5)
public virtual IRdecodeRC5
#endif
#if defined(ALL_IR_PROTOCOL)
,
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_RC6)
public virtual IRdecodeRC6
#endif
#if defined(ALL_IR_PROTOCOL)
,
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_PANASONIC_OLD)
public virtual IRdecodePanasonic_Old
#endif
#if defined(ALL_IR_PROTOCOL)
,
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_JVC)
public virtual IRdecodeJVC
#endif
#if defined(ALL_IR_PROTOCOL)
,
#endif
#if defined(ALL_IR_PROTOCOL) || (MY_IR_PROTOCOL == PROTO_NECX)
public virtual IRdecodeNECx
#endif
{
public:
virtual bool decode(void); // Calls each decode routine individually
};
#ifdef USE_IR_SEND
//Base class for sending signals
class IRsendBase
{
public:
IRsendBase() ;
void sendGeneric(unsigned long data, int Num_Bits, int Head_Mark, int Head_Space, int Mark_One, int Mark_Zero, int Space_One, int Space_Zero, int mHz, bool Stop_Bits);
protected:
void enableIROut(int khz);
VIRTUAL void mark(int usec);
VIRTUAL void space(int usec);
};
class IRsendNEC: public virtual IRsendBase
{
public:
void send(unsigned long data);
};
class IRsendSony: public virtual IRsendBase
{
public:
void send(unsigned long data, int nbits);
};
class IRsendRaw: public virtual IRsendBase
{
public:
void send(unsigned int buf[], int len, int hz);
};
class IRsendRC5: public virtual IRsendBase
{
public:
void send(unsigned long data);
};
class IRsendRC6: public virtual IRsendBase
{
public:
void send(unsigned long data, int nbits);
};
class IRsendPanasonic_Old: public virtual IRsendBase
{
public:
void send(unsigned long data);
};
class IRsendJVC: public virtual IRsendBase
{
public:
void send(unsigned long data, bool First);
};
class IRsendNECx: public virtual IRsendBase
{
public:
void send(unsigned long data);
};
class IRsend:
public virtual IRsendNEC,
public virtual IRsendSony,
public virtual IRsendRaw,
public virtual IRsendRC5,
public virtual IRsendRC6,
public virtual IRsendPanasonic_Old,
public virtual IRsendJVC,
public virtual IRsendNECx
{
public:
void send(IRTYPES Type, unsigned long data, int nbits);
};
#endif
// main class for receiving IR
class IRrecv
{
public:
IRrecv(int recvpin);
void No_Output(void);
void blink13(int blinkflag);
bool GetResults(IRdecodeBase *decoder);
void enableIRIn();
void resume();
};
// Some useful constants
// Decoded value for NEC when a repeat code is received
#define REPEAT 0xffffffff
#endif //IRLib_h

View File

@ -1,83 +0,0 @@
/* IRLibMatch.h from IRLib an Arduino library for infrared encoding and decoding
* Version 1.0 January 2013
* Copyright 2013 by Chris Young http://cyborg5.com
*
* This library is a major rewrite of IRemote by Ken Shirriff which was covered by
* GNU LESSER GENERAL PUBLIC LICENSE which as I read it allows me to make modified versions.
* That same license applies to this modified version. See his original copyright below.
* The latest Ken Shirriff code can be found at https://github.com/shirriff/Arduino-IRremote
* My purpose was to reorganize the code to make it easier to add or remove protocols.
* As a result I have separated the act of receiving a set of raw timing codes from the act of decoding them
* by making them separate classes. That way the receiving aspect can be more black box and implementers
* of decoders and senders can just deal with the decoding of protocols.
* Also added provisions to make the classes base classes that could be extended with new protocols
* which would not require recompiling of the original library nor understanding of its detailed contents.
* Some of the changes were made to reduce code size such as unnecessary use of long versus bool.
* Some changes were just my weird programming style. Also extended debugging information added.
*/
/*
* IRremote
* Version 0.1 July, 2009
* Copyright 2009 Ken Shirriff
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com
*
* Interrupt code based on NECIRrcv by Joe Knapp
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
*/
#ifndef IRLibMatch_h
#define IRLibMatch_h
/*
* This is some miscellaneous definition that is needed by the decoding routines.
* You need not include this file unless you are creating custom decode routines
* which will require these macros and definitions. Even if you include it, you probably
* don't need to be intimately familiar with the internal details.
*/
// Marks tend to be 100us too long, and spaces 100us too short
// when received due to sensor lag.
#define MARK_EXCESS 100
#define USECPERTICK 50 // microseconds per clock interrupt tick
#if 0
#define TOLERANCE 25 // percent tolerance in measurements
#define TICKS_LOW(us) (int) (((us)*(1.0 - TOLERANCE/100.)/USECPERTICK))
#define TICKS_HIGH(us) (int) (((us)*(1.0 + TOLERANCE/100.)/USECPERTICK + 1))
#else
#define TICKS_LOW(us) (((us) - (us>>2))/USECPERTICK)
#define TICKS_HIGH(us) (((us) + (us>>2))/USECPERTICK)
#endif
#ifdef DEBUG
int MATCH(int measured, int desired);
int MATCH_MARK(int measured_ticks, int desired_us);
int MATCH_SPACE(int measured_ticks, int desired_us);
#else
#define MATCH(measured_ticks, desired_us) ((measured_ticks) >= TICKS_LOW(desired_us) && (measured_ticks) <= TICKS_HIGH(desired_us))
#define MATCH_MARK(measured_ticks, desired_us) MATCH(measured_ticks, (desired_us) + MARK_EXCESS)
#define MATCH_SPACE(measured_ticks, desired_us) MATCH((measured_ticks), (desired_us) - MARK_EXCESS)
#endif
#ifdef TRACE
void ATTEMPT_MESSAGE(const __FlashStringHelper * s);
byte REJECTION_MESSAGE(const __FlashStringHelper * s);
#define RAW_COUNT_ERROR REJECTION_MESSAGE(F("number of raw samples"));
#define HEADER_MARK_ERROR REJECTION_MESSAGE(F("header mark"));
#define HEADER_SPACE_ERROR REJECTION_MESSAGE(F("header space"));
#define DATA_MARK_ERROR REJECTION_MESSAGE(F("data mark"));
#define DATA_SPACE_ERROR REJECTION_MESSAGE(F("data space"));
#define TRAILER_BIT_ERROR REJECTION_MESSAGE(F("RC5/RC6 trailer bit length"));
#else
#define ATTEMPT_MESSAGE(s)
#define REJECTION_MESSAGE(s) false
#define RAW_COUNT_ERROR false
#define HEADER_MARK_ERROR false
#define HEADER_SPACE_ERROR false
#define DATA_MARK_ERROR false
#define DATA_SPACE_ERROR false
#define TRAILER_BIT_ERROR false
#endif
#endif //IRLibMatch_h

View File

@ -1,380 +0,0 @@
/* IRLibTimer.h from IRLib an Arduino library for infrared encoding and decoding
* Version 1.0 January 2013
* Copyright 2013 by Chris Young http://cyborg5.com
*
* This library is a major rewrite of IRemote by Ken Shirriff which was covered by
* GNU LESSER GENERAL PUBLIC LICENSE which as I read it allows me to make modified versions.
* That same license applies to this modified version. See his original copyright below.
* The latest Ken Shirriff code can be found at https://github.com/shirriff/Arduino-IRremote
* My purpose was to reorganize the code to make it easier to add or remove protocols.
* As a result I have separated the act of receiving a set of raw timing codes from the act of decoding them
* by making them separate classes. That way the receiving aspect can be more black box and implementers
* of decoders and senders can just deal with the decoding of protocols.
* Also added provisions to make the classes base classes that could be extended with new protocols
* which would not require recompiling of the original library nor understanding of its detailed contents.
* Some of the changes were made to reduce code size such as unnecessary use of long versus bool.
* Some changes were just my weird programming style. Also extended debugging information added.
*/
/*
* IRremote
* Version 0.1 July, 2009
* Copyright 2009 Ken Shirriff
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com
*
* Interrupt code based on NECIRrcv by Joe Knapp
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
*/
/* This file defines which timer you wish to use. Different versions of Arduino and related boards
* have different timers available to them. For various reasons you might want to use something other than
* timer 2. Some boards do not have timer 2. This attempts to detect which type of board you are using.
* You need uncomment wish to use on your board. You probably will not need to include this in your
* program unless you want to see which timer is being used and which board has been detected.
* This information came from an alternative fork of the original Ken Shirriff library found here
* https://github.com/TKJElectronics/Arduino-IRremote
*/
#ifndef IRLibTimer_h
#define IRLibTimer_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#ifdef F_CPU
#define SYSCLOCK F_CPU // main Arduino clock
#else
#define SYSCLOCK 16000000 // main Arduino clock
#endif
// Arduino Mega
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
//#define IR_USE_TIMER1 // tx = pin 11
#define IR_USE_TIMER2 // tx = pin 9
//#define IR_USE_TIMER3 // tx = pin 5
//#define IR_USE_TIMER4 // tx = pin 6
//#define IR_USE_TIMER5 // tx = pin 46
// Teensy 1.0
#elif defined(__AVR_AT90USB162__)
#define IR_USE_TIMER1 // tx = pin 17
// Teensy 2.0 versus Leonardo
// These boards use the same chip but the pinouts are different.
#elif defined(__AVR_ATmega32U4__)
#ifdef CORE_TEENSY
// it's Teensy 2.0
//#define IR_USE_TIMER1 // tx = pin 14
//#define IR_USE_TIMER3 // tx = pin 9
#define IR_USE_TIMER4_HS // tx = pin 10
#else
// it's probably Leonardo
#define IR_USE_TIMER1 // tx = pin 9
//#define IR_USE_TIMER3 // tx = pin 5
//#define IR_USE_TIMER4_HS // tx = pin 13
#endif
// Teensy++ 1.0 & 2.0
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
//#define IR_USE_TIMER1 // tx = pin 25
#define IR_USE_TIMER2 // tx = pin 1
//#define IR_USE_TIMER3 // tx = pin 16
// Sanguino
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
//#define IR_USE_TIMER1 // tx = pin 13
#define IR_USE_TIMER2 // tx = pin 14
// Tested with ATtiny85, presumably works with ATtiny45, possibly with ATtiny25
// The attiny core uses Timer 0 for millis() etc., so using timer 1 is advisable
// for IR out. Pin 4 also conveniently is not used in any role for ISP.
// The Arduino-tiny core uses Timer 1 for millis(), so using timer 0 is advisable
// for IR out. Pin 0 is used by default for IR out in the Tinyspark IR shield, but
// is not usable for PWM waveforms where the frequency, not just the duty cycle,
// needs to be controlled.
#elif defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
// #define IR_USE_TIMER1_TINY // tx = pin 4 (OC1B)
#define IR_USE_TIMER0 // tx = pin 1 (OC0B)
// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc
#else
//#define IR_USE_TIMER1 // tx = pin 9
#define IR_USE_TIMER2 // tx = pin 3
#endif
// defines for timer0 (8 bits). Tested on ATtiny85, may also work on other
// processors, but most of them use Timer 0 to keep system time
#if defined(IR_USE_TIMER0)
#define TIMER_RESET
#define TIMER_ENABLE_PWM (TCCR0A |= _BV(COM0B1))
#define TIMER_DISABLE_PWM (TCCR0A &= ~(_BV(COM0B1)))
#define TIMER_ENABLE_INTR (TIMSK = _BV(OCIE0A))
#define TIMER_DISABLE_INTR (TIMSK = 0)
#define TIMER_INTR_NAME TIMER0_COMPA_vect
#define TIMER_CONFIG_KHZ(val) ({ \
const uint8_t pwmval = SYSCLOCK / 2000 / (val); \
TCCR0A = _BV(WGM00); \
TCCR0B = _BV(WGM02) | _BV(CS00); \
OCR0A = pwmval; \
OCR0B = pwmval / 3; \
})
#define TIMER_COUNT_TOP (SYSCLOCK * USECPERTICK / 1000000)
#if (TIMER_COUNT_TOP < 256)
#define TIMER_CONFIG_NORMAL() ({ \
TCCR0A = _BV(WGM01); \
TCCR0B = _BV(CS00); \
OCR0A = TIMER_COUNT_TOP; \
TCNT0 = 0; \
})
#else
#define TIMER_CONFIG_NORMAL() ({ \
TCCR0A = _BV(WGM01); \
TCCR0B = _BV(CS01); \
OCR0A = TIMER_COUNT_TOP / 8; \
TCNT0 = 0; \
})
#endif
#if defined(CORE_OC0A_PIN)
#define TIMER_PWM_PIN CORE_OC0B_PIN
#else
#define TIMER_PWM_PIN 1 /* Attiny core */
#endif
// defines for timer2 (8 bits)
#elif defined(IR_USE_TIMER2)
#define TIMER_RESET
#define TIMER_ENABLE_PWM (TCCR2A |= _BV(COM2B1))
#define TIMER_DISABLE_PWM (TCCR2A &= ~(_BV(COM2B1)))
#define TIMER_ENABLE_INTR (TIMSK2 = _BV(OCIE2A))
#define TIMER_DISABLE_INTR (TIMSK2 = 0)
#define TIMER_INTR_NAME TIMER2_COMPA_vect
#define TIMER_CONFIG_KHZ(val) ({ \
const uint8_t pwmval = SYSCLOCK / 2000 / (val); \
TCCR2A = _BV(WGM20); \
TCCR2B = _BV(WGM22) | _BV(CS20); \
OCR2A = pwmval; \
OCR2B = pwmval / 3; \
})
#define TIMER_COUNT_TOP (SYSCLOCK * USECPERTICK / 1000000)
#if (TIMER_COUNT_TOP < 256)
#define TIMER_CONFIG_NORMAL() ({ \
TCCR2A = _BV(WGM21); \
TCCR2B = _BV(CS20); \
OCR2A = TIMER_COUNT_TOP; \
TCNT2 = 0; \
})
#else
#define TIMER_CONFIG_NORMAL() ({ \
TCCR2A = _BV(WGM21); \
TCCR2B = _BV(CS21); \
OCR2A = TIMER_COUNT_TOP / 8; \
TCNT2 = 0; \
})
#endif
#if defined(CORE_OC2B_PIN)
#define TIMER_PWM_PIN CORE_OC2B_PIN /* Teensy */
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define TIMER_PWM_PIN 9 /* Arduino Mega */
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
#define TIMER_PWM_PIN 14 /* Sanguino */
#else
#define TIMER_PWM_PIN 3 /* Arduino Duemilanove, Diecimila, LilyPad, etc */
#endif
// defines for timer1 (16 bits)
#elif defined(IR_USE_TIMER1)
#define TIMER_RESET
#define TIMER_ENABLE_PWM (TCCR1A |= _BV(COM1A1))
#define TIMER_DISABLE_PWM (TCCR1A &= ~(_BV(COM1A1)))
#define TIMER_ENABLE_INTR (TIMSK1 = _BV(OCIE1A))
#define TIMER_DISABLE_INTR (TIMSK1 = 0)
#define TIMER_INTR_NAME TIMER1_COMPA_vect
#define TIMER_CONFIG_KHZ(val) ({ \
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
TCCR1A = _BV(WGM11); \
TCCR1B = _BV(WGM13) | _BV(CS10); \
ICR1 = pwmval; \
OCR1A = pwmval / 3; \
})
#define TIMER_CONFIG_NORMAL() ({ \
TCCR1A = 0; \
TCCR1B = _BV(WGM12) | _BV(CS10); \
OCR1A = SYSCLOCK * USECPERTICK / 1000000; \
TCNT1 = 0; \
})
#if defined(CORE_OC1A_PIN)
#define TIMER_PWM_PIN CORE_OC1A_PIN /* Teensy */
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define TIMER_PWM_PIN 11 /* Arduino Mega */
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
#define TIMER_PWM_PIN 13 /* Sanguino */
#else
#define TIMER_PWM_PIN 9 /* Arduino Duemilanove, Diecimila, LilyPad, etc */
#endif
// defines for timer3 (16 bits)
#elif defined(IR_USE_TIMER3)
#define TIMER_RESET
#define TIMER_ENABLE_PWM (TCCR3A |= _BV(COM3A1))
#define TIMER_DISABLE_PWM (TCCR3A &= ~(_BV(COM3A1)))
#define TIMER_ENABLE_INTR (TIMSK3 = _BV(OCIE3A))
#define TIMER_DISABLE_INTR (TIMSK3 = 0)
#define TIMER_INTR_NAME TIMER3_COMPA_vect
#define TIMER_CONFIG_KHZ(val) ({ \
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
TCCR3A = _BV(WGM31); \
TCCR3B = _BV(WGM33) | _BV(CS30); \
ICR3 = pwmval; \
OCR3A = pwmval / 3; \
})
#define TIMER_CONFIG_NORMAL() ({ \
TCCR3A = 0; \
TCCR3B = _BV(WGM32) | _BV(CS30); \
OCR3A = SYSCLOCK * USECPERTICK / 1000000; \
TCNT3 = 0; \
})
#if defined(CORE_OC3A_PIN)
#define TIMER_PWM_PIN CORE_OC3A_PIN /* Teensy */
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define TIMER_PWM_PIN 5 /* Arduino Mega */
#elif defined(__AVR_ATmega32U4__)
#define TIMER_PWM_PIN 5 /* Arduino Leonardo note already checked for Teensy */
#else
#error "Please add OC3A pin number here\n"
#endif
// defines for timer4 (10 bits, high speed option)
#elif defined(IR_USE_TIMER4_HS)
#define TIMER_RESET
#define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A1))
#define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A1)))
#define TIMER_ENABLE_INTR (TIMSK4 = _BV(TOIE4))
#define TIMER_DISABLE_INTR (TIMSK4 = 0)
#define TIMER_INTR_NAME TIMER4_OVF_vect
#define TIMER_CONFIG_KHZ(val) ({ \
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
TCCR4A = (1<<PWM4A); \
TCCR4B = _BV(CS40); \
TCCR4C = 0; \
TCCR4D = (1<<WGM40); \
TCCR4E = 0; \
TC4H = pwmval >> 8; \
OCR4C = pwmval; \
TC4H = (pwmval / 3) >> 8; \
OCR4A = (pwmval / 3) & 255; \
})
#define TIMER_CONFIG_NORMAL() ({ \
TCCR4A = 0; \
TCCR4B = _BV(CS40); \
TCCR4C = 0; \
TCCR4D = 0; \
TCCR4E = 0; \
TC4H = (SYSCLOCK * USECPERTICK / 1000000) >> 8; \
OCR4C = (SYSCLOCK * USECPERTICK / 1000000) & 255; \
TC4H = 0; \
TCNT4 = 0; \
})
#if defined(CORE_OC4A_PIN)
#define TIMER_PWM_PIN CORE_OC4A_PIN /* Teensy */
#elif defined(__AVR_ATmega32U4__)
#define TIMER_PWM_PIN 13 /*Leonardo*/
#else
#error "Please add OC4A pin number here\n"
#endif
// defines for timer4 (16 bits)
#elif defined(IR_USE_TIMER4)
#define TIMER_RESET
#define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A1))
#define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A1)))
#define TIMER_ENABLE_INTR (TIMSK4 = _BV(OCIE4A))
#define TIMER_DISABLE_INTR (TIMSK4 = 0)
#define TIMER_INTR_NAME TIMER4_COMPA_vect
#define TIMER_CONFIG_KHZ(val) ({ \
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
TCCR4A = _BV(WGM41); \
TCCR4B = _BV(WGM43) | _BV(CS40); \
ICR4 = pwmval; \
OCR4A = pwmval / 3; \
})
#define TIMER_CONFIG_NORMAL() ({ \
TCCR4A = 0; \
TCCR4B = _BV(WGM42) | _BV(CS40); \
OCR4A = SYSCLOCK * USECPERTICK / 1000000; \
TCNT4 = 0; \
})
#if defined(CORE_OC4A_PIN)
#define TIMER_PWM_PIN CORE_OC4A_PIN
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define TIMER_PWM_PIN 6 /* Arduino Mega */
#else
#error "Please add OC4A pin number here\n"
#endif
// defines for timer5 (16 bits)
#elif defined(IR_USE_TIMER5)
#define TIMER_RESET
#define TIMER_ENABLE_PWM (TCCR5A |= _BV(COM5A1))
#define TIMER_DISABLE_PWM (TCCR5A &= ~(_BV(COM5A1)))
#define TIMER_ENABLE_INTR (TIMSK5 = _BV(OCIE5A))
#define TIMER_DISABLE_INTR (TIMSK5 = 0)
#define TIMER_INTR_NAME TIMER5_COMPA_vect
#define TIMER_CONFIG_KHZ(val) ({ \
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
TCCR5A = _BV(WGM51); \
TCCR5B = _BV(WGM53) | _BV(CS50); \
ICR5 = pwmval; \
OCR5A = pwmval / 3; \
})
#define TIMER_CONFIG_NORMAL() ({ \
TCCR5A = 0; \
TCCR5B = _BV(WGM52) | _BV(CS50); \
OCR5A = SYSCLOCK * USECPERTICK / 1000000; \
TCNT5 = 0; \
})
#if defined(CORE_OC5A_PIN)
#define TIMER_PWM_PIN CORE_OC5A_PIN
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define TIMER_PWM_PIN 46 /* Arduino Mega */
#else
#error "Please add OC5A pin number here\n"
#endif
#else // unknown timer
#error "Internal code configuration error, no known IR_USE_TIMER# defined\n"
#endif
// defines for blinking the LED
#if defined(CORE_LED0_PIN)
#define BLINKLED CORE_LED0_PIN
#define BLINKLED_ON() (digitalWrite(CORE_LED0_PIN, HIGH))
#define BLINKLED_OFF() (digitalWrite(CORE_LED0_PIN, LOW))
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define BLINKLED 13
#define BLINKLED_ON() (PORTB |= B10000000)
#define BLINKLED_OFF() (PORTB &= B01111111)
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
#define BLINKLED 0
#define BLINKLED_ON() (PORTD |= B00000001)
#define BLINKLED_OFF() (PORTD &= B11111110)
#elif defined(__AVR_ATmega32U4__) && defined(IR_USE_TIMER4_HS)
//Leonardo not teensy. When using Timer4 output is on 13. Therefore disabling blink LED
//You can add an LED elsewhere if you want
#define BLINKLED 1
#define BLINKLED_ON() (digitalWrite(BLINKLED, HIGH))
#define BLINKLED_OFF() (digitalWrite(BLINKLED, LOW))
#else
#define BLINKLED 13
#define BLINKLED_ON() (PORTB |= B00100000)
#define BLINKLED_OFF() (PORTB &= B11011111)
#endif
#endif //IRLibTimer_h

View File

@ -1,70 +0,0 @@
IRLib an Arduino library for infrared encoding and decoding
Version 1.1 april 2013
Copyright 2013 by Chris Young http://cyborg5.com
This library is a major rewrite of IRemote by Ken Shirriff which was covered
by GNU LESSER GENERAL PUBLIC LICENSE which as I read it allows me to make
modified versions. That same license applies to this modified version. See
his original copyright below.
The latest Ken Shirriff code can be found at
https://github.com/shirriff/Arduino-IRremote
My purpose was to reorganize the code to make it easier to add or remove
protocols. As a result I have separated the act of receiving a set of raw timing
codes from the act of decoding them by making them separate classes. That way
the receiving aspect can be more black box and implementers of decoders and
senders can just deal with the decoding of protocols.
Also added provisions to make the classes base classes that could be extended
with new protocols which would not require recompiling of the original library nor
understanding of its detailed contents. Some of the changes were made to reduce
code size such as unnecessary use of long versus bool. Some changes were just my
weird programming style. Also extended debugging information added.
IRremote
Version 0.1 July, 2009
Copyright 2009 Ken Shirriff
For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm
http://arcfn.com
Interrupt code based on NECIRrcv by Joe Knapp
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
****************************************************
The package contains:
IRLib.cpp Code for the library written in object C++
IRLib.h Header file which you will include in your sketch
IRLibMatch.h Match macros used internally. Need not include this unless you implement
your own protocols
iRLibTimer.h Attempts to detect type of Arduino board and allows you to modify which
interrupt timer you will use. Defaults to timer 2 as did the original KS
library. Alternate board and timer information based on a fork of the
original KS library. That for can be found here.
https://github.com/TKJElectronics/Arduino-IRremote
Note: there is no "IRremoteInt.h" header as in the original library. Those values were
moved elsewhere.
The examples directory contains:
IRhashdecode Demonstrates hash decoder.
IRrecord Recording incoming signal and play it back when a character is sent
through the serial console. By using the console you no longer need
to wire up a pushbutton to run this code.
IRrecvDump Receives a code, attempts to decode it, produces well formatted
output of the results using the new "dump" method.
IRsendDemo Simplistic demo to send a Sony DVD power signal every time a
character is received from the serial monitor.
IRsendJVC Demonstrates sending a code using JVC protocol which is tricky.
Samsung36 Demonstrates how to expand the library without recompiling it.
Also demonstrates how to handle codes that are longer than 32 bits.
IRservo Demonstrates controlling a servo motor using an IR remote
IRserial_remote Demonstrates a Python application that runs on your PC and sends
serial data to Arduino which in turn sends IR remote signals.
Note: I did not port any of the other demo sketches although I may add IRTest later.
****************************************************
The library handles the following protocols:
NEC, Sony, RC5, RC6, Raw all of which were supported in the KS version.
Additionally added Panasonic_Old, JVC, NECx.
Also added KS hash code routines which he released separately.

View File

@ -1,84 +0,0 @@
#include <IRLib.h> // In {path_of_installation}/Digispark-Arduino-1.0.x/libraries/DigisparkIRLib/IRLib.h, set MY_PROTOCOL to NEC, SONY, RC5 to find the one used by your own IR Remote Control
#include <DigiUSB.h> // In {path_of_installation}/Digispark-Arduino-1.0.x/libraries/DigisparkUSB/DigiUSB.h, RING_BUFFER_SIZE shall be set to 32
/*
_____ ____ __ _ ____ _ _ _ _
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2013
http://p.loussouarn.free.fr
*************************************************
* Optimized <IRLib> library Dump Demo *
*************************************************
This sketch allows you to discover the protocol used by your own IR Remote Control and the code of each key when pressed.
You will see the decoded key codes in the DigiUSB console.
IMPORTANT:
=========
- In {path_of_installation}/Digispark-Arduino-1.0.x/libraries/DigisparkIRLib/IRLib.h, set MY_PROTOCOL to NEC, SONY, RC5 to find the protocol used by your own IR Remote Control
- In {path_of_installation}/Digispark-Arduino-1.0.x/libraries/DigisparkUSB/DigiUSB.h, RING_BUFFER_SIZE shall be set to 32
Sensor wiring: (Warning: the wiring may vary depending of the model of IR sensor)
=============
.-------.
| ___ |
| / \ | InfraRed
| \___/ | Sensor
| |
'+--+--+'
| | | 100
P5 <----' | '--+---###--- +5V
| |
| '==='4.7uF
| |
'--+--'
|
GND
*/
#define LED_PIN 1
#define IR_RX_PIN 5
#define BUTTON_OFF 0xF740BF //Set here the OFF code for the built-in LED when determined
#define BUTTON_ON 0xF7C03F //Set here the ON code for the built-in LED when determined
IRrecv My_Receiver(IR_RX_PIN);//Receive on pin IR_RX_PIN
IRdecode My_Decoder;
void setup()
{
My_Receiver.enableIRIn(); // Start the receiver
pinMode(LED_PIN, OUTPUT);
DigiUSB.begin();
}
void loop()
{
if(My_Receiver.GetResults(&My_Decoder))
{
My_Decoder.decode();
switch(My_Decoder.value)
{
case BUTTON_OFF:
digitalWrite(LED_PIN, LOW);
break;
case BUTTON_ON:
digitalWrite(LED_PIN, HIGH);
break;
default:break;
}
My_Receiver.resume();
DigiUSB.println(My_Decoder.value, HEX);
}
if(DigiUSB.available())
{
DigiUSB.read();
}
DigiUSB.refresh();
}

View File

@ -1,201 +0,0 @@
#include <TinySoftPwm.h>
#include <IRLib.h>
/*
_____ ____ __ _ ____ _ _ _ _
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2013
http://p.loussouarn.free.fr
*************************************************
* Optimized <IRLib> library Controller Demo *
*************************************************
This sketch allows you to use the Digispark as an IR RGB Controller.
This sketch is designed to used low cost 24 keys IR Remote Control for RGB strip LED,
but you can adapt it to your own IR Remote Control.
Sensor wiring: (Warning: the wiring may vary depending of the model of IR sensor)
=============
.-------.
| ___ |
| / \ | InfraRed
| \___/ | Sensor
| |
'+--+--+'
| | | 100
P5 <----' | '--+---###--- +5V
| |
| '==='4.7uF
| |
'--+--'
|
GND
/* P0, P1 and P2 shall be declared in Digispark-Arduino-1.0.x/libraries/TinySoftPwm.h */
#define LED_GREEN_PIN 0
#define LED_RED_PIN 1
#define LED_BLUE_PIN 2
#define IR_RX_PIN 5
#define CODE_OFF 0xF740BF
#define CODE_ON 0xF7C03F
#define CODE_BRIGHT_MINUS 0xF7807F
#define CODE_BRIGHT_PLUS 0xF700FF
#define CODE_FLASH 0xF7D02F
#define CODE_STROBE 0xF7F00F
#define CODE_FADE 0xF7C837
#define CODE_SMOOTH 0xF7E817
#define CODE_RED 0xF720DF
#define CODE_GREEN 0xF7A05F
#define CODE_BLUE 0xF7609F
#define CODE_WHITE 0xF7E01F
#define CODE_ORANGE 0xF710EF
#define CODE_ORANGE_LIGTH 0xF730CF
#define CODE_BROWN 0xF708F7
#define CODE_YELLOW 0xF728D7
#define CODE_GREEN_LIGTH 0xF7906F
#define CODE_GREEN_BLUE1 0xF7B04F
#define CODE_GREEN_BLUE2 0xF78877
#define CODE_GREEN_BLUE3 0xF7A857
#define CODE_BLUE_LIGTH 0xF750AF
#define CODE_PURPLE_DARK 0xF7708F
#define CODE_PURPLE_LIGTH 0xF748B7
#define CODE_PINK 0xF76897
#define BRIGTH_STEP 10
#define CODE_REPEAT 0xFFFFFFFF
IRrecv My_Receiver(IR_RX_PIN);//Receive on pin IR_RX_PIN
IRdecode My_Decoder;
uint8_t PwmRed=0, PwmGreen=0, PwmBlue=0;
void setup()
{
My_Receiver.enableIRIn(); // Start the receiver
pinMode(LED_RED_PIN, OUTPUT);
TinySoftPwm_begin(255,0);
}
void loop()
{
static uint32_t StartUs=micros(), LastIrCode=0;
if(My_Receiver.GetResults(&My_Decoder))
{
My_Decoder.decode();
if(My_Decoder.value==REPEAT && LastIrCode)
{
My_Decoder.value=LastIrCode;
}
switch(My_Decoder.value)
{
case CODE_BRIGHT_MINUS:
Tune(&PwmRed, -BRIGTH_STEP);
Tune(&PwmGreen, -BRIGTH_STEP);
Tune(&PwmBlue, -BRIGTH_STEP);
LastIrCode=CODE_BRIGHT_MINUS;
break;
case CODE_BRIGHT_PLUS:
if(PwmRed) Tune(&PwmRed, BRIGTH_STEP);
if(PwmGreen) Tune(&PwmGreen, BRIGTH_STEP);
if(PwmBlue) Tune(&PwmBlue, BRIGTH_STEP);
LastIrCode=CODE_BRIGHT_PLUS;
break;
default:
LastIrCode=0; /* No repeat for the following codes */
switch(My_Decoder.value)
{
case CODE_OFF:
RGB(0x00, 0x00, 0x00);
break;
case CODE_ON:
RGB(0x7A, 0x00, 0xBF);
break;
case CODE_RED: RGB(0xFF, 0x00, 0x00);break;
case CODE_GREEN: RGB(0x00, 0xFF, 0x00);break;
case CODE_BLUE: RGB(0x00, 0x00, 0xFF);break;
case CODE_WHITE: RGB(0xFF, 0xFF, 0xFF);break;
case CODE_ORANGE: RGB(0xFF, 0x7F, 0x00); break;
case CODE_ORANGE_LIGTH: RGB(0xFF, 0xAA, 0x00); break;
case CODE_BROWN: RGB(0xFF, 0xD4, 0x00); break;
case CODE_YELLOW: RGB(0xFF, 0xFF, 0x00); break;
case CODE_GREEN_LIGTH: RGB(0x00, 0xFF, 0xAA); break;
case CODE_GREEN_BLUE1: RGB(0x00, 0xFF, 0xFF); break;
case CODE_GREEN_BLUE2: RGB(0x00, 0xAA, 0xFF); break;
case CODE_GREEN_BLUE3: RGB(0x00, 0x55, 0xFF); break;
case CODE_BLUE_LIGTH: RGB(0x00, 0x00, 0x80); break;
case CODE_PURPLE_DARK: RGB(0x3F, 0x00, 0x80); break;
case CODE_PURPLE_LIGTH: RGB(0x7A, 0x00, 0xBF); break;
case CODE_PINK: RGB(0xFF, 0x00, 0xFF); break;
case CODE_FLASH: /* to be implemented */break;
case CODE_STROBE: /* to be implemented */break;
case CODE_FADE: /* to be implemented */break;
case CODE_SMOOTH: /* to be implemented */break;
default:
break;
}
break;
}
My_Receiver.resume();
TinySoftPwm_analogWrite(LED_RED_PIN, GammaCorrection(PwmRed));
TinySoftPwm_analogWrite(LED_GREEN_PIN, GammaCorrection(PwmGreen));
TinySoftPwm_analogWrite(LED_BLUE_PIN, GammaCorrection(PwmBlue));
}
/***********************************************************/
/* Call TinySoftPwm_process() with a period of 60 us */
/* The PWM frequency = 255 x 60 # 15 ms -> F # 65Hz */
/* 255 is the first argument passed to TinySoftPwm_begin() */
/***********************************************************/
if((micros() - StartUs) >= 60)
{
/* We arrived here every 60 microseconds */
StartUs=micros();
TinySoftPwm_process(); /* This function shall be called periodically (like here, based on micros(), or in a timer ISR) */
}
}
void RGB(uint8_t Red, uint8_t Green, uint8_t Blue)
{
PwmRed=Red;
PwmGreen=Green;
PwmBlue=Blue;
}
uint8_t GammaCorrection(uint8_t Pwm)
{
return((Pwm*Pwm)>>8);
}
void Tune(uint8_t* Color, int8_t Offset)
{
if (Offset > 0) {
if ( *Color + Offset <= 255) {
*Color += Offset;
} else {
*Color = 255;
}
} else {
if (*Color + Offset >= 0) {
*Color += Offset;
} else {
// *Color = 0;
}
}
}

View File

@ -1,48 +0,0 @@
/* Example program for from IRLib an Arduino library for infrared encoding and decoding
* Version 1.0 January 2013
* Copyright 2013 by Chris Young http://cyborg5.com
* Based on original example sketch for IRremote library
* Version 0.11 September, 2009
* Copyright 2009 Ken Shirriff
* http://arcfn.com
*/
/*
* IRhashdecode - decode an arbitrary IR code.
* Instead of decoding using a standard encoding scheme
* (e.g. Sony, NEC, RC5), the code is hashed to a 32-bit value.
* This should produce a unique 32-bit number however that number cannot be used
* to retransmit the same code. This is just a quick and dirty way to detect a unique code
* for controlling a device when you don't really care what protocol or values
* are being sent.
*/
#include <IRLib.h>
int RECV_PIN = 11;
IRrecv My_Receiver(RECV_PIN);
IRdecode My_Decoder;
IRdecodeHash My_Hash_Decoder;
void setup()
{
My_Receiver.enableIRIn(); // Start the receiver
Serial.begin(9600);
}
void loop() {
if (My_Receiver.GetResults(&My_Decoder)) {//Puts results in My_Decoder
//Restart the receiver so it can be capturing another code
//while we are working on decoding this one.
My_Receiver.resume();
My_Hash_Decoder.copyBuf(&My_Decoder);//copy the results to the hash decoder
My_Decoder.decode();
Serial.print("real decode type:");
Serial.print(Pnames(My_Decoder.decode_type));
Serial.print(" value: 0x");
Serial.print(My_Decoder.value, HEX);
My_Hash_Decoder.decode();
Serial.print(", hash decode: 0x");
Serial.println(My_Hash_Decoder.hash, HEX); // Do something interesting with this value
}
}

View File

@ -1,130 +0,0 @@
/* Example program for from IRLib an Arduino library for infrared encoding and decoding
* Version 1.0 January 2013
* Copyright 2013 by Chris Young http://cyborg5.com
* Based on original example sketch for IRremote library
* Version 0.11 September, 2009
* Copyright 2009 Ken Shirriff
* http://arcfn.com
*/
/*
* IRrecord: record and play back IR signals
* An IR detector/demodulator must be connected to the input RECV_PIN.
* An IR LED must be connected to the output PWM pin 3.
* Unlike the original version of this demo sketch, you need not hook up a pushbutton
* Simply send any character from the serial screen to send the recorded code.
* Also demonstrates how to use toggle bits which must be controlled outside
* the library routines.
* The logic is:
* If an IR code is received, record it.
* If A serial character is received, send the IR code.
*/
#include <IRLib.h>
int RECV_PIN = 11;
IRrecv My_Receiver(RECV_PIN);
IRdecode My_Decoder;
IRsend My_Sender;
/*
* Because this version of the library separated the receiver from the decoder,
* technically you would not need to "store" the code outside the decoder object
* for this overly simple example. All of the details would remain in the object.
* However we are going to go ahead and store them just to show you how.
*/
// Storage for the recorded code
IRTYPES codeType; // The type of code
unsigned long codeValue; // The data bits if type is not raw
int codeBits; // The length of the code in bits
// These values are only stored if it's an unknown type and we are going to use
// raw codes to resend the information.
unsigned int rawCodes[RAWBUF]; // The durations if raw
int rawCount; //The number of interval samples
bool GotOne, GotNew;
void setup()
{
GotOne=false; GotNew=false;
codeType=UNKNOWN;
codeValue=0;
Serial.begin(9600);
Serial.println(F("Send a code from your remote and we will record it."));
Serial.println(F("Type any character and press enter. We will send the recorded code."));
My_Receiver.enableIRIn(); // Start the receiver
}
// Stores the code for later playback
void storeCode(void) {
GotNew=true;
codeType = My_Decoder.decode_type;
if (codeType == UNKNOWN) {
Serial.println("Received unknown code, saving as raw");
// To store raw codes:
// Drop first value (gap)
// Convert from ticks to microseconds
// Tweak marks shorter, and spaces longer to cancel out IR receiver distortion
rawCount = My_Decoder.rawlen-1;
for (int i = 1; i <=rawCount; i++) {
rawCodes[i - 1] = My_Decoder.Interval_uSec(i);//Converts to microseconds and adjusts for Mark/space
};
My_Decoder.DumpResults();
codeType=UNKNOWN;
}
else {
Serial.print(F("Received "));
Serial.print(Pnames(codeType));
if (My_Decoder.value == REPEAT) {
// Don't record a NEC repeat value as that's useless.
Serial.println("repeat; ignoring.");
}
else {
codeValue = My_Decoder.value;
codeBits = My_Decoder.bits;
}
Serial.print(F(" Value:0x"));
Serial.println(My_Decoder.value, HEX);
}
}
void sendCode(int repeat) {
if(codeType== UNKNOWN) {
// Assume 38 KHz
My_Sender.IRsendRaw::send(rawCodes,rawCount,38);
Serial.println("Sent raw");
return;
}
if( !GotNew ) {//We've already sent this so handle toggle bits
if (codeType == RC5) {
codeValue ^= 0x0800;
}
else if (codeType == RC6) {
codeValue ^= 0x10000;
}
}
GotNew=false;
My_Sender.send(codeType,codeValue,codeBits);
Serial.print(F("Sent "));
Serial.print(Pnames(codeType));
Serial.print(F(" Value:0x"));
Serial.println(codeValue, HEX);
}
void loop() {
if (Serial.read() != -1) {
if(GotOne) {
sendCode(0);
My_Receiver.enableIRIn(); // Re-enable receiver
}
}
else if (My_Receiver.GetResults(&My_Decoder)) {
//Restart the receiver so it can be capturing another code
//while we are working on decoding this one.
if(My_Decoder.decode()) {
GotOne=true;
storeCode();
}
delay(500);
My_Receiver.resume();
}
}

View File

@ -1,39 +0,0 @@
/* Example program for from IRLib an Arduino library for infrared encoding and decoding
* Version 1.0 January 2013
* Copyright 2013 by Chris Young http://cyborg5.com
* Based on original example sketch for IRremote library
* Version 0.11 September, 2009
* Copyright 2009 Ken Shirriff
* http://arcfn.com
*/
/*
* IRLib: IRrecvDump - dump details of IR codes with IRrecv
* An IR detector/demodulator must be connected to the input RECV_PIN.
*/
#include <IRLib.h>
int RECV_PIN = 11;
IRrecv My_Receiver(RECV_PIN);
IRdecode My_Decoder;
unsigned int Buffer[RAWBUF];
void setup()
{
Serial.begin(9600);
My_Receiver.enableIRIn(); // Start the receiver
My_Decoder.UseExtnBuf(Buffer);
}
void loop() {
if (My_Receiver.GetResults(&My_Decoder)) {
//Restart the receiver so it can be capturing another code
//while we are working on decoding this one.
My_Receiver.resume();
My_Decoder.decode();
My_Decoder.DumpResults();
}
}

View File

@ -1,25 +0,0 @@
/* Example program for from IRLib an Arduino library for infrared encoding and decoding
* Version 1.0 January 2013
* Copyright 2013 by Chris Young http://cyborg5.com
* Based on original example sketch for IRremote library
* Version 0.11 September, 2009
* Copyright 2009 Ken Shirriff
* http://arcfn.com
*/
#include <IRLib.h>
IRsend My_Sender;
void setup()
{
Serial.begin(9600);
}
void loop() {
if (Serial.read() != -1) {
//send a code every time a character is received from the serial port
//Sony DVD power A8BCA
My_Sender.send(SONY,0xa8bca, 20);
}
}

View File

@ -1,37 +0,0 @@
/* Example program for from IRLib an Arduino library for infrared encoding and decoding
* Version 1.0 January 2013
* Copyright 2013 by Chris Young http://cyborg5.com
* Based on original example sketch for IRremote library
* Version 0.11 September, 2009
* Copyright 2009 Ken Shirriff
* http://arcfn.com
*/
/*
* JVC sends repeat codes that are identical to the regular JVC codes
* however they have no header. Therefore there is an additional parameter
* that tells you whether or not to send as an original code or as a repeat.
*
* The only device I had to test this protocol was an old JVC VCR. It would only work if at least
* 2 frames are sent separated by 45us of "space". All JVC is the same bit length so we use
* the third parameter as a to tell it whether or not to send the header.
* Once with the third parameter "1" then delay about 50 microseconds and send again
* with the third parameter "0".
*/
#include <IRLib.h>
IRsend My_Sender;
void setup()
{
Serial.begin(9600);
}
//send a code every time a character is received from the serial port
void loop() {
if (Serial.read() != -1) {
My_Sender.send(JVC,0xc2d0,1); delayMicroseconds (50);
My_Sender.send(JVC,0xc2d0,0); delayMicroseconds (50);
}
}

View File

@ -1,50 +0,0 @@
#include <IRLib.h>
IRsend My_Sender;
int protocol;
long code;
int bits;
void setup() {
Serial.begin(9600);
}
long parseHex (void) {
long Value=0; char C;delay(100);
while (Serial.available()>0) {
C= tolower(Serial.read());
if ((C>='0')&&(C<='9'))
C=C-'0';
else
if ((C>='a') && (C<='f'))
C=C-'a'+10;
else
return Value;
Value= C+(Value<<4);
};
return Value;
}
void parseDelimiter () {
char C;
while(Serial.available()>0) {
C=tolower(Serial.peek());
if( (C>='0') && (C<='9') )return;
if( (C>='a') && (C<='f') )return;
C=Serial.read();//throwaway delimiters
delay (5);
}
}
// enum IRTYPES {UNKNOWN, NEC, SONY, RC5, RC6, PANASONIC_OLD, JVC, NECX, HASH_CODE, LAST_PROTOCOL=HASH_CODE};
void loop() {
if (Serial.available ()>0) {
protocol = Serial.parseInt (); parseDelimiter();
code = parseHex (); parseDelimiter();
bits = Serial.parseInt (); parseDelimiter();
/* Serial.print("Prot:"); Serial.print(protocol);
Serial.print(" Code:"); Serial.print(code,HEX);
Serial.print(" Bits:"); Serial.println(bits);
*/
My_Sender.send(IRTYPES(protocol), code, bits);
}
}

View File

@ -1,133 +0,0 @@
# IRLib demo script
# version 1.0 by Chris Young http://tech.cyborg5.com/irlib/
# Displays a "Virtual remote" on your screen. Clicking on the
# buttons sends serial datato the Arduino which in turn
# since IR signals to a cable box in TV.
# Import all of the necessary pieces of code
import serial, sys, pygame, pygame.mixer
from pygame.locals import *
# You will have to edit this to the proper port and speed
ser = serial.Serial('COM4', 9600)
pygame.init()
# Established screen size, size of buttons and position
size = width, height = 400, 768
button_size=54; button_offset=71
button_x1=65;button_y1=39
max_rows=10; max_columns=4
# Specify a font. I'm using Arial narrow bold from my Windows
# font folder. However the default font shown below also works.
myfont =pygame.font.Font ("c:/windows/fonts/ARIALNB.TTF",30)
#myfont=pygame.font.Font(None,36)
# These are the text labels that will appear on each button
label_text=("TVp", "CBp", "P^", "Pv",\
"<<", ">", ">>", "->",\
"Rec", "=", "s", "<-",\
"Gd", "^", "Fav", "Inf",\
"<", "sel", ">", "Lis",\
"ret", "v", "Prv", "Mnu",\
"1", "2", "3", "Ch+",\
"4", "5", "6", "Ch-",\
"7", "8", "9", "Vol+",\
"Pip", "0", "Mut", "Vol-",\
)
# Each of these 40 strings of text correspond to the
# protocol in code which will be sent over the USB serial
# to the Arduino. The first number is the protocol number.
# See the defined protocols in "IRLib.h"for the
# enum IRTYPES at about line 50. This example uses
# protocol 3 which is "RC5" used by my Magnavox TV
# and protocol 5 "PANASONIC_OLD" used by my Scientific
# Atlantic SA 8300 DVR. The protocol number is followed by
# the hex code to be transmitted. That is followed by the
# number of bits. Note that the PANASONIC_OLD protocol
# does not need the number of bits specified so they are omitted.
IR_Codes= ("3,180c,13","5,37c107","5,36d924","5,37d904",\
"5,37291a","5,37990c","5,36293a","5,36b129",\
"5,375914","5,374117","5,365934","5,37c906",\
"5,36c127","5,36812f","5,37f101","5,36213b",\
"5,37810f","5,366133","5,364137","5,36c926",\
"5,366932","5,37a10b","5,36e123","5,373918",\
"5,36113d","5,37111d","5,36912d","5,377111",\
"5,37910d","5,365135","5,375115","5,36f121",\
"5,36d125","5,37d105","5,363139","3,1810,13",\
"5,37b908","5,373119","3,180d,13","3,1811,13",\
)
# This function gets called to shut everything down
def Finished():
pygame.quit()
sys.exit()
# Gets the button index based on mouse position. Returned
# value is from 0 to 39 (number of buttons-1)
# Returns -1 if you are not over a button.
def ComputeButton():
mx,my=pygame.mouse.get_pos()
mx=mx-button_x1
my=my-button_y1
bx=mx/button_offset; by=my/button_offset
if bx<0 or bx>=max_columns:return -1
if by<0 or by> max_rows:return -1
if (mx%button_offset)>button_size:return -1
if (my%button_offset)>button_size:return -1
return bx+by*max_columns
# Blits the button text from button number "i"
# onto the specified layer using the specified color.
def Show_Text(i,Layer,color=(0,0,0)):
t=label_text[i]
label = myfont.render (t,1,color)
labelpos= label.get_rect()
labelpos.centerx=button_x1+button_size/2+i%max_columns*button_offset
labelpos.centery=button_y1+button_size/2+i/max_columns*button_offset
Layer.blit(label,labelpos)
# Create the screen and load the background image.
screen = pygame.display.set_mode(size)
bg = pygame.image.load("remotebg.png")
# Blit black text labels onto the background image
for i in range (max_rows*max_columns):
Show_Text(i, bg)
# Copy the background to the display
screen.blit(bg,(0,0))
pygame.display.flip()
# Load the clicking sound
Click=pygame.mixer.Sound("click.wav")
# Used to detect when the mouse hovers over a different button
previous=-1
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
Finished()
elif event.type == KEYDOWN and event.key == K_ESCAPE:
Finished ()
elif event.type == MOUSEBUTTONDOWN:
i=ComputeButton() #which button did we click
if i>=0:
Click.play() #play the sound
ser.write(IR_Codes[i]) #send the codes
elif event.type==MOUSEMOTION:
i=ComputeButton() #which button are we over
if i!=previous: #difference in the last one?
if i>=0: #turn it red
Show_Text(i,screen,(255,0,0))
else: #or put it back the way it was
screen.blit(bg,(0,0))
previous=i
pygame.display.flip() #update the display
# That's all folks

View File

@ -1,62 +0,0 @@
//POV-Ray source to generate the background image for IRserial_remote
// create rectangular areas with rounded corners for use as
// buttons and background objects.
// Render at 1024x768 then crop 312 pixels from each side
// leaving 400x768 final image.
#declare Area=15; //size of area lights
#declare CR=0.1; //corner radius
#declare ER= 0.5; //edge radius
#declare CX= 3; //width from corner to corner
#declare CY= 7.75; //height from corner to corner
#declare BZ=-ER; //Z offset for buttons
plane {z,0 pigment{rgb<0.8,0.85,1>*0.8}}//background
#macro Thing (ER,CR,CX,CY,T)
#local Corner=
union {
torus {CR,ER rotate x*90}
cylinder {ER*z,-ER*z,CR}
}
union {
object{Corner translate< CX,CY,0>}
object{Corner translate<-CX,CY,0>}
object{Corner translate< CX,-CY,0>}
object{Corner translate<-CX,-CY,0>}
cylinder{CY*y,-CY*y,ER translate<-CX-CR,0,0>}
cylinder{CY*y,-CY*y,ER translate< CX+CR,0,0>}
cylinder{CX*x,-CX*x,ER translate<0,-CY-CR,0>}
cylinder{CX*x,-CX*x,ER translate<0, CY+CR,0>}
box{<-CX,-CY-CR,-ER><CX,CY+CR,ER>}
box{<-CX-CR,-CY,-ER><CX+CR,CY,ER>}
texture {T}
}
#end
#declare BX= 0.4; #declare BY=BX;//size of the buttons
#declare White_Texture=texture{pigment{rgb 1}finish {ambient 0.3}}
#declare Blue_Texture=texture{pigment {rgb<0.85,0.9 ,1>}}
object {Thing(ER,CR,CX,CY, White_Texture)}//main object
//loop through the buttons
#declare R=-4.5;
#while (R<5.5)
#declare C=-1.5;
#while (C<=1.5)
object{Thing(0.1,0.2,(BX*0.8),(BY*0.8), Blue_Texture)
translate <C*BX*4,R*BY*4,BZ>
}
#declare C=C+1;
#end
#declare R=R+1;
#end
light_source{<50,50,-100>*5 color 0.8
#if (Area)area_light x*Area,y*Area,9,9#end
}
light_source{<0,0,-400>*3 rgb 1}
camera{orthographic location <0,0,-120> look_at <0,0,0> angle 11 }
//That's all folks!

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

View File

@ -1,68 +0,0 @@
/* Example program for from IRLib an Arduino library for infrared encoding and decoding
* Version 1.1 April 2013 by Chris Young http://cyborg5.com
* "IRservo" Control a servo using an IR remote
*/
#include <IRLib.h>
#include <Servo.h>
// You will have to set these values depending on the protocol
// and remote codes that you are using. These are from my Sony DVD/VCR
#define MY_PROTOCOL SONY
#define RIGHT_ARROW 0x86bca //Move several clockwise
#define LEFT_ARROW 0x46bca //Move servo counterclockwise
#define SELECT_BUTTON 0xd0bca //Center the servo
#define UP_ARROW 0x42bca //Increased number of degrees servo moves
#define DOWN_ARROW 0xc2bca //Decrease number of degrees servo moves
#define BUTTON_0 0x90bca //Pushing buttons 0-9 moves to fix positions
#define BUTTON_1 0x00bca // each 20 degrees greater
#define BUTTON_2 0x80bca
#define BUTTON_3 0x40bca
#define BUTTON_4 0xc0bca
#define BUTTON_5 0x20bca
#define BUTTON_6 0xa0bca
#define BUTTON_7 0x60bca
#define BUTTON_8 0xe0bca
#define BUTTON_9 0x10bca
IRrecv My_Receiver(11);//Receive on pin 11
IRdecode My_Decoder;
Servo My_Servo; // create servo object to control a servo
int pos; // variable to store the servo position
int Speed; // Number of degrees to move each time a left/right button is pressed
void setup()
{
My_Receiver.No_Output();//Turn off any unused IR LED output circuit
My_Servo.attach(9); // attaches the servo on pin 9 to the servo object
pos = 90; // start at midpoint 90 degrees
Speed = 3; // servo moves 3 degrees each time left/right is pushed
My_Servo.write(pos); // Set initial position
My_Receiver.enableIRIn(); // Start the receiver
}
void loop()
{
if (My_Receiver.GetResults(&My_Decoder)) {
My_Decoder.decode();
if(My_Decoder.decode_type==MY_PROTOCOL) {
switch(My_Decoder.value) {
case LEFT_ARROW: pos=min(180,pos+Speed); break;
case RIGHT_ARROW: pos=max(0,pos-Speed); break;
case SELECT_BUTTON: pos=90; break;
case UP_ARROW: Speed=min(10, Speed+1); break;
case DOWN_ARROW: Speed=max(1, Speed-1); break;
case BUTTON_0: pos=0*20; break;
case BUTTON_1: pos=1*20; break;
case BUTTON_2: pos=2*20; break;
case BUTTON_3: pos=3*20; break;
case BUTTON_4: pos=4*20; break;
case BUTTON_5: pos=5*20; break;
case BUTTON_6: pos=6*20; break;
case BUTTON_7: pos=7*20; break;
case BUTTON_8: pos=8*20; break;
case BUTTON_9: pos=9*20; break;
}
My_Servo.write(pos); // tell servo to go to position in variable 'pos'
}
My_Receiver.resume();
}
}

View File

@ -1,120 +0,0 @@
/* Example program for from IRLib an Arduino library for infrared encoding and decoding
* Version 1.0 January 2013
* Copyright 2013 by Chris Young http://cyborg5.com
* Based on original example sketch for IRremote library
* Version 0.11 September, 2009
* Copyright 2009 Ken Shirriff
* http://arcfn.com
*/
/*
* This example demonstrates how to extend this library to add a new protocol
* without actually modifying or recompiling the library itself. It implements a 36 bit
* Samsung protocol that is used on a Blu-ray player that I own.
* Because a 36 bit value will not fit in the value field (only 32 bits) we have to create
* a second value field.
*/
#include <IRLib.h>
#include <IRLibMatch.h>
int RECV_PIN = 11;
IRrecv My_Receiver(RECV_PIN);
#define SAMSUNG36 (LAST_PROTOCOL+1) //Unfortunately cannot extend an enum. This is the best we can do.
/*Is the value in this if statement is "1" then we will extend the base decoder.
*The result is this will only decode Samsung 36 and no others.
*If the value is "0" we will extend the all-inclusive decoder.
*Try changing this value and note the effect on code size when compiling.
*/
#if(1)
#define MY_BASE IRdecodeBase
#else
#define MY_BASE IRdecode
#endif
class IRdecodeSamsung36: public virtual MY_BASE{
public:
bool decode(void);
unsigned int value2;
void Reset(void);
void DumpResults(void);
private:
bool GetBit(void);
int offset;
unsigned long data;
};
void IRdecodeSamsung36::Reset(void) {
MY_BASE::Reset();//respect your parents
value2=0;
};
bool IRdecodeSamsung36::GetBit(void) {
if (!MATCH_MARK (rawbuf[offset],500)) return DATA_MARK_ERROR;
offset++;
if (MATCH_SPACE(rawbuf[offset],1500)) {
data = (data << 1) | 1;
}
else if (MATCH_SPACE (rawbuf[offset],500)) {
data <<= 1;
}
else return DATA_SPACE_ERROR;
offset++;
return true;
};
/*
* According to http://www.hifi-remote.com/johnsfine/DecodeIR.html#Samsung36
* The IRP notation for this protocol is:
* {38k,500}<1,-1|1,-3>(9,-9,D:8,S:8,1,-9,E:4,F:8,-68u,~F:8,1,-118)+
* This means it uses 38k frequency. Base timing is multiples of 500.
* A "0" is mark(500) space(500). A "1" is mark (500) space(1500)
* The header is mark(4500) space(4500).
* The header is followed by 16 bits (8 device, 8 sub device)
* This is followed by a mark(500) space(4500).
* This is followed by 12 more bits (4+8)
* This is followed by 68us ofspace. Followed by eight more bits
* and a final stop bit.
*/
bool IRdecodeSamsung36::decode(void) {
if(MY_BASE::decode()) return true;
ATTEMPT_MESSAGE(F("Samsung36"));
if (rawlen != 78) return RAW_COUNT_ERROR;
if (!MATCH_MARK(rawbuf[1],4500)) return HEADER_MARK_ERROR;
if (!MATCH_SPACE(rawbuf[2],4500)) return HEADER_SPACE_ERROR;
offset=3; data=0;
//Get first 18 bits
while (offset < 16*2+2) if(!GetBit()) return false;
//Skip middle header
if (!MATCH_MARK(rawbuf[offset],500)) return DATA_MARK_ERROR;
offset++;
if (!MATCH_SPACE(rawbuf[offset],4500)) return DATA_SPACE_ERROR;
//save first 18 bits in "value" and reset data
offset++; value=data; data=0;
rawbuf[62]=(rawbuf[62]*USECPERTICK-68)/USECPERTICK;
while(offset<77)if(!GetBit()) return false;
bits =36;//set bit length
value2 = data;//put remaining bits in value2
decode_type= static_cast<IRTYPES>SAMSUNG36;
return true;
};
void IRdecodeSamsung36::DumpResults(void){
if(decode_type==SAMSUNG36) {
Serial.print(F("Decoded Samsung36: Value1:")); Serial.print(value, HEX);
Serial.print(F(": Value2:")); Serial.print(value2, HEX);
};
MY_BASE::DumpResults();
};
IRdecodeSamsung36 My_Decoder;
void setup()
{
Serial.begin(9600);
My_Receiver.enableIRIn(); // Start the receiver
}
void loop() {
if (My_Receiver.GetResults(&My_Decoder)) {
My_Decoder.decode();
My_Decoder.DumpResults();
My_Receiver.resume();
}
}

View File

@ -1,52 +0,0 @@
CHANGES
2015-01-10 (nb)
Fixed and improved initialization. New and improved printing of text. Updated texts.
- Fixed initialization commands.
- Implemented ssd1306_init more efficiently.
- New functions ssd1306_send_command_start, ssd1306_send_command_stop.
- Improved ssd1306_setpos, more efficient.
- Reimplemented function ssd1306_char_f6x8 as improved ssd1306_char_font6x8 printing single characters only, added new ssd1306_string_font6x8 for printing strings.
- The font8x16 functions and data moved to another file until properly implemented.
- Added to the Make file ssd1306xled8x16 file.
- Updated testing text displayed on the screen.
2015-01-10 (nb)
Changed default pins for display, now PB0=SCL and PB1=SDA. Source code reformatting, improvements, edited comments.
- Changed default pins for connecting to the display for consistency with the built-in TWI interface, they are now PB0=SCL and PB1=SDA.
- Source code, removed redundant initializations of variables.
- Source code reformatting, edited comments.
2015-01-10 (nb)
Fixed some warnings, variables renamed. The font16x16/Chinese stuff moved to other folders.
- Font variable ssd1306xled_font8X16 renamed to ssd1306xled_font8x16 for consistency. TODO: rename "ssd1306xled_font8x16" file as well.
- Fixed ssd1306_draw_bmp prototype: added "const" to bitmap so it wont't generate warning.
- Files related to font 16x16 (Chinese) moved to different folders: font16x16cn.h.
- Functions and other code related to font 16x16 (Chinese) moved to different folders.
- Source code reformatting, edited comments.
2014-10-26 (gs)
Make project compile on gcc-avr - turn static images to consts, and rename include of font16x16cn.h
2014-08-13 (nb)
More files added to the repository.
2014-08-11 (nb)
Files added to the repository.

View File

@ -1,246 +0,0 @@
/*
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
*
* @created: 2014-08-12
* @author: Neven Boyanov
*
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
*
*/
// ----------------------------------------------------------------------------
#include <stdlib.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "DigisparkOLED.h"
#include "font6x8.h"
#ifndef _nofont_8x16 // tBUG Optional removal to save code space
#include "font8x16.h"
#endif
// ----------------------------------------------------------------------------
// Some code based on "IIC_wtihout_ACK" by http://www.14blog.com/archives/1358
const uint8_t ssd1306_init_sequence [] PROGMEM = { // Initialization Sequence
0xAE, // Display OFF (sleep mode)
0x20, 0b00, // Set Memory Addressing Mode
// 00=Horizontal Addressing Mode; 01=Vertical Addressing Mode;
// 10=Page Addressing Mode (RESET); 11=Invalid
0xB0, // Set Page Start Address for Page Addressing Mode, 0-7
0xC8, // Set COM Output Scan Direction
0x00, // ---set low column address
0x10, // ---set high column address
0x40, // --set start line address
0x81, 0x3F, // Set contrast control register
0xA1, // Set Segment Re-map. A0=address mapped; A1=address 127 mapped.
0xA6, // Set display mode. A6=Normal; A7=Inverse
0xA8, 0x3F, // Set multiplex ratio(1 to 64)
0xA4, // Output RAM to Display
// 0xA4=Output follows RAM content; 0xA5,Output ignores RAM content
0xD3, 0x00, // Set display offset. 00 = no offset
0xD5, // --set display clock divide ratio/oscillator frequency
0xF0, // --set divide ratio
0xD9, 0x22, // Set pre-charge period
0xDA, 0x12, // Set com pins hardware configuration
0xDB, // --set vcomh
0x20, // 0x20,0.77xVcc
0x8D, 0x14, // Set DC-DC enable
0xAF // Display ON in normal mode
};
uint8_t oledFont, oledX, oledY = 0;
// Program: 5248 bytes
SSD1306Device::SSD1306Device(void){}
void SSD1306Device::begin(void)
{
Wire.begin();
for (uint8_t i = 0; i < sizeof (ssd1306_init_sequence); i++) {
ssd1306_send_command(pgm_read_byte(&ssd1306_init_sequence[i]));
}
clear();
}
void SSD1306Device::setFont(uint8_t font)
{
oledFont = font;
}
void SSD1306Device::ssd1306_send_command_start(void) {
Wire.beginTransmission(SSD1306);
Wire.write(0x00); // write command
}
void SSD1306Device::ssd1306_send_command_stop(void) {
Wire.endTransmission();
}
void SSD1306Device::ssd1306_send_data_byte(uint8_t byte)
{
if(Wire.writeAvailable()){
ssd1306_send_data_stop();
ssd1306_send_data_start();
}
Wire.write(byte);
}
void SSD1306Device::ssd1306_send_command(uint8_t command)
{
ssd1306_send_command_start();
Wire.write(command);
ssd1306_send_command_stop();
}
void SSD1306Device::ssd1306_send_data_start(void)
{
Wire.beginTransmission(SSD1306);
Wire.write(0x40); //write data
}
void SSD1306Device::ssd1306_send_data_stop(void)
{
Wire.endTransmission();
}
void SSD1306Device::setCursor(uint8_t x, uint8_t y)
{
ssd1306_send_command_start();
Wire.write(0xb0 + y);
Wire.write(((x & 0xf0) >> 4) | 0x10); // | 0x10
Wire.write((x & 0x0f) | 0x01); // | 0x01
ssd1306_send_command_stop();
oledX = x;
oledY = y;
}
void SSD1306Device::clear(void)
{
fill(0x00);
}
void SSD1306Device::fill(uint8_t fill)
{
uint8_t m,n;
for (m = 0; m < 8; m++)
{
ssd1306_send_command(0xb0 + m); // page0 - page1
ssd1306_send_command(0x00); // low column start address
ssd1306_send_command(0x10); // high column start address
ssd1306_send_data_start();
for (n = 0; n < 128; n++)
{
ssd1306_send_data_byte(fill);
}
ssd1306_send_data_stop();
}
setCursor(0, 0);
}
size_t SSD1306Device::write(byte c) {
uint8_t i = 0;
uint8_t ci = c - 32;
if(c == '\r')
return 1;
if(c == '\n'){
if(oledFont == FONT6X8) { // tBUG
oledY++;
// if ( oledY > 7) // tBUG
// oledY = 7;
}
else {
oledY+=2; //tBUG Large Font up by two
if ( oledY > 6) // tBUG
oledY = 6;
}
setCursor(0, oledY);
return 1;
}
if(oledFont == FONT6X8){
if (oledX > 122)
{
oledX = 0;
oledY++;
if ( oledY > 7) // tBUG
oledY = 7;
setCursor(oledX, oledY);
}
ssd1306_send_data_start();
for (i= 0; i < 6; i++)
{
ssd1306_send_data_byte(pgm_read_byte(&ssd1306xled_font6x8[ci * 6 + i]));
}
ssd1306_send_data_stop();
setCursor(oledX+6, oledY);
}
#ifndef _nofont_8x16 // tBUG
else{
if (oledX > 120)
{
oledX = 0;
oledY+=2; //tBUG Large Font up by two
// oledY++;
if ( oledY > 6) // tBUG
oledY = 6;
setCursor(oledX, oledY);
}
ssd1306_send_data_start();
for (i = 0; i < 8; i++)
{
Wire.write(pgm_read_byte(&ssd1306xled_font8x16[ci * 16 + i]));
}
ssd1306_send_data_stop();
setCursor(oledX, oledY + 1);
ssd1306_send_data_start();
for (i = 0; i < 8; i++)
{
Wire.write(pgm_read_byte(&ssd1306xled_font8x16[ci * 16 + i + 8]));
}
ssd1306_send_data_stop();
setCursor(oledX + 8, oledY - 1);
}
#endif
return 1;
}
void SSD1306Device::bitmap(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[])
{
uint16_t j = 0;
uint8_t y, x;
// if (y1 % 8 == 0) y = y1 / 8; // else y = y1 / 8 + 1; // tBUG :: this does nothing as y is initialized below
// THIS PARAM rule on y makes any adjustment here WRONG //usage oled.bitmap(START X IN PIXELS, START Y IN ROWS OF 8 PIXELS, END X IN PIXELS, END Y IN ROWS OF 8 PIXELS, IMAGE ARRAY);
for (y = y0; y < y1; y++)
{
setCursor(x0,y);
ssd1306_send_data_start();
for (x = x0; x < x1; x++)
{
ssd1306_send_data_byte(pgm_read_byte(&bitmap[j++]));
}
ssd1306_send_data_stop();
}
setCursor(0, 0);
}
SSD1306Device oled;
// ----------------------------------------------------------------------------

View File

@ -1,62 +0,0 @@
/*
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
*
* @created: 2014-08-12
* @author: Neven Boyanov
*
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
*
*/
#include <stdint.h>
#include <Arduino.h>
#include <Wire.h>
// #include <avr/pgmspace.h>
// #include <avr/interrupt.h>
#include <util/delay.h>
#ifndef DIGISPARKOLED_H
#define DIGISPARKOLED_H
// #define _nofont_8x16 //tBUG
#ifndef _nofont_8x16 //tBUG
#define FONT8X16 1
#endif
#define FONT6X8 0
// ----------------------------------------------------------------------------
#ifndef SSD1306
#define SSD1306 0x3C // Slave address
#endif
// ----------------------------------------------------------------------------
class SSD1306Device: public Print {
public:
SSD1306Device(void);
void begin(void);
void setFont(uint8_t font);
void ssd1306_send_command(uint8_t command);
void ssd1306_send_data_byte(uint8_t byte);
void ssd1306_send_data_start(void);
void ssd1306_send_data_stop(void);
void setCursor(uint8_t x, uint8_t y);
void fill(uint8_t fill);
void clear(void);
void bitmap(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[]);
void ssd1306_send_command_start(void);
void ssd1306_send_command_stop(void);
void ssd1306_char_f8x16(uint8_t x, uint8_t y, const char ch[]);
virtual size_t write(byte c);
using Print::write;
};
extern SSD1306Device oled;
// ----------------------------------------------------------------------------
#endif

View File

@ -1,11 +0,0 @@
Overhauled to support Wire library, print library, and generally be more "Arduino friendly" - renamed DigiOLED to avoid confussion - 1/14/2015 by Erik Kettenburg/Digistump
Ported to Arduino CPP and working on DigiStump Pro 1/11/15 by defragster
SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
SSD1306xLED is a C library for working with the SSD1306 display driver to control dot matrix OLED/PLED 128x64 displays. It is intended to be used with the Tinusaur board but should also work with any other board based on ATtiny85 or similar microcontroller.
SSD1306xLED is written in plain C and does not require any additional libraries to function except those that come with the WinAVR SDK.

View File

@ -1,28 +0,0 @@
RESEARCH
SSD1306
http://www.solomon-systech.com/en/product/display-ic/oled-driver-controller/ssd1306/
SSD1306 is a single-chip CMOS OLED/PLED driver with controller for organic / polymer light emitting diode dot-matrix graphic display system. It consists of 128 segments and 64 commons. This IC is designed for Common Cathode type OLED panel.
---- SSD1306 Datasheets ----
https://www.adafruit.com/datasheets/SSD1306.pdf
http://www.crystalfontz.com/controllers/Solomon_Systech_SSD1306_v1.1_April_2008.pdf
---- Other SSD1306 Libraries ----
---- Projects ----
---- Other References ----

View File

@ -1,6 +0,0 @@
TODO
- Implement power saving mode

View File

@ -1,39 +0,0 @@
#include <DigisparkOLED.h>
#include <Wire.h>
// ============================================================================
#include "img0_128x64c1.h"
#include "digistump_128x64c1.h"
void setup() {
// put your setup code here, to run once:
oled.begin();
}
void loop() {
// put your main code here, to run repeatedly:
oled.fill(0xFF); //fill screen with color
delay(1000);
oled.clear(); //all black
delay(1000);
//usage: oled.setCursor(X IN PIXELS, Y IN ROWS OF 8 PIXELS STARTING WITH 0);
oled.setCursor(0, 0); //top left
oled.setFont(FONT8X16);
oled.print(F("DIGISTUMP")); //wrap strings in F() to save RAM!
oled.setFont(FONT6X8);
oled.print(F(" OLED!"));
oled.setCursor(0, 2); //two rows down because the 8x16 font takes two rows of 8
oled.println(F("test")); //println will move the cursor 8 or 16 pixels down (based on the front) and back to X=0
oled.print(F("test test test test test")); //lines auto wrap
delay(3000);
//usage oled.bitmap(START X IN PIXELS, START Y IN ROWS OF 8 PIXELS, END X IN PIXELS, END Y IN ROWS OF 8 PIXELS, IMAGE ARRAY);
oled.bitmap(0, 0, 128, 8, img0_128x64c1);
delay(3000);
oled.bitmap(0, 0, 128, 8, digistumplogo);
delay(3000);
}

View File

@ -1,75 +0,0 @@
//------------------------------------------------------------------------------
// File generated by LCD Assistant
// http://en.radzio.dxp.pl/bitmap_converter/
//------------------------------------------------------------------------------
#include <avr/pgmspace.h>
const uint8_t digistumplogo [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xF0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
0xE0, 0xE0, 0xE0, 0xE0, 0xF0, 0xF8, 0xF8, 0xFC, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xE0, 0xF0, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xBF, 0xDF, 0xFF,
0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x0F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C,
0xFC, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC,
0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC, 0xFC,
0xFC, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3F, 0xBF, 0x9F, 0xDF, 0xEF, 0xEF, 0xF7, 0xF7, 0xFB, 0xFD, 0xFD, 0xFE, 0xFF, 0x7F, 0x7F, 0x7F,
0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x0F, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C,
0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0x3C, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFF, 0xFF, 0xFF,
0xFF, 0x3F, 0x3F, 0x03, 0x03, 0x03, 0x03, 0x3F, 0x3F, 0x3F, 0x3F, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C,
0x3C, 0x3C, 0xFC, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C,
0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC, 0xFC,
0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC, 0xFC, 0xFC,
0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x1E,
0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0xFE, 0xFE, 0xE0, 0xE0, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F,
0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F,
0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E,
0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E,
0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E,
0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F,
0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

View File

@ -1,76 +0,0 @@
//------------------------------------------------------------------------------
// File generated by LCD Assistant
// http://en.radzio.dxp.pl/bitmap_converter/
//------------------------------------------------------------------------------
#include <avr/pgmspace.h>
// ----------------------------------------------------------------------------
const uint8_t img0_128x64c1 [] PROGMEM = {
0x00,0x03,0x05,0x09,0x11,0xFF,0x11,0x89,0x05,0xC3,0x00,0xE0,0x00,0xF0,0x00,0xF8,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x28,0xFF,0x11,0xAA,0x44,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x01,0x38,0x44,0x82,0x92,
0x92,0x74,0x01,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x44,0xFF,0x01,0x7D,
0x7D,0x7D,0x01,0x7D,0x7D,0x7D,0x7D,0x01,0x7D,0x7D,0x7D,0x7D,0x7D,0x01,0xFF,0x00,
0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x3F,0x03,0x03,
0xF3,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x01,0xF1,0x11,0x61,0x81,0x01,0x01,0x01,
0x81,0x61,0x11,0xF1,0x01,0x01,0x01,0x01,0x41,0x41,0xF1,0x01,0x01,0x01,0x01,0x01,
0xC1,0x21,0x11,0x11,0x11,0x11,0x21,0xC1,0x01,0x01,0x01,0x01,0x41,0x41,0xF1,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x11,0x11,0x11,0x11,0x11,0xD3,0x33,
0x03,0x03,0x3F,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xE0,0x00,0x00,
0x7F,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x7F,0x00,0x00,0x01,0x06,0x18,0x06,
0x01,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x40,0x40,0x7F,0x40,0x40,0x00,0x00,0x00,
0x1F,0x20,0x40,0x40,0x40,0x40,0x20,0x1F,0x00,0x00,0x00,0x00,0x40,0x40,0x7F,0x40,
0x40,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x40,0x30,0x0C,0x03,0x00,0x00,
0x00,0x00,0xE0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x06,0x06,
0x06,0x06,0x04,0x04,0x04,0x84,0x44,0x44,0x44,0x84,0x04,0x04,0x84,0x44,0x44,0x44,
0x84,0x04,0x04,0x04,0x84,0xC4,0x04,0x04,0x04,0x04,0x84,0x44,0x44,0x44,0x84,0x04,
0x04,0x04,0x04,0x04,0x84,0x44,0x44,0x44,0x84,0x04,0x04,0x04,0x04,0x04,0x84,0x44,
0x44,0x44,0x84,0x04,0x04,0x84,0x44,0x44,0x44,0x84,0x04,0x04,0x04,0x04,0x06,0x06,
0x06,0x06,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x10,0x18,0x14,0x12,0x11,0x00,0x00,0x0F,0x10,0x10,0x10,
0x0F,0x00,0x00,0x00,0x10,0x1F,0x10,0x00,0x00,0x00,0x08,0x10,0x12,0x12,0x0D,0x00,
0x00,0x18,0x00,0x00,0x0D,0x12,0x12,0x12,0x0D,0x00,0x00,0x18,0x00,0x00,0x10,0x18,
0x14,0x12,0x11,0x00,0x00,0x10,0x18,0x14,0x12,0x11,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x7F,0x03,0x0C,0x30,0x0C,0x03,0x7F,0x00,0x00,0x38,0x54,0x54,0x58,0x00,0x00,
0x7C,0x04,0x04,0x78,0x00,0x00,0x3C,0x40,0x40,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xAA,0xAA,0xAA,
0x28,0x08,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x03,0x0C,0x30,0x0C,0x03,0x7F,
0x00,0x00,0x26,0x49,0x49,0x49,0x32,0x00,0x00,0x7F,0x02,0x04,0x08,0x10,0x7F,0x00,
};

View File

@ -1,113 +0,0 @@
/*
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
*
* @created: 2014-08-12
* @author: Neven Boyanov
*
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
*
*/
// ----------------------------------------------------------------------------
#include <avr/pgmspace.h>
// ----------------------------------------------------------------------------
/* Standard ASCII 6x8 font */
const uint8_t ssd1306xled_font6x8 [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // "
0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // #
0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $
0x00, 0x62, 0x64, 0x08, 0x13, 0x23, // %
0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // &
0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // '
0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // (
0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // )
0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // *
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // +
0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // ,
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // -
0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // .
0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // /
0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1
0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2
0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3
0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4
0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5
0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7
0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8
0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9
0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // :
0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ;
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // <
0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // =
0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // >
0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ?
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A
0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B
0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C
0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D
0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E
0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F
0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G
0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H
0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I
0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J
0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K
0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L
0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N
0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O
0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P
0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R
0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S
0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T
0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U
0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V
0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W
0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X
0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y
0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [
0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55, // 55
0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ]
0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _
0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // '
0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a
0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b
0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c
0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d
0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e
0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f
0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h
0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i
0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k
0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l
0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m
0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n
0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o
0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p
0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q
0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r
0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s
0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t
0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u
0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v
0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w
0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x
0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y
0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, // z
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, // horiz lines
};
// ----------------------------------------------------------------------------

View File

@ -1,116 +0,0 @@
/*
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
*
* @created: 2014-08-12
* @author: Neven Boyanov
*
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
*
*/
// ----------------------------------------------------------------------------
#include <avr/pgmspace.h>
// ----------------------------------------------------------------------------
/* Standard ASCII 8x16 font */
const uint8_t ssd1306xled_font8x16 [] PROGMEM = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 0
0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00, // ! 1
0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // " 2
0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00, // # 3
0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00, // $ 4
0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00, // % 5
0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10, // & 6
0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ' 7
0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00, // ( 8
0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00, // ) 9
0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00, // * 10
0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00, // + 11
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00, // , 12
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01, // - 13
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00, // . 14
0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00, // / 15
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00, // 0 16
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // 1 17
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00, // 2 18
0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00, // 3 19
0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00, // 4 20
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00, // 5 21
0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00, // 6 22
0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00, // 7 23
0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00, // 8 24
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00, // 9 25
0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00, // : 26
0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00, // ; 27
0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00, // < 28
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00, // = 29
0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00, // > 30
0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00, // ? 31
0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00, // @ 32
0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20, // A 33
0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00, // B 34
0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00, // C 35
0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00, // D 36
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00, // E 37
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00, // F 38
0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00, // G 39
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20, // H 40
0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // I 41
0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00, // J 42
0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00, // K 43
0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00, // L 44
0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00, // M 45
0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00, // N 46
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00, // O 47
0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00, // P 48
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00, // Q 49
0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20, // R 50
0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00, // S 51
0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00, // T 52
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00, // U 53
0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00, // V 54
0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00, // W 55
0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20, // X 56
0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00, // Y 57
0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00, // Z 58
0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00, // [ 59
0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00, // \ 60
0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00, // ] 61
0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ^ 62
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, // _ 63
0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ` 64
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20, // a 65
0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00, // b 66
0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00, // c 67
0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20, // d 68
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00, // e 69
0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // f 70
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00, // g 71
0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20, // h 72
0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // i 73
0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00, // j 74
0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00, // k 75
0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // l 76
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F, // m 77
0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20, // n 78
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00, // o 79
0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00, // p 80
0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80, // q 81
0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00, // r 82
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00, // s 83
0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00, // t 84
0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20, // u 85
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00, // v 86
0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00, // w 87
0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00, // x 88
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00, // y 89
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00, // z 90
0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40, // { 91
0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00, // | 92
0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00, // } 93
0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ~ 94
};
// ----------------------------------------------------------------------------

View File

@ -1,115 +0,0 @@
#include <RcSeq.h>
#include <TinyPinChange.h>
#include <SoftRcPulseIn.h>
/*
IMPORTANT:
For this sketch to compile, RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT and RC_SEQ_WITH_SHORT_ACTION_SUPPORT shall be defined
in PathOfTheLibraries/(Digispark)RcSeq/RcSeq.h and RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT shall be commented.
This sketch demonstrates how to easily use a 3 positions switch on a channel of a RC Transmitter with <RcSeq> library.
1) If the switch is at the MIDDLE position, a LED will be OFF
2) If the switch is at the DOWN position, a LED will be ON
2) If the switch is at the UP position, a LED will blink
This sketch can be extended to a rotactor (up to 8 positions)
RC Navy (2013)
http://p.loussouarn.free.fr
WIRING A TRANSMITTER SIDE WIRING AT RECEIVER SIDE
.------+-------------> +
| |
/ | # .-------------------------.
| UP o # 4.7K | |
| \ # | ARDUINO or ATTINY |
3 positions | \ | | | R
switch < MIDDLE o o---+-------------> To Tx Channel Rx Channel->|RC_CHANNEL_PIN LED_PIN >----###---|>|----|GND
| C | | | LED
| # | Sketch |
| DOWN o # 4.7K '-------------------------' External or
\ | # Built-in LED
| |
'------+-------------> -
.------------.------------------------.--------------.
| Switch Pos | Pulse Width Range (us) | Action |
+------------+------------------------+--------------+
| UP | 1000 -> 1270 | LED Blinking |
+------------+------------------------+--------------+
| MIDDLE | 1360 -> 1630 | LED OFF |
+------------+------------------------+--------------+
| DOWN | 1720 -> 1990 | LED ON |
'------------'------------------------'--------------'
Note:
====
<RcSeq> computes automatically the valid pulse width range for each position of the switch.
*/
/* Channel Declaration */
enum {RC_CHANNEL=0, RC_CHANNEL_NB}; /* Here, as there is a single channel, we could used a simple "#define RC_CHANNEL 0" rather an enumeration */
#define RC_CHANNEL_PIN 0 // Choose here the pin
#define LED_PIN 1 // Choose here the pin
enum {SW_POS_DOWN=0, SW_POS_MIDDLE, SW_POS_UP, SW_POS_NB}; /* Switch has 3 positions: Down, Middle and Up (For a rotactor with more positions, add positions here) */
boolean BlinkCmd=false;
boolean LedState=false;
void setup()
{
RcSeq_Init();
RcSeq_DeclareSignal(RC_CHANNEL, RC_CHANNEL_PIN); /* RC_CHANNEL Channel is assigned to RC_CHANNEL_PIN pin */
RcSeq_DeclareMultiPosSwitch(RC_CHANNEL, 1000, 2000, SW_POS_NB); /* Tells to <RcSeq> that the RC_CHANNEL channel has SW_POS_NB positions distributed between 1000 and 2000 us */
RcSeq_DeclareCommandAndShortAction(RC_CHANNEL, SW_POS_DOWN, ActionSwPosDown); /* Action assigned to DOWN position */
RcSeq_DeclareCommandAndShortAction(RC_CHANNEL, SW_POS_MIDDLE, ActionSwPosMiddle); /* Action assigned to MIDDLE position */
RcSeq_DeclareCommandAndShortAction(RC_CHANNEL, SW_POS_UP, ActionSwPosUp); /* Action assigned to UP position */
pinMode(LED_PIN, OUTPUT);
}
void loop()
{
static uint32_t StartMs=millis();
/* Refresh RcSeq (mandatory) */
RcSeq_Refresh();
/* Blink Management */
if( (BlinkCmd==true) && (millis() - StartMs >= 250UL) )
{
StartMs=millis();
LedState=!LedState;
digitalWrite(LED_PIN, LedState);
}
}
void ActionSwPosUp() /* This function will be called when the switch is in UP position */
{
BlinkCmd=true;
}
void ActionSwPosMiddle() /* This function will be called when the switch is in MIDDLE position */
{
BlinkCmd=false;
LedState=false;
digitalWrite(LED_PIN, LedState);
}
void ActionSwPosDown() /* This function will be called when the switch is in DOWN position */
{
BlinkCmd=false;
LedState=true;
digitalWrite(LED_PIN, LedState);
}

View File

@ -1,307 +0,0 @@
/*
This sketch illustrates 2 new features of the <RcSeq> library (since the V2.1 version):
1) the "control" capability: it's a function passed as argument to the RcSeq_DeclareCommandAndSequence() method.
It is used to check if a sequence can be launched or not, depending of specific condition
It is also used to inform the sequence is finished: this can be used to memorize in EEPROM the sequence id.
Like that, at the next start-up the position of the servos can be restored according to the last position of the sequence.
2) the "timeout" capability:
The RcSeq_Timeout() method can be used to check if the command signal remains constant (HIGH or LOW).
It's then possible to launch the sequence based on the static state of the command pin rather than a Rc Pulse width.
In practice, it's possible to use both manners to launch a sequence as done in the sketch below.
THE SKETCH:
==========
In this sketch, the first declared sequence opens the 2 doors with the help of 2 servos (1 per door).
The second declared sequence closes the 2 doors with the help of 2 servos (1 per door).
The 2 doors cannot open or close simultaneously with the same speed since there is a nosing secured to the right door.
This nosing forces to open and close the doors using sequences.
Opening <- -> Opening
. .
. .
. .
. .
. .
. .
. .
__ nosing -> .------. __
/ \----------------'---. '----------------/ \
\__/-------------------''-------------------\__/
Left door Right door
TOP VIEW
The opening sequence is like hereafter:
======================================
1) The servo assigned to the right door starts
2) Once rigth door slightly opened, the servo assigned to the left door starts, whilst the servo assigned to the right door resumes its travel
3) Once the 2 servos reached 90°, the 2 doors stop; the opening sequence is finished
The closing sequence is like hereafter:
======================================
1) The 2 servos assigned to the left and right doors start together but the left servo rotates more quickly than the right servo.
2) As a consequence, the left door is closed berfore the right door
3) Once the 2 servos reached 90°, the 2 doors stop; the closing sequence is finished
The sequences of this sketch can be launched either a RC channel either a regular ON/OFF switch:
===============================================================================================
A) Command from a RC channel:
------------------------- _______________
V _______________ | __ |
| __________ | ARDUINO: |________| / \ Left |
| | | | | | \__/ Servo |
| | RC |CH | UNO | |_______________|
'-+ Receiver |----| MEGA | _______________
| | | Digispark | | __ |
|__________| | Digispark pro |________| / \ Right |
|_______________| | \__/ Servo |
|_______________|
B) Command from a ON/OFF switch:
---------------------------- _______________
_______________ | __ |
| ARDUINO: |________| / \ Left |
| | | \__/ Servo |
| UNO | |_______________|
.----| MEGA | _______________
| | Digispark | | __ |
ON/OFF Switch \ | Digispark pro |________| / \ Right |
| |_______________| | \__/ Servo |
-+- |_______________|
GND
*/
/*************************************************/
/* STEP #1: Include the required libraries */
/*************************************************/
#include <RcSeq.h>
#include <TinyPinChange.h>
#include <SoftRcPulseIn.h>
#include <SoftRcPulseOut.h>
#include <EEPROM.h>
/*****************************************************************/
/* STEP #2: Enumeration of the RC Signals used in the sequence */
/*****************************************************************/
enum {RC_SIGNAL = 0, SIGNAL_NB}; /* Here, a single RC signal is used */
/******************************************************************/
/* STEP #3: Enumeration of the different position of the RC stick */
/******************************************************************/
enum {RC_PULSE_LEVEL_MINUS_1 = 0, RC_PULSE_LEVEL_PLUS_1, RC_PULSE_NB};
/*****************************************************************/
/* STEP #4: Enumeration of the servos used in the sequences */
/*****************************************************************/
enum {DOOR_SERVO_LEFT = 0, DOOR_SERVO_RIGHT, SERVO_NB}; /* In this sketch, 2 servos are declared */
/***************************************************/
/* STEP #5: Digital pin assignment for Command */
/***************************************************/
#define COMMAND_PIN 2 /* This pin can be connected to a channel of a RC Receiver or to a regular ON/OFF switch (switch wired between pin and Ground) */
/**************************************************/
/* STEP #6: Digital Pins assignment for Servos */
/**************************************************/
#define DOOR_SERVO_LEFT_PIN 3
#define DOOR_SERVO_RIGHT_PIN 4
/*************************************************************************************/
/* STEP #7: Declaration of the angle of the servos for the different motions (in °) */
/*************************************************************************************/
#define DOOR_SERVO_OPENED_LEFT_POS 135 /* position of the left Servo when left door is opened */
#define DOOR_SERVO_CLOSED_LEFT_POS 45 /* position of the left Servo when left door is closed */
#define DOOR_SERVO_OPENED_RIGHT_POS 45 /* position of the right Servo when right door is opened */
#define DOOR_SERVO_CLOSED_RIGHT_POS 135 /* position of the right Servo when right door is closed */
/***************************************************************************************************************************************/
/* STEP #8: Do a temporal diagram showing the start up and the duration of each motions of each servo */
/***************************************************************************************************************************************/
/*
1) OPENING MOTION OF THE DOORS
===========================
All the start up values (time stamp) have as reference the moment of the sequence startup order (t=0).
1.1 MOTION OF THE LEFT DOOR SERVO FOR OPENING
=========================================
Order <---OPENING_DURATION_LEFT_MS--->
|-----------------------------|--------------------------------|-->Time Axis
0 OPENING_START_LEFT_MS
1.2 MOTION OF THE RIGHT DOOR SERVO FOR OPENING
==========================================
Order <--------OPENING_DURATION_RIGHT_MS------->
|-------------------|------------------------------------------|-->Time Axis
0 OPENING_START_RIGHT_MS
2) CLOSING MOTION OF THE DOORS
===========================
All the start up values (time stamp) have as reference the moment of the sequence startup order (t=0).
2.1 MOTION OF THE LEFT DOOR SERVO FOR CLOSING
=========================================
Order <---CLOSING_DURATION_LEFT_MS--->
|-------------------|--------------------------------|------------>Time Axis
0 CLOSING_START_LEFT_MS
2.2 MOTION OF THE RIGTH DOOR SERVO FOR CLOSING
==========================================
Order <--------CLOSING_DURATION_RIGHT_MS------->
|-------------------|------------------------------------------|-->Time Axis
0 CLOSING_START_RIGHT_MS
*/
/**************************************************************************************************************************************************/
/* STEP #9: With the help of the temporal diagram, declare start up time, the motion duration of servo and optional delay */
/**************************************************************************************************************************************************/
/* Tune below all the motion duration. Do not forget to add a trailer 'UL' for each value to force them in Unsigned Long type */
#define OPENING_START_LEFT_MS 500UL //This means the left servo motion will be delayed of 500ms AFTER the order
#define OPENING_DURATION_LEFT_MS 2500UL //The left door motion ends after 500+2500=3s, as the right door
#define OPENING_START_RIGHT_MS 0UL //Immediate start
#define OPENING_DURATION_RIGHT_MS 3000UL //The right door motion ends after 3s
#define CLOSING_START_LEFT_MS 0UL //Immediate start
#define CLOSING_DURATION_LEFT_MS 3000UL //The left door will be closed BEFORE the right door
#define CLOSING_START_RIGHT_MS 0UL //Immediate start
#define CLOSING_DURATION_RIGHT_MS 4000UL //The right door will be closed AFTER the left door
/********************************************************************************************************************/
/* STEP #10: Declare here the percentage of motion to be performed at half speed for servo start up and stop */
/********************************************************************************************************************/
#define START_STOP_PER_CENT 5 /* Percentage of motion performed at half-speed for starting and stopping the servos (Soft start et Soft stop) */
/************************************************************************************************************/
/* STEP #11: Use a "const SequenceSt_t" structure table to declare the servo sequence */
/* For each table entry, arguments are: */
/* - Servo Index */
/* - Initial Servo Position in ° */
/* - Final Servo Position in ° */
/* - Motion Start Time Stamp in ms */
/* - Motion duration in ms between initial and final position */
/* - Percentage of motion performed at half speed for servo start and servo stop (Soft start and Soft stop) */
/************************************************************************************************************/
/* Table describing the motions of the 2 servos for opening the 2 doors */
const SequenceSt_t OpeningSequence[] PROGMEM = {/* Servo Id , Initial Angle , Final Angle , Delay after order , Motion Duration , Percentage at half speed */
/* 1st Servo */ MOTION_WITH_SOFT_START_AND_STOP(DOOR_SERVO_LEFT, DOOR_SERVO_CLOSED_LEFT_POS, DOOR_SERVO_OPENED_LEFT_POS, OPENING_START_LEFT_MS, OPENING_DURATION_LEFT_MS, START_STOP_PER_CENT)
/* 2nd Servo */ MOTION_WITH_SOFT_START_AND_STOP(DOOR_SERVO_RIGHT, DOOR_SERVO_CLOSED_RIGHT_POS, DOOR_SERVO_OPENED_RIGHT_POS, OPENING_START_RIGHT_MS, OPENING_DURATION_RIGHT_MS, START_STOP_PER_CENT)
};
/* Table describing the motions of the 2 servos for closing the 2 doors */
const SequenceSt_t ClosingSequence[] PROGMEM = {/* Servo Id , Initial Angle , Final Angle , Delai after order , Motion Duration , Percentage at half speed */
/* 1st Servo */ MOTION_WITH_SOFT_START_AND_STOP(DOOR_SERVO_LEFT, DOOR_SERVO_OPENED_LEFT_POS, DOOR_SERVO_CLOSED_LEFT_POS, CLOSING_START_LEFT_MS, CLOSING_DURATION_LEFT_MS, START_STOP_PER_CENT)
/* 2nd Servo */ MOTION_WITH_SOFT_START_AND_STOP(DOOR_SERVO_RIGHT, DOOR_SERVO_OPENED_RIGHT_POS, DOOR_SERVO_CLOSED_RIGHT_POS, CLOSING_START_RIGHT_MS, CLOSING_DURATION_RIGHT_MS, START_STOP_PER_CENT)
};
enum {COMMAND_OPEN = 0, COMMAND_CLOSE};
/* GLOBAL VARIABLES */
uint8_t LastExecutedSeqIdx;
void setup()
{
#if !defined(__AVR_ATtiny24__) && !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(__AVR_ATtiny25__) && !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny167__)
Serial.begin(9600);
Serial.print(F("RcSeq library V"));Serial.print(RcSeq_LibTextVersionRevision());Serial.println(F(" demo: advanced doors sequences"));
#endif
/***************************************************************************/
/* STEP #12: Init <RcSeq> library */
/***************************************************************************/
RcSeq_Init();
/****************************************************************************************/
/* STEP #13: declare the servo command signals with their digital pin number */
/****************************************************************************************/
RcSeq_DeclareSignal(RC_SIGNAL, COMMAND_PIN);
/******************************************************************************************/
/* STEP #14: declare a stick assigned to the RC signal having RC_PULSE_NB positions */
/******************************************************************************************/
RcSeq_DeclareStick(RC_SIGNAL, 1000, 2000, RC_PULSE_NB);
/****************************************************************************************/
/* STEP #15: declare the servo command signals with their digital pin number */
/****************************************************************************************/
RcSeq_DeclareServo(DOOR_SERVO_LEFT, DOOR_SERVO_LEFT_PIN);
RcSeq_DeclareServo(DOOR_SERVO_RIGHT, DOOR_SERVO_RIGHT_PIN);
/*******************************************************************************************************/
/* STEP #16: declare the sequence assigned to specific position of the stick assigned to the RC signal */
/*******************************************************************************************************/
RcSeq_DeclareCommandAndSequence(RC_SIGNAL, RC_PULSE_LEVEL_MINUS_1, RC_SEQUENCE(OpeningSequence), Control); // Declare a sequence triggered by a RC pulse Level Minus 1 (stick at extreme position during at least 250 ms)
RcSeq_DeclareCommandAndSequence(RC_SIGNAL, RC_PULSE_LEVEL_PLUS_1, RC_SEQUENCE(ClosingSequence), Control); // Declare a sequence triggered by a RC pulse Level Plus 1 (stick at extreme position during at least 250 ms)
/*******************************************************************************************/
/* STEP #17: Initialize the position of the servos according to the last finished sequence */
/*******************************************************************************************/
LastExecutedSeqIdx = EEPROM.read(0);
if (LastExecutedSeqIdx == COMMAND_OPEN)
{
RcSeq_ServoWrite(DOOR_SERVO_LEFT, DOOR_SERVO_OPENED_LEFT_POS);
RcSeq_ServoWrite(DOOR_SERVO_RIGHT, DOOR_SERVO_OPENED_RIGHT_POS);
}
else
{
RcSeq_ServoWrite(DOOR_SERVO_LEFT, DOOR_SERVO_CLOSED_LEFT_POS);
RcSeq_ServoWrite(DOOR_SERVO_RIGHT, DOOR_SERVO_CLOSED_RIGHT_POS);
}
}
void loop()
{
uint8_t RcSignalPinState;
/****************************************************************************************************************/
/* STEP #18: call the refresh function inside the loop() to catch RC commands and to manage the servo positions */
/****************************************************************************************************************/
RcSeq_Refresh();
/*********************************************************************************************************/
/* STEP #19: optionally, allow launching the Sequences ou Actions on Timeout (cmd with a regular switch) */
/*********************************************************************************************************/
if (RcSeq_SignalTimeout(RC_SIGNAL, 250, &RcSignalPinState))
{
/* Launch the"OpeningSequence" sequence if a LOW level is present during at least 250ms: this allows testing the sequence of servo without using a RC set, just using a regular switch */
if((LastExecutedSeqIdx == COMMAND_CLOSE) && (RcSignalPinState == LOW))
{
RcSeq_LaunchSequence(OpeningSequence);
}
/* Launch the"ClosingSequence" sequence if a HIGH level is present during at least 250ms: this allows testing the sequence of servo without using a RC set, just using a regular switch */
if((LastExecutedSeqIdx == COMMAND_OPEN) && (RcSignalPinState == HIGH))
{
RcSeq_LaunchSequence(ClosingSequence);
}
}
}
/* The Control() fonction is automatically called by the RcSeq library */
uint8_t Control(uint8_t Action, uint8_t SeqIdx)
{
uint8_t Ret = 0;
#if !defined(__AVR_ATtiny24__) && !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(__AVR_ATtiny25__) && !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny167__)
Serial.print("Action=");Serial.print(Action);Serial.print(" SeqIdx=");Serial.println(SeqIdx);
#endif
switch(Action)
{
case RC_SEQ_START_CONDITION: /* RcSeq asks if the conditions are met to launch the sequence SeqIdx */
/* Put here a condition to allow RcSeq launching the sequence SeqIdx (Put Ret=1 if no specific condition) */
Ret = (SeqIdx != LastExecutedSeqIdx); /* Allows RcSeq launching the sequence if the sequence to launch is different from the last one */
break;
case RC_SEQ_END_OF_SEQ: /* RcSeq informs the sequence SeqIdx is finished */
/* We memorize the last finished sequence id in EEPROM memory. Like that, at next power-up, we will know how to position the servos ( done in the Setup() ) */
EEPROM.write(0, SeqIdx);
LastExecutedSeqIdx = SeqIdx;
break;
}
return(Ret);
}

View File

@ -1,116 +0,0 @@
RcSeq library
=============
**RcSeq** is an asynchronous library for ATmega328P (**UNO**), ATmega2560 (**MEGA**), ATtiny84, ATtiny85 (**Digispark**) and ATtiny167 (**Digispark pro**) to easily create **servo's sequences** and/or to execute **short actions** from RC commands, from a digital input, or from a launch function called in the sketch.
The **A**pplication **P**rogramming **I**nterface (**API**) makes **RcSeq** library very easy to use.
Some definitions:
----------------
* **Sequence**: is used to sequence one or several servos (sequence is defined in a structure in the user's sketch to be performed when the RC command rises). The Sequence table (structure) may contain some servo motions and some short actions to call at a predefined time. For each servo, start angle, end angle and speed are tunable.
* **Short Action**: is used to perform a quick action (action is a short function defined in the user's sketch to be called when the RC command rises). The duration must be less than 20ms to not disturb the servo commands.
Some examples of use cases:
--------------------------
* **A landing gear retract:**
* Lock, door and leg servos sequenced with a single RC channel
* from a predefined position of the stick on the transmitter
* from the 2 positions "Aux Channel" of the transmitter
* **Navigation lights for aircraft:**
* Anticollision, beacon, landing lights commanded:
* from predefined positions of the stick on the transmitter
* from push-buttons in place of the stick potentiometer
* **Multi-switch:**
* Up to 8 digital pins driven from a single RC channel
* using the stick of the transmitter
* using 8 push-buttons in place of the stick potentiometer
* **Zodiac animation:**
* A pneumatic Zodiac dropped at sea and lifted back to the deck of a ship. Drop and lift sequences commanded:
* from predefined positions of the stick on the transmitter
* from a regular ON/OFF switch (for demo on table without RC set)
* **Animatronics sequences:**
* leg motion,
* mouth motion,
* eyes motion,
* etc.
Triggers:
--------
**Sequences** and **short actions** can be trigged by:
* a RC signal (eg: RC receiver output)
* from one or several **predefined positions of a stick** of the transmitter
* from one or several **push-button** (keyboard) replacing a a stick of the transmitter. (**RcSeq** assumes Push-Buttons associated Pulse duration are equidistant).
* from **Custom Keyboard** replacing a stick of the the transmitter. (The pulse durations can be defined independently for each Push-Button).
* from **Multi position switch** (2 pos switch, 3 pos switch, or more, eg. rotactor) replacing a stick of the the transmitter.
* a regular ON/OFF switch (no RC set required).
* a launch function call in the sketch.
API/methods:
-----------
* RcSeq_Init()
* RcSeq_DeclareSignal()
* RcSeq_DeclareStick()
* RcSeq_DeclareKeyboard()
* RcSeq_DeclareCustomKeyboard()
* RcSeq_DeclareMultiPosSwitch()
* RcSeq_SignalTimeout()
* RcSeq_DeclareServo()
* RcSeq_DeclareCommandAndSequence()
* RcSeq_DeclareCommandAndShortAction()
* RcSeq_LaunchSequence()
* RcSeq_LaunchShortAction()
* RcSeq_Refresh()
* RcSeq_LibVersion()
* RcSeq_LibRevision()
* RcSeq_LibTextVersionRevision()
Macros and constants:
--------------------
* const SequenceSt_t
* const KeyMap_t
* RC_SEQUENCE()
* RC_CUSTOM_KEYBOARD()
* SHORT_ACTION_TO_PERFORM()
* MOTION_WITH_SOFT_START_AND_STOP()
* MOTION_WITHOUT_SOFT_START_AND_STOP()
* CENTER_VALUE_US
* RC_SEQ_START_CONDITION
* RC_SEQ_END_OF_SEQ
Design considerations:
---------------------
The **RcSeq** library requires 3 other libraries written by the same author:
1. **TinyPinChange**: a library to catch asynchronously the input change using Pin Change Interruption capability of the AVR microcontroller.
2. **SoftRcPulseIn**: a library to catch asynchronously the input pulses using **TinyPinChange** library.
3. **SoftRcPulseOut**: a library mainly based on the **SoftwareServo** library, but with a better pulse generation to limit jitter and with some other enhancements.
CAUTION:
-------
The end user shall also use asynchronous programmation method in the loop() function (no blocking functions such as delay() or pulseIn()).
Contact
-------
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).

View File

@ -1,52 +0,0 @@
SoftRcPulseIn library
======================
**SoftRcPulseIn** is an asynchronous library designed to read RC pulse signals. It is a non-blocking version of arduino **pulseIn()** function.
Some examples of use cases:
-------------------------
* **RC Servo/ESC/Brushless Controller**
* **Multi-switch (RC Channel to digital outputs converter)** (look at **RcSeq** library)
* **Servo sequencer** (look at **RcSeq** library which uses **SoftRcPulseOut** library)
* **RC Robot using wheels with modified Servo to support 360° rotation**
* **RC pulse stretcher** (in conjunction with **SoftRcPulseOut** library)
Supported Arduinos:
------------------
* **ATmega328 (UNO)**
* **ATmega2560 (MEGA)**
* **ATtiny84 (Standalone)**
* **ATtiny85 (Standalone or Digispark)**
* **ATtiny167 (Digispark pro)**
Tip and Tricks:
--------------
Develop your project on an arduino UNO or MEGA, and then shrink it by loading the sketch in an ATtiny or Digispark (pro).
API/methods:
-----------
* attach()
* available()
* width_us()
* timeout()
* LibVersion()
* LibRevision()
* LibTextVersionRevision()
Design considerations:
---------------------
The **SoftRcPulseIn** library relies the **TinyPinChange** library. This one shall be included in the sketch as well.
On the arduino MEGA, as all the pins do not support "pin change interrupt", only the following pins are supported:
* 10 -> 15
* 50 -> 53
* A8 -> A15
On other devices (ATmega328, ATtiny84, ATtiny85 and ATtiny167), all the pins are usable.
Contact
-------
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).

View File

@ -1,78 +0,0 @@
/*
_____ ____ __ _ ____ _ _ _ _
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|_| |_| \____/ |_| \__| |_| |_| \__/ |_| 2013
http://p.loussouarn.free.fr
*******************************************
* Digispark RC Debug Demo with 1 I/O *
*******************************************
This sketch demonstrates how to display received RC pulse width with a Digispark in the serial console of the arduino IDE.
by using a bi-directional serial port using a single I/O.
This approach allows to use the built-in Serial Console of the arduino IDE.
Please, note this solution requires a native RS232 port (rare today) or a RS232/USB adapter on the development PC.
To display properly the outputs in the IDE serial console, you have to:
- in the arduino IDE, select "Tools->Board->Digispark 16.0mhz - NO USB (Tiny core)"
- in the arduino IDE, select the right serial port in "Tools->Serial Port" and select the port where the debug cable is connected to.
- in the serial console, set the right baud rate (38400 in this sketch)
In this sketch, only Tx capabilty of SoftSerial is used.
Hardware Wiring:
===============
SERIAL SINGLE I/O
DEBUGGING CABLE
___________________/\__________________
/ \
____
.--------. | \
| GND |--------------------------------+---o5 \
| | 47K | | 9o |
| | .--###--' | o4 |
| DEBUG | 4.7K | | 8o |
| TX_RX |-------------------###--+--|<|------o3 | ---> To regular RS232 SubD 9 pins Male of PC
| PIN | ^ | 1N4148 | 7o | or to RS232/USB adapter
| | | '-----------o2 |
'--------' | | 6o |
ATtiny85 Single | o1 /
(Digispark) I/O |____/
SubD 9 pins
Female
*/
#include <TinyPinChange.h>
#include <SoftRcPulseIn.h>
#include <SoftSerial.h>
#define RX_AUX_GEAR_PIN 0 //Choose here the pin for the RC signal
#define DEBUG_TX_RX_PIN 1 //Adjust here your Tx/Rx debug pin (Do NOT work on Digispark PIN 5: choose another PIN)
#define SERIAL_BAUD_RATE 57600 //Adjust rate here
SoftRcPulseIn RxAuxGear; //Choose a name for your RC channel signal
SoftSerial MyDbgSerial(DEBUG_TX_RX_PIN, DEBUG_TX_RX_PIN, true); //true allows to connect to a regular RS232 without RS232 line driver
void setup()
{
RxAuxGear.attach(RX_AUX_GEAR_PIN);
MyDbgSerial.begin(SERIAL_BAUD_RATE); //Do NOT forget to setup your terminal at same baud rate (eg: arduino IDE serial monitor)
MyDbgSerial.txMode(); //Before sending a message, switch to txMode
MyDbgSerial.print(F("SoftRcPulseIn lib V"));MyDbgSerial.print(SoftRcPulseIn::LibTextVersionRevision());MyDbgSerial.println(F(" demo"));
}
void loop()
{
if(RxAuxGear.available())
{
MyDbgSerial.print(F("Pulse="));MyDbgSerial.println(RxAuxGear.width_us()); // Display Rx Pulse Width (in us)
}
}

View File

@ -1,67 +0,0 @@
SoftRcPulseOut library
======================
**SoftRcPulseOut** is pseudo-asynchronous library designed to generate RC pulse signals. RC pulse signals are intended to command servos, **E**lectronic **S**peed **C**ontrollers (**ESC**), Brushless Controllers and any devices expecting such a command signal.
Some examples of use cases:
-------------------------
* **Servo/ESC/Brushless Controller tester**
* **Servo sequencer** (look at RcSeq library which uses _SoftRcPulseOut_)
* **Robot wheels using modified Servo to support 360° rotation**
* **RC pulse stretcher** (in conjunction with **SoftRcPulseIn** library)
Supported Arduinos:
------------------
* **ATmega368 (UNO)**
* **ATmega2560 (MEGA)**
* **ATtiny84 (Standalone)**
* **ATtiny85 (Standalone or Digispark)**
* **ATtiny167 (Digispark pro)**
Tip and Tricks:
--------------
Develop your project on an arduino UNO or MEGA, and then shrink it by loading the sketch in an ATtiny or Digispark (pro).
API/methods:
-----------
* The **SoftRcPulseOut** library uses the same API as the regular **SoftwareServo** library:
* attach()
* attached()
* detach()
* write()
* read()
* setMinimumPulse()
* setMaximumPulse()
* refresh()
* Two additional methods allow using µs rather than angle in ° :
* write_us()
* read_us()
* Methods for version management:
* LibVersion
* LibRevision
* LibTextVersionRevision
* Synchronization:
* By giving **_1_** or **_true_** as optional argument for the **SoftRcPulseOut::refresh()** method, the pulses are refreshed immediately (without waiting for the usual 20ms).
* the **SoftRcPulseOut::refresh()** method returns **_1_** or **_true_** when the pulses have been refreshed. Testing this return value provides a 20ms timer.
Design considerations:
---------------------
The **SoftRcPulseOut** library relies on a 8 bit timer. This allows using it even on little MCU (such as ATtiny85) which do not have any 16 bit timer.
Whereas a 8 bit timer is used for pulse generation, the jitter is limited by using anticipated interrupt masking.
Interrups are only masked during rising and falling edges of the pulse signals.
CAUTION:
-------
The end user shall also use asynchronous programmation method in the loop() function (not too long blocking functions such as delay(1000): the **SoftRcPulseOut::refresh()** method shall be called at least every 50ms).
Contact
-------
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).

View File

@ -1,229 +0,0 @@
#include "SoftRcPulseOut.h"
/*
Update 01/03/2013: add support for Digispark (http://digistump.com): automatic Timer selection (RC Navy: p.loussouarn.free.fr)
Update 19/08/2014: usage with write_us and read_us fixed
English: by RC Navy (2012)
=======
<SoftRcPulseOut>: a library mainly based on the <SoftwareServo> library, but with a better pulse generation to limit jitter.
It supports the same methods as <SoftwareServo>.
It also support Pulse Width order given in microseconds. The current Pulse Width can also be read in microseconds.
The refresh method can admit an optionnal argument (force). If SoftRcPulseOut::refresh(1) is called, the refresh is forced even if 20 ms are not elapsed.
The refresh() method returns 1 if refresh done (can be used for synchro and/or for 20ms timer).
http://p.loussouarn.free.fr
Francais: par RC Navy (2012)
========
<SoftRcPulseOut>: une librairie majoritairement basee sur la librairie <SoftwareServo>, mais avec une meilleure generation des impulsions pour limiter la gigue.
Elle supporte les memes methodes que <SoftwareServo>.
Elle supporte egalement une consigne de largeur d'impulsion passee en microseconde. La largeur de l'impulsion courante peut egalement etre lue en microseconde.
La methode refresh peut admettre un parametre optionnel (force). Si SoftRcPulseOut::resfresh(1) est appelee, le refresh est force meme si 20 ms ne se sont pas ecoulee.
La methode refresh() retourne 1 si refresh effectue (peut etre utilise pour synhro et/ou 20ms timer).
http://p.loussouarn.free.fr
*/
/* Automatic Timer selection (at compilation time) */
#ifndef TIMER_TO_USE_FOR_MILLIS //This symbol is not defined arduino standard core and is defined in core_build_options.h in DigiStump version
#define SOFT_RC_PULSE_OUT_TCNT TCNT0 //For arduino standard core of UNO/MEGA, etc
#else
#if (TIMER_TO_USE_FOR_MILLIS==1)
#define SOFT_RC_PULSE_OUT_TCNT TCNT1 //For example for ATtiny85
#else
#define SOFT_RC_PULSE_OUT_TCNT TCNT0 //For example for ATtiny84 and ATtiny167
#endif
#endif
SoftRcPulseOut *SoftRcPulseOut::first;
#define NO_ANGLE (0xff)
SoftRcPulseOut::SoftRcPulseOut() : pin(0), angle(NO_ANGLE), pulse0(0), min16(34), max16(150), next(0)
{}
void SoftRcPulseOut::setMinimumPulse(uint16_t t)
{
min16 = t / 16;
}
void SoftRcPulseOut::setMaximumPulse(uint16_t t)
{
max16 = t / 16;
}
uint8_t SoftRcPulseOut::attach(int pinArg)
{
pin = pinArg;
angle = NO_ANGLE;
pulse0 = 0;
next = first;
first = this;
digitalWrite(pin, LOW);
pinMode(pin, OUTPUT);
return (1);
}
void SoftRcPulseOut::detach()
{
for ( SoftRcPulseOut **p = &first; *p != 0; p = &((*p)->next) )
{
if ( *p == this )
{
*p = this->next;
this->next = 0;
return;
}
}
}
void SoftRcPulseOut::write(int angleArg)
{
if ( angleArg < 0) angleArg = 0;
if ( angleArg > 180) angleArg = 180;
angle = angleArg;
// bleh, have to use longs to prevent overflow, could be tricky if always a 16MHz clock, but not true
// That 64L on the end is the TCNT0 prescaler, it will need to change if the clock's prescaler changes,
// but then there will likely be an overflow problem, so it will have to be handled by a human.
#ifdef MS_TIMER_TICK_EVERY_X_CYCLES
pulse0 = (min16 * 16L * clockCyclesPerMicrosecond() + (max16 - min16) * (16L * clockCyclesPerMicrosecond()) * angle / 180L) / MS_TIMER_TICK_EVERY_X_CYCLES;
#else
pulse0 = (min16 * 16L * clockCyclesPerMicrosecond() + (max16 - min16) * (16L * clockCyclesPerMicrosecond()) * angle / 180L) / 64L;
#endif
}
void SoftRcPulseOut::write_us(uint16_t PulseWidth_us)
{
if ( PulseWidth_us < (min16 * 16)) PulseWidth_us = (min16 * 16);
if ( PulseWidth_us > (max16 * 16)) PulseWidth_us = (max16 * 16);
#ifdef MS_TIMER_TICK_EVERY_X_CYCLES
pulse0 = (PulseWidth_us * clockCyclesPerMicrosecond()) / MS_TIMER_TICK_EVERY_X_CYCLES;
#else
pulse0 = (PulseWidth_us * clockCyclesPerMicrosecond()) / 64L;
#endif
angle = map(PulseWidth_us, min16 * 16, max16 * 16, 0, 180);
}
uint8_t SoftRcPulseOut::read()
{
return angle;
}
uint16_t SoftRcPulseOut::read_us()
{
#ifdef MS_TIMER_TICK_EVERY_X_CYCLES
return((pulse0 * MS_TIMER_TICK_EVERY_X_CYCLES) / clockCyclesPerMicrosecond());
#else
return((pulse0 * 64L) / clockCyclesPerMicrosecond());
#endif
}
uint8_t SoftRcPulseOut::attached()
{
for ( SoftRcPulseOut *p = first; p != 0; p = p->next )
{
if ( p == this) return (1);
}
return (0);
}
uint8_t SoftRcPulseOut::refresh(bool force /* = false */)
{
uint8_t RefreshDone = 0;
uint8_t count = 0, i = 0;
uint16_t base = 0;
SoftRcPulseOut *p;
static uint32_t lastRefresh = 0;
uint32_t m = millis();
if(!force)
{
// if we haven't wrapped millis, and 20ms have not passed, then don't do anything
if ( (m - lastRefresh) < 20UL ) return(RefreshDone);
}
RefreshDone = 1; //Ok: Refresh will be performed
lastRefresh = m;
for ( p = first; p != 0; p = p->next ) if ( p->pulse0 ) count++;
if ( count == 0 ) return(RefreshDone);
// gather all the SoftRcPulseOuts in an array
SoftRcPulseOut *s[count];
for ( p = first; p != 0; p = p->next ) if ( p->pulse0) s[i++] = p;
// bubblesort the SoftRcPulseOuts by pulse time, ascending order
s[0]->ItMasked = 0;
for(;;)
{
uint8_t moved = 0;
for ( i = 1; i < count; i++ )
{
s[i]->ItMasked = 0;
if ( s[i]->pulse0 < s[i - 1]->pulse0 )
{
SoftRcPulseOut *t = s[i];
s[i] = s[i - 1];
s[i - 1] = t;
moved = 1;
}
}
if ( !moved ) break;
}
for ( i = 1; i < count; i++ )
{
if ( abs(s[i]->pulse0 - s[i - 1]->pulse0) <= 5)
{
s[i]->ItMasked = 1; /* 2 consecutive Pulses are close each other, so do not unmask interrupts between Pulses */
}
}
// turn on all the pins
// Note the timing error here... when you have many SoftwareServos going, the
// ones at the front will get a pulse that is a few microseconds too long.
// Figure about 4uS/SoftRcPulseOut after them. This could be compensated, but I feel
// it is within the margin of error of software SoftRcPulseOuts that could catch
// an extra interrupt handler at any time.
noInterrupts();
for ( i = 0; i < count; i++ ) digitalWrite( s[i]->pin, 1);
interrupts();
uint8_t start = SOFT_RC_PULSE_OUT_TCNT;
uint8_t now = start;
uint8_t last = now;
// Now wait for each pin's time in turn..
for ( i = 0; i < count; i++ )
{
uint16_t go = start + s[i]->pulse0;
#ifndef MS_TIMER_TICK_EVERY_X_CYCLES
uint16_t it = go - 4; /* 4 Ticks is OK for UNO @ 16MHz with default prescaler*/ /* Mask Interruptions just before setting down the pin */
#else
uint16_t it = go - max(4, (256 / MS_TIMER_TICK_EVERY_X_CYCLES)); /* 4 Ticks is OK for UNO @ 16MHz */ /* Mask Interruptions just before setting down the pin */
#endif
// loop until we reach or pass 'go' time: this is a blocking loop (max 2400us) except for non masked ISR (between edges)
for (;;)
{
now = SOFT_RC_PULSE_OUT_TCNT;
if ( now < last ) base += 256;
last = now;
if( !s[i]->ItMasked )
{
if( base + now > it)
{
noInterrupts();
s[i]->ItMasked = 1;
}
}
if ( base + now > go )
{
digitalWrite( s[i]->pin, 0);
if( (i + 1) < count )
{
if( !s[i + 1]->ItMasked )
{
interrupts();
}
}else interrupts();
break;
}
}
}
return(RefreshDone);
}

View File

@ -1,74 +0,0 @@
#ifndef SoftRcPulseOut_h
#define SoftRcPulseOut_h
/*
Update 01/03/2013: add support for Digispark (http://digistump.com): automatic Timer selection (RC Navy: p.loussouarn.free.fr)
Update 19/08/2014: usage with write_us and read_us fixed and optimized for highest resolution
English: by RC Navy (2012)
=======
<SoftRcPulseOut>: a library mainly based on the <SoftwareServo> library, but with a better pulse generation to limit jitter.
It supports the same methods as <SoftwareServo>.
It also support Pulse Width order given in microseconds. The current Pulse Width can also be read in microseconds.
The refresh method can admit an optionnal argument (force). If SoftRcPulseOut::refresh(1) is called, the refresh is forced even if 20 ms are not elapsed.
The refresh() method returns 1 if refresh done (can be used for synchro and/or for 20ms timer).
http://p.loussouarn.free.fr
Francais: par RC Navy (2012)
========
<SoftRcPulseOut>: une librairie majoritairement basee sur la librairie <SoftwareServo>, mais avec une meilleure generation des impulsions pour limiter la gigue.
Elle supporte les memes methodes que <SoftwareServo>.
Elle supporte egalement une consigne de largeur d'impulsion passee en microseconde. La largeur de l'impulsion courante peut egalement etre lue en microseconde.
La methode refresh peut admettre un parametre optionnel (force). Si SoftRcPulseOut::resfresh(1) est appelee, le refresh est force meme si 20 ms ne se sont pas ecoulee.
La methode refresh() retourne 1 si refresh effectue (peut etre utilise pour synhro et/ou 20ms timer).
http://p.loussouarn.free.fr
*/
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <inttypes.h>
class SoftRcPulseOut
{
private:
boolean ItMasked;
uint8_t pin;
uint8_t angle; // in degrees
uint16_t pulse0; // pulse width in TCNT0 counts
uint8_t min16; // minimum pulse, 16uS units (default is 34)
uint8_t max16; // maximum pulse, 16uS units, 0-4ms range (default is 150)
class SoftRcPulseOut *next;
static SoftRcPulseOut *first;
public:
SoftRcPulseOut();
uint8_t attach(int); // attach to a pin, sets pinMode, returns 0 on failure, won't
// position the servo until a subsequent write() happens
void detach();
void write(int); // specify the angle in degrees, 0 to 180
void write_us(uint16_t); // specify the angle in microseconds, 500 to 2500
uint8_t read(); // return the current angle
uint16_t read_us(); // return the current pulse with in microseconds
uint8_t attached();
void setMinimumPulse(uint16_t); // pulse length for 0 degrees in microseconds, 540uS default
void setMaximumPulse(uint16_t); // pulse length for 180 degrees in microseconds, 2400uS default
static uint8_t refresh(bool force = false);// must be called at least every 50ms or so to keep servo alive
// you can call more often, it won't happen more than once every 20ms
};
/* Methodes en Francais English native methods */
#define attache attach
#define detache detach
#define ecrit write
#define ecrit_us write_us
#define lit read
#define lit_us read_us
#define estAttache attached
#define definitImpulsionMinimum setMinimumPulse
#define definitImpulsionMaximum setMaximumPulse
#define rafraichit refresh
#endif

View File

@ -1,37 +0,0 @@
// SweepNoDelay
// by RC Navy (http://p.loussouarn.free.fr/arduino/arduino.html>)
// This sketch can work with ATtiny and Arduino UNO, MEGA, etc...
// This example code is in the public domain.
#include <SoftRcPulseOut.h>
SoftRcPulseOut myservo; // create servo object to control a servo
// a maximum of eight servo objects can be created
#define SERVO_PIN 0
#define UP_DIRECTION +1
#define DOWN_DIRECTION -1
#define POS_MIN 0
#define POS_MAX 180
int pos = POS_MIN; // variable to store the servo position
int step = UP_DIRECTION;
void setup()
{
myservo.attach(SERVO_PIN); // attaches the servo on pin defined by SERVO_PIN to the servo object
myservo.write(pos);
}
void loop()
{
if (SoftRcPulseOut::refresh()) // refresh() returns 1 every 20ms (after pulse update)
{
// We arrive here every 20ms
pos += step;
if(pos >= POS_MAX) step = DOWN_DIRECTION; //180 degrees reached -> Change direction
if(pos <= POS_MIN) step = UP_DIRECTION; // 0 degrees reached -> Change direction
myservo.write(pos);
}
}

View File

@ -1,37 +0,0 @@
#######################################
# Syntax Coloring Map SoftRcPulseOut
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
SoftRcPulseOut KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
attach KEYWORD2
attache KEYWORD2
detach KEYWORD2
detache KEYWORD2
write KEYWORD2
ecrit KEYWORD2
write_us KEYWORD2
ecrit_us KEYWORD2
read KEYWORD2
lit KEYWORD2
read_us KEYWORD2
lit_us KEYWORD2
attached KEYWORD2
estAttache KEYWORD2
setMinimumPulse KEYWORD2
definitImpulsionMinimum KEYWORD2
setMaximumPulse KEYWORD2
definitImpulsionMaximum KEYWORD2
refresh KEYWORD2
rafraichit KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View File

@ -1,64 +0,0 @@
SoftSerial library
==================
The **SoftSerial** library is exactly the same as the **SoftwareSerial** library but used with the **TinyPinChange** library which allows to share
the "Pin Change Interrupt" Vector.
**SoftwareSerial** monopolizes the Pin Change Interrupt Vector and do not allow sharing.
With **SoftSerial**, it's possible. Don't forget to #include **TinyPinChange** in your sketch!
Additionally, for small devices such as **ATtiny85** (Digispark), it's possible to declare **the same pin for TX and RX**.
Data direction is set by using the new **txMode()** and **rxMode()** methods.
Some examples of use cases:
-------------------------
* **half-duplex bi-directional serial port on a single wire for debuging purpose**
* **half-duplex serial port to interface with Bluetooth module**
* **half-duplex serial port to interconnect an arduino with another one**
Supported Arduinos:
------------------
* **ATmega368 (UNO)**
* **ATmega2560 (MEGA)**
* **ATtiny84 (Standalone)**
* **ATtiny85 (Standalone or Digispark)**
* **ATtiny167 (Digispark pro)**
Tip and Tricks:
--------------
Develop your project on an arduino UNO or MEGA, and then shrink it by loading the sketch in an ATtiny or Digispark (pro).
API/methods:
-----------
* The **SoftSerial** library uses the same API as the regular **SoftwareSerial** library:
* begin()
* end()
* available()
* read()
* listen()
* isListening()
* overflow()
* flush()
* Two additional methods are used to manage the serial port on a single pin:
* txMode()
* rxMode()
Design considerations:
---------------------
The **SoftSerial** library relies the **TinyPinChange** library **for the RX pin**. This one shall be included in the sketch as well.
On the arduino MEGA, as all the pins do not support "pin change interrupt", only the following pins are supported **for the RX pin**:
* 10 -> 15
* 50 -> 53
* A8 -> A15
On other devices (ATmega328, ATtiny84, ATtiny85 and ATtiny167), all the pins are usable.
Contact
-------
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).

View File

@ -1,60 +0,0 @@
TinyPinChange library
=====================
**TinyPinChange** is an asynchronous (interrupt-driven) library designed to detect event (rising or falling edege) on pins.
Very often in the arduino world, users complain about conflicts between libraries.
This **TinyPinChange** library allows to share the "pin change interrupt" vector for several "clients".
For example, it's possible to use the **SoftRcPulseIn** library whilst using the **SoftSerial** library: both libraries rely on the **TinyPinChange** library.
Some examples of use cases:
-------------------------
* **Event detector** (on pins)
* **Frequency meter**
* **Pulse width meter**
* **Tachometer**
* **Duty cycle measurement**
* **Software serial port** (see **SoftSerial** library which relies on TinyPinChange)
Supported Arduinos:
------------------
* **ATmega368 (UNO)**
* **ATmega2560 (MEGA)**
* **ATtiny84 (Standalone)**
* **ATtiny85 (Standalone or Digispark)**
* **ATtiny167 (Digispark pro)**
Tip and Tricks:
--------------
Develop your project on an arduino UNO or MEGA, and then shrink it by loading the sketch in an ATtiny or Digispark (pro).
API/methods:
-----------
* TinyPinChange_Init()
* TinyPinChange_RegisterIsr()
* TinyPinChange_EnablePin()
* TinyPinChange_DisablePin()
* TinyPinChange_GetPortEvent()
* TinyPinChange_GetCurPortSt()
* TinyPinChange_PinToMsk()
* TinyPinChange_Edge()
* TinyPinChange_RisingEdge
* TinyPinChange_FallingEdge
Design considerations:
---------------------
On the arduino MEGA, as all the pins do not support "pin change interrupt", only the following pins are supported:
* 10 -> 15
* 50 -> 53
* A8 -> A15
On other devices (ATmega328, ATtiny84, ATtiny85 and ATtiny167), all the pins are usable.
Contact
-------
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).

View File

@ -1,184 +0,0 @@
/********************************************************************************/
/* PROJECT: All based on ATtinyX5, ATtinyX4, Atiny167, ATmega328P, ATmega2560 */
/* MODULE: TinyPinChange */
/* VERSION: 1.2 (20/12/2014) */
/* DATE: 30/01/2011 */
/* TARGET: ATtinyX5, ATtinyX4, ATtiny167, ATmega328P, ATmega2560 */
/* COMPILER: WinAvr, avr-gcc, avr-g++ */
/* IDE: ARDUINO, AVR Studio 4 */
/* PROGRAMER: AVR-JTAG-ICE MKII, ARDUINO IDE */
/* AUTHOR: P.LOUSSOUARN (P.Loussouarn: http://p.loussouarn.free.fr) */
/********************************************************************************/
#include <TinyPinChange.h>
#include <avr/interrupt.h>
/*************************************************************************
MACROS
*************************************************************************/
#define PIN_CHANGE_HANDLER_MAX_NB 3 /* ISR max number Pin Change ISR can handle per port */
/*************************************************************************
GLOBAL VARIABLES
*************************************************************************/
struct PinChangeStruct
{
void (*Isr[PIN_CHANGE_HANDLER_MAX_NB])(void);
uint8_t LoadedIsrNb;
uint8_t Event;
uint8_t PinPrev;
uint8_t PinCur;
};
struct PinChangePortStruct
{
PinChangeStruct Port[PIN_CHG_PORT_NB];
};
static volatile struct PinChangePortStruct PinChange;
/*************************************************************************
INTERRUPT SUB-ROUTINE
*************************************************************************/
#define DECLARE_PIN_CHANGE_ISR(VirtualPortIdx) \
ISR(PCINT##VirtualPortIdx##_vect) \
{ \
uint8_t Idx; \
PinChange.Port[VirtualPortIdx].PinCur = (PC_PIN##VirtualPortIdx) & (PC_PCMSK##VirtualPortIdx); \
PinChange.Port[VirtualPortIdx].Event = PinChange.Port[VirtualPortIdx].PinPrev ^ PinChange.Port[VirtualPortIdx].PinCur; \
PinChange.Port[VirtualPortIdx].PinPrev = PinChange.Port[VirtualPortIdx].PinCur; \
for(Idx = 0; Idx < PinChange.Port[VirtualPortIdx].LoadedIsrNb; Idx++) \
{ \
PinChange.Port[VirtualPortIdx].Isr[Idx](); \
} \
}
DECLARE_PIN_CHANGE_ISR(0)
#if defined(__AVR_ATtinyX4__) || defined(__AVR_ATtiny167__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega2560__)
DECLARE_PIN_CHANGE_ISR(1)
#endif
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega2560__)
DECLARE_PIN_CHANGE_ISR(2)
#endif
/*************************************************************************
PUBLIC FUNCTIONS
*************************************************************************/
/*********************************************************************
PinChange Initialization Function
Input:
Void
Output:
Void
*********************************************************************/
void TinyPinChange_Init(void)
{
/* ATtinyX5, ATtiny167, ATtinyX4, UNO, MEGA */
PinChange.Port[0].PinCur = PC_PIN0 & PC_PCMSK0;//PINB for ATtinyX5, UNO or MEGA, PINA for ATtinyX4 or ATtiny167
PinChange.Port[0].PinPrev = PinChange.Port[0].PinCur;
#if defined(__AVR_ATtinyX4__) || defined(__AVR_ATtiny167__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega2560__)
/* ATtinyX4, ATtiny167, UNO or MEGA */
PinChange.Port[1].PinCur = PC_PIN1 & PC_PCMSK1;//PINB for for ATtinyX4 or ATtiny167, PINC for UNO, PINJ for MEGA
PinChange.Port[1].PinPrev = PinChange.Port[1].PinCur;
#endif
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega2560__)
/* UNO or MEGA */
PinChange.Port[2].PinCur = PC_PIN2 & PC_PCMSK2;//PIND for UNO, PINK for MEGA
PinChange.Port[2].PinPrev = PinChange.Port[2].PinCur;
#endif
}
/*********************************************************************
PinChange RegisterIsr Function
Input:
Pointer on a PinChange Function
Output:
The associated VirtualPortIdx (0 to 2)
< 0 in case of failure
*********************************************************************/
int8_t TinyPinChange_RegisterIsr(uint8_t Pin, void(*Isr)(void))
{
int8_t IsrIdx, PortIdx, AlreadyLoaded = 0;
PortIdx = DigitalPinToPortIdx(Pin);
for(IsrIdx = 0; IsrIdx < PIN_CHANGE_HANDLER_MAX_NB; IsrIdx++)
{
if(PinChange.Port[PortIdx].Isr[IsrIdx] == Isr)
{
AlreadyLoaded = 1;
break; /* Already loaded */
}
}
if(!AlreadyLoaded)
{
if(PinChange.Port[PortIdx].LoadedIsrNb < PIN_CHANGE_HANDLER_MAX_NB)
{
/* Not aready loaded: load it */
PinChange.Port[PortIdx].Isr[PinChange.Port[PortIdx].LoadedIsrNb] = Isr;
PinChange.Port[PortIdx].LoadedIsrNb++;
}
else PortIdx = -1; /* Failure */
}
return(PortIdx);
}
/*********************************************************************
PinChange Enable Pin Function
Input:
Pin: the Pin
Output:
Void
*********************************************************************/
void TinyPinChange_EnablePin(uint8_t Pin)
{
if(digitalPinToPCICR(Pin))
{
*digitalPinToPCICR(Pin) |= _BV(digitalPinToPCICRbit(Pin));
*digitalPinToPCMSK(Pin) |= _BV(digitalPinToPCMSKbit(Pin));
}
}
/*********************************************************************
PinChange Disable Pin Function
Input:
Pin: the Pin
Output:
Void
*********************************************************************/
void TinyPinChange_DisablePin(uint8_t Pin)
{
if(digitalPinToPCICR(Pin))
{
*digitalPinToPCMSK(Pin) &= (_BV(digitalPinToPCMSKbit(Pin)) ^ 0xFF);
}
}
/*********************************************************************
PinChange GetPortEvent Function
Input:
VirtualPortIdx: Index of the Port
Output:
The bits which have changed in the port
*********************************************************************/
uint8_t TinyPinChange_GetPortEvent(uint8_t VirtualPortIdx)
{
return(PinChange.Port[VirtualPortIdx].Event);
}
/*********************************************************************
PinChange GetCurPortSt Function
Input:
VirtualPortIdx: Index of the Port
Output:
Current Status of the port
*********************************************************************/
uint8_t TinyPinChange_GetCurPortSt(uint8_t VirtualPortIdx)
{
return(PinChange.Port[VirtualPortIdx].PinCur);
}

View File

@ -1,116 +0,0 @@
#ifndef TINY_PIN_CHANGE_H
#define TINY_PIN_CHANGE_H 1
/*
* <TinyPinChange>, a library for Pin Change Interrupt by RC Navy (2012)
* Supported devices: ATmega238P (UNO), ATmega2560 (MEGA), ATtiny84, ATtiny85, ATtiny167
*
* http://p.loussouarn.free.fr
* 20/04/2014: Support for MEGA added
* 22/12/2014: Support for ATtiny167 added
* Methods TinyPinChange_Edge(), TinyPinChange_RisingEdge(), TinyPinChange_FallingEdge() added
* TinyPinChange_GetPinEvent() replaced with TinyPinChange_GetPortEvent()
* TinyPinChange_GetPinCurSt() replaced with TinyPinChange_GetCurPortSt()
*/
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <inttypes.h>
#ifdef __AVR_ATtinyX5__
#undef __AVR_ATtinyX5__
#endif
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
#define __AVR_ATtinyX5__
#endif
#ifdef __AVR_ATtinyX4__
#undef __AVR_ATtinyX4__
#endif
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
#define __AVR_ATtinyX4__
#endif
#ifdef __AVR_ATtinyX5__
/* ATtinyX5 */
#define PIN_CHG_PORT_NB 1
#define DigitalPinToPortIdx(p) 0
#define PC_PIN0 PINB
#define PC_PCMSK0 PCMSK
#else
#ifdef __AVR_ATtinyX4__
/* ATtinyX4 */
#define PIN_CHG_PORT_NB 2
#define DigitalPinToPortIdx(p) (((p) <= 7) ? (0) : (((p) <= 10) ? (1) : (0)))
#define PC_PIN0 PINA
#define PC_PCMSK0 PCMSK0
#define PC_PIN1 PINB
#define PC_PCMSK1 PCMSK1
#else
#if defined(__AVR_ATmega2560__)
/* MEGA */
#define PIN_CHG_PORT_NB 3
#define DigitalPinToPortIdx(p) ((((p) >= A8) && ((p) <= A15)) ? (2) : ((((p) >= 50) && ((p) <= 53)) ? (0) : ((((p) >= 10) && ((p) <= 13)) ? (0) : (1))))
#define PC_PIN0 PINB
#define PC_PCMSK0 PCMSK0
#define PC_PIN1 PINJ
#define PC_PCMSK1 PCMSK1
#define PC_PIN2 PINK
#define PC_PCMSK2 PCMSK2
#else
#if defined(__AVR_ATtiny167__)
/* ATtiny167 */
#define PIN_CHG_PORT_NB 2
#define DigitalPinToPortIdx(p) (((p) >= 5 && (p) <= 12) ? (0) : (1))
#define PC_PIN0 PINA
#define PC_PCMSK0 PCMSK0
#define PC_PIN1 PINB
#define PC_PCMSK1 PCMSK1
#else
/* UNO */
#define PIN_CHG_PORT_NB 3
#define DigitalPinToPortIdx(p) (((p) <= 7) ? (2) : (((p) <= 13) ? (0) : (((p) <= 21) ? (1) : (0))))
#define PC_PIN0 PINB
#define PC_PCMSK0 PCMSK0
#define PC_PIN1 PINC
#define PC_PCMSK1 PCMSK1
#define PC_PIN2 PIND
#define PC_PCMSK2 PCMSK2
#endif
#endif
#endif
#endif
void TinyPinChange_Init(void);
int8_t TinyPinChange_RegisterIsr(uint8_t Pin, void(*Isr)(void));
void TinyPinChange_EnablePin(uint8_t Pin);
void TinyPinChange_DisablePin(uint8_t Pin);
uint8_t TinyPinChange_GetPortEvent(uint8_t VirtualPortIdx);
uint8_t TinyPinChange_GetCurPortSt(uint8_t VirtualPortIdx);
#define TinyPinChange_PinToMsk(Pin) _BV(digitalPinToPCMSKbit(Pin))
#define TinyPinChange_Edge(VirtualPortIdx, Pin) ( TinyPinChange_GetPortEvent((VirtualPortIdx)) & TinyPinChange_PinToMsk((Pin)) )
#define TinyPinChange_RisingEdge(VirtualPortIdx, Pin) ( TinyPinChange_GetPortEvent((VirtualPortIdx)) & TinyPinChange_PinToMsk((Pin)) & TinyPinChange_GetCurPortSt((VirtualPortIdx)) )
#define TinyPinChange_FallingEdge(VirtualPortIdx, Pin) ( TinyPinChange_GetPortEvent((VirtualPortIdx)) & TinyPinChange_PinToMsk((Pin)) & (TinyPinChange_GetCurPortSt((VirtualPortIdx) ^ 0xFF)) )
/*******************************************************/
/* Application Programming Interface (API) en Francais */
/*******************************************************/
/* Methodes en Francais English native methods */
#define TinyPinChange_EnregistreFonctionInterruption TinyPinChange_RegisterIsr
#define TinyPinChange_ActiveBroche TinyPinChange_EnablePin
#define TinyPinChange_DesactiveBroche TinyPinChange_DisablePin
#define TinyPinChange_RetourneEvenemenPort TinyPinChange_GetPortEvent
#define TinyPinChange_RetourneEtatCourantPort TinyPinChange_GetCurPortSt
#define TinyPinChange_MasqueDeBroche TinyPinChange_PinToMsk
#define TinyPinChange_Front TinyPinChange_Edge
#define TinyPinChange_FrontMontant TinyPinChange_RisingEdge
#define TinyPinChange_FrontDescendant TinyPinChange_FallingEdge
#endif

View File

@ -1,158 +0,0 @@
/*
_____ ____ __ _ ____ _ _ _ _
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2013/2014
http://p.loussouarn.free.fr
*******************************************************
* <TinyPinChange> library Demo *
* with debugging capabilities using *
* <SoftSerial> object as single wire serial interface *
*******************************************************
This sketch demonstrates how to use <TinyPinChange> library.
It counts all the FALLING edges on 2 different pins.
/!\CAUTION/!\: as <TinyPinChange> library can be shared (and it is with SoftSerial in this sketch) , the user shall test if the changes are related to the declared pins.
Trick: By connecting Pin#1 to Pin#0 or to Pin#5 through a 1K resistor, you can generate transitions for testing purpose.
Output results are sent to a software serial.
And the great thing is: using a <SoftSerial> object as a bi-directionnal software serial port (half-duplex) on a single pin to communicate with the outside world!
To display the sketch results on a PC (in a Terminal):
1) Build the "Serial One Wire Debug Cable" and plug it to the regular RS232 port as depicted below,
2) Open your favorite Terminal at 38400,n,8,1: HyperTerminal, Teraterm (Windows) or Minicom, GtkTerm (Linux) and CoolTerm (MAC) does the trick.
3) You can also use the Serial Monitor of the arduino IDE: Tools->Serial Port and select your RS232 port (may be an USB virtual port), Rate=38400.
4) To enable the display, type 1, to disable, type 0 in the Terminal/Monitor.
SERIAL ONE WIRE
DEBUGGING CABLE
_______________ ________________
/ \___/\___/ \
____
.--------. | \
| GND |--------------------------------+---o5 \
| | 47K | | 9o |
| | .--###--' | o4 |
| DEBUG | 4.7K | | 8o |
| TX_RX |-------------------###--+--|<|------o3 | ---> To regular RS232 SubD 9 pins Male of PC or Serial/USB adapter
| PIN | ^ | 1N4148 | 7o |
| | | '-----------o2 |
'--------' | | 6o |
ATtiny85 Single | o1 /
(Digispark) I/O |____/
SubD 9 pins
Female
*/
#include <TinyPinChange.h>
#include <SoftSerial.h>
#define LED_PIN 1
#define DEBUG_TX_RX_PIN 2
#define FIRST_INPUT 0
#define SECOND_INPUT 5
volatile uint16_t FirstInputChangeCount = 0; /* Volatile since the variable will be updated in interruption */
volatile uint16_t SecondInputChangeCount = 0; /* Volatile since the variable will be updated in interruption */
SoftSerial MySerial(DEBUG_TX_RX_PIN, DEBUG_TX_RX_PIN, true); /* Tx/Rx on a single Pin !!! (Pin#2) */
uint8_t VirtualPortNb;
uint8_t VirtualPortNb_;
void setup()
{
TinyPinChange_Init();
MySerial.begin(57600); /* Trick: use a "high" data rate (less time wasted in ISR and for transmitting each character) */
VirtualPortNb = TinyPinChange_RegisterIsr(FIRST_INPUT, InterruptFunctionToCall);
VirtualPortNb_ = TinyPinChange_RegisterIsr(SECOND_INPUT, InterruptFunctionToCall);
/* Enable Pin Change for each pin */
TinyPinChange_EnablePin(FIRST_INPUT);
TinyPinChange_EnablePin(SECOND_INPUT);
MySerial.txMode();
MySerial.println(F("\n*** Tiny PinChange Demo (Falling Edge) ***"));
MySerial.print(F("Pin "));MySerial.print((int)FIRST_INPUT);
MySerial.print(F(" is part of virtual port "));MySerial.println((int)VirtualPortNb);
MySerial.print(F("Pin "));MySerial.print((int)SECOND_INPUT);
MySerial.print(F(" is part of virtual port "));MySerial.println((int)VirtualPortNb_);
MySerial.println(F("As you can see, virtual port is always port 0 for ATtiny85"));
MySerial.println(F("Remember <TinyPinChange> is also designed for UNO, MEGA, ATtiny84 and ATtiny167 ;-)"));
MySerial.println(F("Type 1 to start display, 0 to stop display"));
pinMode(LED_PIN, OUTPUT);
MySerial.rxMode(); /* Switch to Rx Mode */
}
/* Function called in interruption in case of change on pins */
void InterruptFunctionToCall(void)
{
if(TinyPinChange_FallingEdge(VirtualPortNb, FIRST_INPUT)) /* Check for FIRST_INPUT Rising Edge */
{
FirstInputChangeCount++; /* Only Falling edges are counted */
}
if(TinyPinChange_FallingEdge(VirtualPortNb_, SECOND_INPUT)) /* Check for SECOND_INPUT Rising Edge */
{
SecondInputChangeCount++; /* Only Falling edges are counted */
}
}
void loop()
{
static boolean State = HIGH, DisplayEnabled = true;
static uint32_t LedStartMs = millis(), DisplayStartMs = millis();
uint16_t LocalFirstInputChangeCount;
uint16_t LocalSecondInputChangeCount;
/* Blink the built-in LED */
if(millis() - LedStartMs >= 500UL)
{
LedStartMs = millis();
digitalWrite(LED_PIN, State);
State = !State; /* State will be inverted at the next digitalWrite() */
}
/* Get command from single wire SoftSerial */
if(MySerial.available())
{
switch(MySerial.read())
{
case '0':
DisplayEnabled = false;
break;
case '1':
DisplayEnabled = true;
break;
}
}
/* Diplay Transition numbers every second */
if((millis() - DisplayStartMs >= 1000UL) && DisplayEnabled)
{
DisplayStartMs = millis();
noInterrupts(); /* Mandatory since counters are 16 bits */
LocalFirstInputChangeCount = FirstInputChangeCount;
LocalSecondInputChangeCount = SecondInputChangeCount;
interrupts();
MySerial.txMode();
MySerial.print(F("FirstInputChangeCount="));MySerial.println(LocalFirstInputChangeCount);
MySerial.print(F("SecondInputChangeCount="));MySerial.println(LocalSecondInputChangeCount);
MySerial.rxMode();
}
}

View File

@ -1,158 +0,0 @@
/*
_____ ____ __ _ ____ _ _ _ _
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2013/2014
http://p.loussouarn.free.fr
*******************************************************
* <TinyPinChange> library Demo *
* with debugging capabilities using *
* <SoftSerial> object as single wire serial interface *
*******************************************************
This sketch demonstrates how to use <TinyPinChange> library.
It counts all the RISING edges on 2 different pins.
/!\CAUTION/!\: as <TinyPinChange> library can be shared (and it is with SoftSerial in this sketch) , the user shall test if the changes are related to the declared pins.
Trick: By connecting Pin#1 to Pin#0 or to Pin#5 through a 1K resistor, you can generate transitions for testing purpose.
Output results are sent to a software serial.
And the great thing is: using a <SoftSerial> object as a bi-directionnal software serial port (half-duplex) on a single pin to communicate with the outside world!
To display the sketch results on a PC (in a Terminal):
1) Build the "Serial One Wire Debug Cable" and plug it to the regular RS232 port as depicted below,
2) Open your favorite Terminal at 38400,n,8,1: HyperTerminal, Teraterm (Windows) or Minicom, GtkTerm (Linux) and CoolTerm (MAC) does the trick.
3) You can also use the Serial Monitor of the arduino IDE: Tools->Serial Port and select your RS232 port (may be an USB virtual port), Rate=38400.
4) To enable the display, type 1, to disable, type 0 in the Terminal/Monitor.
SERIAL ONE WIRE
DEBUGGING CABLE
_______________ ________________
/ \___/\___/ \
____
.--------. | \
| GND |--------------------------------+---o5 \
| | 47K | | 9o |
| | .--###--' | o4 |
| DEBUG | 4.7K | | 8o |
| TX_RX |-------------------###--+--|<|------o3 | ---> To regular RS232 SubD 9 pins Male of PC or Serial/USB adapter
| PIN | ^ | 1N4148 | 7o |
| | | '-----------o2 |
'--------' | | 6o |
ATtiny85 Single | o1 /
(Digispark) I/O |____/
SubD 9 pins
Female
*/
#include <TinyPinChange.h>
#include <SoftSerial.h>
#define LED_PIN 1
#define DEBUG_TX_RX_PIN 2
#define FIRST_INPUT 0
#define SECOND_INPUT 5
volatile uint16_t FirstInputChangeCount = 0; /* Volatile since the variable will be updated in interruption */
volatile uint16_t SecondInputChangeCount = 0; /* Volatile since the variable will be updated in interruption */
SoftSerial MySerial(DEBUG_TX_RX_PIN, DEBUG_TX_RX_PIN, true); /* Tx/Rx on a single Pin !!! (Pin#2) */
uint8_t VirtualPortNb;
uint8_t VirtualPortNb_;
void setup()
{
TinyPinChange_Init();
MySerial.begin(57600); /* Trick: use a "high" data rate (less time wasted in ISR and for transmitting each character) */
VirtualPortNb = TinyPinChange_RegisterIsr(FIRST_INPUT, InterruptFunctionToCall);
VirtualPortNb_ = TinyPinChange_RegisterIsr(SECOND_INPUT, InterruptFunctionToCall);
/* Enable Pin Change for each pin */
TinyPinChange_EnablePin(FIRST_INPUT);
TinyPinChange_EnablePin(SECOND_INPUT);
MySerial.txMode();
MySerial.println(F("\n*** Tiny PinChange Demo (Rising Edge) ***"));
MySerial.print(F("Pin "));MySerial.print((int)FIRST_INPUT);
MySerial.print(F(" is part of virtual port "));MySerial.println((int)VirtualPortNb);
MySerial.print(F("Pin "));MySerial.print((int)SECOND_INPUT);
MySerial.print(F(" is part of virtual port "));MySerial.println((int)VirtualPortNb_);
MySerial.println(F("As you can see, virtual port is always port 0 for ATtiny85"));
MySerial.println(F("Remember <TinyPinChange> is also designed for UNO, MEGA, ATtiny84 and ATtiny167 ;-)"));
MySerial.println(F("Type 1 to start display, 0 to stop display"));
pinMode(LED_PIN, OUTPUT);
MySerial.rxMode(); /* Switch to Rx Mode */
}
/* Function called in interruption in case of change on pins */
void InterruptFunctionToCall(void)
{
if(TinyPinChange_RisingEdge(VirtualPortNb, FIRST_INPUT)) /* Check for FIRST_INPUT Rising Edge */
{
FirstInputChangeCount++; /* Only Rising edges are counted */
}
if(TinyPinChange_RisingEdge(VirtualPortNb_, SECOND_INPUT)) /* Check for SECOND_INPUT Rising Edge */
{
SecondInputChangeCount++; /* Only Rising edges are counted */
}
}
void loop()
{
static boolean State = HIGH, DisplayEnabled = true;
static uint32_t LedStartMs = millis(), DisplayStartMs = millis();
uint16_t LocalFirstInputChangeCount;
uint16_t LocalSecondInputChangeCount;
/* Blink the built-in LED */
if(millis() - LedStartMs >= 500UL)
{
LedStartMs = millis();
digitalWrite(LED_PIN, State);
State = !State; /* State will be inverted at the next digitalWrite() */
}
/* Get command from single wire SoftSerial */
if(MySerial.available())
{
switch(MySerial.read())
{
case '0':
DisplayEnabled = false;
break;
case '1':
DisplayEnabled = true;
break;
}
}
/* Diplay Transition numbers every second */
if((millis() - DisplayStartMs >= 1000UL) && DisplayEnabled)
{
DisplayStartMs = millis();
noInterrupts(); /* Mandatory since counters are 16 bits */
LocalFirstInputChangeCount = FirstInputChangeCount;
LocalSecondInputChangeCount = SecondInputChangeCount;
interrupts();
MySerial.txMode();
MySerial.print(F("FirstInputChangeCount="));MySerial.println(LocalFirstInputChangeCount);
MySerial.print(F("SecondInputChangeCount="));MySerial.println(LocalSecondInputChangeCount);
MySerial.rxMode();
}
}

View File

@ -1,440 +0,0 @@
/*
_____ ____ __ _ ____ _ _ _ _
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2013/2014
http://p.loussouarn.free.fr
*******************************************************
* <TinyPinChange> library Demo *
* with display capabilities using *
* <SoftSerial> object as single wire serial interface *
*******************************************************
This "Tiny RC Scope" sketch demonstrates how to use <TinyPinChange> and <SoftSerial> libraries.
"Tiny RC Scope" acts as a simple real time ASCII oscilloscope for displaying one RC Channel in the serial console.
The displayed measurement (in µs) are: pulse width and RC period.
Trick: By connecting Pin#1 to Pin#0, through a 1K resistor, you can measure the RC Signal provided by the built-in RC generator for testing purpose.
Output results are sent to a software serial port. If a real RC signal is connected to Pin0, the trace is displayed in real time in the terminal.
And the great thing is: using a <SoftSerial> object as a bi-directionnal software serial port (half-duplex) on a single pin to communicate with the outside world!
To display the sketch results on a PC (in a Terminal):
1) Build the "Serial One Wire Debug Cable" and plug it to the regular RS232 port as depicted below.
2) Open your favorite Terminal at 57600,n,8,1: HyperTerminal, Teraterm (Windows) or Minicom, GtkTerm (Linux) and CoolTerm (MAC) does the trick.
3) You can also use the Serial Monitor of the arduino IDE: Tools->Serial Port and select your RS232 port (may be an USB virtual port), Rate=57600.
4) To test "Tiny RC Scope", connect Pin1 to Pin0, and look at the Terminal (57600,n,8,1) connected to Pin2 through a debug cable ()
5) The wave form should be displayed in the Terminal,
6) Type - to decrease the pulse width (-10us),
7) Type + to increase the pulse width (+10us),
8) Type m to set the pulse width to its minimum (500us),
9) Type n or N to set the pulse width to its Neutral value (1500us),
10) Type M to set the pulse width to its Maximum (2500us),
11) To measure real RC signals, disconnect the Pin1 from Pin0 and connect a RC receiver output to Pin0,
12) The Terminal will display in real time the pulse width of the connected RC channel.
13) If the channel is not connected, a flat line is displayed.
SERIAL ONE WIRE
DEBUGGING CABLE
_______________ ________________
/ \___/\___/ \
____
.--------. | \
| GND |--------------------------------+---o5 \
| | 47K | | 9o |
| | .--###--' | o4 |
| DEBUG | 4.7K | | 8o |
| TX_RX |-------------------###--+--|<|------o3 | ---> To regular RS232 SubD 9 pins Male of PC or Serial/USB adapter
| PIN | ^ | 1N4148 | 7o |
| | | '-----------o2 |
'--------' | | 6o |
ATtiny85 Single | o1 /
(Digispark) I/O |____/
(pro) SubD 9 pins
Female
*/
#include <TinyPinChange.h>
#include <SoftSerial.h>
#define RC_CHANNEL_PIN 0 /* RC Channel is connected to pin 0 */
#define RC_GEN_PIN 1 /* Pin used as internal RC generator for test purpose */
#define RC_PINS_MSK (_BV(RC_CHANNEL_PIN) | _BV(RC_GEN_PIN))
#define DEBUG_TX_RX_PIN 2
#define DEF_TEST_RC_CH_WIDTH_US 1500 /* This value can be change via the Terminal */
#define TEST_RC_PERIOD_US 20000
#define PULSE_MAX_US 2500
#define PULSE_MIN_US 500
#define STEP_US 10
#define ERR_MARGIN_US 150
#define SERIAL_BAUD_RATE 57600 /* 57600 is the maximum for Receiving commands from the serial port: 1 char -> #200us */
SoftSerial MySerial(DEBUG_TX_RX_PIN, DEBUG_TX_RX_PIN, true); /* Tx/Rx on a single Pin !!! (Pin#2) */
#define ONE_CHAR_TX_TIME_US 200 /* @ 57600 bauds */
enum {PULSE_SRC_INTERNAL, PULSE_SRC_EXTERNAL};
typedef struct {
uint32_t RisingStartUs;
uint32_t RcWidth_us;
uint32_t LastRxPulseMs;
boolean FallingEdgeFound;
}RcChSt_t;
volatile RcChSt_t Ch; /* volatile, since value are used in ISR and in the loop() */
volatile uint32_t RcPeriod_us = TEST_RC_PERIOD_US;
uint32_t TestRcWidth_us = DEF_TEST_RC_CH_WIDTH_US;
/* The different states of the display state machine */
enum {DISP_COMPUTE, DISP_FIRST_LINE, DISP_PREP_SEC_LINE, DISP_SECOND_LINE, DISP_PREP_THIRD_LINE, DISP_THIRD_LINE, DISP_WAIT};
#define LINE_LEN 38
typedef struct{
char Line[LINE_LEN];
uint8_t Idx;
uint8_t State;
uint8_t HighNb;
}DispSt_t;
static DispSt_t Disp;
volatile uint8_t IntRcSynch = 0;
uint8_t VirtualPortIdx;
/*
RC Signal
____ ____
_| |____________________________| |_
<---->
Width_us
<-------------------------------->
Period_us
*/
void setup()
{
TinyPinChange_Init();
MySerial.begin(SERIAL_BAUD_RATE); /* Trick: use a "high" data rate (less time wasted in ISR and for transmitting each character) */
Disp.State = DISP_COMPUTE;
VirtualPortIdx = TinyPinChange_RegisterIsr(RC_CHANNEL_PIN, InterruptFunctionToCall); /* As all pins are on the same port, a single ISR is needed */
pinMode(RC_CHANNEL_PIN, INPUT);
digitalWrite(RC_CHANNEL_PIN, HIGH); /* Enable Pull-up to avoid floating inputs in case of nothing connected to them */
TinyPinChange_EnablePin(RC_CHANNEL_PIN);
Ch.RcWidth_us = 0;
Ch.FallingEdgeFound = 0;
MySerial.txMode();
MySerial.println(F("\n -- Tiny RC Scope V1.0 (C) RC Navy 2014 --\n"));
MySerial.rxMode(); /* Switch to Rx Mode */
pinMode(RC_GEN_PIN, OUTPUT);
}
void loop()
{
uint32_t RcGeneStartUs = micros();
static uint32_t ProcessStartUs = micros();
static uint32_t DisplayStartMs = millis();
uint32_t ProcessDurationUs;
uint32_t HalfRemaingLowUs;
char RxChar;
/* Blink the built-in LED (Built-in RC Signal generator) */
if(IsInternalRcSrc())
{
RcGeneStartUs = micros();
digitalWrite(RC_GEN_PIN, HIGH);
while(micros() - RcGeneStartUs < TestRcWidth_us);
digitalWrite(RC_GEN_PIN, LOW);
}
/********************/
/* Start of process */
/********************/
ProcessStartUs = micros();
DisplayRcMeasurement(5000U);/* Gives 5000 us to display a part of the trace */
/* Get command from single wire SoftSerial (to tune the built-in generator) */
if(MySerial.available() > 0)
{
RxChar = MySerial.read();MySerial.txMode();MySerial.println("");MySerial.rxMode(); /* Carriage return after the echo */
switch(RxChar)
{
case '-': /* Decrease Built-in RC Pulse */
if((TestRcWidth_us - STEP_US) >= PULSE_MIN_US)
{
TestRcWidth_us -= STEP_US;
}
break;
case '+': /* Increase Built-in RC Pulse */
if(TestRcWidth_us + STEP_US <= PULSE_MAX_US)
{
TestRcWidth_us += STEP_US;
}
break;
case 'm': /* Set Built-in RC Pulse o min value: 500 */
TestRcWidth_us = PULSE_MIN_US;
break;
case 'N': /* Set Built-in RC Pulse to Neutral: 1500 */
case 'n':
TestRcWidth_us = DEF_TEST_RC_CH_WIDTH_US;
break;
case 'M': /* Set Built-in RC Pulse to Max value: 2500 */
TestRcWidth_us = PULSE_MAX_US;
break;
default:
/* Ignore */
break;
}
}
/********************/
/* End of process */
/********************/
ProcessDurationUs = micros() - ProcessStartUs; //Compute how many us took the previous instructions
if(IsInternalRcSrc())
{
HalfRemaingLowUs = TEST_RC_PERIOD_US - (ProcessDurationUs + TestRcWidth_us + 100UL);
RcGeneStartUs = micros();
while((micros() - RcGeneStartUs) < HalfRemaingLowUs);
}
}
/*
RC Signal
____ ____
_| |____________________________| |_
<---->
Width_us
<-------------------------------->
Period_us
<-------------------->
Display is processed here
Explanation: the display of the trace is performed just after the falling edge of the RC pulse
As the duration between 2 pulses is too short to display the full trace, the trace is displayed part by part.
A full trace is composed of around 100 characters:
At 57600 bauds, one character takes (1/57600) * 10 = 174 us. As there are some overhead, it is closer than 200us.
So, the full trace takes 100 x 200 = 20000 us = 20 ms. It's impossible to display the full trace between 2 consecutive pulses.
DisplayRcMeasurement() function is the very tricky part of this sketch: it has as argument an amount of time and exits before
it exceeds it. A state machine is used to memorize where the display was arrived.
*/
uint8_t DisplayRcMeasurement(uint16_t FreetimeUs)
{
static uint32_t LocalRcWidth_us;
static uint32_t LocalRcPeriod_us;
static uint32_t StartWaitMs;
char *Ptr;
uint32_t ProcessStart_us;
uint32_t Elapsed_us;
uint8_t StartIdx, Idx;
uint8_t Ret = 0;
switch(Disp.State)
{
case DISP_COMPUTE:
DispCompute:
if(Ch.FallingEdgeFound)
{
DispComputeNoSignal:
ProcessStart_us = micros();
Ch.FallingEdgeFound = 0;
noInterrupts(); /* Mandatory since RcWidth_us and RcPeriod_us are 32 bits */
LocalRcWidth_us = Ch.RcWidth_us;
LocalRcPeriod_us = RcPeriod_us;
interrupts();
if(LocalRcWidth_us < (PULSE_MIN_US - ERR_MARGIN_US) || LocalRcWidth_us > (PULSE_MAX_US + ERR_MARGIN_US)) LocalRcWidth_us = 0; /* Out of Range */
Disp.HighNb = (LocalRcWidth_us + 50UL) / 100;
strcpy_P(Disp.Line, PSTR("Ch(P0)__"));
if(LocalRcWidth_us)
{
Ptr = Disp.Line + 8;
for(Idx = 0; Idx < Disp.HighNb; Idx++) *Ptr++='_';*Ptr++='\n';*Ptr=0;
}
else Disp.Line[6] = 0;
Elapsed_us = micros() - ProcessStart_us;
FreetimeUs -= (uint16_t)Elapsed_us;
Disp.Idx=0;
Disp.State = DISP_FIRST_LINE;
if(FreetimeUs >= ONE_CHAR_TX_TIME_US)
{
goto DispFirstLine;
}
}
else
{
if(millis() - StartWaitMs >= 1000UL)
{
LocalRcWidth_us = 0;
goto DispComputeNoSignal;
}
}
break;
case DISP_PREP_SEC_LINE:
DispPrepSecLine:
/* Prepare second line */
ProcessStart_us = micros();
if(LocalRcWidth_us)
{
strcpy_P(Disp.Line, PSTR("_____/"));
for(Idx = 0; Idx < (2 + Disp.HighNb); Idx++) Disp.Line[6 + Idx] = ' ';
itoa(LocalRcWidth_us, Disp.Line + 6, 10);StartIdx = 9; if(LocalRcWidth_us >= 1000) StartIdx++;Disp.Line[StartIdx++] = 'u';Disp.Line[StartIdx++] = 's';
StartIdx = 6 + 2 + Disp.HighNb;Disp.Line[StartIdx++] = '\\';
}
else StartIdx = 0;
for(Idx = 0; (StartIdx + Idx ) < (LINE_LEN - 2); Idx++) Disp.Line[StartIdx + Idx] = '_';Disp.Line[StartIdx + Idx] = '\n';Disp.Line[++StartIdx + Idx] = 0;
Elapsed_us = micros() - ProcessStart_us;
FreetimeUs -= (uint16_t)Elapsed_us;
Disp.Idx=0;
Disp.State = DISP_SECOND_LINE;
if(FreetimeUs >= ONE_CHAR_TX_TIME_US)
{
goto DispSecondLine;
}
break;
case DISP_PREP_THIRD_LINE:
DispPrepThirdLine:
/* Prepare third line */
ProcessStart_us = micros();
strcpy_P(Disp.Line, PSTR(" RC Period: "));
if(LocalRcWidth_us)
{
itoa(LocalRcPeriod_us, Disp.Line + 20, 10);
strcat_P(Disp.Line, PSTR("us"));
}
else strcat_P(Disp.Line, PSTR("???"));
Elapsed_us = micros() - ProcessStart_us;
FreetimeUs -= (uint16_t)Elapsed_us;
Disp.Idx=0;
Disp.State = DISP_THIRD_LINE;
if(FreetimeUs >= ONE_CHAR_TX_TIME_US)
{
goto DispThirdLine;
}
break;
case DISP_FIRST_LINE:
case DISP_SECOND_LINE:
case DISP_THIRD_LINE:
DispFirstLine:
DispSecondLine:
DispThirdLine:
ProcessStart_us = micros();
MySerial.txMode();
while(1)
{
if(Disp.Line[Disp.Idx])
{
MySerial.print(Disp.Line[Disp.Idx++]);
if (micros() - ProcessStart_us >= (FreetimeUs - ONE_CHAR_TX_TIME_US))
{
MySerial.rxMode();
break; /* exit while(1) and stay in the current state */
}
}
else
{
switch(Disp.State)
{
case DISP_FIRST_LINE:
/* First line is fully displayed */
Disp.State = DISP_PREP_SEC_LINE;
if(FreetimeUs - Elapsed_us >= 200)
{
FreetimeUs -= (uint16_t)Elapsed_us;
goto DispPrepSecLine;
}
else
{
/* Not enough time: just change state */
MySerial.rxMode();
}
break;
case DISP_SECOND_LINE:
/* Second line is fully displayed */
Disp.State = DISP_PREP_THIRD_LINE;
if(FreetimeUs - Elapsed_us >= 200)
{
FreetimeUs -= (uint16_t)Elapsed_us;
goto DispPrepThirdLine;
}
else
{
/* Not enough time: just change state */
MySerial.rxMode();
}
break;
case DISP_THIRD_LINE:
/* Third line is fully displayed */
MySerial.print('\n');
StartWaitMs = millis();
Disp.State = DISP_WAIT;
MySerial.rxMode();
break;
}
break; /* exit while(1) */
}
}
break;
case DISP_WAIT:
if(millis() - StartWaitMs >= 500UL) Disp.State = DISP_COMPUTE; /* Give some time to enter commands via the terminal (in internal source mode) */
else Ch.FallingEdgeFound = false;
break;
}
return(Ret);
}
/* The following function checks if the received signal is the image of the one of the built-in RC generator */
uint8_t IsInternalRcSrc()
{
uint8_t Ret;
static uint32_t SampleStartMs = millis();
if(millis() - Ch.LastRxPulseMs >= 300UL) IntRcSynch = 100; /* Kick off Internal RC generator */
Ret = (IntRcSynch >= 100);
if(millis() - SampleStartMs >= 10UL)
{
SampleStartMs = millis();
IntRcSynch = 99;
}
return(Ret);
}
/* Function called in interruption in case of change on RC pins: pulse width and RC period measurement */
void InterruptFunctionToCall(void)
{
if(TinyPinChange_RisingEdge(VirtualPortIdx, RC_CHANNEL_PIN)) /* Check for RC Channel rising edge */
{
RcPeriod_us = micros() - Ch.RisingStartUs;
Ch.RisingStartUs = micros();
}
else
{
Ch.RcWidth_us = micros() - Ch.RisingStartUs;
Ch.FallingEdgeFound = true;
Ch.LastRxPulseMs = millis();
if(!(PINB & RC_PINS_MSK)) /* Check if RC_CHANNEL_PIN and RC_GEN_PIN are both to 0 */
{
if(IntRcSynch < 100) IntRcSynch++; /* if IntRcSynch reaches 100, it means the RC source is internal (synchronized) */
}else IntRcSynch = 0; /* Not synchronized */
}
}

View File

@ -1,39 +0,0 @@
TinySoftPwm library
===================
**TinySoftPwm** is a library designed to generate PWM signals by software.
Some examples of use cases:
-------------------------
* **RGB strip LED Controller**
* **DC Motor controller**
* **Digital to Analog converter**
Supported Arduinos:
------------------
* **ATtiny85 (Standalone or Digispark)** (up to 6 software PWM supported)
* **ATtiny167 (Digispark pro)** (up to 13 software PWM supported)
API/methods:
-----------
* TinySoftPwm_begin()
* TinySoftPwm_analogWrite()
* TinySoftPwm_process()
Design considerations:
---------------------
In order to reduce **program** and **RAM** memories, PWM pins shall be declared in the **TinySoftPwm.h** file. All the required amount of **program** and **RAM** memories are allocated at compilation time.
The **TinySoftPwm_process()** method shall be called periodically:
* using micros() in the loop(): in this case, asynchronous programmation shall be used: no call to blocking functions such as delay() is permitted.
* or better using periodic interruption.
In order to reduce the memory footprint (programm and RAM), try to use the PWM on pins which are part of the same port: PORTA or PORTB.
Contact
-------
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).

View File

@ -1,299 +0,0 @@
// a Tiny optimized Software PWM Manager (all pins must be part of the same port)
// Only resources RAM/Program Memory of used pins are declared in the code at compilation time.
// based largely on Atmel's AVR136: Low-Jitter Multi-Channel Software PWM Application Note:
// http://www.atmel.com/dyn/resources/prod_documents/doc8020.pdf
// RC Navy 2013-2015
// http://p.loussouarn.free.fr
// 11/01/2015: Multi port support added for ATtiny167
#include <TinySoftPwm.h>
#if (TINY_SOFT_PWM_CH_MAX == 0)
#error At least one PWM pin shall be declared in TinySoftPwm.h
#endif
#if defined(TINY_SOFT_PWM_DDR1) && defined(TINY_SOFT_PWM_DDR0)
#define TINY_SOFT_PWM_DECLARE_PIN(Pin) do{ \
if(digitalPinToPortIdx(Pin)) \
{ \
TINY_SOFT_PWM_DDR1 |= (1 << digitalPinToPortBit(Pin)); \
Port1_PwmMask |= (1 << digitalPinToPortBit(Pin)); \
} \
else \
{ \
TINY_SOFT_PWM_DDR0 |= (1 << digitalPinToPortBit(Pin)); \
Port0_PwmMask |= (1 << digitalPinToPortBit(Pin)); \
} \
}while(0)
#define TINY_SOFT_PWM_CLEAR_PIN(RamIdx) GET_PWM_PIN_PORT(RamIdx) \
? (Port1_PwmTo1 &= GET_PWM_INV_MSK(RamIdx)) \
: (Port0_PwmTo1 &= GET_PWM_INV_MSK(RamIdx))
#else
#if defined(TINY_SOFT_PWM_DDR1)
#define TINY_SOFT_PWM_DECLARE_PIN(Pin) TINY_SOFT_PWM_DDR1 |= (1 << digitalPinToPortBit(Pin)); Port1_PwmMask |= (1 << digitalPinToPortBit(Pin))
#define TINY_SOFT_PWM_CLEAR_PIN(RamIdx) Port1_PwmTo1 &= GET_PWM_INV_MSK(RamIdx)
#else
#define TINY_SOFT_PWM_DECLARE_PIN(Pin) TINY_SOFT_PWM_DDR0 |= (1 << digitalPinToPortBit(Pin)); Port0_PwmMask |= (1 << digitalPinToPortBit(Pin))
#define TINY_SOFT_PWM_CLEAR_PIN(RamIdx) Port0_PwmTo1 &= GET_PWM_INV_MSK(RamIdx)
#endif
#endif
#define GET_PWM_PIN_ID(RamIdx) ((uint8_t)pgm_read_byte(&PwmPin[(RamIdx)].Id))
#define GET_PWM_PIN_PORT(RamIdx) ((uint8_t)pgm_read_byte(&PwmPin[(RamIdx)].Port))
#define GET_PWM_INV_MSK(RamIdx) ((uint8_t)pgm_read_byte(&PwmPin[(RamIdx)].InvMsk))
typedef struct {
uint8_t Id;
uint8_t Port;
uint8_t InvMsk;
}SoftPwmPinSt_t;
const SoftPwmPinSt_t PwmPin[] PROGMEM ={
#if (TINY_SOFT_PWM_USES_PIN0 == 1)
{0, digitalPinToPortIdx(0), ~(1 << digitalPinToPortBit(0))},
#endif
#if (TINY_SOFT_PWM_USES_PIN1 == 1)
{1, digitalPinToPortIdx(1), ~(1 << digitalPinToPortBit(1))},
#endif
#if (TINY_SOFT_PWM_USES_PIN2 == 1)
{2, digitalPinToPortIdx(2), ~(1 << digitalPinToPortBit(2))},
#endif
#if (TINY_SOFT_PWM_USES_PIN3 == 1)
{3, digitalPinToPortIdx(3), ~(1 << digitalPinToPortBit(3))},
#endif
#if (TINY_SOFT_PWM_USES_PIN4 == 1)
{4, digitalPinToPortIdx(4), ~(1 << digitalPinToPortBit(4))},
#endif
#if (TINY_SOFT_PWM_USES_PIN5 == 1)
{5, digitalPinToPortIdx(5), ~(1 << digitalPinToPortBit(5))},
#endif
#if defined (__AVR_ATtiny167__)
#if (TINY_SOFT_PWM_USES_PIN6 == 1)
{6, digitalPinToPortIdx(6), ~(1 << digitalPinToPortBit(6))},
#endif
#if (TINY_SOFT_PWM_USES_PIN7 == 1)
{7, digitalPinToPortIdx(7), ~(1 << digitalPinToPortBit(7))},
#endif
#if (TINY_SOFT_PWM_USES_PIN8 == 1)
{8, digitalPinToPortIdx(8), ~(1 << digitalPinToPortBit(8))},
#endif
#if (TINY_SOFT_PWM_USES_PIN9 == 1)
{9, digitalPinToPortIdx(9), ~(1 << digitalPinToPortBit(9))},
#endif
#if (TINY_SOFT_PWM_USES_PIN10 == 1)
{10, digitalPinToPortIdx(10), ~(1 << digitalPinToPortBit(10))},
#endif
#if (TINY_SOFT_PWM_USES_PIN11 == 1)
{11, digitalPinToPortIdx(11), ~(1 << digitalPinToPortBit(11))},
#endif
#if (TINY_SOFT_PWM_USES_PIN12 == 1)
{12, digitalPinToPortIdx(12), ~(1 << digitalPinToPortBit(12))},
#endif
#endif
};
static uint8_t Compare[TINY_SOFT_PWM_CH_MAX];
volatile uint8_t PwmOrder[TINY_SOFT_PWM_CH_MAX];
#ifdef TINY_SOFT_PWM_PORT0
static uint8_t Port0_PwmMask = 0;
volatile uint8_t Port0_PwmTo1 = 0x00;
volatile uint8_t Port0_PwmTo0 = 0xFF;
#endif
#ifdef TINY_SOFT_PWM_PORT1
static uint8_t Port1_PwmMask = 0;
volatile uint8_t Port1_PwmTo1 = 0x00;
volatile uint8_t Port1_PwmTo0 = 0xFF;
#endif
static uint8_t _TickMax = 255;
static uint8_t PwmToPwmMax(uint8_t Pwm);
void TinySoftPwm_begin(uint8_t TickMax, uint8_t PwmInit)
{
uint8_t oldSREG = SREG;
cli();
// set the direction of the used ports and update PortPwmMask
#if (TINY_SOFT_PWM_USES_PIN0 == 1)
TINY_SOFT_PWM_DECLARE_PIN(0);
#endif
#if (TINY_SOFT_PWM_USES_PIN1 == 1)
TINY_SOFT_PWM_DECLARE_PIN(1);
#endif
#if (TINY_SOFT_PWM_USES_PIN2 == 1)
TINY_SOFT_PWM_DECLARE_PIN(2);
#endif
#if (TINY_SOFT_PWM_USES_PIN3 == 1)
TINY_SOFT_PWM_DECLARE_PIN(3);
#endif
#if (TINY_SOFT_PWM_USES_PIN4 == 1)
TINY_SOFT_PWM_DECLARE_PIN(4);
#endif
#if (TINY_SOFT_PWM_USES_PIN5 == 1)
TINY_SOFT_PWM_DECLARE_PIN(5);
#endif
#if (TINY_SOFT_PWM_USES_PIN6 == 1)
TINY_SOFT_PWM_DECLARE_PIN(6);
#endif
#if (TINY_SOFT_PWM_USES_PIN7 == 1)
TINY_SOFT_PWM_DECLARE_PIN(7);
#endif
#if (TINY_SOFT_PWM_USES_PIN8 == 1)
TINY_SOFT_PWM_DECLARE_PIN(8);
#endif
#if (TINY_SOFT_PWM_USES_PIN9 == 1)
TINY_SOFT_PWM_DECLARE_PIN(9);
#endif
#if (TINY_SOFT_PWM_USES_PIN10 == 1)
TINY_SOFT_PWM_DECLARE_PIN(10);
#endif
#if (TINY_SOFT_PWM_USES_PIN11 == 1)
TINY_SOFT_PWM_DECLARE_PIN(11);
#endif
#if (TINY_SOFT_PWM_USES_PIN12 == 1)
TINY_SOFT_PWM_DECLARE_PIN(12);
#endif
_TickMax = TickMax;
#ifdef TINY_SOFT_PWM_PORT0
Port0_PwmTo1 = Port0_PwmMask;
#endif
#ifdef TINY_SOFT_PWM_PORT1
Port1_PwmTo1 = Port1_PwmMask;
#endif
// initialise all channels
for(uint8_t i = 0; i < TINY_SOFT_PWM_CH_MAX; i++)
{
Compare[i] = PwmToPwmMax(PwmInit); // set default PWM values
PwmOrder[i] = Compare[i]; // set default PWM values
}
SREG = oldSREG;
}
void TinySoftPwm_analogWrite(uint8_t Pin, uint8_t Pwm)
{
uint8_t RamIdx;
for(RamIdx = 0; RamIdx < TINY_SOFT_PWM_CH_MAX; RamIdx++)
{
if(GET_PWM_PIN_ID(RamIdx) == Pin) break;
}
if(RamIdx < TINY_SOFT_PWM_CH_MAX)
{
PwmOrder[RamIdx] = PwmToPwmMax(Pwm);
}
}
static uint8_t PwmToPwmMax(uint8_t Pwm)
{
uint16_t Pwm16;
Pwm16 = map(Pwm, 0, 255, 0, _TickMax);
Pwm16 = constrain(Pwm16, 0, _TickMax);
return((uint8_t)Pwm16);
}
void TinySoftPwm_process(void)
{
static uint8_t OvfCount=0xFF;
#ifdef TINY_SOFT_PWM_PORT0
Port0_PwmTo0 = (~Port0_PwmTo1) ^ Port0_PwmMask;
TINY_SOFT_PWM_PORT0 |= Port0_PwmTo1; // update ONLY used outputs to 1 without disturbing the others
TINY_SOFT_PWM_PORT0 &= Port0_PwmTo0; // update ONLY used outputs to 0 without disturbing the others
#endif
#ifdef TINY_SOFT_PWM_PORT1
Port1_PwmTo0 = (~Port1_PwmTo1) ^ Port1_PwmMask;
TINY_SOFT_PWM_PORT1 |= Port1_PwmTo1; // update ONLY used outputs to 1 without disturbing the others
TINY_SOFT_PWM_PORT1 &= Port1_PwmTo0; // update ONLY used outputs to 0 without disturbing the others
#endif
if(++OvfCount == _TickMax)
{ // increment modulo 256 counter and update
// the compare values only when counter = 0.
OvfCount=0;
#if (TINY_SOFT_PWM_CH_MAX >= 1)
Compare[0] = PwmOrder[0]; // verbose code for speed
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 2)
Compare[1] = PwmOrder[1];
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 3)
Compare[2] = PwmOrder[2];
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 4)
Compare[3] = PwmOrder[3];
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 5)
Compare[4] = PwmOrder[4];
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 6)
Compare[5] = PwmOrder[5];
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 7)
Compare[6] = PwmOrder[6]; // verbose code for speed
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 8)
Compare[7] = PwmOrder[7];
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 9)
Compare[8] = PwmOrder[8];
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 10)
Compare[9] = PwmOrder[9];
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 11)
Compare[10] = PwmOrder[10];
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 12)
Compare[11] = PwmOrder[11];
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 13)
Compare[12] = PwmOrder[12];
#endif
#ifdef TINY_SOFT_PWM_PORT0
Port0_PwmTo1 = Port0_PwmMask; // set all port used pins high
#endif
#ifdef TINY_SOFT_PWM_PORT1
Port1_PwmTo1 = Port1_PwmMask; // set all port used pins high
#endif
}
// clear port pin on compare match (executed on next interrupt)
#if (TINY_SOFT_PWM_CH_MAX >= 1)
if(Compare[0] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(0);
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 2)
if(Compare[1] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(1);
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 3)
if(Compare[2] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(2);
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 4)
if(Compare[3] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(3);
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 5)
if(Compare[4] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(4);
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 6)
if(Compare[5] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(5);
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 7)
if(Compare[6] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(6);
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 8)
if(Compare[7] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(7);
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 9)
if(Compare[8] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(8);
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 10)
if(Compare[9] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(9);
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 11)
if(Compare[10] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(10);
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 12)
if(Compare[11] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(11);
#endif
#if (TINY_SOFT_PWM_CH_MAX >= 13)
if(Compare[12] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(12);
#endif
}

View File

@ -1,192 +0,0 @@
#ifndef TinySoftPwm_h
#define TinySoftPwm_h
// a Tiny optimized Software PWM Manager (all pins must be part of the same port)
// Only resources RAM/Program Memory of used pins are declared in the code at compilation time.
// based largely on Atmel's AVR136: Low-Jitter Multi-Channel Software PWM Application Note:
// http://www.atmel.com/dyn/resources/prod_documents/doc8020.pdf
// RC Navy 2013-2015
// http://p.loussouarn.free.fr
// 11/01/2015: Automated multi port support (at compilation time) added for ATtiny167
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <inttypes.h>
/*************************************************/
/* Define here the PIN to use with Tiny Soft PWM */
/* Unused Pin(s) SHALL be commented */
/*************************************************/
#define TINY_SOFT_PWM_USES_PIN0
#define TINY_SOFT_PWM_USES_PIN1
#define TINY_SOFT_PWM_USES_PIN2
#define TINY_SOFT_PWM_USES_PIN3 /* /!\ used for USB on DigiSpark (pro): do not use it for PWM if DigiUSB or SerialCDC are also used /!\ */
#define TINY_SOFT_PWM_USES_PIN4 /* /!\ used for USB on DigiSpark (pro): do not use it for PWM if DigiUSB or SerialCDC are also used /!\ */
#define TINY_SOFT_PWM_USES_PIN5
#define TINY_SOFT_PWM_USES_PIN6
#define TINY_SOFT_PWM_USES_PIN7
#define TINY_SOFT_PWM_USES_PIN8
#define TINY_SOFT_PWM_USES_PIN9
#define TINY_SOFT_PWM_USES_PIN10
#define TINY_SOFT_PWM_USES_PIN11
#define TINY_SOFT_PWM_USES_PIN12
/*******************************************************************/
/* Do NOT modify below: it's used to optimize RAM and Program size */
/*******************************************************************/
#if defined (__AVR_ATtiny85__)
#undef TINY_SOFT_PWM_USES_PIN6
#undef TINY_SOFT_PWM_USES_PIN7
#undef TINY_SOFT_PWM_USES_PIN8
#undef TINY_SOFT_PWM_USES_PIN9
#undef TINY_SOFT_PWM_USES_PIN10
#undef TINY_SOFT_PWM_USES_PIN11
#undef TINY_SOFT_PWM_USES_PIN12
#endif
#ifdef TINY_SOFT_PWM_USES_PIN0
#undef TINY_SOFT_PWM_USES_PIN0
#define TINY_SOFT_PWM_USES_PIN0 1
#else
#define TINY_SOFT_PWM_USES_PIN0 0
#endif
#ifdef TINY_SOFT_PWM_USES_PIN1
#undef TINY_SOFT_PWM_USES_PIN1
#define TINY_SOFT_PWM_USES_PIN1 1
#else
#define TINY_SOFT_PWM_USES_PIN1 0
#endif
#ifdef TINY_SOFT_PWM_USES_PIN2
#undef TINY_SOFT_PWM_USES_PIN2
#define TINY_SOFT_PWM_USES_PIN2 1
#else
#define TINY_SOFT_PWM_USES_PIN2 0
#endif
#ifdef TINY_SOFT_PWM_USES_PIN3
#undef TINY_SOFT_PWM_USES_PIN3
#define TINY_SOFT_PWM_USES_PIN3 1
#else
#define TINY_SOFT_PWM_USES_PIN3 0
#endif
#ifdef TINY_SOFT_PWM_USES_PIN4
#undef TINY_SOFT_PWM_USES_PIN4
#define TINY_SOFT_PWM_USES_PIN4 1
#else
#define TINY_SOFT_PWM_USES_PIN4 0
#endif
#ifdef TINY_SOFT_PWM_USES_PIN5
#undef TINY_SOFT_PWM_USES_PIN5
#define TINY_SOFT_PWM_USES_PIN5 1
#else
#define TINY_SOFT_PWM_USES_PIN5 0
#endif
#ifdef TINY_SOFT_PWM_USES_PIN6
#undef TINY_SOFT_PWM_USES_PIN6
#define TINY_SOFT_PWM_USES_PIN6 1
#else
#define TINY_SOFT_PWM_USES_PIN6 0
#endif
#ifdef TINY_SOFT_PWM_USES_PIN7
#undef TINY_SOFT_PWM_USES_PIN7
#define TINY_SOFT_PWM_USES_PIN7 1
#else
#define TINY_SOFT_PWM_USES_PIN7 0
#endif
#ifdef TINY_SOFT_PWM_USES_PIN8
#undef TINY_SOFT_PWM_USES_PIN8
#define TINY_SOFT_PWM_USES_PIN8 1
#else
#define TINY_SOFT_PWM_USES_PIN8 0
#endif
#ifdef TINY_SOFT_PWM_USES_PIN9
#undef TINY_SOFT_PWM_USES_PIN9
#define TINY_SOFT_PWM_USES_PIN9 1
#else
#define TINY_SOFT_PWM_USES_PIN9 0
#endif
#ifdef TINY_SOFT_PWM_USES_PIN10
#undef TINY_SOFT_PWM_USES_PIN10
#define TINY_SOFT_PWM_USES_PIN10 1
#else
#define TINY_SOFT_PWM_USES_PIN10 0
#endif
#ifdef TINY_SOFT_PWM_USES_PIN11
#undef TINY_SOFT_PWM_USES_PIN11
#define TINY_SOFT_PWM_USES_PIN11 1
#else
#define TINY_SOFT_PWM_USES_PIN11 0
#endif
#ifdef TINY_SOFT_PWM_USES_PIN12
#undef TINY_SOFT_PWM_USES_PIN12
#define TINY_SOFT_PWM_USES_PIN12 1
#else
#define TINY_SOFT_PWM_USES_PIN12 0
#endif
#define TINY_SOFT_PWM_CH_MAX (TINY_SOFT_PWM_USES_PIN0 + TINY_SOFT_PWM_USES_PIN1 + TINY_SOFT_PWM_USES_PIN2 + \
TINY_SOFT_PWM_USES_PIN3 + TINY_SOFT_PWM_USES_PIN4 + TINY_SOFT_PWM_USES_PIN5 + \
TINY_SOFT_PWM_USES_PIN6 + TINY_SOFT_PWM_USES_PIN7 + TINY_SOFT_PWM_USES_PIN8 + \
TINY_SOFT_PWM_USES_PIN9 + TINY_SOFT_PWM_USES_PIN10+ TINY_SOFT_PWM_USES_PIN11+ \
TINY_SOFT_PWM_USES_PIN12)
#if defined (__AVR_ATtiny85__)
#define TINY_SOFT_PWM_USES_PORT0 0
#define TINY_SOFT_PWM_USES_PORT1 1
#ifndef digitalPinToPortIdx
#define digitalPinToPortIdx(p) 1
#endif
#else
#if defined (__AVR_ATtiny167__)
#define TINY_SOFT_PWM_USES_PORT0 (TINY_SOFT_PWM_USES_PIN5 || TINY_SOFT_PWM_USES_PIN6 || TINY_SOFT_PWM_USES_PIN7 || \
TINY_SOFT_PWM_USES_PIN8 || TINY_SOFT_PWM_USES_PIN9 || TINY_SOFT_PWM_USES_PIN10 || \
TINY_SOFT_PWM_USES_PIN11 || TINY_SOFT_PWM_USES_PIN12)
#define TINY_SOFT_PWM_USES_PORT1 (TINY_SOFT_PWM_USES_PIN0 || TINY_SOFT_PWM_USES_PIN1 || TINY_SOFT_PWM_USES_PIN2 || \
TINY_SOFT_PWM_USES_PIN3 || TINY_SOFT_PWM_USES_PIN4)
#ifndef digitalPinToPortIdx
#define digitalPinToPortIdx(p) (((p) >= 5 && (p) <= 12) ? (0) : (1))
#endif
#endif
#endif
#if (TINY_SOFT_PWM_USES_PORT0 == 1)
#undef TINY_SOFT_PWM_USES_PORT0
#define TINY_SOFT_PWM_PORT0 PORTA
#define TINY_SOFT_PWM_DDR0 DDRA
#endif
#if (TINY_SOFT_PWM_USES_PORT1 == 1)
#undef TINY_SOFT_PWM_USES_PORT1
#define TINY_SOFT_PWM_PORT1 PORTB
#define TINY_SOFT_PWM_DDR1 DDRB
#endif
#ifndef digitalPinToPortBit
#define digitalPinToPortBit(p) digitalPinToPCMSKbit(p)
#endif
/* Public Function Prototypes */
void TinySoftPwm_begin(uint8_t TickMax, uint8_t PwmInit);
void TinySoftPwm_analogWrite(uint8_t Pin, uint8_t Pwm);
void TinySoftPwm_process(void);
#endif

View File

@ -1,75 +0,0 @@
#include <TinySoftPwm.h>
/*
_____ ____ __ _ ____ _ _ _ _
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2015
http://p.loussouarn.free.fr
****************************************
* <TinySoftPwm> library Demo *
****************************************
This sketch generates simultaneously PWM signals on 13 pins (Pin 0 to pin 12 of the Digispark pro).
It also increases the luminosity of the built-in LED of the Digispark whilst the duty cycle remains constant for all other pins.
When the luminosity reaches its maximum, the luminosity decreases.
When the luminosity reaches its minimum, the luminosity increases, and so on...
Note:
====
Declare the Pin(s) used in "librarie/TinySoftPwm/TinySoftPwm.h"
In this sketch, #define TINY_SOFT_PWM_USES_PINO to TINY_SOFT_PWM_USES_PIN12 must be enabled (not commented) since it uses the first 13 pins of the DigiSpark pro.
In this basic example, TinySoftPwm_process() is called periodically using micros(), but it is recommanded to call it from a timer ISR
to ensure a better periodicity.
*/
#define BUILT_IN_LED_PIN 1 /* Digispark Model A (Rev2) built-in LED pin number (Change it to 2 for Model B) */
void setup()
{
TinySoftPwm_begin(255, 0); /* 255 x TinySoftPwm_process() calls before overlap (Frequency tuning), 0 = PWM init for all declared pins */
for(uint8_t PinIdx = 0; PinIdx <= 12; PinIdx++)
{
TinySoftPwm_analogWrite(PinIdx, (PinIdx + 1) * 19); /* Low to high duty cycle for pin 0 to 12 */
}
}
void loop()
{
static uint32_t StartUs = micros();
static uint32_t StartMs = millis();
static uint8_t Pwm = 0;
static int8_t Dir = 1;
/***********************************************************/
/* Call TinySoftPwm_process() with a period of 40 us */
/* The PWM frequency = 255 x 40 # 10.2 ms -> F # 100Hz */
/* 255 is the first argument passed to TinySoftPwm_begin() */
/***********************************************************/
if((micros() - StartUs) >= 40)
{
/* We arrived here every 40 microseconds */
StartUs = micros();
TinySoftPwm_process(); /* This function shall be called periodically (like here, based on micros(), or in a timer ISR) */
}
/*************************************************************/
/* Increment/decrement PWM on LED Pin with a period of 10 ms */
/*************************************************************/
if((millis() - StartMs) >= 10)
{
/* We arrived here every 10 milliseconds */
StartMs = millis();
Pwm += Dir; /* increment or decrement PWM depending of sign of Dir */
TinySoftPwm_analogWrite(BUILT_IN_LED_PIN, Pwm); /* Update built-in LED for Digispark */
if(Pwm == 255) Dir = -1; /* if PWM reaches the maximum: change direction */
if(Pwm == 0) Dir = +1; /* if PWM reaches the minimum: change direction */
}
}

View File

@ -1,13 +0,0 @@
void setup() {
//If prompted for a pairing code it is 1234, 12345, or 000000
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
if (Serial.available()) {
Serial.write(Serial.read());
}
}

View File

@ -1,94 +0,0 @@
void setup() {
// put your setup code here, to run once:
Serial.begin(9600); //open connection to bt/ble module
botInit(); //setup the pins for the bot
}
void loop() {
if(Serial.available()){
char input = Serial.read();
//route based on input
if(input == 'f'){
botForward(255);
}
else if(input == 'b'){
botReverse(255);
}
else if(input == 'r'){
botRight(255);
}
else if(input == 'l'){
botLeft(255);
}
else if(input == 's'){
botStop();
}
}
}
void botForward(int botSpeed){
digitalWrite(2, HIGH);
digitalWrite(5, HIGH);
analogWrite(0, 255 - botSpeed);
analogWrite(1, 255 - botSpeed);
}
void botReverse(int botSpeed){
digitalWrite(2, LOW);
digitalWrite(5, LOW);
analogWrite(0, botSpeed);
analogWrite(1, botSpeed);
}
void botRight(int botSpeed){
digitalWrite(2, LOW);
digitalWrite(5, HIGH);
analogWrite(0, 0);
analogWrite(1, 255 - botSpeed);
}
void botHardRight(int botSpeed){
digitalWrite(2, LOW);
digitalWrite(5, HIGH);
analogWrite(0, botSpeed);
analogWrite(1, 255 - botSpeed);
}
void botLeft(int botSpeed){
digitalWrite(2, HIGH);
digitalWrite(5, LOW);
analogWrite(0, 255 - botSpeed);
analogWrite(1, 0);
}
void botHardLeft(int botSpeed){
digitalWrite(2, HIGH);
digitalWrite(5, LOW);
analogWrite(0, 255 - botSpeed);
analogWrite(1, botSpeed);
}
void botStop(){
digitalWrite(2,LOW);
digitalWrite(5,LOW);
analogWrite(0,0);
analogWrite(1,0);
}
void botInit(){
pinMode(0,OUTPUT);
pinMode(1,OUTPUT);
pinMode(2,OUTPUT);
pinMode(5,OUTPUT);
}

View File

@ -1 +0,0 @@
//This file allows the Digispark_Examples to appear in the File > Examples menu and fixes the Invalid library warning in Arduino IDE 1.6.6+

View File

@ -1,105 +0,0 @@
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
//THESE MUST BE SET! CHANGE ADDRESS AS YOU UPLOAD TO EACH NODE!
#define TOTAL_NODES 3 //TOTAL NUMBER OF NODES IN MESH
#define NODE_ADDRESS 0 //the sero indexed address of this node - nodes must be numbered 0 thru TOTAL_NODES-1 //also note 255 is broadcast address
//hold the seuqnce numbers to avoid repeating the same messages
uint8_t sequence[TOTAL_NODES];
//setup radio module
RF24 radio(9,12);
//message format - adjust data as needed - the rest is madatory for this mesh to work
struct
{
char toAddress;
char fromAddress;
char fromSequence;
long data;
} msg;
//don't change! read is same for all nodes, write is automatically calculated here
const uint64_t writePipe = 0xF0F0F0F00LL + NODE_ADDRESS;
const uint64_t readPipe = 0xF0F0F0F0D2LL;
void setup() {
// put your setup code here, to run once:
radio.begin();
radio.setDataRate(RF24_250KBPS); //lowest speed = most range
radio.setAutoAck(false); //this is a mesh so we don't want ACKs!
radio.setRetries(15, 15);
radio.setPayloadSize(sizeof(msg));
radio.openWritingPipe(writePipe);
radio.openReadingPipe(1, readPipe);
radio.startListening();
}
long now = 0;
void loop() {
if(readAndRepeat()){ //will repeat messages as needed and return false unless there is packet for this node - CALL FREQUENTLY!
//if this does not return false then we have a packet for THIS node!
//msg.fromAddress is the node that sent it
//msg.data is the data itself
//Do something with it!
//For example display packets coming to this node on a LCD:
/*
NOTE: TO USE THIS ADD THE LCD INCLUDES AND SETUP ROUTINE FROM THE DigisparkLCD example
lcd.clear();
lcd.print("From: ");
lcd.println(msg.fromAddress);
lcd.print("Value: ");
lcd.println(msg.data);
*/
}
if(millis() - now > 10000){ //send a packet from this node to the mesh every 10 seconds but wait in a non-blocking way so that we can still run this loop and repeat things
now = millis(); //set now to millis so we wait another 10 seconds before sending again
//sendToMesh(To_Address,Data_To_Send);
//sendToMesh(0, analogRead(A5)); //send to node 0 the analog read value of pin 5 - could also send a temp sensor value, etc ,etc
//sendToMesh(255, analogRead(A5)); //send to all nodes (255 is the broadcast address) the analog read value of pin 5
}
}
void sendToMesh(uint8_t toAddress, long data){
if(sequence[NODE_ADDRESS]<255)
sequence[NODE_ADDRESS]++; //increment sequence count for this device
else
sequence[NODE_ADDRESS] = 0; //set to zero if last was 255 so we don't overflow - logic for read is built to handle this too
msg.toAddress = toAddress; //set the address of the destination node
msg.fromAddress = NODE_ADDRESS; //set the from as this node - of course
msg.fromSequence = sequence[NODE_ADDRESS]; //set it to the sequence number we just implemented which should be greater than any the nodes have received
radio.stopListening(); //turn of recv so we can transmit
radio.write(&msg, sizeof(msg));
radio.startListening(); //turn recv back on
}
bool readAndRepeat(){
if(radio.read(&msg, sizeof(msg))){ //if we have incoming data
if(msg.fromAddress!=NODE_ADDRESS){ //make sure this node didn't send it
if(sequence[msg.fromAddress] < msg.fromSequence || (sequence[msg.fromAddress] == 255 && msg.fromSequence == 0)){ //make sure we haven't already repeated it or received it
//increment sequence for that address so we don't repeat it twice from this node or receive it twice
sequence[msg.fromAddress] = msg.fromSequence;
if(msg.toAddress==NODE_ADDRESS){ //is it for this node? if so return true so we can use it!
return true;
}
//otherwise repeat it - send it back out
radio.write(&msg, sizeof(msg));
if(msg.toAddress == 255){ //it was a broadcast so return true so we do something with it
return true;
}
}
}
}
return false;
}

View File

@ -1,157 +0,0 @@
#include <Wire.h>
#include <DigiKeyboard.h>
#define ADXL345 (0x53) //address of Accelerometer
#define ADXL345_X (0x32) //register for X value from Accelerometer
#define ADXL345_Y (0x34) //register for Y value from Accelerometer
#define ADXL345_Z (0x36) //register for Z value from Accelerometer
#define HMC5883 (0x1E) //address of Magnetometer
#define ITG3200 (0x68) //address of Gyro
int16_t magX = 0; //X value from Magnetometer
int16_t magY = 0; //Y value from Magnetometer
int16_t magZ = 0; //Z value from Magnetometer
int gyroHX = 0; //HX value from Gyro
int gyroHY = 0; //HY value from Gyro
int gyroHZ = 0; //HZ value from Gyro
void setup()
{
Wire.begin();
initAccelerometer();
initMagnetometer();
initGyro();
}
void loop()
{
DigiKeyboard.println(readAccelerometer(ADXL345_X));
DigiKeyboard.println(readAccelerometer(ADXL345_Y));
DigiKeyboard.println(readAccelerometer(ADXL345_Z));
DigiKeyboard.delay(1000);
readMagnetometer();
DigiKeyboard.println(magX);
DigiKeyboard.println(magY);
DigiKeyboard.println(magZ);
DigiKeyboard.println(getHeading());
DigiKeyboard.delay(1000);
readGyro();
DigiKeyboard.println(gyroHX);
DigiKeyboard.println(gyroHY);
DigiKeyboard.println(gyroHZ);
DigiKeyboard.delay(1000);
}
void initGyro(){
writeRegister(ITG3200, 0x3E, 0x00); //enable
writeRegister(ITG3200, 0x15, 0x07); // EB, 50, 80, 7F, DE, 23, 20, FF
writeRegister(ITG3200, 0x16, 0x1E); // +/- 2000 dgrs/sec, 1KHz, 1E, 19
writeRegister(ITG3200, 0x17, 0x00);
}
void readGyro(){
Wire.beginTransmission(ITG3200);
Wire.write(0x1B); //format x y z temp
Wire.endTransmission();
Wire.requestFrom(ITG3200, (byte)8);
// Wait around until enough data is available
while (Wire.available() < 8);
uint8_t lo = Wire.read();
uint8_t hi = Wire.read();
//throw out first two - don't seem accurate
//gyroTemp = (lo << 8) | hi; // temperature
//gyroTemp = ((double) (gyroTemp + 13200)) / 280;
lo = Wire.read();
hi = Wire.read();
gyroHX = (((lo << 8) | hi) + 120 )/ 14.375;
lo = Wire.read();
hi = Wire.read();
gyroHY = (((lo << 8) | hi) + 20 )/ 14.375;
lo = Wire.read();
hi = Wire.read();
gyroHZ = (((lo << 8) | hi) + 93 )/ 14.375;
}
void initMagnetometer(){
writeRegister(HMC5883, 0x02, 0x00); //enable
}
void readMagnetometer(){
Wire.beginTransmission(HMC5883);
Wire.write(0x03); //format X_H_M
Wire.endTransmission();
Wire.requestFrom(HMC5883, (byte)6);
// Wait around until enough data is available
while (Wire.available() < 6);
// Note high before low (different than accel)
uint8_t hi = Wire.read();
uint8_t lo = Wire.read();
// Shift values to create properly formed integer (low byte first)
magX = (int16_t)(hi | ((int16_t)lo << 8));
// Note high before low (different than accel)
hi = Wire.read();
lo = Wire.read();
// Shift values to create properly formed integer (low byte first)
magY = (int16_t)(hi | ((int16_t)lo << 8));
// Note high before low (different than accel)
hi = Wire.read();
lo = Wire.read();
// Shift values to create properly formed integer (low byte first)
magZ = (int16_t)(hi | ((int16_t)lo << 8));
}
void initAccelerometer(){
//if(readRegister(ADXL345,0x00) != 0xE5)
writeRegister(ADXL345, 0x2D, 0x08); //power up and enable measurements
writeRegister(ADXL345, 0x31, 0x01);//set range to +/-4G
}
uint16_t readAccelerometer(uint8_t reg){
Wire.beginTransmission(ADXL345);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom(ADXL345, 2);
return (uint16_t)(Wire.read() | (Wire.read() << 8));
}
uint8_t readRegister(uint8_t address, uint8_t reg){
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom(address, 1);
return Wire.read();
}
void writeRegister(uint8_t address, uint8_t reg, uint8_t val){
Wire.beginTransmission(address);
Wire.write(reg);
Wire.write(val);
Wire.endTransmission();
}
float getHeading(){
// Hold the module so that Z is pointing 'up' and you can measure the heading with x&y
// Calculate heading when the magnetometer is level, then correct for signs of axis.
float heading = atan2(magY, magX);
// Correct for when signs are reversed.
if(heading < 0)
heading += 2*PI;
// Check for wrap due to addition of declination.
if(heading > 2*PI)
heading -= 2*PI;
// Convert radians to degrees for readability.
heading = heading * 180/M_PI;
return heading;
}

View File

@ -1,146 +0,0 @@
/*
EEPROM.h - EEPROM library
Original Copyright (c) 2006 David A. Mellis. All right reserved.
New version by Christopher Andrews 2015.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef EEPROM_h
#define EEPROM_h
#include <inttypes.h>
#include <avr/eeprom.h>
#include <avr/io.h>
/***
EERef class.
This object references an EEPROM cell.
Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM.
This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell.
***/
struct EERef{
EERef( const int index )
: index( index ) {}
//Access/read members.
uint8_t operator*() const { return eeprom_read_byte( (uint8_t*) index ); }
operator const uint8_t() const { return **this; }
//Assignment/write members.
EERef &operator=( const EERef &ref ) { return *this = *ref; }
EERef &operator=( uint8_t in ) { return eeprom_write_byte( (uint8_t*) index, in ), *this; }
EERef &operator +=( uint8_t in ) { return *this = **this + in; }
EERef &operator -=( uint8_t in ) { return *this = **this - in; }
EERef &operator *=( uint8_t in ) { return *this = **this * in; }
EERef &operator /=( uint8_t in ) { return *this = **this / in; }
EERef &operator ^=( uint8_t in ) { return *this = **this ^ in; }
EERef &operator %=( uint8_t in ) { return *this = **this % in; }
EERef &operator &=( uint8_t in ) { return *this = **this & in; }
EERef &operator |=( uint8_t in ) { return *this = **this | in; }
EERef &operator <<=( uint8_t in ) { return *this = **this << in; }
EERef &operator >>=( uint8_t in ) { return *this = **this >> in; }
EERef &update( uint8_t in ) { return in != *this ? *this = in : *this; }
/** Prefix increment/decrement **/
EERef& operator++() { return *this += 1; }
EERef& operator--() { return *this -= 1; }
/** Postfix increment/decrement **/
uint8_t operator++ (int){
uint8_t ret = **this;
return ++(*this), ret;
}
uint8_t operator-- (int){
uint8_t ret = **this;
return --(*this), ret;
}
int index; //Index of current EEPROM cell.
};
/***
EEPtr class.
This object is a bidirectional pointer to EEPROM cells represented by EERef objects.
Just like a normal pointer type, this can be dereferenced and repositioned using
increment/decrement operators.
***/
struct EEPtr{
EEPtr( const int index )
: index( index ) {}
operator const int() const { return index; }
EEPtr &operator=( int in ) { return index = in, *this; }
//Iterator functionality.
bool operator!=( const EEPtr &ptr ) { return index != ptr.index; }
EERef operator*() { return index; }
/** Prefix & Postfix increment/decrement **/
EEPtr& operator++() { return ++index, *this; }
EEPtr& operator--() { return --index, *this; }
EEPtr operator++ (int) { return index++; }
EEPtr operator-- (int) { return index--; }
int index; //Index of current EEPROM cell.
};
/***
EEPROMClass class.
This object represents the entire EEPROM space.
It wraps the functionality of EEPtr and EERef into a basic interface.
This class is also 100% backwards compatible with earlier Arduino core releases.
***/
struct EEPROMClass{
//Basic user access methods.
EERef operator[]( const int idx ) { return idx; }
uint8_t read( int idx ) { return EERef( idx ); }
void write( int idx, uint8_t val ) { (EERef( idx )) = val; }
void update( int idx, uint8_t val ) { EERef( idx ).update( val ); }
//STL and C++11 iteration capability.
EEPtr begin() { return 0x00; }
EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid.
uint16_t length() { return E2END + 1; }
//Functionality to 'get' and 'put' objects to and from EEPROM.
template< typename T > T &get( int idx, T &t ){
EEPtr e = idx;
uint8_t *ptr = (uint8_t*) &t;
for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e;
return t;
}
template< typename T > const T &put( int idx, const T &t ){
EEPtr e = idx;
const uint8_t *ptr = (const uint8_t*) &t;
for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ );
return t;
}
};
static EEPROMClass EEPROM;
#endif

View File

@ -1,139 +0,0 @@
## **EEPROM Library V2.0** for Arduino
**Written by:** _Christopher Andrews_.
### **What is the EEPROM library.**
Th EEPROM library provides an easy to use interface to interact with the internal non-volatile storage found in AVR based Arduino boards. This library will work on many AVR devices like ATtiny and ATmega chips.
### **How to use it**
The EEPROM library is included in your IDE download. To add its functionality to your sketch you'll need to reference the library header file. You do this by adding an include directive to the top of your sketch.
```Arduino
#include <EEPROM.h>
void setup(){
}
void loop(){
}
```
The library provides a global variable named `EEPROM`, you use this variable to access the library functions. The methods provided in the EEPROM class are listed below.
You can view all the examples [here](examples/).
### **Library functions**
#### **`EEPROM.read( address )`** [[_example_]](examples/eeprom_read/eeprom_read.ino)
This function allows you to read a single byte of data from the eeprom.
Its only parameter is an `int` which should be set to the address you wish to read.
The function returns an `unsigned char` containing the value read.
#### **`EEPROM.write( address, value )`** [[_example_]](examples/eeprom_write/eeprom_write.ino)
The `write()` method allows you to write a single byte of data to the EEPROM.
Two parameters are needed. The first is an `int` containing the address that is to be written, and the second is a the data to be written (`unsigned char`).
This function does not return any value.
#### **`EEPROM.update( address, value )`** [[_example_]](examples/eeprom_update/eeprom_update.ino)
This function is similar to `EEPROM.write()` however this method will only write data if the cell contents pointed to by `address` is different to `value`. This method can help prevent unnecessary wear on the EEPROM cells.
This function does not return any value.
#### **`EEPROM.get( address, object )`** [[_example_]](examples/eeprom_get/eeprom_get.ino)
This function will retrieve any object from the EEPROM.
Two parameters are needed to call this function. The first is an `int` containing the address that is to be written, and the second is the object you would like to read.
This function returns a reference to the `object` passed in. It does not need to be used and is only returned for conveience.
#### **`EEPROM.put( address, object )`** [[_example_]](examples/eeprom_put/eeprom_put.ino)
This function will write any object to the EEPROM.
Two parameters are needed to call this function. The first is an `int` containing the address that is to be written, and the second is the object you would like to write.
This function uses the _update_ method to write its data, and therefore only rewrites changed cells.
This function returns a reference to the `object` passed in. It does not need to be used and is only returned for conveience.
#### **Subscript operator: `EEPROM[address]`** [[_example_]](examples/eeprom_crc/eeprom_crc.ino)
This operator allows using the identifier `EEPROM` like an array.
EEPROM cells can be read _and_ **_written_** directly using this method.
This operator returns a reference to the EEPROM cell.
```c++
unsigned char val;
//Read first EEPROM cell.
val = EEPROM[ 0 ];
//Write first EEPROM cell.
EEPROM[ 0 ] = val;
//Compare contents
if( val == EEPROM[ 0 ] ){
//Do something...
}
```
#### **`EEPROM.length()`**
This function returns an `unsigned int` containing the number of cells in the EEPROM.
---
### **Advanced features**
This library uses a component based approach to provide its functionality. This means you can also use these components to design a customized approach. Two background classes are available for use: `EERef` & `EEPtr`.
#### **`EERef` class**
This object references an EEPROM cell.
Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM.
This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell.
```C++
EERef ref = EEPROM[ 10 ]; //Create a reference to 11th cell.
ref = 4; //write to EEPROM cell.
unsigned char val = ref; //Read referenced cell.
```
#### **`EEPtr` class**
This object is a bidirectional pointer to EEPROM cells represented by `EERef` objects.
Just like a normal pointer type, this type can be dereferenced and repositioned using
increment/decrement operators.
```C++
EEPtr ptr = 10; //Create a pointer to 11th cell.
*ptr = 4; //dereference and write to EEPROM cell.
unsigned char val = *ptr; //dereference and read.
ptr++; //Move to next EEPROM cell.
```
#### **`EEPROM.begin()`**
This function returns an `EEPtr` pointing to the first cell in the EEPROM.
This is useful for STL objects, custom iteration and C++11 style ranged for loops.
#### **`EEPROM.end()`**
This function returns an `EEPtr` pointing at the location after the last EEPROM cell.
Used with `begin()` to provide custom iteration.
**Note:** The `EEPtr` returned is invalid as it is out of range. Infact the hardware causes wrapping of the address (overflow) and `EEPROM.end()` actually references the first EEPROM cell.

View File

@ -1,35 +0,0 @@
/*
* EEPROM Clear
*
* Sets all of the bytes of the EEPROM to 0.
* Please see eeprom_iteration for a more in depth
* look at how to traverse the EEPROM.
*
* This example code is in the public domain.
*/
#include <EEPROM.h>
void setup()
{
/***
Iterate through each byte of the EEPROM storage.
Larger AVR processors have larger EEPROM sizes, E.g:
- Arduno Duemilanove: 512b EEPROM storage.
- Arduino Uno: 1kb EEPROM storage.
- Arduino Mega: 4kb EEPROM storage.
Rather than hard-coding the length, you should use the pre-provided length function.
This will make your code portable to all AVR processors.
***/
for ( int i = 0 ; i < EEPROM.length() ; i++ )
EEPROM.write(i, 0);
// turn the LED on when we're done
digitalWrite(13, HIGH);
}
void loop(){ /** Empty loop. **/ }

View File

@ -1,50 +0,0 @@
/***
Written by Christopher Andrews.
CRC algorithm generated by pycrc, MIT licence ( https://github.com/tpircher/pycrc ).
A CRC is a simple way of checking whether data has changed or become corrupted.
This example calculates a CRC value directly on the EEPROM values.
The purpose of this example is to highlight how the EEPROM object can be used just like an array.
***/
#include <Arduino.h>
#include <EEPROM.h>
void setup(){
//Start serial
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
//Print length of data to run CRC on.
Serial.print( "EEPROM length: " );
Serial.println( EEPROM.length() );
//Print the result of calling eeprom_crc()
Serial.print( "CRC32 of EEPROM data: 0x" );
Serial.println( eeprom_crc(), HEX );
Serial.print( "\n\nDone!" );
}
void loop(){ /* Empty loop */ }
unsigned long eeprom_crc( void ){
const unsigned long crc_table[16] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
unsigned long crc = ~0L;
for( int index = 0 ; index < EEPROM.length() ; ++index ){
crc = crc_table[( crc ^ EEPROM[index] ) & 0x0f] ^ (crc >> 4);
crc = crc_table[( crc ^ ( EEPROM[index] >> 4 )) & 0x0f] ^ (crc >> 4);
crc = ~crc;
}
return crc;
}

View File

@ -1,66 +0,0 @@
/***
eeprom_get example.
This shows how to use the EEPROM.get() method.
To pre-set the EEPROM data, run the example sketch eeprom_put.
This sketch will run without it, however, the values shown
will be shown from what ever is already on the EEPROM.
This may cause the serial object to print out a large string
of garbage if there is no null character inside one of the strings
loaded.
Written by Christopher Andrews 2015
Released under MIT licence.
***/
#include <EEPROM.h>
void setup(){
float f = 0.00f; //Variable to store data read from EEPROM.
int eeAddress = 0; //EEPROM address to start reading from
Serial.begin( 9600 );
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.print( "Read float from EEPROM: " );
//Get the float data from the EEPROM at position 'eeAddress'
EEPROM.get( eeAddress, f );
Serial.println( f, 3 ); //This may print 'ovf, nan' if the data inside the EEPROM is not a valid float.
/***
As get also returns a reference to 'f', you can use it inline.
E.g: Serial.print( EEPROM.get( eeAddress, f ) );
***/
/***
Get can be used with custom structures too.
I have separated this into an extra function.
***/
secondTest(); //Run the next test.
}
struct MyObject{
float field1;
byte field2;
char name[10];
};
void secondTest(){
int eeAddress = sizeof(float); //Move address to the next byte after float 'f'.
MyObject customVar; //Variable to store custom object read from EEPROM.
EEPROM.get( eeAddress, customVar );
Serial.println( "Read custom object from EEPROM: " );
Serial.println( customVar.field1 );
Serial.println( customVar.field2 );
Serial.println( customVar.name );
}
void loop(){ /* Empty loop */ }

View File

@ -1,57 +0,0 @@
/***
eeprom_iteration example.
A set of example snippets highlighting the
simplest methods for traversing the EEPROM.
Running this sketch is not necessary, this is
simply highlighting certain programming methods.
Written by Christopher Andrews 2015
Released under MIT licence.
***/
#include <EEPROM.h>
void setup() {
/***
Iterate the EEPROM using a for loop.
***/
for( int index = 0 ; index < EEPROM.length() ; index++ ){
//Add one to each cell in the EEPROM
EEPROM[ index ] += 1;
}
/***
Iterate the EEPROM using a while loop.
***/
int index = 0;
while( index < EEPROM.length() ){
//Add one to each cell in the EEPROM
EEPROM[ index ] += 1;
index++;
}
/***
Iterate the EEPROM using a do-while loop.
***/
int idx = 0; //Used 'idx' to avoid name conflict with 'index' above.
do{
//Add one to each cell in the EEPROM
EEPROM[ idx ] += 1;
idx++;
}while( idx < EEPROM.length() );
} //End of setup function.
void loop(){}

View File

@ -1,56 +0,0 @@
/***
eeprom_put example.
This shows how to use the EEPROM.put() method.
Also, this sketch will pre-set the EEPROM data for the
example sketch eeprom_get.
Note, unlike the single byte version EEPROM.write(),
the put method will use update semantics. As in a byte
will only be written to the EEPROM if the data is actually
different.
Written by Christopher Andrews 2015
Released under MIT licence.
***/
#include <EEPROM.h>
struct MyObject{
float field1;
byte field2;
char name[10];
};
void setup(){
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
float f = 123.456f; //Variable to store in EEPROM.
int eeAddress = 0; //Location we want the data to be put.
//One simple call, with the address first and the object second.
EEPROM.put( eeAddress, f );
Serial.println("Written float data type!");
/** Put is designed for use with custom structures also. **/
//Data to store.
MyObject customVar = {
3.14f,
65,
"Working!"
};
eeAddress += sizeof(float); //Move address to the next byte after float 'f'.
EEPROM.put( eeAddress, customVar );
Serial.print( "Written custom data type! \n\nView the example sketch eeprom_get to see how you can retrieve the values!" );
}
void loop(){ /* Empty loop */ }

View File

@ -1,57 +0,0 @@
/*
* EEPROM Read
*
* Reads the value of each byte of the EEPROM and prints it
* to the computer.
* This example code is in the public domain.
*/
#include <EEPROM.h>
// start reading from the first byte (address 0) of the EEPROM
int address = 0;
byte value;
void setup()
{
// initialize serial and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
}
void loop()
{
// read a byte from the current address of the EEPROM
value = EEPROM.read(address);
Serial.print(address);
Serial.print("\t");
Serial.print(value, DEC);
Serial.println();
/***
Advance to the next address, when at the end restart at the beginning.
Larger AVR processors have larger EEPROM sizes, E.g:
- Arduno Duemilanove: 512b EEPROM storage.
- Arduino Uno: 1kb EEPROM storage.
- Arduino Mega: 4kb EEPROM storage.
Rather than hard-coding the length, you should use the pre-provided length function.
This will make your code portable to all AVR processors.
***/
address = address + 1;
if(address == EEPROM.length())
address = 0;
/***
As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an
EEPROM address is also doable by a bitwise and of the length - 1.
++address &= EEPROM.length() - 1;
***/
delay(500);
}

View File

@ -1,69 +0,0 @@
/***
EEPROM Update method
Stores values read from analog input 0 into the EEPROM.
These values will stay in the EEPROM when the board is
turned off and may be retrieved later by another sketch.
If a value has not changed in the EEPROM, it is not overwritten
which would reduce the life span of the EEPROM unnecessarily.
Released using MIT licence.
***/
#include <EEPROM.h>
/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/
int address = 0;
void setup(){ /** EMpty setup **/ }
void loop()
{
/***
need to divide by 4 because analog inputs range from
0 to 1023 and each byte of the EEPROM can only hold a
value from 0 to 255.
***/
int val = analogRead(0) / 4;
/***
Update the particular EEPROM cell.
these values will remain there when the board is
turned off.
***/
EEPROM.update(address, val);
/***
The function EEPROM.update(address, val) is equivalent to the following:
if( EEPROM.read(address) != val ){
EEPROM.write(address, val);
}
***/
/***
Advance to the next address, when at the end restart at the beginning.
Larger AVR processors have larger EEPROM sizes, E.g:
- Arduno Duemilanove: 512b EEPROM storage.
- Arduino Uno: 1kb EEPROM storage.
- Arduino Mega: 4kb EEPROM storage.
Rather than hard-coding the length, you should use the pre-provided length function.
This will make your code portable to all AVR processors.
***/
address = address + 1;
if(address == EEPROM.length())
address = 0;
/***
As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an
EEPROM address is also doable by a bitwise and of the length - 1.
++address &= EEPROM.length() - 1;
***/
delay(100);
}

View File

@ -1,58 +0,0 @@
/*
* EEPROM Write
*
* Stores values read from analog input 0 into the EEPROM.
* These values will stay in the EEPROM when the board is
* turned off and may be retrieved later by another sketch.
*/
#include <EEPROM.h>
/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/
int addr = 0;
void setup(){ /** Empty setup. **/}
void loop()
{
/***
Need to divide by 4 because analog inputs range from
0 to 1023 and each byte of the EEPROM can only hold a
value from 0 to 255.
***/
int val = analogRead(0) / 4;
/***
Write the value to the appropriate byte of the EEPROM.
these values will remain there when the board is
turned off.
***/
EEPROM.write(addr, val);
/***
Advance to the next address, when at the end restart at the beginning.
Larger AVR processors have larger EEPROM sizes, E.g:
- Arduno Duemilanove: 512b EEPROM storage.
- Arduino Uno: 1kb EEPROM storage.
- Arduino Mega: 4kb EEPROM storage.
Rather than hard-coding the length, you should use the pre-provided length function.
This will make your code portable to all AVR processors.
***/
addr = addr + 1;
if(addr == EEPROM.length())
addr = 0;
/***
As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an
EEPROM address is also doable by a bitwise and of the length - 1.
++addr &= EEPROM.length() - 1;
***/
delay(100);
}

View File

@ -1,9 +0,0 @@
name=EEPROM
version=2.0
author=Arduino, Christopher Andrews
maintainer=Arduino <info@arduino.cc>
sentence=Enables reading and writing to the permanent board storage. For all Arduino boards BUT Arduino DUE.
paragraph=
url=http://www.arduino.cc/en/Reference/EEPROM
architectures=avr

View File

@ -1,201 +0,0 @@
/*
* Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
* Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
* SPI Master library for arduino.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either the GNU General Public License version 2
* or the GNU Lesser General Public License version 2.1, both as
* published by the Free Software Foundation.
*/
#include "SPI.h"
SPIClass SPI;
uint8_t SPIClass::initialized = 0;
uint8_t SPIClass::interruptMode = 0;
uint8_t SPIClass::interruptMask = 0;
uint8_t SPIClass::interruptSave = 0;
#ifdef SPI_TRANSACTION_MISMATCH_LED
uint8_t SPIClass::inTransactionFlag = 0;
#endif
void SPIClass::begin()
{
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
if (!initialized) {
// Set SS to high so a connected chip will be "deselected" by default
uint8_t port = digitalPinToPort(SS);
uint8_t bit = digitalPinToBitMask(SS);
volatile uint8_t *reg = portModeRegister(port);
// if the SS pin is not already configured as an output
// then set it high (to enable the internal pull-up resistor)
if(!(*reg & bit)){
digitalWrite(SS, HIGH);
}
// When the SS pin is set as OUTPUT, it can be used as
// a general purpose output port (it doesn't influence
// SPI operations).
pinMode(SS, OUTPUT);
// Warning: if the SS pin ever becomes a LOW INPUT then SPI
// automatically switches to Slave, so the data direction of
// the SS pin MUST be kept as OUTPUT.
SPCR |= _BV(MSTR);
SPCR |= _BV(SPE);
// Set direction register for SCK and MOSI pin.
// MISO pin automatically overrides to INPUT.
// By doing this AFTER enabling SPI, we avoid accidentally
// clocking in a single bit since the lines go directly
// from "input" to SPI control.
// http://code.google.com/p/arduino/issues/detail?id=888
pinMode(SCK, OUTPUT);
pinMode(MOSI, OUTPUT);
}
initialized++; // reference count
SREG = sreg;
}
void SPIClass::end() {
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
// Decrease the reference counter
if (initialized)
initialized--;
// If there are no more references disable SPI
if (!initialized) {
SPCR &= ~_BV(SPE);
interruptMode = 0;
#ifdef SPI_TRANSACTION_MISMATCH_LED
inTransactionFlag = 0;
#endif
}
SREG = sreg;
}
// mapping of interrupt numbers to bits within SPI_AVR_EIMSK
#if defined(__AVR_ATmega32U4__)
#define SPI_INT0_MASK (1<<INT0)
#define SPI_INT1_MASK (1<<INT1)
#define SPI_INT2_MASK (1<<INT2)
#define SPI_INT3_MASK (1<<INT3)
#define SPI_INT4_MASK (1<<INT6)
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define SPI_INT0_MASK (1<<INT0)
#define SPI_INT1_MASK (1<<INT1)
#define SPI_INT2_MASK (1<<INT2)
#define SPI_INT3_MASK (1<<INT3)
#define SPI_INT4_MASK (1<<INT4)
#define SPI_INT5_MASK (1<<INT5)
#define SPI_INT6_MASK (1<<INT6)
#define SPI_INT7_MASK (1<<INT7)
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
#define SPI_INT0_MASK (1<<INT4)
#define SPI_INT1_MASK (1<<INT5)
#define SPI_INT2_MASK (1<<INT0)
#define SPI_INT3_MASK (1<<INT1)
#define SPI_INT4_MASK (1<<INT2)
#define SPI_INT5_MASK (1<<INT3)
#define SPI_INT6_MASK (1<<INT6)
#define SPI_INT7_MASK (1<<INT7)
#else
#ifdef INT0
#define SPI_INT0_MASK (1<<INT0)
#endif
#ifdef INT1
#define SPI_INT1_MASK (1<<INT1)
#endif
#ifdef INT2
#define SPI_INT2_MASK (1<<INT2)
#endif
#endif
void SPIClass::usingInterrupt(uint8_t interruptNumber)
{
uint8_t mask = 0;
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
switch (interruptNumber) {
#ifdef SPI_INT0_MASK
case 0: mask = SPI_INT0_MASK; break;
#endif
#ifdef SPI_INT1_MASK
case 1: mask = SPI_INT1_MASK; break;
#endif
#ifdef SPI_INT2_MASK
case 2: mask = SPI_INT2_MASK; break;
#endif
#ifdef SPI_INT3_MASK
case 3: mask = SPI_INT3_MASK; break;
#endif
#ifdef SPI_INT4_MASK
case 4: mask = SPI_INT4_MASK; break;
#endif
#ifdef SPI_INT5_MASK
case 5: mask = SPI_INT5_MASK; break;
#endif
#ifdef SPI_INT6_MASK
case 6: mask = SPI_INT6_MASK; break;
#endif
#ifdef SPI_INT7_MASK
case 7: mask = SPI_INT7_MASK; break;
#endif
default:
interruptMode = 2;
break;
}
interruptMask |= mask;
if (!interruptMode)
interruptMode = 1;
SREG = sreg;
}
void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
{
// Once in mode 2 we can't go back to 0 without a proper reference count
if (interruptMode == 2)
return;
uint8_t mask = 0;
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
switch (interruptNumber) {
#ifdef SPI_INT0_MASK
case 0: mask = SPI_INT0_MASK; break;
#endif
#ifdef SPI_INT1_MASK
case 1: mask = SPI_INT1_MASK; break;
#endif
#ifdef SPI_INT2_MASK
case 2: mask = SPI_INT2_MASK; break;
#endif
#ifdef SPI_INT3_MASK
case 3: mask = SPI_INT3_MASK; break;
#endif
#ifdef SPI_INT4_MASK
case 4: mask = SPI_INT4_MASK; break;
#endif
#ifdef SPI_INT5_MASK
case 5: mask = SPI_INT5_MASK; break;
#endif
#ifdef SPI_INT6_MASK
case 6: mask = SPI_INT6_MASK; break;
#endif
#ifdef SPI_INT7_MASK
case 7: mask = SPI_INT7_MASK; break;
#endif
default:
break;
// this case can't be reached
}
interruptMask &= ~mask;
if (!interruptMask)
interruptMode = 0;
SREG = sreg;
}

View File

@ -1,324 +0,0 @@
/*
* Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
* Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
* SPI Master library for arduino.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either the GNU General Public License version 2
* or the GNU Lesser General Public License version 2.1, both as
* published by the Free Software Foundation.
*/
#ifndef _SPI_H_INCLUDED
#define _SPI_H_INCLUDED
#include <Arduino.h>
// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(),
// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode)
#define SPI_HAS_TRANSACTION 1
// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method
#define SPI_HAS_NOTUSINGINTERRUPT 1
// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version.
// This way when there is a bug fix you can check this define to alert users
// of your code if it uses better version of this library.
// This also implies everything that SPI_HAS_TRANSACTION as documented above is
// available too.
#define SPI_ATOMIC_VERSION 1
// Uncomment this line to add detection of mismatched begin/end transactions.
// A mismatch occurs if other libraries fail to use SPI.endTransaction() for
// each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn
// on if any mismatch is ever detected.
//#define SPI_TRANSACTION_MISMATCH_LED 5
#ifndef LSBFIRST
#define LSBFIRST 0
#endif
#ifndef MSBFIRST
#define MSBFIRST 1
#endif
#define SPI_CLOCK_DIV4 0x00
#define SPI_CLOCK_DIV16 0x01
#define SPI_CLOCK_DIV64 0x02
#define SPI_CLOCK_DIV128 0x03
#define SPI_CLOCK_DIV2 0x04
#define SPI_CLOCK_DIV8 0x05
#define SPI_CLOCK_DIV32 0x06
#define SPI_MODE0 0x00
#define SPI_MODE1 0x04
#define SPI_MODE2 0x08
#define SPI_MODE3 0x0C
#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
// define SPI_AVR_EIMSK for AVR boards with external interrupt pins
#if defined(EIMSK)
#define SPI_AVR_EIMSK EIMSK
#elif defined(GICR)
#define SPI_AVR_EIMSK GICR
#elif defined(GIMSK)
#define SPI_AVR_EIMSK GIMSK
#endif
class SPISettings {
public:
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
if (__builtin_constant_p(clock)) {
init_AlwaysInline(clock, bitOrder, dataMode);
} else {
init_MightInline(clock, bitOrder, dataMode);
}
}
SPISettings() {
init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
}
private:
void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
init_AlwaysInline(clock, bitOrder, dataMode);
}
void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
__attribute__((__always_inline__)) {
// Clock settings are defined as follows. Note that this shows SPI2X
// inverted, so the bits form increasing numbers. Also note that
// fosc/64 appears twice
// SPR1 SPR0 ~SPI2X Freq
// 0 0 0 fosc/2
// 0 0 1 fosc/4
// 0 1 0 fosc/8
// 0 1 1 fosc/16
// 1 0 0 fosc/32
// 1 0 1 fosc/64
// 1 1 0 fosc/64
// 1 1 1 fosc/128
// We find the fastest clock that is less than or equal to the
// given clock rate. The clock divider that results in clock_setting
// is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the
// slowest (128 == 2 ^^ 7, so clock_div = 6).
uint8_t clockDiv;
// When the clock is known at compiletime, use this if-then-else
// cascade, which the compiler knows how to completely optimize
// away. When clock is not known, use a loop instead, which generates
// shorter code.
if (__builtin_constant_p(clock)) {
if (clock >= F_CPU / 2) {
clockDiv = 0;
} else if (clock >= F_CPU / 4) {
clockDiv = 1;
} else if (clock >= F_CPU / 8) {
clockDiv = 2;
} else if (clock >= F_CPU / 16) {
clockDiv = 3;
} else if (clock >= F_CPU / 32) {
clockDiv = 4;
} else if (clock >= F_CPU / 64) {
clockDiv = 5;
} else {
clockDiv = 6;
}
} else {
uint32_t clockSetting = F_CPU / 2;
clockDiv = 0;
while (clockDiv < 6 && clock < clockSetting) {
clockSetting /= 2;
clockDiv++;
}
}
// Compensate for the duplicate fosc/64
if (clockDiv == 6)
clockDiv = 7;
// Invert the SPI2X bit
clockDiv ^= 0x1;
// Pack into the SPISettings class
spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
(dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK);
spsr = clockDiv & SPI_2XCLOCK_MASK;
}
uint8_t spcr;
uint8_t spsr;
friend class SPIClass;
};
class SPIClass {
public:
// Initialize the SPI library
static void begin();
// If SPI is used from within an interrupt, this function registers
// that interrupt with the SPI library, so beginTransaction() can
// prevent conflicts. The input interruptNumber is the number used
// with attachInterrupt. If SPI is used from a different interrupt
// (eg, a timer), interruptNumber should be 255.
static void usingInterrupt(uint8_t interruptNumber);
// And this does the opposite.
static void notUsingInterrupt(uint8_t interruptNumber);
// Note: the usingInterrupt and notUsingInterrupt functions should
// not to be called from ISR context or inside a transaction.
// For details see:
// https://github.com/arduino/Arduino/pull/2381
// https://github.com/arduino/Arduino/pull/2449
// Before using SPI.transfer() or asserting chip select pins,
// this function is used to gain exclusive access to the SPI bus
// and configure the correct settings.
inline static void beginTransaction(SPISettings settings) {
if (interruptMode > 0) {
uint8_t sreg = SREG;
noInterrupts();
#ifdef SPI_AVR_EIMSK
if (interruptMode == 1) {
interruptSave = SPI_AVR_EIMSK;
SPI_AVR_EIMSK &= ~interruptMask;
SREG = sreg;
} else
#endif
{
interruptSave = sreg;
}
}
#ifdef SPI_TRANSACTION_MISMATCH_LED
if (inTransactionFlag) {
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
}
inTransactionFlag = 1;
#endif
SPCR = settings.spcr;
SPSR = settings.spsr;
}
// Write to the SPI bus (MOSI pin) and also receive (MISO pin)
inline static uint8_t transfer(uint8_t data) {
SPDR = data;
/*
* The following NOP introduces a small delay that can prevent the wait
* loop form iterating when running at the maximum speed. This gives
* about 10% more speed, even if it seems counter-intuitive. At lower
* speeds it is unnoticed.
*/
asm volatile("nop");
while (!(SPSR & _BV(SPIF))) ; // wait
return SPDR;
}
inline static uint16_t transfer16(uint16_t data) {
union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out;
in.val = data;
if (!(SPCR & _BV(DORD))) {
SPDR = in.msb;
asm volatile("nop"); // See transfer(uint8_t) function
while (!(SPSR & _BV(SPIF))) ;
out.msb = SPDR;
SPDR = in.lsb;
asm volatile("nop");
while (!(SPSR & _BV(SPIF))) ;
out.lsb = SPDR;
} else {
SPDR = in.lsb;
asm volatile("nop");
while (!(SPSR & _BV(SPIF))) ;
out.lsb = SPDR;
SPDR = in.msb;
asm volatile("nop");
while (!(SPSR & _BV(SPIF))) ;
out.msb = SPDR;
}
return out.val;
}
inline static void transfer(void *buf, size_t count) {
if (count == 0) return;
uint8_t *p = (uint8_t *)buf;
SPDR = *p;
while (--count > 0) {
uint8_t out = *(p + 1);
while (!(SPSR & _BV(SPIF))) ;
uint8_t in = SPDR;
SPDR = out;
*p++ = in;
}
while (!(SPSR & _BV(SPIF))) ;
*p = SPDR;
}
// After performing a group of transfers and releasing the chip select
// signal, this function allows others to access the SPI bus
inline static void endTransaction(void) {
#ifdef SPI_TRANSACTION_MISMATCH_LED
if (!inTransactionFlag) {
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
}
inTransactionFlag = 0;
#endif
if (interruptMode > 0) {
#ifdef SPI_AVR_EIMSK
uint8_t sreg = SREG;
#endif
noInterrupts();
#ifdef SPI_AVR_EIMSK
if (interruptMode == 1) {
SPI_AVR_EIMSK = interruptSave;
SREG = sreg;
} else
#endif
{
SREG = interruptSave;
}
}
}
// Disable the SPI bus
static void end();
// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
inline static void setBitOrder(uint8_t bitOrder) {
if (bitOrder == LSBFIRST) SPCR |= _BV(DORD);
else SPCR &= ~(_BV(DORD));
}
// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
inline static void setDataMode(uint8_t dataMode) {
SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
}
// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
inline static void setClockDivider(uint8_t clockDiv) {
SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK);
SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK);
}
// These undocumented functions should not be used. SPI.transfer()
// polls the hardware flag which is automatically cleared as the
// AVR responds to SPI's interrupt
inline static void attachInterrupt() { SPCR |= _BV(SPIE); }
inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); }
private:
static uint8_t initialized;
static uint8_t interruptMode; // 0=none, 1=mask, 2=global
static uint8_t interruptMask; // which interrupts to mask
static uint8_t interruptSave; // temp storage, to restore state
#ifdef SPI_TRANSACTION_MISMATCH_LED
static uint8_t inTransactionFlag;
#endif
};
extern SPIClass SPI;
#endif

View File

@ -1,10 +0,0 @@
name=SPI
version=1.0
author=Arduino
maintainer=Arduino <info@arduino.cc>
sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. For all Arduino boards, BUT Arduino DUE.
paragraph=
category=Communication
url=http://www.arduino.cc/en/Reference/SPI
architectures=avr

View File

@ -1,8 +0,0 @@
TinyWireM
=========
ATtiny (e.g. Adafruit Trinket, Gemma) I2C library, adapted from BroHogan's code on Arduino Playground: http://playground.arduino.cc/Code/USIi2c
Minor changes for consistency with the Arduino 1.0 Wire library (e.g. uses write() instead of send()). Buffer size slightly increased for Adafruit_LEDBackpack use.
On the Trinket boards, pin #0 is SDA (I2C data), pin #2 is SCK (I2C clock).

View File

@ -1,9 +0,0 @@
name=TinyWireM
version=1.0.0
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=I2C library for Trinket and Gemma, adapted from BroHogan's code on Arduino Playground
paragraph=I2C library for Trinket and Gemma, adapted from BroHogan's code on Arduino Playground
category=Signal Input/Output
url=https://github.com/adafruit/TinyWireM
architectures=*

View File

@ -1,5 +0,0 @@
micronucleusprog.name=Micronucleus
micronucleusprog.communication=usb
micronucleusprog.protocol=micronucleus
micronucleusprog.program.tool={runtime.tools.micronucleus.path}/micronucleus
micronucleusprog.program.extra_params=-Pusb

View File

@ -1 +0,0 @@
//This file allows the DigiXBetaBonus sketches to appear in the File > Examples menu and fixes the Invalid library warning in Arduino IDE 1.6.6+

View File

@ -1,203 +0,0 @@
/*
EEPROM.h - EEPROM library for the Digistump DigiX
This is mostly the merger of the stock Arduino EEPROM library, original
Copyright (c) 2006 David A. Mellis/Christopher Andrews 2015 (LGPL 2.1) with a
few functions from Dennis Schweer (Inglorious Engineer)'s Extensive TWI/I2C
EEPROM Library for 24LCxxx devices v0.4.1 (CC-BY-SA), as distributed with the
DigiX core.
Merging work by SukkoPera <software@sukkology.net>, 2016.
The basic idea is to create a library that is interface-compatible with
Arduino's stock library that is used on non-Due boards, to achieve
compatibility at source level, so that the usual EEPROM.write()/read()/get()
/put() calls can be used.
I'm not really sure of what license the resulting code should be released
under, so I'm leaving the LGPL 2.1, as most of the code here actually came
under that license, and the rest is pretty basic stuff, but let me know if I
should change that.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef EEPROM_h
#define EEPROM_h
#include <inttypes.h>
#include <Wire.h>
static const int DIGIX_EEPROM_ADDR = 0x50;
static const int E2END = 0xFFF;
/***
EERef class.
This object references an EEPROM cell.
Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM.
This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell.
***/
struct EERef{
private:
void extEEPROMwrite(int EEPROM_addr, int addr, byte data)
{
Wire.beginTransmission(EEPROM_addr); //Start transmission to EEPROM
Wire.write(highByte(addr)); // send high byte of address
Wire.write(lowByte(addr)); // send low byte of address
Wire.write((byte) data); // send data
Wire.endTransmission(true); // stop transmitting
delay(6); // wait for a successful write
}
byte extEEPROMread(int EEPROM_addr, int addr) const
{
Wire.beginTransmission(EEPROM_addr); //Start transmission to EEPROM
Wire.write(highByte(addr)); // send high byte of address
Wire.write(lowByte(addr)); // send low byte of address
Wire.endTransmission(true); // stop transmitting
Wire.requestFrom(EEPROM_addr, 0x01, true); // request 1 byte form the device attached to EEPROM_addr
byte data_out = 64;
// read that byte
while(Wire.available() == 0) {} // wait for data
data_out = Wire.read(); //read single byte
return data_out;
}
public:
EERef( const int index )
: index( index ) {}
//Access/read members.
uint8_t operator*() const { return extEEPROMread( DIGIX_EEPROM_ADDR, index ); }
operator const uint8_t() const { return **this; }
//Assignment/write members.
EERef &operator=( const EERef &ref ) { return *this = *ref; }
EERef &operator=( uint8_t in ) { return extEEPROMwrite( DIGIX_EEPROM_ADDR, index, in ), *this; }
EERef &operator +=( uint8_t in ) { return *this = **this + in; }
EERef &operator -=( uint8_t in ) { return *this = **this - in; }
EERef &operator *=( uint8_t in ) { return *this = **this * in; }
EERef &operator /=( uint8_t in ) { return *this = **this / in; }
EERef &operator ^=( uint8_t in ) { return *this = **this ^ in; }
EERef &operator %=( uint8_t in ) { return *this = **this % in; }
EERef &operator &=( uint8_t in ) { return *this = **this & in; }
EERef &operator |=( uint8_t in ) { return *this = **this | in; }
EERef &operator <<=( uint8_t in ) { return *this = **this << in; }
EERef &operator >>=( uint8_t in ) { return *this = **this >> in; }
EERef &update( uint8_t in ) { return in != *this ? *this = in : *this; }
/** Prefix increment/decrement **/
EERef& operator++() { return *this += 1; }
EERef& operator--() { return *this -= 1; }
/** Postfix increment/decrement **/
uint8_t operator++ (int){
uint8_t ret = **this;
return ++(*this), ret;
}
uint8_t operator-- (int){
uint8_t ret = **this;
return --(*this), ret;
}
int index; //Index of current EEPROM cell.
};
/***
EEPtr class.
This object is a bidirectional pointer to EEPROM cells represented by EERef objects.
Just like a normal pointer type, this can be dereferenced and repositioned using
increment/decrement operators.
***/
struct EEPtr{
EEPtr( const int index )
: index( index ) {}
operator const int() const { return index; }
EEPtr &operator=( int in ) { return index = in, *this; }
//Iterator functionality.
bool operator!=( const EEPtr &ptr ) { return index != ptr.index; }
EERef operator*() { return index; }
/** Prefix & Postfix increment/decrement **/
EEPtr& operator++() { return ++index, *this; }
EEPtr& operator--() { return --index, *this; }
EEPtr operator++ (int) { return index++; }
EEPtr operator-- (int) { return index--; }
int index; //Index of current EEPROM cell.
};
/***
EEPROMClass class.
This object represents the entire EEPROM space.
It wraps the functionality of EEPtr and EERef into a basic interface.
This class is also 100% backwards compatible with earlier Arduino core releases.
***/
struct EEPROMClass{
boolean inited;
// c'tor
EEPROMClass () { inited = false; }
// Check if the i2c library was initialized, and do it if not.
// FIXME: What happens if the sketch has already called Wire.begin() on its
// own?
void checkInited () { if (!inited) { Wire.begin(); inited = true; } }
//Basic user access methods.
EERef operator[]( const int idx ) { return idx; }
uint8_t read( int idx ) { checkInited (); return EERef( idx ); }
void write( int idx, uint8_t val ) { checkInited (); (EERef( idx )) = val; }
void update( int idx, uint8_t val ) { checkInited (); EERef( idx ).update( val ); }
//STL and C++11 iteration capability.
EEPtr begin() { return 0x00; }
EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid.
uint16_t length() { return E2END + 1; }
//Functionality to 'get' and 'put' objects to and from EEPROM.
template< typename T > T &get( int idx, T &t ){
checkInited ();
EEPtr e = idx;
uint8_t *ptr = (uint8_t*) &t;
for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e;
return t;
}
template< typename T > const T &put( int idx, const T &t ){
checkInited ();
EEPtr e = idx;
const uint8_t *ptr = (const uint8_t*) &t;
for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ );
return t;
}
};
static EEPROMClass EEPROM;
#endif

View File

@ -62,46 +62,4 @@ digispark-pro64.build.core=pro
digispark-pro64.build.variant=pro64buffer
digispark-pro64.upload.wait_for_upload_port = false
digispark-pro64.upload.use_1200bps_touch = false
digispark-pro64.upload.disable_flushing = false
digispark-tiny16.name=Digispark (16mhz - No USB)
digispark-tiny16.upload.using=micronucleusprog
digispark-tiny16.upload.protocol=usb
digispark-tiny16.upload.tool=micronucleus
digispark-tiny16.upload.maximum_size=6012
digispark-tiny16.build.mcu=attiny85
digispark-tiny16.build.f_cpu=16000000L
digispark-tiny16.build.board=AVR_DIGISPARK
digispark-tiny16.build.core=tiny
digispark-tiny16.build.variant=digispark
digispark-tiny16.upload.wait_for_upload_port = false
digispark-tiny16.upload.use_1200bps_touch = false
digispark-tiny16.upload.disable_flushing = false
digispark-tiny8.name=Digispark (8mhz - No USB)
digispark-tiny8.upload.using=micronucleusprog
digispark-tiny8.upload.protocol=usb
digispark-tiny8.upload.tool=micronucleus
digispark-tiny8.upload.maximum_size=6012
digispark-tiny8.build.mcu=attiny85
digispark-tiny8.build.f_cpu=8000000L
digispark-tiny8.build.board=AVR_DIGISPARK
digispark-tiny8.build.core=tiny
digispark-tiny8.build.variant=digispark
digispark-tiny8.upload.wait_for_upload_port = false
digispark-tiny8.upload.use_1200bps_touch = false
digispark-tiny8.upload.disable_flushing = false
digispark-tiny1.name=Digispark (1mhz - No USB)
digispark-tiny1.upload.using=micronucleusprog
digispark-tiny1.upload.protocol=usb
digispark-tiny1.upload.tool=micronucleus
digispark-tiny1.upload.maximum_size=6012
digispark-tiny1.build.mcu=attiny85
digispark-tiny1.build.f_cpu=1000000L
digispark-tiny1.build.board=AVR_DIGISPARK
digispark-tiny1.build.core=tiny
digispark-tiny1.build.variant=digispark
digispark-tiny1.upload.wait_for_upload_port = false
digispark-tiny1.upload.use_1200bps_touch = false
digispark-tiny1.upload.disable_flushing = false
digispark-pro64.upload.disable_flushing = false

View File

@ -103,11 +103,6 @@ int digitalRead(uint8_t);
int analogRead(uint8_t);
void analogReference(uint8_t mode);
void analogWrite(uint8_t, int);
void pwmWrite(uint8_t, int);
void pwmConnect(uint8_t);
void pwmDisconnect(uint8_t);
void pwmReset(void);
unsigned long millis(void);
unsigned long micros(void);
@ -165,9 +160,6 @@ extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
#define TIMER1B 4
#define TIMER1D 5
#define CHANNELA 3 //TIMER1A
#define CHANNELB 4 //TIMER1B
#include "pins_arduino.h"
#ifndef USE_SOFTWARE_SERIAL

Some files were not shown because too many files have changed in this diff Show More