Added some more projects and libraries.
This commit is contained in:
parent
f7151392ab
commit
1e1459fa50
94 changed files with 11904 additions and 0 deletions
14
AnalogInOutSerial/AnalogInOutSerial.ino
Normal file
14
AnalogInOutSerial/AnalogInOutSerial.ino
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
const int analogIn = A0;
|
||||
|
||||
int sensorValue = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
sensorValue = analogRead(analogIn);
|
||||
Serial.print("Sensor: ");
|
||||
Serial.println(sensorValue);
|
||||
delay(2000);
|
||||
}
|
||||
28
BMP180_SERIAL/BMP180_SERIAL.ino
Normal file
28
BMP180_SERIAL/BMP180_SERIAL.ino
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_BMP085_U.h>
|
||||
|
||||
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085);
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
Serial.println("Arduino BMP180 Pressure Sensor");
|
||||
Serial.println("");
|
||||
bmp.begin();
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
sensors_event_t event;
|
||||
bmp.getEvent(&event);
|
||||
if (event.pressure)
|
||||
{
|
||||
Serial.print("Pressure: ");
|
||||
Serial.print(event.pressure);
|
||||
Serial.println(" hPa");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Sensor error");
|
||||
}
|
||||
delay(1000);
|
||||
}
|
||||
116
DCF77alarmInterrupt/DCF77alarmInterrupt.ino
Normal file
116
DCF77alarmInterrupt/DCF77alarmInterrupt.ino
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/******************************************************************************
|
||||
Beispiel: alarmInterrupt
|
||||
|
||||
Beschreibung: Dieses Beispiel zeigt die Verwendung des Alarms innerhalb des
|
||||
RTC-DCF.
|
||||
|
||||
Hinweis: Zur Einstellung des Kommunikationswegs (UART, SPI oder I2C) zum
|
||||
RTC-DCF enthält die Library die Datei RTC_DCF_config.h im
|
||||
Unterordner \libraries\RTC_DCF\config\. Innerhalb dieser Datei
|
||||
kann der Kommunikationsweg umgestellt werden.
|
||||
|
||||
Bei Verwendung der UART-Schnittstelle wird ein Objekt der Klasse
|
||||
modSoftSerial angelegt. Diese Klasse entspricht einer
|
||||
modifizierten SoftSerial-Klasse. Innerhalb der modifizierten
|
||||
Klasse wird nur der PinChange-Interrupt für den Port D (PCINT2_vect)
|
||||
angelegt, anstatt alle PinChange-Interrupts anzulegen. Ohne diese
|
||||
Modifizierung wäre eine Verwendung von SoftSerial und PinChangeInt
|
||||
nicht parallel möglich.
|
||||
|
||||
Die modifizierte SoftSerial-Klasse ist Teil der RTC-DCF-Library.
|
||||
|
||||
Die PinChangeInt-Klasse ist nicht Teil der RTC-DCF-Library, kann
|
||||
aber auf folgender Internetseite heruntergeladen werden:
|
||||
http://arduino.cc/playground/Main/PinChangeInt
|
||||
******************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include "DateTime.h"
|
||||
#include "RealTimeClock_DCF.h"
|
||||
|
||||
/* leider setzt die Arduino-IDE voraus, dass alle in einem Projekt verwendeten
|
||||
Klassen auch ins Sketch übernommen werden. Wird dieses nicht berücksichtigt,
|
||||
kommt es zu Fehlern beim Linken des Programms. Daher muss an dieser Stelle
|
||||
die Headerdatei zu der jeweils verwendeten Kommunikationsklasse eingefügt
|
||||
werden. Die beiden jeweils nicht verwendeten Header müssen auskommentiert
|
||||
werden. */
|
||||
|
||||
/* für die Kommunikation über UART die modSoftwareSerial.h verwenden */
|
||||
//#include "modSoftwareSerial.h"
|
||||
|
||||
/* für die Kommunikation über SPI die SPI.h verwenden */
|
||||
//#include "SPI.h"
|
||||
|
||||
/* für die Kommunikation über Wire die Wire.h verwenden */
|
||||
#include "Wire.h"
|
||||
|
||||
/******************************************************************************
|
||||
Definitionen
|
||||
******************************************************************************/
|
||||
/* für die Kommunikation über UART wird ein Objekt der Klasse modSoftwareSerial
|
||||
benötigt. Da diese Klasse den Pin Change Interrupt am Port D blockiert, muss
|
||||
dieser für die Klasse PinChangeInt deaktiviert werden. */
|
||||
#if RTC_DCF_COMMUNICATION == 0x00
|
||||
#define NO_PORTD_PINCHANGES
|
||||
#endif
|
||||
|
||||
#include "PinChangeInt.h"
|
||||
|
||||
/******************************************************************************
|
||||
globale Variablen
|
||||
******************************************************************************/
|
||||
/* einzustellende Uhrzeit */
|
||||
DateTime dateTime = DateTime(0, 1, 1, DateTime::SATURDAY, 0, 59, 55);
|
||||
|
||||
/* Flag zur Anzeige eines Alarms */
|
||||
volatile uint8_t alarmFlag = 0;
|
||||
|
||||
/******************************************************************************
|
||||
Funktionen
|
||||
******************************************************************************/
|
||||
void setup()
|
||||
{
|
||||
/* der RTC-DCF benötigt ca. 1,5 Sekunden bis er Daten empfangen kann */
|
||||
delay(1500);
|
||||
|
||||
/* den Pin für den Alarm-Interrupt als Eingang und als externe
|
||||
Interrupt-Quelle definieren */
|
||||
pinMode(RTC_DCF_ALARM_INT_PIN, INPUT);
|
||||
PCintPort::attachInterrupt(RTC_DCF_ALARM_INT_PIN, &alarmInterrupt, FALLING);
|
||||
|
||||
/* RTC-DCF initialisieren */
|
||||
RTC_DCF.begin();
|
||||
|
||||
/* Uhrzeit im RTC-DCF setzen */
|
||||
RTC_DCF.setDateTime(&dateTime);
|
||||
|
||||
/* den Alarm auf 1:00 Uhr (5 Sekunden nach der eingestellten Uhrzeit) setzen */
|
||||
RTC_DCF.setAlarmTime(RTC_ALARM_WEEKDAYS_ALL, 1, 0);
|
||||
|
||||
/* den Alarm-Interrupt des RTC-DCF aktivieren */
|
||||
RTC_DCF.enableAlarmInterrupt();
|
||||
|
||||
/* die serielle Ausgabe initialisieren */
|
||||
Serial.begin(115200);
|
||||
|
||||
/* Interrupts einschalten */
|
||||
interrupts();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
/* "ALARM" über die serielle Schnittstelle ausgeben und den Alarm-Interrupt
|
||||
des RTC-DCF zurücksetzen, wenn das Alarm-Flag gesetzt wird */
|
||||
if(alarmFlag == 1)
|
||||
{
|
||||
Serial.println("ALARM");
|
||||
|
||||
RTC_DCF.resetAlarmInterrupt();
|
||||
|
||||
alarmFlag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void alarmInterrupt(void)
|
||||
{
|
||||
alarmFlag = 1;
|
||||
}
|
||||
60
DCF77dcf77Interrupt/DCF77dcf77Interrupt.ino
Normal file
60
DCF77dcf77Interrupt/DCF77dcf77Interrupt.ino
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#include <stdio.h>
|
||||
#include "DateTime.h"
|
||||
#include "RealTimeClock_DCF.h"
|
||||
#include "Wire.h"
|
||||
#include "PinChangeInt.h"
|
||||
|
||||
DateTime readDateTime;
|
||||
volatile uint8_t perInterruptFlag = 0;
|
||||
volatile uint8_t dcf77InterruptFlag = 0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
|
||||
delay(1500);
|
||||
pinMode(RTC_DCF_PER_INT_PIN, INPUT);
|
||||
PCintPort::attachInterrupt(RTC_DCF_PER_INT_PIN, &periodicInterrupt, FALLING);
|
||||
pinMode(RTC_DCF_DCF77_INT_PIN, INPUT);
|
||||
PCintPort::attachInterrupt(RTC_DCF_DCF77_INT_PIN, &dcf77Interrupt, FALLING);
|
||||
RTC_DCF.begin();
|
||||
RTC_DCF.enableDCF77Reception();
|
||||
RTC_DCF.enableDCF77Interrupt();
|
||||
RTC_DCF.setPeriodicInterruptMode(RTC_PERIODIC_INT_PULSE_1_HZ);
|
||||
RTC_DCF.enablePeriodicInterrupt();
|
||||
Serial.begin(115200);
|
||||
interrupts();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if(perInterruptFlag == 1)
|
||||
{
|
||||
RTC_DCF.getDateTime(&readDateTime);
|
||||
printClock();
|
||||
perInterruptFlag = 0;
|
||||
}
|
||||
|
||||
if(dcf77InterruptFlag == 1)
|
||||
{
|
||||
Serial.println("DCF77 empfangen");
|
||||
RTC_DCF.resetDCF77Interrupt();
|
||||
dcf77InterruptFlag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void periodicInterrupt(void)
|
||||
{
|
||||
perInterruptFlag = 1;
|
||||
}
|
||||
|
||||
void dcf77Interrupt(void)
|
||||
{
|
||||
dcf77InterruptFlag = 1;
|
||||
}
|
||||
|
||||
void printClock(void)
|
||||
{
|
||||
char clockString[30];
|
||||
sprintf(clockString, "Es ist %02u:%02u:%02u am %02u.%02u.%02u", readDateTime.getHour(), readDateTime.getMinute(), readDateTime.getSecond(), readDateTime.getDay(), readDateTime.getMonth(), readDateTime.getYear());
|
||||
Serial.println(clockString);
|
||||
}
|
||||
27
DCF77setTime/DCF77setTime.ino
Normal file
27
DCF77setTime/DCF77setTime.ino
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#include <stdio.h>
|
||||
#include "DateTime.h"
|
||||
#include "RealTimeClock_DCF.h"
|
||||
#include "Wire.h"
|
||||
|
||||
DateTime dateTime;
|
||||
|
||||
void setup() {
|
||||
delay(1500);
|
||||
RTC_DCF.begin();
|
||||
RTC_DCF.enableDCF77Reception();
|
||||
RTC_DCF.getDateTime(&dateTime);
|
||||
Serial.begin(115200);
|
||||
printClock();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
delay(1000);
|
||||
RTC_DCF.getDateTime(&dateTime);
|
||||
printClock();
|
||||
}
|
||||
|
||||
void printClock(void) {
|
||||
char clockString[30];
|
||||
sprintf(clockString, "Es ist %02u:%02u:%02u am %02u.%02u.%02u", dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getDay(), dateTime.getMonth(), dateTime.getYear());
|
||||
Serial.println(clockString);
|
||||
}
|
||||
17
Digispark_Blink/Digispark_Blink.ino
Normal file
17
Digispark_Blink/Digispark_Blink.ino
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
// the setup routine runs once when you press reset:
|
||||
void setup() {
|
||||
// initialize the digital pin as an output.
|
||||
pinMode(0, OUTPUT); //LED on Model B
|
||||
pinMode(1, OUTPUT); //LED on Model A or Pro
|
||||
}
|
||||
|
||||
// the loop routine runs over and over again forever:
|
||||
void loop() {
|
||||
digitalWrite(0, HIGH); // turn the LED on (HIGH is the voltage level)
|
||||
digitalWrite(1, HIGH);
|
||||
delay(100); // wait for a second
|
||||
digitalWrite(0, LOW); // turn the LED off by making the voltage LOW
|
||||
digitalWrite(1, LOW);
|
||||
delay(100); // wait for a second
|
||||
}
|
||||
11
Digispark_HID/Digispark_HID.ino
Normal file
11
Digispark_HID/Digispark_HID.ino
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include "Keyboard.h"
|
||||
|
||||
void setup() {
|
||||
//initialize keyboard
|
||||
Keyboard.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Keyboard.print("Hello World!"); //print "Hello World!"
|
||||
delay(3000); //wait 3 seconds
|
||||
}
|
||||
12
Digispark_Keyboard/Digispark_Keyboard.ino
Normal file
12
Digispark_Keyboard/Digispark_Keyboard.ino
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#include "DigiKeyboard.h"
|
||||
|
||||
void setup() {
|
||||
pinMode(0, OUTPUT);
|
||||
DigiKeyboard.delay(2000);
|
||||
DigiKeyboard.sendKeyStroke(0);
|
||||
DigiKeyboard.println("test");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
DigiKeyboard.delay(500000);
|
||||
}
|
||||
18
Digispark_Passkey/Digispark_Passkey.ino
Normal file
18
Digispark_Passkey/Digispark_Passkey.ino
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#include "DigiKeyboard.h"
|
||||
#include <ezButton.h>
|
||||
|
||||
void setup() {
|
||||
pinMode(0, INPUT);
|
||||
pinMode(1, OUTPUT);
|
||||
DigiKeyboard.delay(3000);
|
||||
DigiKeyboard.sendKeyStroke(0);
|
||||
DigiKeyboard.println("qMpI7Af06Z4XnMDhzXROnEgtuxPsCPLiBJT90Rb1F2BZKCmIhpLOdxtBpurUa9Tg");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
digitalWrite(1, HIGH);
|
||||
delay(25);
|
||||
digitalWrite(1, LOW);
|
||||
delay(10000);
|
||||
//DigiKeyboard.delay(500000);
|
||||
}
|
||||
99
ESP8266ArduinoSerial/ESP8266ArduinoSerial.ino
Normal file
99
ESP8266ArduinoSerial/ESP8266ArduinoSerial.ino
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
#include <SoftwareSerial.h>
|
||||
#define SSID "xxxxxxxx"
|
||||
#define PASS "xxxxxxxx"
|
||||
#define DST_IP "220.181.111.85" //baidu.com
|
||||
SoftwareSerial dbgSerial(10, 11); // RX, TX
|
||||
void setup()
|
||||
{
|
||||
// Open serial communications and wait for port to open:
|
||||
Serial.begin(57600);
|
||||
Serial.setTimeout(5000);
|
||||
dbgSerial.begin(9600); //can't be faster than 19200 for softserial
|
||||
dbgSerial.println("ESP8266 Demo");
|
||||
//test if the module is ready
|
||||
Serial.println("AT+RST");
|
||||
delay(1000);
|
||||
if(Serial.find("ready"))
|
||||
{
|
||||
dbgSerial.println("Module is ready");
|
||||
}
|
||||
else
|
||||
{
|
||||
dbgSerial.println("Module have no response.");
|
||||
while(1);
|
||||
}
|
||||
delay(1000);
|
||||
//connect to the wifi
|
||||
boolean connected=false;
|
||||
for(int i=0;i<5;i++)
|
||||
{
|
||||
if(connectWiFi())
|
||||
{
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!connected){while(1);}
|
||||
delay(5000);
|
||||
//print the ip addr
|
||||
/*Serial.println("AT+CIFSR");
|
||||
dbgSerial.println("ip address:");
|
||||
while (Serial.available())
|
||||
dbgSerial.write(Serial.read());*/
|
||||
//set the single connection mode
|
||||
Serial.println("AT+CIPMUX=0");
|
||||
}
|
||||
void loop()
|
||||
{
|
||||
String cmd = "AT+CIPSTART=\"TCP\",\"";
|
||||
cmd += DST_IP;
|
||||
cmd += "\",80";
|
||||
Serial.println(cmd);
|
||||
dbgSerial.println(cmd);
|
||||
if(Serial.find("Error")) return;
|
||||
cmd = "GET / HTTP/1.0\r\n\r\n";
|
||||
Serial.print("AT+CIPSEND=");
|
||||
Serial.println(cmd.length());
|
||||
if(Serial.find(">"))
|
||||
{
|
||||
dbgSerial.print(">");
|
||||
}else
|
||||
{
|
||||
Serial.println("AT+CIPCLOSE");
|
||||
dbgSerial.println("connect timeout");
|
||||
delay(1000);
|
||||
return;
|
||||
}
|
||||
Serial.print(cmd);
|
||||
delay(2000);
|
||||
//Serial.find("+IPD");
|
||||
while (Serial.available())
|
||||
{
|
||||
char c = Serial.read();
|
||||
dbgSerial.write(c);
|
||||
if(c=='\r') dbgSerial.print('\n');
|
||||
}
|
||||
dbgSerial.println("====");
|
||||
delay(1000);
|
||||
}
|
||||
boolean connectWiFi()
|
||||
{
|
||||
Serial.println("AT+CWMODE=1");
|
||||
String cmd="AT+CWJAP=\"";
|
||||
cmd+=SSID;
|
||||
cmd+="\",\"";
|
||||
cmd+=PASS;
|
||||
cmd+="\"";
|
||||
dbgSerial.println(cmd);
|
||||
Serial.println(cmd);
|
||||
delay(2000);
|
||||
if(Serial.find("OK"))
|
||||
{
|
||||
dbgSerial.println("OK, Connected to WiFi.");
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
dbgSerial.println("Can not connect to the WiFi.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
73
ESP8266HelloServer/ESP8266HelloServer.ino
Normal file
73
ESP8266HelloServer/ESP8266HelloServer.ino
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#include <ESP8266WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
|
||||
const char* ssid = "Cyberdyne Systems Skynet";
|
||||
const char* password = "HalloDUDoofeW";
|
||||
MDNSResponder mdns;
|
||||
|
||||
ESP8266WebServer server(80);
|
||||
|
||||
const int led = 13;
|
||||
|
||||
void handleRoot() {
|
||||
digitalWrite(led, 1);
|
||||
server.send(200, "text/plain", "hello from esp8266!");
|
||||
digitalWrite(led, 0);
|
||||
}
|
||||
|
||||
void handleNotFound(){
|
||||
digitalWrite(led, 1);
|
||||
String message = "File Not Found\n\n";
|
||||
message += "URI: ";
|
||||
message += server.uri();
|
||||
message += "\nMethod: ";
|
||||
message += (server.method() == HTTP_GET)?"GET":"POST";
|
||||
message += "\nArguments: ";
|
||||
message += server.args();
|
||||
message += "\n";
|
||||
for (uint8_t i=0; i<server.args(); i++){
|
||||
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
|
||||
}
|
||||
server.send(404, "text/plain", message);
|
||||
digitalWrite(led, 0);
|
||||
}
|
||||
|
||||
void setup(void){
|
||||
pinMode(led, OUTPUT);
|
||||
digitalWrite(led, 0);
|
||||
Serial.begin(115200);
|
||||
WiFi.begin(ssid, password);
|
||||
Serial.println("");
|
||||
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println("");
|
||||
Serial.print("Connected to ");
|
||||
Serial.println(ssid);
|
||||
Serial.print("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
if (mdns.begin("esp8266", WiFi.localIP())) {
|
||||
Serial.println("MDNS responder started");
|
||||
}
|
||||
|
||||
server.on("/", handleRoot);
|
||||
|
||||
server.on("/inline", [](){
|
||||
server.send(200, "text/plain", "this works as well");
|
||||
});
|
||||
|
||||
server.onNotFound(handleNotFound);
|
||||
|
||||
server.begin();
|
||||
Serial.println("HTTP server started");
|
||||
}
|
||||
|
||||
void loop(void){
|
||||
server.handleClient();
|
||||
}
|
||||
79
PCF8575_i2c_Arduino/PCF8575_i2c_Arduino.ino
Normal file
79
PCF8575_i2c_Arduino/PCF8575_i2c_Arduino.ino
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#include <Wire.h>
|
||||
|
||||
//fuzzywobble.com 2012
|
||||
//this code turns every PCF8575 pin into an input (without interrupt)
|
||||
//datasheet - http://www.ti.com/general/docs/lit/getliterature.tsp?genericPartNumber=pcf8575&fileType=pdf
|
||||
//i2c code adapted from i2c_dio_pcf8575c.cpp - Arduino class library for TI PCF8575C 16-bit I2C I/O expander
|
||||
|
||||
//address is |0100|A0|A1|A2|
|
||||
int address = 0x20; //0100000 (7bit)
|
||||
uint16_t dataReceive; //16bit data received
|
||||
uint16_t dataSend; //16bit data sent
|
||||
|
||||
void setup(){
|
||||
Wire.begin();
|
||||
Serial.begin(9600);
|
||||
//turn pins to input in setup
|
||||
//if bit = 0, pin functions as input or an output that is off
|
||||
//if bit = 1, pin functions as an output that is on
|
||||
dataSend = word(B01111111,B11111111); //turn every pin to output
|
||||
pcf8575_write(dataSend); //turn the pcf8575 pins to output
|
||||
}
|
||||
|
||||
void loop(){
|
||||
dataSend = word(B01111110,B01110001);
|
||||
pcf8575_write(dataSend); //read the pcf8575 pins
|
||||
delay(100);
|
||||
dataSend = word(B00000000,B00000000);
|
||||
pcf8575_write(dataSend); //read the pcf8575 pins
|
||||
delay(100);
|
||||
}
|
||||
|
||||
|
||||
//custom functions -----------------------------
|
||||
|
||||
//I2C/TWI success (transaction was successful).
|
||||
static const uint8_t ku8TWISuccess = 0;
|
||||
//I2C/TWI device not present (address sent, NACK received).
|
||||
static const uint8_t ku8TWIDeviceNACK = 2;
|
||||
//I2C/TWI data not received (data sent, NACK received).
|
||||
static const uint8_t ku8TWIDataNACK = 3;
|
||||
//I2C/TWI other error.
|
||||
static const uint8_t ku8TWIError = 4;
|
||||
|
||||
uint8_t error;
|
||||
void pcf8575_write(uint16_t dt){
|
||||
Wire.beginTransmission(address);
|
||||
Wire.write(lowByte(dt));
|
||||
Wire.write(highByte(dt));
|
||||
error = Wire.endTransmission();
|
||||
if(error == ku8TWISuccess){ //okay!
|
||||
|
||||
}
|
||||
else{ //we have an error
|
||||
//do something here if you like
|
||||
}
|
||||
}
|
||||
uint8_t hi,lo;
|
||||
uint16_t pcf8575_read(){
|
||||
Wire.beginTransmission(address);
|
||||
error = Wire.endTransmission();
|
||||
if(error == ku8TWISuccess){ //okay!
|
||||
Wire.requestFrom(address,2);
|
||||
if(Wire.available()){
|
||||
lo = Wire.read();
|
||||
hi = Wire.read();
|
||||
return(word(hi,lo)); //joing bytes
|
||||
}
|
||||
else{//error
|
||||
//do something here if you like
|
||||
}
|
||||
}
|
||||
else{ //error
|
||||
//do something here if you like
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
57
PF575_I2C/PF575_I2C.ino
Normal file
57
PF575_I2C/PF575_I2C.ino
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#include <Wire.h>
|
||||
|
||||
/**
|
||||
* Arduino PF575/PCF8575 I2C I/O port exapander LED blink example
|
||||
*
|
||||
* Setup:
|
||||
*
|
||||
* 1. Connect A0, A1 and A2 to GND to set the address to 0x20.
|
||||
* 2. Connect SDL and SCL to the Arduino's I2C bus.
|
||||
* 3. Connect a LED to the P0 port of the I2C exapander.
|
||||
* In my setup I am using a PNP Transistor connected to 5V unsing
|
||||
* an resistor, the LED and the Arduino to make sure the LED gets
|
||||
* a current from Vcc and not from the I2C exapander port.
|
||||
*
|
||||
* This code is trying to explain how it works as simple as possible.
|
||||
* More detailed examples are found on the web. Search for pcf8575 and
|
||||
* you will find what you want.
|
||||
*/
|
||||
|
||||
// Set I2C address
|
||||
int address = 0x20;
|
||||
|
||||
void setup(){
|
||||
Wire.begin();
|
||||
// Set all ports as output
|
||||
//pf575_write(word(B11111111,B11111111));
|
||||
//delay(1000);
|
||||
pf575_write(word(B00000000,B00000000));
|
||||
}
|
||||
|
||||
void loop(){
|
||||
int dTime = 1000;
|
||||
pf575_write(word(B00000001,B00000000));
|
||||
delay(dTime);
|
||||
pf575_write(word(B00000011,B00000000));
|
||||
delay(dTime);
|
||||
pf575_write(word(B00000111,B00000000));
|
||||
delay(dTime);
|
||||
pf575_write(word(B00001111,B00000000));
|
||||
delay(dTime);
|
||||
pf575_write(word(B00001110,B00000000));
|
||||
delay(dTime);
|
||||
pf575_write(word(B00001100,B00000000));
|
||||
delay(dTime);
|
||||
pf575_write(word(B00001000,B00000000));
|
||||
delay(dTime);
|
||||
pf575_write(word(B00000000,B00000000));
|
||||
delay(dTime);
|
||||
}
|
||||
|
||||
// Function for writing two Bytes to the I2C expander device
|
||||
void pf575_write(uint16_t data) {
|
||||
Wire.beginTransmission(address);
|
||||
Wire.write(highByte(data));
|
||||
Wire.write(lowByte(data));
|
||||
Wire.endTransmission();
|
||||
}
|
||||
24
TimedAction/TimedAction.ino
Normal file
24
TimedAction/TimedAction.ino
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#include <TimedAction.h>
|
||||
|
||||
TimedAction timedAction = TimedAction(1000,blink1);
|
||||
|
||||
boolean ledState1 = false;
|
||||
|
||||
|
||||
void setup(){
|
||||
pinMode(13,OUTPUT);
|
||||
digitalWrite(13,ledState1);
|
||||
}
|
||||
|
||||
void loop(){
|
||||
timedAction.check();
|
||||
}
|
||||
|
||||
void blink1(){
|
||||
ledState1 ? ledState1=false : ledState1=true;
|
||||
digitalWrite(13,ledState1);
|
||||
}
|
||||
void blink2(){
|
||||
ledState2 ? ledState2=false : ledState2=true;
|
||||
digitalWrite(12,ledState2);
|
||||
}
|
||||
481
libraries/Adafruit_BMP085_Unified-master/Adafruit_BMP085_U.cpp
Normal file
481
libraries/Adafruit_BMP085_Unified-master/Adafruit_BMP085_U.cpp
Normal file
|
|
@ -0,0 +1,481 @@
|
|||
/***************************************************************************
|
||||
This is a library for the BMP085 pressure sensor
|
||||
|
||||
Designed specifically to work with the Adafruit BMP085 or BMP180 Breakout
|
||||
----> http://www.adafruit.com/products/391
|
||||
----> http://www.adafruit.com/products/1603
|
||||
|
||||
These displays use I2C to communicate, 2 pins are required to interface.
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit andopen-source hardware by purchasing products
|
||||
from Adafruit!
|
||||
|
||||
Written by Kevin Townsend for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
***************************************************************************/
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#ifdef __AVR_ATtiny85__
|
||||
#include "TinyWireM.h"
|
||||
#define Wire TinyWireM
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "Adafruit_BMP085_U.h"
|
||||
|
||||
static bmp085_calib_data _bmp085_coeffs; // Last read accelerometer data will be available here
|
||||
static uint8_t _bmp085Mode;
|
||||
|
||||
#define BMP085_USE_DATASHEET_VALS (0) /* Set to 1 for sanity check */
|
||||
|
||||
/***************************************************************************
|
||||
PRIVATE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Writes an 8 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void writeCommand(byte reg, byte value)
|
||||
{
|
||||
Wire.beginTransmission((uint8_t)BMP085_ADDRESS);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
Wire.write((uint8_t)value);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
Wire.send(value);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads an 8 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void read8(byte reg, uint8_t *value)
|
||||
{
|
||||
Wire.beginTransmission((uint8_t)BMP085_ADDRESS);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)1);
|
||||
#if ARDUINO >= 100
|
||||
*value = Wire.read();
|
||||
#else
|
||||
*value = Wire.receive();
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads a 16 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void read16(byte reg, uint16_t *value)
|
||||
{
|
||||
Wire.beginTransmission((uint8_t)BMP085_ADDRESS);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)2);
|
||||
#if ARDUINO >= 100
|
||||
*value = (Wire.read() << 8) | Wire.read();
|
||||
#else
|
||||
*value = (Wire.receive() << 8) | Wire.receive();
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads a signed 16 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readS16(byte reg, int16_t *value)
|
||||
{
|
||||
uint16_t i;
|
||||
read16(reg, &i);
|
||||
*value = (int16_t)i;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the factory-set coefficients
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readCoefficients(void)
|
||||
{
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
_bmp085_coeffs.ac1 = 408;
|
||||
_bmp085_coeffs.ac2 = -72;
|
||||
_bmp085_coeffs.ac3 = -14383;
|
||||
_bmp085_coeffs.ac4 = 32741;
|
||||
_bmp085_coeffs.ac5 = 32757;
|
||||
_bmp085_coeffs.ac6 = 23153;
|
||||
_bmp085_coeffs.b1 = 6190;
|
||||
_bmp085_coeffs.b2 = 4;
|
||||
_bmp085_coeffs.mb = -32768;
|
||||
_bmp085_coeffs.mc = -8711;
|
||||
_bmp085_coeffs.md = 2868;
|
||||
_bmp085Mode = 0;
|
||||
#else
|
||||
readS16(BMP085_REGISTER_CAL_AC1, &_bmp085_coeffs.ac1);
|
||||
readS16(BMP085_REGISTER_CAL_AC2, &_bmp085_coeffs.ac2);
|
||||
readS16(BMP085_REGISTER_CAL_AC3, &_bmp085_coeffs.ac3);
|
||||
read16(BMP085_REGISTER_CAL_AC4, &_bmp085_coeffs.ac4);
|
||||
read16(BMP085_REGISTER_CAL_AC5, &_bmp085_coeffs.ac5);
|
||||
read16(BMP085_REGISTER_CAL_AC6, &_bmp085_coeffs.ac6);
|
||||
readS16(BMP085_REGISTER_CAL_B1, &_bmp085_coeffs.b1);
|
||||
readS16(BMP085_REGISTER_CAL_B2, &_bmp085_coeffs.b2);
|
||||
readS16(BMP085_REGISTER_CAL_MB, &_bmp085_coeffs.mb);
|
||||
readS16(BMP085_REGISTER_CAL_MC, &_bmp085_coeffs.mc);
|
||||
readS16(BMP085_REGISTER_CAL_MD, &_bmp085_coeffs.md);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readRawTemperature(int32_t *temperature)
|
||||
{
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
*temperature = 27898;
|
||||
#else
|
||||
uint16_t t;
|
||||
writeCommand(BMP085_REGISTER_CONTROL, BMP085_REGISTER_READTEMPCMD);
|
||||
delay(5);
|
||||
read16(BMP085_REGISTER_TEMPDATA, &t);
|
||||
*temperature = t;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readRawPressure(int32_t *pressure)
|
||||
{
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
*pressure = 23843;
|
||||
#else
|
||||
uint8_t p8;
|
||||
uint16_t p16;
|
||||
int32_t p32;
|
||||
|
||||
writeCommand(BMP085_REGISTER_CONTROL, BMP085_REGISTER_READPRESSURECMD + (_bmp085Mode << 6));
|
||||
switch(_bmp085Mode)
|
||||
{
|
||||
case BMP085_MODE_ULTRALOWPOWER:
|
||||
delay(5);
|
||||
break;
|
||||
case BMP085_MODE_STANDARD:
|
||||
delay(8);
|
||||
break;
|
||||
case BMP085_MODE_HIGHRES:
|
||||
delay(14);
|
||||
break;
|
||||
case BMP085_MODE_ULTRAHIGHRES:
|
||||
default:
|
||||
delay(26);
|
||||
break;
|
||||
}
|
||||
|
||||
read16(BMP085_REGISTER_PRESSUREDATA, &p16);
|
||||
p32 = (uint32_t)p16 << 8;
|
||||
read8(BMP085_REGISTER_PRESSUREDATA+2, &p8);
|
||||
p32 += p8;
|
||||
p32 >>= (8 - _bmp085Mode);
|
||||
|
||||
*pressure = p32;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Compute B5 coefficient used in temperature & pressure calcs.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
int32_t Adafruit_BMP085_Unified::computeB5(int32_t ut) {
|
||||
int32_t X1 = (ut - (int32_t)_bmp085_coeffs.ac6) * ((int32_t)_bmp085_coeffs.ac5) >> 15;
|
||||
int32_t X2 = ((int32_t)_bmp085_coeffs.mc << 11) / (X1+(int32_t)_bmp085_coeffs.md);
|
||||
return X1 + X2;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CONSTRUCTOR
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Instantiates a new Adafruit_BMP085_Unified class
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_BMP085_Unified::Adafruit_BMP085_Unified(int32_t sensorID) {
|
||||
_sensorID = sensorID;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
PUBLIC FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Setups the HW
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_BMP085_Unified::begin(bmp085_mode_t mode)
|
||||
{
|
||||
// Enable I2C
|
||||
Wire.begin();
|
||||
|
||||
/* Mode boundary check */
|
||||
if ((mode > BMP085_MODE_ULTRAHIGHRES) || (mode < 0))
|
||||
{
|
||||
mode = BMP085_MODE_ULTRAHIGHRES;
|
||||
}
|
||||
|
||||
/* Make sure we have the right device */
|
||||
uint8_t id;
|
||||
read8(BMP085_REGISTER_CHIPID, &id);
|
||||
if(id != 0x55)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set the mode indicator */
|
||||
_bmp085Mode = mode;
|
||||
|
||||
/* Coefficients need to be read once */
|
||||
readCoefficients();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the compensated pressure level in kPa
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_BMP085_Unified::getPressure(float *pressure)
|
||||
{
|
||||
int32_t ut = 0, up = 0, compp = 0;
|
||||
int32_t x1, x2, b5, b6, x3, b3, p;
|
||||
uint32_t b4, b7;
|
||||
|
||||
/* Get the raw pressure and temperature values */
|
||||
readRawTemperature(&ut);
|
||||
readRawPressure(&up);
|
||||
|
||||
/* Temperature compensation */
|
||||
b5 = computeB5(ut);
|
||||
|
||||
/* Pressure compensation */
|
||||
b6 = b5 - 4000;
|
||||
x1 = (_bmp085_coeffs.b2 * ((b6 * b6) >> 12)) >> 11;
|
||||
x2 = (_bmp085_coeffs.ac2 * b6) >> 11;
|
||||
x3 = x1 + x2;
|
||||
b3 = (((((int32_t) _bmp085_coeffs.ac1) * 4 + x3) << _bmp085Mode) + 2) >> 2;
|
||||
x1 = (_bmp085_coeffs.ac3 * b6) >> 13;
|
||||
x2 = (_bmp085_coeffs.b1 * ((b6 * b6) >> 12)) >> 16;
|
||||
x3 = ((x1 + x2) + 2) >> 2;
|
||||
b4 = (_bmp085_coeffs.ac4 * (uint32_t) (x3 + 32768)) >> 15;
|
||||
b7 = ((uint32_t) (up - b3) * (50000 >> _bmp085Mode));
|
||||
|
||||
if (b7 < 0x80000000)
|
||||
{
|
||||
p = (b7 << 1) / b4;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = (b7 / b4) << 1;
|
||||
}
|
||||
|
||||
x1 = (p >> 8) * (p >> 8);
|
||||
x1 = (x1 * 3038) >> 16;
|
||||
x2 = (-7357 * p) >> 16;
|
||||
compp = p + ((x1 + x2 + 3791) >> 4);
|
||||
|
||||
/* Assign compensated pressure value */
|
||||
*pressure = compp;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the temperatures in degrees Celsius
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_BMP085_Unified::getTemperature(float *temp)
|
||||
{
|
||||
int32_t UT, X1, X2, B5; // following ds convention
|
||||
float t;
|
||||
|
||||
readRawTemperature(&UT);
|
||||
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
// use datasheet numbers!
|
||||
UT = 27898;
|
||||
_bmp085_coeffs.ac6 = 23153;
|
||||
_bmp085_coeffs.ac5 = 32757;
|
||||
_bmp085_coeffs.mc = -8711;
|
||||
_bmp085_coeffs.md = 2868;
|
||||
#endif
|
||||
|
||||
B5 = computeB5(UT);
|
||||
t = (B5+8) >> 4;
|
||||
t /= 10;
|
||||
|
||||
*temp = t;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the altitude (in meters) from the specified atmospheric
|
||||
pressure (in hPa), and sea-level pressure (in hPa).
|
||||
|
||||
@param seaLevel Sea-level pressure in hPa
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::pressureToAltitude(float seaLevel, float atmospheric)
|
||||
{
|
||||
// Equation taken from BMP180 datasheet (page 16):
|
||||
// http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
|
||||
|
||||
// Note that using the equation from wikipedia can give bad results
|
||||
// at high altitude. See this thread for more information:
|
||||
// http://forums.adafruit.com/viewtopic.php?f=22&t=58064
|
||||
|
||||
return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the altitude (in meters) from the specified atmospheric
|
||||
pressure (in hPa), and sea-level pressure (in hPa). Note that this
|
||||
function just calls the overload of pressureToAltitude which takes
|
||||
seaLevel and atmospheric pressure--temperature is ignored. The original
|
||||
implementation of this function was based on calculations from Wikipedia
|
||||
which are not accurate at higher altitudes. To keep compatibility with
|
||||
old code this function remains with the same interface, but it calls the
|
||||
more accurate calculation.
|
||||
|
||||
@param seaLevel Sea-level pressure in hPa
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
@param temp Temperature in degrees Celsius
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::pressureToAltitude(float seaLevel, float atmospheric, float temp)
|
||||
{
|
||||
return pressureToAltitude(seaLevel, atmospheric);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the pressure at sea level (in hPa) from the specified altitude
|
||||
(in meters), and atmospheric pressure (in hPa).
|
||||
|
||||
@param altitude Altitude in meters
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::seaLevelForAltitude(float altitude, float atmospheric)
|
||||
{
|
||||
// Equation taken from BMP180 datasheet (page 17):
|
||||
// http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
|
||||
|
||||
// Note that using the equation from wikipedia can give bad results
|
||||
// at high altitude. See this thread for more information:
|
||||
// http://forums.adafruit.com/viewtopic.php?f=22&t=58064
|
||||
|
||||
return atmospheric / pow(1.0 - (altitude/44330.0), 5.255);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the pressure at sea level (in hPa) from the specified altitude
|
||||
(in meters), and atmospheric pressure (in hPa). Note that this
|
||||
function just calls the overload of seaLevelForAltitude which takes
|
||||
altitude and atmospheric pressure--temperature is ignored. The original
|
||||
implementation of this function was based on calculations from Wikipedia
|
||||
which are not accurate at higher altitudes. To keep compatibility with
|
||||
old code this function remains with the same interface, but it calls the
|
||||
more accurate calculation.
|
||||
|
||||
@param altitude Altitude in meters
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
@param temp Temperature in degrees Celsius
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::seaLevelForAltitude(float altitude, float atmospheric, float temp)
|
||||
{
|
||||
return seaLevelForAltitude(altitude, atmospheric);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Provides the sensor_t data for this sensor
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_BMP085_Unified::getSensor(sensor_t *sensor)
|
||||
{
|
||||
/* Clear the sensor_t object */
|
||||
memset(sensor, 0, sizeof(sensor_t));
|
||||
|
||||
/* Insert the sensor name in the fixed length char array */
|
||||
strncpy (sensor->name, "BMP085", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name)- 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _sensorID;
|
||||
sensor->type = SENSOR_TYPE_PRESSURE;
|
||||
sensor->min_delay = 0;
|
||||
sensor->max_value = 1100.0F; // 300..1100 hPa
|
||||
sensor->min_value = 300.0F;
|
||||
sensor->resolution = 0.01F; // Datasheet states 0.01 hPa resolution
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the sensor and returns the data as a sensors_event_t
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_BMP085_Unified::getEvent(sensors_event_t *event)
|
||||
{
|
||||
float pressure_kPa;
|
||||
|
||||
/* Clear the event */
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _sensorID;
|
||||
event->type = SENSOR_TYPE_PRESSURE;
|
||||
event->timestamp = 0;
|
||||
getPressure(&pressure_kPa);
|
||||
event->pressure = pressure_kPa / 100.0F;
|
||||
|
||||
return true;
|
||||
}
|
||||
122
libraries/Adafruit_BMP085_Unified-master/Adafruit_BMP085_U.h
Normal file
122
libraries/Adafruit_BMP085_Unified-master/Adafruit_BMP085_U.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/***************************************************************************
|
||||
This is a library for the BMP085 pressure sensor
|
||||
|
||||
Designed specifically to work with the Adafruit BMP085 or BMP180 Breakout
|
||||
----> http://www.adafruit.com/products/391
|
||||
----> http://www.adafruit.com/products/1603
|
||||
|
||||
These displays use I2C to communicate, 2 pins are required to interface.
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit andopen-source hardware by purchasing products
|
||||
from Adafruit!
|
||||
|
||||
Written by Kevin Townsend for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
***************************************************************************/
|
||||
#ifndef __BMP085_H__
|
||||
#define __BMP085_H__
|
||||
|
||||
#if (ARDUINO >= 100)
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include <Adafruit_Sensor.h>
|
||||
|
||||
#ifdef __AVR_ATtiny85__
|
||||
#include "TinyWireM.h"
|
||||
#define Wire TinyWireM
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
/*=========================================================================
|
||||
I2C ADDRESS/BITS
|
||||
-----------------------------------------------------------------------*/
|
||||
#define BMP085_ADDRESS (0x77)
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
REGISTERS
|
||||
-----------------------------------------------------------------------*/
|
||||
enum
|
||||
{
|
||||
BMP085_REGISTER_CAL_AC1 = 0xAA, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC2 = 0xAC, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC3 = 0xAE, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC4 = 0xB0, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC5 = 0xB2, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC6 = 0xB4, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_B1 = 0xB6, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_B2 = 0xB8, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_MB = 0xBA, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_MC = 0xBC, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_MD = 0xBE, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CHIPID = 0xD0,
|
||||
BMP085_REGISTER_VERSION = 0xD1,
|
||||
BMP085_REGISTER_SOFTRESET = 0xE0,
|
||||
BMP085_REGISTER_CONTROL = 0xF4,
|
||||
BMP085_REGISTER_TEMPDATA = 0xF6,
|
||||
BMP085_REGISTER_PRESSUREDATA = 0xF6,
|
||||
BMP085_REGISTER_READTEMPCMD = 0x2E,
|
||||
BMP085_REGISTER_READPRESSURECMD = 0x34
|
||||
};
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
MODE SETTINGS
|
||||
-----------------------------------------------------------------------*/
|
||||
typedef enum
|
||||
{
|
||||
BMP085_MODE_ULTRALOWPOWER = 0,
|
||||
BMP085_MODE_STANDARD = 1,
|
||||
BMP085_MODE_HIGHRES = 2,
|
||||
BMP085_MODE_ULTRAHIGHRES = 3
|
||||
} bmp085_mode_t;
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
CALIBRATION DATA
|
||||
-----------------------------------------------------------------------*/
|
||||
typedef struct
|
||||
{
|
||||
int16_t ac1;
|
||||
int16_t ac2;
|
||||
int16_t ac3;
|
||||
uint16_t ac4;
|
||||
uint16_t ac5;
|
||||
uint16_t ac6;
|
||||
int16_t b1;
|
||||
int16_t b2;
|
||||
int16_t mb;
|
||||
int16_t mc;
|
||||
int16_t md;
|
||||
} bmp085_calib_data;
|
||||
/*=========================================================================*/
|
||||
|
||||
class Adafruit_BMP085_Unified : public Adafruit_Sensor
|
||||
{
|
||||
public:
|
||||
Adafruit_BMP085_Unified(int32_t sensorID = -1);
|
||||
|
||||
bool begin(bmp085_mode_t mode = BMP085_MODE_ULTRAHIGHRES);
|
||||
void getTemperature(float *temp);
|
||||
void getPressure(float *pressure);
|
||||
float pressureToAltitude(float seaLvel, float atmospheric);
|
||||
float seaLevelForAltitude(float altitude, float atmospheric);
|
||||
// Note that the next two functions are just for compatibility with old
|
||||
// code that passed the temperature as a third parameter. A newer
|
||||
// calculation is used which does not need temperature.
|
||||
float pressureToAltitude(float seaLevel, float atmospheric, float temp);
|
||||
float seaLevelForAltitude(float altitude, float atmospheric, float temp);
|
||||
bool getEvent(sensors_event_t*);
|
||||
void getSensor(sensor_t*);
|
||||
|
||||
private:
|
||||
int32_t computeB5(int32_t ut);
|
||||
int32_t _sensorID;
|
||||
};
|
||||
|
||||
#endif
|
||||
27
libraries/Adafruit_BMP085_Unified-master/README.md
Normal file
27
libraries/Adafruit_BMP085_Unified-master/README.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#Adafruit Unified BMP085/BMP180 Driver (Barometric Pressure Sensor) #
|
||||
|
||||
This driver is for the Adafruit BMP085 Breakout (http://www.adafruit.com/products/391) or BMP180 breakout (http://www.adafruit.com/products/1603), and is based on Adafruit's Unified Sensor Library (Adafruit_Sensor).
|
||||
|
||||
## About the BMP085 / BMP180 ##
|
||||
|
||||
This precision sensor from Bosch is the best low-cost sensing solution for measuring barometric pressure and temperature. Because pressure changes with altitude you can also use it as an altimeter!
|
||||
|
||||
## What is the Adafruit Unified Sensor Library? ##
|
||||
|
||||
The Adafruit Unified Sensor Library ([Adafruit_Sensor](https://github.com/adafruit/Adafruit_Sensor)) provides a common interface and data type for any supported sensor. It defines some basic information about the sensor (sensor limits, etc.), and returns standard SI units of a specific type and scale for each supported sensor type.
|
||||
|
||||
It provides a simple abstraction layer between your application and the actual sensor HW, allowing you to drop in any comparable sensor with only one or two lines of code to change in your project (essentially the constructor since the functions to read sensor data and get information about the sensor are defined in the base Adafruit_Sensor class).
|
||||
|
||||
This is imporant useful for two reasons:
|
||||
|
||||
1.) You can use the data right away because it's already converted to SI units that you understand and can compare, rather than meaningless values like 0..1023.
|
||||
|
||||
2.) Because SI units are standardised in the sensor library, you can also do quick sanity checks when working with new sensors, or drop in any comparable sensor if you need better sensitivity or if a lower cost unit becomes available, etc.
|
||||
|
||||
Light sensors will always report units in lux, gyroscopes will always report units in rad/s, etc. ... freeing you up to focus on the data, rather than digging through the datasheet to understand what the sensor's raw numbers really mean.
|
||||
|
||||
## About this Driver ##
|
||||
|
||||
Adafruit invests time and resources providing this open source code. Please support Adafruit and open-source hardware by purchasing products from Adafruit!
|
||||
|
||||
Written by Kevin (KTOWN) Townsend for Adafruit Industries.
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_BMP085_U.h>
|
||||
|
||||
/* This driver uses the Adafruit unified sensor library (Adafruit_Sensor),
|
||||
which provides a common 'type' for sensor data and some helper functions.
|
||||
|
||||
To use this driver you will also need to download the Adafruit_Sensor
|
||||
library and include it in your libraries folder.
|
||||
|
||||
You should also assign a unique ID to this sensor for use with
|
||||
the Adafruit Sensor API so that you can identify this particular
|
||||
sensor in any data logs, etc. To assign a unique ID, simply
|
||||
provide an appropriate value in the constructor below (12345
|
||||
is used by default in this example).
|
||||
|
||||
Connections
|
||||
===========
|
||||
Connect SCL to analog 5
|
||||
Connect SDA to analog 4
|
||||
Connect VDD to 3.3V DC
|
||||
Connect GROUND to common ground
|
||||
|
||||
History
|
||||
=======
|
||||
2013/JUN/17 - Updated altitude calculations (KTOWN)
|
||||
2013/FEB/13 - First version (KTOWN)
|
||||
*/
|
||||
|
||||
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085);
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Displays some basic information on this sensor from the unified
|
||||
sensor API sensor_t type (see Adafruit_Sensor for more information)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void displaySensorDetails(void)
|
||||
{
|
||||
sensor_t sensor;
|
||||
bmp.getSensor(&sensor);
|
||||
Serial.println("------------------------------------");
|
||||
Serial.print ("Sensor: "); Serial.println(sensor.name);
|
||||
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
|
||||
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
|
||||
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" hPa");
|
||||
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" hPa");
|
||||
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" hPa");
|
||||
Serial.println("------------------------------------");
|
||||
Serial.println("");
|
||||
delay(500);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Arduino setup function (automatically called at startup)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.println("Pressure Sensor Test"); Serial.println("");
|
||||
|
||||
/* Initialise the sensor */
|
||||
if(!bmp.begin())
|
||||
{
|
||||
/* There was a problem detecting the BMP085 ... check your connections */
|
||||
Serial.print("Ooops, no BMP085 detected ... Check your wiring or I2C ADDR!");
|
||||
while(1);
|
||||
}
|
||||
|
||||
/* Display some basic information on this sensor */
|
||||
displaySensorDetails();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Arduino loop function, called once 'setup' is complete (your own code
|
||||
should go here)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void loop(void)
|
||||
{
|
||||
/* Get a new sensor event */
|
||||
sensors_event_t event;
|
||||
bmp.getEvent(&event);
|
||||
|
||||
/* Display the results (barometric pressure is measure in hPa) */
|
||||
if (event.pressure)
|
||||
{
|
||||
/* Display atmospheric pressue in hPa */
|
||||
Serial.print("Pressure: ");
|
||||
Serial.print(event.pressure);
|
||||
Serial.println(" hPa");
|
||||
|
||||
/* Calculating altitude with reasonable accuracy requires pressure *
|
||||
* sea level pressure for your position at the moment the data is *
|
||||
* converted, as well as the ambient temperature in degress *
|
||||
* celcius. If you don't have these values, a 'generic' value of *
|
||||
* 1013.25 hPa can be used (defined as SENSORS_PRESSURE_SEALEVELHPA *
|
||||
* in sensors.h), but this isn't ideal and will give variable *
|
||||
* results from one day to the next. *
|
||||
* *
|
||||
* You can usually find the current SLP value by looking at weather *
|
||||
* websites or from environmental information centers near any major *
|
||||
* airport. *
|
||||
* *
|
||||
* For example, for Paris, France you can check the current mean *
|
||||
* pressure and sea level at: http://bit.ly/16Au8ol */
|
||||
|
||||
/* First we get the current temperature from the BMP085 */
|
||||
float temperature;
|
||||
bmp.getTemperature(&temperature);
|
||||
Serial.print("Temperature: ");
|
||||
Serial.print(temperature);
|
||||
Serial.println(" C");
|
||||
|
||||
/* Then convert the atmospheric pressure, and SLP to altitude */
|
||||
/* Update this next line with the current SLP for better results */
|
||||
float seaLevelPressure = 1009;
|
||||
Serial.print("Altitude: ");
|
||||
Serial.print(bmp.pressureToAltitude(seaLevelPressure,
|
||||
event.pressure));
|
||||
Serial.println(" m");
|
||||
Serial.println("");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Sensor error");
|
||||
}
|
||||
delay(1000);
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
name=Adafruit BMP085 Unified
|
||||
version=1.0.0
|
||||
author=Adafruit
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=Unified sensor driver for Adafruit's BMP085 & BMP180 breakouts
|
||||
paragraph=Unified sensor driver for Adafruit's BMP085 & BMP180 breakouts
|
||||
category=Sensors
|
||||
url=https://github.com/adafruit/Adafruit_BMP085_Unified
|
||||
architectures=*
|
||||
478
libraries/Adafruit_BMP085_Unified/Adafruit_BMP085_U.cpp
Normal file
478
libraries/Adafruit_BMP085_Unified/Adafruit_BMP085_U.cpp
Normal file
|
|
@ -0,0 +1,478 @@
|
|||
/*!
|
||||
* @file Adafruit_BMP085_U.cpp
|
||||
*
|
||||
* @mainpage Adafruit BMP085 Pressure Sensor
|
||||
*
|
||||
* @section intro_sec Introduction
|
||||
*
|
||||
* This is a library for the BMP085 pressure sensor
|
||||
*
|
||||
* Designed specifically to work with the Adafruit BMP085 or BMP180 Breakout
|
||||
* ----> http://www.adafruit.com/products/391
|
||||
* ----> http://www.adafruit.com/products/1603
|
||||
*
|
||||
* These displays use I2C to communicate, 2 pins are required to interface.
|
||||
*
|
||||
* Adafruit invests time and resources providing this open source code,
|
||||
* please support Adafruit andopen-source hardware by purchasing products
|
||||
* from Adafruit!
|
||||
*
|
||||
* @section author Author
|
||||
*
|
||||
* Written by Kevin Townsend for Adafruit Industries.
|
||||
*
|
||||
* @section license License
|
||||
* BSD license, all text above must be included in any redistribution
|
||||
*/
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#ifdef __AVR_ATtiny85__
|
||||
#include "TinyWireM.h"
|
||||
#define Wire TinyWireM
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "Adafruit_BMP085_U.h"
|
||||
|
||||
static bmp085_calib_data
|
||||
_bmp085_coeffs; // Last read accelerometer data will be available here
|
||||
static uint8_t _bmp085Mode;
|
||||
|
||||
#define BMP085_USE_DATASHEET_VALS \
|
||||
(0) //!< Set to 1 for sanity check, when true, will use values from datasheet
|
||||
|
||||
/***************************************************************************
|
||||
PRIVATE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Writes an 8 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void writeCommand(byte reg, byte value) {
|
||||
Wire.beginTransmission((uint8_t)BMP085_ADDRESS);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
Wire.write((uint8_t)value);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
Wire.send(value);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads an 8 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void read8(byte reg, uint8_t *value) {
|
||||
Wire.beginTransmission((uint8_t)BMP085_ADDRESS);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)1);
|
||||
#if ARDUINO >= 100
|
||||
*value = Wire.read();
|
||||
#else
|
||||
*value = Wire.receive();
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads a 16 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void read16(byte reg, uint16_t *value) {
|
||||
Wire.beginTransmission((uint8_t)BMP085_ADDRESS);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)2);
|
||||
#if ARDUINO >= 100
|
||||
*value = (Wire.read() << 8) | Wire.read();
|
||||
#else
|
||||
*value = (Wire.receive() << 8) | Wire.receive();
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads a signed 16 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readS16(byte reg, int16_t *value) {
|
||||
uint16_t i;
|
||||
read16(reg, &i);
|
||||
*value = (int16_t)i;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the factory-set coefficients
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readCoefficients(void) {
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
_bmp085_coeffs.ac1 = 408;
|
||||
_bmp085_coeffs.ac2 = -72;
|
||||
_bmp085_coeffs.ac3 = -14383;
|
||||
_bmp085_coeffs.ac4 = 32741;
|
||||
_bmp085_coeffs.ac5 = 32757;
|
||||
_bmp085_coeffs.ac6 = 23153;
|
||||
_bmp085_coeffs.b1 = 6190;
|
||||
_bmp085_coeffs.b2 = 4;
|
||||
_bmp085_coeffs.mb = -32768;
|
||||
_bmp085_coeffs.mc = -8711;
|
||||
_bmp085_coeffs.md = 2868;
|
||||
_bmp085Mode = 0;
|
||||
#else
|
||||
readS16(BMP085_REGISTER_CAL_AC1, &_bmp085_coeffs.ac1);
|
||||
readS16(BMP085_REGISTER_CAL_AC2, &_bmp085_coeffs.ac2);
|
||||
readS16(BMP085_REGISTER_CAL_AC3, &_bmp085_coeffs.ac3);
|
||||
read16(BMP085_REGISTER_CAL_AC4, &_bmp085_coeffs.ac4);
|
||||
read16(BMP085_REGISTER_CAL_AC5, &_bmp085_coeffs.ac5);
|
||||
read16(BMP085_REGISTER_CAL_AC6, &_bmp085_coeffs.ac6);
|
||||
readS16(BMP085_REGISTER_CAL_B1, &_bmp085_coeffs.b1);
|
||||
readS16(BMP085_REGISTER_CAL_B2, &_bmp085_coeffs.b2);
|
||||
readS16(BMP085_REGISTER_CAL_MB, &_bmp085_coeffs.mb);
|
||||
readS16(BMP085_REGISTER_CAL_MC, &_bmp085_coeffs.mc);
|
||||
readS16(BMP085_REGISTER_CAL_MD, &_bmp085_coeffs.md);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readRawTemperature(int32_t *temperature) {
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
*temperature = 27898;
|
||||
#else
|
||||
uint16_t t;
|
||||
writeCommand(BMP085_REGISTER_CONTROL, BMP085_REGISTER_READTEMPCMD);
|
||||
delay(5);
|
||||
read16(BMP085_REGISTER_TEMPDATA, &t);
|
||||
*temperature = t;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readRawPressure(int32_t *pressure) {
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
*pressure = 23843;
|
||||
#else
|
||||
uint8_t p8;
|
||||
uint16_t p16;
|
||||
int32_t p32;
|
||||
|
||||
writeCommand(BMP085_REGISTER_CONTROL,
|
||||
BMP085_REGISTER_READPRESSURECMD + (_bmp085Mode << 6));
|
||||
switch (_bmp085Mode) {
|
||||
case BMP085_MODE_ULTRALOWPOWER:
|
||||
delay(5);
|
||||
break;
|
||||
case BMP085_MODE_STANDARD:
|
||||
delay(8);
|
||||
break;
|
||||
case BMP085_MODE_HIGHRES:
|
||||
delay(14);
|
||||
break;
|
||||
case BMP085_MODE_ULTRAHIGHRES:
|
||||
default:
|
||||
delay(26);
|
||||
break;
|
||||
}
|
||||
|
||||
read16(BMP085_REGISTER_PRESSUREDATA, &p16);
|
||||
p32 = (uint32_t)p16 << 8;
|
||||
read8(BMP085_REGISTER_PRESSUREDATA + 2, &p8);
|
||||
p32 += p8;
|
||||
p32 >>= (8 - _bmp085Mode);
|
||||
|
||||
*pressure = p32;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Compute B5 coefficient used in temperature & pressure calcs.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
int32_t Adafruit_BMP085_Unified::computeB5(int32_t ut) {
|
||||
int32_t X1 =
|
||||
(ut - (int32_t)_bmp085_coeffs.ac6) * ((int32_t)_bmp085_coeffs.ac5) >> 15;
|
||||
int32_t X2 =
|
||||
((int32_t)_bmp085_coeffs.mc << 11) / (X1 + (int32_t)_bmp085_coeffs.md);
|
||||
return X1 + X2;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
CONSTRUCTOR
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Instantiates a new Adafruit_BMP085_Unified class
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_BMP085_Unified::Adafruit_BMP085_Unified(int32_t sensorID) {
|
||||
_sensorID = sensorID;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
PUBLIC FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Setups the HW
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_BMP085_Unified::begin(bmp085_mode_t mode) {
|
||||
// Enable I2C
|
||||
Wire.begin();
|
||||
|
||||
/* Mode boundary check */
|
||||
if ((mode > BMP085_MODE_ULTRAHIGHRES) || (mode < 0)) {
|
||||
mode = BMP085_MODE_ULTRAHIGHRES;
|
||||
}
|
||||
|
||||
/* Make sure we have the right device */
|
||||
uint8_t id;
|
||||
read8(BMP085_REGISTER_CHIPID, &id);
|
||||
if (id != 0x55) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set the mode indicator */
|
||||
_bmp085Mode = mode;
|
||||
|
||||
/* Coefficients need to be read once */
|
||||
readCoefficients();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the compensated pressure level in kPa
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_BMP085_Unified::getPressure(float *pressure) {
|
||||
int32_t ut = 0, up = 0, compp = 0;
|
||||
int32_t x1, x2, b5, b6, x3, b3, p;
|
||||
uint32_t b4, b7;
|
||||
|
||||
/* Get the raw pressure and temperature values */
|
||||
readRawTemperature(&ut);
|
||||
readRawPressure(&up);
|
||||
|
||||
/* Temperature compensation */
|
||||
b5 = computeB5(ut);
|
||||
|
||||
/* Pressure compensation */
|
||||
b6 = b5 - 4000;
|
||||
x1 = (_bmp085_coeffs.b2 * ((b6 * b6) >> 12)) >> 11;
|
||||
x2 = (_bmp085_coeffs.ac2 * b6) >> 11;
|
||||
x3 = x1 + x2;
|
||||
b3 = (((((int32_t)_bmp085_coeffs.ac1) * 4 + x3) << _bmp085Mode) + 2) >> 2;
|
||||
x1 = (_bmp085_coeffs.ac3 * b6) >> 13;
|
||||
x2 = (_bmp085_coeffs.b1 * ((b6 * b6) >> 12)) >> 16;
|
||||
x3 = ((x1 + x2) + 2) >> 2;
|
||||
b4 = (_bmp085_coeffs.ac4 * (uint32_t)(x3 + 32768)) >> 15;
|
||||
b7 = ((uint32_t)(up - b3) * (50000 >> _bmp085Mode));
|
||||
|
||||
if (b7 < 0x80000000) {
|
||||
p = (b7 << 1) / b4;
|
||||
} else {
|
||||
p = (b7 / b4) << 1;
|
||||
}
|
||||
|
||||
x1 = (p >> 8) * (p >> 8);
|
||||
x1 = (x1 * 3038) >> 16;
|
||||
x2 = (-7357 * p) >> 16;
|
||||
compp = p + ((x1 + x2 + 3791) >> 4);
|
||||
|
||||
/* Assign compensated pressure value */
|
||||
*pressure = compp;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the temperatures in degrees Celsius
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_BMP085_Unified::getTemperature(float *temp) {
|
||||
int32_t UT, B5; // following ds convention
|
||||
float t;
|
||||
|
||||
readRawTemperature(&UT);
|
||||
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
// use datasheet numbers!
|
||||
UT = 27898;
|
||||
_bmp085_coeffs.ac6 = 23153;
|
||||
_bmp085_coeffs.ac5 = 32757;
|
||||
_bmp085_coeffs.mc = -8711;
|
||||
_bmp085_coeffs.md = 2868;
|
||||
#endif
|
||||
|
||||
B5 = computeB5(UT);
|
||||
t = (B5 + 8) >> 4;
|
||||
t /= 10;
|
||||
|
||||
*temp = t;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the altitude (in meters) from the specified atmospheric
|
||||
pressure (in hPa), and sea-level pressure (in hPa).
|
||||
|
||||
@param seaLevel Sea-level pressure in hPa
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::pressureToAltitude(float seaLevel,
|
||||
float atmospheric) {
|
||||
// Equation taken from BMP180 datasheet (page 16):
|
||||
// http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
|
||||
|
||||
// Note that using the equation from wikipedia can give bad results
|
||||
// at high altitude. See this thread for more information:
|
||||
// http://forums.adafruit.com/viewtopic.php?f=22&t=58064
|
||||
|
||||
return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the altitude (in meters) from the specified atmospheric
|
||||
pressure (in hPa), and sea-level pressure (in hPa). Note that this
|
||||
function just calls the overload of pressureToAltitude which takes
|
||||
seaLevel and atmospheric pressure--temperature is ignored. The original
|
||||
implementation of this function was based on calculations from Wikipedia
|
||||
which are not accurate at higher altitudes. To keep compatibility with
|
||||
old code this function remains with the same interface, but it calls the
|
||||
more accurate calculation.
|
||||
|
||||
@param seaLevel Sea-level pressure in hPa
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
@param temp Temperature in degrees Celsius
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::pressureToAltitude(float seaLevel,
|
||||
float atmospheric,
|
||||
float temp) {
|
||||
return pressureToAltitude(seaLevel, atmospheric);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the pressure at sea level (in hPa) from the specified altitude
|
||||
(in meters), and atmospheric pressure (in hPa).
|
||||
|
||||
@param altitude Altitude in meters
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::seaLevelForAltitude(float altitude,
|
||||
float atmospheric) {
|
||||
// Equation taken from BMP180 datasheet (page 17):
|
||||
// http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
|
||||
|
||||
// Note that using the equation from wikipedia can give bad results
|
||||
// at high altitude. See this thread for more information:
|
||||
// http://forums.adafruit.com/viewtopic.php?f=22&t=58064
|
||||
|
||||
return atmospheric / pow(1.0 - (altitude / 44330.0), 5.255);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the pressure at sea level (in hPa) from the specified altitude
|
||||
(in meters), and atmospheric pressure (in hPa). Note that this
|
||||
function just calls the overload of seaLevelForAltitude which takes
|
||||
altitude and atmospheric pressure--temperature is ignored. The original
|
||||
implementation of this function was based on calculations from Wikipedia
|
||||
which are not accurate at higher altitudes. To keep compatibility with
|
||||
old code this function remains with the same interface, but it calls the
|
||||
more accurate calculation.
|
||||
|
||||
@param altitude Altitude in meters
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
@param temp Temperature in degrees Celsius
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::seaLevelForAltitude(float altitude,
|
||||
float atmospheric,
|
||||
float temp) {
|
||||
return seaLevelForAltitude(altitude, atmospheric);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Provides the sensor_t data for this sensor
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_BMP085_Unified::getSensor(sensor_t *sensor) {
|
||||
/* Clear the sensor_t object */
|
||||
memset(sensor, 0, sizeof(sensor_t));
|
||||
|
||||
/* Insert the sensor name in the fixed length char array */
|
||||
strncpy(sensor->name, "BMP085", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name) - 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _sensorID;
|
||||
sensor->type = SENSOR_TYPE_PRESSURE;
|
||||
sensor->min_delay = 0;
|
||||
sensor->max_value = 1100.0F; // 300..1100 hPa
|
||||
sensor->min_value = 300.0F;
|
||||
sensor->resolution = 0.01F; // Datasheet states 0.01 hPa resolution
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the sensor and returns the data as a sensors_event_t
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_BMP085_Unified::getEvent(sensors_event_t *event) {
|
||||
float pressure_kPa;
|
||||
|
||||
/* Clear the event */
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _sensorID;
|
||||
event->type = SENSOR_TYPE_PRESSURE;
|
||||
event->timestamp = 0;
|
||||
getPressure(&pressure_kPa);
|
||||
event->pressure = pressure_kPa / 100.0F;
|
||||
|
||||
return true;
|
||||
}
|
||||
154
libraries/Adafruit_BMP085_Unified/Adafruit_BMP085_U.h
Normal file
154
libraries/Adafruit_BMP085_Unified/Adafruit_BMP085_U.h
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/*!
|
||||
* @file Adafruit_BMP085_U.h
|
||||
*/
|
||||
|
||||
#ifndef __BMP085_H__
|
||||
#define __BMP085_H__
|
||||
|
||||
#if (ARDUINO >= 100)
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include <Adafruit_Sensor.h>
|
||||
|
||||
#ifdef __AVR_ATtiny85__
|
||||
#include "TinyWireM.h"
|
||||
#define Wire TinyWireM
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @brief BMP085 I2C address/bits
|
||||
*/
|
||||
#define BMP085_ADDRESS (0x77)
|
||||
|
||||
/*!
|
||||
* @brief BMP085 I2C registers
|
||||
*/
|
||||
enum {
|
||||
BMP085_REGISTER_CAL_AC1 = 0xAA, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC2 = 0xAC, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC3 = 0xAE, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC4 = 0xB0, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC5 = 0xB2, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC6 = 0xB4, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_B1 = 0xB6, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_B2 = 0xB8, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_MB = 0xBA, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_MC = 0xBC, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_MD = 0xBE, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CHIPID = 0xD0, //!< Register that contains the chip ID
|
||||
BMP085_REGISTER_VERSION = 0xD1, //!< Register that contains the chip version
|
||||
BMP085_REGISTER_SOFTRESET = 0xE0, //!< Register for doing a soft reset
|
||||
BMP085_REGISTER_CONTROL = 0xF4, //!< Control register
|
||||
BMP085_REGISTER_TEMPDATA = 0xF6, //!< Temperature data register
|
||||
BMP085_REGISTER_PRESSUREDATA = 0xF6, //!< Pressure data register
|
||||
BMP085_REGISTER_READTEMPCMD =
|
||||
0x2E, //!< Read temperature control register value
|
||||
BMP085_REGISTER_READPRESSURECMD =
|
||||
0x34 //!< Read pressure control register value
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief BMP085 mode settings
|
||||
*/
|
||||
typedef enum {
|
||||
BMP085_MODE_ULTRALOWPOWER = 0,
|
||||
BMP085_MODE_STANDARD = 1,
|
||||
BMP085_MODE_HIGHRES = 2,
|
||||
BMP085_MODE_ULTRAHIGHRES = 3
|
||||
} bmp085_mode_t;
|
||||
/*=========================================================================*/
|
||||
|
||||
/*!
|
||||
* @brief Calibration data
|
||||
*/
|
||||
typedef struct {
|
||||
int16_t ac1; //!< R calibration coefficient (16-bits)
|
||||
int16_t ac2; //!< R calibration coefficient (16-bits)
|
||||
int16_t ac3; //!< R calibration coefficient (16-bits)
|
||||
uint16_t ac4; //!< R calibration coefficient (16-bits)
|
||||
uint16_t ac5; //!< R calibration coefficient (16-bits)
|
||||
uint16_t ac6; //!< R calibration coefficient (16-bits)
|
||||
int16_t b1; //!< R calibration coefficient (16-bits)
|
||||
int16_t b2; //!< R calibration coefficient (16-bits)
|
||||
int16_t mb; //!< R calibration coefficient (16-bits)
|
||||
int16_t mc; //!< R calibration coefficient (16-bits)
|
||||
int16_t md; //!< R calibration coefficient (16-bits)
|
||||
} bmp085_calib_data;
|
||||
|
||||
/*!
|
||||
* @brief Class that stores state and functions for interacting with BMP183
|
||||
*/
|
||||
class Adafruit_BMP085_Unified : public Adafruit_Sensor {
|
||||
public:
|
||||
Adafruit_BMP085_Unified(
|
||||
int32_t sensorID = -1); //!< @param sensorID ID of the BMP085 sensor
|
||||
|
||||
/*!
|
||||
* @brief Starts I2C connection
|
||||
* @param mode Mode to set, ultra high-res by default
|
||||
* @return Returns true if successful
|
||||
*/
|
||||
bool begin(bmp085_mode_t mode = BMP085_MODE_ULTRAHIGHRES);
|
||||
/*!
|
||||
* @brief Gets the temperature over I2C from the BMP085
|
||||
* @param temp Temperature
|
||||
* @return Returns the temperature
|
||||
*/
|
||||
void getTemperature(float *temp);
|
||||
/*!
|
||||
* @brief Gets the pressure over I2C from the BMP085
|
||||
* @param pressure Pressure
|
||||
* @return Returns the pressure
|
||||
*/
|
||||
void getPressure(float *pressure);
|
||||
/*!
|
||||
* @brief Calculates absolute pressure
|
||||
* @param seaLevel Pressure at sea level
|
||||
* @param atmospheric measured pressure
|
||||
* @return Absolute altitude
|
||||
*/
|
||||
float pressureToAltitude(float seaLevel, float atmospheric);
|
||||
/*!
|
||||
* @brief Calculates pressure at sea level
|
||||
* @param altitude Altitude
|
||||
* @param atmospheric measured pressure
|
||||
* @return Pressure at sea level
|
||||
*/
|
||||
float seaLevelForAltitude(float altitude, float atmospheric);
|
||||
// Note that the next two functions are just for compatibility with old
|
||||
// code that passed the temperature as a third parameter. A newer
|
||||
// calculation is used which does not need temperature.
|
||||
/*!
|
||||
* @brief Calculates absolute pressure
|
||||
* @param seaLevel Pressure at sea level
|
||||
* @param atmospheric Measured pressure
|
||||
* @param temp Temperature
|
||||
* @return Absolute altitude
|
||||
*/
|
||||
float pressureToAltitude(float seaLevel, float atmospheric, float temp);
|
||||
/*!
|
||||
* @brief Calculates pressure at sea level
|
||||
* @param altitude Altitude
|
||||
* @param atmospheric measured pressure
|
||||
* @param temp Temperature
|
||||
* @return Pressure at sea level
|
||||
*/
|
||||
float seaLevelForAltitude(float altitude, float atmospheric, float temp);
|
||||
/*!
|
||||
* @brief Used to read the sensor
|
||||
* @return Returns an event
|
||||
*/
|
||||
bool getEvent(sensors_event_t *);
|
||||
void getSensor(sensor_t *);
|
||||
|
||||
private:
|
||||
int32_t computeB5(int32_t ut);
|
||||
int32_t _sensorID;
|
||||
};
|
||||
|
||||
#endif
|
||||
27
libraries/Adafruit_BMP085_Unified/README.md
Normal file
27
libraries/Adafruit_BMP085_Unified/README.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Adafruit Unified BMP085/BMP180 Driver (Barometric Pressure Sensor) [](https://github.com/adafruit/Adafruit_BMP085_Unified/actions)[](http://adafruit.github.io/Adafruit_BMP085_Unified/html/index.html)
|
||||
|
||||
This driver is for the Adafruit BMP085 Breakout (http://www.adafruit.com/products/391) or BMP180 breakout (http://www.adafruit.com/products/1603), and is based on Adafruit's Unified Sensor Library (Adafruit_Sensor).
|
||||
|
||||
## About the BMP085 / BMP180 ##
|
||||
|
||||
This precision sensor from Bosch is the best low-cost sensing solution for measuring barometric pressure and temperature. Because pressure changes with altitude you can also use it as an altimeter!
|
||||
|
||||
## What is the Adafruit Unified Sensor Library? ##
|
||||
|
||||
The Adafruit Unified Sensor Library ([Adafruit_Sensor](https://github.com/adafruit/Adafruit_Sensor)) provides a common interface and data type for any supported sensor. It defines some basic information about the sensor (sensor limits, etc.), and returns standard SI units of a specific type and scale for each supported sensor type.
|
||||
|
||||
It provides a simple abstraction layer between your application and the actual sensor HW, allowing you to drop in any comparable sensor with only one or two lines of code to change in your project (essentially the constructor since the functions to read sensor data and get information about the sensor are defined in the base Adafruit_Sensor class).
|
||||
|
||||
This is imporant useful for two reasons:
|
||||
|
||||
1.) You can use the data right away because it's already converted to SI units that you understand and can compare, rather than meaningless values like 0..1023.
|
||||
|
||||
2.) Because SI units are standardised in the sensor library, you can also do quick sanity checks when working with new sensors, or drop in any comparable sensor if you need better sensitivity or if a lower cost unit becomes available, etc.
|
||||
|
||||
Light sensors will always report units in lux, gyroscopes will always report units in rad/s, etc. ... freeing you up to focus on the data, rather than digging through the datasheet to understand what the sensor's raw numbers really mean.
|
||||
|
||||
## About this Driver ##
|
||||
|
||||
Adafruit invests time and resources providing this open source code. Please support Adafruit and open-source hardware by purchasing products from Adafruit!
|
||||
|
||||
Written by Kevin (KTOWN) Townsend for Adafruit Industries.
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_BMP085_U.h>
|
||||
|
||||
/* This driver uses the Adafruit unified sensor library (Adafruit_Sensor),
|
||||
which provides a common 'type' for sensor data and some helper functions.
|
||||
|
||||
To use this driver you will also need to download the Adafruit_Sensor
|
||||
library and include it in your libraries folder.
|
||||
|
||||
You should also assign a unique ID to this sensor for use with
|
||||
the Adafruit Sensor API so that you can identify this particular
|
||||
sensor in any data logs, etc. To assign a unique ID, simply
|
||||
provide an appropriate value in the constructor below (12345
|
||||
is used by default in this example).
|
||||
|
||||
Connections
|
||||
===========
|
||||
Connect SCL to analog 5
|
||||
Connect SDA to analog 4
|
||||
Connect VDD to 3.3V DC
|
||||
Connect GROUND to common ground
|
||||
|
||||
History
|
||||
=======
|
||||
2013/JUN/17 - Updated altitude calculations (KTOWN)
|
||||
2013/FEB/13 - First version (KTOWN)
|
||||
*/
|
||||
|
||||
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085);
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Displays some basic information on this sensor from the unified
|
||||
sensor API sensor_t type (see Adafruit_Sensor for more information)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void displaySensorDetails(void)
|
||||
{
|
||||
sensor_t sensor;
|
||||
bmp.getSensor(&sensor);
|
||||
Serial.println("------------------------------------");
|
||||
Serial.print ("Sensor: "); Serial.println(sensor.name);
|
||||
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
|
||||
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
|
||||
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" hPa");
|
||||
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" hPa");
|
||||
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" hPa");
|
||||
Serial.println("------------------------------------");
|
||||
Serial.println("");
|
||||
delay(500);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Arduino setup function (automatically called at startup)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.println("Pressure Sensor Test"); Serial.println("");
|
||||
|
||||
/* Initialise the sensor */
|
||||
if(!bmp.begin())
|
||||
{
|
||||
/* There was a problem detecting the BMP085 ... check your connections */
|
||||
Serial.print("Ooops, no BMP085 detected ... Check your wiring or I2C ADDR!");
|
||||
while(1);
|
||||
}
|
||||
|
||||
/* Display some basic information on this sensor */
|
||||
displaySensorDetails();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Arduino loop function, called once 'setup' is complete (your own code
|
||||
should go here)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void loop(void)
|
||||
{
|
||||
/* Get a new sensor event */
|
||||
sensors_event_t event;
|
||||
bmp.getEvent(&event);
|
||||
|
||||
/* Display the results (barometric pressure is measure in hPa) */
|
||||
if (event.pressure)
|
||||
{
|
||||
/* Display atmospheric pressue in hPa */
|
||||
Serial.print("Pressure: ");
|
||||
Serial.print(event.pressure);
|
||||
Serial.println(" hPa");
|
||||
|
||||
/* Calculating altitude with reasonable accuracy requires pressure *
|
||||
* sea level pressure for your position at the moment the data is *
|
||||
* converted, as well as the ambient temperature in degress *
|
||||
* celcius. If you don't have these values, a 'generic' value of *
|
||||
* 1013.25 hPa can be used (defined as SENSORS_PRESSURE_SEALEVELHPA *
|
||||
* in sensors.h), but this isn't ideal and will give variable *
|
||||
* results from one day to the next. *
|
||||
* *
|
||||
* You can usually find the current SLP value by looking at weather *
|
||||
* websites or from environmental information centers near any major *
|
||||
* airport. *
|
||||
* *
|
||||
* For example, for Paris, France you can check the current mean *
|
||||
* pressure and sea level at: http://bit.ly/16Au8ol */
|
||||
|
||||
/* First we get the current temperature from the BMP085 */
|
||||
float temperature;
|
||||
bmp.getTemperature(&temperature);
|
||||
Serial.print("Temperature: ");
|
||||
Serial.print(temperature);
|
||||
Serial.println(" C");
|
||||
|
||||
/* Then convert the atmospheric pressure, and SLP to altitude */
|
||||
/* Update this next line with the current SLP for better results */
|
||||
float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
|
||||
Serial.print("Altitude: ");
|
||||
Serial.print(bmp.pressureToAltitude(seaLevelPressure,
|
||||
event.pressure));
|
||||
Serial.println(" m");
|
||||
Serial.println("");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Sensor error");
|
||||
}
|
||||
delay(1000);
|
||||
}
|
||||
10
libraries/Adafruit_BMP085_Unified/library.properties
Normal file
10
libraries/Adafruit_BMP085_Unified/library.properties
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
name=Adafruit BMP085 Unified
|
||||
version=1.1.1
|
||||
author=Adafruit
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=Unified sensor driver for Adafruit's BMP085 & BMP180 breakouts
|
||||
paragraph=Unified sensor driver for Adafruit's BMP085 & BMP180 breakouts
|
||||
category=Sensors
|
||||
url=https://github.com/adafruit/Adafruit_BMP085_Unified
|
||||
architectures=*
|
||||
depends=Adafruit Unified Sensor
|
||||
154
libraries/Adafruit_Sensor/Adafruit_Sensor.h
Normal file
154
libraries/Adafruit_Sensor/Adafruit_Sensor.h
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software< /span>
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and
|
||||
* extended sensor support to include color, voltage and current */
|
||||
|
||||
#ifndef _ADAFRUIT_SENSOR_H
|
||||
#define _ADAFRUIT_SENSOR_H
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#include "Print.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
/* Intentionally modeled after sensors.h in the Android API:
|
||||
* https://github.com/android/platform_hardware_libhardware/blob/master/include/hardware/sensors.h */
|
||||
|
||||
/* Constants */
|
||||
#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */
|
||||
#define SENSORS_GRAVITY_MOON (1.6F) /**< The moon's gravity in m/s^2 */
|
||||
#define SENSORS_GRAVITY_SUN (275.0F) /**< The sun's gravity in m/s^2 */
|
||||
#define SENSORS_GRAVITY_STANDARD (SENSORS_GRAVITY_EARTH)
|
||||
#define SENSORS_MAGFIELD_EARTH_MAX (60.0F) /**< Maximum magnetic field on Earth's surface */
|
||||
#define SENSORS_MAGFIELD_EARTH_MIN (30.0F) /**< Minimum magnetic field on Earth's surface */
|
||||
#define SENSORS_PRESSURE_SEALEVELHPA (1013.25F) /**< Average sea level pressure is 1013.25 hPa */
|
||||
#define SENSORS_DPS_TO_RADS (0.017453293F) /**< Degrees/s to rad/s multiplier */
|
||||
#define SENSORS_GAUSS_TO_MICROTESLA (100) /**< Gauss to micro-Tesla multiplier */
|
||||
|
||||
/** Sensor types */
|
||||
typedef enum
|
||||
{
|
||||
SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */
|
||||
SENSOR_TYPE_MAGNETIC_FIELD = (2),
|
||||
SENSOR_TYPE_ORIENTATION = (3),
|
||||
SENSOR_TYPE_GYROSCOPE = (4),
|
||||
SENSOR_TYPE_LIGHT = (5),
|
||||
SENSOR_TYPE_PRESSURE = (6),
|
||||
SENSOR_TYPE_PROXIMITY = (8),
|
||||
SENSOR_TYPE_GRAVITY = (9),
|
||||
SENSOR_TYPE_LINEAR_ACCELERATION = (10), /**< Acceleration not including gravity */
|
||||
SENSOR_TYPE_ROTATION_VECTOR = (11),
|
||||
SENSOR_TYPE_RELATIVE_HUMIDITY = (12),
|
||||
SENSOR_TYPE_AMBIENT_TEMPERATURE = (13),
|
||||
SENSOR_TYPE_VOLTAGE = (15),
|
||||
SENSOR_TYPE_CURRENT = (16),
|
||||
SENSOR_TYPE_COLOR = (17)
|
||||
} sensors_type_t;
|
||||
|
||||
/** struct sensors_vec_s is used to return a vector in a common format. */
|
||||
typedef struct {
|
||||
union {
|
||||
float v[3];
|
||||
struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
/* Orientation sensors */
|
||||
struct {
|
||||
float roll; /**< Rotation around the longitudinal axis (the plane body, 'X axis'). Roll is positive and increasing when moving downward. -90°<=roll<=90° */
|
||||
float pitch; /**< Rotation around the lateral axis (the wing span, 'Y axis'). Pitch is positive and increasing when moving upwards. -180°<=pitch<=180°) */
|
||||
float heading; /**< Angle between the longitudinal axis (the plane body) and magnetic north, measured clockwise when viewing from the top of the device. 0-359° */
|
||||
};
|
||||
};
|
||||
int8_t status;
|
||||
uint8_t reserved[3];
|
||||
} sensors_vec_t;
|
||||
|
||||
/** struct sensors_color_s is used to return color data in a common format. */
|
||||
typedef struct {
|
||||
union {
|
||||
float c[3];
|
||||
/* RGB color space */
|
||||
struct {
|
||||
float r; /**< Red component */
|
||||
float g; /**< Green component */
|
||||
float b; /**< Blue component */
|
||||
};
|
||||
};
|
||||
uint32_t rgba; /**< 24-bit RGBA value */
|
||||
} sensors_color_t;
|
||||
|
||||
/* Sensor event (36 bytes) */
|
||||
/** struct sensor_event_s is used to provide a single sensor event in a common format. */
|
||||
typedef struct
|
||||
{
|
||||
int32_t version; /**< must be sizeof(struct sensors_event_t) */
|
||||
int32_t sensor_id; /**< unique sensor identifier */
|
||||
int32_t type; /**< sensor type */
|
||||
int32_t reserved0; /**< reserved */
|
||||
int32_t timestamp; /**< time is in milliseconds */
|
||||
union
|
||||
{
|
||||
float data[4];
|
||||
sensors_vec_t acceleration; /**< acceleration values are in meter per second per second (m/s^2) */
|
||||
sensors_vec_t magnetic; /**< magnetic vector values are in micro-Tesla (uT) */
|
||||
sensors_vec_t orientation; /**< orientation values are in degrees */
|
||||
sensors_vec_t gyro; /**< gyroscope values are in rad/s */
|
||||
float temperature; /**< temperature is in degrees centigrade (Celsius) */
|
||||
float distance; /**< distance in centimeters */
|
||||
float light; /**< light in SI lux units */
|
||||
float pressure; /**< pressure in hectopascal (hPa) */
|
||||
float relative_humidity; /**< relative humidity in percent */
|
||||
float current; /**< current in milliamps (mA) */
|
||||
float voltage; /**< voltage in volts (V) */
|
||||
sensors_color_t color; /**< color in RGB component values */
|
||||
};
|
||||
} sensors_event_t;
|
||||
|
||||
/* Sensor details (40 bytes) */
|
||||
/** struct sensor_s is used to describe basic information about a specific sensor. */
|
||||
typedef struct
|
||||
{
|
||||
char name[12]; /**< sensor name */
|
||||
int32_t version; /**< version of the hardware + driver */
|
||||
int32_t sensor_id; /**< unique sensor identifier */
|
||||
int32_t type; /**< this sensor's type (ex. SENSOR_TYPE_LIGHT) */
|
||||
float max_value; /**< maximum value of this sensor's value in SI units */
|
||||
float min_value; /**< minimum value of this sensor's value in SI units */
|
||||
float resolution; /**< smallest difference between two values reported by this sensor */
|
||||
int32_t min_delay; /**< min delay in microseconds between events. zero = not a constant rate */
|
||||
} sensor_t;
|
||||
|
||||
class Adafruit_Sensor {
|
||||
public:
|
||||
// Constructor(s)
|
||||
Adafruit_Sensor() {}
|
||||
virtual ~Adafruit_Sensor() {}
|
||||
|
||||
// These must be defined by the subclass
|
||||
virtual void enableAutoRange(bool enabled) {};
|
||||
virtual bool getEvent(sensors_event_t*) = 0;
|
||||
virtual void getSensor(sensor_t*) = 0;
|
||||
|
||||
private:
|
||||
bool _autoRange;
|
||||
};
|
||||
|
||||
#endif
|
||||
221
libraries/Adafruit_Sensor/README.md
Normal file
221
libraries/Adafruit_Sensor/README.md
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
# Adafruit Unified Sensor Driver #
|
||||
|
||||
Many small embedded systems exist to collect data from sensors, analyse the data, and either take an appropriate action or send that sensor data to another system for processing.
|
||||
|
||||
One of the many challenges of embedded systems design is the fact that parts you used today may be out of production tomorrow, or system requirements may change and you may need to choose a different sensor down the road.
|
||||
|
||||
Creating new drivers is a relatively easy task, but integrating them into existing systems is both error prone and time consuming since sensors rarely use the exact same units of measurement.
|
||||
|
||||
By reducing all data to a single **sensors\_event\_t** 'type' and settling on specific, **standardised SI units** for each sensor family the same sensor types return values that are comparable with any other similar sensor. This enables you to switch sensor models with very little impact on the rest of the system, which can help mitigate some of the risks and problems of sensor availability and code reuse.
|
||||
|
||||
The unified sensor abstraction layer is also useful for data-logging and data-transmission since you only have one well-known type to log or transmit over the air or wire.
|
||||
|
||||
## Unified Sensor Drivers ##
|
||||
|
||||
The following drivers are based on the Adafruit Unified Sensor Driver:
|
||||
|
||||
**Accelerometers**
|
||||
- [Adafruit\_ADXL345](https://github.com/adafruit/Adafruit_ADXL345)
|
||||
- [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC)
|
||||
- [Adafruit\_MMA8451\_Library](https://github.com/adafruit/Adafruit_MMA8451_Library)
|
||||
|
||||
**Gyroscope**
|
||||
- [Adafruit\_L3GD20\_U](https://github.com/adafruit/Adafruit_L3GD20_U)
|
||||
|
||||
**Light**
|
||||
- [Adafruit\_TSL2561](https://github.com/adafruit/Adafruit_TSL2561)
|
||||
- [Adafruit\_TSL2591\_Library](https://github.com/adafruit/Adafruit_TSL2591_Library)
|
||||
|
||||
**Magnetometers**
|
||||
- [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC)
|
||||
- [Adafruit\_HMC5883\_Unified](https://github.com/adafruit/Adafruit_HMC5883_Unified)
|
||||
|
||||
**Barometric Pressure**
|
||||
- [Adafruit\_BMP085\_Unified](https://github.com/adafruit/Adafruit_BMP085_Unified)
|
||||
- [Adafruit\_BMP183\_Unified\_Library](https://github.com/adafruit/Adafruit_BMP183_Unified_Library)
|
||||
|
||||
**Humidity & Temperature**
|
||||
- [Adafruit\_DHT\_Unified](https://github.com/adafruit/Adafruit_DHT_Unified)
|
||||
|
||||
**Orientation**
|
||||
- [Adafruit_BNO055](https://github.com/adafruit/Adafruit_BNO055)
|
||||
|
||||
## How Does it Work? ##
|
||||
|
||||
Any driver that supports the Adafruit unified sensor abstraction layer will implement the Adafruit\_Sensor base class. There are two main typedefs and one enum defined in Adafruit_Sensor.h that are used to 'abstract' away the sensor details and values:
|
||||
|
||||
**Sensor Types (sensors\_type\_t)**
|
||||
|
||||
These pre-defined sensor types are used to properly handle the two related typedefs below, and allows us determine what types of units the sensor uses, etc.
|
||||
|
||||
```
|
||||
/** Sensor types */
|
||||
typedef enum
|
||||
{
|
||||
SENSOR_TYPE_ACCELEROMETER = (1),
|
||||
SENSOR_TYPE_MAGNETIC_FIELD = (2),
|
||||
SENSOR_TYPE_ORIENTATION = (3),
|
||||
SENSOR_TYPE_GYROSCOPE = (4),
|
||||
SENSOR_TYPE_LIGHT = (5),
|
||||
SENSOR_TYPE_PRESSURE = (6),
|
||||
SENSOR_TYPE_PROXIMITY = (8),
|
||||
SENSOR_TYPE_GRAVITY = (9),
|
||||
SENSOR_TYPE_LINEAR_ACCELERATION = (10),
|
||||
SENSOR_TYPE_ROTATION_VECTOR = (11),
|
||||
SENSOR_TYPE_RELATIVE_HUMIDITY = (12),
|
||||
SENSOR_TYPE_AMBIENT_TEMPERATURE = (13),
|
||||
SENSOR_TYPE_VOLTAGE = (15),
|
||||
SENSOR_TYPE_CURRENT = (16),
|
||||
SENSOR_TYPE_COLOR = (17)
|
||||
} sensors_type_t;
|
||||
```
|
||||
|
||||
**Sensor Details (sensor\_t)**
|
||||
|
||||
This typedef describes the specific capabilities of this sensor, and allows us to know what sensor we are using beneath the abstraction layer.
|
||||
|
||||
```
|
||||
/* Sensor details (40 bytes) */
|
||||
/** struct sensor_s is used to describe basic information about a specific sensor. */
|
||||
typedef struct
|
||||
{
|
||||
char name[12];
|
||||
int32_t version;
|
||||
int32_t sensor_id;
|
||||
int32_t type;
|
||||
float max_value;
|
||||
float min_value;
|
||||
float resolution;
|
||||
int32_t min_delay;
|
||||
} sensor_t;
|
||||
```
|
||||
|
||||
The individual fields are intended to be used as follows:
|
||||
|
||||
- **name**: The sensor name or ID, up to a maximum of twelve characters (ex. "MPL115A2")
|
||||
- **version**: The version of the sensor HW and the driver to allow us to differentiate versions of the board or driver
|
||||
- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network
|
||||
- **type**: The sensor type, based on **sensors\_type\_t** in sensors.h
|
||||
- **max\_value**: The maximum value that this sensor can return (in the appropriate SI unit)
|
||||
- **min\_value**: The minimum value that this sensor can return (in the appropriate SI unit)
|
||||
- **resolution**: The smallest difference between two values that this sensor can report (in the appropriate SI unit)
|
||||
- **min\_delay**: The minimum delay in microseconds between two sensor events, or '0' if there is no constant sensor rate
|
||||
|
||||
**Sensor Data/Events (sensors\_event\_t)**
|
||||
|
||||
This typedef is used to return sensor data from any sensor supported by the abstraction layer, using standard SI units and scales.
|
||||
|
||||
```
|
||||
/* Sensor event (36 bytes) */
|
||||
/** struct sensor_event_s is used to provide a single sensor event in a common format. */
|
||||
typedef struct
|
||||
{
|
||||
int32_t version;
|
||||
int32_t sensor_id;
|
||||
int32_t type;
|
||||
int32_t reserved0;
|
||||
int32_t timestamp;
|
||||
union
|
||||
{
|
||||
float data[4];
|
||||
sensors_vec_t acceleration;
|
||||
sensors_vec_t magnetic;
|
||||
sensors_vec_t orientation;
|
||||
sensors_vec_t gyro;
|
||||
float temperature;
|
||||
float distance;
|
||||
float light;
|
||||
float pressure;
|
||||
float relative_humidity;
|
||||
float current;
|
||||
float voltage;
|
||||
sensors_color_t color;
|
||||
};
|
||||
} sensors_event_t;
|
||||
```
|
||||
It includes the following fields:
|
||||
|
||||
- **version**: Contain 'sizeof(sensors\_event\_t)' to identify which version of the API we're using in case this changes in the future
|
||||
- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network (must match the sensor\_id value in the corresponding sensor\_t enum above!)
|
||||
- **type**: the sensor type, based on **sensors\_type\_t** in sensors.h
|
||||
- **timestamp**: time in milliseconds when the sensor value was read
|
||||
- **data[4]**: An array of four 32-bit values that allows us to encapsulate any type of sensor data via a simple union (further described below)
|
||||
|
||||
**Required Functions**
|
||||
|
||||
In addition to the two standard types and the sensor type enum, all drivers based on Adafruit_Sensor must also implement the following two functions:
|
||||
|
||||
```
|
||||
bool getEvent(sensors_event_t*);
|
||||
```
|
||||
Calling this function will populate the supplied sensors\_event\_t reference with the latest available sensor data. You should call this function as often as you want to update your data.
|
||||
|
||||
```
|
||||
void getSensor(sensor_t*);
|
||||
```
|
||||
Calling this function will provide some basic information about the sensor (the sensor name, driver version, min and max values, etc.
|
||||
|
||||
**Standardised SI values for sensors\_event\_t**
|
||||
|
||||
A key part of the abstraction layer is the standardisation of values on SI units of a particular scale, which is accomplished via the data[4] union in sensors\_event\_t above. This 16 byte union includes fields for each main sensor type, and uses the following SI units and scales:
|
||||
|
||||
- **acceleration**: values are in **meter per second per second** (m/s^2)
|
||||
- **magnetic**: values are in **micro-Tesla** (uT)
|
||||
- **orientation**: values are in **degrees**
|
||||
- **gyro**: values are in **rad/s**
|
||||
- **temperature**: values in **degrees centigrade** (Celsius)
|
||||
- **distance**: values are in **centimeters**
|
||||
- **light**: values are in **SI lux** units
|
||||
- **pressure**: values are in **hectopascal** (hPa)
|
||||
- **relative\_humidity**: values are in **percent**
|
||||
- **current**: values are in **milliamps** (mA)
|
||||
- **voltage**: values are in **volts** (V)
|
||||
- **color**: values are in 0..1.0 RGB channel luminosity and 32-bit RGBA format
|
||||
|
||||
## The Unified Driver Abstraction Layer in Practice ##
|
||||
|
||||
Using the unified sensor abstraction layer is relatively easy once a compliant driver has been created.
|
||||
|
||||
Every compliant sensor can now be read using a single, well-known 'type' (sensors\_event\_t), and there is a standardised way of interrogating a sensor about its specific capabilities (via sensor\_t).
|
||||
|
||||
An example of reading the [TSL2561](https://github.com/adafruit/Adafruit_TSL2561) light sensor can be seen below:
|
||||
|
||||
```
|
||||
Adafruit_TSL2561 tsl = Adafruit_TSL2561(TSL2561_ADDR_FLOAT, 12345);
|
||||
...
|
||||
/* Get a new sensor event */
|
||||
sensors_event_t event;
|
||||
tsl.getEvent(&event);
|
||||
|
||||
/* Display the results (light is measured in lux) */
|
||||
if (event.light)
|
||||
{
|
||||
Serial.print(event.light); Serial.println(" lux");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If event.light = 0 lux the sensor is probably saturated
|
||||
and no reliable data could be generated! */
|
||||
Serial.println("Sensor overload");
|
||||
}
|
||||
```
|
||||
|
||||
Similarly, we can get the basic technical capabilities of this sensor with the following code:
|
||||
|
||||
```
|
||||
sensor_t sensor;
|
||||
|
||||
sensor_t sensor;
|
||||
tsl.getSensor(&sensor);
|
||||
|
||||
/* Display the sensor details */
|
||||
Serial.println("------------------------------------");
|
||||
Serial.print ("Sensor: "); Serial.println(sensor.name);
|
||||
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
|
||||
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
|
||||
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux");
|
||||
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux");
|
||||
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux");
|
||||
Serial.println("------------------------------------");
|
||||
Serial.println("");
|
||||
```
|
||||
9
libraries/Adafruit_Sensor/library.properties
Normal file
9
libraries/Adafruit_Sensor/library.properties
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
name=Adafruit Unified Sensor
|
||||
version=1.0.2
|
||||
author=Adafruit <info@adafruit.com>
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=Required for all Adafruit Unified Sensor based libraries.
|
||||
paragraph=A unified sensor abstraction layer used by many Adafruit sensor libraries.
|
||||
category=Sensors
|
||||
url=https://github.com/adafruit/Adafruit_Sensor
|
||||
architectures=*
|
||||
81
libraries/Adafruit_Unified_Sensor/Adafruit_Sensor.cpp
Normal file
81
libraries/Adafruit_Unified_Sensor/Adafruit_Sensor.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#include "Adafruit_Sensor.h"
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Prints sensor information to serial console
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_Sensor::printSensorDetails(void) {
|
||||
sensor_t sensor;
|
||||
getSensor(&sensor);
|
||||
Serial.println(F("------------------------------------"));
|
||||
Serial.print(F("Sensor: "));
|
||||
Serial.println(sensor.name);
|
||||
Serial.print(F("Type: "));
|
||||
switch ((sensors_type_t)sensor.type) {
|
||||
case SENSOR_TYPE_ACCELEROMETER:
|
||||
Serial.print(F("Acceleration (m/s2)"));
|
||||
break;
|
||||
case SENSOR_TYPE_MAGNETIC_FIELD:
|
||||
Serial.print(F("Magnetic (uT)"));
|
||||
break;
|
||||
case SENSOR_TYPE_ORIENTATION:
|
||||
Serial.print(F("Orientation (degrees)"));
|
||||
break;
|
||||
case SENSOR_TYPE_GYROSCOPE:
|
||||
Serial.print(F("Gyroscopic (rad/s)"));
|
||||
break;
|
||||
case SENSOR_TYPE_LIGHT:
|
||||
Serial.print(F("Light (lux)"));
|
||||
break;
|
||||
case SENSOR_TYPE_PRESSURE:
|
||||
Serial.print(F("Pressure (hPa)"));
|
||||
break;
|
||||
case SENSOR_TYPE_PROXIMITY:
|
||||
Serial.print(F("Distance (cm)"));
|
||||
break;
|
||||
case SENSOR_TYPE_GRAVITY:
|
||||
Serial.print(F("Gravity (m/s2)"));
|
||||
break;
|
||||
case SENSOR_TYPE_LINEAR_ACCELERATION:
|
||||
Serial.print(F("Linear Acceleration (m/s2)"));
|
||||
break;
|
||||
case SENSOR_TYPE_ROTATION_VECTOR:
|
||||
Serial.print(F("Rotation vector"));
|
||||
break;
|
||||
case SENSOR_TYPE_RELATIVE_HUMIDITY:
|
||||
Serial.print(F("Relative Humidity (%)"));
|
||||
break;
|
||||
case SENSOR_TYPE_AMBIENT_TEMPERATURE:
|
||||
Serial.print(F("Ambient Temp (C)"));
|
||||
break;
|
||||
case SENSOR_TYPE_OBJECT_TEMPERATURE:
|
||||
Serial.print(F("Object Temp (C)"));
|
||||
break;
|
||||
case SENSOR_TYPE_VOLTAGE:
|
||||
Serial.print(F("Voltage (V)"));
|
||||
break;
|
||||
case SENSOR_TYPE_CURRENT:
|
||||
Serial.print(F("Current (mA)"));
|
||||
break;
|
||||
case SENSOR_TYPE_COLOR:
|
||||
Serial.print(F("Color (RGBA)"));
|
||||
break;
|
||||
case SENSOR_TYPE_TVOC:
|
||||
Serial.print(F("Total Volatile Organic Compounds (ppb)"));
|
||||
break;
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
Serial.print(F("Driver Ver: "));
|
||||
Serial.println(sensor.version);
|
||||
Serial.print(F("Unique ID: "));
|
||||
Serial.println(sensor.sensor_id);
|
||||
Serial.print(F("Min Value: "));
|
||||
Serial.println(sensor.min_value);
|
||||
Serial.print(F("Max Value: "));
|
||||
Serial.println(sensor.max_value);
|
||||
Serial.print(F("Resolution: "));
|
||||
Serial.println(sensor.resolution);
|
||||
Serial.println(F("------------------------------------\n"));
|
||||
}
|
||||
190
libraries/Adafruit_Unified_Sensor/Adafruit_Sensor.h
Normal file
190
libraries/Adafruit_Unified_Sensor/Adafruit_Sensor.h
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software< /span>
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and
|
||||
* extended sensor support to include color, voltage and current */
|
||||
|
||||
#ifndef _ADAFRUIT_SENSOR_H
|
||||
#define _ADAFRUIT_SENSOR_H
|
||||
|
||||
#ifndef ARDUINO
|
||||
#include <stdint.h>
|
||||
#elif ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#include "Print.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
/* Constants */
|
||||
#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */
|
||||
#define SENSORS_GRAVITY_MOON (1.6F) /**< The moon's gravity in m/s^2 */
|
||||
#define SENSORS_GRAVITY_SUN (275.0F) /**< The sun's gravity in m/s^2 */
|
||||
#define SENSORS_GRAVITY_STANDARD (SENSORS_GRAVITY_EARTH)
|
||||
#define SENSORS_MAGFIELD_EARTH_MAX \
|
||||
(60.0F) /**< Maximum magnetic field on Earth's surface */
|
||||
#define SENSORS_MAGFIELD_EARTH_MIN \
|
||||
(30.0F) /**< Minimum magnetic field on Earth's surface */
|
||||
#define SENSORS_PRESSURE_SEALEVELHPA \
|
||||
(1013.25F) /**< Average sea level pressure is 1013.25 hPa */
|
||||
#define SENSORS_DPS_TO_RADS \
|
||||
(0.017453293F) /**< Degrees/s to rad/s multiplier \
|
||||
*/
|
||||
#define SENSORS_RADS_TO_DPS \
|
||||
(57.29577793F) /**< Rad/s to degrees/s multiplier */
|
||||
#define SENSORS_GAUSS_TO_MICROTESLA \
|
||||
(100) /**< Gauss to micro-Tesla multiplier */
|
||||
|
||||
/** Sensor types */
|
||||
typedef enum {
|
||||
SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */
|
||||
SENSOR_TYPE_MAGNETIC_FIELD = (2),
|
||||
SENSOR_TYPE_ORIENTATION = (3),
|
||||
SENSOR_TYPE_GYROSCOPE = (4),
|
||||
SENSOR_TYPE_LIGHT = (5),
|
||||
SENSOR_TYPE_PRESSURE = (6),
|
||||
SENSOR_TYPE_PROXIMITY = (8),
|
||||
SENSOR_TYPE_GRAVITY = (9),
|
||||
SENSOR_TYPE_LINEAR_ACCELERATION =
|
||||
(10), /**< Acceleration not including gravity */
|
||||
SENSOR_TYPE_ROTATION_VECTOR = (11),
|
||||
SENSOR_TYPE_RELATIVE_HUMIDITY = (12),
|
||||
SENSOR_TYPE_AMBIENT_TEMPERATURE = (13),
|
||||
SENSOR_TYPE_OBJECT_TEMPERATURE = (14),
|
||||
SENSOR_TYPE_VOLTAGE = (15),
|
||||
SENSOR_TYPE_CURRENT = (16),
|
||||
SENSOR_TYPE_COLOR = (17),
|
||||
SENSOR_TYPE_TVOC = (18)
|
||||
} sensors_type_t;
|
||||
|
||||
/** struct sensors_vec_s is used to return a vector in a common format. */
|
||||
typedef struct {
|
||||
union {
|
||||
float v[3]; ///< 3D vector elements
|
||||
struct {
|
||||
float x; ///< X component of vector
|
||||
float y; ///< Y component of vector
|
||||
float z; ///< Z component of vector
|
||||
}; ///< Struct for holding XYZ component
|
||||
/* Orientation sensors */
|
||||
struct {
|
||||
float roll; /**< Rotation around the longitudinal axis (the plane body, 'X
|
||||
axis'). Roll is positive and increasing when moving
|
||||
downward. -90 degrees <= roll <= 90 degrees */
|
||||
float pitch; /**< Rotation around the lateral axis (the wing span, 'Y
|
||||
axis'). Pitch is positive and increasing when moving
|
||||
upwards. -180 degrees <= pitch <= 180 degrees) */
|
||||
float heading; /**< Angle between the longitudinal axis (the plane body)
|
||||
and magnetic north, measured clockwise when viewing from
|
||||
the top of the device. 0-359 degrees */
|
||||
}; ///< Struct for holding roll/pitch/heading
|
||||
}; ///< Union that can hold 3D vector array, XYZ components or
|
||||
///< roll/pitch/heading
|
||||
int8_t status; ///< Status byte
|
||||
uint8_t reserved[3]; ///< Reserved
|
||||
} sensors_vec_t;
|
||||
|
||||
/** struct sensors_color_s is used to return color data in a common format. */
|
||||
typedef struct {
|
||||
union {
|
||||
float c[3]; ///< Raw 3-element data
|
||||
/* RGB color space */
|
||||
struct {
|
||||
float r; /**< Red component */
|
||||
float g; /**< Green component */
|
||||
float b; /**< Blue component */
|
||||
}; ///< RGB data in floating point notation
|
||||
}; ///< Union of various ways to describe RGB colorspace
|
||||
uint32_t rgba; /**< 24-bit RGBA value */
|
||||
} sensors_color_t;
|
||||
|
||||
/* Sensor event (36 bytes) */
|
||||
/** struct sensor_event_s is used to provide a single sensor event in a common
|
||||
* format. */
|
||||
typedef struct {
|
||||
int32_t version; /**< must be sizeof(struct sensors_event_t) */
|
||||
int32_t sensor_id; /**< unique sensor identifier */
|
||||
int32_t type; /**< sensor type */
|
||||
int32_t reserved0; /**< reserved */
|
||||
int32_t timestamp; /**< time is in milliseconds */
|
||||
union {
|
||||
float data[4]; ///< Raw data
|
||||
sensors_vec_t acceleration; /**< acceleration values are in meter per second
|
||||
per second (m/s^2) */
|
||||
sensors_vec_t
|
||||
magnetic; /**< magnetic vector values are in micro-Tesla (uT) */
|
||||
sensors_vec_t orientation; /**< orientation values are in degrees */
|
||||
sensors_vec_t gyro; /**< gyroscope values are in rad/s */
|
||||
float temperature; /**< temperature is in degrees centigrade (Celsius) */
|
||||
float distance; /**< distance in centimeters */
|
||||
float light; /**< light in SI lux units */
|
||||
float pressure; /**< pressure in hectopascal (hPa) */
|
||||
float relative_humidity; /**< relative humidity in percent */
|
||||
float current; /**< current in milliamps (mA) */
|
||||
float voltage; /**< voltage in volts (V) */
|
||||
float tvoc; /**< Total Volatile Organic Compounds, in ppb */
|
||||
sensors_color_t color; /**< color in RGB component values */
|
||||
}; ///< Union for the wide ranges of data we can carry
|
||||
} sensors_event_t;
|
||||
|
||||
/* Sensor details (40 bytes) */
|
||||
/** struct sensor_s is used to describe basic information about a specific
|
||||
* sensor. */
|
||||
typedef struct {
|
||||
char name[12]; /**< sensor name */
|
||||
int32_t version; /**< version of the hardware + driver */
|
||||
int32_t sensor_id; /**< unique sensor identifier */
|
||||
int32_t type; /**< this sensor's type (ex. SENSOR_TYPE_LIGHT) */
|
||||
float max_value; /**< maximum value of this sensor's value in SI units */
|
||||
float min_value; /**< minimum value of this sensor's value in SI units */
|
||||
float resolution; /**< smallest difference between two values reported by this
|
||||
sensor */
|
||||
int32_t min_delay; /**< min delay in microseconds between events. zero = not a
|
||||
constant rate */
|
||||
} sensor_t;
|
||||
|
||||
/** @brief Common sensor interface to unify various sensors.
|
||||
* Intentionally modeled after sensors.h in the Android API:
|
||||
* https://github.com/android/platform_hardware_libhardware/blob/master/include/hardware/sensors.h
|
||||
*/
|
||||
class Adafruit_Sensor {
|
||||
public:
|
||||
// Constructor(s)
|
||||
Adafruit_Sensor() {}
|
||||
virtual ~Adafruit_Sensor() {}
|
||||
|
||||
// These must be defined by the subclass
|
||||
|
||||
/*! @brief Whether we should automatically change the range (if possible) for
|
||||
higher precision
|
||||
@param enabled True if we will try to autorange */
|
||||
virtual void enableAutoRange(bool enabled) {
|
||||
(void)enabled; /* suppress unused warning */
|
||||
};
|
||||
|
||||
/*! @brief Get the latest sensor event
|
||||
@returns True if able to fetch an event */
|
||||
virtual bool getEvent(sensors_event_t *) = 0;
|
||||
/*! @brief Get info about the sensor itself */
|
||||
virtual void getSensor(sensor_t *) = 0;
|
||||
|
||||
void printSensorDetails(void);
|
||||
|
||||
private:
|
||||
bool _autoRange;
|
||||
};
|
||||
|
||||
#endif
|
||||
202
libraries/Adafruit_Unified_Sensor/LICENSE.txt
Normal file
202
libraries/Adafruit_Unified_Sensor/LICENSE.txt
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
229
libraries/Adafruit_Unified_Sensor/README.md
Normal file
229
libraries/Adafruit_Unified_Sensor/README.md
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
# Adafruit Unified Sensor Driver #
|
||||
|
||||
Many small embedded systems exist to collect data from sensors, analyse the data, and either take an appropriate action or send that sensor data to another system for processing.
|
||||
|
||||
One of the many challenges of embedded systems design is the fact that parts you used today may be out of production tomorrow, or system requirements may change and you may need to choose a different sensor down the road.
|
||||
|
||||
Creating new drivers is a relatively easy task, but integrating them into existing systems is both error prone and time consuming since sensors rarely use the exact same units of measurement.
|
||||
|
||||
By reducing all data to a single **sensors\_event\_t** 'type' and settling on specific, **standardised SI units** for each sensor family the same sensor types return values that are comparable with any other similar sensor. This enables you to switch sensor models with very little impact on the rest of the system, which can help mitigate some of the risks and problems of sensor availability and code reuse.
|
||||
|
||||
The unified sensor abstraction layer is also useful for data-logging and data-transmission since you only have one well-known type to log or transmit over the air or wire.
|
||||
|
||||
## Unified Sensor Drivers ##
|
||||
|
||||
The following drivers are based on the Adafruit Unified Sensor Driver:
|
||||
|
||||
**Accelerometers**
|
||||
- [Adafruit\_ADXL345](https://github.com/adafruit/Adafruit_ADXL345)
|
||||
- [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC)
|
||||
- [Adafruit\_MMA8451\_Library](https://github.com/adafruit/Adafruit_MMA8451_Library)
|
||||
|
||||
**Gyroscope**
|
||||
- [Adafruit\_L3GD20\_U](https://github.com/adafruit/Adafruit_L3GD20_U)
|
||||
|
||||
**Light**
|
||||
- [Adafruit\_TSL2561](https://github.com/adafruit/Adafruit_TSL2561)
|
||||
- [Adafruit\_TSL2591\_Library](https://github.com/adafruit/Adafruit_TSL2591_Library)
|
||||
|
||||
**Magnetometers**
|
||||
- [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC)
|
||||
- [Adafruit\_HMC5883\_Unified](https://github.com/adafruit/Adafruit_HMC5883_Unified)
|
||||
|
||||
**Barometric Pressure**
|
||||
- [Adafruit\_BMP085\_Unified](https://github.com/adafruit/Adafruit_BMP085_Unified)
|
||||
- [Adafruit\_BMP183\_Unified\_Library](https://github.com/adafruit/Adafruit_BMP183_Unified_Library)
|
||||
|
||||
**Humidity & Temperature**
|
||||
- [DHT-sensor-library](https://github.com/adafruit/DHT-sensor-library)
|
||||
|
||||
**Humidity, Temperature, & Barometric Pressure**
|
||||
- [Adafruit_BME280_Library](https://github.com/adafruit/Adafruit_BME280_Library/)
|
||||
|
||||
**Orientation**
|
||||
- [Adafruit_BNO055](https://github.com/adafruit/Adafruit_BNO055)
|
||||
|
||||
**All in one device**
|
||||
- [Adafruit_LSM9DS0](https://github.com/adafruit/Adafruit_LSM9DS0_Library) (accelerometer, gyroscope, magnetometer)
|
||||
- [Adafruit_LSM9DS1](https://github.com/adafruit/Adafruit_LSM9DS1/) (accelerometer, gyroscope, magnetometer)
|
||||
|
||||
|
||||
## How Does it Work? ##
|
||||
|
||||
Any driver that supports the Adafruit unified sensor abstraction layer will implement the Adafruit\_Sensor base class. There are two main typedefs and one enum defined in Adafruit_Sensor.h that are used to 'abstract' away the sensor details and values:
|
||||
|
||||
## Sensor Types (`sensors_type_t`)
|
||||
|
||||
These pre-defined sensor types are used to properly handle the two related typedefs below, and allows us determine what types of units the sensor uses, etc.
|
||||
|
||||
```c++
|
||||
/** Sensor types */
|
||||
typedef enum
|
||||
{
|
||||
SENSOR_TYPE_ACCELEROMETER = (1),
|
||||
SENSOR_TYPE_MAGNETIC_FIELD = (2),
|
||||
SENSOR_TYPE_ORIENTATION = (3),
|
||||
SENSOR_TYPE_GYROSCOPE = (4),
|
||||
SENSOR_TYPE_LIGHT = (5),
|
||||
SENSOR_TYPE_PRESSURE = (6),
|
||||
SENSOR_TYPE_PROXIMITY = (8),
|
||||
SENSOR_TYPE_GRAVITY = (9),
|
||||
SENSOR_TYPE_LINEAR_ACCELERATION = (10),
|
||||
SENSOR_TYPE_ROTATION_VECTOR = (11),
|
||||
SENSOR_TYPE_RELATIVE_HUMIDITY = (12),
|
||||
SENSOR_TYPE_AMBIENT_TEMPERATURE = (13),
|
||||
SENSOR_TYPE_VOLTAGE = (15),
|
||||
SENSOR_TYPE_CURRENT = (16),
|
||||
SENSOR_TYPE_COLOR = (17)
|
||||
} sensors_type_t;
|
||||
```
|
||||
|
||||
## Sensor Details (`sensor_t`)
|
||||
|
||||
This typedef describes the specific capabilities of this sensor, and allows us to know what sensor we are using beneath the abstraction layer.
|
||||
|
||||
```c++
|
||||
/* Sensor details (40 bytes) */
|
||||
/** struct sensor_s is used to describe basic information about a specific sensor. */
|
||||
typedef struct
|
||||
{
|
||||
char name[12];
|
||||
int32_t version;
|
||||
int32_t sensor_id;
|
||||
int32_t type;
|
||||
float max_value;
|
||||
float min_value;
|
||||
float resolution;
|
||||
int32_t min_delay;
|
||||
} sensor_t;
|
||||
```
|
||||
|
||||
The individual fields are intended to be used as follows:
|
||||
|
||||
- **name**: The sensor name or ID, up to a maximum of twelve characters (ex. "MPL115A2")
|
||||
- **version**: The version of the sensor HW and the driver to allow us to differentiate versions of the board or driver
|
||||
- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network
|
||||
- **type**: The sensor type, based on **sensors\_type\_t** in sensors.h
|
||||
- **max\_value**: The maximum value that this sensor can return (in the appropriate SI unit)
|
||||
- **min\_value**: The minimum value that this sensor can return (in the appropriate SI unit)
|
||||
- **resolution**: The smallest difference between two values that this sensor can report (in the appropriate SI unit)
|
||||
- **min\_delay**: The minimum delay in microseconds between two sensor events, or '0' if there is no constant sensor rate
|
||||
|
||||
## Sensor Data/Events (`sensors_event_t`)
|
||||
|
||||
This typedef is used to return sensor data from any sensor supported by the abstraction layer, using standard SI units and scales.
|
||||
|
||||
```c++
|
||||
/* Sensor event (36 bytes) */
|
||||
/** struct sensor_event_s is used to provide a single sensor event in a common format. */
|
||||
typedef struct
|
||||
{
|
||||
int32_t version;
|
||||
int32_t sensor_id;
|
||||
int32_t type;
|
||||
int32_t reserved0;
|
||||
int32_t timestamp;
|
||||
union
|
||||
{
|
||||
float data[4];
|
||||
sensors_vec_t acceleration;
|
||||
sensors_vec_t magnetic;
|
||||
sensors_vec_t orientation;
|
||||
sensors_vec_t gyro;
|
||||
float temperature;
|
||||
float distance;
|
||||
float light;
|
||||
float pressure;
|
||||
float relative_humidity;
|
||||
float current;
|
||||
float voltage;
|
||||
sensors_color_t color;
|
||||
};
|
||||
} sensors_event_t;
|
||||
```
|
||||
It includes the following fields:
|
||||
|
||||
- **version**: Contain 'sizeof(sensors\_event\_t)' to identify which version of the API we're using in case this changes in the future
|
||||
- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network (must match the sensor\_id value in the corresponding sensor\_t enum above!)
|
||||
- **type**: the sensor type, based on **sensors\_type\_t** in sensors.h
|
||||
- **timestamp**: time in milliseconds when the sensor value was read
|
||||
- **data[4]**: An array of four 32-bit values that allows us to encapsulate any type of sensor data via a simple union (further described below)
|
||||
|
||||
## Required Functions
|
||||
|
||||
In addition to the two standard types and the sensor type enum, all drivers based on Adafruit_Sensor must also implement the following two functions:
|
||||
|
||||
```c++
|
||||
bool getEvent(sensors_event_t*);
|
||||
```
|
||||
Calling this function will populate the supplied sensors\_event\_t reference with the latest available sensor data. You should call this function as often as you want to update your data.
|
||||
|
||||
```c++
|
||||
void getSensor(sensor_t*);
|
||||
```
|
||||
Calling this function will provide some basic information about the sensor (the sensor name, driver version, min and max values, etc.
|
||||
|
||||
## Standardised SI values for `sensors_event_t`
|
||||
|
||||
A key part of the abstraction layer is the standardisation of values on SI units of a particular scale, which is accomplished via the data[4] union in sensors\_event\_t above. This 16 byte union includes fields for each main sensor type, and uses the following SI units and scales:
|
||||
|
||||
- **acceleration**: values are in **meter per second per second** (m/s^2)
|
||||
- **magnetic**: values are in **micro-Tesla** (uT)
|
||||
- **orientation**: values are in **degrees**
|
||||
- **gyro**: values are in **rad/s**
|
||||
- **temperature**: values in **degrees centigrade** (Celsius)
|
||||
- **distance**: values are in **centimeters**
|
||||
- **light**: values are in **SI lux** units
|
||||
- **pressure**: values are in **hectopascal** (hPa)
|
||||
- **relative\_humidity**: values are in **percent**
|
||||
- **current**: values are in **milliamps** (mA)
|
||||
- **voltage**: values are in **volts** (V)
|
||||
- **color**: values are in 0..1.0 RGB channel luminosity and 32-bit RGBA format
|
||||
|
||||
## The Unified Driver Abstraction Layer in Practice ##
|
||||
|
||||
Using the unified sensor abstraction layer is relatively easy once a compliant driver has been created.
|
||||
|
||||
Every compliant sensor can now be read using a single, well-known 'type' (sensors\_event\_t), and there is a standardised way of interrogating a sensor about its specific capabilities (via sensor\_t).
|
||||
|
||||
An example of reading the [TSL2561](https://github.com/adafruit/Adafruit_TSL2561) light sensor can be seen below:
|
||||
|
||||
```c++
|
||||
Adafruit_TSL2561 tsl = Adafruit_TSL2561(TSL2561_ADDR_FLOAT, 12345);
|
||||
...
|
||||
/* Get a new sensor event */
|
||||
sensors_event_t event;
|
||||
tsl.getEvent(&event);
|
||||
|
||||
/* Display the results (light is measured in lux) */
|
||||
if (event.light)
|
||||
{
|
||||
Serial.print(event.light); Serial.println(" lux");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If event.light = 0 lux the sensor is probably saturated
|
||||
and no reliable data could be generated! */
|
||||
Serial.println("Sensor overload");
|
||||
}
|
||||
```
|
||||
|
||||
Similarly, we can get the basic technical capabilities of this sensor with the following code:
|
||||
|
||||
```c++
|
||||
sensor_t sensor;
|
||||
|
||||
sensor_t sensor;
|
||||
tsl.getSensor(&sensor);
|
||||
|
||||
/* Display the sensor details */
|
||||
Serial.println("------------------------------------");
|
||||
Serial.print ("Sensor: "); Serial.println(sensor.name);
|
||||
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
|
||||
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
|
||||
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux");
|
||||
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux");
|
||||
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux");
|
||||
Serial.println("------------------------------------");
|
||||
Serial.println("");
|
||||
```
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_ADXL343.h>
|
||||
|
||||
/* Assign a unique ID to this sensor at the same time */
|
||||
/* Uncomment following line for default Wire bus */
|
||||
Adafruit_ADXL343 accel = Adafruit_ADXL343(12345);
|
||||
|
||||
/* NeoTrellis M4, etc. */
|
||||
/* Uncomment following line for Wire1 bus */
|
||||
//Adafruit_ADXL343 accel = Adafruit_ADXL343(12345, &Wire1);
|
||||
|
||||
void displaySensorDetails(void)
|
||||
{
|
||||
sensor_t sensor;
|
||||
accel.getSensor(&sensor);
|
||||
Serial.println("------------------------------------");
|
||||
Serial.print ("Sensor: "); Serial.println(sensor.name);
|
||||
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
|
||||
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
|
||||
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" m/s^2");
|
||||
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" m/s^2");
|
||||
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" m/s^2");
|
||||
Serial.println("------------------------------------");
|
||||
Serial.println("");
|
||||
delay(500);
|
||||
}
|
||||
|
||||
void displayDataRate(void)
|
||||
{
|
||||
Serial.print ("Data Rate: ");
|
||||
|
||||
switch(accel.getDataRate())
|
||||
{
|
||||
case ADXL343_DATARATE_3200_HZ:
|
||||
Serial.print ("3200 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_1600_HZ:
|
||||
Serial.print ("1600 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_800_HZ:
|
||||
Serial.print ("800 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_400_HZ:
|
||||
Serial.print ("400 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_200_HZ:
|
||||
Serial.print ("200 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_100_HZ:
|
||||
Serial.print ("100 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_50_HZ:
|
||||
Serial.print ("50 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_25_HZ:
|
||||
Serial.print ("25 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_12_5_HZ:
|
||||
Serial.print ("12.5 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_6_25HZ:
|
||||
Serial.print ("6.25 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_3_13_HZ:
|
||||
Serial.print ("3.13 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_1_56_HZ:
|
||||
Serial.print ("1.56 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_0_78_HZ:
|
||||
Serial.print ("0.78 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_0_39_HZ:
|
||||
Serial.print ("0.39 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_0_20_HZ:
|
||||
Serial.print ("0.20 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_0_10_HZ:
|
||||
Serial.print ("0.10 ");
|
||||
break;
|
||||
default:
|
||||
Serial.print ("???? ");
|
||||
break;
|
||||
}
|
||||
Serial.println(" Hz");
|
||||
}
|
||||
|
||||
void displayRange(void)
|
||||
{
|
||||
Serial.print ("Range: +/- ");
|
||||
|
||||
switch(accel.getRange())
|
||||
{
|
||||
case ADXL343_RANGE_16_G:
|
||||
Serial.print ("16 ");
|
||||
break;
|
||||
case ADXL343_RANGE_8_G:
|
||||
Serial.print ("8 ");
|
||||
break;
|
||||
case ADXL343_RANGE_4_G:
|
||||
Serial.print ("4 ");
|
||||
break;
|
||||
case ADXL343_RANGE_2_G:
|
||||
Serial.print ("2 ");
|
||||
break;
|
||||
default:
|
||||
Serial.print ("?? ");
|
||||
break;
|
||||
}
|
||||
Serial.println(" g");
|
||||
}
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(9600);
|
||||
while (!Serial);
|
||||
Serial.println("Accelerometer Test"); Serial.println("");
|
||||
|
||||
/* Initialise the sensor */
|
||||
if(!accel.begin())
|
||||
{
|
||||
/* There was a problem detecting the ADXL343 ... check your connections */
|
||||
Serial.println("Ooops, no ADXL343 detected ... Check your wiring!");
|
||||
while(1);
|
||||
}
|
||||
|
||||
/* Set the range to whatever is appropriate for your project */
|
||||
accel.setRange(ADXL343_RANGE_16_G);
|
||||
// accel.setRange(ADXL343_RANGE_8_G);
|
||||
// accel.setRange(ADXL343_RANGE_4_G);
|
||||
// accel.setRange(ADXL343_RANGE_2_G);
|
||||
|
||||
/* Display some basic information on this sensor */
|
||||
displaySensorDetails();
|
||||
displayDataRate();
|
||||
displayRange();
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
/* Get a new sensor event */
|
||||
sensors_event_t event;
|
||||
accel.getEvent(&event);
|
||||
|
||||
/* Display the results (acceleration is measured in m/s^2) */
|
||||
Serial.print("X: "); Serial.print(event.acceleration.x); Serial.print(" ");
|
||||
Serial.print("Y: "); Serial.print(event.acceleration.y); Serial.print(" ");
|
||||
Serial.print("Z: "); Serial.print(event.acceleration.z); Serial.print(" ");Serial.println("m/s^2 ");
|
||||
delay(500);
|
||||
}
|
||||
11
libraries/Adafruit_Unified_Sensor/library.properties
Normal file
11
libraries/Adafruit_Unified_Sensor/library.properties
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
name=Adafruit Unified Sensor
|
||||
version=1.1.6
|
||||
author=Adafruit <info@adafruit.com>
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=Required for all Adafruit Unified Sensor based libraries.
|
||||
paragraph=A unified sensor abstraction layer used by many Adafruit sensor libraries.
|
||||
category=Sensors
|
||||
url=https://github.com/adafruit/Adafruit_Sensor
|
||||
architectures=*
|
||||
includes=Adafruit_Sensor.h
|
||||
|
||||
324
libraries/ByteBuffer/ByteBuffer.cpp
Executable file
324
libraries/ByteBuffer/ByteBuffer.cpp
Executable file
|
|
@ -0,0 +1,324 @@
|
|||
/*
|
||||
ByteBuffer.cpp - A circular buffer implementation for Arduino
|
||||
Created by Sigurdur Orn, July 19, 2010.
|
||||
siggi@mit.edu
|
||||
Updated by GreyGnome (aka Mike Schwager) Mon Apr 8 21:11:15 CDT 2013
|
||||
Fixed putString() so it reenables inputs correctly. In the if (length == capacity) section,
|
||||
it was missing this line:
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
Updated by GreyGnome (aka Mike Schwager) Thu Feb 23 17:25:14 CST 2012
|
||||
added the putString() method and the fillError variable.
|
||||
added the checkError() and resetError() methods. The checkError() method resets the fillError variable
|
||||
to false as a side effect.
|
||||
added the ByteBuffer(unsigned int buf_size) constructor.
|
||||
added the init() method, and had the constructor call it automagically.
|
||||
Also made the capacity, position, length, and fillError variables volatile, for safe use by interrupts.
|
||||
Mon Dec 3 07:55:04 CST 2012
|
||||
Added the putHex() and putDec() methods.
|
||||
*/
|
||||
|
||||
#include "ByteBuffer.h"
|
||||
|
||||
void ByteBuffer::init(){
|
||||
ByteBuffer::init(DEFAULTBUFSIZE);
|
||||
}
|
||||
|
||||
void ByteBuffer::init(unsigned int buf_length){
|
||||
data = (byte*)malloc(sizeof(byte)*buf_length);
|
||||
capacity = buf_length;
|
||||
position = 0;
|
||||
length = 0;
|
||||
fillError=false;
|
||||
}
|
||||
|
||||
// Arduino 1.0: free() doesn't free. :-( This is a no-op as of 11/2012.
|
||||
void ByteBuffer::deAllocate(){
|
||||
free(data);
|
||||
}
|
||||
|
||||
void ByteBuffer::clear(){
|
||||
position = 0;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
void ByteBuffer::resetError(){
|
||||
fillError=false;
|
||||
}
|
||||
|
||||
boolean ByteBuffer::checkError(){
|
||||
/*
|
||||
if (fillError) {
|
||||
Serial.print("E: checkError: length ");
|
||||
Serial.println(length, DEC);
|
||||
}
|
||||
*/
|
||||
|
||||
boolean result=fillError;
|
||||
fillError=false;
|
||||
return(result);
|
||||
}
|
||||
|
||||
int ByteBuffer::getSize(){
|
||||
return length;
|
||||
}
|
||||
|
||||
int ByteBuffer::getCapacity(){
|
||||
return capacity;
|
||||
}
|
||||
|
||||
byte ByteBuffer::peek(unsigned int index){
|
||||
byte b = data[(position+index)%capacity];
|
||||
return b;
|
||||
}
|
||||
|
||||
uint8_t ByteBuffer::put(byte in){
|
||||
if(length < capacity){
|
||||
// save data byte at end of buffer
|
||||
data[(position+length) % capacity] = in;
|
||||
// increment the length
|
||||
length++;
|
||||
return 1;
|
||||
}
|
||||
// return failure
|
||||
//Serial.print("E: put: ");
|
||||
//Serial.println(length, DEC);
|
||||
fillError=true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint8_t ByteBuffer::putString(const char *in) {
|
||||
return(putString((char *) in));
|
||||
}
|
||||
|
||||
uint8_t ByteBuffer::putString(char *in){
|
||||
uint8_t count=0;
|
||||
char *inString;
|
||||
|
||||
inString=in;
|
||||
uint8_t oldSREG = SREG; cli();
|
||||
while(length <= capacity){
|
||||
if (length == capacity) {
|
||||
fillError=true;
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return count;
|
||||
}
|
||||
// save data byte at end of buffer
|
||||
data[(position+length) % capacity] = *inString;
|
||||
// increment the length
|
||||
length++;
|
||||
inString++;
|
||||
count++;
|
||||
if (*inString == 0) {
|
||||
if (count==0) fillError=true; // Serial.println("E: putString"); };
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return count;
|
||||
}
|
||||
}
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t ByteBuffer::putInFront(byte in){
|
||||
uint8_t oldSREG = SREG; cli();
|
||||
if(length < capacity){
|
||||
// save data byte at end of buffer
|
||||
if( position == 0 )
|
||||
position = capacity-1;
|
||||
else
|
||||
position = (position-1)%capacity;
|
||||
data[position] = in;
|
||||
// increment the length
|
||||
length++;
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return 1;
|
||||
}
|
||||
// return failure
|
||||
//Serial.println("E: putInFront");
|
||||
fillError=true;
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns 0 if length of data is 0.
|
||||
byte ByteBuffer::get(){
|
||||
uint8_t oldSREG = SREG; cli();
|
||||
byte b = 0;
|
||||
|
||||
if(length > 0){
|
||||
b = data[position];
|
||||
// move index down and decrement length
|
||||
position = (position+1)%capacity;
|
||||
length--;
|
||||
}
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return b;
|
||||
}
|
||||
|
||||
byte ByteBuffer::getFromBack(){
|
||||
byte b = 0;
|
||||
if(length > 0){
|
||||
uint8_t oldSREG = SREG; cli();
|
||||
b = data[(position+length-1)%capacity];
|
||||
length--;
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
//
|
||||
// Ints
|
||||
//
|
||||
|
||||
void ByteBuffer::putIntInFront(int in){
|
||||
byte *pointer = (byte *)∈
|
||||
putInFront(pointer[0]);
|
||||
putInFront(pointer[1]);
|
||||
}
|
||||
|
||||
void ByteBuffer::putInt(int in){
|
||||
byte *pointer = (byte *)∈
|
||||
put(pointer[1]);
|
||||
put(pointer[0]);
|
||||
}
|
||||
|
||||
|
||||
int ByteBuffer::getInt(){
|
||||
int ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[1] = get();
|
||||
pointer[0] = get();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ByteBuffer::getIntFromBack(){
|
||||
int ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[0] = getFromBack();
|
||||
pointer[1] = getFromBack();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ByteBuffer::putHex(uint8_t theByte) {
|
||||
put('0'); put('x');
|
||||
uint8_t hinybble=theByte>>4;
|
||||
uint8_t lonybble=theByte & 0x0F;
|
||||
uint8_t addend=0;
|
||||
if (hinybble >= 0x0a) addend=7;
|
||||
put(hinybble+48+addend);
|
||||
if (lonybble >= 0x0a) addend=7;
|
||||
else addend=0;
|
||||
put(lonybble+48+addend);
|
||||
}
|
||||
|
||||
void ByteBuffer::putDec(uint8_t number) {
|
||||
uint8_t hundreds=0;
|
||||
uint8_t tens=0;
|
||||
uint8_t ones=0;
|
||||
uint8_t tmp=number;
|
||||
|
||||
while (tmp >= 100 ) {
|
||||
hundreds++;
|
||||
tmp-=100;
|
||||
}
|
||||
while (tmp >= 10 ) {
|
||||
tens++;
|
||||
tmp-=10;
|
||||
}
|
||||
ones=tmp;
|
||||
hundreds+=48; tens+=48; ones+=48;
|
||||
if (number >= 100) { put(hundreds); }
|
||||
if (number >= 10) { put(tens); }
|
||||
put(ones);
|
||||
}
|
||||
|
||||
void ByteBuffer::putDec(int8_t number) {
|
||||
uint8_t absNumber=abs(number);
|
||||
if (number < 0) put('-');
|
||||
putDec(absNumber);
|
||||
}
|
||||
|
||||
//
|
||||
// Longs
|
||||
//
|
||||
|
||||
void ByteBuffer::putLongInFront(long in){
|
||||
byte *pointer = (byte *)∈
|
||||
putInFront(pointer[0]);
|
||||
putInFront(pointer[1]);
|
||||
putInFront(pointer[2]);
|
||||
putInFront(pointer[3]);
|
||||
}
|
||||
|
||||
void ByteBuffer::putLong(long in){
|
||||
byte *pointer = (byte *)∈
|
||||
put(pointer[3]);
|
||||
put(pointer[2]);
|
||||
put(pointer[1]);
|
||||
put(pointer[0]);
|
||||
}
|
||||
|
||||
|
||||
long ByteBuffer::getLong(){
|
||||
long ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[3] = get();
|
||||
pointer[2] = get();
|
||||
pointer[1] = get();
|
||||
pointer[0] = get();
|
||||
return ret;
|
||||
}
|
||||
|
||||
long ByteBuffer::getLongFromBack(){
|
||||
long ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[0] = getFromBack();
|
||||
pointer[1] = getFromBack();
|
||||
pointer[2] = getFromBack();
|
||||
pointer[3] = getFromBack();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Floats
|
||||
//
|
||||
|
||||
void ByteBuffer::putFloatInFront(float in){
|
||||
byte *pointer = (byte *)∈
|
||||
putInFront(pointer[0]);
|
||||
putInFront(pointer[1]);
|
||||
putInFront(pointer[2]);
|
||||
putInFront(pointer[3]);
|
||||
}
|
||||
|
||||
void ByteBuffer::putFloat(float in){
|
||||
byte *pointer = (byte *)∈
|
||||
put(pointer[3]);
|
||||
put(pointer[2]);
|
||||
put(pointer[1]);
|
||||
put(pointer[0]);
|
||||
}
|
||||
|
||||
float ByteBuffer::getFloat(){
|
||||
float ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[3] = get();
|
||||
pointer[2] = get();
|
||||
pointer[1] = get();
|
||||
pointer[0] = get();
|
||||
return ret;
|
||||
}
|
||||
|
||||
float ByteBuffer::getFloatFromBack(){
|
||||
float ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[0] = getFromBack();
|
||||
pointer[1] = getFromBack();
|
||||
pointer[2] = getFromBack();
|
||||
pointer[3] = getFromBack();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
109
libraries/ByteBuffer/ByteBuffer.h
Executable file
109
libraries/ByteBuffer/ByteBuffer.h
Executable file
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
ByteBuffer.h - A circular buffer implementation for Arduino
|
||||
Created by Sigurdur Orn, July 19, 2010. siggi@mit.edu
|
||||
Updated by GreyGnome (aka Mike Schwager) Thu Feb 23 17:25:14 CST 2012
|
||||
added the putString() method and the fillError variable.
|
||||
added the checkError() and resetError() methods. The checkError() method resets the fillError variable
|
||||
to false as a side effect.
|
||||
added the ByteBuffer(unsigned int buf_size) constructor.
|
||||
added the init() method, and had the constructor call it automagically.
|
||||
protected certain sections of the code with cli()/sei() calls, for safe use by interrupts.
|
||||
Also made the capacity, position, length, and fillError variables volatile, for safe use by interrupts.
|
||||
*/
|
||||
|
||||
#ifndef ByteBuffer_h
|
||||
#define ByteBuffer_h
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
//#include <util/atomic.h>
|
||||
|
||||
#define DEFAULTBUFSIZE 32
|
||||
class ByteBuffer
|
||||
{
|
||||
public:
|
||||
ByteBuffer() {
|
||||
init();
|
||||
};
|
||||
ByteBuffer(unsigned int buf_size) {
|
||||
init(buf_size);
|
||||
};
|
||||
|
||||
// This method initializes the datastore of the buffer to a certain size.
|
||||
void init(unsigned int buf_size);
|
||||
|
||||
// This method initializes the datastore of the buffer to the default size.
|
||||
void init();
|
||||
|
||||
// This method resets the buffer into an original state (with no data)
|
||||
void clear();
|
||||
|
||||
// This method resets the fillError variable to false.
|
||||
void resetError();
|
||||
|
||||
// This method tells you if your buffer overflowed at some time since the last
|
||||
// check. The error state will be reset to false.
|
||||
boolean checkError();
|
||||
|
||||
// This releases resources for this buffer, after this has been called the buffer should NOT be used
|
||||
void deAllocate();
|
||||
|
||||
// Returns how much space is used in the buffer
|
||||
int getSize();
|
||||
|
||||
// Returns the maximum capacity of the buffer
|
||||
int getCapacity();
|
||||
|
||||
// This method returns the byte that is located at index in the buffer but doesn't modify the buffer like the get methods (doesn't remove the retured byte from the buffer)
|
||||
byte peek(unsigned int index);
|
||||
|
||||
//
|
||||
// Put methods, either a regular put in back or put in front
|
||||
//
|
||||
uint8_t putInFront(byte in);
|
||||
uint8_t put(byte in);
|
||||
uint8_t putString(const char *in);
|
||||
uint8_t putString(char *in);
|
||||
|
||||
void putIntInFront(int in);
|
||||
void putInt(int in);
|
||||
|
||||
void putHex(uint8_t in);
|
||||
void putDec(uint8_t in);
|
||||
void putDec(int8_t in);
|
||||
|
||||
void putLongInFront(long in);
|
||||
void putLong(long in);
|
||||
|
||||
void putFloatInFront(float in);
|
||||
void putFloat(float in);
|
||||
|
||||
//
|
||||
// Get methods, either a regular get from front or from back
|
||||
//
|
||||
byte get();
|
||||
byte getFromBack();
|
||||
|
||||
int getInt();
|
||||
int getIntFromBack();
|
||||
|
||||
long getLong();
|
||||
long getLongFromBack();
|
||||
|
||||
float getFloat();
|
||||
float getFloatFromBack();
|
||||
|
||||
private:
|
||||
byte* data;
|
||||
|
||||
volatile unsigned int capacity;
|
||||
volatile unsigned int position;
|
||||
volatile unsigned int length;
|
||||
volatile boolean fillError;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
40
libraries/ByteBuffer/examples/ByteBufferExample.pde
Normal file
40
libraries/ByteBuffer/examples/ByteBufferExample.pde
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#include <ByteBuffer.h>
|
||||
|
||||
/*
|
||||
Silly program that emulates buffered processing
|
||||
using a circular bytebuffer
|
||||
*/
|
||||
|
||||
ByteBuffer buffer;
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Initialize the buffer with a capacity for 256 bytes
|
||||
buffer.init(256);
|
||||
|
||||
// Init serial just to debug
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
int cnt = 0;
|
||||
void loop() {
|
||||
cnt++;
|
||||
|
||||
// Every 100th update
|
||||
if( cnt%100 == 0 ){
|
||||
buffer.clear();
|
||||
buffer.put(200); // Put one byte at end
|
||||
buffer.putInt(2000); // Put one int at end
|
||||
buffer.putLong(20000); // Put one long at end
|
||||
buffer.putFloatInFront(200000); // Put one float at beginning
|
||||
}
|
||||
|
||||
// Every 100th update (20 updates offset)
|
||||
if( (cnt+20)%100 == 0 ){
|
||||
Serial.println("Received following bytes");
|
||||
while( buffer.getSize() > 0 )
|
||||
Serial.println(buffer.get(), DEC);
|
||||
Serial.println("");
|
||||
}
|
||||
}
|
||||
|
||||
18
libraries/MemoryFree/MemoryFree.cpp
Normal file
18
libraries/MemoryFree/MemoryFree.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
extern unsigned int __bss_end;
|
||||
extern unsigned int __heap_start;
|
||||
extern void *__brkval;
|
||||
|
||||
|
||||
#include "MemoryFree.h";
|
||||
|
||||
|
||||
int freeMemory() {
|
||||
int free_memory;
|
||||
|
||||
if((int)__brkval == 0)
|
||||
free_memory = ((int)&free_memory) - ((int)&__bss_end);
|
||||
else
|
||||
free_memory = ((int)&free_memory) - ((int)__brkval);
|
||||
|
||||
return free_memory;
|
||||
}
|
||||
18
libraries/MemoryFree/MemoryFree.h
Normal file
18
libraries/MemoryFree/MemoryFree.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// memoryFree header
|
||||
// From http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1213583720/15
|
||||
// ...written by user "mem".
|
||||
|
||||
#ifndef MEMORY_FREE_H
|
||||
#define MEMORY_FREE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int freeMemory();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
324
libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.cpp
Executable file
324
libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.cpp
Executable file
|
|
@ -0,0 +1,324 @@
|
|||
/*
|
||||
ByteBuffer.cpp - A circular buffer implementation for Arduino
|
||||
Created by Sigurdur Orn, July 19, 2010.
|
||||
siggi@mit.edu
|
||||
Updated by GreyGnome (aka Mike Schwager) Mon Apr 8 21:11:15 CDT 2013
|
||||
Fixed putString() so it reenables inputs correctly. In the if (length == capacity) section,
|
||||
it was missing this line:
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
Updated by GreyGnome (aka Mike Schwager) Thu Feb 23 17:25:14 CST 2012
|
||||
added the putString() method and the fillError variable.
|
||||
added the checkError() and resetError() methods. The checkError() method resets the fillError variable
|
||||
to false as a side effect.
|
||||
added the ByteBuffer(unsigned int buf_size) constructor.
|
||||
added the init() method, and had the constructor call it automagically.
|
||||
Also made the capacity, position, length, and fillError variables volatile, for safe use by interrupts.
|
||||
Mon Dec 3 07:55:04 CST 2012
|
||||
Added the putHex() and putDec() methods.
|
||||
*/
|
||||
|
||||
#include "ByteBuffer.h"
|
||||
|
||||
void ByteBuffer::init(){
|
||||
ByteBuffer::init(DEFAULTBUFSIZE);
|
||||
}
|
||||
|
||||
void ByteBuffer::init(unsigned int buf_length){
|
||||
data = (byte*)malloc(sizeof(byte)*buf_length);
|
||||
capacity = buf_length;
|
||||
position = 0;
|
||||
length = 0;
|
||||
fillError=false;
|
||||
}
|
||||
|
||||
// Arduino 1.0: free() doesn't free. :-( This is a no-op as of 11/2012.
|
||||
void ByteBuffer::deAllocate(){
|
||||
free(data);
|
||||
}
|
||||
|
||||
void ByteBuffer::clear(){
|
||||
position = 0;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
void ByteBuffer::resetError(){
|
||||
fillError=false;
|
||||
}
|
||||
|
||||
boolean ByteBuffer::checkError(){
|
||||
/*
|
||||
if (fillError) {
|
||||
Serial.print("E: checkError: length ");
|
||||
Serial.println(length, DEC);
|
||||
}
|
||||
*/
|
||||
|
||||
boolean result=fillError;
|
||||
fillError=false;
|
||||
return(result);
|
||||
}
|
||||
|
||||
int ByteBuffer::getSize(){
|
||||
return length;
|
||||
}
|
||||
|
||||
int ByteBuffer::getCapacity(){
|
||||
return capacity;
|
||||
}
|
||||
|
||||
byte ByteBuffer::peek(unsigned int index){
|
||||
byte b = data[(position+index)%capacity];
|
||||
return b;
|
||||
}
|
||||
|
||||
uint8_t ByteBuffer::put(byte in){
|
||||
if(length < capacity){
|
||||
// save data byte at end of buffer
|
||||
data[(position+length) % capacity] = in;
|
||||
// increment the length
|
||||
length++;
|
||||
return 1;
|
||||
}
|
||||
// return failure
|
||||
//Serial.print("E: put: ");
|
||||
//Serial.println(length, DEC);
|
||||
fillError=true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint8_t ByteBuffer::putString(const char *in) {
|
||||
return(putString((char *) in));
|
||||
}
|
||||
|
||||
uint8_t ByteBuffer::putString(char *in){
|
||||
uint8_t count=0;
|
||||
char *inString;
|
||||
|
||||
inString=in;
|
||||
uint8_t oldSREG = SREG; cli();
|
||||
while(length <= capacity){
|
||||
if (length == capacity) {
|
||||
fillError=true;
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return count;
|
||||
}
|
||||
// save data byte at end of buffer
|
||||
data[(position+length) % capacity] = *inString;
|
||||
// increment the length
|
||||
length++;
|
||||
inString++;
|
||||
count++;
|
||||
if (*inString == 0) {
|
||||
if (count==0) fillError=true; // Serial.println("E: putString"); };
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return count;
|
||||
}
|
||||
}
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t ByteBuffer::putInFront(byte in){
|
||||
uint8_t oldSREG = SREG; cli();
|
||||
if(length < capacity){
|
||||
// save data byte at end of buffer
|
||||
if( position == 0 )
|
||||
position = capacity-1;
|
||||
else
|
||||
position = (position-1)%capacity;
|
||||
data[position] = in;
|
||||
// increment the length
|
||||
length++;
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return 1;
|
||||
}
|
||||
// return failure
|
||||
//Serial.println("E: putInFront");
|
||||
fillError=true;
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns 0 if length of data is 0.
|
||||
byte ByteBuffer::get(){
|
||||
uint8_t oldSREG = SREG; cli();
|
||||
byte b = 0;
|
||||
|
||||
if(length > 0){
|
||||
b = data[position];
|
||||
// move index down and decrement length
|
||||
position = (position+1)%capacity;
|
||||
length--;
|
||||
}
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return b;
|
||||
}
|
||||
|
||||
byte ByteBuffer::getFromBack(){
|
||||
byte b = 0;
|
||||
if(length > 0){
|
||||
uint8_t oldSREG = SREG; cli();
|
||||
b = data[(position+length-1)%capacity];
|
||||
length--;
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
//
|
||||
// Ints
|
||||
//
|
||||
|
||||
void ByteBuffer::putIntInFront(int in){
|
||||
byte *pointer = (byte *)∈
|
||||
putInFront(pointer[0]);
|
||||
putInFront(pointer[1]);
|
||||
}
|
||||
|
||||
void ByteBuffer::putInt(int in){
|
||||
byte *pointer = (byte *)∈
|
||||
put(pointer[1]);
|
||||
put(pointer[0]);
|
||||
}
|
||||
|
||||
|
||||
int ByteBuffer::getInt(){
|
||||
int ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[1] = get();
|
||||
pointer[0] = get();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ByteBuffer::getIntFromBack(){
|
||||
int ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[0] = getFromBack();
|
||||
pointer[1] = getFromBack();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ByteBuffer::putHex(uint8_t theByte) {
|
||||
put('0'); put('x');
|
||||
uint8_t hinybble=theByte>>4;
|
||||
uint8_t lonybble=theByte & 0x0F;
|
||||
uint8_t addend=0;
|
||||
if (hinybble >= 0x0a) addend=7;
|
||||
put(hinybble+48+addend);
|
||||
if (lonybble >= 0x0a) addend=7;
|
||||
else addend=0;
|
||||
put(lonybble+48+addend);
|
||||
}
|
||||
|
||||
void ByteBuffer::putDec(uint8_t number) {
|
||||
uint8_t hundreds=0;
|
||||
uint8_t tens=0;
|
||||
uint8_t ones=0;
|
||||
uint8_t tmp=number;
|
||||
|
||||
while (tmp >= 100 ) {
|
||||
hundreds++;
|
||||
tmp-=100;
|
||||
}
|
||||
while (tmp >= 10 ) {
|
||||
tens++;
|
||||
tmp-=10;
|
||||
}
|
||||
ones=tmp;
|
||||
hundreds+=48; tens+=48; ones+=48;
|
||||
if (number >= 100) { put(hundreds); }
|
||||
if (number >= 10) { put(tens); }
|
||||
put(ones);
|
||||
}
|
||||
|
||||
void ByteBuffer::putDec(int8_t number) {
|
||||
uint8_t absNumber=abs(number);
|
||||
if (number < 0) put('-');
|
||||
putDec(absNumber);
|
||||
}
|
||||
|
||||
//
|
||||
// Longs
|
||||
//
|
||||
|
||||
void ByteBuffer::putLongInFront(long in){
|
||||
byte *pointer = (byte *)∈
|
||||
putInFront(pointer[0]);
|
||||
putInFront(pointer[1]);
|
||||
putInFront(pointer[2]);
|
||||
putInFront(pointer[3]);
|
||||
}
|
||||
|
||||
void ByteBuffer::putLong(long in){
|
||||
byte *pointer = (byte *)∈
|
||||
put(pointer[3]);
|
||||
put(pointer[2]);
|
||||
put(pointer[1]);
|
||||
put(pointer[0]);
|
||||
}
|
||||
|
||||
|
||||
long ByteBuffer::getLong(){
|
||||
long ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[3] = get();
|
||||
pointer[2] = get();
|
||||
pointer[1] = get();
|
||||
pointer[0] = get();
|
||||
return ret;
|
||||
}
|
||||
|
||||
long ByteBuffer::getLongFromBack(){
|
||||
long ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[0] = getFromBack();
|
||||
pointer[1] = getFromBack();
|
||||
pointer[2] = getFromBack();
|
||||
pointer[3] = getFromBack();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Floats
|
||||
//
|
||||
|
||||
void ByteBuffer::putFloatInFront(float in){
|
||||
byte *pointer = (byte *)∈
|
||||
putInFront(pointer[0]);
|
||||
putInFront(pointer[1]);
|
||||
putInFront(pointer[2]);
|
||||
putInFront(pointer[3]);
|
||||
}
|
||||
|
||||
void ByteBuffer::putFloat(float in){
|
||||
byte *pointer = (byte *)∈
|
||||
put(pointer[3]);
|
||||
put(pointer[2]);
|
||||
put(pointer[1]);
|
||||
put(pointer[0]);
|
||||
}
|
||||
|
||||
float ByteBuffer::getFloat(){
|
||||
float ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[3] = get();
|
||||
pointer[2] = get();
|
||||
pointer[1] = get();
|
||||
pointer[0] = get();
|
||||
return ret;
|
||||
}
|
||||
|
||||
float ByteBuffer::getFloatFromBack(){
|
||||
float ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[0] = getFromBack();
|
||||
pointer[1] = getFromBack();
|
||||
pointer[2] = getFromBack();
|
||||
pointer[3] = getFromBack();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
104
libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.h
Executable file
104
libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.h
Executable file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
ByteBuffer.h - A circular buffer implementation for Arduino
|
||||
Created by Sigurdur Orn, July 19, 2010. siggi@mit.edu
|
||||
Updated by GreyGnome (aka Mike Schwager) Thu Feb 23 17:25:14 CST 2012
|
||||
added the putString() method and the fillError variable.
|
||||
added the checkError() and resetError() methods. The checkError() method resets the fillError variable
|
||||
to false as a side effect.
|
||||
added the ByteBuffer(unsigned int buf_size) constructor.
|
||||
added the init() method, and had the constructor call it automagically.
|
||||
protected certain sections of the code with cli()/sei() calls, for safe use by interrupts.
|
||||
Also made the capacity, position, length, and fillError variables volatile, for safe use by interrupts.
|
||||
*/
|
||||
|
||||
#ifndef ByteBuffer_h
|
||||
#define ByteBuffer_h
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
//#include <util/atomic.h>
|
||||
|
||||
#define DEFAULTBUFSIZE 32
|
||||
class ByteBuffer
|
||||
{
|
||||
public:
|
||||
ByteBuffer() {
|
||||
init();
|
||||
};
|
||||
ByteBuffer(unsigned int buf_size) {
|
||||
init(buf_size);
|
||||
};
|
||||
|
||||
// This method initializes the datastore of the buffer to a certain size.
|
||||
void init(unsigned int buf_size);
|
||||
|
||||
// This method initializes the datastore of the buffer to the default size.
|
||||
void init();
|
||||
|
||||
// This method resets the buffer into an original state (with no data)
|
||||
void clear();
|
||||
|
||||
// This method resets the fillError variable to false.
|
||||
void resetError();
|
||||
|
||||
// This method tells you if your buffer overflowed at some time since the last
|
||||
// check. The error state will be reset to false.
|
||||
boolean checkError();
|
||||
|
||||
// This releases resources for this buffer, after this has been called the buffer should NOT be used
|
||||
void deAllocate();
|
||||
|
||||
// Returns how much space is used in the buffer
|
||||
int getSize();
|
||||
|
||||
// Returns the maximum capacity of the buffer
|
||||
int getCapacity();
|
||||
|
||||
// This method returns the byte that is located at index in the buffer but doesn't modify the buffer like the get methods (doesn't remove the retured byte from the buffer)
|
||||
byte peek(unsigned int index);
|
||||
|
||||
//
|
||||
// Put methods, either a regular put in back or put in front
|
||||
//
|
||||
uint8_t putInFront(byte in);
|
||||
uint8_t put(byte in);
|
||||
uint8_t putString(char *in);
|
||||
|
||||
void putIntInFront(int in);
|
||||
void putInt(int in);
|
||||
|
||||
void putLongInFront(long in);
|
||||
void putLong(long in);
|
||||
|
||||
void putFloatInFront(float in);
|
||||
void putFloat(float in);
|
||||
|
||||
//
|
||||
// Get methods, either a regular get from front or from back
|
||||
//
|
||||
byte get();
|
||||
byte getFromBack();
|
||||
|
||||
int getInt();
|
||||
int getIntFromBack();
|
||||
|
||||
long getLong();
|
||||
long getLongFromBack();
|
||||
|
||||
float getFloat();
|
||||
float getFloatFromBack();
|
||||
|
||||
private:
|
||||
byte* data;
|
||||
|
||||
volatile unsigned int capacity;
|
||||
volatile unsigned int position;
|
||||
volatile unsigned int length;
|
||||
volatile boolean fillError;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
21
libraries/PinChangeInt/Examples/GetPSTR/GetPSTR.h
Normal file
21
libraries/PinChangeInt/Examples/GetPSTR/GetPSTR.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef INCLUDE_GETPSTR
|
||||
#define INCLUDE_GETPSTR
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include "pins_arduino.h"
|
||||
#include "WProgram.h"
|
||||
#include "wiring.h"
|
||||
#endif
|
||||
|
||||
#define getPSTR(s) pgmStrToRAM(PSTR(s))
|
||||
|
||||
char *_pstr_to_print;
|
||||
char *pgmStrToRAM(PROGMEM char *theString) {
|
||||
free(_pstr_to_print);
|
||||
_pstr_to_print=(char *) malloc(strlen_P(theString));
|
||||
strcpy_P(_pstr_to_print, theString);
|
||||
return (_pstr_to_print);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
// PinChangeIntDebug
|
||||
// version 1.0 Wed Jul 9 16:20:56 CDT 2014
|
||||
// Lean project for debugging. Don't expect a lot of commentary in here. This is for hacking.
|
||||
// This code taken from Examples/PinChangeIntTest, so refer there for more information and commentary.
|
||||
|
||||
#define PINMODE
|
||||
#define FLASH
|
||||
#include <ByteBuffer.h>
|
||||
#include <MemoryFree.h>
|
||||
#include <PinChangeInt.h>
|
||||
|
||||
// This example demonstrates a configuration of 6 interrupting pins and 3 interrupt functions.
|
||||
// A variety of interrupting pins have been chosen, so as to test all PORTs on the Arduino.
|
||||
// The pins are as follows:
|
||||
#define INTERRUPT_PIN1 2 // port D
|
||||
#define INTERRUPT_PIN2 3
|
||||
#define INTERRUPT_PIN3 11 // Port B
|
||||
#define INTERRUPT_PIN4 12
|
||||
#define INTERRUPT_PIN5 A3 // Port C, also can be given as "17"
|
||||
#define INTERRUPT_PIN6 A4
|
||||
|
||||
uint8_t pins[6]={ INTERRUPT_PIN1, INTERRUPT_PIN2, INTERRUPT_PIN3, INTERRUPT_PIN4, INTERRUPT_PIN5, INTERRUPT_PIN6 };
|
||||
uint8_t ports[6]={ 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
uint8_t latest_interrupted_pin;
|
||||
uint8_t interrupt_count[20]={0}; // 20 possible arduino pins
|
||||
uint8_t port;
|
||||
uint8_t mode;
|
||||
|
||||
ByteBuffer printBuffer(200);
|
||||
char charArray[16];
|
||||
char numBuffer[5] = { 0, 0, 0, 0, 0 };
|
||||
uint8_t printFull=0;
|
||||
|
||||
volatile boolean start=0;
|
||||
volatile boolean initial=true;
|
||||
long begintime=0;
|
||||
long now=0;
|
||||
|
||||
void smallIntToString(char *outString, int number) {
|
||||
uint8_t thousands=0;
|
||||
uint8_t hundreds=0;
|
||||
uint8_t tens=0;
|
||||
uint8_t ones=0;
|
||||
|
||||
if (number > 9999) {
|
||||
outString[0]='S'; outString[1]='I'; outString[2]='Z'; outString[3]='E'; outString[4]=0;
|
||||
return;
|
||||
}
|
||||
while (number >= 1000 ) {
|
||||
thousands++;
|
||||
number-=1000;
|
||||
}
|
||||
while (number >= 100 ) {
|
||||
hundreds++;
|
||||
number-=100;
|
||||
}
|
||||
while (number >= 10 ) {
|
||||
tens++;
|
||||
number-=10;
|
||||
}
|
||||
ones=number;
|
||||
ones+=48;
|
||||
if (thousands > 0) {
|
||||
thousands+=48; hundreds+=48; tens+=48;
|
||||
outString[0]=thousands; outString[1]=hundreds; outString[2]=tens;
|
||||
outString[3]=ones; outString[4]=0;
|
||||
}
|
||||
else if (hundreds > 0) {
|
||||
hundreds+=48; tens+=48;
|
||||
outString[0]=hundreds; outString[1]=tens; outString[2]=ones; outString[3]=0;
|
||||
}
|
||||
else if (tens > 0) {
|
||||
tens+=48;
|
||||
outString[0]=tens; outString[1]=ones; outString[2]=0;
|
||||
}
|
||||
else { outString[0]=ones; outString[1]=0; };
|
||||
}
|
||||
|
||||
void showMode() {
|
||||
switch (mode) {
|
||||
case FALLING:
|
||||
printBuffer.putString((char *) "-F-");
|
||||
break;
|
||||
case RISING:
|
||||
printBuffer.putString((char *) "+R+");
|
||||
break;
|
||||
case CHANGE:
|
||||
printBuffer.putString((char *) "*C*");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void quicfunc0() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
mode=PCintPort::pinmode;
|
||||
showMode();
|
||||
if (start==1) {
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
}
|
||||
smallIntToString(numBuffer, latest_interrupted_pin);
|
||||
printBuffer.putString((char *) "f0p"); printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P");
|
||||
smallIntToString(numBuffer, digitalPinToPort(latest_interrupted_pin));
|
||||
printBuffer.putString(numBuffer);
|
||||
printBuffer.putString((char *) "\n");
|
||||
};
|
||||
|
||||
#define MAXPINCOUNT 6
|
||||
void attachInterrupts() {
|
||||
uint8_t i;
|
||||
for (i=0; i < MAXPINCOUNT; i++) {
|
||||
pinMode(pins[i], INPUT); digitalWrite(pins[i], HIGH);
|
||||
ports[i]=digitalPinToPort(pins[i]);
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc0, CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
void detachInterrupts() {
|
||||
uint8_t i;
|
||||
for (i=0; i < MAXPINCOUNT; i++) {
|
||||
PCintPort::detachInterrupt(pins[i]);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t i;
|
||||
bool interrupts_are_attached=false;
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(250);
|
||||
Serial.println("Test");
|
||||
delay(250);
|
||||
Serial.print("*---*");
|
||||
begintime=millis();
|
||||
attachInterrupts(); interrupts_are_attached=true;
|
||||
Serial.println("NOTICE: Interrupts ATTACHED.");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
#define LOOPDELAY 2000
|
||||
now=millis();
|
||||
uint8_t count;
|
||||
char outChar;
|
||||
uint8_t pinState;
|
||||
while ((outChar=(char)printBuffer.get()) != 0) Serial.print(outChar);
|
||||
if ((now - begintime) > LOOPDELAY) {
|
||||
Serial.print(".");
|
||||
pinState=digitalRead(INTERRUPT_PIN1);
|
||||
if (pinState == HIGH){
|
||||
Serial.print("H");
|
||||
}
|
||||
else { Serial.print("L");
|
||||
}
|
||||
if (printBuffer.checkError()) {
|
||||
Serial.println("NOTICE: Some output lost due to filled buffer.");
|
||||
}
|
||||
for (i=0; i < 20; i++) {
|
||||
if (interrupt_count[i] != 0) {
|
||||
count=interrupt_count[i];
|
||||
interrupt_count[i]=0;
|
||||
Serial.print("Count for pin ");
|
||||
if (i < 14) {
|
||||
Serial.print("D");
|
||||
Serial.print(i, DEC);
|
||||
} else {
|
||||
Serial.print("A");
|
||||
Serial.print(i-14, DEC);
|
||||
}
|
||||
Serial.print(" is ");
|
||||
Serial.println(count, DEC);
|
||||
}
|
||||
}
|
||||
begintime=millis();
|
||||
if (interrupts_are_attached) {
|
||||
detachInterrupts(); interrupts_are_attached=false;
|
||||
Serial.print("NOTICE: Interrupts DETACHED. Memory: ");
|
||||
Serial.print(freeMemory(), DEC);
|
||||
Serial.println(" bytes");
|
||||
}
|
||||
else {
|
||||
Serial.print("NOTICE: ATTACHING Interrupts. Memory: ");
|
||||
Serial.print(freeMemory(), DEC);
|
||||
Serial.println(" bytes");
|
||||
attachInterrupts(); interrupts_are_attached=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
// PinChangeIntExample2560
|
||||
// This only works for ATMega2560-based boards.
|
||||
// See the Arduino and the chip documentation for more details.
|
||||
|
||||
// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information.
|
||||
// for vim editing: :set et ts=2 sts=2 sw=2
|
||||
|
||||
// This example demonstrates a configuration of 3 interrupting pins and 2 interrupt functions.
|
||||
// The functions set the values of some global variables. All interrupts are serviced immediately,
|
||||
// and the sketch can then query the values at our leisure. This makes loop timing non-critical.
|
||||
|
||||
// The interrupt functions are a simple count of the number of times the pin was brought high.
|
||||
// For 2 of the pins, the values are stored and retrieved from an array and they are reset after
|
||||
// every read. For one of the pins ("MYPIN3"), there is a monotonically increasing count; that is,
|
||||
// until the 8-bit value reaches 255. Then it will go back to 0.
|
||||
|
||||
// For a more introductory sketch, see the SimpleExample328.ino sketch in the PinChangeInt
|
||||
// library distribution.
|
||||
|
||||
#include <PinChangeInt.h>
|
||||
|
||||
// PIN NAMING
|
||||
// For the Analog Input pins used as digital input pins, you can call them 14, 15, 16, etc.
|
||||
// or you can use A0, A1, A2, etc. (the Arduino code will properly recognize the symbolic names,
|
||||
// for example, pinMode(A0, INPUT_PULLUP);
|
||||
|
||||
// For Arduino MEGA (AT2560-based), besides the regular pins and the A (analog) pins,
|
||||
// you have 4 more pins with defined names:
|
||||
// SS = 53
|
||||
// MOSI = 51
|
||||
// MISO = 50
|
||||
// SCK = 52
|
||||
|
||||
// NOW CHOOSE PINS
|
||||
#if ! ( defined __AVR_ATmega2560__ || defined __AVR_ATmega1280__ || defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ || defined __AVR_ATmega640__ )
|
||||
#error "This sketch only works on chips in the ATmega2560 family."
|
||||
#endif
|
||||
|
||||
#define FIRST_ANALOG_PIN 54
|
||||
#define TOTAL_PINS 69 // But only 18 of them (not including RX0) are PinChangeInt-compatible
|
||||
// Don't use RX0 (Arduino pin 0) in this program- it won't work this is the
|
||||
// pin that Serial.print() uses!
|
||||
// See the Arduino and the chip documentation for more details.
|
||||
#define MYPIN1 SS
|
||||
#define MYPIN2 SCK
|
||||
#define MYPIN3 MOSI
|
||||
#define PIN3TEXT "MOSI" // This will say what MYPIN3 is, on the serial monitor
|
||||
|
||||
volatile uint8_t latest_interrupted_pin;
|
||||
volatile uint8_t interrupt_count[TOTAL_PINS]={0}; // possible arduino pins
|
||||
volatile uint8_t pin3Count=0;
|
||||
|
||||
// Do not use any Serial.print() in this function. Serial.print() uses interrupts, and is not compatible
|
||||
// with an interrupt routine...!
|
||||
void quicfunc() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
};
|
||||
|
||||
// You can assign any number of functions to different pins. How cool is that?
|
||||
void pin3func() {
|
||||
pin3Count++;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
pinMode(MYPIN1, INPUT_PULLUP);
|
||||
attachPinChangeInterrupt(MYPIN1, quicfunc, FALLING); // add more attachInterrupt code as required
|
||||
pinMode(MYPIN2, INPUT_PULLUP);
|
||||
attachPinChangeInterrupt(MYPIN2, quicfunc, FALLING);
|
||||
pinMode(MYPIN3, INPUT_PULLUP);
|
||||
attachPinChangeInterrupt(MYPIN3, pin3func, CHANGE);
|
||||
Serial.begin(115200);
|
||||
Serial.println("---------------------------------------");
|
||||
}
|
||||
|
||||
uint8_t i;
|
||||
uint8_t currentPIN3Count=0;
|
||||
void loop() {
|
||||
uint8_t count;
|
||||
Serial.print(".");
|
||||
delay(1000); // every second,
|
||||
for (i=0; i < TOTAL_PINS; i++) {
|
||||
if (interrupt_count[i] != 0) { // look at all the interrupted pins
|
||||
count=interrupt_count[i]; // store its count since the last iteration
|
||||
interrupt_count[i]=0; // and reset it to 0.
|
||||
Serial.print("Count for pin ");
|
||||
if (i == 50) { Serial.print("MISO"); } // then tell the user what it was, in a friendly way.
|
||||
else if (i == 51) { Serial.print("MOSI"); }
|
||||
else if (i == 52) { Serial.print("SCK"); }
|
||||
else if (i == 53) { Serial.print("SS"); }
|
||||
else if (i < FIRST_ANALOG_PIN) {
|
||||
Serial.print("D");
|
||||
Serial.print(i, DEC);
|
||||
} else {
|
||||
Serial.print("A");
|
||||
Serial.print(i-FIRST_ANALOG_PIN, DEC);
|
||||
}
|
||||
Serial.print(" is ");
|
||||
Serial.println(count, DEC);
|
||||
}
|
||||
}
|
||||
if (currentPIN3Count != pin3Count) { // Print our monotonically increasing counter (no reset to 0)
|
||||
Serial.print(PIN3TEXT);
|
||||
Serial.print(" count update: "); Serial.print(pin3Count, DEC); Serial.println();
|
||||
currentPIN3Count=pin3Count;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
// PinChangeIntExample
|
||||
// This only works for ATMega328-compatibles; ie, Leonardo is not covered here.
|
||||
// See the Arduino and the chip documentation for more details.
|
||||
// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information.
|
||||
|
||||
// for vim editing: :set et ts=2 sts=2 sw=2
|
||||
|
||||
// This example demonstrates a configuration of 3 interrupting pins and 2 interrupt functions.
|
||||
// The functions set the values of some global variables. All interrupts are serviced immediately,
|
||||
// and the sketch can then query the values at our leisure. This makes loop timing non-critical.
|
||||
|
||||
// The interrupt functions are a simple count of the number of times the pin was brought high.
|
||||
// For 2 of the pins, the values are stored and retrieved from an array and they are reset after
|
||||
// every read. For one of the pins ("MYPIN3"), there is a monotonically increasing count; that is,
|
||||
// until the 8-bit value reaches 255. Then it will go back to 0.
|
||||
|
||||
// For a more introductory sketch, see the SimpleExample328.ino sketch in the PinChangeInt
|
||||
// library distribution.
|
||||
|
||||
#include <PinChangeInt.h>
|
||||
|
||||
// Modify these at your leisure.
|
||||
#define MYPIN1 A3
|
||||
#define MYPIN2 A4
|
||||
#define MYPIN3 A5
|
||||
|
||||
// Don't change these.
|
||||
#define FIRST_ANALOG_PIN 14
|
||||
#define TOTAL_PINS 19
|
||||
// Notice that anything that gets modified inside an interrupt, that I wish to access
|
||||
// outside the interrupt, is marked "volatile". That tells the compiler not to optimize
|
||||
// them.
|
||||
volatile uint8_t latest_interrupted_pin;
|
||||
volatile uint8_t interrupt_count[TOTAL_PINS]={0}; // possible arduino pins
|
||||
volatile uint8_t pin3Count=0;
|
||||
|
||||
// Do not use any Serial.print() in interrupt subroutines. Serial.print() uses interrupts,
|
||||
// and by default interrupts are off in interrupt subroutines.
|
||||
// Here we update a counter corresponding to whichever pin interrupted.
|
||||
void quicfunc() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
};
|
||||
|
||||
// You can assign any number of functions to different pins. How cool is that?
|
||||
// Here we have a global variable that we increment. We can access this variable outside the interrupt,
|
||||
// and we know it will be valid because it was declared "volatile"- meaning, the compiler performs
|
||||
// no optimizations on it.
|
||||
void pin3func() {
|
||||
pin3Count++;
|
||||
}
|
||||
|
||||
// Attach the interrupts in setup()
|
||||
void setup() {
|
||||
pinMode(MYPIN1, INPUT_PULLUP);
|
||||
attachPinChangeInterrupt(MYPIN1, quicfunc, RISING);
|
||||
pinMode(MYPIN2, INPUT_PULLUP);
|
||||
attachPinChangeInterrupt(MYPIN2, quicfunc, RISING);
|
||||
pinMode(MYPIN3, INPUT_PULLUP);
|
||||
attachPinChangeInterrupt(MYPIN3, pin3func, CHANGE); // Any state change will trigger the interrupt.
|
||||
Serial.begin(115200);
|
||||
Serial.println("---------------------------------------");
|
||||
}
|
||||
|
||||
uint8_t i;
|
||||
uint8_t currentPIN3Count=0;
|
||||
|
||||
void loop() {
|
||||
uint8_t count;
|
||||
Serial.print(".");
|
||||
delay(1000); // every second,
|
||||
for (i=0; i < TOTAL_PINS; i++) {
|
||||
if (interrupt_count[i] != 0) { // look at all the interrupted pins
|
||||
count=interrupt_count[i]; // store its count since the last iteration
|
||||
interrupt_count[i]=0; // and reset it to 0
|
||||
Serial.print("Count for pin ");
|
||||
if (i < FIRST_ANALOG_PIN) { // then tell the user what it was, in a friendly way
|
||||
Serial.print("D");
|
||||
Serial.print(i, DEC);
|
||||
} else {
|
||||
Serial.print("A");
|
||||
Serial.print(i-FIRST_ANALOG_PIN, DEC);
|
||||
}
|
||||
Serial.print(" is ");
|
||||
Serial.println(count, DEC);
|
||||
}
|
||||
}
|
||||
if (currentPIN3Count != pin3Count) { // Print our monotonically increasing counter (no reset to 0).
|
||||
Serial.print("Pin 3 count update: "); Serial.print(pin3Count, DEC); Serial.println();
|
||||
currentPIN3Count=pin3Count;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
// PinChangeIntSpeedTest by GreyGnome aka Mike Schwager. Version numbers here refer to this sketch.
|
||||
// Version 1.0 - initial version
|
||||
// Version 1.1 - added code to test digitalRead()
|
||||
// Version 1.2 - added new comments for the #define's for the NO_PORTx_PINCHANGES.
|
||||
// Version 1.3 - includes cbiface.h with ooPinChangeInt, rather than cb.h
|
||||
// Version 1.4 - testing version 2.10Beta with robtillaart's optimization
|
||||
// Also added a #define/#undef INLINE_PCINTFUNC for inlining of the function called by the interrupt.
|
||||
// Default: #undef for using the function as per usual. Changed PCIVERSION so that
|
||||
// ooPinChangeInt starts at 1000 instead of 200. Modified the "Start" message to show "Start..", pause
|
||||
// for 1 second, show "*\n" (where \n is a newline), pause for 1 second, then run the test.
|
||||
// Version 1.4 - made this compatible with version 1.5 of PinChangeInt
|
||||
// Version 1.5 - modified it to use #define OOPCIVERSION for ooPinChangeInt
|
||||
|
||||
// This version number is for ooPinChangeInt
|
||||
//#define OOPCIVERSION 1030
|
||||
#ifndef OOPCIVERSION
|
||||
#define PCIVERSION 217 // 110 if using PinChangeInt-1.1, 120 for version 1.2
|
||||
// 1000 for ooPinChangeIntversion 1.00, 1001 for ooPinChangeInt version 1.01, etc.
|
||||
#endif
|
||||
|
||||
//-------- define these in your sketch, if applicable ----------------------------------------------------------
|
||||
// You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts
|
||||
// on any one or two of the three ports. If only a single port remains, the handler will be declared inline
|
||||
// reducing the size and latency of the handler.
|
||||
#undef NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts
|
||||
#undef NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts
|
||||
// #define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts
|
||||
// You can reduce the code size by 20-50 bytes, and you can speed up the interrupt routine
|
||||
// slightly by declaring that you don't care if the static variables PCintPort::pinState and/or
|
||||
// PCintPort::arduinoPin are set and made available to your interrupt routine.
|
||||
// #define NO_PIN_STATE // to indicate that you don't need the pinState
|
||||
// #define NO_PIN_NUMBER // to indicate that you don't need the arduinoPin
|
||||
// if there is only one PCInt vector in use the code can be inlined
|
||||
// reducing latency and code size
|
||||
// define DISABLE_PCINT_MULTI_SERVICE below to limit the handler to servicing a single interrupt per invocation.
|
||||
//#define DISABLE_PCINT_MULTI_SERVICE
|
||||
//-------- define the above in your sketch, if applicable ------------------------------------------------------
|
||||
#if defined(OOPCIVERSION)
|
||||
#define LIBRARYUNDERTEST "ooPinChangeInt"
|
||||
#include <ooPinChangeInt.h>
|
||||
#if PCIVERSION == 1001
|
||||
#include <cb.h>
|
||||
#else
|
||||
#include <cbiface.h>
|
||||
#endif
|
||||
#else
|
||||
#define LIBRARYUNDERTEST "PinChangeInt"
|
||||
#include <PinChangeInt.h>
|
||||
#endif
|
||||
|
||||
#define SERIALSTUFF // undef to take out all serial statements. Default: #define for measuring time.
|
||||
#undef MEMTEST // undef to take out memory tests. Default: #undef for measuring time.
|
||||
#undef INLINE_PCINTFUNC // define to inline the function called from the interrupt. This should have no effect,
|
||||
// because the compiler will store the registers upon calling the interrupt routine, just
|
||||
// like calling a function. Still, we test all assumptions.
|
||||
//-----------------------
|
||||
// NOTE: BECAUSE OF COLLISIONS in these libraries, you CANNOT have both libraries: PinChangeInt
|
||||
// and ooPinChangeInt in the libraries directory at the same time. That said, under UNIX-y operating
|
||||
// systems, it's easy to move the library directory to a name such as "PinChangeInt-1.3", which the
|
||||
// Arduino will not recognize, and then create a symbolic link when you want to use a library. Such as:
|
||||
// cd ~/Documents/Arduino/libaries
|
||||
// mv PinChangeInt PinChangeInt-1.30
|
||||
// mv ooPinChangeInt ooPinChangeInt-1.00
|
||||
// ln -s PinChangeInt-1.30 PinChangeInt
|
||||
|
||||
#undef FLASH // to flash LED on pin 13 during test
|
||||
|
||||
#ifdef MEMTEST
|
||||
#include <MemoryFree.h>
|
||||
#endif
|
||||
|
||||
#define TEST 6
|
||||
|
||||
#if TEST == 1
|
||||
#define PTEST 2 // pin to trigger interrupt. pins 0 and 1 are used
|
||||
#define PLOW 2 // by Serial, so steer clear of them!
|
||||
#define PHIGH 2 // Interrupts are attached to these pins
|
||||
|
||||
#elif TEST == 2 // see the #if TEST == 2 || TEST == 3 code, below
|
||||
#define PTEST 2
|
||||
#define PLOW 2
|
||||
#define PHIGH 2 // need to attachInterrupt to 5 in the code
|
||||
|
||||
#elif TEST == 3 // see the #if TEST == 2 || TEST == 3 code, below
|
||||
#define PTEST 5
|
||||
#define PLOW 2
|
||||
#define PHIGH 2 // need to attachInterrupt to 5 in the code
|
||||
|
||||
#elif TEST == 4
|
||||
#define PTEST 2
|
||||
#define PLOW 2
|
||||
#define PHIGH 5
|
||||
|
||||
#elif TEST == 5
|
||||
#define PTEST 3
|
||||
#define PLOW 2
|
||||
#define PHIGH 5
|
||||
|
||||
#elif TEST == 6
|
||||
#define PTEST 4
|
||||
#define PLOW 2
|
||||
#define PHIGH 5
|
||||
|
||||
#elif TEST == 7
|
||||
#define PTEST 5
|
||||
#define PLOW 2
|
||||
#define PHIGH 5
|
||||
#endif
|
||||
|
||||
uint8_t qf0;
|
||||
|
||||
#ifdef INLINE_PCINTFUNC
|
||||
#define INLINE_PCINTFUNC inline
|
||||
#else
|
||||
#define INLINE_PCINTFUNC
|
||||
#endif
|
||||
INLINE_PCINTFUNC void quicfunc();
|
||||
void quicfunc() {
|
||||
qf0=TCNT0;
|
||||
}
|
||||
|
||||
#if defined(OOPCIVERSION)
|
||||
class speedy : public CallBackInterface
|
||||
{
|
||||
public:
|
||||
uint8_t id;
|
||||
static uint8_t var0;
|
||||
speedy () { id=0; };
|
||||
speedy (uint8_t _i): id(_i) {};
|
||||
|
||||
void cbmethod() {
|
||||
speedy::var0=TCNT0;
|
||||
//Serial.print("Speedy method "); // debugging
|
||||
//Serial.println(id, DEC);
|
||||
};
|
||||
};
|
||||
uint8_t speedy::var0=0;
|
||||
#endif
|
||||
|
||||
volatile uint8_t *led_port;
|
||||
volatile uint8_t *pinT_OP;
|
||||
volatile uint8_t *pinT_IP;
|
||||
uint8_t led_mask, not_led_mask;
|
||||
uint8_t pinT_M, not_pinT_M;
|
||||
volatile uint8_t pintest, pinIntLow, pinIntHigh;
|
||||
uint8_t totalpins;
|
||||
#if defined(OOPCIVERSION)
|
||||
speedy speedster[8]={speedy(0), speedy(1), speedy(2), speedy(3), speedy(4), speedy(5), speedy(6), speedy(7) };
|
||||
#endif
|
||||
#ifdef MEMTEST
|
||||
int freemem;
|
||||
#endif
|
||||
|
||||
int i=0;
|
||||
|
||||
#define PINLED 13
|
||||
void setup()
|
||||
{
|
||||
#ifdef SERIALSTUFF
|
||||
Serial.begin(115200); Serial.println("---------------------------------------");
|
||||
#endif // SERIALSTUFF
|
||||
// set up ports for trigger
|
||||
pinMode(0, OUTPUT); digitalWrite(0, HIGH);
|
||||
pinMode(1, OUTPUT); digitalWrite(1, HIGH);
|
||||
pinMode(2, OUTPUT); digitalWrite(2, HIGH);
|
||||
pinMode(3, OUTPUT); digitalWrite(3, HIGH);
|
||||
pinMode(4, OUTPUT); digitalWrite(4, HIGH);
|
||||
pinMode(5, OUTPUT); digitalWrite(5, HIGH);
|
||||
pinMode(6, OUTPUT); digitalWrite(6, HIGH);
|
||||
pinMode(7, OUTPUT); digitalWrite(7, HIGH);
|
||||
#ifdef FLASH
|
||||
led_port=portOutputRegister(digitalPinToPort(PINLED));
|
||||
led_mask=digitalPinToBitMask(PINLED);
|
||||
not_led_mask=led_mask^0xFF;
|
||||
pinMode(PINLED, OUTPUT); digitalWrite(PINLED, LOW);
|
||||
#endif
|
||||
// *****************************************************************************
|
||||
// set up ports for output ************ PIN TO TEST IS GIVEN HERE **************
|
||||
// *****************************************************************************
|
||||
pintest=PTEST;
|
||||
pinIntLow=PLOW; pinIntHigh=PHIGH; // Interrupts are attached to these pins
|
||||
// *****************************************************************************
|
||||
// *****************************************************************************
|
||||
pinT_OP=portOutputRegister(digitalPinToPort(pintest)); // output port
|
||||
pinT_IP=portInputRegister(digitalPinToPort(pintest)); // input port
|
||||
pinT_M=digitalPinToBitMask(pintest); // mask
|
||||
not_pinT_M=pinT_M^0xFF; // not-mask
|
||||
*pinT_OP|=pinT_M;
|
||||
for (i=pinIntLow; i <= pinIntHigh; i++) {
|
||||
#if defined(OOPCIVERSION)
|
||||
PCintPort::attachInterrupt(i, &speedster[i], CHANGE); // C++ technique; v1.3 or better
|
||||
#endif
|
||||
#if defined(PCIVERSION)
|
||||
PCintPort::attachInterrupt((uint8_t) i, &quicfunc, CHANGE); // C technique; v1.2 or earlier
|
||||
#endif
|
||||
}
|
||||
#if TEST == 2 || TEST == 3
|
||||
i=5; totalpins=2;
|
||||
#if defined(OOPCIVERSION)
|
||||
PCintPort::attachInterrupt(i, &speedster[i], CHANGE); // C++ technique; v1.3 or better
|
||||
#endif
|
||||
#if defined(PCIVERSION)
|
||||
PCintPort::attachInterrupt(i, &quicfunc, CHANGE); // C technique; v1.2 or earlier
|
||||
#endif
|
||||
#else
|
||||
totalpins=pinIntHigh - pinIntLow + 1;
|
||||
#endif
|
||||
i=0;
|
||||
} // end setup()
|
||||
|
||||
uint8_t k=0;
|
||||
unsigned long milliStart, milliEnd, elapsed;
|
||||
void loop() {
|
||||
k=0;
|
||||
*pinT_OP|=pinT_M; // pintest to 1
|
||||
#ifdef SERIALSTUFF
|
||||
Serial.print(LIBRARYUNDERTEST); Serial.print(" ");
|
||||
Serial.print("TEST: "); Serial.print(TEST, DEC); Serial.print(" ");
|
||||
#ifndef MEMTEST
|
||||
Serial.print("test pin mask: "); Serial.print(pinT_M, HEX);
|
||||
Serial.print(". Total of "); Serial.print(totalpins, DEC); Serial.println(" pins enabled.");
|
||||
#endif
|
||||
#ifdef MEMTEST
|
||||
freemem=freeMemory(); Serial.print("Free memory: "); Serial.println(freemem, DEC);
|
||||
#endif
|
||||
#endif
|
||||
delay(1000);
|
||||
Serial.print("Start..");
|
||||
delay(1000); Serial.print("*");
|
||||
#ifdef FLASH
|
||||
*led_port|=led_mask;
|
||||
#endif
|
||||
milliStart=millis();
|
||||
while (k < 10) {
|
||||
i=0;
|
||||
while (i < 10000) {
|
||||
*pinT_OP&=not_pinT_M; // pintest to 0 ****************************** 16.8 us
|
||||
*pinT_OP|=pinT_M; // pintest to 1 ****************************** ...to get here
|
||||
i++;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
milliEnd=millis();
|
||||
#ifdef FLASH
|
||||
*led_port&=not_led_mask;
|
||||
#endif
|
||||
elapsed=milliEnd-milliStart;
|
||||
#ifndef MEMTEST
|
||||
Serial.print(" Elapsed: ");
|
||||
Serial.println(elapsed, DEC);
|
||||
#endif
|
||||
#ifdef SERIALSTUFF
|
||||
Serial.print("Interrupted pin: ");
|
||||
#if defined(OOPCIVERSION)
|
||||
Serial.println(speedster[pintest].id, DEC);
|
||||
#else
|
||||
Serial.println(PCintPort::arduinoPin, DEC);
|
||||
#endif
|
||||
#ifdef MEMTEST
|
||||
freemem=freeMemory(); Serial.print("END-Free memory: "); Serial.println(freemem, DEC);
|
||||
#endif
|
||||
#endif
|
||||
delay(500);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,355 @@
|
|||
// PinChangeIntTest
|
||||
//
|
||||
// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information.
|
||||
// This sketch requires the ByteBuffer library, which is found in the PinChangeInt zipfile.
|
||||
// for vim editing: :set et ts=2 sts=2 sw=2
|
||||
//-------- define these in your sketch, if applicable ----------------------------------------------------------
|
||||
//-------- This must go ahead of the #include statement --------------------------------------------------------
|
||||
// You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts
|
||||
// on any one or two of the three ports. If only a single port remains, the handler will be declared inline
|
||||
// reducing the size and latency of the handler.
|
||||
// #define NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts
|
||||
// #define NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts
|
||||
// #define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts
|
||||
// You can reduce the code size by 20-50 bytes, and you can speed up the interrupt routine
|
||||
// slightly by declaring that you don't care if the static variables PCintPort::pinState and/or
|
||||
// PCintPort::arduinoPin are set and made available to your interrupt routine.
|
||||
// #define NO_PIN_STATE // to indicate that you don't need the pinState
|
||||
// #define NO_PIN_NUMBER // to indicate that you don't need the arduinoPin
|
||||
// if there is only one PCInt vector in use the code can be inlined
|
||||
// reducing latency and code size
|
||||
// define DISABLE_PCINT_MULTI_SERVICE below to limit the handler to servicing a single interrupt per invocation.
|
||||
// #define DISABLE_PCINT_MULTI_SERVICE
|
||||
// The following is intended for testing purposes. If defined, then a variable PCintPort::pinMode can be read
|
||||
// in your interrupt subroutine. It is not defined by default:
|
||||
// #define PINMODE
|
||||
//-------- define the above in your sketch, if applicable ------------------------------------------------------
|
||||
#define PINMODE
|
||||
#define FLASH
|
||||
#include <ByteBuffer.h>
|
||||
#include <PinChangeInt.h>
|
||||
|
||||
#define NEWLINE "\r\n" // Programs like "screen" in Linux don't return with a "\n" character.
|
||||
|
||||
// This example demonstrates a configuration of 6 interrupting pins and 3 interrupt functions.
|
||||
// A variety of interrupting pins have been chosen, so as to test all PORTs on the Arduino.
|
||||
// The pins are as follows:
|
||||
// quicfunc0 is attached to tPIN1-4.
|
||||
// quicfunc1 is attached to tPIN5.
|
||||
// quicfunc2 is attached to tPIN6.
|
||||
// Pins tPIN1 and tPIN6 interrupt on FALLING.
|
||||
// tPIN2 and tPIN4 interrupt on RISING.
|
||||
// tPIN3 and tPIN5 interrupt on CHANGE.
|
||||
// NOTE:
|
||||
// For the Analog Input pins used as digital input pins, you can use numbers such as 14, 15, 16, etc.
|
||||
// or you can use A0, A1, A2, etc. (the Arduino code comes with #define's for the Analog Input pin
|
||||
// names and will properly recognize e.g., pinMode(A0, INPUT_PULLUP));
|
||||
#if defined __AVR_ATmega2560__ || defined __AVR_ATmega1280__ || defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ || defined __AVR_ATmega640__
|
||||
#define tPIN1 14 // port J
|
||||
#define tPIN2 15
|
||||
#define tPIN3 A8 // Port K
|
||||
#define tPIN4 A12
|
||||
#define tPIN5 SS // Port B, also can be given as "57"
|
||||
#define tPIN6 MOSI // This pin starts and stops the count
|
||||
#else
|
||||
// These only work for ATMega328-compatibles; ie, Leonardo is not covered here.
|
||||
#define tPIN1 2 // port D
|
||||
#define tPIN2 3
|
||||
#define tPIN3 11 // Port B
|
||||
#define tPIN4 12
|
||||
#define tPIN5 A3 // Port C, also can be given as "17"
|
||||
#define tPIN6 A4 // This pin starts and stops the count
|
||||
#endif
|
||||
|
||||
// HOW IT WORKS (ATmega328-specific; replace the references with the proper pins for the other chip types)
|
||||
// The interrupt on Arduino pin A4 (tPIN6) will, when triggered, start the counting of interrupts.
|
||||
// The array interrupt_count0[20] is updated in the interrupts; each cell keeps track of the number
|
||||
// of interrupts on one of the 20 available interrupt pins on the Arduino. Every second in the main
|
||||
// loop the array is scanned and registered interrupts are reported for all pins interrupted since
|
||||
// the previous second. If no interrupts, the output is quiet.
|
||||
|
||||
// tPIN6 is special. Not only does it start the counting of the interrups, but it turns on and off
|
||||
// interrupts on pins 2, 11, and A3/17 (tPIN1, tPIN3, tPIN5). All pins start by interrupting, but after
|
||||
// the count is turned on and then turned off, the 3 pins are detached from interrupts.
|
||||
// Everytime thereafter when the count is turned off the 3 pins are detached. They are reattached
|
||||
// when turned on.
|
||||
|
||||
// Output is copied to a buffer, because we can't do a Serial.print() statement in an interrupt
|
||||
// routine. The main loop checks for entries in the buffer and prints them if found.
|
||||
// Output looks like this:
|
||||
// -F- - an interrupt triggered by a falling signal occurred.
|
||||
// +R+ - an interrupt triggered by a rising signal occurred.
|
||||
// *C* - an interrupt triggered by a change in signal occurred.
|
||||
// f#p#-P# - f# shows the interrupt subroutine that was called: 0, 1, or 2
|
||||
// - p# shows the pin number that triggered the interrupt
|
||||
// - P# shows the port that this pin number is attached to. 2 is PORTB, 3 is PORTC, 4 is PORTD
|
||||
|
||||
// HOW TO CONNECT
|
||||
// Each pin gets a momentary contact switch connected to it. One side of the switch should connect
|
||||
// to ground. The other side of the switch connects to the Arduino pin. For my purposes, I am using
|
||||
// two rotary encoders. Each encoder contains 3 switches. But 6 regular pushbuttons would work, too.
|
||||
|
||||
/* WHAT TO LOOK FOR
|
||||
Output is sent to the serial line, so the Arduino IDE's serial terminal should be opened.
|
||||
Upon startup, press tPINS1-5. You will see output like this:
|
||||
-F-f0p2-P4 (counting off)
|
||||
..*C*f0p11-P2 (counting off)
|
||||
+R+f0p3-P4 (counting off)
|
||||
This shows that
|
||||
1. an interrupt was triggered on a falling signal (*F*). It called (f0) function 0, which is quicfunc0.
|
||||
The triggering pin was (p2) Arduuino pin 2, which is on (P4) Port 4 (PORTD). Counting of this interrupt is
|
||||
off, so you will not see any output from the main loop.
|
||||
2. Two dots appeared. Dots came from iterations of loop(), so these 2 dots show that the two interrupts happened 2 seconds apart.
|
||||
3. an interrupt was triggered on a change in signal (*C*). It called quicfunc0, from Arduino pin 11, on Port 2 (PORTB).
|
||||
The interrupt was not counted.
|
||||
4. an interrupt was triggered on a rising signal (+R+). It called quicfunc0, from Arduino pin 3, on Purt 4 (PORTD).
|
||||
The pin should have started out at the high level, so likely the signal fell during onother interrupt, and now
|
||||
the rise has been caught.
|
||||
|
||||
Now press the button attached to tPIN6 (in our case, A4 or D18). You will see something like this:
|
||||
-F-START! f2p18-P3
|
||||
.Count for pin A4 is 1
|
||||
This shows that
|
||||
1. The counting machanism (START!) was triggered by a folling signal (-F-) on pin 18 (p18) which is in Port 3 (P3) (which == PORTC) and
|
||||
function f2 was called (f2).
|
||||
2. A dot appeared, which came from loop() because a second passed.
|
||||
3. The count for p18 or A4 was displayed.
|
||||
|
||||
Now you will see messages for all the pins that you manipulate, for example:
|
||||
*C*f0p11-P2
|
||||
+R+f0p3-P4
|
||||
*C*f0p11-P2
|
||||
+R+f0p3-P4
|
||||
*C*f0p11-P2
|
||||
.Count for pin D3 is 6
|
||||
Count for pin D11 is 9
|
||||
.+R+f0p3-P4
|
||||
-F-f0p2-P4
|
||||
.Count for pin D2 is 1
|
||||
Count for pin D3 is 1
|
||||
These codes reflect the interrupts, as described above. This output will take place until you press tPIN6:
|
||||
-F-f2: STOP! Counting off.
|
||||
Interrupt OFF on tPIN1 (2) tPIN3 (11) tPIN5 (17)
|
||||
Then you will see output like this:
|
||||
.....................+R+f0p12-P2 (counting off)
|
||||
.+R+f0p12-P2 (counting off)
|
||||
+R+f0p12-P2 (counting off)
|
||||
+R+f0p12-P2 (counting off)
|
||||
and tPIN1, tPIN3, and tPIN5 will not trigger interrupts.
|
||||
*/
|
||||
// NOTES
|
||||
// Output overwrites:
|
||||
// It's possible during moderately fast interrupts to see your print output get garbled; eg,
|
||||
// +R+f0p12-P2 (+R+f0p12-P2 (counting +R+f0p12-P2 (cou+R+f0p12-P+R+f0p12
|
||||
// This is because the print of the buffer takes place inside a while loop, and it can
|
||||
// be interrupted and new data inserted into the buffer at a midpoint of the buffer's text.
|
||||
// Just by spinning my rotary encoders I can readily generate over 200 interrupts per second
|
||||
// on a pin, which is easily fast enough to overrun Serial output at 115,200 bps.
|
||||
// The lesson here? ...Interrupts are tricky, and interrupt service routines should be fast.
|
||||
// Just sayin'.
|
||||
|
||||
// Pins:
|
||||
// We want to use pins from each of ports B, C and D. So choose wisely. Ports are shown in
|
||||
// this diagram of the ATmega328P chip. PD0 means "Port D, pin 0". PC3 means "Port C, Pin 3",
|
||||
// PB2 means "Port B, pin 2" and so on. The corresponding Arduino pins are in parentheses.
|
||||
// So PB2 is Arduino pin D 10, for example.
|
||||
/*
|
||||
+-\/-+
|
||||
PC6 1| |28 PC5 (AI 5)
|
||||
(D 0) PD0 2| |27 PC4 (AI 4)
|
||||
(D 1) PD1 3| |26 PC3 (AI 3)
|
||||
(D 2) PD2 4| |25 PC2 (AI 2)
|
||||
PWM+ (D 3) PD3 5| |24 PC1 (AI 1)
|
||||
(D 4) PD4 6| |23 PC0 (AI 0)
|
||||
VCC 7| |22 GND
|
||||
GND 8| |21 AREF
|
||||
PB6 9| |20 AVCC
|
||||
PB7 10| |19 PB5 (D 13)
|
||||
PWM+ (D 5) PD5 11| |18 PB4 (D 12)
|
||||
PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM
|
||||
(D 7) PD7 13| |16 PB2 (D 10) PWM
|
||||
(D 8) PB0 14| |15 PB1 (D 9) PWM
|
||||
+----+
|
||||
*/
|
||||
|
||||
uint8_t pins[6]={ tPIN1, tPIN2, tPIN3, tPIN4, tPIN5, tPIN6 };
|
||||
uint8_t ports[6]={ 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
uint8_t latest_interrupted_pin;
|
||||
uint8_t interrupt_count[20]={0}; // 20 possible arduino pins
|
||||
uint8_t port;
|
||||
uint8_t mode;
|
||||
|
||||
ByteBuffer printBuffer(80);
|
||||
char charArray[16];
|
||||
char numBuffer[4] = { 0, 0, 0, 0 };
|
||||
uint8_t printFull=0;
|
||||
|
||||
volatile boolean start=0;
|
||||
volatile boolean initial=true;
|
||||
long begintime=0;
|
||||
long now=0;
|
||||
|
||||
void uint8ToString(char *outString, uint8_t number) {
|
||||
uint8_t hundreds=0;
|
||||
uint8_t tens=0;
|
||||
uint8_t ones=0;
|
||||
|
||||
while (number >= 100 ) {
|
||||
hundreds++;
|
||||
number-=100;
|
||||
}
|
||||
while (number >= 10 ) {
|
||||
tens++;
|
||||
number-=10;
|
||||
}
|
||||
ones=number;
|
||||
ones+=48;
|
||||
if (hundreds > 0) { hundreds+=48; tens+=48; outString[0]=hundreds; outString[1]=tens; outString[2]=ones; outString[3]=0; }
|
||||
else if (tens > 0) { tens+=48; outString[0]=tens; outString[1]=ones; outString[2]=0; }
|
||||
else { outString[0]=ones; outString[1]=0; };
|
||||
}
|
||||
|
||||
void showMode() {
|
||||
switch (mode) {
|
||||
case FALLING:
|
||||
printBuffer.putString((char *) "-F-");
|
||||
break;
|
||||
case RISING:
|
||||
printBuffer.putString((char *) "+R+");
|
||||
break;
|
||||
case CHANGE:
|
||||
printBuffer.putString((char *) "*C*");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void quicfunc0() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
mode=PCintPort::pinmode;
|
||||
showMode();
|
||||
if (start==1) {
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
}
|
||||
uint8ToString(numBuffer, latest_interrupted_pin);
|
||||
printBuffer.putString((char *) "f0p"); printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P");
|
||||
uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin));
|
||||
printBuffer.putString(numBuffer);
|
||||
if (start !=1) printBuffer.putString((char *) " (counting off)");
|
||||
printBuffer.putString((char *) NEWLINE);
|
||||
};
|
||||
|
||||
void quicfunc1() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
mode=PCintPort::pinmode;
|
||||
showMode();
|
||||
if (start==1) {
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
}
|
||||
uint8ToString(numBuffer, latest_interrupted_pin);
|
||||
printBuffer.putString((char *) "f1p"); printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P");
|
||||
uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin));
|
||||
printBuffer.putString(numBuffer);
|
||||
if (start !=1) printBuffer.putString((char *) " (counting off)");
|
||||
printBuffer.putString((char *) NEWLINE);
|
||||
};
|
||||
|
||||
void quicfunc2() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
mode=PCintPort::pinmode;
|
||||
showMode();
|
||||
if (start == 1) {
|
||||
printBuffer.putString((char *) "f2: STOP! Counting off.\n");
|
||||
printBuffer.putString((char *) "Interrupt OFF on tPIN1 ("); uint8ToString(numBuffer, tPIN1), printBuffer.putString(numBuffer);
|
||||
printBuffer.putString((char *) ") tPIN3 (");uint8ToString(numBuffer, tPIN3), printBuffer.putString(numBuffer);
|
||||
printBuffer.putString((char *) ") tPIN5 (");uint8ToString(numBuffer, tPIN5), printBuffer.putString(numBuffer);
|
||||
printBuffer.putString((char *) ")");
|
||||
printBuffer.putString((char *) NEWLINE);
|
||||
PCintPort::detachInterrupt(tPIN1); PCintPort::detachInterrupt(tPIN3); PCintPort::detachInterrupt(tPIN5);
|
||||
start=0;
|
||||
} else {
|
||||
start=1;
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
printBuffer.putString((char *) "START! f2p");
|
||||
uint8ToString(numBuffer, latest_interrupted_pin);
|
||||
printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P");
|
||||
uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin));
|
||||
printBuffer.putString(numBuffer); printBuffer.putString((char *) NEWLINE);
|
||||
if (! initial) {
|
||||
PCintPort::attachInterrupt(tPIN1, &quicfunc0, FALLING);
|
||||
PCintPort::attachInterrupt(tPIN3, &quicfunc0, CHANGE);
|
||||
PCintPort::attachInterrupt(tPIN5, &quicfunc1, CHANGE);
|
||||
} else {
|
||||
initial=false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
uint8_t i;
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(250);
|
||||
Serial.println("Test");
|
||||
for (i=0; i < 6; i++) {
|
||||
pinMode(pins[i], INPUT_PULLUP);
|
||||
ports[i]=digitalPinToPort(pins[i]);
|
||||
switch (pins[i]) {
|
||||
case tPIN1:
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc0, FALLING);
|
||||
break;
|
||||
case tPIN3:
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc0, CHANGE);
|
||||
break;
|
||||
case tPIN2:
|
||||
case tPIN4:
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc0, RISING);
|
||||
break;
|
||||
case tPIN5:
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc1, CHANGE);
|
||||
break;
|
||||
case tPIN6:
|
||||
attachPinChangeInterrupt(pins[i], quicfunc2, FALLING); // attachPinChangeInterrupt is a #define
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Serial.println(printBuffer.getCapacity(), DEC);
|
||||
//Serial.println("*---------------------------------------*");
|
||||
Serial.print("*---*");
|
||||
delay(250);
|
||||
begintime=millis();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
now=millis();
|
||||
uint8_t count;
|
||||
char outChar;
|
||||
// uint8_t bufsize;
|
||||
//if (printBuffer.getSize() != 0) { Serial.print("SZ:"); Serial.println (printBuffer.getSize(), DEC); };
|
||||
//bufsize=printBuffer.getSize();
|
||||
//if (bufsize > 0) { Serial.print("S:"); Serial.println(bufsize); }
|
||||
while ((outChar=(char)printBuffer.get()) != 0) Serial.print(outChar);
|
||||
if ((now - begintime) > 1000) {
|
||||
Serial.print(".");
|
||||
if (printBuffer.checkError()) {
|
||||
Serial.println("NOTICE: Some output lost due to filled buffer.");
|
||||
}
|
||||
for (i=0; i < 20; i++) {
|
||||
if (interrupt_count[i] != 0) {
|
||||
count=interrupt_count[i];
|
||||
interrupt_count[i]=0;
|
||||
Serial.print("Count for pin ");
|
||||
if (i < 14) {
|
||||
Serial.print("D");
|
||||
Serial.print(i, DEC);
|
||||
} else {
|
||||
Serial.print("A");
|
||||
Serial.print(i-14, DEC);
|
||||
}
|
||||
Serial.print(" is ");
|
||||
Serial.println(count, DEC);
|
||||
}
|
||||
}
|
||||
begintime=millis();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,275 @@
|
|||
//#define DISABLE_PCINT_MULTI_SERVICE
|
||||
#define PINMODE
|
||||
#define FLASH
|
||||
#include <GetPSTR.h>
|
||||
#include <ByteBuffer.h>
|
||||
#include <PinChangeInt.h>
|
||||
|
||||
// This example demonstrates a configuration of 6 interrupting pins and 3 interrupt functions.
|
||||
// A variety of interrupting pins have been chosen, so as to test all PORTs on the Arduino.
|
||||
// The pins are as follows:
|
||||
#define tPIN1 2 // port D
|
||||
#define tPIN2 3
|
||||
#define tPIN3 11 // Port B
|
||||
#define tPIN4 12
|
||||
#define tPIN5 A3 // Port C, also can be given as "17"
|
||||
#define tPIN6 A4 // starts and stops the count
|
||||
|
||||
uint8_t pins[6]={ tPIN1, tPIN2, tPIN3, tPIN4, tPIN5, tPIN6 };
|
||||
uint8_t ports[6]={ 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
uint8_t latest_interrupted_pin;
|
||||
uint8_t interrupt_count[20]={0}; // 20 possible arduino pins
|
||||
uint8_t port;
|
||||
uint8_t mode;
|
||||
|
||||
ByteBuffer printBuffer(200);
|
||||
char charArray[16];
|
||||
char numBuffer[5] = { 0, 0, 0, 0, 0 };
|
||||
uint8_t printFull=0;
|
||||
|
||||
volatile boolean start=0;
|
||||
volatile boolean initial=true;
|
||||
long begintime=0;
|
||||
long now=0;
|
||||
|
||||
void uint8ToHexString(char *outString, uint8_t theByte) {
|
||||
outString[0]='0'; outString[1]='x';
|
||||
uint8_t hinybble=theByte>>4;
|
||||
uint8_t lonybble=theByte & 0x0F;
|
||||
if (hinybble < 0x0a) outString[2]=hinybble+48;
|
||||
else outString[2]=hinybble+55;
|
||||
if (lonybble < 0x0a) outString[3]=lonybble+48;
|
||||
else outString[3]=lonybble+55;
|
||||
outString[4]=0;
|
||||
}
|
||||
|
||||
void uint8ToString(char *outString, uint8_t number) {
|
||||
uint8_t hundreds=0;
|
||||
uint8_t tens=0;
|
||||
uint8_t ones=0;
|
||||
|
||||
while (number >= 100 ) {
|
||||
hundreds++;
|
||||
number-=100;
|
||||
}
|
||||
while (number >= 10 ) {
|
||||
tens++;
|
||||
number-=10;
|
||||
}
|
||||
ones=number;
|
||||
ones+=48;
|
||||
if (hundreds > 0) { hundreds+=48; tens+=48; outString[0]=hundreds; outString[1]=tens; outString[2]=ones; outString[3]=0; }
|
||||
else if (tens > 0) { tens+=48; outString[0]=tens; outString[1]=ones; outString[2]=0; }
|
||||
else { outString[0]=ones; outString[1]=0; };
|
||||
}
|
||||
|
||||
void showMode() {
|
||||
switch (mode) {
|
||||
case FALLING:
|
||||
printBuffer.putString(getPSTR("-F-"));
|
||||
break;
|
||||
case RISING:
|
||||
printBuffer.putString(getPSTR("+R+"));
|
||||
break;
|
||||
case CHANGE:
|
||||
printBuffer.putString(getPSTR("*C*"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void quicfunc0() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
mode=PCintPort::pinmode;
|
||||
showMode();
|
||||
if (start==1) {
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
}
|
||||
uint8ToString(numBuffer, latest_interrupted_pin);
|
||||
printBuffer.putString((char *) "f0p"); printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P");
|
||||
uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin));
|
||||
printBuffer.putString(numBuffer);
|
||||
if (start !=1) printBuffer.putString(getPSTR(" no count"));
|
||||
printBuffer.putString((char *) "\n");
|
||||
};
|
||||
|
||||
void quicfunc1() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
mode=PCintPort::pinmode;
|
||||
showMode();
|
||||
if (start==1) {
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
}
|
||||
uint8ToString(numBuffer, latest_interrupted_pin);
|
||||
printBuffer.putString(getPSTR("f1p")); printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P");
|
||||
uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin));
|
||||
printBuffer.putString(numBuffer);
|
||||
if (start !=1) printBuffer.putString(getPSTR(" (counting off)"));
|
||||
printBuffer.putString((char *) "\n");
|
||||
};
|
||||
*/
|
||||
|
||||
void quicfunc2() {
|
||||
//*led_port|=led_mask;
|
||||
//*led_port&=not_led_mask; // 2 micros to here (ie, 2 micros used to push registers and call subroutine)
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
mode=PCintPort::pinmode;
|
||||
showMode();
|
||||
*led_port|=led_mask; // 73 micros to get here from above. Used in "Rigol Timing Example"
|
||||
*led_port&=not_led_mask;
|
||||
//uint8ToString(numBuffer, PCintPort::s_count); printBuffer.putString(numBuffer);
|
||||
*led_port|=led_mask; // 73 micros to get here from above. Second pulse in "Rigol Timing Example"
|
||||
*led_port&=not_led_mask;
|
||||
printBuffer.putString(getPSTR(" f2: P"));/*
|
||||
uint8ToHexString(numBuffer, *portInputRegister(3)); printBuffer.putString(numBuffer);// C port
|
||||
printBuffer.putString(getPSTR(" pin:")); uint8ToString(numBuffer, latest_interrupted_pin); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" c")); uint8ToHexString(numBuffer, PCintPort::curr); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" l")); uint8ToHexString(numBuffer, PCintPort::s_lastPinView); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" r")); uint8ToHexString(numBuffer, PCintPort::s_portRisingPins); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" f")); uint8ToHexString(numBuffer, PCintPort::s_portFallingPins); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" m")); uint8ToHexString(numBuffer, PCintPort::s_pmask); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" P")); printBuffer.put(PCintPort::s_PORT); printBuffer.putString("\r\n");
|
||||
printBuffer.putString(getPSTR("cp")); uint8ToHexString(numBuffer, PCintPort::s_changedPins); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" cXORlpv")); uint8ToHexString(numBuffer, PCintPort::s_currXORlastPinView); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" rp_nCurr")); uint8ToHexString(numBuffer, PCintPort::s_portRisingPins_nCurr); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" fp_nNCurr")); uint8ToHexString(numBuffer, PCintPort::s_portFallingPins_nNCurr); printBuffer.putString(numBuffer);
|
||||
*/printBuffer.putString("\r\n");
|
||||
if (PCintPort::pcint_multi > 0) {
|
||||
printBuffer.putString("MULTI!\n"); PCintPort::pcint_multi=0;
|
||||
}
|
||||
if (PCintPort::PCIFRbug > 0) { printBuffer.putString("ERROR: BUG- PCIFR should be reset!"); PCintPort::PCIFRbug=0; }
|
||||
//s_registers, if it existed, could be used to keep a running queue of the latest interrupts that have
|
||||
//been serviced by the PCint(). But generally I don't think it's necessary for debugging at this point (famous last words?)
|
||||
/*if (PCintPort::s_count > 2) {
|
||||
for (uint8_t i=0; i < PCintPort::s_count; i++) {
|
||||
uint8ToHexString(numBuffer, PCintPort::s_registers[i]); printBuffer.putString(numBuffer); printBuffer.putString(" ");
|
||||
}
|
||||
}
|
||||
PCintPort::s_count=0;*/
|
||||
/*
|
||||
if (start == 1) {
|
||||
printBuffer.putString(getPSTR("STOP Count off\n"));
|
||||
printBuffer.putString(getPSTR("Intr OFF: (")); uint8ToString(numBuffer, tPIN1), printBuffer.putString(numBuffer);
|
||||
printBuffer.putString((char *) " "); uint8ToString(numBuffer, tPIN3), printBuffer.putString(numBuffer);
|
||||
printBuffer.putString((char *) " "); uint8ToString(numBuffer, tPIN5), printBuffer.putString(numBuffer);
|
||||
printBuffer.putString((char *) ")\n");
|
||||
PCintPort::detachInterrupt(tPIN1); PCintPort::detachInterrupt(tPIN3); PCintPort::detachInterrupt(tPIN5);
|
||||
start=0;
|
||||
} else {
|
||||
start=1;
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
printBuffer.putString(getPSTR("START! p"));
|
||||
uint8ToString(numBuffer, latest_interrupted_pin);
|
||||
printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P");
|
||||
// MIKE put the REAL PORT HERE
|
||||
uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin));
|
||||
printBuffer.putString(numBuffer); printBuffer.putString((char *) "\n");
|
||||
if (! initial) {
|
||||
PCintPort::attachInterrupt(tPIN1, &quicfunc0, FALLING);
|
||||
PCintPort::attachInterrupt(tPIN3, &quicfunc0, CHANGE);
|
||||
PCintPort::attachInterrupt(tPIN5, &quicfunc1, CHANGE);
|
||||
} else {
|
||||
initial=false;
|
||||
}
|
||||
}*/
|
||||
};
|
||||
|
||||
uint8_t i;
|
||||
char hexBuffer[5];
|
||||
void setup() {
|
||||
int8_t returncode=1;
|
||||
Serial.begin(115200);
|
||||
Serial.println("Test");
|
||||
delay(500);
|
||||
for (i=5; i < 6; i++) {
|
||||
pinMode(pins[i], INPUT); digitalWrite(pins[i], HIGH);
|
||||
ports[i]=digitalPinToPort(pins[i]);
|
||||
switch (pins[i]) {
|
||||
/*case tPIN1:
|
||||
#if PCINT_VERSION > 2100
|
||||
returncode=PCintPort::attachInterrupt(pins[i], &quicfunc0, FALLING);
|
||||
#else
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc0, FALLING);
|
||||
#endif
|
||||
Serial.println(getPSTR("FIRST FAILURE OK."));
|
||||
break;
|
||||
case tPIN3:
|
||||
#if PCINT_VERSION > 2100
|
||||
returncode=PCintPort::attachInterrupt(pins[i], &quicfunc0, CHANGE);
|
||||
#else
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc0, CHANGE);
|
||||
#endif
|
||||
break;
|
||||
case tPIN2:
|
||||
case tPIN4:
|
||||
#if PCINT_VERSION > 2100
|
||||
returncode=PCintPort::attachInterrupt(pins[i], &quicfunc0, RISING);
|
||||
#else
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc0, RISING);
|
||||
#endif
|
||||
break;
|
||||
case tPIN5:
|
||||
#if PCINT_VERSION > 2100
|
||||
returncode=PCintPort::attachInterrupt(pins[i], &quicfunc1, CHANGE);
|
||||
#else
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc1, CHANGE);
|
||||
#endif
|
||||
break;*/
|
||||
case tPIN6:
|
||||
#if PCINT_VERSION > 2100
|
||||
returncode=PCintPort::attachInterrupt(pins[i], &quicfunc2, FALLING);
|
||||
#else
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc2, FALLING);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#if PCINT_VERSION > 2100
|
||||
Serial.print(getPSTR("setup(): Interrupt attach "));
|
||||
if (returncode != 1) Serial.print(getPSTR("unsuccessful "));
|
||||
else Serial.print(getPSTR("GOOD "));
|
||||
Serial.print(pins[i], DEC);
|
||||
Serial.print(getPSTR(":pin, code: ")); Serial.println(returncode, DEC);
|
||||
#endif
|
||||
}
|
||||
//Serial.println(printBuffer.getCapacity(), DEC);
|
||||
//Serial.println("*---------------------------------------*");
|
||||
Serial.print("*---*");
|
||||
delay(250);
|
||||
begintime=millis();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
now=millis();
|
||||
uint8_t count;
|
||||
char outChar;
|
||||
// uint8_t bufsize;
|
||||
//if (printBuffer.getSize() != 0) { Serial.print("SZ:"); Serial.println (printBuffer.getSize(), DEC); };
|
||||
//bufsize=printBuffer.getSize();
|
||||
//if (bufsize > 0) { Serial.print("S:"); Serial.println(bufsize); }
|
||||
while ((outChar=(char)printBuffer.get()) != 0) Serial.print(outChar);
|
||||
if ((now - begintime) > 1000) {
|
||||
Serial.print(".");
|
||||
if (printBuffer.checkError()) {
|
||||
Serial.println(getPSTR("!Some output lost due to full buffer!"));
|
||||
}
|
||||
for (i=0; i < 20; i++) {
|
||||
if (interrupt_count[i] != 0) {
|
||||
count=interrupt_count[i];
|
||||
interrupt_count[i]=0;
|
||||
Serial.print(getPSTR("Count for pin "));
|
||||
if (i < 14) {
|
||||
Serial.print("D");
|
||||
Serial.print(i, DEC);
|
||||
} else {
|
||||
Serial.print("A");
|
||||
Serial.print(i-14, DEC);
|
||||
}
|
||||
Serial.print(" is ");
|
||||
Serial.println(count, DEC);
|
||||
}
|
||||
}
|
||||
begintime=millis();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// PinChangeInt SimpleExample sketch
|
||||
// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information.
|
||||
|
||||
// for vim editing: :set et ts=2 sts=2 sw=2 et
|
||||
|
||||
// This example demonstrates the use of the PinChangeInt library on a single pin of your choice.
|
||||
// This only works for ATMega328-compatibles; ie, Leonardo is not covered here.
|
||||
// To use:
|
||||
|
||||
// 1. You must be using a fairly recent version of the Arduino IDE software on your PC/Mac,
|
||||
// that is, version 1.0.1 or later. Check Help->About Arduino in the IDE.
|
||||
|
||||
// 2. Wire a simple switch to any Analog or Digital pin (known as ARDUINOPIN, defined below).
|
||||
// Attach the other end to a GND pin. A "single pole single throw momentary contact"
|
||||
// pushbutton switch is best for the best interrupting fun.
|
||||
|
||||
// 3. When pressed, the switch will connect the pin to ground ("low", or "0") voltage, and interrupt the
|
||||
// processor. Don't let it confuse you that a switch press means the pin's voltage goes to 0; it
|
||||
// may seem more intuitive to apply a "1" or high voltage to the pin to represent "pressed".
|
||||
// But the processor is perfectly happy that we've made "0" equal "Pressed". The reason we've done so
|
||||
// is because we are using the "internal pullup resistor" feature of the processor... the chip gives
|
||||
// us a free resistor on every pin!
|
||||
// See http://arduino.cc/en/Tutorial/DigitalPins for a complete explanation.
|
||||
|
||||
// 4. The interrupt is serviced immediately, and the ISR (Interrupt SubRoutine) sets the value of a global
|
||||
// variable. The sketch can then query the value at its leisure. This makes loop timing non-critical.
|
||||
// Open Tools->Serial Monitor in the IDE to see the results of your interrupts.
|
||||
|
||||
// 5. See PinChangeIntExample328.ino (in the PinChangeInt distribution) for a more elaborate example.
|
||||
|
||||
// 6. Create your own sketch using the PinChangeInt library!
|
||||
|
||||
#include <PinChangeInt.h>
|
||||
|
||||
// Modify this at your leisure.
|
||||
#define ARDUINOPIN A4
|
||||
|
||||
// Notice that values that get modified inside an interrupt, that I wish to access
|
||||
// outside the interrupt, are marked "volatile". It tells the compiler not to optimize
|
||||
// the variable.
|
||||
volatile uint16_t interruptCount=0; // The count will go back to 0 after hitting 65535.
|
||||
|
||||
// Do not use any Serial.print() in interrupt subroutines. Serial.print() uses interrupts,
|
||||
// and by default interrupts are off in interrupt subroutines. Interrupt routines should also
|
||||
// be as fast as possible. Here we just increment a counter.
|
||||
void interruptFunction() {
|
||||
interruptCount++;
|
||||
}
|
||||
|
||||
// Attach the interrupt in setup()
|
||||
void setup() {
|
||||
pinMode(ARDUINOPIN, INPUT_PULLUP); // Configure the pin as an input, and turn on the pullup resistor.
|
||||
// See http://arduino.cc/en/Tutorial/DigitalPins
|
||||
attachPinChangeInterrupt(ARDUINOPIN, interruptFunction, FALLING);
|
||||
Serial.begin(115200);
|
||||
Serial.println("---------------------------------------");
|
||||
}
|
||||
|
||||
// In the loop, we just check to see where the interrupt count is at. The value gets updated by the
|
||||
// interrupt routine.
|
||||
void loop() {
|
||||
delay(1000); // Every second,
|
||||
Serial.print("Pin was interrupted: ");
|
||||
Serial.print(interruptCount, DEC); // print the interrupt count.
|
||||
Serial.println(" times so far.");
|
||||
}
|
||||
54
libraries/PinChangeInt/LICENSE
Normal file
54
libraries/PinChangeInt/LICENSE
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
Apache License
|
||||
|
||||
Version 2.0, January 2004
|
||||
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||
You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
27
libraries/PinChangeInt/NOTICE
Normal file
27
libraries/PinChangeInt/NOTICE
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
NOTICE
|
||||
PinChangeInt Arduino Library
|
||||
Copyright 2008 Chris J. Kiick
|
||||
Copyright 2009-2011 Lex Talionis
|
||||
Copyright 2010-2014 Michael Schwager (aka "GreyGnome")
|
||||
|
||||
This product includes software developed by Chris J. Kiick, Lex Talionis,
|
||||
and Mike Schwager (aka, 'GreyGnome').
|
||||
|
||||
This library was inspired by and derived from Chris J. Kiick's PCInt Arduino
|
||||
Playground example here: http://www.arduino.cc/playground/Main/PcInt
|
||||
|
||||
Lex Talionis picked it up, refined it, and created a Google Code page for
|
||||
it, found here: http://code.google.com/p/arduino-pinchangeint/
|
||||
|
||||
GreyGnome is the current maintainer, and would like to thank all those
|
||||
Open Source coders, the Arduino makers and community, and especially Chris
|
||||
and Lex for lighting the flame and showing the way! And a big thank you to
|
||||
the users who have contributed comments and bug fixes along the way.
|
||||
Without you this project would not have overcome some significant hurdles.
|
||||
A more complete list can be found in the README file.
|
||||
|
||||
A HUGE thanks to Jan Baeyens ("jantje"), who has graciously DONATED an
|
||||
Arduino Mega ADK board to the PinChangeInt project!!! Wow, thanks Jan!
|
||||
This makes the 2560-based Arduino Mega a first class supported platform-
|
||||
I will be able to test it and verify that it works.
|
||||
|
||||
652
libraries/PinChangeInt/PinChangeInt.h
Normal file
652
libraries/PinChangeInt/PinChangeInt.h
Normal file
|
|
@ -0,0 +1,652 @@
|
|||
// This file is part of the PinChangeInt library for the Arduino. This library will work on any ATmega328-based
|
||||
// or ATmega2560-based Arduino, as well as the Sanguino or Mioduino.
|
||||
|
||||
// Most of the pins of an Arduino Uno use Pin Change Interrupts, and because of the way the ATmega interrupt
|
||||
// system is designed it is difficult to trigger an Interrupt Service Request off of any single pin, and on
|
||||
// any change of state (either rising, or falling, or both). The goal of this library is to make it easy for
|
||||
// the programmer to attach an ISR so it will trigger on any change of state on any Pin Change Interrupt pin.
|
||||
|
||||
// (NOTE TO SELF: Update the PCINT_VERSION define, below) -----------------
|
||||
#define PCINT_VERSION 2402
|
||||
/*
|
||||
Copyright 2008 Chris J. Kiick
|
||||
Copyright 2009-2011 Lex Talionis
|
||||
Copyright 2010-2014 Michael Schwager (aka, "GreyGnome")
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* QUICKSTART
|
||||
*
|
||||
* For the beginners/lazy/busy/wreckless:
|
||||
* To attach an interrupt to your Arduino Pin, calling your function "userFunc", and acting on
|
||||
* the "mode", which is a change in the pin's state; either RISING or FALLING or CHANGE:
|
||||
* attachPinChangeInterrupt(pin,userFunc,mode)
|
||||
* Your function must not return any values and it cannot take any arguments (that is, its definition
|
||||
* has to look like this:
|
||||
* void userFunc() {
|
||||
* ...your code here...
|
||||
* }
|
||||
*
|
||||
* That's it. Everything else are details.
|
||||
*
|
||||
* If you need to exchange information to/from the interrupt, you can use global volatile variables.
|
||||
* See the example for more information.
|
||||
*
|
||||
* You probably will not need to do this, but later in your sketch you can detach the interrupt:
|
||||
* detachPinChangeInterrupt(pin)
|
||||
*
|
||||
* If you want to see what the *last* pin that triggered an interrupt was, you can get it this way:
|
||||
* getInterruptedPin()
|
||||
* Note: If you have multiple pins that are triggering interrupts and they are sufficiently fast,
|
||||
* you will not be able to find all the pins that interrupted.
|
||||
*/
|
||||
|
||||
//
|
||||
// For the beginners
|
||||
//
|
||||
#define detachPinChangeInterrupt(pin) PCintPort::detachInterrupt(pin)
|
||||
#define attachPinChangeInterrupt(pin,userFunc,mode) PCintPort::attachInterrupt(pin, &userFunc,mode)
|
||||
#define getInterruptedPin() PCintPort::getArduinoPin()
|
||||
|
||||
// We use 4-character tabstops, so IN VIM: <esc>:set ts=4 sw=4 sts=4
|
||||
// ...that's: ESCAPE key, colon key, then
|
||||
// "s-e-t SPACE key t-s = 4 SPACE key s-w = 4 SPACE key s-t-s = 4"
|
||||
|
||||
/*
|
||||
* This is the PinChangeInt library for the Arduino.
|
||||
This library provides an extension to the interrupt support for arduino by adding pin change
|
||||
interrupts, giving a way for users to have interrupts drive off of any pin (ATmega328-based
|
||||
Arduinos) and by the Port B, J, and K pins on the Arduino Mega and its ilk (see the README file).
|
||||
|
||||
See the README for license, acknowledgments, and other details (especially concerning the Arduino MEGA).
|
||||
|
||||
See google code project for latest, bugs and info http://code.google.com/p/arduino-pinchangeint/
|
||||
See github for the bleeding edge code: https://github.com/GreyGnome/PinChangeInt
|
||||
For more information Refer to avr-gcc header files, arduino source and atmega datasheet.
|
||||
|
||||
This library was inspired by and derived from Chris J. Kiick's PCInt Arduino Playground
|
||||
example here: http://www.arduino.cc/playground/Main/PcInt
|
||||
Nice job, Chris!
|
||||
*/
|
||||
|
||||
//-------- define these in your sketch, if applicable ----------------------------------------------------------
|
||||
//-------- These must go in your sketch ahead of the #include <PinChangeInt.h> statement -----------------------
|
||||
// You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts
|
||||
// on any one or two of the three ports. If only a single port remains, the handler will be declared inline
|
||||
// reducing the size and latency of the handler.
|
||||
// #define NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts
|
||||
// #define NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts
|
||||
// #define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts
|
||||
// --- Mega support ---
|
||||
// #define NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts
|
||||
// #define NO_PORTJ_PINCHANGES // to indicate that port j will not be used for pin change interrupts
|
||||
// #define NO_PORTK_PINCHANGES // to indicate that port k will not be used for pin change interrupts
|
||||
// In the Mega, there is no Port C, no Port D. Instead, you get Port J and Port K. Port B remains.
|
||||
// Port J, however, is practically useless because there is only 1 pin available for interrupts. Most
|
||||
// of the Port J pins are not even connected to a header connection. // </end> "Mega Support" notes
|
||||
// --- Sanguino, Mioduino support ---
|
||||
// #define NO_PORTA_PINCHANGES // to indicate that port a will not be used for pin change interrupts
|
||||
|
||||
// You can reduce the code size by 20-50 bytes, and you can speed up the interrupt routine
|
||||
// slightly by declaring that you don't care if the static variables PCintPort::pinState and/or
|
||||
// PCintPort::arduinoPin are set and made available to your interrupt routine.
|
||||
// #define NO_PIN_STATE // to indicate that you don't need the pinState
|
||||
// #define NO_PIN_NUMBER // to indicate that you don't need the arduinoPin
|
||||
// #define DISABLE_PCINT_MULTI_SERVICE // to limit the handler to servicing a single interrupt per invocation.
|
||||
// #define GET_PCINT_VERSION // to enable the uint16_t getPCIintVersion () function.
|
||||
// The following is intended for testing purposes. If defined, then a whole host of static variables can be read
|
||||
// in your interrupt subroutine. It is not defined by default, and you DO NOT want to define this in
|
||||
// Production code!:
|
||||
// #define PINMODE
|
||||
//-------- define the above in your sketch, if applicable ------------------------------------------------------
|
||||
|
||||
/*
|
||||
VERSIONS found in moved to RELEASE_NOTES.
|
||||
|
||||
See the README file for the License and more details.
|
||||
*/
|
||||
|
||||
#ifndef PinChangeInt_h
|
||||
#define PinChangeInt_h
|
||||
|
||||
#include "stddef.h"
|
||||
|
||||
// Maurice Beelen, nms277, Akesson Karlpetter, and Orly Andico
|
||||
// sent in fixes to work with Arduino >= version 1.0
|
||||
#include <Arduino.h>
|
||||
#include <new.h>
|
||||
#include <wiring_private.h> // cbi and sbi defined here
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
/*
|
||||
* Theory: For the IO pins covered by Pin Change Interrupts
|
||||
* (== all of them on the Atmega168/328, and a subset on the Atmega2560),
|
||||
* the PCINT corresponding to the pin must be enabled and masked, and
|
||||
* an ISR routine provided. Since PCINTs are per port, not per pin, the ISR
|
||||
* must use some logic to actually implement a per-pin interrupt service.
|
||||
*/
|
||||
|
||||
/* Pin to interrupt map, ATmega328:
|
||||
* D0-D7 = PCINT 16-23 = PCIR2 = PD = PCIE2 = pcmsk2
|
||||
* D8-D13 = PCINT 0-5 = PCIR0 = PB = PCIE0 = pcmsk0
|
||||
* A0-A5 (D14-D19) = PCINT 8-13 = PCIR1 = PC = PCIE1 = pcmsk1
|
||||
*/
|
||||
|
||||
#undef INLINE_PCINT
|
||||
#define INLINE_PCINT
|
||||
// Thanks to cserveny...@gmail.com for MEGA support!
|
||||
#if defined __AVR_ATmega2560__ || defined __AVR_ATmega1280__ || defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ || defined __AVR_ATmega640__
|
||||
#define __USE_PORT_JK
|
||||
// Mega does not have PORTA, C or D
|
||||
#define NO_PORTA_PINCHANGES
|
||||
#define NO_PORTC_PINCHANGES
|
||||
#define NO_PORTD_PINCHANGES
|
||||
#if ((defined(NO_PORTB_PINCHANGES) && defined(NO_PORTJ_PINCHANGES)) || \
|
||||
(defined(NO_PORTJ_PINCHANGES) && defined(NO_PORTK_PINCHANGES)) || \
|
||||
(defined(NO_PORTK_PINCHANGES) && defined(NO_PORTB_PINCHANGES)))
|
||||
#define INLINE_PCINT inline
|
||||
#endif
|
||||
#else
|
||||
#define NO_PORTJ_PINCHANGES
|
||||
#define NO_PORTK_PINCHANGES
|
||||
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
||||
#ifndef NO_PORTA_PINCHANGES
|
||||
#define __USE_PORT_A
|
||||
#endif
|
||||
#else
|
||||
#define NO_PORTA_PINCHANGES
|
||||
#endif
|
||||
// if defined only D .OR. only C .OR. only B .OR. only A, then inline it
|
||||
#if ( (defined(NO_PORTA_PINCHANGES) && defined(NO_PORTB_PINCHANGES) && defined(NO_PORTC_PINCHANGES)) || \
|
||||
(defined(NO_PORTA_PINCHANGES) && defined(NO_PORTB_PINCHANGES) && defined(NO_PORTD_PINCHANGES)) || \
|
||||
(defined(NO_PORTA_PINCHANGES) && defined(NO_PORTC_PINCHANGES) && defined(NO_PORTD_PINCHANGES)) || \
|
||||
(defined(NO_PORTB_PINCHANGES) && defined(NO_PORTC_PINCHANGES) && defined(NO_PORTD_PINCHANGES)) )
|
||||
#define INLINE_PCINT inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Provide drop in compatibility with Chris J. Kiick's PCInt project at
|
||||
// http://www.arduino.cc/playground/Main/PcInt
|
||||
#define PCdetachInterrupt(pin) PCintPort::detachInterrupt(pin)
|
||||
#define PCattachInterrupt(pin,userFunc,mode) PCintPort::attachInterrupt(pin, userFunc,mode)
|
||||
#define PCgetArduinoPin() PCintPort::getArduinoPin()
|
||||
|
||||
typedef void (*PCIntvoidFuncPtr)(void);
|
||||
|
||||
class PCintPort {
|
||||
public:
|
||||
// portB=PCintPort(2, 1,PCMSK1);
|
||||
// index: portInputReg(*portInputRegister(index)),
|
||||
// pcindex: PCICRbit(1 << pcindex)
|
||||
// maskReg: portPCMask(maskReg)
|
||||
PCintPort(int index,int pcindex, volatile uint8_t& maskReg) :
|
||||
portInputReg(*portInputRegister(index)),
|
||||
portPCMask(maskReg),
|
||||
PCICRbit(1 << pcindex),
|
||||
portRisingPins(0),
|
||||
portFallingPins(0),
|
||||
firstPin(NULL)
|
||||
#ifdef PINMODE
|
||||
,intrCount(0)
|
||||
#endif
|
||||
{
|
||||
#ifdef FLASH
|
||||
ledsetup();
|
||||
#endif
|
||||
}
|
||||
volatile uint8_t& portInputReg;
|
||||
static int8_t attachInterrupt(uint8_t pin, PCIntvoidFuncPtr userFunc, int mode);
|
||||
static void detachInterrupt(uint8_t pin);
|
||||
INLINE_PCINT void PCint();
|
||||
static volatile uint8_t curr;
|
||||
#ifndef NO_PIN_NUMBER
|
||||
static volatile uint8_t arduinoPin;
|
||||
#endif
|
||||
#ifndef NO_PIN_STATE
|
||||
static volatile uint8_t pinState;
|
||||
#endif
|
||||
#ifdef PINMODE
|
||||
static volatile uint8_t pinmode;
|
||||
static volatile uint8_t s_portRisingPins;
|
||||
static volatile uint8_t s_portFallingPins;
|
||||
static volatile uint8_t s_lastPinView;
|
||||
static volatile uint8_t s_pmask;
|
||||
static volatile char s_PORT;
|
||||
static volatile uint8_t s_changedPins;
|
||||
static volatile uint8_t s_portRisingPins_nCurr;
|
||||
static volatile uint8_t s_portFallingPins_nNCurr;
|
||||
static volatile uint8_t s_currXORlastPinView;
|
||||
volatile uint8_t intrCount;
|
||||
static volatile uint8_t s_count;
|
||||
static volatile uint8_t pcint_multi;
|
||||
static volatile uint8_t PCIFRbug;
|
||||
#endif
|
||||
#ifdef FLASH
|
||||
static void ledsetup(void);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
class PCintPin {
|
||||
public:
|
||||
PCintPin() :
|
||||
PCintFunc((PCIntvoidFuncPtr)NULL),
|
||||
mode(0) {}
|
||||
PCIntvoidFuncPtr PCintFunc;
|
||||
uint8_t mode;
|
||||
uint8_t mask;
|
||||
uint8_t arduinoPin;
|
||||
PCintPin* next;
|
||||
};
|
||||
void enable(PCintPin* pin, PCIntvoidFuncPtr userFunc, uint8_t mode);
|
||||
int8_t addPin(uint8_t arduinoPin,PCIntvoidFuncPtr userFunc, uint8_t mode);
|
||||
volatile uint8_t& portPCMask;
|
||||
const uint8_t PCICRbit;
|
||||
volatile uint8_t portRisingPins;
|
||||
volatile uint8_t portFallingPins;
|
||||
volatile uint8_t lastPinView;
|
||||
PCintPin* firstPin;
|
||||
};
|
||||
|
||||
#ifndef LIBCALL_PINCHANGEINT // LIBCALL_PINCHANGEINT ***********************************************
|
||||
volatile uint8_t PCintPort::curr=0;
|
||||
#ifndef NO_PIN_NUMBER
|
||||
volatile uint8_t PCintPort::arduinoPin=0;
|
||||
#endif
|
||||
#ifndef NO_PIN_STATE
|
||||
volatile uint8_t PCintPort::pinState=0;
|
||||
#endif
|
||||
#ifdef PINMODE
|
||||
volatile uint8_t PCintPort::pinmode=0;
|
||||
volatile uint8_t PCintPort::s_portRisingPins=0;
|
||||
volatile uint8_t PCintPort::s_portFallingPins=0;
|
||||
volatile uint8_t PCintPort::s_lastPinView=0;
|
||||
volatile uint8_t PCintPort::s_pmask=0;
|
||||
volatile char PCintPort::s_PORT='x';
|
||||
volatile uint8_t PCintPort::s_changedPins=0;
|
||||
volatile uint8_t PCintPort::s_portRisingPins_nCurr=0;
|
||||
volatile uint8_t PCintPort::s_portFallingPins_nNCurr=0;
|
||||
volatile uint8_t PCintPort::s_currXORlastPinView=0;
|
||||
volatile uint8_t PCintPort::s_count=0;
|
||||
volatile uint8_t PCintPort::pcint_multi=0;
|
||||
volatile uint8_t PCintPort::PCIFRbug=0;
|
||||
#endif
|
||||
|
||||
#ifdef FLASH
|
||||
#define PINLED 13
|
||||
volatile uint8_t *led_port;
|
||||
uint8_t led_mask;
|
||||
uint8_t not_led_mask;
|
||||
boolean ledsetup_run=false;
|
||||
void PCintPort::ledsetup(void) {
|
||||
if (! ledsetup_run) {
|
||||
led_port=portOutputRegister(digitalPinToPort(PINLED));
|
||||
led_mask=digitalPinToBitMask(PINLED);
|
||||
not_led_mask=led_mask^0xFF;
|
||||
pinMode(PINLED, OUTPUT); digitalWrite(PINLED, LOW);
|
||||
ledsetup_run=true;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
//
|
||||
// ATMEGA 644
|
||||
//
|
||||
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) // Sanguino, Mosquino uino bobino bonanafannafofino, me my momino...
|
||||
|
||||
#ifndef NO_PORTA_PINCHANGES
|
||||
PCintPort portA=PCintPort(1, 0,PCMSK0); // port PA==1 (from Arduino.h, Arduino version 1.0)
|
||||
#endif
|
||||
#ifndef NO_PORTB_PINCHANGES
|
||||
PCintPort portB=PCintPort(2, 1,PCMSK1); // port PB==2 (from Arduino.h, Arduino version 1.0)
|
||||
#endif
|
||||
#ifndef NO_PORTC_PINCHANGES
|
||||
PCintPort portC=PCintPort(3, 2,PCMSK2); // port PC==3 (also in pins_arduino.c, Arduino version 022)
|
||||
#endif
|
||||
#ifndef NO_PORTD_PINCHANGES
|
||||
PCintPort portD=PCintPort(4, 3,PCMSK3); // port PD==4
|
||||
#endif
|
||||
|
||||
#else // others
|
||||
|
||||
#ifndef NO_PORTB_PINCHANGES
|
||||
PCintPort portB=PCintPort(2, 0,PCMSK0); // port PB==2 (from Arduino.h, Arduino version 1.0)
|
||||
#endif
|
||||
#ifndef NO_PORTC_PINCHANGES // note: no PORTC on MEGA
|
||||
PCintPort portC=PCintPort(3, 1,PCMSK1); // port PC==3 (also in pins_arduino.c, Arduino version 022)
|
||||
#endif
|
||||
#ifndef NO_PORTD_PINCHANGES // note: no PORTD on MEGA
|
||||
PCintPort portD=PCintPort(4, 2,PCMSK2); // port PD==4
|
||||
#endif
|
||||
|
||||
#endif // defined __AVR_ATmega644__
|
||||
|
||||
#ifdef __USE_PORT_JK
|
||||
#ifndef NO_PORTJ_PINCHANGES
|
||||
PCintPort portJ=PCintPort(10,1,PCMSK1); // port PJ==10
|
||||
#endif
|
||||
#ifndef NO_PORTK_PINCHANGES
|
||||
PCintPort portK=PCintPort(11,2,PCMSK2); // port PK==11
|
||||
#endif
|
||||
#endif // USE_PORT_JK
|
||||
|
||||
static PCintPort *lookupPortNumToPort( int portNum ) {
|
||||
PCintPort *port = NULL;
|
||||
|
||||
switch (portNum) {
|
||||
#ifndef NO_PORTA_PINCHANGES
|
||||
case 1:
|
||||
port=&portA;
|
||||
break;
|
||||
#endif
|
||||
#ifndef NO_PORTB_PINCHANGES
|
||||
case 2:
|
||||
port=&portB;
|
||||
break;
|
||||
#endif
|
||||
#ifndef NO_PORTC_PINCHANGES
|
||||
case 3:
|
||||
port=&portC;
|
||||
break;
|
||||
#endif
|
||||
#ifndef NO_PORTD_PINCHANGES
|
||||
case 4:
|
||||
port=&portD;
|
||||
break;
|
||||
#endif
|
||||
#ifdef __USE_PORT_JK
|
||||
|
||||
#ifndef NO_PORTJ_PINCHANGES
|
||||
case 10:
|
||||
port=&portJ;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifndef NO_PORTK_PINCHANGES
|
||||
case 11:
|
||||
port=&portK;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#endif // __USE_PORT_JK
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
|
||||
void PCintPort::enable(PCintPin* p, PCIntvoidFuncPtr userFunc, uint8_t mode) {
|
||||
// Enable the pin for interrupts by adding to the PCMSKx register.
|
||||
// ...The final steps; at this point the interrupt is enabled on this pin.
|
||||
p->mode=mode;
|
||||
p->PCintFunc=userFunc;
|
||||
#ifndef NO_PORTJ_PINCHANGES
|
||||
// A big shout out to jrhelbert for this fix! Thanks!!!
|
||||
if ((p->arduinoPin == 14) || (p->arduinoPin == 15)) {
|
||||
portPCMask |= (p->mask << 1); // PORTJ's PCMSK1 is a little odd...
|
||||
}
|
||||
else {
|
||||
portPCMask |= p->mask;
|
||||
}
|
||||
#else
|
||||
portPCMask |= p->mask;
|
||||
#endif
|
||||
if ((p->mode == RISING) || (p->mode == CHANGE)) portRisingPins |= p->mask;
|
||||
if ((p->mode == FALLING) || (p->mode == CHANGE)) portFallingPins |= p->mask;
|
||||
PCICR |= PCICRbit;
|
||||
}
|
||||
|
||||
int8_t PCintPort::addPin(uint8_t arduinoPin, PCIntvoidFuncPtr userFunc, uint8_t mode)
|
||||
{
|
||||
PCintPin* tmp;
|
||||
|
||||
tmp=firstPin;
|
||||
// Add to linked list, starting with firstPin. If pin already exists, just enable.
|
||||
if (firstPin != NULL) {
|
||||
do {
|
||||
if (tmp->arduinoPin == arduinoPin) { enable(tmp, userFunc, mode); return(0); }
|
||||
if (tmp->next == NULL) break;
|
||||
tmp=tmp->next;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
// Create pin p: fill in the data.
|
||||
PCintPin* p=new PCintPin;
|
||||
if (p == NULL) return(-1);
|
||||
p->arduinoPin=arduinoPin;
|
||||
p->mode = mode;
|
||||
p->next=NULL;
|
||||
p->mask = digitalPinToBitMask(arduinoPin); // the mask
|
||||
|
||||
if (firstPin == NULL) firstPin=p;
|
||||
else tmp->next=p; // NOTE that tmp cannot be NULL.
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print("addPin. pin given: "); Serial.print(arduinoPin, DEC);
|
||||
int addr = (int) p;
|
||||
Serial.print(" instance addr: "); Serial.println(addr, HEX);
|
||||
Serial.print("userFunc addr: "); Serial.println((int)p->PCintFunc, HEX);
|
||||
#endif
|
||||
|
||||
enable(p, userFunc, mode);
|
||||
#ifdef DEBUG
|
||||
Serial.print("addPin. pin given: "); Serial.print(arduinoPin, DEC), Serial.print (" pin stored: ");
|
||||
int addr = (int) p;
|
||||
Serial.print(" instance addr: "); Serial.println(addr, HEX);
|
||||
#endif
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* attach an interrupt to a specific pin using pin change interrupts.
|
||||
*/
|
||||
int8_t PCintPort::attachInterrupt(uint8_t arduinoPin, PCIntvoidFuncPtr userFunc, int mode)
|
||||
{
|
||||
PCintPort *port;
|
||||
uint8_t portNum = digitalPinToPort(arduinoPin);
|
||||
if ((portNum == NOT_A_PORT) || (userFunc == NULL)) return(-1);
|
||||
|
||||
port=lookupPortNumToPort(portNum);
|
||||
// Added by GreyGnome... must set the initial value of lastPinView for it to be correct on the 1st interrupt.
|
||||
// ...but even then, how do you define "correct"? Ultimately, the user must specify (not provisioned for yet).
|
||||
port->lastPinView=port->portInputReg;
|
||||
#ifdef DEBUG
|
||||
Serial.print("attachInterrupt- pin: "); Serial.println(arduinoPin, DEC);
|
||||
#endif
|
||||
// map pin to PCIR register
|
||||
return(port->addPin(arduinoPin,userFunc,mode));
|
||||
}
|
||||
|
||||
void PCintPort::detachInterrupt(uint8_t arduinoPin)
|
||||
{
|
||||
PCintPort *port;
|
||||
PCintPin* current;
|
||||
uint8_t mask;
|
||||
uint8_t portNum = digitalPinToPort(arduinoPin);
|
||||
if (portNum == NOT_A_PORT) return;
|
||||
port=lookupPortNumToPort(portNum);
|
||||
mask=digitalPinToBitMask(arduinoPin);
|
||||
current=port->firstPin;
|
||||
while (current) {
|
||||
if (current->mask == mask) { // found the target
|
||||
uint8_t oldSREG = SREG;
|
||||
cli(); // disable interrupts
|
||||
#ifndef NO_PORTJ_PINCHANGES
|
||||
// A big shout out to jrhelbert for this fix! Thanks!!!
|
||||
if ((arduinoPin == 14) || (arduinoPin == 15)) {
|
||||
port->portPCMask &= ~(mask << 1); // PORTJ's PCMSK1 is a little odd...
|
||||
}
|
||||
else {
|
||||
port->portPCMask &= ~mask; // disable the mask entry.
|
||||
}
|
||||
#else
|
||||
port->portPCMask &= ~mask; // disable the mask entry.
|
||||
#endif
|
||||
if (port->portPCMask == 0) PCICR &= ~(port->PCICRbit);
|
||||
port->portRisingPins &= ~current->mask; port->portFallingPins &= ~current->mask;
|
||||
// TODO: This is removed until we can add code that frees memory.
|
||||
// Note that in the addPin() function, above, we do not define a new pin if it was
|
||||
// once already defined.
|
||||
// ... ...
|
||||
// Link the previous' next to the found next. Then remove the found.
|
||||
//if (prev != NULL) prev->next=current->next; // linked list skips over current.
|
||||
//else firstPin=current->next; // at the first pin; save the new first pin
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return;
|
||||
}
|
||||
current=current->next;
|
||||
}
|
||||
}
|
||||
|
||||
// common code for isr handler. "port" is the PCINT number.
|
||||
// there isn't really a good way to back-map ports and masks to pins.
|
||||
void PCintPort::PCint() {
|
||||
|
||||
#ifdef FLASH
|
||||
if (*led_port & led_mask) *led_port&=not_led_mask;
|
||||
else *led_port|=led_mask;
|
||||
#endif
|
||||
#ifndef DISABLE_PCINT_MULTI_SERVICE
|
||||
uint8_t pcifr;
|
||||
while (true) {
|
||||
#endif
|
||||
// get the pin states for the indicated port.
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_lastPinView=lastPinView;
|
||||
intrCount++;
|
||||
PCintPort::s_count=intrCount;
|
||||
#endif
|
||||
uint8_t changedPins = (PCintPort::curr ^ lastPinView) &
|
||||
((portRisingPins & PCintPort::curr ) | ( portFallingPins & ~PCintPort::curr ));
|
||||
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_currXORlastPinView=PCintPort::curr ^ lastPinView;
|
||||
PCintPort::s_portRisingPins_nCurr=portRisingPins & PCintPort::curr;
|
||||
PCintPort::s_portFallingPins_nNCurr=portFallingPins & ~PCintPort::curr;
|
||||
#endif
|
||||
lastPinView = PCintPort::curr;
|
||||
|
||||
PCintPin* p = firstPin;
|
||||
while (p) {
|
||||
// Trigger interrupt if the bit is high and it's set to trigger on mode RISING or CHANGE
|
||||
// Trigger interrupt if the bit is low and it's set to trigger on mode FALLING or CHANGE
|
||||
if (p->mask & changedPins) {
|
||||
#ifndef NO_PIN_STATE
|
||||
PCintPort::pinState=PCintPort::curr & p->mask ? HIGH : LOW;
|
||||
#endif
|
||||
#ifndef NO_PIN_NUMBER
|
||||
PCintPort::arduinoPin=p->arduinoPin;
|
||||
#endif
|
||||
#ifdef PINMODE
|
||||
PCintPort::pinmode=p->mode;
|
||||
PCintPort::s_portRisingPins=portRisingPins;
|
||||
PCintPort::s_portFallingPins=portFallingPins;
|
||||
PCintPort::s_pmask=p->mask;
|
||||
PCintPort::s_changedPins=changedPins;
|
||||
#endif
|
||||
p->PCintFunc();
|
||||
}
|
||||
p=p->next;
|
||||
}
|
||||
#ifndef DISABLE_PCINT_MULTI_SERVICE
|
||||
pcifr = PCIFR & PCICRbit;
|
||||
if (pcifr == 0) break;
|
||||
PCIFR |= PCICRbit;
|
||||
#ifdef PINMODE
|
||||
PCintPort::pcint_multi++;
|
||||
if (PCIFR & PCICRbit) PCintPort::PCIFRbug=1; // PCIFR & PCICRbit should ALWAYS be 0 here!
|
||||
#endif
|
||||
PCintPort::curr=portInputReg;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NO_PORTA_PINCHANGES
|
||||
ISR(PCINT0_vect) {
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_PORT='A';
|
||||
#endif
|
||||
PCintPort::curr = portA.portInputReg;
|
||||
portA.PCint();
|
||||
}
|
||||
#define PORTBVECT PCINT1_vect
|
||||
#define PORTCVECT PCINT2_vect
|
||||
#define PORTDVECT PCINT3_vect
|
||||
#else
|
||||
#define PORTBVECT PCINT0_vect
|
||||
#define PORTCVECT PCINT1_vect
|
||||
#define PORTDVECT PCINT2_vect
|
||||
#endif
|
||||
|
||||
#ifndef NO_PORTB_PINCHANGES
|
||||
ISR(PORTBVECT) {
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_PORT='B';
|
||||
#endif
|
||||
PCintPort::curr = portB.portInputReg;
|
||||
portB.PCint();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NO_PORTC_PINCHANGES
|
||||
ISR(PORTCVECT) {
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_PORT='C';
|
||||
#endif
|
||||
PCintPort::curr = portC.portInputReg;
|
||||
portC.PCint();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NO_PORTD_PINCHANGES
|
||||
ISR(PORTDVECT){
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_PORT='D';
|
||||
#endif
|
||||
PCintPort::curr = portD.portInputReg;
|
||||
portD.PCint();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __USE_PORT_JK
|
||||
#ifndef NO_PORTJ_PINCHANGES
|
||||
ISR(PCINT1_vect) {
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_PORT='J';
|
||||
#endif
|
||||
PCintPort::curr = portJ.portInputReg;
|
||||
portJ.PCint();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NO_PORTK_PINCHANGES
|
||||
ISR(PCINT2_vect){
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_PORT='K';
|
||||
#endif
|
||||
PCintPort::curr = portK.portInputReg;
|
||||
portK.PCint();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __USE_PORT_JK
|
||||
|
||||
#ifdef GET_PCINT_VERSION
|
||||
uint16_t getPCIntVersion () {
|
||||
return ((uint16_t) PCINT_VERSION);
|
||||
}
|
||||
#endif // GET_PCINT_VERSION
|
||||
#endif // #ifndef LIBCALL_PINCHANGEINT *************************************************************
|
||||
#endif // #ifndef PinChangeInt_h *******************************************************************
|
||||
45
libraries/PinChangeInt/Posting_Raising_Question.txt
Normal file
45
libraries/PinChangeInt/Posting_Raising_Question.txt
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
Prompted by this thread: https://groups.google.com/a/arduino.cc/forum/#!topic/developers/GkCunoVbuVA , I thought I would introduce a thread to spur discussion of creating a bona fide library that would enable Pin Change Interrupts on the Arduino (ATmega-based) processors, as first class interrupts equivalent to attachInterrupt(). I have been maintaining a library for the Arduino, and thinking about the technical details of such a thing for a while now as well.
|
||||
|
||||
Ultimately, any solution is going to carry with it some ugliness because the ATmega328p's interrupt model is, at least to a beginning user, ugly. Having two interrupt types is confusing and annoying; the attachInterrupt() function, like the whole concept of External vs Pin Change Interrupts, contains complexities specific to the ATmega 8-bit line. At the moment, the programmer needs to keep in mind this translation table:
|
||||
Board int.0 int.1 int.2 int.3 int.4 int.5
|
||||
Uno, Ethernet 2 3
|
||||
Mega2560 2 3 21 20 19 18
|
||||
Leonardo 3 2 0 1 7
|
||||
Due (no translation necessary, the pin number is referenced)
|
||||
|
||||
So if you have an 8-bit processor, there's no official support for "interrupt on any pin" so you must translate External Interrupts as per the table. If you are not (eg, Due): just use the pin number. To me that's the most intuitive and it's what I expected to see back when I was first working on the Arduino. But the situation is hard to fix: Different types of interrupts don't all respond to the same stimuli. External Interrupts respond on rising, or falling, or change (either high or low), or low level. Interrupts on 32-bit processors appear to support all of that, plus high level. Pin Change Interrupts by default only support change.
|
||||
|
||||
That said, what would be the ultimate goal of such a library? I think it makes the most sense to have a library that supports the concept of "Interrupt by pin number", and it would support as many modes as possible, with the PinChangeInterrupt mimicking the low and high modes in software. Here's some ideas:
|
||||
|
||||
* create a new enable function in the Arduino API, referencing the proper interrupt type under the covers. Only Arduino pin numbers are given as arguments but many of those pin numbers will not be available as External Interrupts on (especially) the ATmega328. So, to use the other pins, you have to make them Pin Change Interrupts, and OR the pin number with the flag PINCHANGEINTERRUPT. As its value is 0 on other architectures, it has no effect on the Due and Galileo.
|
||||
* Or, add code to the attachInterrupt() call to make it work with Pin Change Interrupts. Essentially, it would operate like the above.
|
||||
* Or, just create another library call, just for 8-bit Arduinos and their wonky Pin Change Interrupts (this is what I'd created).
|
||||
|
||||
Concerning a new function in the Arduino API, called for example, "enableInterrupt()":
|
||||
This call could look the same on any platform, and for 8-bit chips you'd need a flag so as to create the proper interrupt type for the programmer. The flag would be a no-op on other (32-bit) chips. For example:
|
||||
#ifdef defined(EICRA) && defined(EICRB) && defined(EIMSK)
|
||||
#define PINCHANGEINTERRUPT 0x80
|
||||
#define SLOWINTERRUPT 0x80
|
||||
...
|
||||
#ifdef NOT_ATMEGA
|
||||
#define PINCHANGEINTERRUPT 0
|
||||
#define SLOWINTERRUPT 0
|
||||
#endif
|
||||
|
||||
void enableInterrupt(interruptNumber, function, mode); // declaration
|
||||
enableInterrupt(2, 0, myFunction, LOW); // Usage example; this sets an interrupt on Arduino pin 2.
|
||||
// It is an external interrupt.
|
||||
// The following examples show that the 8-bit chips will create Pin Change Interrupts.
|
||||
// On the Due and Galileo, they will be regular interrupts (Because SLOWINTERRUPT==0 there).
|
||||
enableInterrupt(PINCHANGEINTERRUPT | 4, myFunction, RISING); // usage example for pin 4
|
||||
enableInterrupt(SLOWINTERRUPT | 4, myFunction, RISING); // same thing.
|
||||
enableInterrupt(4, myFunction, RISING); // ...as will this.
|
||||
|
||||
I don't see a way around the complexity and confusion of this call:
|
||||
enableInterrupt(PINCHANGEINTERRUPT | 4, myFunction, RISING); // usage example for pin 4
|
||||
but I think it's clearer than our current situation, where External Interrupts are officially supported but for Pin Change Interrupts the user is on his or her own, or they find a library somewhere.
|
||||
|
||||
On Monday, August 11, 2014 9:54:11 AM UTC-5, David A. Mellis wrote:
|
||||
|
||||
Just to throw in a random opinion: I think something like this would be good to include, although I haven't thought about the technical details. If it does get added, though, it should probably be called something like attachPinChangeInterrupt() as opposed to something with "PCINT" or "int".
|
||||
|
||||
109
libraries/PinChangeInt/README
Normal file
109
libraries/PinChangeInt/README
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
---- README --------------------------------------------------------------------
|
||||
PinChangeInt README. Find instructions and more information at
|
||||
http://code.google.com/p/arduino-pinchangeint/
|
||||
|
||||
---- DESCRIPTION ---------------------------------------------------------------
|
||||
This is the PinChangeInt library for the Arduino. It provides an extension to
|
||||
the interrupt support for ATmega328 and ATmega2560-based Arduinos, and some
|
||||
ATmega32u4 and Sanguinos. It adds pin change interrupts, giving a way for users
|
||||
to have interrupts drive off of any pin (ATmega328-based Arduinos), by the Port
|
||||
B, J, and K pins on the Arduino Mega and its ilk, and on the appropriate ports
|
||||
(including Port A) on the Sanguino and its ilk. Yun and Sanguino support are
|
||||
weak, quite honestly, as I don't have either a Sanguino or a Yun. Theoretically
|
||||
the library would work with a Leonardo but I have no reports regarding that
|
||||
platform. The ATmega32u4 has port B (8 pins) pin change interrupts only.
|
||||
|
||||
See Google Code project for latest, bugs and info:
|
||||
http://code.google.com/p/arduino-pinchangeint/
|
||||
See Github for the bleeding edge code:
|
||||
https://github.com/GreyGnome/PinChangeInt
|
||||
For more information refer to avr-gcc header files, Arduino source and Atmega
|
||||
datasheet.
|
||||
|
||||
This library was inspired by and derived from Chris J. Kiick's PCInt Arduino
|
||||
Playground example here: http://playground.arduino.cc/Main/PcInt
|
||||
|
||||
Regarding the MEGA and friends, Cserveny says: "J is mostly useless, because of
|
||||
the hardware UART... (many) pins are not connected on the arduino boards." The
|
||||
following pins are usable PinChangeInt pins on the Mega (ATmega1280 and
|
||||
ATmega2560-based Arduinos**):
|
||||
|
||||
Arduino Arduino Arduino
|
||||
Pin* PORT PCINT Pin PORT PCINT Pin PORT PCINT
|
||||
A8 PK0 16 10 PB4 4 SS PB0 0
|
||||
A9 PK1 17 11 PB5 5 SCK PB1 1
|
||||
A10 PK2 18 12 PB6 6 MOSI PB2 2
|
||||
A11 PK3 19 13 PB7 7** MISO PB3 3
|
||||
A12 PK4 20 14 PJ1 10
|
||||
A13 PK5 21 15 PJ0 9
|
||||
A14 PK6 22
|
||||
A15 PK7 23
|
||||
...indeed, the ATmega2560 chip supports many more Pin Change Interrupt pins but
|
||||
they are unavailable on the Arduino, unless you want to solder teeny tiny wires.
|
||||
|
||||
* Note: Arduino Pin 0 is PE0 (PCINT8), which is RX0 and thus is not supported by
|
||||
this library. It is the same pin the Arduino uses to upload sketches, and they
|
||||
are connected to the FT232RL USB-to-Serial chip (ATmega16U2 on the R3).
|
||||
** On the MegaADK, according to http://arduino.cc/en/Main/ArduinoBoardMegaADK:
|
||||
"USB Host: MAX3421E. The MAX3421E comunicate with Arduino with the SPI bus. So
|
||||
it uses the following pins:
|
||||
Digital: 7 (RST), 50 (MISO), 51 (MOSI), 52 (SCK). NB: Please do not use Digital
|
||||
pin 7 as input or output because is used in the comunication (sic) with
|
||||
MAX3421E "
|
||||
|
||||
---- LICENSE -------------------------------------------------------------------
|
||||
Licensed under the Apache2.0 license. See the source files for the license
|
||||
boilerplate, the LICENSE file for the full text, and the NOTICE file which the
|
||||
Apache2.0 license requires that you distribute with any code that you distribute
|
||||
that uses this library. The copyright holders for this code are Chris J. Kiick,
|
||||
Lex Talionis, and Michael Schwager. Chris and Lex have graciously agreed to the
|
||||
Apache 2.0 license for this code, and beginning with version 2.40-rc1 this is
|
||||
the license that applies.
|
||||
|
||||
---- ACKNOWLEDGMENTS -----------------------------------------------------------
|
||||
This library was originally written by Chris J. Kiick, Robot builder and all
|
||||
around geek, who said of it,
|
||||
"Hi, Yeah, I wrote the original PCint library. It was a bit of a hack
|
||||
and the new one has better features. I intended the code to be freely
|
||||
usable. Didn't really think about a license. Feel free to use it in
|
||||
your code: I hereby grant you permission."
|
||||
Thanks, Chris! A hack? I dare say not, if I have taken this any further it's
|
||||
merely by standing on the shoulders of giants. This library was the best
|
||||
"tutorial" I found on Arduino Pin Change Interrupts and because of that I
|
||||
decided to continue to maintain and (hopefully) improve it. We, the Arduino
|
||||
community of robot builders and geeks, owe you a great debt of gratitude for
|
||||
your hack- a hack in the finest sense.
|
||||
|
||||
The library was then picked up by Lex Talionis, who created the Google Code
|
||||
website. We all owe a debt of thanks to Lex, too, for all his hard work! He is
|
||||
currently the other official maintainer of this code.
|
||||
|
||||
Many thanks to all the contributors who have contributed bug fixes, code, and
|
||||
suggestions to this project:
|
||||
|
||||
John Boiles and Baziki (who added fixes to PcInt), Maurice Beelen, nms277,
|
||||
Akesson Karlpetter, and Orly Andico for various fixes to this code, Rob Tillaart
|
||||
for some excellent code reviews and nice optimizations, Andre' Franken for a
|
||||
good bug report that kept me thinking, cserveny.tamas a special shout out for
|
||||
providing the MEGA code to PinChangeInt, and Pat O'Brien for testing and
|
||||
reporting on the Arduino Yun.- Thanks!
|
||||
|
||||
A HUGE thanks to JRHelbert for fixing the PJ0 and PJ1 interrupt PCMSK1 issue on
|
||||
the Mega... 06/2014
|
||||
|
||||
A HUGE thanks to Jan Baeyens ("jantje"), who has graciously DONATED an Arduino
|
||||
Mega ADK to the PinChangeInt project!!! Wow, thanks Jan! This makes the
|
||||
2560-based Arduino Mega a first class supported platform- I will be able to test
|
||||
it and verify that it works.
|
||||
|
||||
Finally, a shout out to Leonard Bernstein. I was inspired by him
|
||||
(https://www.youtube.com/watch?feature=player_detailpage&v=R9g3Q-qvtss#t=1160)
|
||||
from a Ted talk by Itay Talgam. None of the contributors, myself included, has
|
||||
any interest in making money from this library and so I decided to free up the
|
||||
code as much as possible for any purpose. ...But! You must give credit where
|
||||
credit is due (it's not only a nice idea, it's the law- as in, the license
|
||||
terms)!
|
||||
|
||||
"If you love something, give it away."
|
||||
|
||||
If apologize if I have forgotten anyone here. Please let me know if so.
|
||||
436
libraries/PinChangeInt/RELEASE_NOTES
Normal file
436
libraries/PinChangeInt/RELEASE_NOTES
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
******************************************************************************
|
||||
|
||||
PinChangeInt
|
||||
---- RELEASE NOTES ---
|
||||
Version 2.40-rc2 Mon Jan 12 07:37:22 CST 2015
|
||||
Happy New Year!
|
||||
|
||||
Cleaned up some code, and added the following #define's for ease-of-use:
|
||||
|
||||
#define detachPinChangeInterrupt(pin) PCintPort::detachInterrupt(pin)
|
||||
#define attachPinChangeInterrupt(pin,userFunc,mode) PCintPort::attachInterrupt(pin, &userFunc,mode)
|
||||
#define getInterruptedPin() PCintPort::getArduinoPin()
|
||||
|
||||
Cleaned up the README for better display on GitHub.
|
||||
|
||||
Version 2.40-rc1 Fri Nov 7 07:26:36 CST 2014
|
||||
I'm going to the "-rcX" numbering format like the Linux kernel. That is, 2.40-rc1 is the first "release
|
||||
candidate" on the way to a stable 2.40 release.
|
||||
|
||||
Beginning with this release, only Arduino >= 1.00 is supported. The older Arduinos are left to the
|
||||
dustbin of history...
|
||||
|
||||
I have BIG news: Jan Baeyens ("jantje") has graciously DONATED an Arduino Mega ADK
|
||||
to the PinChangeInt project!!! Wow, thanks Jan! This makes the 2560-based Arduino Mega
|
||||
a first class supported platform- I will be able to test it and verify that it works.
|
||||
I have done so in this release.
|
||||
|
||||
To that end, The PinChangeIntExample has been modified to work properly with the Arduino Mega.
|
||||
Thanks, Jan!
|
||||
|
||||
And the BIG BIG BIG news: The library is now licensed under the Apache 2.0 License. I wanted to
|
||||
free the code up for any use, and Chris J. Kiick and Lex Talionis graciously agreed.
|
||||
|
||||
Version 2.32 Fri Oct 31 05:16:34 CDT 2014
|
||||
Argh! I should have done a "git status" prior to to tagging 2.31. Well, this makes 2.32.
|
||||
|
||||
I had added an additional method to putString, so as to allow for a different signature and stop
|
||||
the compiler from complaining:
|
||||
|
||||
uint8_t ByteBuffer::putString(const char *in) {
|
||||
return(putString((char *) in));
|
||||
}
|
||||
|
||||
No other changes over 2.32
|
||||
|
||||
Version 2.31 Fri Oct 31 05:11:41 CDT 2014
|
||||
I forgot to update these release notes for version 2.30. And I didn't tag it. This is merely a
|
||||
some housekeeping from 2.30. Here is what changed from version 2.21:
|
||||
|
||||
In Examples/PinChangeIntTest/PinChangeIntTest.ino:
|
||||
Whacked a nasty little bug in setup(), where my 'i' variable in the for
|
||||
loop went until 'i < 7'. Should have been 'i < 6' all along. Grrr.
|
||||
|
||||
In PinChangeInt.h:
|
||||
Most significantly: Many thanks to JRHelbert for fixing the PJ0 and PJ1
|
||||
interrupt PCMSK1 issue on the Arduino Mega! This was a great coup, in my
|
||||
humble opinion. Mega interrupt users are indebted to you, jrhelbert.
|
||||
|
||||
Added PinChangeIntDebug.ino, which is a simplified PinChangeIntTest. My
|
||||
head was spinning in PinChangeIntTest due to a nasty bug that I whacked,
|
||||
so I wanted a simplified test file.
|
||||
|
||||
|
||||
Version 2.21 (beta) Mon Apr 8 22:06:13 CDT 2013
|
||||
Fixed Examples/ByteBuffer/ByteBuffer.cpp. Bug in the PutString() method. Does not affect the behavior
|
||||
of the library at all whatsoever, this was only used in the example code.
|
||||
|
||||
Version 2.19 (beta) Tue Nov 20 07:33:37 CST 2012
|
||||
SANGUINO SUPPORT! ...And Mioduino!
|
||||
...The ATmega644 chip is so cool, how can I not? 4 full ports of Pin Change Interrupt bliss! 32 i/o pins! 64k Flash! 4k RAM! Well I wish I had one. That said, Sanguino users, PLEASE send in your bug or bliss reports! Your interrupt-loving brethren and sistren are depending on you, so I can assure everyone that my changes work on that platform. Thanks.
|
||||
|
||||
Modified the addPin() method to save 12 bytes; thanks again robtilllart!
|
||||
if (firstPin != NULL) {
|
||||
tmp=firstPin;
|
||||
do {
|
||||
if (tmp->arduinoPin == arduinoPin) { enable(tmp, userFunc, mode); return(0); }
|
||||
if (tmp->next == NULL) break;
|
||||
tmp=tmp->next;
|
||||
} while (true);
|
||||
}
|
||||
Also changed the goto in the PCint() loop to be a while/break combination. No change to
|
||||
code speed, but it looks better and passes the cleanliness "gut check".
|
||||
|
||||
Includes PinChangeIntTest 1.5 sketch.
|
||||
|
||||
...Ooops! Forgot the GetPSTR library, needed for the PinChangeIntTest code! Now it's included.
|
||||
******************************************************************************
|
||||
Version 2.17 (beta) Sat Nov 17 09:46:50 CST 2012
|
||||
Another bugfix in the PCINT_MULTI_SERVICE section. I was using sbi(PCIFR, PCICRbit);
|
||||
I didn't realize that was for I/O ports, and not ATmega registers.
|
||||
But according to "deprecated.h",
|
||||
"These macros became obsolete, as reading and writing IO ports can
|
||||
be done by simply using the IO port name in an expression, and all
|
||||
bit manipulation (including those on IO ports) can be done using
|
||||
generic C bit manipulation operators."
|
||||
So now I do:
|
||||
PCIFR |= PCICRbit;
|
||||
******************************************************************************
|
||||
Version 2.15 (beta) Sat Nov 17 01:17:44 CST 2012
|
||||
Fixed it so that attachInterrupt() will now follow your changes to the user function,
|
||||
as well as the mode. detachInterrupt() still does not delete the PCintPin object but
|
||||
at least you can detach and reattach at will, using different modes (RISING, FALLING,
|
||||
CHANGE) and different functions as you wish.
|
||||
|
||||
******************************************************************************
|
||||
Version 2.13 (beta) Mon Nov 12 09:33:06 CST 2012
|
||||
SIGNIFICANT BUGFIX release! Significant changes:
|
||||
1. PCintPort::curr bug. Interrupts that occur rapidly will likely not get serviced properly by PCint().
|
||||
2. PCint() interrupt handler optimization.
|
||||
3. PCIFR port bit set bug fix.
|
||||
4. Many static variables added for debugging; used only when #define PINMODE is on.
|
||||
5. detachInterrupt() no longer does a delete(), since that wasn't working anyway. When you detachInterrupt(), the PORT just disables interrupts for that pin; the PCintPin object remains in memory and in the linked list of pins (possibly slowing down your interrupts a couple of micros). You can reenable a detached interrupt- but you must do it within the PinChangeInt library (would anyone ever enable an interrupt on a pin, then disable it, then have need to reenable it but not using the library?).
|
||||
6. attachInterrupt() now returns a uint8_t value: 1 on successful attach, 0 on successful attach but using an already-enabled pin, and -1 if the new() operator failed to create a PCintPin object.
|
||||
Also, modified these release notes.
|
||||
|
||||
Details:
|
||||
|
||||
Uncovered a nasty bug, thanks to robtillaart on the Arduino Forums and Andre' Franken who posted to the PinChangeInt groups. This bug was introduced by me when I assigned PCintPort::curr early in the interrupt handler:
|
||||
ISR(PCINT0_vect) {
|
||||
PCintPort::curr = portB.portInputReg;
|
||||
portB.PCint();
|
||||
}
|
||||
Later, in the interrupt handler PCint(), we loop as long as PCIFR indicates a new interrupt wants to be triggered, provided DISABLE_PCINT_MULTI_SERVICE is not defined (it is not by default):
|
||||
#ifndef DISABLE_PCINT_MULTI_SERVICE
|
||||
pcifr = PCIFR & PCICRbit;
|
||||
PCIFR = pcifr; // clear the interrupt if we will process it (no effect if bit is zero)
|
||||
} while(pcifr);
|
||||
#endif
|
||||
...Well. Problem is, if a pin pops up and causes the PCIFR to change, we have to reread the port and look at how it is now! I wasn't doing that before, so if a new interrupt appeared while I was still servicing the old one, odd behavior would take place. For example, an interrupt would register but then the userFunc would not be called upon to service it. The code needs to be:
|
||||
pcifr = PCIFR & PCICRbit;
|
||||
PCIFR = pcifr; // clear the interrupt if we will process it (no effect if bit is zero)
|
||||
PCintPort::curr=portInputReg; // ...Fixed in 2.11beta.
|
||||
} while(pcifr);
|
||||
|
||||
Also, made the interrupt handler even faster with an optimization from robtillaart to take out the checks for changed pins from the while() loop that steps through the pins:
|
||||
uint8_t changedPins = (PCintPort::curr ^ lastPinView) &
|
||||
((portRisingPins & PCintPort::curr ) | ( portFallingPins & ~PCintPort::curr ));
|
||||
|
||||
...This speedup is offset by more changes in the PCint() handler, which now looks like the following; there are two bug fixes:
|
||||
----------------------------
|
||||
FIX 1: sbi(PCIFR, PCICRbit);
|
||||
FIX 2: ...the aforementioned PCintPort::curr=portInputReg;
|
||||
Here's the new code:
|
||||
----------------------------
|
||||
#ifndef DISABLE_PCINT_MULTI_SERVICE
|
||||
pcifr = PCIFR & PCICRbit;
|
||||
if (pcifr) {
|
||||
//if (PCIFR & PCICRbit) { // believe it or not, this adds .6 micros
|
||||
sbi(PCIFR, PCICRbit); // This was a BUG: PCIFR = pcifr ...And here is the fix.
|
||||
#ifdef PINMODE
|
||||
PCintPort::pcint_multi++;
|
||||
if (PCIFR & PCICRbit) PCintPort::PCIFRbug=1; // PCIFR & PCICRbit should ALWAYS be 0 here!
|
||||
#endif
|
||||
PCintPort::curr=portInputReg; // ...Fixed in 2.11beta.
|
||||
goto loop; // A goto!!! Don't want to look at the portInputReg gratuitously, so the while() will not do.
|
||||
}
|
||||
#endif
|
||||
|
||||
Also I added a lot of variables for debugging when PINMODE is defined, for routing out nasty bugs. I may need them in the future... :-(
|
||||
|
||||
Finally, I am not putting newlines in this commentary so I can make it easier to paste online.
|
||||
|
||||
******************************************************************************
|
||||
Version 2.11 (beta) Mon Nov 12 09:33:06 CST 2012
|
||||
See version 2.13 (beta) above. No change other than tidying up the release notes.
|
||||
******************************************************************************
|
||||
Version 2.01 (beta) Thu Jun 28 12:35:48 CDT 2012
|
||||
...Wow, Version 2! What? Why?
|
||||
Modified the way that the pin is tested inside the interrupt subroutine (ISR) PCintPort::PCint(),
|
||||
to make the interrupt quicker and slightly reduce the memory footprint. The interrupt's time is
|
||||
reduced by 2 microseconds or about 7%. Instead of using the mode variable, two bitmasks are maintained
|
||||
for each port. One bitmask contains all the pins that are configured to work on RISING signals, the other
|
||||
on FALLING signals. A pin configured to work on CHANGE signals will appear in both bitmasks of the port.
|
||||
Then, the test for a change goes like this:
|
||||
if (thisChangedPin) {
|
||||
if ((thisChangedPin & portRisingPins & PCintPort::curr ) ||
|
||||
(thisChangedPin & portFallingPins & ~PCintPort::curr )) {
|
||||
where portRisingPins is the bitmask for the pins configured to interrupt on RISING signals, and
|
||||
portFallingPins is the bitmask for the pins configured to interrupt on FALLING signals. Each port includes
|
||||
these two bitmask variables.
|
||||
|
||||
This is a significant change to some core functionality to the library, and it saves an appreciable amount
|
||||
of time (2 out of 36 or so micros). Hence, the 2.00 designation.
|
||||
|
||||
Tue Jun 26 12:42:20 CDT 2012
|
||||
I was officially given permission to use the PCint library:
|
||||
|
||||
Re: PCint library
|
||||
« Sent to: GreyGnome on: Today at 08:10:33 AM »
|
||||
« You have forwarded or responded to this message. »
|
||||
Quote Reply Remove
|
||||
HI,
|
||||
Yeah, I wrote the original PCint library. It was a bit of a hack and the new one has better features.
|
||||
I intended the code to be freely usable. Didn't really think about a license. Feel free to use it in
|
||||
your code: I hereby grant you permission.
|
||||
|
||||
I'll investigate the MIT license, and see if it is appropriate.
|
||||
Chris J. Kiick
|
||||
Robot builder and all around geek.
|
||||
|
||||
Version 1.81 (beta) Tue Jun 19 07:29:08 CDT 2012
|
||||
Created the getPCIntVersion function, and its associated GET_PCINT_VERSION preprocessor macro. The version
|
||||
is a 16-bit int, therefore versions are represented as a 4-digit integer. 1810, then, is the first beta
|
||||
release of 1.81x series. 1811 would be a bugfix of 1.810. 1820 would be the production release.
|
||||
|
||||
Reversed the order of this list, so the most recent notes come first.
|
||||
|
||||
Made some variables "volatile", because they are changed in the interrupt code. Thanks, Tony Cappellini!
|
||||
|
||||
Added support for the Arduino Mega! Thanks to cserveny...@gmail.com!
|
||||
NOTE: I don't have a Mega, so I rely on you to give me error (or working) reports!
|
||||
To sum it up for the Mega: No Port C, no Port D. Instead, you get Port J and Port K. Port B remains.
|
||||
Port J, however, is practically useless because there is only 1 pin available for interrupts.
|
||||
Most of the Port J pins are not even connected to a header connector. Caveat Programmer.
|
||||
|
||||
Created a function to report the version of this code. Put this #define ahead of the #include of this file,
|
||||
in your sketch:
|
||||
#define GET_PCINT_VERSION
|
||||
Then you can call
|
||||
uint16_t getPCIntVersion ();
|
||||
and it will return a 16-bit integer representation of the version of this library. That is, version 1.73beta
|
||||
will be reported as "1730". 1.74, then, will return "1740". And so on, for whatever version of the library
|
||||
this happens to be. The odd number in the 10's position will indicate a beta version, as per usual, and the
|
||||
number in the 1s place will indicate the beta revision (bugs may necessitate a 1.731, 1.732, etc.).
|
||||
|
||||
Here are some of his notes based on his changes:
|
||||
Mega and friends are using port B, J and K for interrupts. B is working without any modifications.
|
||||
|
||||
J is mostly useless, because of the hardware UART. I was not able to get pin change notifications from
|
||||
the TX pin (14), so only 15 left. All other (PORT J) pins are not connected on the Arduino boards.
|
||||
|
||||
K controls Arduino pin A8-A15, working fine.
|
||||
|
||||
328/168 boards use C and D. So in case the lib is compiled with Mega target, the C and D will be
|
||||
disabled. Also you cannot see port J/K with other targets. For J and K new flags introduced:
|
||||
NO_PORTJ_PINCHANGES and NO_PORTK_PINCHANGES.
|
||||
Maybe we should have PORTJ_PINCHANGES to enable PJ, because they will be most likely unused.
|
||||
|
||||
Enjoy!
|
||||
|
||||
Note: To remain consistent, I have not included PORTJ_PINCHANGES. All ports behave the same,
|
||||
no matter how trivial those ports may seem... no surprises...
|
||||
|
||||
Version 1.72 Wed Mar 14 18:57:55 CDT 2012
|
||||
Release.
|
||||
|
||||
Version 1.71beta Sat Mar 10 12:57:05 CST 2012
|
||||
Code reordering: Starting in version 1.3 of this library, I put the code that enables
|
||||
interrupts for the given pin, and the code that enables Pin Change Interrupts, ahead of actually
|
||||
setting the user's function for the pin. Thus in the small interval between turning on the
|
||||
interrupts and actually creating a valid link to an interrupt handler, it is possible to get an
|
||||
interrupt. At that point the value of the pointer is 0, so this means that the Arduino
|
||||
will start over again from memory location 0- just as if you'd pressed the reset button. Oops!
|
||||
|
||||
I corrected it so the code now operates in the proper order.
|
||||
(EDITORIAL NOTE: If you want to really learn something, teach it!)
|
||||
|
||||
Minor code clean-up: All references to PCintPort::curr are now explicit. This changes the compiled
|
||||
hex code not one whit. I just sleep better at night.
|
||||
|
||||
Numbering: Changed the numbering scheme. Beta versions will end with an odd number in the hundredths
|
||||
place- because they may be odd- and continue to be marked "beta". I'll just sleep better at night. :-)
|
||||
|
||||
Version 1.70beta Mon Feb 27 07:20:42 CST 2012
|
||||
Happy Birthday to me! Happy Birthday tooooo meee! Happy Birthday, Dear Meeeeee-eeeee!
|
||||
Happy Birthday to me!
|
||||
|
||||
Yes, it is on this auspicious occasion of mine (and Elizabeth Taylor's [R.I.P.]) birthday that I
|
||||
humbly submit to you, gracious Arduino PinChangeInt user, version 1.70beta of the PinChangeInt
|
||||
library. I hope you enjoy it.
|
||||
|
||||
New in this release:
|
||||
The PinChangeIntTest sketch was created, which can be found in the Examples directory. It exercises:
|
||||
* Two interrupting pins, one on each of the Arduino's PORTs.
|
||||
* detachInterrupt() (and subsequent attachInterrupt()s).
|
||||
Hopefully this will help avoid the embarrassing bugs that I have heretofore missed.
|
||||
|
||||
As well, it has come to this author's (GreyGnome) attention that the Serial class in Arduino 1.0
|
||||
uses an interrupt that, if you attempt to print from an interrupt (which is what I was doing in my
|
||||
tests) can easily lock up the Arduino. So I have taken SigurðurOrn's excellent ByteBuffer library
|
||||
and modified it for my own nefarious purposes. (see http://siggiorn.com/?p=460). The zipfile
|
||||
comes complete with the ByteBuffer library; see the ByteBuffer/ByteBuffer.h file for a list of
|
||||
changes, and see the PinChangeIntTest sketch for a usage scenario. Now the (interrupt-less and)
|
||||
relatively fast operation of filling a circular buffer is used in the interrupt routines. The buffer
|
||||
is then printed from loop().
|
||||
|
||||
The library has been modified so it can be used in other libraries, such as my AdaEncoder library
|
||||
(http://code.google.com/p/adaencoder/). When #include'd by another library you should #define
|
||||
the LIBCALL_PINCHANGEINT macro. For example:
|
||||
#ifndef PinChangeInt_h
|
||||
#define LIBCALL_PINCHANGEINT
|
||||
#include "../PinChangeInt/PinChangeInt.h"
|
||||
#endif
|
||||
This is necessary because the IDE compiles both your sketch and the .cpp file of your library, and
|
||||
the .h file is included in both places. But since the .h file actually contains the code, any variable
|
||||
or function definitions would occur twice and cause compilation errors- unless #ifdef'ed out.
|
||||
|
||||
Version 1.6beta Fri Feb 10 08:48:35 CST 2012
|
||||
Set the value of the current register settings, first thing in each ISR; e.g.,
|
||||
ISR(PCINT0_vect) {
|
||||
PCintPort::curr = portB.portInputReg; // version 1.6
|
||||
...
|
||||
...instead of at the beginning of the PCintPort::PCint() static method. This means that the port is read
|
||||
closer to the beginning of the interrupt, and may be slightly more accurate- only by a couple of microseconds,
|
||||
really, but it's a cheap win.
|
||||
|
||||
Fixed a bug- a BUG!- in the attachInterrupt() and detachInterrupt() methods. I didn't have breaks in my
|
||||
switch statements! Augh! What am I, a (UNIX) shell programmer? ...Uh, generally, yes...
|
||||
|
||||
Added the PINMODE define and the PCintPort::pinmode variable.
|
||||
|
||||
Version 1.51 Sun Feb 5 23:28:02 CST 2012
|
||||
Crap, a bug! Changed line 392 from this:
|
||||
PCintPort::pinState=curr & changedPins ? HIGH : LOW;
|
||||
to this:
|
||||
PCintPort::pinState=curr & p->mask ? HIGH : LOW;
|
||||
Also added a few lines of (commented-out) debug code.
|
||||
|
||||
Version 1.5 Thu Feb 2 18:09:49 CST 2012
|
||||
Added the PCintPort::pinState static variable to allow the programmer to query the state of the pin
|
||||
at the time of interrupt.
|
||||
Added two new #defines, NO_PIN_STATE and NO_PIN_NUMBER so as to reduce the code size by 20-50 bytes,
|
||||
and to speed up the interrupt routine slightly by declaring that you don't care if the static variables
|
||||
PCintPort::pinState and/or PCintPort::arduinoPin are set and made available to your interrupt routine.
|
||||
// #define NO_PIN_STATE // to indicate that you don't need the pinState
|
||||
// #define NO_PIN_NUMBER // to indicate that you don't need the arduinoPin
|
||||
|
||||
Version 1.4 Tue Jan 10 09:41:14 CST 2012
|
||||
All the code has been moved into this .h file, so as to allow #define's to work from the user's
|
||||
sketch. Thanks to Paul Stoffregen from pjrc.com for the inspiration! (Check out his website for
|
||||
some nice [lots more memory] Arduino-like boards at really good prices. ...This has been an unsolicited
|
||||
plug. Now back to our regular programming. ...Hehe, "programming", get it?)
|
||||
|
||||
As a result, we no longer use the PinChangeIntConfig.h file. The user must #define things in his/her
|
||||
sketch. Which is better anyway.
|
||||
|
||||
Removed the pcIntPorts[] array, which created all the ports by default no matter what. Now, only
|
||||
those ports (PCintPort objects) that you need will get created if you use the NO_PORTx_PINCHANGES #defines.
|
||||
This saves flash memory, and actually we get a bit of a memory savings anyway even if all the ports are
|
||||
left enabled.
|
||||
|
||||
The attachInterrupt and detachInterrupt routines were modified to handle the new PCintPort objects.
|
||||
|
||||
Version 1.3 Sat Dec 3 22:56:20 CST 2011
|
||||
Significant internal changes:
|
||||
Tested and modified to work with Arduino 1.0.
|
||||
|
||||
Modified to use the new() operator and symbolic links instead of creating a pre-populated
|
||||
PCintPins[]. Renamed some variables to simplify or make their meaning more obvious (IMHO anyway).
|
||||
Modified the PCintPort::PCint() code (ie, the interrupt code) to loop over a linked-list. For
|
||||
those who love arrays, I have left some code in there that should work to loop over an array
|
||||
instead. But it is commented out in the release version.
|
||||
|
||||
For Arduino versions prior to 1.0: The new() operator requires the cppfix.h library, which is
|
||||
included with this package. For Arduino 1.0 and above: new.h comes with the distribution, and
|
||||
that is #included.
|
||||
|
||||
Version 1.2 Sat Dec 3 Sat Dec 3 09:15:52 CST 2011
|
||||
Modified Thu Sep 8 07:33:17 CDT 2011 by GreyGnome. Fixes a bug with the initial port
|
||||
value. Now it sets the initial value to be the state of the port at the time of
|
||||
attachInterrupt(). The line is port.PCintLast=port.portInputReg; in attachInterrupt().
|
||||
See GreyGnome comment, below.
|
||||
|
||||
Added the "arduinoPin" variable, so the user's function will know exactly which pin on
|
||||
the Arduino was triggered.
|
||||
|
||||
Version 1.1 Sat Dec 3 00:06:03 CST 2011
|
||||
...updated to fix the "delPin" function as per "pekka"'s bug report. Thanks!
|
||||
|
||||
---- ^^^ VERSIONS ^^^ (NOTE TO SELF: Update the PCINT_VERSION define, below) -------------
|
||||
|
||||
See google code project for latest, bugs and info http://code.google.com/p/arduino-pinchangeint/
|
||||
For more information Refer to avr-gcc header files, arduino source and atmega datasheet.
|
||||
|
||||
This library was inspired by and derived from "johnboiles" (it seems)
|
||||
PCInt Arduino Playground example here: http://www.arduino.cc/playground/Main/PcInt
|
||||
If you are the original author, please let us know at the google code page
|
||||
|
||||
It provides an extension to the interrupt support for arduino by
|
||||
adding pin change interrupts, giving a way for users to have
|
||||
interrupts drive off of any pin.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
NOTES ================================================================================
|
||||
|
||||
Serial.print()----------------
|
||||
|
||||
Serial.print() does not work well inside interrupts. This is because it uses interrupts,
|
||||
and while you are in an interrupt, interrupts are (by default) turned off.
|
||||
Serial is declared in /usr/share/arduino/hardware/arduino/cores/arduino/HardwareSerial.h .
|
||||
In the write() method in the .cpp file, for example it says:
|
||||
...
|
||||
// If the output buffer is full, there's nothing for it other than to
|
||||
// wait for the interrupt handler to empty it a bit
|
||||
// ???: return 0 here instead?
|
||||
while (i == _tx_buffer->tail)
|
||||
;
|
||||
...
|
||||
And the ISR is further down in that file (this for the ATmega328 I believe):
|
||||
ISR(USART_RX_vect)
|
||||
...
|
||||
|
||||
If a user wants to try to use Serial.print() inside an ISR, I believe it's possible
|
||||
(by turning on interrupts inside the interrupt)...
|
||||
but it would require them to be aware of any possible contention between the interrupts,
|
||||
and the print ISRs.
|
||||
|
||||
|
||||
Software Serial----------
|
||||
Also, the SoftwareSerial library defines ISRs for Pin Change Interrupt ports:
|
||||
|
||||
ISR(PCINT0_vect)
|
||||
{
|
||||
SoftwareSerial::handle_interrupt();
|
||||
}
|
||||
|
||||
...It defines the interrupt on all ports, whether it's using them or not
|
||||
(the library cannot know ahead of time if the user will be using a set of pins
|
||||
or not).
|
||||
|
||||
To ensure compatibility with the SoftwareSerial library, the user should comment
|
||||
out the ports that they are NOT using with the SoftwareSerial library, in
|
||||
/usr/share/arduino/libraries/SoftwareSerial/SoftwareSerial.cpp
|
||||
and comment out the ports that they ARE using with this library in PinChangeInt.h
|
||||
70
libraries/PinChangeInt/Technical_Notes
Normal file
70
libraries/PinChangeInt/Technical_Notes
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
The purpose of this library is to give the programmer the ability to add interrupts
|
||||
with the easy of attachInterrupt, which looks like this:
|
||||
attachInterrupt(interrupt, &function, MODE)
|
||||
...the interrupt is a number which gets translated to the proper pin on the Arduino. For example,
|
||||
Board int.0 int.1 int.2 int.3 int.4 int.5
|
||||
Uno, Ethernet 2 3
|
||||
Mega2560 2 3 21 20 19 18
|
||||
Leonardo 3 2 0 1 7
|
||||
Due (doesn't use interrupt numbers, it uses the pin numbers directly)
|
||||
|
||||
The MODE is LOW, CHANGE, RISING, or FALLING. On the Due board, you also have HIGH.
|
||||
|
||||
|
||||
The PinChangeInterrupt library does not work on the Due; it is not necessary. It is somewhat easier
|
||||
to use than attachInterrupt() because you don't have to translate from an "Interrupt number" to a
|
||||
pin number- you simply give it the pin that you want to Interrupt on:
|
||||
|
||||
PCintPort::attachInterrupt(interrupt, &function, MODE)
|
||||
|
||||
The MODE is LOW, CHANGE, RISING, or FALLING. On the Due board, you also have HIGH.
|
||||
|
||||
To have an Interrupt:
|
||||
|
||||
Global Interrupt flag must be enabled.
|
||||
Set the I-bit in SREG.
|
||||
In PCICR: bit 2 == PCIE2: set, enable pins PCINT[23:16], enable individual by PCMSK2
|
||||
bit 1 == PCIE1: set, enable PCINT[14:8], enable individual by PCMSK1
|
||||
bit 0 == PCIE0: set, enable PCINT[7:0], enable individual by PCMSK0
|
||||
|
||||
Pin Change Interrupts and Other Libraries ============================================================
|
||||
|
||||
Serial.print()----------------
|
||||
|
||||
Serial.print() does not work well inside interrupts. This is because it uses interrupts,
|
||||
and while you are in an interrupt, interrupts are (by default) turned off.
|
||||
Serial is declared in /usr/share/arduino/hardware/arduino/cores/arduino/HardwareSerial.h .
|
||||
In the write() method in the .cpp file, for example it says:
|
||||
...
|
||||
// If the output buffer is full, there's nothing for it other than to
|
||||
// wait for the interrupt handler to empty it a bit
|
||||
// ???: return 0 here instead?
|
||||
while (i == _tx_buffer->tail)
|
||||
;
|
||||
...
|
||||
And the ISR is further down in that file (this for the ATmega328 I believe):
|
||||
ISR(USART_RX_vect)
|
||||
...
|
||||
|
||||
If a user wants to try to use Serial.print() inside an ISR, I believe it's possible
|
||||
(by turning on interrupts inside the interrupt)...
|
||||
but it would require them to be aware of any possible contention between the interrupts,
|
||||
and the print ISRs.
|
||||
|
||||
|
||||
Software Serial----------
|
||||
The SoftwareSerial library defines ISRs for Pin Change Interrupt ports:
|
||||
|
||||
ISR(PCINT0_vect)
|
||||
{
|
||||
SoftwareSerial::handle_interrupt();
|
||||
}
|
||||
|
||||
...It defines the interrupt on all ports, whether it's using them or not
|
||||
(the library cannot know ahead of time if the user will be using a set of pins
|
||||
or not).
|
||||
|
||||
To ensure compatibility with the SoftwareSerial library, the user should comment
|
||||
out the ports that they are NOT using with the SoftwareSerial library, in
|
||||
/usr/share/arduino/libraries/SoftwareSerial/SoftwareSerial.cpp
|
||||
and comment out the ports that they ARE using with this library in PinChangeInt.h
|
||||
10
libraries/PinChangeInt/keywords.txt
Normal file
10
libraries/PinChangeInt/keywords.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# LITERAL1 specifies constants
|
||||
|
||||
# KEYWORD1 specifies datatypes and C/C++ keywords
|
||||
pinState KEYWORD1 PinState
|
||||
arduinoPin KEYWORD1 ArduinoPin
|
||||
PCintPort KEYWORD1 PCInterruptPort
|
||||
|
||||
# KEYWORD2 specifies methods and functions
|
||||
attachInterrupt KEYWORD2 AttachInterrupt
|
||||
detachInterrupt KEYWORD2 DetachInterrupt
|
||||
243
libraries/RTC_DCF/DateTime.cpp
Normal file
243
libraries/RTC_DCF/DateTime.cpp
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
#include "DateTime.h"
|
||||
|
||||
/**********************************************************
|
||||
Konstruktor
|
||||
**********************************************************/
|
||||
DateTime::DateTime()
|
||||
{}
|
||||
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: DateTime
|
||||
|
||||
Beschreibung: Konstruktor mit Übergabe der Datum und Uhrzeit
|
||||
|
||||
Eingänge: unsigned char year
|
||||
Jahr
|
||||
|
||||
unsigned char month
|
||||
Monat
|
||||
|
||||
unsigned char day
|
||||
Tag
|
||||
|
||||
unsigned char weekday
|
||||
Wochentag (0: Sonntag, 1: Montag ...)
|
||||
|
||||
unsigned char hour
|
||||
Stunde
|
||||
|
||||
unsigned char minute
|
||||
Minute
|
||||
|
||||
unsigned char second
|
||||
Sekunde
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
DateTime::DateTime( unsigned char year, unsigned char month, unsigned char day, unsigned char weekday,
|
||||
unsigned char hour, unsigned char minute, unsigned char second)
|
||||
{
|
||||
this->year = year;
|
||||
this->month = month;
|
||||
this->day = day;
|
||||
this->weekday = weekday;
|
||||
this->hour = hour;
|
||||
this->minute = minute;
|
||||
this->second = second;
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
öffentliche Methoden
|
||||
**********************************************************/
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: addSecond
|
||||
|
||||
Beschreibung: addiert eine Sekunde auf die aktuell
|
||||
gespeicherte Zeit inkl. Auswertung aller
|
||||
Überträge
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void DateTime::addSecond(void)
|
||||
{
|
||||
this->second++;
|
||||
|
||||
if(this->second >= 60)
|
||||
{
|
||||
this->second = 0;
|
||||
this->minute++;
|
||||
|
||||
if(this->minute >= 60)
|
||||
{
|
||||
this->minute = 0;
|
||||
this->hour++;
|
||||
|
||||
if(this->hour >= 24)
|
||||
{
|
||||
this->hour = 0;
|
||||
this->day++;
|
||||
|
||||
this->weekday = (this->weekday + 1) % 7;
|
||||
|
||||
if(this->day >= daysInMonth(month, year))
|
||||
{
|
||||
this->day = 1;
|
||||
this->month++;
|
||||
|
||||
if(this->month > 12)
|
||||
{
|
||||
this->month = 1;
|
||||
this->year++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: daysInMonth
|
||||
|
||||
Beschreibung: gibt die Anzahl der Tages eines Monats zurück
|
||||
|
||||
Eingänge: unsigned char month
|
||||
Monat für den die Anzahl der Tage gesucht wird
|
||||
|
||||
unsigned char year
|
||||
Jahr in dem sich der Monat befindet
|
||||
(wird bei der Entscheidung benötigt, ob
|
||||
der Februar 28 oder 29 Tage hat)
|
||||
|
||||
Ausgang: unsigned char
|
||||
Anzahl der Monatstage
|
||||
---------------------------------------------------------*/
|
||||
unsigned char DateTime::daysInMonth(unsigned char month, unsigned char year)
|
||||
{
|
||||
unsigned char days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
unsigned char daysInMonth = days[month];
|
||||
|
||||
if(month == 2 && isLeapyear(year))
|
||||
{
|
||||
daysInMonth = 29;
|
||||
}
|
||||
|
||||
return daysInMonth;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: isLeapyear
|
||||
|
||||
Beschreibung: gibt zurück ob das übergebene Jahr ein Schaltjahr ist
|
||||
|
||||
Hinweis:
|
||||
Bei der Auswertung wird nur kontrolliert, ob das Jahr
|
||||
durch 4 teilbar ist.
|
||||
|
||||
Eingänge: unsigned char year
|
||||
Jahr, das auf Schaltjahr geprüft werden soll
|
||||
(Angabe als 2stelliger Wert)
|
||||
|
||||
Ausgang: unsigned char
|
||||
Jahr ist ein Schaltjahr?
|
||||
|
||||
0: kein Schaltjahr
|
||||
1: Schaltjahr
|
||||
---------------------------------------------------------*/
|
||||
unsigned char DateTime::isLeapyear(unsigned char year)
|
||||
{
|
||||
unsigned char leapyear = 0;
|
||||
|
||||
if(year & 0x03 == 0)
|
||||
{
|
||||
leapyear = 1;
|
||||
}
|
||||
|
||||
return leapyear;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: getDateTimeString
|
||||
|
||||
Beschreibung: gibt die gespeicherte Zeit als Zeichenkette
|
||||
zurück
|
||||
|
||||
Eingänge: char* dateTimeString
|
||||
enthält am Ende der Funktion die gespeicherte
|
||||
Zeit (Datum und Uhrzeit)
|
||||
|
||||
Mindestgröße: 18 Byte
|
||||
|
||||
Ausgabeformat: dd.MM.yy-hh:mm:ss
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void DateTime::getDateTimeString(char* dateTimeString)
|
||||
{
|
||||
getDateString(dateTimeString);
|
||||
|
||||
dateTimeString[8] = '-';
|
||||
|
||||
getTimeString(dateTimeString + 9);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: getDateString
|
||||
|
||||
Beschreibung: gibt das gespeicherte Datum als Zeichenkette
|
||||
zurück
|
||||
|
||||
Eingänge: char* dateString
|
||||
enthält am Ende der Funktion das gespeicherte
|
||||
Datum
|
||||
|
||||
Mindestgröße: 9 Byte
|
||||
|
||||
Ausgabeformat: dd.MM.yy
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void DateTime::getDateString(char* dateString)
|
||||
{
|
||||
dateString[0] = (this->day / 10) + '0';
|
||||
dateString[1] = (this->day % 10) + '0';
|
||||
dateString[2] = '.';
|
||||
dateString[3] = (this->month / 10) + '0';
|
||||
dateString[4] = (this->month % 10) + '0';
|
||||
dateString[5] = '.';
|
||||
dateString[6] = (this->year / 10) + '0';
|
||||
dateString[7] = (this->year % 10) + '0';
|
||||
dateString[8] = '\n';
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: getTimeString
|
||||
|
||||
Beschreibung: gibt die gespeicherte Uhrzeit als Zeichenkette
|
||||
zurück
|
||||
|
||||
Eingänge: char* timeString
|
||||
enthält am Ende der Funktion die gespeicherte
|
||||
Uhrzeit
|
||||
|
||||
Mindestgröße: 9 Byte
|
||||
|
||||
Ausgabeformat: hh:mm:ss
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void DateTime::getTimeString(char* timeString)
|
||||
{
|
||||
timeString[0] = (this->hour / 10) + '0';
|
||||
timeString[1] = (this->hour % 10) + '0';
|
||||
timeString[2] = ':';
|
||||
timeString[3] = (this->minute / 10) + '0';
|
||||
timeString[4] = (this->minute % 10) + '0';
|
||||
timeString[5] = ':';
|
||||
timeString[6] = (this->second / 10) + '0';
|
||||
timeString[7] = (this->second % 10) + '0';
|
||||
timeString[8] = '\n';
|
||||
}
|
||||
70
libraries/RTC_DCF/DateTime.h
Normal file
70
libraries/RTC_DCF/DateTime.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef DateTime_h
|
||||
#define DateTime_h
|
||||
|
||||
/**********************************************************
|
||||
Klasse DateTime
|
||||
**********************************************************/
|
||||
class DateTime
|
||||
{
|
||||
private:
|
||||
unsigned char second;
|
||||
unsigned char minute;
|
||||
unsigned char hour;
|
||||
unsigned char weekday;
|
||||
unsigned char day;
|
||||
unsigned char month;
|
||||
unsigned char year;
|
||||
|
||||
public:
|
||||
enum weekday {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY};
|
||||
|
||||
DateTime();
|
||||
|
||||
DateTime( unsigned char year, unsigned char month, unsigned char day, unsigned char weekday,
|
||||
unsigned char hour, unsigned char minute, unsigned char second);
|
||||
|
||||
|
||||
// Schreiben bzw. Lesen der Sekunde
|
||||
unsigned char getSecond(void) { return second; }
|
||||
void setSecond(unsigned char value) { second = value; }
|
||||
|
||||
// Schreiben bzw. Lesen der Minute
|
||||
unsigned char getMinute(void) { return minute; }
|
||||
void setMinute(unsigned char value) { minute = value; }
|
||||
|
||||
// Schreiben bzw. Lesen der Stunde
|
||||
unsigned char getHour(void) { return hour; }
|
||||
void setHour(unsigned char value) { hour = value; }
|
||||
|
||||
// Schreiben bzw. Lesen des Wochentags
|
||||
unsigned char getWeekday(void) { return weekday; }
|
||||
void setWeekday(unsigned char value) { weekday = value; }
|
||||
|
||||
// Schreiben bzw. Lesen des Tags
|
||||
unsigned char getDay(void) { return day; }
|
||||
void setDay(unsigned char value) { day = value; }
|
||||
|
||||
// Schreiben bzw. Lesen des Monats
|
||||
unsigned char getMonth(void) { return month; }
|
||||
void setMonth(unsigned char value) { month = value; }
|
||||
|
||||
// Schreiben bzw. Lesen des Jahres
|
||||
unsigned char getYear(void) { return year; }
|
||||
void setYear(unsigned char value) { year = value; }
|
||||
|
||||
// Weiterzählen der Sekunden
|
||||
void addSecond(void);
|
||||
|
||||
// Anzahl Tage im Monat
|
||||
unsigned char daysInMonth(unsigned char month, unsigned char year);
|
||||
|
||||
// Kontrolle, ob Schaltjahr
|
||||
unsigned char isLeapyear(unsigned char year);
|
||||
|
||||
// Datum und/oder Uhrzeit als Zeichenkette
|
||||
void getDateTimeString(char* dateTimeString);
|
||||
void getDateString(char* dateString);
|
||||
void getTimeString(char* timeString);
|
||||
};
|
||||
|
||||
#endif
|
||||
802
libraries/RTC_DCF/RealTimeClock_DCF.cpp
Normal file
802
libraries/RTC_DCF/RealTimeClock_DCF.cpp
Normal file
|
|
@ -0,0 +1,802 @@
|
|||
#include "RealTimeClock_DCF.h"
|
||||
|
||||
/**********************************************************
|
||||
Konstruktor
|
||||
**********************************************************/
|
||||
#if RTC_DCF_COMMUNICATION == 0x00
|
||||
RealTimeClock_DCF::RealTimeClock_DCF() : softSerial(2, 3)
|
||||
{}
|
||||
#else
|
||||
RealTimeClock_DCF::RealTimeClock_DCF()
|
||||
{}
|
||||
#endif
|
||||
|
||||
/**********************************************************
|
||||
öffentliche Methoden
|
||||
**********************************************************/
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: begin
|
||||
|
||||
Beschreibung: initialisiert den gewählten Kommunikations-
|
||||
weg
|
||||
|
||||
Eingänge: RTCCommunication_t rtcCommunication
|
||||
Kommunikationsweg zum RTC-DCF
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::begin(void)
|
||||
{
|
||||
#if RTC_DCF_COMMUNICATION == 0x00
|
||||
softSerial.begin(RTC_DCF_UART_BAUDRATE);
|
||||
#endif
|
||||
|
||||
#if RTC_DCF_COMMUNICATION == 0x01
|
||||
SPI.begin();
|
||||
SPI.setBitOrder(MSBFIRST);
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV32);
|
||||
SPI.setDataMode(SPI_MODE1);
|
||||
#endif
|
||||
|
||||
#if RTC_DCF_COMMUNICATION == 0x02
|
||||
Wire.begin();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: setTime
|
||||
|
||||
Beschreibung: setzt die Uhrzeit des RTC-DCF
|
||||
|
||||
Eingänge: DateTime *dateTime
|
||||
Struktur mit Datum und Uhrzeit, die im
|
||||
RTC-DCF gesetzt werden soll.
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::setDateTime(DateTime *dateTime)
|
||||
{
|
||||
uint8_t dateTimeBCD[7];
|
||||
|
||||
dateTimeBCD[0] = decimalToBCD(dateTime->getSecond());
|
||||
dateTimeBCD[1] = decimalToBCD(dateTime->getMinute());
|
||||
dateTimeBCD[2] = decimalToBCD(dateTime->getHour());
|
||||
dateTimeBCD[3] = decimalToBCD(dateTime->getWeekday() + 1);
|
||||
dateTimeBCD[4] = decimalToBCD(dateTime->getDay());
|
||||
dateTimeBCD[5] = decimalToBCD(dateTime->getMonth());
|
||||
dateTimeBCD[6] = decimalToBCD(dateTime->getYear());
|
||||
|
||||
writeRegister(RTC_DCF_REG_SECOND, dateTimeBCD, 7);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: getTime
|
||||
|
||||
Beschreibung: liest die Uhrzeit des RTC-DCF
|
||||
|
||||
Eingänge: DateTime *dateTime
|
||||
Struktur mit Datum und Uhrzeit, in die Daten
|
||||
aus dem RTC-DCF gespeichert werden
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::getDateTime(DateTime *dateTime)
|
||||
{
|
||||
uint8_t dateTimeBCD[7];
|
||||
|
||||
readRegister(RTC_DCF_REG_SECOND, 7, dateTimeBCD);
|
||||
|
||||
dateTime->setSecond(BCDToDecimal(dateTimeBCD[0]));
|
||||
dateTime->setMinute(BCDToDecimal(dateTimeBCD[1]));
|
||||
dateTime->setHour(BCDToDecimal(dateTimeBCD[2]));
|
||||
dateTime->setWeekday(BCDToDecimal(dateTimeBCD[3]) - 1);
|
||||
dateTime->setDay(BCDToDecimal(dateTimeBCD[4]));
|
||||
dateTime->setMonth(BCDToDecimal(dateTimeBCD[5]));
|
||||
dateTime->setYear(BCDToDecimal(dateTimeBCD[6]));
|
||||
}
|
||||
/*---------------------------------------------------------
|
||||
Name: setAlarmTime
|
||||
|
||||
Beschreibung: setzt einen der beiden Alarmuhrzeiten im RTC-Chip
|
||||
|
||||
Eingänge: RTCAlarmWeekdays_t weekdays
|
||||
Wochentage für den der Alarm gelten soll
|
||||
mögliche Werte:
|
||||
RTC_ALARM_WEEKDAYS_NONE,
|
||||
RTC_ALARM_WEEKDAYS_MON,
|
||||
RTC_ALARM_WEEKDAYS_TUE,
|
||||
RTC_ALARM_WEEKDAYS_WED,
|
||||
RTC_ALARM_WEEKDAYS_THU,
|
||||
RTC_ALARM_WEEKDAYS_FRI,
|
||||
RTC_ALARM_WEEKDAYS_SAT,
|
||||
RTC_ALARM_WEEKDAYS_SUN,
|
||||
RTC_ALARM_WEEKDAYS_MON_TO_FRI,
|
||||
RTC_ALARM_WEEKDAYS_SAT_TO_SUN,
|
||||
RTC_ALARM_WEEKDAYS_ALL
|
||||
|
||||
die Wochentage sind über das bitweise Oder (|)
|
||||
verknüpfbar.
|
||||
|
||||
Beispiel: Für einen Alarm an den Wochentagen
|
||||
Montag und Donnerstag wird der Funktion folgendes
|
||||
übergeben:
|
||||
(RTC_ALARM_WEEKDAYS_MON | RTC_ALARM_WEEKDAYS_THU)
|
||||
|
||||
uint8_t hour
|
||||
Stunde zu der der Alarm auslösen soll
|
||||
|
||||
uint8_t minute
|
||||
Minute zu der der Alarm auslösen soll
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::setAlarmTime(RTCAlarmWeekdays_t weekdays, uint8_t hour, uint8_t minute)
|
||||
{
|
||||
uint8_t alarmTimeBCD[] = { decimalToBCD(minute),
|
||||
decimalToBCD(hour),
|
||||
(uint8_t)weekdays };
|
||||
|
||||
writeRegister(RTC_DCF_REG_ALARM_MINUTE, alarmTimeBCD, 3);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: getAlarmTime
|
||||
|
||||
Beschreibung: liest einen der beiden Alarmuhrzeiten aus dem RTC-Chip
|
||||
|
||||
Eingänge: RTCAlarmWeekdays_t *weekdays
|
||||
ausgelesener Wochentag an dem Alarm aktiv ist
|
||||
(Bitkodierung siehe setAlarmTime)
|
||||
|
||||
uint8_t *hour
|
||||
ausgelesene Stunde des Alarms
|
||||
|
||||
uint8_t *minute
|
||||
ausgelesene Minute des Alarms
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::getAlarmTime(RTCAlarmWeekdays_t *weekdays, uint8_t *hour, uint8_t *minute)
|
||||
{
|
||||
uint8_t alarmTimeBCD[3];
|
||||
|
||||
readRegister(RTC_DCF_REG_ALARM_MINUTE, 7, alarmTimeBCD);
|
||||
|
||||
*minute = BCDToDecimal(alarmTimeBCD[0]);
|
||||
*hour = BCDToDecimal(alarmTimeBCD[1]);
|
||||
*weekdays = (RTCAlarmWeekdays_t)alarmTimeBCD[2];
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: enableAlarmInterrupt
|
||||
|
||||
Beschreibung: aktiviert den eingestellten Alarm
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::enableAlarmInterrupt(void)
|
||||
{
|
||||
uint8_t alarmRegister;
|
||||
|
||||
readRegister(RTC_DCF_REG_ALARM_CONFIG, 1, &alarmRegister);
|
||||
|
||||
alarmRegister |= RTC_ALARM_CONFIG_REGISTER_AIE;
|
||||
|
||||
writeRegister(RTC_DCF_REG_ALARM_CONFIG, &alarmRegister, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: disableAlarmInterrupt
|
||||
|
||||
Beschreibung: deaktiviert den eingestellten Alarm
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::disableAlarmInterrupt(void)
|
||||
{
|
||||
uint8_t alarmRegister;
|
||||
|
||||
readRegister(RTC_DCF_REG_ALARM_CONFIG, 1, &alarmRegister);
|
||||
|
||||
alarmRegister &= ~RTC_ALARM_CONFIG_REGISTER_AIE;
|
||||
|
||||
writeRegister(RTC_DCF_REG_ALARM_CONFIG, &alarmRegister, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: resetAlarmInterrupt
|
||||
|
||||
Beschreibung: schaltet den Alarm wieder scharf
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::resetAlarmInterrupt(void)
|
||||
{
|
||||
uint8_t statusRegister = RTC_STATUS_AIF;
|
||||
|
||||
writeRegister(RTC_DCF_REG_STATUS, &statusRegister, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: enableAlarmLED
|
||||
|
||||
Beschreibung: aktiviert, dass die LED bei einem Alarm ein- bzw.
|
||||
nach ausschalten des Alarms wieder ausgeschaltet
|
||||
wird.
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::enableAlarmLED(void)
|
||||
{
|
||||
uint8_t alarmRegister;
|
||||
|
||||
readRegister(RTC_DCF_REG_ALARM_CONFIG, 1, &alarmRegister);
|
||||
|
||||
alarmRegister |= RTC_ALARM_CONFIG_REGISTER_AILED;
|
||||
|
||||
writeRegister(RTC_DCF_REG_ALARM_CONFIG, &alarmRegister, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: disableAlarmLED
|
||||
|
||||
Beschreibung: deaktiviert, dass die LED bei einem Alarm ein- bzw.
|
||||
nach ausschalten des Alarms wieder ausgeschaltet
|
||||
wird.
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::disableAlarmLED(void)
|
||||
{
|
||||
uint8_t alarmRegister;
|
||||
|
||||
readRegister(RTC_DCF_REG_ALARM_CONFIG, 1, &alarmRegister);
|
||||
|
||||
alarmRegister &= ~RTC_ALARM_CONFIG_REGISTER_AILED;
|
||||
|
||||
writeRegister(RTC_DCF_REG_ALARM_CONFIG, &alarmRegister, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: setPeriodicInterruptMode
|
||||
|
||||
Beschreibung: stellt den periodischen Interruptbetrieb ein
|
||||
|
||||
Eingänge: PeriodicInterruptSelection_t periodicInterruptSelection
|
||||
Art des periodischen Betriebs:
|
||||
|
||||
RTC_PERIODIC_INT_PULSE_1_HZ
|
||||
Pulsmodus mit 1 Hz
|
||||
|
||||
RTC_PERIODIC_INT_PULSE_2_HZ
|
||||
Pulsmodus mit 2 Hz
|
||||
|
||||
RTC_PERIODIC_INT_LEVEL_EVERY_SECOND
|
||||
Interrupt jede Sekunde (synchron mit Sekundenzähler)
|
||||
|
||||
RTC_PERIODIC_INT_LEVEL_EVERY_MINUTE
|
||||
Interrupt jede Minute (bei Sekunde = 0)
|
||||
|
||||
RTC_PERIODIC_INT_LEVEL_EVERY_HOUR
|
||||
Interrupt jede Stunde (bei Minute und Sekunde = 0)
|
||||
|
||||
RTC_PERIODIC_INT_LEVEL_EVERY_DAY
|
||||
Interrupt jeden Tag (bei Stunde, Minute und Sekunde = 0)
|
||||
|
||||
RTC_PERIODIC_INT_LEVEL_EVERY_MONTH
|
||||
Interrupt jeden Monat (jeweils am 1. um 0:00:00)
|
||||
|
||||
Hinweis:
|
||||
Die Interrupts mit der Bezeichnung LEVEL werden
|
||||
nicht automatisch zurückgesetzt, sondern müssen durch
|
||||
den Aufruf der Methode resetPeriodicInterrupt wieder
|
||||
scharf geschaltet werden.
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::setPeriodicInterruptMode(RTCPeriodicInterruptMode_t periodicInterruptMode)
|
||||
{
|
||||
uint8_t mode = (uint8_t)periodicInterruptMode;
|
||||
|
||||
writeRegister(RTC_DCF_REG_PERIODIC_INTERRUPT, &mode, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: enablePeriodicInterrupt
|
||||
|
||||
Beschreibung: aktiviert den eingestellten periodischen
|
||||
Interrupt
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::enablePeriodicInterrupt(void)
|
||||
{
|
||||
uint8_t perIntRegister;
|
||||
|
||||
readRegister(RTC_DCF_REG_PER_INT_CONFIG, 1, &perIntRegister);
|
||||
|
||||
perIntRegister |= RTC_PER_INT_CONFIG_REGISTER_PIE;
|
||||
|
||||
writeRegister(RTC_DCF_REG_PER_INT_CONFIG, &perIntRegister, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: disablePeriodicInterrupt
|
||||
|
||||
Beschreibung: deaktiviert den eingestellten periodischen
|
||||
Interrupt
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::disablePeriodicInterrupt(void)
|
||||
{
|
||||
uint8_t perIntRegister;
|
||||
|
||||
readRegister(RTC_DCF_REG_PER_INT_CONFIG, 1, &perIntRegister);
|
||||
|
||||
perIntRegister &= ~RTC_PER_INT_CONFIG_REGISTER_PIE;
|
||||
|
||||
writeRegister(RTC_DCF_REG_PER_INT_CONFIG, &perIntRegister, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: resetPeriodicInterrupt
|
||||
|
||||
Beschreibung: schaltet den periodischen Interrupt bei
|
||||
Auswahl eines der Level-Modi wieder scharf
|
||||
(siehe setPeriodicInterrupt)
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::resetPeriodicInterrupt(void)
|
||||
{
|
||||
uint8_t statusRegister = RTC_STATUS_PIF;
|
||||
|
||||
writeRegister(RTC_DCF_REG_STATUS, &statusRegister, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: enablePeriodicInterruptLED
|
||||
|
||||
Beschreibung: aktiviert, dass die LED bei einem periodischen Interrupt
|
||||
ein- bzw. nach ausschalten des Interrupts wieder ausgeschaltet
|
||||
wird.
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::enablePeriodicInterruptLED(void)
|
||||
{
|
||||
uint8_t perIntRegister;
|
||||
|
||||
readRegister(RTC_DCF_REG_PER_INT_CONFIG, 1, &perIntRegister);
|
||||
|
||||
perIntRegister |= RTC_PER_INT_CONFIG_REGISTER_PILED;
|
||||
|
||||
writeRegister(RTC_DCF_REG_PER_INT_CONFIG, &perIntRegister, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: disablePeriodicInterruptLED
|
||||
|
||||
Beschreibung: deaktiviert, dass die LED bei einem periodischen Interrupt
|
||||
ein- bzw. nach ausschalten des Interrupts wieder ausgeschaltet
|
||||
wird.
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::disablePeriodicInterruptLED(void)
|
||||
{
|
||||
uint8_t perIntRegister;
|
||||
|
||||
readRegister(RTC_DCF_REG_PER_INT_CONFIG, 1, &perIntRegister);
|
||||
|
||||
perIntRegister &= ~RTC_PER_INT_CONFIG_REGISTER_PILED;
|
||||
|
||||
writeRegister(RTC_DCF_REG_PER_INT_CONFIG, &perIntRegister, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: enableDCF77Reception
|
||||
|
||||
Beschreibung: aktiviert den DCF77-Empfang
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::enableDCF77Reception(void)
|
||||
{
|
||||
uint8_t dcf77Register;
|
||||
|
||||
readRegister(RTC_DCF_REG_DCF77_CONFIG, 1, &dcf77Register);
|
||||
|
||||
dcf77Register |= RTC_DCF77_CONFIG_REGISTER_DCFE;
|
||||
|
||||
writeRegister(RTC_DCF_REG_DCF77_CONFIG, &dcf77Register, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: disableDCF77Reception
|
||||
|
||||
Beschreibung: deaktiviert den DCF77-Empfang
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::disableDCF77Reception(void)
|
||||
{
|
||||
uint8_t dcf77Register;
|
||||
|
||||
readRegister(RTC_DCF_REG_DCF77_CONFIG, 1, &dcf77Register);
|
||||
|
||||
dcf77Register &= ~RTC_DCF77_CONFIG_REGISTER_DCFE;
|
||||
|
||||
writeRegister(RTC_DCF_REG_DCF77_CONFIG, &dcf77Register, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: enableDCF77Interrupt
|
||||
|
||||
Beschreibung: aktiviert den Interrupt bei DCF77-Empfang
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::enableDCF77Interrupt(void)
|
||||
{
|
||||
uint8_t dcf77Register;
|
||||
|
||||
readRegister(RTC_DCF_REG_DCF77_CONFIG, 1, &dcf77Register);
|
||||
|
||||
dcf77Register |= RTC_DCF77_CONFIG_REGISTER_DCFIE;
|
||||
|
||||
writeRegister(RTC_DCF_REG_DCF77_CONFIG, &dcf77Register, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: disableDCF77Interrupt
|
||||
|
||||
Beschreibung: deaktiviert den Interrupt bei DCF77-Empfang
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::disableDCF77Interrupt(void)
|
||||
{
|
||||
uint8_t dcf77Register;
|
||||
|
||||
readRegister(RTC_DCF_REG_DCF77_CONFIG, 1, &dcf77Register);
|
||||
|
||||
dcf77Register &= ~RTC_DCF77_CONFIG_REGISTER_DCFIE;
|
||||
|
||||
writeRegister(RTC_DCF_REG_DCF77_CONFIG, &dcf77Register, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: resetAlarmInterrupt
|
||||
|
||||
Beschreibung: schaltet den Interrupt bei DCF77-Empfang
|
||||
wieder scharf
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::resetDCF77Interrupt(void)
|
||||
{
|
||||
uint8_t statusRegister = RTC_STATUS_DCFIF;
|
||||
|
||||
writeRegister(RTC_DCF_REG_STATUS, &statusRegister, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: enableDCF77LED
|
||||
|
||||
Beschreibung: aktiviert, dass die LED bei einem DCF77-Empfangs-Interrupt
|
||||
ein- bzw. nach ausschalten des Interrupts wieder ausgeschaltet
|
||||
wird.
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::enableDCF77LED(void)
|
||||
{
|
||||
uint8_t dcf77Register;
|
||||
|
||||
readRegister(RTC_DCF_REG_DCF77_CONFIG, 1, &dcf77Register);
|
||||
|
||||
dcf77Register |= RTC_DCF77_CONFIG_REGISTER_DCFLED;
|
||||
|
||||
writeRegister(RTC_DCF_REG_DCF77_CONFIG, &dcf77Register, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: disableDCF77LED
|
||||
|
||||
Beschreibung: deaktiviert, dass die LED bei einem DCF77-Empfangs-Interrupt
|
||||
ein- bzw. nach ausschalten des Interrupts wieder ausgeschaltet
|
||||
wird.
|
||||
|
||||
Eingänge: void
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::disableDCF77LED(void)
|
||||
{
|
||||
uint8_t dcf77Register;
|
||||
|
||||
readRegister(RTC_DCF_REG_DCF77_CONFIG, 1, &dcf77Register);
|
||||
|
||||
dcf77Register &= ~RTC_DCF77_CONFIG_REGISTER_DCFLED;
|
||||
|
||||
writeRegister(RTC_DCF_REG_DCF77_CONFIG, &dcf77Register, 1);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************
|
||||
private Methoden
|
||||
**********************************************************/
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: writeRegister
|
||||
|
||||
Beschreibung: schreibt eine vorgegebene Anzahl Register des
|
||||
des RTC-DCF
|
||||
|
||||
Eingänge: unsigned char regAddress
|
||||
Registeradresse ab der die Daten geschrieben
|
||||
werden sollen
|
||||
|
||||
unsigned char *data
|
||||
zu schreibende Daten
|
||||
|
||||
unsigned char datalength
|
||||
Anzahl der zu schreibenden Daten
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::writeRegister(RTCRegister_t regAddress, uint8_t *data, uint8_t datalength)
|
||||
{
|
||||
#if RTC_DCF_COMMUNICATION == 0x00
|
||||
/* start byte */
|
||||
softSerial.write(0x02);
|
||||
|
||||
/* write direction */
|
||||
softSerial.write((uint8_t)0x00);
|
||||
|
||||
/* start address */
|
||||
softSerial.write(regAddress);
|
||||
|
||||
/* data */
|
||||
while(datalength--)
|
||||
{
|
||||
/* use bytestuffing at data bytes equal to STX, ETX and DLE */
|
||||
if( (*data == 0x02) ||
|
||||
(*data == 0x03) ||
|
||||
(*data == 0x10) )
|
||||
{
|
||||
softSerial.write(0x10);
|
||||
softSerial.write(*data | 0x80);
|
||||
}
|
||||
else
|
||||
{
|
||||
softSerial.write(*data);
|
||||
}
|
||||
|
||||
data++;
|
||||
}
|
||||
|
||||
/* end byte */
|
||||
softSerial.write(0x03);
|
||||
#endif
|
||||
|
||||
#if RTC_DCF_COMMUNICATION == 0x01
|
||||
digitalWrite(SPI_SLAVE_SELECT_PIN, LOW);
|
||||
|
||||
delayMicroseconds(50);
|
||||
SPI.transfer(regAddress | SPI_BURST_WRITE);
|
||||
|
||||
while(datalength--)
|
||||
{
|
||||
delayMicroseconds(50);
|
||||
SPI.transfer(*data);
|
||||
|
||||
data++;
|
||||
}
|
||||
|
||||
digitalWrite(SPI_SLAVE_SELECT_PIN, HIGH);
|
||||
|
||||
delayMicroseconds(300);
|
||||
#endif
|
||||
|
||||
#if RTC_DCF_COMMUNICATION == 0x02
|
||||
Wire.beginTransmission(RTC_DCF_I2C_ADDRESS);
|
||||
|
||||
Wire.write(regAddress);
|
||||
|
||||
while(datalength--)
|
||||
{
|
||||
Wire.write(*data);
|
||||
|
||||
data++;
|
||||
}
|
||||
|
||||
Wire.endTransmission();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: readRegister
|
||||
|
||||
Beschreibung: liest eine vorgegebene Anzahl Register des
|
||||
des RTC-DCF
|
||||
|
||||
Eingänge: unsigned char regAddress
|
||||
Registeradresse ab der die Daten gelesen
|
||||
werden sollen
|
||||
|
||||
unsigned char length
|
||||
Anzahl der zu lesenden Daten
|
||||
|
||||
unsigned char *data
|
||||
gelesene Daten
|
||||
|
||||
Ausgang: void
|
||||
---------------------------------------------------------*/
|
||||
void RealTimeClock_DCF::readRegister(RTCRegister_t regAddress, uint8_t length, uint8_t *data)
|
||||
{
|
||||
#if RTC_DCF_COMMUNICATION == 0x00
|
||||
uint8_t receivedByte;
|
||||
uint8_t nextByteStuffed;
|
||||
|
||||
/* start byte */
|
||||
softSerial.write(0x02);
|
||||
|
||||
/* write direction */
|
||||
softSerial.write(0x01);
|
||||
|
||||
/* start address */
|
||||
softSerial.write(regAddress);
|
||||
|
||||
/* count of read register */
|
||||
softSerial.write(length);
|
||||
|
||||
/* end byte */
|
||||
softSerial.write(0x03);
|
||||
|
||||
/* wait for start byte of slave */
|
||||
while(softSerial.read() != 0x02)
|
||||
{}
|
||||
|
||||
/* receive data until length is reached */
|
||||
while(length != 0)
|
||||
{
|
||||
/* wait until there are data to receive */
|
||||
while(softSerial.available() == 0)
|
||||
{}
|
||||
|
||||
receivedByte = softSerial.read();
|
||||
|
||||
/* check for stuffed bytes */
|
||||
if(receivedByte == 0x10)
|
||||
{
|
||||
nextByteStuffed = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(nextByteStuffed == 1)
|
||||
{
|
||||
receivedByte &= 0x7f;
|
||||
nextByteStuffed = 0;
|
||||
}
|
||||
|
||||
*data = receivedByte;
|
||||
|
||||
data++;
|
||||
length--;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if RTC_DCF_COMMUNICATION == 0x01
|
||||
digitalWrite(SPI_SLAVE_SELECT_PIN, LOW);
|
||||
|
||||
delayMicroseconds(50);
|
||||
SPI.transfer(regAddress | SPI_BURST_READ);
|
||||
|
||||
while(length--)
|
||||
{
|
||||
delayMicroseconds(50);
|
||||
*data = SPI.transfer(0xff);
|
||||
|
||||
data++;
|
||||
}
|
||||
|
||||
digitalWrite(SPI_SLAVE_SELECT_PIN, HIGH);
|
||||
|
||||
delayMicroseconds(300);
|
||||
#endif
|
||||
|
||||
#if RTC_DCF_COMMUNICATION == 0x02
|
||||
// set the register pointer to the given position, but do not stop the communication
|
||||
// after writing the pointer
|
||||
Wire.beginTransmission(RTC_DCF_I2C_ADDRESS);
|
||||
Wire.write(regAddress);
|
||||
Wire.endTransmission(false);
|
||||
|
||||
// read out the given amount of data from the registers
|
||||
Wire.requestFrom((uint8_t)RTC_DCF_I2C_ADDRESS, length);
|
||||
|
||||
while( Wire.available() )
|
||||
{
|
||||
*data = Wire.read();
|
||||
data++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: decimalToBCD
|
||||
|
||||
Beschreibung: rechnet Dezimalwerte in das BCD-System um
|
||||
(der RTC-DCF arbeitet intern mit BCD-Daten)
|
||||
|
||||
Eingänge: unsigned char decimal
|
||||
umzurechnender Dezimalwert
|
||||
|
||||
Ausgang: unsigned char
|
||||
BCD-Wert der übergebenen Dezimalzahl
|
||||
---------------------------------------------------------*/
|
||||
uint8_t RealTimeClock_DCF::decimalToBCD(uint8_t decimal)
|
||||
{
|
||||
return (((decimal / 10) << 4) | (decimal % 10));
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
Name: BCDToDecimal
|
||||
|
||||
Beschreibung: rechnet BCD-Werte in das Dezimal-System um
|
||||
(der RTC-DCF arbeitet intern mit BCD-Daten)
|
||||
|
||||
Eingänge: unsigned char bcd
|
||||
umzurechnender BCD-Wert
|
||||
|
||||
Ausgang: unsigned char
|
||||
Dezimalwert der übergebenen BCD-Zahl
|
||||
---------------------------------------------------------*/
|
||||
uint8_t RealTimeClock_DCF::BCDToDecimal(uint8_t bcd)
|
||||
{
|
||||
return (((((bcd)>>4) & 0x0F) * 10) + ((bcd) & 0x0F));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**********************************************************
|
||||
Vorinstantiiertes Objekt
|
||||
**********************************************************/
|
||||
RealTimeClock_DCF RTC_DCF = RealTimeClock_DCF();
|
||||
170
libraries/RTC_DCF/RealTimeClock_DCF.h
Normal file
170
libraries/RTC_DCF/RealTimeClock_DCF.h
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
#ifndef RealTimeClock_DCF_h
|
||||
#define RealTimeClock_DCF_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "DateTime.h"
|
||||
#include "config/RTC_DCF_config.h"
|
||||
|
||||
#if RTC_DCF_COMMUNICATION == 0x00
|
||||
#include "../modSoftSerial/modSoftwareSerial.h"
|
||||
#define RTC_DCF_ALARM_INT_PIN 11
|
||||
#define RTC_DCF_PER_INT_PIN 12
|
||||
#define RTC_DCF_DCF77_INT_PIN 10
|
||||
#endif
|
||||
|
||||
#if RTC_DCF_COMMUNICATION == 0x01
|
||||
#include "../SPI/SPI.h"
|
||||
#define RTC_DCF_ALARM_INT_PIN 2
|
||||
#define RTC_DCF_PER_INT_PIN 18
|
||||
#define RTC_DCF_DCF77_INT_PIN 19
|
||||
#endif
|
||||
|
||||
#if RTC_DCF_COMMUNICATION == 0x02
|
||||
#include "../Wire/Wire.h"
|
||||
#define RTC_DCF_ALARM_INT_PIN 11
|
||||
#define RTC_DCF_PER_INT_PIN 12
|
||||
#define RTC_DCF_DCF77_INT_PIN 10
|
||||
#endif
|
||||
|
||||
#define SPI_SLAVE_SELECT_PIN 10
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SPI_BURST_WRITE = 0x00,
|
||||
SPI_SINGLE_WRITE = 0x80,
|
||||
SPI_BURST_READ = 0x40,
|
||||
SPI_SINGLE_READ = 0xc0
|
||||
} SPITransferFormat_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RTC_DCF_REG_SECOND = 0x20,
|
||||
RTC_DCF_REG_MINUTE,
|
||||
RTC_DCF_REG_HOUR,
|
||||
RTC_DCF_REG_WEEKDAY,
|
||||
RTC_DCF_REG_DAY,
|
||||
RTC_DCF_REG_MONTH,
|
||||
RTC_DCF_REG_YEAR,
|
||||
RTC_DCF_REG_ALARM_MINUTE,
|
||||
RTC_DCF_REG_ALARM_HOUR,
|
||||
RTC_DCF_REG_ALARM_WEEKDAY,
|
||||
RTC_DCF_REG_PERIODIC_INTERRUPT,
|
||||
RTC_DCF_REG_ALARM_CONFIG,
|
||||
RTC_DCF_REG_PER_INT_CONFIG,
|
||||
RTC_DCF_REG_DCF77_CONFIG,
|
||||
RTC_DCF_REG_STATUS,
|
||||
RTC_DCF_REG_RESERVED
|
||||
} RTCRegister_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RTC_PERIODIC_INT_PULSE_1_HZ = 0x00,
|
||||
RTC_PERIODIC_INT_PULSE_2_HZ = 0x01,
|
||||
RTC_PERIODIC_INT_LEVEL_EVERY_SECOND = 0x02,
|
||||
RTC_PERIODIC_INT_LEVEL_EVERY_MINUTE = 0x03,
|
||||
RTC_PERIODIC_INT_LEVEL_EVERY_HOUR = 0x04,
|
||||
RTC_PERIODIC_INT_LEVEL_EVERY_DAY = 0x05,
|
||||
RTC_PERIODIC_INT_LEVEL_EVERY_MONTH = 0x06
|
||||
} RTCPeriodicInterruptMode_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RTC_ALARM_CONFIG_REGISTER_AIE = 0x02, // Alarm-Interrupt Enable
|
||||
RTC_ALARM_CONFIG_REGISTER_AILED = 0x04 // LED-Signalisation at Alarm-Interrupt Enable
|
||||
} RTCAlarmConfigRegisterBits_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RTC_PER_INT_CONFIG_REGISTER_PIE = 0x02, // Periodic-Interrupt Enable
|
||||
RTC_PER_INT_CONFIG_REGISTER_PILED = 0x04 // LED-Signalisation at Periodic-Interrupt Enable
|
||||
} RTCPeriodicInterruptConfigRegisterBits_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RTC_DCF77_CONFIG_REGISTER_DCFE = 0x01, // DCF77 Enable
|
||||
RTC_DCF77_CONFIG_REGISTER_DCFIE = 0x02, // DCF77-Interrupt Enable
|
||||
RTC_DCF77_CONFIG_REGISTER_DCFLED = 0x04 // LED-Signalisation at DCF77-Interrupt Enable
|
||||
} RTCDCF77ConfigRegisterBits_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RTC_STATUS_DCFIF = 0x01, // DCF77-Interrupt Flag
|
||||
RTC_STATUS_PIF = 0x02, // Periodic-Interrupt Flag
|
||||
RTC_STATUS_AIF = 0x04 // Alarm-Interrupt Flag
|
||||
} RTCStatusRegisterBits_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RTC_ALARM_WEEKDAYS_NONE = 0x00,
|
||||
RTC_ALARM_WEEKDAYS_MON = 0x01,
|
||||
RTC_ALARM_WEEKDAYS_TUE = 0x02,
|
||||
RTC_ALARM_WEEKDAYS_WED = 0x04,
|
||||
RTC_ALARM_WEEKDAYS_THU = 0x08,
|
||||
RTC_ALARM_WEEKDAYS_FRI = 0x10,
|
||||
RTC_ALARM_WEEKDAYS_SAT = 0x20,
|
||||
RTC_ALARM_WEEKDAYS_SUN = 0x40,
|
||||
RTC_ALARM_WEEKDAYS_MON_TO_FRI = 0x1f,
|
||||
RTC_ALARM_WEEKDAYS_SAT_TO_SUN = 0x60,
|
||||
RTC_ALARM_WEEKDAYS_ALL = 0x7f
|
||||
} RTCAlarmWeekdays_t;
|
||||
|
||||
|
||||
/**********************************************************
|
||||
Klasse RealTimeClock_DCF
|
||||
**********************************************************/
|
||||
class RealTimeClock_DCF
|
||||
{
|
||||
private:
|
||||
|
||||
// Schreiben bzw. Lesen der Register
|
||||
void writeRegister(RTCRegister_t, uint8_t*, uint8_t);
|
||||
void readRegister(RTCRegister_t, uint8_t, uint8_t*);
|
||||
|
||||
// Konvertierung BCD zu Dezimal bzw. Dezimal zu BCD
|
||||
uint8_t decimalToBCD(uint8_t);
|
||||
uint8_t BCDToDecimal(uint8_t);
|
||||
|
||||
#if RTC_DCF_COMMUNICATION == 0x00
|
||||
modSoftwareSerial softSerial;
|
||||
#endif
|
||||
|
||||
public:
|
||||
RealTimeClock_DCF();
|
||||
|
||||
// Systemstart
|
||||
void begin(void);
|
||||
|
||||
// Zeiteinstellung
|
||||
void setDateTime(DateTime*);
|
||||
void getDateTime(DateTime*);
|
||||
|
||||
// Alarm
|
||||
void setAlarmTime(RTCAlarmWeekdays_t, uint8_t, uint8_t);
|
||||
void getAlarmTime(RTCAlarmWeekdays_t*, uint8_t*, uint8_t*);
|
||||
void enableAlarmInterrupt(void);
|
||||
void disableAlarmInterrupt(void);
|
||||
void resetAlarmInterrupt(void);
|
||||
void enableAlarmLED(void);
|
||||
void disableAlarmLED(void);
|
||||
|
||||
// Periodic Interrupt
|
||||
void setPeriodicInterruptMode(RTCPeriodicInterruptMode_t);
|
||||
void enablePeriodicInterrupt(void);
|
||||
void disablePeriodicInterrupt(void);
|
||||
void resetPeriodicInterrupt(void);
|
||||
void enablePeriodicInterruptLED(void);
|
||||
void disablePeriodicInterruptLED(void);
|
||||
|
||||
// DCF77
|
||||
void enableDCF77Reception(void);
|
||||
void disableDCF77Reception(void);
|
||||
void enableDCF77Interrupt(void);
|
||||
void disableDCF77Interrupt(void);
|
||||
void resetDCF77Interrupt(void);
|
||||
void enableDCF77LED(void);
|
||||
void disableDCF77LED(void);
|
||||
};
|
||||
|
||||
extern RealTimeClock_DCF RTC_DCF;
|
||||
|
||||
#endif /* RealTimeClock_DCF_h */
|
||||
20
libraries/RTC_DCF/config/RTC_DCF_config.h
Normal file
20
libraries/RTC_DCF/config/RTC_DCF_config.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef RTC_DCF_config_h
|
||||
#define RTC_DCF_config_h
|
||||
|
||||
/******************************************************************************
|
||||
Definitionen
|
||||
******************************************************************************/
|
||||
/* Wahl der Kommunikationsart
|
||||
mögliche Werte: 0x00 UART
|
||||
0x01 SPI
|
||||
Ox02 I2C */
|
||||
#define RTC_DCF_COMMUNICATION 0x02
|
||||
|
||||
/* eingestellte I2C-Adresse des RTC-DCF (wird nur bei I2C-Kommunikation benötigt) */
|
||||
#define RTC_DCF_I2C_ADDRESS 0x01
|
||||
|
||||
/* eingestellte Baudrate des RTC-DCF (wird nur bei UART-Kommunikation benötigt) */
|
||||
#define RTC_DCF_UART_BAUDRATE 4800
|
||||
|
||||
#endif /* RTC_DCF_config_h */
|
||||
|
||||
116
libraries/RTC_DCF/examples/alarmInterrupt/alarmInterrupt.ino
Normal file
116
libraries/RTC_DCF/examples/alarmInterrupt/alarmInterrupt.ino
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/******************************************************************************
|
||||
Beispiel: alarmInterrupt
|
||||
|
||||
Beschreibung: Dieses Beispiel zeigt die Verwendung des Alarms innerhalb des
|
||||
RTC-DCF.
|
||||
|
||||
Hinweis: Zur Einstellung des Kommunikationswegs (UART, SPI oder I2C) zum
|
||||
RTC-DCF enthält die Library die Datei RTC_DCF_config.h im
|
||||
Unterordner \libraries\RTC_DCF\config\. Innerhalb dieser Datei
|
||||
kann der Kommunikationsweg umgestellt werden.
|
||||
|
||||
Bei Verwendung der UART-Schnittstelle wird ein Objekt der Klasse
|
||||
modSoftSerial angelegt. Diese Klasse entspricht einer
|
||||
modifizierten SoftSerial-Klasse. Innerhalb der modifizierten
|
||||
Klasse wird nur der PinChange-Interrupt für den Port D (PCINT2_vect)
|
||||
angelegt, anstatt alle PinChange-Interrupts anzulegen. Ohne diese
|
||||
Modifizierung wäre eine Verwendung von SoftSerial und PinChangeInt
|
||||
nicht parallel möglich.
|
||||
|
||||
Die modifizierte SoftSerial-Klasse ist Teil der RTC-DCF-Library.
|
||||
|
||||
Die PinChangeInt-Klasse ist nicht Teil der RTC-DCF-Library, kann
|
||||
aber auf folgender Internetseite heruntergeladen werden:
|
||||
http://arduino.cc/playground/Main/PinChangeInt
|
||||
******************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include "DateTime.h"
|
||||
#include "RealTimeClock_DCF.h"
|
||||
|
||||
/* leider setzt die Arduino-IDE voraus, dass alle in einem Projekt verwendeten
|
||||
Klassen auch ins Sketch übernommen werden. Wird dieses nicht berücksichtigt,
|
||||
kommt es zu Fehlern beim Linken des Programms. Daher muss an dieser Stelle
|
||||
die Headerdatei zu der jeweils verwendeten Kommunikationsklasse eingefügt
|
||||
werden. Die beiden jeweils nicht verwendeten Header müssen auskommentiert
|
||||
werden. */
|
||||
|
||||
/* für die Kommunikation über UART die modSoftwareSerial.h verwenden */
|
||||
//#include "modSoftwareSerial.h"
|
||||
|
||||
/* für die Kommunikation über SPI die SPI.h verwenden */
|
||||
//#include "SPI.h"
|
||||
|
||||
/* für die Kommunikation über Wire die Wire.h verwenden */
|
||||
#include "Wire.h"
|
||||
|
||||
/******************************************************************************
|
||||
Definitionen
|
||||
******************************************************************************/
|
||||
/* für die Kommunikation über UART wird ein Objekt der Klasse modSoftwareSerial
|
||||
benötigt. Da diese Klasse den Pin Change Interrupt am Port D blockiert, muss
|
||||
dieser für die Klasse PinChangeInt deaktiviert werden. */
|
||||
#if RTC_DCF_COMMUNICATION == 0x00
|
||||
#define NO_PORTD_PINCHANGES
|
||||
#endif
|
||||
|
||||
#include "PinChangeInt.h"
|
||||
|
||||
/******************************************************************************
|
||||
globale Variablen
|
||||
******************************************************************************/
|
||||
/* einzustellende Uhrzeit */
|
||||
DateTime dateTime = DateTime(0, 1, 1, DateTime::SATURDAY, 0, 59, 55);
|
||||
|
||||
/* Flag zur Anzeige eines Alarms */
|
||||
volatile uint8_t alarmFlag = 0;
|
||||
|
||||
/******************************************************************************
|
||||
Funktionen
|
||||
******************************************************************************/
|
||||
void setup()
|
||||
{
|
||||
/* der RTC-DCF benötigt ca. 1,5 Sekunden bis er Daten empfangen kann */
|
||||
delay(1500);
|
||||
|
||||
/* den Pin für den Alarm-Interrupt als Eingang und als externe
|
||||
Interrupt-Quelle definieren */
|
||||
pinMode(RTC_DCF_ALARM_INT_PIN, INPUT);
|
||||
PCintPort::attachInterrupt(RTC_DCF_ALARM_INT_PIN, &alarmInterrupt, FALLING);
|
||||
|
||||
/* RTC-DCF initialisieren */
|
||||
RTC_DCF.begin();
|
||||
|
||||
/* Uhrzeit im RTC-DCF setzen */
|
||||
RTC_DCF.setDateTime(&dateTime);
|
||||
|
||||
/* den Alarm auf 1:00 Uhr (5 Sekunden nach der eingestellten Uhrzeit) setzen */
|
||||
RTC_DCF.setAlarmTime(RTC_ALARM_WEEKDAYS_ALL, 1, 0);
|
||||
|
||||
/* den Alarm-Interrupt des RTC-DCF aktivieren */
|
||||
RTC_DCF.enableAlarmInterrupt();
|
||||
|
||||
/* die serielle Ausgabe initialisieren */
|
||||
Serial.begin(115200);
|
||||
|
||||
/* Interrupts einschalten */
|
||||
interrupts();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
/* "ALARM" über die serielle Schnittstelle ausgeben und den Alarm-Interrupt
|
||||
des RTC-DCF zurücksetzen, wenn das Alarm-Flag gesetzt wird */
|
||||
if(alarmFlag == 1)
|
||||
{
|
||||
Serial.println("ALARM");
|
||||
|
||||
RTC_DCF.resetAlarmInterrupt();
|
||||
|
||||
alarmFlag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void alarmInterrupt(void)
|
||||
{
|
||||
alarmFlag = 1;
|
||||
}
|
||||
151
libraries/RTC_DCF/examples/dcf77Interrupt/dcf77Interrupt.ino
Normal file
151
libraries/RTC_DCF/examples/dcf77Interrupt/dcf77Interrupt.ino
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/******************************************************************************
|
||||
Beispiel: dcf77Interrupt
|
||||
|
||||
Beschreibung: Dieses Beispiel zeigt die Verwendung des DCF77-Empfänger
|
||||
innerhalb des RTC-DCF.
|
||||
|
||||
Hinweis: Zur Einstellung des Kommunikationswegs (UART, SPI oder I2C) zum
|
||||
RTC-DCF enthält die Library die Datei RTC_DCF_config.h im
|
||||
Unterordner \libraries\RTC_DCF\config\. Innerhalb dieser Datei
|
||||
kann der Kommunikationsweg umgestellt werden.
|
||||
|
||||
Bei Verwendung der UART-Schnittstelle wird ein Objekt der Klasse
|
||||
modSoftSerial angelegt. Diese Klasse entspricht einer
|
||||
modifizierten SoftSerial-Klasse. Innerhalb der modifizierten
|
||||
Klasse wird nur der PinChange-Interrupt für den Port D (PCINT2_vect)
|
||||
angelegt, anstatt alle PinChange-Interrupts anzulegen. Ohne diese
|
||||
Modifizierung wäre eine Verwendung von SoftSerial und PinChangeInt
|
||||
nicht parallel möglich.
|
||||
|
||||
Die modifizierte SoftSerial-Klasse ist Teil der RTC-DCF-Library.
|
||||
|
||||
Die PinChangeInt-Klasse ist nicht Teil der RTC-DCF-Library, kann
|
||||
aber auf folgender Internetseite heruntergeladen werden:
|
||||
http://arduino.cc/playground/Main/PinChangeInt
|
||||
******************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include "DateTime.h"
|
||||
#include "RealTimeClock_DCF.h"
|
||||
|
||||
/* leider setzt die Arduino-IDE voraus, dass alle in einem Projekt verwendeten
|
||||
Klassen auch ins Sketch übernommen werden. Wird dieses nicht berücksichtigt,
|
||||
kommt es zu Fehlern beim Linken des Programms. Daher muss an dieser Stelle
|
||||
die Headerdatei zu der jeweils verwendeten Kommunikationsklasse eingefügt
|
||||
werden. Die beiden jeweils nicht verwendeten Header müssen auskommentiert
|
||||
werden. */
|
||||
|
||||
/* für die Kommunikation über UART die modSoftwareSerial.h verwenden */
|
||||
//#include "modSoftwareSerial.h"
|
||||
|
||||
/* für die Kommunikation über SPI die SPI.h verwenden */
|
||||
//#include "SPI.h"
|
||||
|
||||
/* für die Kommunikation über Wire die Wire.h verwenden */
|
||||
#include "Wire.h"
|
||||
|
||||
/******************************************************************************
|
||||
Definitionen
|
||||
******************************************************************************/
|
||||
/* für die Kommunikation über UART wird ein Objekt der Klasse modSoftwareSerial
|
||||
benötigt. Da diese Klasse den Pin Change Interrupt am Port D blockiert, muss
|
||||
dieser für die Klasse PinChangeInt deaktiviert werden. */
|
||||
#if RTC_DCF_COMMUNICATION == 0x00
|
||||
#define NO_PORTD_PINCHANGES
|
||||
#endif
|
||||
|
||||
#include "PinChangeInt.h"
|
||||
|
||||
/******************************************************************************
|
||||
globale Variablen
|
||||
******************************************************************************/
|
||||
/* gelesene Uhrzeit */
|
||||
DateTime readDateTime;
|
||||
|
||||
/* Flag zur Anzeige eines periodischen Interrupts */
|
||||
volatile uint8_t perInterruptFlag = 0;
|
||||
|
||||
/* Flag zur Anzeige eines DCF77-Empfangs-Interrupts */
|
||||
volatile uint8_t dcf77InterruptFlag = 0;
|
||||
|
||||
/******************************************************************************
|
||||
Funktionen
|
||||
******************************************************************************/
|
||||
|
||||
void setup()
|
||||
{
|
||||
/* der RTC-DCF benötigt ca. 1,5 Sekunden bis er Daten empfangen kann */
|
||||
delay(1500);
|
||||
|
||||
/* den Pin für den periodischen Interrupt als Eingang definieren und als externe
|
||||
Interrupt-Quelle definieren */
|
||||
pinMode(RTC_DCF_PER_INT_PIN, INPUT);
|
||||
PCintPort::attachInterrupt(RTC_DCF_PER_INT_PIN, &periodicInterrupt, FALLING);
|
||||
|
||||
/* den Pin für den DCF77-Interrupt als Eingang definieren und als externe
|
||||
Interrupt-Quelle definieren */
|
||||
pinMode(RTC_DCF_DCF77_INT_PIN, INPUT);
|
||||
PCintPort::attachInterrupt(RTC_DCF_DCF77_INT_PIN, &dcf77Interrupt, FALLING);
|
||||
|
||||
/* RTC-DCF initialisieren */
|
||||
RTC_DCF.begin();
|
||||
|
||||
/* DCF77-Empfang aktivieren */
|
||||
RTC_DCF.enableDCF77Reception();
|
||||
RTC_DCF.enableDCF77Interrupt();
|
||||
|
||||
/* den periodischen Interrupt auf 1 Hz einstellen */
|
||||
RTC_DCF.setPeriodicInterruptMode(RTC_PERIODIC_INT_PULSE_1_HZ);
|
||||
|
||||
/* den periodischen Interrupt des RTC-DCF aktivieren */
|
||||
RTC_DCF.enablePeriodicInterrupt();
|
||||
|
||||
/* die serielle Ausgabe initialisieren */
|
||||
Serial.begin(115200);
|
||||
|
||||
/* Interrupts einschalten */
|
||||
interrupts();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
/* wenn das Flag für den periodischen Interrupt gesetzt wird die Uhrzeit aus dem
|
||||
RTC-DCF auslesen und über die serielle Schnittstelle */
|
||||
if(perInterruptFlag == 1)
|
||||
{
|
||||
RTC_DCF.getDateTime(&readDateTime);
|
||||
printClock();
|
||||
|
||||
perInterruptFlag = 0;
|
||||
}
|
||||
|
||||
if(dcf77InterruptFlag == 1)
|
||||
{
|
||||
Serial.println("DCF77 empfangen");
|
||||
|
||||
RTC_DCF.getDateTime(&readDateTime);
|
||||
|
||||
RTC_DCF.resetDCF77Interrupt();
|
||||
printClock();
|
||||
|
||||
dcf77InterruptFlag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void periodicInterrupt(void)
|
||||
{
|
||||
perInterruptFlag = 1;
|
||||
}
|
||||
|
||||
void dcf77Interrupt(void)
|
||||
{
|
||||
dcf77InterruptFlag = 1;
|
||||
}
|
||||
|
||||
void printClock(void)
|
||||
{
|
||||
char clockString[30];
|
||||
|
||||
sprintf(clockString, "Es ist %02u:%02u:%02u am %02u.%02u.%02u", readDateTime.getHour(), readDateTime.getMinute(), readDateTime.getSecond(), readDateTime.getDay(), readDateTime.getMonth(), readDateTime.getYear());
|
||||
|
||||
Serial.println(clockString);
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/******************************************************************************
|
||||
Beispiel: periodicInterrupt
|
||||
|
||||
Beschreibung: Dieses Beispiel zeigt die Verwendung des periodischen Interrupts
|
||||
innerhalb des RTC-DCF.
|
||||
|
||||
Hinweis: Zur Einstellung des Kommunikationswegs (UART, SPI oder I2C) zum
|
||||
RTC-DCF enthält die Library die Datei RTC_DCF_config.h im
|
||||
Unterordner \libraries\RTC_DCF\config\. Innerhalb dieser Datei
|
||||
kann der Kommunikationsweg umgestellt werden.
|
||||
|
||||
Bei Verwendung der UART-Schnittstelle wird ein Objekt der Klasse
|
||||
modSoftSerial angelegt. Diese Klasse entspricht einer
|
||||
modifizierten SoftSerial-Klasse. Innerhalb der modifizierten
|
||||
Klasse wird nur der PinChange-Interrupt für den Port D (PCINT2_vect)
|
||||
angelegt, anstatt alle PinChange-Interrupts anzulegen. Ohne diese
|
||||
Modifizierung wäre eine Verwendung von SoftSerial und PinChangeInt
|
||||
nicht parallel möglich.
|
||||
|
||||
Die modifizierte SoftSerial-Klasse ist Teil der RTC-DCF-Library.
|
||||
|
||||
Die PinChangeInt-Klasse ist nicht Teil der RTC-DCF-Library, kann
|
||||
aber auf folgender Internetseite heruntergeladen werden:
|
||||
http://arduino.cc/playground/Main/PinChangeInt
|
||||
******************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include "DateTime.h"
|
||||
#include "RealTimeClock_DCF.h"
|
||||
|
||||
/* leider setzt die Arduino-IDE voraus, dass alle in einem Projekt verwendeten
|
||||
Klassen auch ins Sketch übernommen werden. Wird dieses nicht berücksichtigt,
|
||||
kommt es zu Fehlern beim Linken des Programms. Daher muss an dieser Stelle
|
||||
die Headerdatei zu der jeweils verwendeten Kommunikationsklasse eingefügt
|
||||
werden. Die beiden jeweils nicht verwendeten Header müssen auskommentiert
|
||||
werden. */
|
||||
|
||||
/* für die Kommunikation über UART die modSoftwareSerial.h verwenden */
|
||||
#include "modSoftwareSerial.h"
|
||||
|
||||
/* für die Kommunikation über SPI die SPI.h verwenden */
|
||||
//#include "SPI.h"
|
||||
|
||||
/* für die Kommunikation über Wire die Wire.h verwenden */
|
||||
//#include "Wire.h"
|
||||
|
||||
/******************************************************************************
|
||||
Definitionen
|
||||
******************************************************************************/
|
||||
/* für die Kommunikation über UART wird ein Objekt der Klasse modSoftwareSerial
|
||||
benötigt. Da diese Klasse den Pin Change Interrupt am Port D blockiert, muss
|
||||
dieser für die Klasse PinChangeInt deaktiviert werden. */
|
||||
#if RTC_DCF_COMMUNICATION == 0x00
|
||||
#define NO_PORTD_PINCHANGES
|
||||
#endif
|
||||
|
||||
#include "PinChangeInt.h"
|
||||
|
||||
/******************************************************************************
|
||||
globale Variablen
|
||||
******************************************************************************/
|
||||
/* aktuelle Uhrzeit */
|
||||
DateTime dateTime;
|
||||
|
||||
/* Flag zur Anzeige eines periodischen Interrupts */
|
||||
volatile uint8_t periodicInterruptFlag = 0;
|
||||
|
||||
/******************************************************************************
|
||||
Funktionen
|
||||
******************************************************************************/
|
||||
|
||||
void setup()
|
||||
{
|
||||
/* der RTC-DCF benötigt ca. 1,5 Sekunden bis er Daten empfangen kann */
|
||||
delay(1500);
|
||||
|
||||
/* den Pin für den periodischen Interrupt als Eingang und als externe
|
||||
Interrupt-Quelle definieren */
|
||||
pinMode(RTC_DCF_PER_INT_PIN, INPUT);
|
||||
PCintPort::attachInterrupt(RTC_DCF_PER_INT_PIN, &periodicInterrupt, FALLING);
|
||||
|
||||
/* RTC-DCF initialisieren */
|
||||
RTC_DCF.begin();
|
||||
|
||||
/* den periodischen Interrupt auf 1 Hz einstellen */
|
||||
RTC_DCF.setPeriodicInterruptMode(RTC_PERIODIC_INT_PULSE_1_HZ);
|
||||
|
||||
/* den periodischen Interrupt des RTC-DCF aktivieren */
|
||||
RTC_DCF.enablePeriodicInterrupt();
|
||||
|
||||
/* die serielle Ausgabe initialisieren */
|
||||
Serial.begin(115200);
|
||||
|
||||
/* Interrupts einschalten */
|
||||
interrupts();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
/* wenn das Flag für den periodischen Interrupt gesetzt wird die Uhrzeit aus dem
|
||||
RTC-DCF auslesen und über die serielle Schnittstelle */
|
||||
if(periodicInterruptFlag == 1)
|
||||
{
|
||||
RTC_DCF.getDateTime(&dateTime);
|
||||
|
||||
printClock();
|
||||
|
||||
periodicInterruptFlag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void periodicInterrupt(void)
|
||||
{
|
||||
periodicInterruptFlag = 1;
|
||||
}
|
||||
|
||||
void printClock(void)
|
||||
{
|
||||
char clockString[30];
|
||||
|
||||
sprintf(clockString, "Es ist %02u:%02u:%02u am %02u.%02u.%02u", dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getDay(), dateTime.getMonth(), dateTime.getYear());
|
||||
|
||||
Serial.println(clockString);
|
||||
}
|
||||
74
libraries/RTC_DCF/examples/setTime/setTime.ino
Normal file
74
libraries/RTC_DCF/examples/setTime/setTime.ino
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/******************************************************************************
|
||||
Beispiel: setTime
|
||||
|
||||
Beschreibung: Dieses Beispiel zeigt das Schreiben und Lesen der Uhrzeit aus
|
||||
dem RTC-DCF.
|
||||
|
||||
Hinweis: Zur Einstellung des Kommunikationswegs (UART, SPI oder I2C) zum
|
||||
RTC-DCF enthält die Library die Datei RTC_DCF_config.h im
|
||||
Unterordner \libraries\RTC_DCF\config\. Innerhalb dieser Datei
|
||||
kann der Kommunikationsweg umgestellt werden.
|
||||
******************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include "DateTime.h"
|
||||
#include "RealTimeClock_DCF.h"
|
||||
|
||||
/* leider setzt die Arduino-IDE voraus, dass alle in einem Projekt verwendeten
|
||||
Klassen auch ins Sketch übernommen werden. Wird dieses nicht berücksichtigt,
|
||||
kommt es zu Fehlern beim Linken des Programms. Daher muss an dieser Stelle
|
||||
die Headerdatei zu der jeweils verwendeten Kommunikationsklasse eingefügt
|
||||
werden. Die beiden jeweils nicht verwendeten Header müssen auskommentiert
|
||||
werden. */
|
||||
|
||||
/* für die Kommunikation über UART die modSoftwareSerial.h verwenden */
|
||||
//#include "modSoftwareSerial.h"
|
||||
|
||||
/* für die Kommunikation über SPI die SPI.h verwenden */
|
||||
//#include "SPI.h"
|
||||
|
||||
/* für die Kommunikation über Wire die Wire.h verwenden */
|
||||
#include "Wire.h"
|
||||
|
||||
/******************************************************************************
|
||||
globale Variablen
|
||||
******************************************************************************/
|
||||
/* einzustellende Uhrzeit */
|
||||
DateTime dateTime = DateTime(0, 1, 1, DateTime::SATURDAY, 0, 0, 0);
|
||||
|
||||
/******************************************************************************
|
||||
Funktionen
|
||||
******************************************************************************/
|
||||
void setup()
|
||||
{
|
||||
/* der RTC-DCF benötigt ca. 1,5 Sekunden bis er Daten empfangen kann */
|
||||
delay(1500);
|
||||
|
||||
/* RTC-DCF initialisieren */
|
||||
RTC_DCF.begin();
|
||||
|
||||
/* Uhrzeit im RTC-DCF setzen */
|
||||
RTC_DCF.setDateTime(&dateTime);
|
||||
|
||||
/* die serielle Ausgabe initialisieren */
|
||||
Serial.begin(115200);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
/* ca. jede Sekunde wird die Uhrzeit ausgelesen und über die serielle Schnittstelle
|
||||
ausgegeben. */
|
||||
delay(1000);
|
||||
|
||||
RTC_DCF.getDateTime(&dateTime);
|
||||
|
||||
printClock();
|
||||
}
|
||||
|
||||
void printClock(void)
|
||||
{
|
||||
char clockString[30];
|
||||
|
||||
sprintf(clockString, "Es ist %02u:%02u:%02u am %02u.%02u.%02u", dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getDay(), dateTime.getMonth(), dateTime.getYear());
|
||||
|
||||
Serial.println(clockString);
|
||||
}
|
||||
69
libraries/RTC_DCF/keywords.txt
Normal file
69
libraries/RTC_DCF/keywords.txt
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For RTC_DCF
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
RTC_PERIODIC_INT_PULSE_1_HZ KEYWORD1
|
||||
RTC_PERIODIC_INT_PULSE_2_HZ KEYWORD1
|
||||
RTC_PERIODIC_INT_LEVEL_EVERY_SECOND KEYWORD1
|
||||
RTC_PERIODIC_INT_LEVEL_EVERY_MINUTE KEYWORD1
|
||||
RTC_PERIODIC_INT_LEVEL_EVERY_HOUR KEYWORD1
|
||||
RTC_PERIODIC_INT_LEVEL_EVERY_DAY KEYWORD1
|
||||
RTC_PERIODIC_INT_LEVEL_EVERY_MONTH KEYWORD1
|
||||
|
||||
RTC_ALARM_WEEKDAYS_NONE KEYWORD1
|
||||
RTC_ALARM_WEEKDAYS_MON KEYWORD1
|
||||
RTC_ALARM_WEEKDAYS_TUE KEYWORD1
|
||||
RTC_ALARM_WEEKDAYS_WED KEYWORD1
|
||||
RTC_ALARM_WEEKDAYS_THU KEYWORD1
|
||||
RTC_ALARM_WEEKDAYS_FRI KEYWORD1
|
||||
RTC_ALARM_WEEKDAYS_SAT KEYWORD1
|
||||
RTC_ALARM_WEEKDAYS_SUN KEYWORD1
|
||||
RTC_ALARM_WEEKDAYS_MON_TO_FRI KEYWORD1
|
||||
RTC_ALARM_WEEKDAYS_SAT_TO_SUN KEYWORD1
|
||||
RTC_ALARM_WEEKDAYS_ALL KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
begin KEYWORD2
|
||||
|
||||
setDateTime KEYWORD2
|
||||
getDateTime KEYWORD2
|
||||
|
||||
setAlarmTime KEYWORD2
|
||||
getAlarmTime KEYWORD2
|
||||
enableAlarmInterrupt KEYWORD2
|
||||
disableAlarmInterrupt KEYWORD2
|
||||
resetAlarmInterrupt KEYWORD2
|
||||
enableAlarmLED KEYWORD2
|
||||
disableAlarmLED KEYWORD2
|
||||
|
||||
setPeriodicInterruptMode KEYWORD2
|
||||
enablePeriodicInterrupt KEYWORD2
|
||||
disablePeriodicInterrupt KEYWORD2
|
||||
resetPeriodicInterrupt KEYWORD2
|
||||
enablePeriodicInterruptLED KEYWORD2
|
||||
disablePeriodicInterruptLED KEYWORD2
|
||||
|
||||
enableDCF77Reception KEYWORD2
|
||||
disableDCF77Reception KEYWORD2
|
||||
enableDCF77Interrupt KEYWORD2
|
||||
disableDCF77Interrupt KEYWORD2
|
||||
resetDCF77Interrupt KEYWORD2
|
||||
enableDCF77LED KEYWORD2
|
||||
disableDCF77LED KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Instances (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
RTC_DCF KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
11
libraries/arduino-mcp2515-master/.project
Normal file
11
libraries/arduino-mcp2515-master/.project
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>arduino-mcp2515</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
eclipse.preferences.version=1
|
||||
encoding/<project>=UTF-8
|
||||
19
libraries/arduino-mcp2515-master/.travis.yml
Normal file
19
libraries/arduino-mcp2515-master/.travis.yml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
language: c
|
||||
sudo: false
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- llvm-toolchain-trusty-5.0
|
||||
- key_url: 'http://apt.llvm.org/llvm-snapshot.gpg.key'
|
||||
|
||||
script:
|
||||
- build_main_platforms
|
||||
|
||||
before_install:
|
||||
- source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh)
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- ~/arduino_ide
|
||||
- ~/.arduino15/packages/
|
||||
22
libraries/arduino-mcp2515-master/LICENSE.md
Normal file
22
libraries/arduino-mcp2515-master/LICENSE.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Seeed Technology Inc.
|
||||
Copyright (c) 2016 Dmitry
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
279
libraries/arduino-mcp2515-master/README.md
Normal file
279
libraries/arduino-mcp2515-master/README.md
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
Arduino MCP2515 CAN interface library
|
||||
---------------------------------------------------------
|
||||
[](https://travis-ci.org/autowp/arduino-mcp2515)
|
||||
|
||||
<br>
|
||||
CAN-BUS is a common industrial bus because of its long travel distance, medium communication speed and high reliability. It is commonly found on modern machine tools and as an automotive diagnostic bus. This CAN-BUS Shield gives your Arduino/Seeeduino CAN-BUS capibility. With an OBD-II converter cable added on and the OBD-II library imported, you are ready to build an onboard diagnostic device or data logger.
|
||||
|
||||
- Implements CAN V2.0B at up to 1 Mb/s
|
||||
- SPI Interface up to 10 MHz
|
||||
- Standard (11 bit) and extended (29 bit) data and remote frames
|
||||
- Two receive buffers with prioritized message storage
|
||||
|
||||
**Contents:**
|
||||
* [Hardware](#hardware)
|
||||
* [CAN Shield](#can-shield)
|
||||
* [Do It Yourself](#do-it-yourself)
|
||||
* [Software Usage](#software-usage)
|
||||
* [Library Installation](#library-installation)
|
||||
* [Initialization](#initialization)
|
||||
* [Frame data format](#frame-data-format)
|
||||
* [Send Data](#send-data)
|
||||
* [Receive Data](#receive-data)
|
||||
* [Set Receive Mask and Filter](#set-receive-mask-and-filter)
|
||||
* [Examples](#examples)
|
||||
|
||||
# Hardware:
|
||||
|
||||
## CAN Shield
|
||||
|
||||
The following code samples uses the CAN-BUS Shield, wired up as shown:
|
||||
|
||||

|
||||
|
||||
## Do It Yourself
|
||||
|
||||
If you want to make your own CAN board for under $10, you can achieve that with something like this:
|
||||
|
||||

|
||||
|
||||
Component References:
|
||||
* [MCP2515](https://www.microchip.com/wwwproducts/en/MCP2515) Stand-Alone CAN Controller with SPI Interface
|
||||
* [MCP2551](https://www.microchip.com/wwwproducts/en/MCP2551) High-speed CAN Transceiver - pictured above, however "not recommended for new designs"
|
||||
* [MCP2562](https://www.microchip.com/wwwproducts/en/MCP2562) High-speed CAN Transceiver with Standby Mode and VIO Pin - an updated tranceiver since the _MCP2551_ (requires different wiring, read datasheet for example, also [here](https://fragmuffin.github.io/howto-micropython/slides/index.html#/7/5))
|
||||
* [TJA1055](https://www.nxp.com/docs/en/data-sheet/TJA1055.pdf) Fault-tolerant low speed CAN Transceiver. Mostly used in vehicles.
|
||||
|
||||
|
||||
# Software Usage:
|
||||
|
||||
## Library Installation
|
||||
|
||||
1. Download the ZIP file from https://github.com/autowp/arduino-mcp2515/archive/master.zip
|
||||
2. From the Arduino IDE: Sketch -> Include Library... -> Add .ZIP Library...
|
||||
3. Restart the Arduino IDE to see the new "mcp2515" library with examples
|
||||
|
||||
## Initialization
|
||||
|
||||
To create connection with MCP2515 provide pin number where SPI CS is connected (10 by default), baudrate and mode
|
||||
|
||||
The available modes are listed as follows:
|
||||
```C++
|
||||
mcp2515.setNormalMode();
|
||||
mcp2515.setLoopbackMode();
|
||||
mcp2515.setListenOnlyMode();
|
||||
```
|
||||
The available baudrates are listed as follows:
|
||||
```C++
|
||||
enum CAN_SPEED {
|
||||
CAN_5KBPS,
|
||||
CAN_10KBPS,
|
||||
CAN_20KBPS,
|
||||
CAN_31K25BPS,
|
||||
CAN_33KBPS,
|
||||
CAN_40KBPS,
|
||||
CAN_50KBPS,
|
||||
CAN_80KBPS,
|
||||
CAN_83K3BPS,
|
||||
CAN_95KBPS,
|
||||
CAN_100KBPS,
|
||||
CAN_125KBPS,
|
||||
CAN_200KBPS,
|
||||
CAN_250KBPS,
|
||||
CAN_500KBPS,
|
||||
CAN_1000KBPS
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
Example of initialization
|
||||
|
||||
```C++
|
||||
MCP2515 mcp2515(10);
|
||||
mcp2515.reset();
|
||||
mcp2515.setBitrate(CAN_125KBPS);
|
||||
mcp2515.setLoopbackMode();
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
<br>
|
||||
You can also set oscillator frequency for module when setting bitrate:
|
||||
|
||||
```C++
|
||||
mcp2515.setBitrate(CAN_125KBPS, MCP_8MHZ);
|
||||
```
|
||||
|
||||
<br>
|
||||
The available clock speeds are listed as follows:
|
||||
|
||||
```C++
|
||||
enum CAN_CLOCK {
|
||||
MCP_20MHZ,
|
||||
MCP_16MHZ,
|
||||
MCP_8MHZ
|
||||
};
|
||||
```
|
||||
|
||||
Default value is MCP_16MHZ
|
||||
<br>
|
||||
|
||||
Note: To transfer data on high speed of CAN interface via UART dont forget to update UART baudrate as necessary.
|
||||
|
||||
## Frame data format
|
||||
|
||||
Library uses Linux-like structure to store can frames;
|
||||
|
||||
```C++
|
||||
struct can_frame {
|
||||
uint32_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
|
||||
uint8_t can_dlc;
|
||||
uint8_t data[8];
|
||||
};
|
||||
```
|
||||
|
||||
For additional information see [SocketCAN](https://www.kernel.org/doc/Documentation/networking/can.txt)
|
||||
|
||||
## Send Data
|
||||
|
||||
```C++
|
||||
MCP2515::ERROR sendMessage(const MCP2515::TXBn txbn, const struct can_frame *frame);
|
||||
MCP2515::ERROR sendMessage(const struct can_frame *frame);
|
||||
```
|
||||
|
||||
This is a function to send data onto the bus.
|
||||
|
||||
For example, In the 'send' example, we have:
|
||||
|
||||
```C++
|
||||
struct can_frame frame;
|
||||
frame.can_id = 0x000;
|
||||
frame.can_dlc = 4;
|
||||
frame.data[0] = 0xFF;
|
||||
frame.data[1] = 0xFF;
|
||||
frame.data[2] = 0xFF;
|
||||
frame.data[3] = 0xFF;
|
||||
|
||||
/* send out the message to the bus and
|
||||
tell other devices this is a standard frame from 0x00. */
|
||||
mcp2515.sendMessage(&frame);
|
||||
```
|
||||
|
||||
```C++
|
||||
struct can_frame frame;
|
||||
frame.can_id = 0x12345678 | CAN_EFF_FLAG;
|
||||
frame.can_dlc = 2;
|
||||
frame.data[0] = 0xFF;
|
||||
frame.data[1] = 0xFF;
|
||||
|
||||
/* send out the message to the bus using second TX buffer and
|
||||
tell other devices this is a extended frame from 0x12345678. */
|
||||
mcp2515.sendMessage(MCP2515::TXB1, &frame);
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Receive Data
|
||||
|
||||
The following function is used to receive data on the 'receive' node:
|
||||
|
||||
```C++
|
||||
MCP2515::ERROR readMessage(const MCP2515::RXBn rxbn, struct can_frame *frame);
|
||||
MCP2515::ERROR readMessage(struct can_frame *frame);
|
||||
```
|
||||
|
||||
In conditions that masks and filters have been set. This function can only get frames that meet the requirements of masks and filters.
|
||||
|
||||
You can choise one of two method to receive: interrupt-based and polling
|
||||
|
||||
Example of poll read
|
||||
|
||||
```C++
|
||||
struct can_frame frame;
|
||||
|
||||
void loop() {
|
||||
if (mcp2515.readMessage(&frame) == MCP2515::ERROR_OK) {
|
||||
// frame contains received message
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Example of interrupt based read
|
||||
|
||||
```C++
|
||||
volatile bool interrupt = false;
|
||||
struct can_frame frame;
|
||||
|
||||
void irqHandler() {
|
||||
interrupt = true;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
...
|
||||
attachInterrupt(0, irqHandler, FALLING);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (interrupt) {
|
||||
interrupt = false;
|
||||
|
||||
uint8_t irq = mcp2515.getInterrupts();
|
||||
|
||||
if (irq & MCP2515::CANINTF_RX0IF) {
|
||||
if (mcp2515.readMessage(MCP2515::RXB0, &frame) == MCP2515::ERROR_OK) {
|
||||
// frame contains received from RXB0 message
|
||||
}
|
||||
}
|
||||
|
||||
if (irq & MCP2515::CANINTF_RX1IF) {
|
||||
if (mcp2515.readMessage(MCP2515::RXB1, &frame) == MCP2515::ERROR_OK) {
|
||||
// frame contains received from RXB1 message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Set Receive Mask and Filter
|
||||
|
||||
There are 2 receive mask registers and 5 filter registers on the controller chip that guarantee you get data from the target device. They are useful especially in a large network consisting of numerous nodes.
|
||||
|
||||
We provide two functions for you to utilize these mask and filter registers. They are:
|
||||
|
||||
```C++
|
||||
MCP2515::ERROR setFilterMask(const MASK mask, const bool ext, const uint32_t ulData)
|
||||
MCP2515::ERROR setFilter(const RXF num, const bool ext, const uint32_t ulData)
|
||||
```
|
||||
|
||||
**MASK mask** represents one of two mask **MCP2515::MASK0** or **MCP2515::MASK1**
|
||||
|
||||
**RXF num** represents one of six acceptance filters registers from **MCP2515::RXF0** to **MCP2515::RXF5**
|
||||
|
||||
**ext** represents the status of the frame. **false** means it's a mask or filter for a standard frame. **true** means it's for a extended frame.
|
||||
|
||||
**ulData** represents the content of the mask of filter.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Example implementation of CanHacker (lawicel) protocol based device: [https://github.com/autowp/can-usb](https://github.com/autowp/can-usb)
|
||||
|
||||
|
||||
For more information, please refer to [wiki page](http://www.seeedstudio.com/wiki/CAN-BUS_Shield) .
|
||||
|
||||
|
||||
----
|
||||
|
||||
This software is written by loovee ([luweicong@seeed.cc](luweicong@seeed.cc "luweicong@seeed.cc")) for seeed studio,<br>
|
||||
Updated by Dmitry ([https://github.com/autowp](https://github.com/autowp "https://github.com/autowp"))<br>
|
||||
and is licensed under [The MIT License](http://opensource.org/licenses/mit-license.php). Check [LICENSE.md](LICENSE.md) for more information.<br>
|
||||
|
||||
Contributing to this software is warmly welcomed. You can do this basically by<br>
|
||||
[forking](https://help.github.com/articles/fork-a-repo), committing modifications and then [pulling requests](https://help.github.com/articles/using-pull-requests) (follow the links above<br>
|
||||
for operating guide). Adding change log and your contact into file header is encouraged.<br>
|
||||
Thanks for your contribution.
|
||||
|
||||
Seeed Studio is an open hardware facilitation company based in Shenzhen, China. <br>
|
||||
Benefiting from local manufacture power and convenient global logistic system, <br>
|
||||
we integrate resources to serve new era of innovation. Seeed also works with <br>
|
||||
global distributors and partners to push open hardware movement.<br>
|
||||
45
libraries/arduino-mcp2515-master/can.h
Normal file
45
libraries/arduino-mcp2515-master/can.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef CAN_H_
|
||||
#define CAN_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
typedef unsigned char __u8;
|
||||
typedef unsigned short __u16;
|
||||
typedef unsigned long __u32;
|
||||
|
||||
|
||||
/* special address description flags for the CAN_ID */
|
||||
#define CAN_EFF_FLAG 0x80000000UL /* EFF/SFF is set in the MSB */
|
||||
#define CAN_RTR_FLAG 0x40000000UL /* remote transmission request */
|
||||
#define CAN_ERR_FLAG 0x20000000UL /* error message frame */
|
||||
|
||||
/* valid bits in CAN ID for frame formats */
|
||||
#define CAN_SFF_MASK 0x000007FFUL /* standard frame format (SFF) */
|
||||
#define CAN_EFF_MASK 0x1FFFFFFFUL /* extended frame format (EFF) */
|
||||
#define CAN_ERR_MASK 0x1FFFFFFFUL /* omit EFF, RTR, ERR flags */
|
||||
|
||||
/*
|
||||
* Controller Area Network Identifier structure
|
||||
*
|
||||
* bit 0-28 : CAN identifier (11/29 bit)
|
||||
* bit 29 : error message frame flag (0 = data frame, 1 = error message)
|
||||
* bit 30 : remote transmission request flag (1 = rtr frame)
|
||||
* bit 31 : frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
|
||||
*/
|
||||
typedef __u32 canid_t;
|
||||
|
||||
#define CAN_SFF_ID_BITS 11
|
||||
#define CAN_EFF_ID_BITS 29
|
||||
|
||||
/* CAN payload length and DLC definitions according to ISO 11898-1 */
|
||||
#define CAN_MAX_DLC 8
|
||||
#define CAN_MAX_DLEN 8
|
||||
|
||||
struct can_frame {
|
||||
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
|
||||
__u8 can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
|
||||
__u8 data[CAN_MAX_DLEN] __attribute__((aligned(8)));
|
||||
};
|
||||
|
||||
#endif /* CAN_H_ */
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#include <SPI.h>
|
||||
#include <mcp2515.h>
|
||||
|
||||
struct can_frame canMsg;
|
||||
MCP2515 mcp2515(10);
|
||||
int cntr = 0;
|
||||
unsigned long oldTime = 0;
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
mcp2515.reset();
|
||||
mcp2515.setBitrate(CAN_125KBPS);
|
||||
mcp2515.setNormalMode();
|
||||
|
||||
Serial.println("------- CAN Speedtest ----------");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) {
|
||||
cntr++;
|
||||
}
|
||||
|
||||
if ((millis()-oldTime)>1000) {
|
||||
oldTime = millis();
|
||||
Serial.print(cntr);
|
||||
Serial.println(" msg/sec");
|
||||
cntr = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#include <SPI.h>
|
||||
#include <mcp2515.h>
|
||||
|
||||
struct can_frame canMsg;
|
||||
MCP2515 mcp2515(10);
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
mcp2515.reset();
|
||||
mcp2515.setBitrate(CAN_125KBPS);
|
||||
mcp2515.setNormalMode();
|
||||
|
||||
Serial.println("------- CAN Read ----------");
|
||||
Serial.println("ID DLC DATA");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) {
|
||||
Serial.print(canMsg.can_id, HEX); // print ID
|
||||
Serial.print(" ");
|
||||
Serial.print(canMsg.can_dlc, HEX); // print DLC
|
||||
Serial.print(" ");
|
||||
|
||||
for (int i = 0; i<canMsg.can_dlc; i++) { // print the data
|
||||
Serial.print(canMsg.data[i],HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#include <SPI.h>
|
||||
#include <mcp2515.h>
|
||||
|
||||
struct can_frame canMsg1;
|
||||
struct can_frame canMsg2;
|
||||
MCP2515 mcp2515(10);
|
||||
|
||||
|
||||
void setup() {
|
||||
canMsg1.can_id = 0x0F6;
|
||||
canMsg1.can_dlc = 8;
|
||||
canMsg1.data[0] = 0x8E;
|
||||
canMsg1.data[1] = 0x87;
|
||||
canMsg1.data[2] = 0x32;
|
||||
canMsg1.data[3] = 0xFA;
|
||||
canMsg1.data[4] = 0x26;
|
||||
canMsg1.data[5] = 0x8E;
|
||||
canMsg1.data[6] = 0xBE;
|
||||
canMsg1.data[7] = 0x86;
|
||||
|
||||
canMsg2.can_id = 0x036;
|
||||
canMsg2.can_dlc = 8;
|
||||
canMsg2.data[0] = 0x0E;
|
||||
canMsg2.data[1] = 0x00;
|
||||
canMsg2.data[2] = 0x00;
|
||||
canMsg2.data[3] = 0x08;
|
||||
canMsg2.data[4] = 0x01;
|
||||
canMsg2.data[5] = 0x00;
|
||||
canMsg2.data[6] = 0x00;
|
||||
canMsg2.data[7] = 0xA0;
|
||||
|
||||
while (!Serial);
|
||||
Serial.begin(115200);
|
||||
|
||||
mcp2515.reset();
|
||||
mcp2515.setBitrate(CAN_125KBPS);
|
||||
mcp2515.setNormalMode();
|
||||
|
||||
Serial.println("Example: Write to CAN");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
mcp2515.sendMessage(&canMsg1);
|
||||
mcp2515.sendMessage(&canMsg2);
|
||||
|
||||
Serial.println("Messages sent");
|
||||
|
||||
delay(100);
|
||||
}
|
||||
BIN
libraries/arduino-mcp2515-master/examples/wiring-diy.png
Normal file
BIN
libraries/arduino-mcp2515-master/examples/wiring-diy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
libraries/arduino-mcp2515-master/examples/wiring.png
Normal file
BIN
libraries/arduino-mcp2515-master/examples/wiring.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 220 KiB |
14
libraries/arduino-mcp2515-master/keywords.txt
Normal file
14
libraries/arduino-mcp2515-master/keywords.txt
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
MCP2515 KEYWORD1
|
||||
|
||||
CAN_5KBPS LITERAL1
|
||||
CAN_10KBPS LITERAL1
|
||||
CAN_20KBPS LITERAL1
|
||||
CAN_40KBPS LITERAL1
|
||||
CAN_50KBPS LITERAL1
|
||||
CAN_80KBPS LITERAL1
|
||||
CAN_100KBPS LITERAL1
|
||||
CAN_125KBPS LITERAL1
|
||||
CAN_200KBPS LITERAL1
|
||||
CAN_250KBPS LITERAL1
|
||||
CAN_500KBPS LITERAL1
|
||||
CAN_1000KBPS LITERAL1
|
||||
766
libraries/arduino-mcp2515-master/mcp2515.cpp
Normal file
766
libraries/arduino-mcp2515-master/mcp2515.cpp
Normal file
|
|
@ -0,0 +1,766 @@
|
|||
#include "Arduino.h"
|
||||
#include "mcp2515.h"
|
||||
|
||||
const struct MCP2515::TXBn_REGS MCP2515::TXB[MCP2515::N_TXBUFFERS] = {
|
||||
{MCP_TXB0CTRL, MCP_TXB0SIDH, MCP_TXB0DATA},
|
||||
{MCP_TXB1CTRL, MCP_TXB1SIDH, MCP_TXB1DATA},
|
||||
{MCP_TXB2CTRL, MCP_TXB2SIDH, MCP_TXB2DATA}
|
||||
};
|
||||
|
||||
const struct MCP2515::RXBn_REGS MCP2515::RXB[N_RXBUFFERS] = {
|
||||
{MCP_RXB0CTRL, MCP_RXB0SIDH, MCP_RXB0DATA, CANINTF_RX0IF},
|
||||
{MCP_RXB1CTRL, MCP_RXB1SIDH, MCP_RXB1DATA, CANINTF_RX1IF}
|
||||
};
|
||||
|
||||
MCP2515::MCP2515(const uint8_t _CS)
|
||||
{
|
||||
SPI.begin();
|
||||
|
||||
SPICS = _CS;
|
||||
pinMode(SPICS, OUTPUT);
|
||||
endSPI();
|
||||
}
|
||||
|
||||
void MCP2515::startSPI() {
|
||||
SPI.beginTransaction(SPISettings(SPI_CLOCK, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(SPICS, LOW);
|
||||
}
|
||||
|
||||
void MCP2515::endSPI() {
|
||||
digitalWrite(SPICS, HIGH);
|
||||
SPI.endTransaction();
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::reset(void)
|
||||
{
|
||||
startSPI();
|
||||
SPI.transfer(INSTRUCTION_RESET);
|
||||
endSPI();
|
||||
|
||||
delay(10);
|
||||
|
||||
uint8_t zeros[14];
|
||||
memset(zeros, 0, sizeof(zeros));
|
||||
setRegisters(MCP_TXB0CTRL, zeros, 14);
|
||||
setRegisters(MCP_TXB1CTRL, zeros, 14);
|
||||
setRegisters(MCP_TXB2CTRL, zeros, 14);
|
||||
|
||||
setRegister(MCP_RXB0CTRL, 0);
|
||||
setRegister(MCP_RXB1CTRL, 0);
|
||||
|
||||
setRegister(MCP_CANINTE, CANINTF_RX0IF | CANINTF_RX1IF | CANINTF_ERRIF | CANINTF_MERRF);
|
||||
|
||||
// receives all valid messages using either Standard or Extended Identifiers that
|
||||
// meet filter criteria. RXF0 is applied for RXB0, RXF1 is applied for RXB1
|
||||
modifyRegister(MCP_RXB0CTRL,
|
||||
RXBnCTRL_RXM_MASK | RXB0CTRL_BUKT | RXB0CTRL_FILHIT_MASK,
|
||||
RXBnCTRL_RXM_STDEXT | RXB0CTRL_BUKT | RXB0CTRL_FILHIT);
|
||||
modifyRegister(MCP_RXB1CTRL,
|
||||
RXBnCTRL_RXM_MASK | RXB1CTRL_FILHIT_MASK,
|
||||
RXBnCTRL_RXM_STDEXT | RXB1CTRL_FILHIT);
|
||||
|
||||
// clear filters and masks
|
||||
// do not filter any standard frames for RXF0 used by RXB0
|
||||
// do not filter any extended frames for RXF1 used by RXB1
|
||||
RXF filters[] = {RXF0, RXF1, RXF2, RXF3, RXF4, RXF5};
|
||||
for (int i=0; i<6; i++) {
|
||||
bool ext = (i == 1);
|
||||
ERROR result = setFilter(filters[i], ext, 0);
|
||||
if (result != ERROR_OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
MASK masks[] = {MASK0, MASK1};
|
||||
for (int i=0; i<2; i++) {
|
||||
ERROR result = setFilterMask(masks[i], true, 0);
|
||||
if (result != ERROR_OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
uint8_t MCP2515::readRegister(const REGISTER reg)
|
||||
{
|
||||
startSPI();
|
||||
SPI.transfer(INSTRUCTION_READ);
|
||||
SPI.transfer(reg);
|
||||
uint8_t ret = SPI.transfer(0x00);
|
||||
endSPI();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void MCP2515::readRegisters(const REGISTER reg, uint8_t values[], const uint8_t n)
|
||||
{
|
||||
startSPI();
|
||||
SPI.transfer(INSTRUCTION_READ);
|
||||
SPI.transfer(reg);
|
||||
// mcp2515 has auto-increment of address-pointer
|
||||
for (uint8_t i=0; i<n; i++) {
|
||||
values[i] = SPI.transfer(0x00);
|
||||
}
|
||||
endSPI();
|
||||
}
|
||||
|
||||
void MCP2515::setRegister(const REGISTER reg, const uint8_t value)
|
||||
{
|
||||
startSPI();
|
||||
SPI.transfer(INSTRUCTION_WRITE);
|
||||
SPI.transfer(reg);
|
||||
SPI.transfer(value);
|
||||
endSPI();
|
||||
}
|
||||
|
||||
void MCP2515::setRegisters(const REGISTER reg, const uint8_t values[], const uint8_t n)
|
||||
{
|
||||
startSPI();
|
||||
SPI.transfer(INSTRUCTION_WRITE);
|
||||
SPI.transfer(reg);
|
||||
for (uint8_t i=0; i<n; i++) {
|
||||
SPI.transfer(values[i]);
|
||||
}
|
||||
endSPI();
|
||||
}
|
||||
|
||||
void MCP2515::modifyRegister(const REGISTER reg, const uint8_t mask, const uint8_t data)
|
||||
{
|
||||
startSPI();
|
||||
SPI.transfer(INSTRUCTION_BITMOD);
|
||||
SPI.transfer(reg);
|
||||
SPI.transfer(mask);
|
||||
SPI.transfer(data);
|
||||
endSPI();
|
||||
}
|
||||
|
||||
uint8_t MCP2515::getStatus(void)
|
||||
{
|
||||
startSPI();
|
||||
SPI.transfer(INSTRUCTION_READ_STATUS);
|
||||
uint8_t i = SPI.transfer(0x00);
|
||||
endSPI();
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::setConfigMode()
|
||||
{
|
||||
return setMode(CANCTRL_REQOP_CONFIG);
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::setListenOnlyMode()
|
||||
{
|
||||
return setMode(CANCTRL_REQOP_LISTENONLY);
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::setSleepMode()
|
||||
{
|
||||
return setMode(CANCTRL_REQOP_SLEEP);
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::setLoopbackMode()
|
||||
{
|
||||
return setMode(CANCTRL_REQOP_LOOPBACK);
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::setNormalMode()
|
||||
{
|
||||
return setMode(CANCTRL_REQOP_NORMAL);
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::setMode(const CANCTRL_REQOP_MODE mode)
|
||||
{
|
||||
modifyRegister(MCP_CANCTRL, CANCTRL_REQOP, mode);
|
||||
|
||||
unsigned long endTime = millis() + 10;
|
||||
bool modeMatch = false;
|
||||
while (millis() < endTime) {
|
||||
uint8_t newmode = readRegister(MCP_CANSTAT);
|
||||
newmode &= CANSTAT_OPMOD;
|
||||
|
||||
modeMatch = newmode == mode;
|
||||
|
||||
if (modeMatch) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return modeMatch ? ERROR_OK : ERROR_FAIL;
|
||||
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::setBitrate(const CAN_SPEED canSpeed)
|
||||
{
|
||||
return setBitrate(canSpeed, MCP_16MHZ);
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::setBitrate(const CAN_SPEED canSpeed, CAN_CLOCK canClock)
|
||||
{
|
||||
ERROR error = setConfigMode();
|
||||
if (error != ERROR_OK) {
|
||||
return error;
|
||||
}
|
||||
|
||||
uint8_t set, cfg1, cfg2, cfg3;
|
||||
set = 1;
|
||||
switch (canClock)
|
||||
{
|
||||
case (MCP_8MHZ):
|
||||
switch (canSpeed)
|
||||
{
|
||||
case (CAN_5KBPS): // 5KBPS
|
||||
cfg1 = MCP_8MHz_5kBPS_CFG1;
|
||||
cfg2 = MCP_8MHz_5kBPS_CFG2;
|
||||
cfg3 = MCP_8MHz_5kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_10KBPS): // 10KBPS
|
||||
cfg1 = MCP_8MHz_10kBPS_CFG1;
|
||||
cfg2 = MCP_8MHz_10kBPS_CFG2;
|
||||
cfg3 = MCP_8MHz_10kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_20KBPS): // 20KBPS
|
||||
cfg1 = MCP_8MHz_20kBPS_CFG1;
|
||||
cfg2 = MCP_8MHz_20kBPS_CFG2;
|
||||
cfg3 = MCP_8MHz_20kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_31K25BPS): // 31.25KBPS
|
||||
cfg1 = MCP_8MHz_31k25BPS_CFG1;
|
||||
cfg2 = MCP_8MHz_31k25BPS_CFG2;
|
||||
cfg3 = MCP_8MHz_31k25BPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_33KBPS): // 33.333KBPS
|
||||
cfg1 = MCP_8MHz_33k3BPS_CFG1;
|
||||
cfg2 = MCP_8MHz_33k3BPS_CFG2;
|
||||
cfg3 = MCP_8MHz_33k3BPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_40KBPS): // 40Kbps
|
||||
cfg1 = MCP_8MHz_40kBPS_CFG1;
|
||||
cfg2 = MCP_8MHz_40kBPS_CFG2;
|
||||
cfg3 = MCP_8MHz_40kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_50KBPS): // 50Kbps
|
||||
cfg1 = MCP_8MHz_50kBPS_CFG1;
|
||||
cfg2 = MCP_8MHz_50kBPS_CFG2;
|
||||
cfg3 = MCP_8MHz_50kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_80KBPS): // 80Kbps
|
||||
cfg1 = MCP_8MHz_80kBPS_CFG1;
|
||||
cfg2 = MCP_8MHz_80kBPS_CFG2;
|
||||
cfg3 = MCP_8MHz_80kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_100KBPS): // 100Kbps
|
||||
cfg1 = MCP_8MHz_100kBPS_CFG1;
|
||||
cfg2 = MCP_8MHz_100kBPS_CFG2;
|
||||
cfg3 = MCP_8MHz_100kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_125KBPS): // 125Kbps
|
||||
cfg1 = MCP_8MHz_125kBPS_CFG1;
|
||||
cfg2 = MCP_8MHz_125kBPS_CFG2;
|
||||
cfg3 = MCP_8MHz_125kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_200KBPS): // 200Kbps
|
||||
cfg1 = MCP_8MHz_200kBPS_CFG1;
|
||||
cfg2 = MCP_8MHz_200kBPS_CFG2;
|
||||
cfg3 = MCP_8MHz_200kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_250KBPS): // 250Kbps
|
||||
cfg1 = MCP_8MHz_250kBPS_CFG1;
|
||||
cfg2 = MCP_8MHz_250kBPS_CFG2;
|
||||
cfg3 = MCP_8MHz_250kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_500KBPS): // 500Kbps
|
||||
cfg1 = MCP_8MHz_500kBPS_CFG1;
|
||||
cfg2 = MCP_8MHz_500kBPS_CFG2;
|
||||
cfg3 = MCP_8MHz_500kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_1000KBPS): // 1Mbps
|
||||
cfg1 = MCP_8MHz_1000kBPS_CFG1;
|
||||
cfg2 = MCP_8MHz_1000kBPS_CFG2;
|
||||
cfg3 = MCP_8MHz_1000kBPS_CFG3;
|
||||
break;
|
||||
|
||||
default:
|
||||
set = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case (MCP_16MHZ):
|
||||
switch (canSpeed)
|
||||
{
|
||||
case (CAN_5KBPS): // 5Kbps
|
||||
cfg1 = MCP_16MHz_5kBPS_CFG1;
|
||||
cfg2 = MCP_16MHz_5kBPS_CFG2;
|
||||
cfg3 = MCP_16MHz_5kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_10KBPS): // 10Kbps
|
||||
cfg1 = MCP_16MHz_10kBPS_CFG1;
|
||||
cfg2 = MCP_16MHz_10kBPS_CFG2;
|
||||
cfg3 = MCP_16MHz_10kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_20KBPS): // 20Kbps
|
||||
cfg1 = MCP_16MHz_20kBPS_CFG1;
|
||||
cfg2 = MCP_16MHz_20kBPS_CFG2;
|
||||
cfg3 = MCP_16MHz_20kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_33KBPS): // 33.333Kbps
|
||||
cfg1 = MCP_16MHz_33k3BPS_CFG1;
|
||||
cfg2 = MCP_16MHz_33k3BPS_CFG2;
|
||||
cfg3 = MCP_16MHz_33k3BPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_40KBPS): // 40Kbps
|
||||
cfg1 = MCP_16MHz_40kBPS_CFG1;
|
||||
cfg2 = MCP_16MHz_40kBPS_CFG2;
|
||||
cfg3 = MCP_16MHz_40kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_50KBPS): // 50Kbps
|
||||
cfg1 = MCP_16MHz_50kBPS_CFG1;
|
||||
cfg2 = MCP_16MHz_50kBPS_CFG2;
|
||||
cfg3 = MCP_16MHz_50kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_80KBPS): // 80Kbps
|
||||
cfg1 = MCP_16MHz_80kBPS_CFG1;
|
||||
cfg2 = MCP_16MHz_80kBPS_CFG2;
|
||||
cfg3 = MCP_16MHz_80kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_83K3BPS): // 83.333Kbps
|
||||
cfg1 = MCP_16MHz_83k3BPS_CFG1;
|
||||
cfg2 = MCP_16MHz_83k3BPS_CFG2;
|
||||
cfg3 = MCP_16MHz_83k3BPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_100KBPS): // 100Kbps
|
||||
cfg1 = MCP_16MHz_100kBPS_CFG1;
|
||||
cfg2 = MCP_16MHz_100kBPS_CFG2;
|
||||
cfg3 = MCP_16MHz_100kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_125KBPS): // 125Kbps
|
||||
cfg1 = MCP_16MHz_125kBPS_CFG1;
|
||||
cfg2 = MCP_16MHz_125kBPS_CFG2;
|
||||
cfg3 = MCP_16MHz_125kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_200KBPS): // 200Kbps
|
||||
cfg1 = MCP_16MHz_200kBPS_CFG1;
|
||||
cfg2 = MCP_16MHz_200kBPS_CFG2;
|
||||
cfg3 = MCP_16MHz_200kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_250KBPS): // 250Kbps
|
||||
cfg1 = MCP_16MHz_250kBPS_CFG1;
|
||||
cfg2 = MCP_16MHz_250kBPS_CFG2;
|
||||
cfg3 = MCP_16MHz_250kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_500KBPS): // 500Kbps
|
||||
cfg1 = MCP_16MHz_500kBPS_CFG1;
|
||||
cfg2 = MCP_16MHz_500kBPS_CFG2;
|
||||
cfg3 = MCP_16MHz_500kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_1000KBPS): // 1Mbps
|
||||
cfg1 = MCP_16MHz_1000kBPS_CFG1;
|
||||
cfg2 = MCP_16MHz_1000kBPS_CFG2;
|
||||
cfg3 = MCP_16MHz_1000kBPS_CFG3;
|
||||
break;
|
||||
|
||||
default:
|
||||
set = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case (MCP_20MHZ):
|
||||
switch (canSpeed)
|
||||
{
|
||||
case (CAN_33KBPS): // 33.333Kbps
|
||||
cfg1 = MCP_20MHz_33k3BPS_CFG1;
|
||||
cfg2 = MCP_20MHz_33k3BPS_CFG2;
|
||||
cfg3 = MCP_20MHz_33k3BPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_40KBPS): // 40Kbps
|
||||
cfg1 = MCP_20MHz_40kBPS_CFG1;
|
||||
cfg2 = MCP_20MHz_40kBPS_CFG2;
|
||||
cfg3 = MCP_20MHz_40kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_50KBPS): // 50Kbps
|
||||
cfg1 = MCP_20MHz_50kBPS_CFG1;
|
||||
cfg2 = MCP_20MHz_50kBPS_CFG2;
|
||||
cfg3 = MCP_20MHz_50kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_80KBPS): // 80Kbps
|
||||
cfg1 = MCP_20MHz_80kBPS_CFG1;
|
||||
cfg2 = MCP_20MHz_80kBPS_CFG2;
|
||||
cfg3 = MCP_20MHz_80kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_83K3BPS): // 83.333Kbps
|
||||
cfg1 = MCP_20MHz_83k3BPS_CFG1;
|
||||
cfg2 = MCP_20MHz_83k3BPS_CFG2;
|
||||
cfg3 = MCP_20MHz_83k3BPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_100KBPS): // 100Kbps
|
||||
cfg1 = MCP_20MHz_100kBPS_CFG1;
|
||||
cfg2 = MCP_20MHz_100kBPS_CFG2;
|
||||
cfg3 = MCP_20MHz_100kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_125KBPS): // 125Kbps
|
||||
cfg1 = MCP_20MHz_125kBPS_CFG1;
|
||||
cfg2 = MCP_20MHz_125kBPS_CFG2;
|
||||
cfg3 = MCP_20MHz_125kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_200KBPS): // 200Kbps
|
||||
cfg1 = MCP_20MHz_200kBPS_CFG1;
|
||||
cfg2 = MCP_20MHz_200kBPS_CFG2;
|
||||
cfg3 = MCP_20MHz_200kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_250KBPS): // 250Kbps
|
||||
cfg1 = MCP_20MHz_250kBPS_CFG1;
|
||||
cfg2 = MCP_20MHz_250kBPS_CFG2;
|
||||
cfg3 = MCP_20MHz_250kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_500KBPS): // 500Kbps
|
||||
cfg1 = MCP_20MHz_500kBPS_CFG1;
|
||||
cfg2 = MCP_20MHz_500kBPS_CFG2;
|
||||
cfg3 = MCP_20MHz_500kBPS_CFG3;
|
||||
break;
|
||||
|
||||
case (CAN_1000KBPS): // 1Mbps
|
||||
cfg1 = MCP_20MHz_1000kBPS_CFG1;
|
||||
cfg2 = MCP_20MHz_1000kBPS_CFG2;
|
||||
cfg3 = MCP_20MHz_1000kBPS_CFG3;
|
||||
break;
|
||||
|
||||
default:
|
||||
set = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
set = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (set) {
|
||||
setRegister(MCP_CNF1, cfg1);
|
||||
setRegister(MCP_CNF2, cfg2);
|
||||
setRegister(MCP_CNF3, cfg3);
|
||||
return ERROR_OK;
|
||||
}
|
||||
else {
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::setClkOut(const CAN_CLKOUT divisor)
|
||||
{
|
||||
if (divisor == CLKOUT_DISABLE) {
|
||||
/* Turn off CLKEN */
|
||||
modifyRegister(MCP_CANCTRL, CANCTRL_CLKEN, 0x00);
|
||||
|
||||
/* Turn on CLKOUT for SOF */
|
||||
modifyRegister(MCP_CNF3, CNF3_SOF, CNF3_SOF);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* Set the prescaler (CLKPRE) */
|
||||
modifyRegister(MCP_CANCTRL, CANCTRL_CLKPRE, divisor);
|
||||
|
||||
/* Turn on CLKEN */
|
||||
modifyRegister(MCP_CANCTRL, CANCTRL_CLKEN, CANCTRL_CLKEN);
|
||||
|
||||
/* Turn off CLKOUT for SOF */
|
||||
modifyRegister(MCP_CNF3, CNF3_SOF, 0x00);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
void MCP2515::prepareId(uint8_t *buffer, const bool ext, const uint32_t id)
|
||||
{
|
||||
uint16_t canid = (uint16_t)(id & 0x0FFFF);
|
||||
|
||||
if (ext) {
|
||||
buffer[MCP_EID0] = (uint8_t) (canid & 0xFF);
|
||||
buffer[MCP_EID8] = (uint8_t) (canid >> 8);
|
||||
canid = (uint16_t)(id >> 16);
|
||||
buffer[MCP_SIDL] = (uint8_t) (canid & 0x03);
|
||||
buffer[MCP_SIDL] += (uint8_t) ((canid & 0x1C) << 3);
|
||||
buffer[MCP_SIDL] |= TXB_EXIDE_MASK;
|
||||
buffer[MCP_SIDH] = (uint8_t) (canid >> 5);
|
||||
} else {
|
||||
buffer[MCP_SIDH] = (uint8_t) (canid >> 3);
|
||||
buffer[MCP_SIDL] = (uint8_t) ((canid & 0x07 ) << 5);
|
||||
buffer[MCP_EID0] = 0;
|
||||
buffer[MCP_EID8] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::setFilterMask(const MASK mask, const bool ext, const uint32_t ulData)
|
||||
{
|
||||
ERROR res = setConfigMode();
|
||||
if (res != ERROR_OK) {
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t tbufdata[4];
|
||||
prepareId(tbufdata, ext, ulData);
|
||||
|
||||
REGISTER reg;
|
||||
switch (mask) {
|
||||
case MASK0: reg = MCP_RXM0SIDH; break;
|
||||
case MASK1: reg = MCP_RXM1SIDH; break;
|
||||
default:
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
setRegisters(reg, tbufdata, 4);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::setFilter(const RXF num, const bool ext, const uint32_t ulData)
|
||||
{
|
||||
ERROR res = setConfigMode();
|
||||
if (res != ERROR_OK) {
|
||||
return res;
|
||||
}
|
||||
|
||||
REGISTER reg;
|
||||
|
||||
switch (num) {
|
||||
case RXF0: reg = MCP_RXF0SIDH; break;
|
||||
case RXF1: reg = MCP_RXF1SIDH; break;
|
||||
case RXF2: reg = MCP_RXF2SIDH; break;
|
||||
case RXF3: reg = MCP_RXF3SIDH; break;
|
||||
case RXF4: reg = MCP_RXF4SIDH; break;
|
||||
case RXF5: reg = MCP_RXF5SIDH; break;
|
||||
default:
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
uint8_t tbufdata[4];
|
||||
prepareId(tbufdata, ext, ulData);
|
||||
setRegisters(reg, tbufdata, 4);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::sendMessage(const TXBn txbn, const struct can_frame *frame)
|
||||
{
|
||||
if (frame->can_dlc > CAN_MAX_DLEN) {
|
||||
return ERROR_FAILTX;
|
||||
}
|
||||
|
||||
const struct TXBn_REGS *txbuf = &TXB[txbn];
|
||||
|
||||
uint8_t data[13];
|
||||
|
||||
bool ext = (frame->can_id & CAN_EFF_FLAG);
|
||||
bool rtr = (frame->can_id & CAN_RTR_FLAG);
|
||||
uint32_t id = (frame->can_id & (ext ? CAN_EFF_MASK : CAN_SFF_MASK));
|
||||
|
||||
prepareId(data, ext, id);
|
||||
|
||||
data[MCP_DLC] = rtr ? (frame->can_dlc | RTR_MASK) : frame->can_dlc;
|
||||
|
||||
memcpy(&data[MCP_DATA], frame->data, frame->can_dlc);
|
||||
|
||||
setRegisters(txbuf->SIDH, data, 5 + frame->can_dlc);
|
||||
|
||||
modifyRegister(txbuf->CTRL, TXB_TXREQ, TXB_TXREQ);
|
||||
|
||||
uint8_t ctrl = readRegister(txbuf->CTRL);
|
||||
if ((ctrl & (TXB_ABTF | TXB_MLOA | TXB_TXERR)) != 0) {
|
||||
return ERROR_FAILTX;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::sendMessage(const struct can_frame *frame)
|
||||
{
|
||||
if (frame->can_dlc > CAN_MAX_DLEN) {
|
||||
return ERROR_FAILTX;
|
||||
}
|
||||
|
||||
TXBn txBuffers[N_TXBUFFERS] = {TXB0, TXB1, TXB2};
|
||||
|
||||
for (int i=0; i<N_TXBUFFERS; i++) {
|
||||
const struct TXBn_REGS *txbuf = &TXB[txBuffers[i]];
|
||||
uint8_t ctrlval = readRegister(txbuf->CTRL);
|
||||
if ( (ctrlval & TXB_TXREQ) == 0 ) {
|
||||
return sendMessage(txBuffers[i], frame);
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_ALLTXBUSY;
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::readMessage(const RXBn rxbn, struct can_frame *frame)
|
||||
{
|
||||
const struct RXBn_REGS *rxb = &RXB[rxbn];
|
||||
|
||||
uint8_t tbufdata[5];
|
||||
|
||||
readRegisters(rxb->SIDH, tbufdata, 5);
|
||||
|
||||
uint32_t id = (tbufdata[MCP_SIDH]<<3) + (tbufdata[MCP_SIDL]>>5);
|
||||
|
||||
if ( (tbufdata[MCP_SIDL] & TXB_EXIDE_MASK) == TXB_EXIDE_MASK ) {
|
||||
id = (id<<2) + (tbufdata[MCP_SIDL] & 0x03);
|
||||
id = (id<<8) + tbufdata[MCP_EID8];
|
||||
id = (id<<8) + tbufdata[MCP_EID0];
|
||||
id |= CAN_EFF_FLAG;
|
||||
}
|
||||
|
||||
uint8_t dlc = (tbufdata[MCP_DLC] & DLC_MASK);
|
||||
if (dlc > CAN_MAX_DLEN) {
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
uint8_t ctrl = readRegister(rxb->CTRL);
|
||||
if (ctrl & RXBnCTRL_RTR) {
|
||||
id |= CAN_RTR_FLAG;
|
||||
}
|
||||
|
||||
frame->can_id = id;
|
||||
frame->can_dlc = dlc;
|
||||
|
||||
readRegisters(rxb->DATA, frame->data, dlc);
|
||||
|
||||
modifyRegister(MCP_CANINTF, rxb->CANINTF_RXnIF, 0);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
MCP2515::ERROR MCP2515::readMessage(struct can_frame *frame)
|
||||
{
|
||||
ERROR rc;
|
||||
uint8_t stat = getStatus();
|
||||
|
||||
if ( stat & STAT_RX0IF ) {
|
||||
rc = readMessage(RXB0, frame);
|
||||
} else if ( stat & STAT_RX1IF ) {
|
||||
rc = readMessage(RXB1, frame);
|
||||
} else {
|
||||
rc = ERROR_NOMSG;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool MCP2515::checkReceive(void)
|
||||
{
|
||||
uint8_t res = getStatus();
|
||||
if ( res & STAT_RXIF_MASK ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MCP2515::checkError(void)
|
||||
{
|
||||
uint8_t eflg = getErrorFlags();
|
||||
|
||||
if ( eflg & EFLG_ERRORMASK ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t MCP2515::getErrorFlags(void)
|
||||
{
|
||||
return readRegister(MCP_EFLG);
|
||||
}
|
||||
|
||||
void MCP2515::clearRXnOVRFlags(void)
|
||||
{
|
||||
modifyRegister(MCP_EFLG, EFLG_RX0OVR | EFLG_RX1OVR, 0);
|
||||
}
|
||||
|
||||
uint8_t MCP2515::getInterrupts(void)
|
||||
{
|
||||
return readRegister(MCP_CANINTF);
|
||||
}
|
||||
|
||||
void MCP2515::clearInterrupts(void)
|
||||
{
|
||||
setRegister(MCP_CANINTF, 0);
|
||||
}
|
||||
|
||||
uint8_t MCP2515::getInterruptMask(void)
|
||||
{
|
||||
return readRegister(MCP_CANINTE);
|
||||
}
|
||||
|
||||
void MCP2515::clearTXInterrupts(void)
|
||||
{
|
||||
modifyRegister(MCP_CANINTF, (CANINTF_TX0IF | CANINTF_TX1IF | CANINTF_TX2IF), 0);
|
||||
}
|
||||
|
||||
void MCP2515::clearRXnOVR(void)
|
||||
{
|
||||
uint8_t eflg = getErrorFlags();
|
||||
if (eflg != 0) {
|
||||
clearRXnOVRFlags();
|
||||
clearInterrupts();
|
||||
//modifyRegister(MCP_CANINTF, CANINTF_ERRIF, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MCP2515::clearMERR()
|
||||
{
|
||||
//modifyRegister(MCP_EFLG, EFLG_RX0OVR | EFLG_RX1OVR, 0);
|
||||
//clearInterrupts();
|
||||
modifyRegister(MCP_CANINTF, CANINTF_MERRF, 0);
|
||||
}
|
||||
|
||||
void MCP2515::clearERRIF()
|
||||
{
|
||||
//modifyRegister(MCP_EFLG, EFLG_RX0OVR | EFLG_RX1OVR, 0);
|
||||
//clearInterrupts();
|
||||
modifyRegister(MCP_CANINTF, CANINTF_ERRIF, 0);
|
||||
}
|
||||
|
||||
uint8_t MCP2515::errorCountRX(void)
|
||||
{
|
||||
return readRegister(MCP_REC);
|
||||
}
|
||||
|
||||
uint8_t MCP2515::errorCountTX(void)
|
||||
{
|
||||
return readRegister(MCP_TEC);
|
||||
}
|
||||
495
libraries/arduino-mcp2515-master/mcp2515.h
Normal file
495
libraries/arduino-mcp2515-master/mcp2515.h
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
#ifndef _MCP2515_H_
|
||||
#define _MCP2515_H_
|
||||
|
||||
#include <SPI.h>
|
||||
#include "can.h"
|
||||
|
||||
/*
|
||||
* Speed 8M
|
||||
*/
|
||||
#define MCP_8MHz_1000kBPS_CFG1 (0x00)
|
||||
#define MCP_8MHz_1000kBPS_CFG2 (0x80)
|
||||
#define MCP_8MHz_1000kBPS_CFG3 (0x80)
|
||||
|
||||
#define MCP_8MHz_500kBPS_CFG1 (0x00)
|
||||
#define MCP_8MHz_500kBPS_CFG2 (0x90)
|
||||
#define MCP_8MHz_500kBPS_CFG3 (0x82)
|
||||
|
||||
#define MCP_8MHz_250kBPS_CFG1 (0x00)
|
||||
#define MCP_8MHz_250kBPS_CFG2 (0xB1)
|
||||
#define MCP_8MHz_250kBPS_CFG3 (0x85)
|
||||
|
||||
#define MCP_8MHz_200kBPS_CFG1 (0x00)
|
||||
#define MCP_8MHz_200kBPS_CFG2 (0xB4)
|
||||
#define MCP_8MHz_200kBPS_CFG3 (0x86)
|
||||
|
||||
#define MCP_8MHz_125kBPS_CFG1 (0x01)
|
||||
#define MCP_8MHz_125kBPS_CFG2 (0xB1)
|
||||
#define MCP_8MHz_125kBPS_CFG3 (0x85)
|
||||
|
||||
#define MCP_8MHz_100kBPS_CFG1 (0x01)
|
||||
#define MCP_8MHz_100kBPS_CFG2 (0xB4)
|
||||
#define MCP_8MHz_100kBPS_CFG3 (0x86)
|
||||
|
||||
#define MCP_8MHz_80kBPS_CFG1 (0x01)
|
||||
#define MCP_8MHz_80kBPS_CFG2 (0xBF)
|
||||
#define MCP_8MHz_80kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_8MHz_50kBPS_CFG1 (0x03)
|
||||
#define MCP_8MHz_50kBPS_CFG2 (0xB4)
|
||||
#define MCP_8MHz_50kBPS_CFG3 (0x86)
|
||||
|
||||
#define MCP_8MHz_40kBPS_CFG1 (0x03)
|
||||
#define MCP_8MHz_40kBPS_CFG2 (0xBF)
|
||||
#define MCP_8MHz_40kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_8MHz_33k3BPS_CFG1 (0x47)
|
||||
#define MCP_8MHz_33k3BPS_CFG2 (0xE2)
|
||||
#define MCP_8MHz_33k3BPS_CFG3 (0x85)
|
||||
|
||||
#define MCP_8MHz_31k25BPS_CFG1 (0x07)
|
||||
#define MCP_8MHz_31k25BPS_CFG2 (0xA4)
|
||||
#define MCP_8MHz_31k25BPS_CFG3 (0x84)
|
||||
|
||||
#define MCP_8MHz_20kBPS_CFG1 (0x07)
|
||||
#define MCP_8MHz_20kBPS_CFG2 (0xBF)
|
||||
#define MCP_8MHz_20kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_8MHz_10kBPS_CFG1 (0x0F)
|
||||
#define MCP_8MHz_10kBPS_CFG2 (0xBF)
|
||||
#define MCP_8MHz_10kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_8MHz_5kBPS_CFG1 (0x1F)
|
||||
#define MCP_8MHz_5kBPS_CFG2 (0xBF)
|
||||
#define MCP_8MHz_5kBPS_CFG3 (0x87)
|
||||
|
||||
/*
|
||||
* speed 16M
|
||||
*/
|
||||
#define MCP_16MHz_1000kBPS_CFG1 (0x00)
|
||||
#define MCP_16MHz_1000kBPS_CFG2 (0xD0)
|
||||
#define MCP_16MHz_1000kBPS_CFG3 (0x82)
|
||||
|
||||
#define MCP_16MHz_500kBPS_CFG1 (0x00)
|
||||
#define MCP_16MHz_500kBPS_CFG2 (0xF0)
|
||||
#define MCP_16MHz_500kBPS_CFG3 (0x86)
|
||||
|
||||
#define MCP_16MHz_250kBPS_CFG1 (0x41)
|
||||
#define MCP_16MHz_250kBPS_CFG2 (0xF1)
|
||||
#define MCP_16MHz_250kBPS_CFG3 (0x85)
|
||||
|
||||
#define MCP_16MHz_200kBPS_CFG1 (0x01)
|
||||
#define MCP_16MHz_200kBPS_CFG2 (0xFA)
|
||||
#define MCP_16MHz_200kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_16MHz_125kBPS_CFG1 (0x03)
|
||||
#define MCP_16MHz_125kBPS_CFG2 (0xF0)
|
||||
#define MCP_16MHz_125kBPS_CFG3 (0x86)
|
||||
|
||||
#define MCP_16MHz_100kBPS_CFG1 (0x03)
|
||||
#define MCP_16MHz_100kBPS_CFG2 (0xFA)
|
||||
#define MCP_16MHz_100kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_16MHz_80kBPS_CFG1 (0x03)
|
||||
#define MCP_16MHz_80kBPS_CFG2 (0xFF)
|
||||
#define MCP_16MHz_80kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_16MHz_83k3BPS_CFG1 (0x03)
|
||||
#define MCP_16MHz_83k3BPS_CFG2 (0xBE)
|
||||
#define MCP_16MHz_83k3BPS_CFG3 (0x07)
|
||||
|
||||
#define MCP_16MHz_50kBPS_CFG1 (0x07)
|
||||
#define MCP_16MHz_50kBPS_CFG2 (0xFA)
|
||||
#define MCP_16MHz_50kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_16MHz_40kBPS_CFG1 (0x07)
|
||||
#define MCP_16MHz_40kBPS_CFG2 (0xFF)
|
||||
#define MCP_16MHz_40kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_16MHz_33k3BPS_CFG1 (0x4E)
|
||||
#define MCP_16MHz_33k3BPS_CFG2 (0xF1)
|
||||
#define MCP_16MHz_33k3BPS_CFG3 (0x85)
|
||||
|
||||
#define MCP_16MHz_20kBPS_CFG1 (0x0F)
|
||||
#define MCP_16MHz_20kBPS_CFG2 (0xFF)
|
||||
#define MCP_16MHz_20kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_16MHz_10kBPS_CFG1 (0x1F)
|
||||
#define MCP_16MHz_10kBPS_CFG2 (0xFF)
|
||||
#define MCP_16MHz_10kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_16MHz_5kBPS_CFG1 (0x3F)
|
||||
#define MCP_16MHz_5kBPS_CFG2 (0xFF)
|
||||
#define MCP_16MHz_5kBPS_CFG3 (0x87)
|
||||
|
||||
/*
|
||||
* speed 20M
|
||||
*/
|
||||
#define MCP_20MHz_1000kBPS_CFG1 (0x00)
|
||||
#define MCP_20MHz_1000kBPS_CFG2 (0xD9)
|
||||
#define MCP_20MHz_1000kBPS_CFG3 (0x82)
|
||||
|
||||
#define MCP_20MHz_500kBPS_CFG1 (0x00)
|
||||
#define MCP_20MHz_500kBPS_CFG2 (0xFA)
|
||||
#define MCP_20MHz_500kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_20MHz_250kBPS_CFG1 (0x41)
|
||||
#define MCP_20MHz_250kBPS_CFG2 (0xFB)
|
||||
#define MCP_20MHz_250kBPS_CFG3 (0x86)
|
||||
|
||||
#define MCP_20MHz_200kBPS_CFG1 (0x01)
|
||||
#define MCP_20MHz_200kBPS_CFG2 (0xFF)
|
||||
#define MCP_20MHz_200kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_20MHz_125kBPS_CFG1 (0x03)
|
||||
#define MCP_20MHz_125kBPS_CFG2 (0xFA)
|
||||
#define MCP_20MHz_125kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_20MHz_100kBPS_CFG1 (0x04)
|
||||
#define MCP_20MHz_100kBPS_CFG2 (0xFA)
|
||||
#define MCP_20MHz_100kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_20MHz_83k3BPS_CFG1 (0x04)
|
||||
#define MCP_20MHz_83k3BPS_CFG2 (0xFE)
|
||||
#define MCP_20MHz_83k3BPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_20MHz_80kBPS_CFG1 (0x04)
|
||||
#define MCP_20MHz_80kBPS_CFG2 (0xFF)
|
||||
#define MCP_20MHz_80kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_20MHz_50kBPS_CFG1 (0x09)
|
||||
#define MCP_20MHz_50kBPS_CFG2 (0xFA)
|
||||
#define MCP_20MHz_50kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_20MHz_40kBPS_CFG1 (0x09)
|
||||
#define MCP_20MHz_40kBPS_CFG2 (0xFF)
|
||||
#define MCP_20MHz_40kBPS_CFG3 (0x87)
|
||||
|
||||
#define MCP_20MHz_33k3BPS_CFG1 (0x0B)
|
||||
#define MCP_20MHz_33k3BPS_CFG2 (0xFF)
|
||||
#define MCP_20MHz_33k3BPS_CFG3 (0x87)
|
||||
|
||||
enum CAN_CLOCK {
|
||||
MCP_20MHZ,
|
||||
MCP_16MHZ,
|
||||
MCP_8MHZ
|
||||
};
|
||||
|
||||
enum CAN_SPEED {
|
||||
CAN_5KBPS,
|
||||
CAN_10KBPS,
|
||||
CAN_20KBPS,
|
||||
CAN_31K25BPS,
|
||||
CAN_33KBPS,
|
||||
CAN_40KBPS,
|
||||
CAN_50KBPS,
|
||||
CAN_80KBPS,
|
||||
CAN_83K3BPS,
|
||||
CAN_95KBPS,
|
||||
CAN_100KBPS,
|
||||
CAN_125KBPS,
|
||||
CAN_200KBPS,
|
||||
CAN_250KBPS,
|
||||
CAN_500KBPS,
|
||||
CAN_1000KBPS
|
||||
};
|
||||
|
||||
enum CAN_CLKOUT {
|
||||
CLKOUT_DISABLE = -1,
|
||||
CLKOUT_DIV1 = 0x0,
|
||||
CLKOUT_DIV2 = 0x1,
|
||||
CLKOUT_DIV4 = 0x2,
|
||||
CLKOUT_DIV8 = 0x3,
|
||||
};
|
||||
|
||||
class MCP2515
|
||||
{
|
||||
public:
|
||||
enum ERROR {
|
||||
ERROR_OK = 0,
|
||||
ERROR_FAIL = 1,
|
||||
ERROR_ALLTXBUSY = 2,
|
||||
ERROR_FAILINIT = 3,
|
||||
ERROR_FAILTX = 4,
|
||||
ERROR_NOMSG = 5
|
||||
};
|
||||
|
||||
enum MASK {
|
||||
MASK0,
|
||||
MASK1
|
||||
};
|
||||
|
||||
enum RXF {
|
||||
RXF0 = 0,
|
||||
RXF1 = 1,
|
||||
RXF2 = 2,
|
||||
RXF3 = 3,
|
||||
RXF4 = 4,
|
||||
RXF5 = 5
|
||||
};
|
||||
|
||||
enum RXBn {
|
||||
RXB0 = 0,
|
||||
RXB1 = 1
|
||||
};
|
||||
|
||||
enum TXBn {
|
||||
TXB0 = 0,
|
||||
TXB1 = 1,
|
||||
TXB2 = 2
|
||||
};
|
||||
|
||||
enum /*class*/ CANINTF : uint8_t {
|
||||
CANINTF_RX0IF = 0x01,
|
||||
CANINTF_RX1IF = 0x02,
|
||||
CANINTF_TX0IF = 0x04,
|
||||
CANINTF_TX1IF = 0x08,
|
||||
CANINTF_TX2IF = 0x10,
|
||||
CANINTF_ERRIF = 0x20,
|
||||
CANINTF_WAKIF = 0x40,
|
||||
CANINTF_MERRF = 0x80
|
||||
};
|
||||
|
||||
enum /*class*/ EFLG : uint8_t {
|
||||
EFLG_RX1OVR = (1<<7),
|
||||
EFLG_RX0OVR = (1<<6),
|
||||
EFLG_TXBO = (1<<5),
|
||||
EFLG_TXEP = (1<<4),
|
||||
EFLG_RXEP = (1<<3),
|
||||
EFLG_TXWAR = (1<<2),
|
||||
EFLG_RXWAR = (1<<1),
|
||||
EFLG_EWARN = (1<<0)
|
||||
};
|
||||
|
||||
private:
|
||||
static const uint8_t CANCTRL_REQOP = 0xE0;
|
||||
static const uint8_t CANCTRL_ABAT = 0x10;
|
||||
static const uint8_t CANCTRL_OSM = 0x08;
|
||||
static const uint8_t CANCTRL_CLKEN = 0x04;
|
||||
static const uint8_t CANCTRL_CLKPRE = 0x03;
|
||||
|
||||
enum /*class*/ CANCTRL_REQOP_MODE : uint8_t {
|
||||
CANCTRL_REQOP_NORMAL = 0x00,
|
||||
CANCTRL_REQOP_SLEEP = 0x20,
|
||||
CANCTRL_REQOP_LOOPBACK = 0x40,
|
||||
CANCTRL_REQOP_LISTENONLY = 0x60,
|
||||
CANCTRL_REQOP_CONFIG = 0x80,
|
||||
CANCTRL_REQOP_POWERUP = 0xE0
|
||||
};
|
||||
|
||||
static const uint8_t CANSTAT_OPMOD = 0xE0;
|
||||
static const uint8_t CANSTAT_ICOD = 0x0E;
|
||||
|
||||
static const uint8_t CNF3_SOF = 0x80;
|
||||
|
||||
static const uint8_t TXB_EXIDE_MASK = 0x08;
|
||||
static const uint8_t DLC_MASK = 0x0F;
|
||||
static const uint8_t RTR_MASK = 0x40;
|
||||
|
||||
static const uint8_t RXBnCTRL_RXM_STD = 0x20;
|
||||
static const uint8_t RXBnCTRL_RXM_EXT = 0x40;
|
||||
static const uint8_t RXBnCTRL_RXM_STDEXT = 0x00;
|
||||
static const uint8_t RXBnCTRL_RXM_MASK = 0x60;
|
||||
static const uint8_t RXBnCTRL_RTR = 0x08;
|
||||
static const uint8_t RXB0CTRL_BUKT = 0x04;
|
||||
static const uint8_t RXB0CTRL_FILHIT_MASK = 0x03;
|
||||
static const uint8_t RXB1CTRL_FILHIT_MASK = 0x07;
|
||||
static const uint8_t RXB0CTRL_FILHIT = 0x00;
|
||||
static const uint8_t RXB1CTRL_FILHIT = 0x01;
|
||||
|
||||
static const uint8_t MCP_SIDH = 0;
|
||||
static const uint8_t MCP_SIDL = 1;
|
||||
static const uint8_t MCP_EID8 = 2;
|
||||
static const uint8_t MCP_EID0 = 3;
|
||||
static const uint8_t MCP_DLC = 4;
|
||||
static const uint8_t MCP_DATA = 5;
|
||||
|
||||
enum /*class*/ STAT : uint8_t {
|
||||
STAT_RX0IF = (1<<0),
|
||||
STAT_RX1IF = (1<<1)
|
||||
};
|
||||
|
||||
static const uint8_t STAT_RXIF_MASK = STAT_RX0IF | STAT_RX1IF;
|
||||
|
||||
enum /*class*/ TXBnCTRL : uint8_t {
|
||||
TXB_ABTF = 0x40,
|
||||
TXB_MLOA = 0x20,
|
||||
TXB_TXERR = 0x10,
|
||||
TXB_TXREQ = 0x08,
|
||||
TXB_TXIE = 0x04,
|
||||
TXB_TXP = 0x03
|
||||
};
|
||||
|
||||
static const uint8_t EFLG_ERRORMASK = EFLG_RX1OVR
|
||||
| EFLG_RX0OVR
|
||||
| EFLG_TXBO
|
||||
| EFLG_TXEP
|
||||
| EFLG_RXEP;
|
||||
|
||||
enum /*class*/ INSTRUCTION : uint8_t {
|
||||
INSTRUCTION_WRITE = 0x02,
|
||||
INSTRUCTION_READ = 0x03,
|
||||
INSTRUCTION_BITMOD = 0x05,
|
||||
INSTRUCTION_LOAD_TX0 = 0x40,
|
||||
INSTRUCTION_LOAD_TX1 = 0x42,
|
||||
INSTRUCTION_LOAD_TX2 = 0x44,
|
||||
INSTRUCTION_RTS_TX0 = 0x81,
|
||||
INSTRUCTION_RTS_TX1 = 0x82,
|
||||
INSTRUCTION_RTS_TX2 = 0x84,
|
||||
INSTRUCTION_RTS_ALL = 0x87,
|
||||
INSTRUCTION_READ_RX0 = 0x90,
|
||||
INSTRUCTION_READ_RX1 = 0x94,
|
||||
INSTRUCTION_READ_STATUS = 0xA0,
|
||||
INSTRUCTION_RX_STATUS = 0xB0,
|
||||
INSTRUCTION_RESET = 0xC0
|
||||
};
|
||||
|
||||
enum /*class*/ REGISTER : uint8_t {
|
||||
MCP_RXF0SIDH = 0x00,
|
||||
MCP_RXF0SIDL = 0x01,
|
||||
MCP_RXF0EID8 = 0x02,
|
||||
MCP_RXF0EID0 = 0x03,
|
||||
MCP_RXF1SIDH = 0x04,
|
||||
MCP_RXF1SIDL = 0x05,
|
||||
MCP_RXF1EID8 = 0x06,
|
||||
MCP_RXF1EID0 = 0x07,
|
||||
MCP_RXF2SIDH = 0x08,
|
||||
MCP_RXF2SIDL = 0x09,
|
||||
MCP_RXF2EID8 = 0x0A,
|
||||
MCP_RXF2EID0 = 0x0B,
|
||||
MCP_CANSTAT = 0x0E,
|
||||
MCP_CANCTRL = 0x0F,
|
||||
MCP_RXF3SIDH = 0x10,
|
||||
MCP_RXF3SIDL = 0x11,
|
||||
MCP_RXF3EID8 = 0x12,
|
||||
MCP_RXF3EID0 = 0x13,
|
||||
MCP_RXF4SIDH = 0x14,
|
||||
MCP_RXF4SIDL = 0x15,
|
||||
MCP_RXF4EID8 = 0x16,
|
||||
MCP_RXF4EID0 = 0x17,
|
||||
MCP_RXF5SIDH = 0x18,
|
||||
MCP_RXF5SIDL = 0x19,
|
||||
MCP_RXF5EID8 = 0x1A,
|
||||
MCP_RXF5EID0 = 0x1B,
|
||||
MCP_TEC = 0x1C,
|
||||
MCP_REC = 0x1D,
|
||||
MCP_RXM0SIDH = 0x20,
|
||||
MCP_RXM0SIDL = 0x21,
|
||||
MCP_RXM0EID8 = 0x22,
|
||||
MCP_RXM0EID0 = 0x23,
|
||||
MCP_RXM1SIDH = 0x24,
|
||||
MCP_RXM1SIDL = 0x25,
|
||||
MCP_RXM1EID8 = 0x26,
|
||||
MCP_RXM1EID0 = 0x27,
|
||||
MCP_CNF3 = 0x28,
|
||||
MCP_CNF2 = 0x29,
|
||||
MCP_CNF1 = 0x2A,
|
||||
MCP_CANINTE = 0x2B,
|
||||
MCP_CANINTF = 0x2C,
|
||||
MCP_EFLG = 0x2D,
|
||||
MCP_TXB0CTRL = 0x30,
|
||||
MCP_TXB0SIDH = 0x31,
|
||||
MCP_TXB0SIDL = 0x32,
|
||||
MCP_TXB0EID8 = 0x33,
|
||||
MCP_TXB0EID0 = 0x34,
|
||||
MCP_TXB0DLC = 0x35,
|
||||
MCP_TXB0DATA = 0x36,
|
||||
MCP_TXB1CTRL = 0x40,
|
||||
MCP_TXB1SIDH = 0x41,
|
||||
MCP_TXB1SIDL = 0x42,
|
||||
MCP_TXB1EID8 = 0x43,
|
||||
MCP_TXB1EID0 = 0x44,
|
||||
MCP_TXB1DLC = 0x45,
|
||||
MCP_TXB1DATA = 0x46,
|
||||
MCP_TXB2CTRL = 0x50,
|
||||
MCP_TXB2SIDH = 0x51,
|
||||
MCP_TXB2SIDL = 0x52,
|
||||
MCP_TXB2EID8 = 0x53,
|
||||
MCP_TXB2EID0 = 0x54,
|
||||
MCP_TXB2DLC = 0x55,
|
||||
MCP_TXB2DATA = 0x56,
|
||||
MCP_RXB0CTRL = 0x60,
|
||||
MCP_RXB0SIDH = 0x61,
|
||||
MCP_RXB0SIDL = 0x62,
|
||||
MCP_RXB0EID8 = 0x63,
|
||||
MCP_RXB0EID0 = 0x64,
|
||||
MCP_RXB0DLC = 0x65,
|
||||
MCP_RXB0DATA = 0x66,
|
||||
MCP_RXB1CTRL = 0x70,
|
||||
MCP_RXB1SIDH = 0x71,
|
||||
MCP_RXB1SIDL = 0x72,
|
||||
MCP_RXB1EID8 = 0x73,
|
||||
MCP_RXB1EID0 = 0x74,
|
||||
MCP_RXB1DLC = 0x75,
|
||||
MCP_RXB1DATA = 0x76
|
||||
};
|
||||
|
||||
static const uint32_t SPI_CLOCK = 10000000; // 10MHz
|
||||
|
||||
static const int N_TXBUFFERS = 3;
|
||||
static const int N_RXBUFFERS = 2;
|
||||
|
||||
static const struct TXBn_REGS {
|
||||
REGISTER CTRL;
|
||||
REGISTER SIDH;
|
||||
REGISTER DATA;
|
||||
} TXB[N_TXBUFFERS];
|
||||
|
||||
static const struct RXBn_REGS {
|
||||
REGISTER CTRL;
|
||||
REGISTER SIDH;
|
||||
REGISTER DATA;
|
||||
CANINTF CANINTF_RXnIF;
|
||||
} RXB[N_RXBUFFERS];
|
||||
|
||||
uint8_t SPICS;
|
||||
|
||||
private:
|
||||
|
||||
void startSPI();
|
||||
void endSPI();
|
||||
|
||||
ERROR setMode(const CANCTRL_REQOP_MODE mode);
|
||||
|
||||
uint8_t readRegister(const REGISTER reg);
|
||||
void readRegisters(const REGISTER reg, uint8_t values[], const uint8_t n);
|
||||
void setRegister(const REGISTER reg, const uint8_t value);
|
||||
void setRegisters(const REGISTER reg, const uint8_t values[], const uint8_t n);
|
||||
void modifyRegister(const REGISTER reg, const uint8_t mask, const uint8_t data);
|
||||
|
||||
void prepareId(uint8_t *buffer, const bool ext, const uint32_t id);
|
||||
|
||||
public:
|
||||
MCP2515(const uint8_t _CS);
|
||||
ERROR reset(void);
|
||||
ERROR setConfigMode();
|
||||
ERROR setListenOnlyMode();
|
||||
ERROR setSleepMode();
|
||||
ERROR setLoopbackMode();
|
||||
ERROR setNormalMode();
|
||||
ERROR setClkOut(const CAN_CLKOUT divisor);
|
||||
ERROR setBitrate(const CAN_SPEED canSpeed);
|
||||
ERROR setBitrate(const CAN_SPEED canSpeed, const CAN_CLOCK canClock);
|
||||
ERROR setFilterMask(const MASK num, const bool ext, const uint32_t ulData);
|
||||
ERROR setFilter(const RXF num, const bool ext, const uint32_t ulData);
|
||||
ERROR sendMessage(const TXBn txbn, const struct can_frame *frame);
|
||||
ERROR sendMessage(const struct can_frame *frame);
|
||||
ERROR readMessage(const RXBn rxbn, struct can_frame *frame);
|
||||
ERROR readMessage(struct can_frame *frame);
|
||||
bool checkReceive(void);
|
||||
bool checkError(void);
|
||||
uint8_t getErrorFlags(void);
|
||||
void clearRXnOVRFlags(void);
|
||||
uint8_t getInterrupts(void);
|
||||
uint8_t getInterruptMask(void);
|
||||
void clearInterrupts(void);
|
||||
void clearTXInterrupts(void);
|
||||
uint8_t getStatus(void);
|
||||
void clearRXnOVR(void);
|
||||
void clearMERR();
|
||||
void clearERRIF();
|
||||
uint8_t errorCountRX(void);
|
||||
uint8_t errorCountTX(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
40
libraries/ezButton/README.md
Normal file
40
libraries/ezButton/README.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
## ezButton Library for Arduino
|
||||
This library is designed to make it easy to use push button, momentary switches, toggle switch, magnetic contact switch (door sensor)... It is easy to use for not only beginners but also experienced users.
|
||||
|
||||
__ezButton__ stands for __Easy Button__
|
||||
|
||||
Features
|
||||
----------------------------
|
||||
* Uses the internal pull-up resistor to avoid the floating value
|
||||
* Supports debounce to eliminate the chattering phenomenon
|
||||
* Supports the pressed and released events
|
||||
* Supports the counting (for FALLING, RISING and BOTH)
|
||||
* Easy to use with multiple buttons
|
||||
* All functions are non-blocking
|
||||
|
||||
Available Examples
|
||||
----------------------------
|
||||
* [01.SingleButton](https://arduinogetstarted.com/library/button/example/arduino-single-button)
|
||||
* [02.SingleButtonEvents](https://arduinogetstarted.com/library/button/example/arduino-single-button-events)
|
||||
* [03.SingleButtonDebounce](https://arduinogetstarted.com/library/button/example/arduino-single-button-debounce)
|
||||
* [04.SingleButtonAll](https://arduinogetstarted.com/library/button/example/arduino-single-button-all)
|
||||
* [05.MultipleButtonAll](https://arduinogetstarted.com/library/button/example/arduino-multiple-button-all)
|
||||
* [06.ButtonCount](https://arduinogetstarted.com/library/button/example/arduino-button-count)
|
||||
* [07.ButtonArray](https://arduinogetstarted.com/library/button/example/arduino-button-array)
|
||||
|
||||
|
||||
Available Functions
|
||||
----------------------------
|
||||
* setDebounceTime()
|
||||
* getState()
|
||||
* getStateRaw()
|
||||
* isPressed()
|
||||
* isReleased()
|
||||
* setCountMode()
|
||||
* getCount()
|
||||
* resetCount()
|
||||
* loop()
|
||||
|
||||
References
|
||||
----------------------------
|
||||
* [ezButton Library Reference](https://arduinogetstarted.com/tutorials/arduino-button-library)
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Created by ArduinoGetStarted.com
|
||||
*
|
||||
* This example code is in the public domain
|
||||
*
|
||||
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-button-library
|
||||
*
|
||||
* This example reads the state of a button without debounce and print it to Serial Monitor.
|
||||
*/
|
||||
|
||||
#include <ezButton.h>
|
||||
|
||||
ezButton button(7); // create ezButton object that attach to pin 7;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
button.loop(); // MUST call the loop() function first
|
||||
|
||||
int btnState = button.getState();
|
||||
Serial.println(btnState);
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Created by ArduinoGetStarted.com
|
||||
*
|
||||
* This example code is in the public domain
|
||||
*
|
||||
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-button-library
|
||||
*
|
||||
* This example detects the pressed and released events of a button without debounce.
|
||||
*/
|
||||
|
||||
#include <ezButton.h>
|
||||
|
||||
ezButton button(7); // create ezButton object that attach to pin 7;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
button.loop(); // MUST call the loop() function first
|
||||
|
||||
if(button.isPressed())
|
||||
Serial.println("The button is pressed");
|
||||
|
||||
if(button.isReleased())
|
||||
Serial.println("The button is released");
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Created by ArduinoGetStarted.com
|
||||
*
|
||||
* This example code is in the public domain
|
||||
*
|
||||
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-button-library
|
||||
*
|
||||
* This example reads the state of a button with debounce and print it to Serial Monitor.
|
||||
*/
|
||||
|
||||
#include <ezButton.h>
|
||||
|
||||
ezButton button(7); // create ezButton object that attach to pin 7;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
button.setDebounceTime(50); // set debounce time to 50 milliseconds
|
||||
}
|
||||
|
||||
void loop() {
|
||||
button.loop(); // MUST call the loop() function first
|
||||
|
||||
if(button.isPressed())
|
||||
Serial.println("The button is pressed");
|
||||
|
||||
if(button.isReleased())
|
||||
Serial.println("The button is released");
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Created by ArduinoGetStarted.com
|
||||
*
|
||||
* This example code is in the public domain
|
||||
*
|
||||
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-button-library
|
||||
*
|
||||
* This example:
|
||||
* + uses debounce for a button.
|
||||
* + reads state of a button
|
||||
* + detects the pressed and released events of a button
|
||||
*/
|
||||
|
||||
#include <ezButton.h>
|
||||
|
||||
ezButton button(7); // create ezButton object that attach to pin 7;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
button.setDebounceTime(50); // set debounce time to 50 milliseconds
|
||||
}
|
||||
|
||||
void loop() {
|
||||
button.loop(); // MUST call the loop() function first
|
||||
|
||||
int btnState = button.getState();
|
||||
Serial.println(btnState);
|
||||
|
||||
if(button.isPressed())
|
||||
Serial.println("The button is pressed");
|
||||
|
||||
if(button.isReleased())
|
||||
Serial.println("The button is released");
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Created by ArduinoGetStarted.com
|
||||
*
|
||||
* This example code is in the public domain
|
||||
*
|
||||
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-button-library
|
||||
*
|
||||
* This example:
|
||||
* + uses debounce for multiple buttons.
|
||||
* + reads state of multiple buttons
|
||||
* + detects the pressed and released events of multiple buttons
|
||||
*/
|
||||
|
||||
#include <ezButton.h>
|
||||
|
||||
ezButton button1(6); // create ezButton object that attach to pin 6;
|
||||
ezButton button2(7); // create ezButton object that attach to pin 7;
|
||||
ezButton button3(8); // create ezButton object that attach to pin 8;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
button1.setDebounceTime(50); // set debounce time to 50 milliseconds
|
||||
button2.setDebounceTime(50); // set debounce time to 50 milliseconds
|
||||
button3.setDebounceTime(50); // set debounce time to 50 milliseconds
|
||||
}
|
||||
|
||||
void loop() {
|
||||
button1.loop(); // MUST call the loop() function first
|
||||
button2.loop(); // MUST call the loop() function first
|
||||
button3.loop(); // MUST call the loop() function first
|
||||
|
||||
int btn1State = button1.getState();
|
||||
int btn2State = button2.getState();
|
||||
int btn3State = button3.getState();
|
||||
Serial.print("button 1 state: ");
|
||||
Serial.println(btn1State);
|
||||
Serial.print("button 2 state: ");
|
||||
Serial.println(btn2State);
|
||||
Serial.print("button 3 state: ");
|
||||
Serial.println(btn3State);
|
||||
|
||||
if(button1.isPressed())
|
||||
Serial.println("The button 1 is pressed");
|
||||
|
||||
if(button1.isReleased())
|
||||
Serial.println("The button 1 is released");
|
||||
|
||||
if(button2.isPressed())
|
||||
Serial.println("The button 2 is pressed");
|
||||
|
||||
if(button2.isReleased())
|
||||
Serial.println("The button 2 is released");
|
||||
|
||||
if(button3.isPressed())
|
||||
Serial.println("The button 3 is pressed");
|
||||
|
||||
if(button3.isReleased())
|
||||
Serial.println("The button 3 is released");
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Created by ArduinoGetStarted.com
|
||||
*
|
||||
* This example code is in the public domain
|
||||
*
|
||||
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-button-library
|
||||
*
|
||||
* This example reads the number of the pressed count of a button with debounce and print it to Serial Monitor.
|
||||
*/
|
||||
|
||||
#include <ezButton.h>
|
||||
|
||||
ezButton button(7); // create ezButton object that attach to pin 7;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
button.setDebounceTime(50); // set debounce time to 50 milliseconds
|
||||
button.setCountMode(COUNT_FALLING);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
button.loop(); // MUST call the loop() function first
|
||||
|
||||
unsigned long count = button.getCount();
|
||||
Serial.println(count);
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Created by ArduinoGetStarted.com
|
||||
*
|
||||
* This example code is in the public domain
|
||||
*
|
||||
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-button-library
|
||||
*
|
||||
* This example shows how to use array of button.
|
||||
*/
|
||||
|
||||
#include <ezButton.h>
|
||||
|
||||
const int BUTTON_NUM = 5;
|
||||
|
||||
const int BUTTON_1_PIN = 2;
|
||||
const int BUTTON_2_PIN = 3;
|
||||
const int BUTTON_3_PIN = 4;
|
||||
const int BUTTON_4_PIN = 5;
|
||||
const int BUTTON_5_PIN = 6;
|
||||
|
||||
ezButton buttonArray[] = {
|
||||
ezButton(BUTTON_1_PIN),
|
||||
ezButton(BUTTON_2_PIN),
|
||||
ezButton(BUTTON_3_PIN),
|
||||
ezButton(BUTTON_4_PIN),
|
||||
ezButton(BUTTON_5_PIN)
|
||||
};
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
for (byte i = 0; i < BUTTON_NUM; i++) {
|
||||
buttonArray[i].setDebounceTime(50); // set debounce time to 50 milliseconds
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
for (byte i = 0; i < BUTTON_NUM; i++)
|
||||
buttonArray[i].loop(); // MUST call the loop() function first
|
||||
|
||||
for (byte i = 0; i < BUTTON_NUM; i++) {
|
||||
if (buttonArray[i].isPressed()) {
|
||||
Serial.print("The button ");
|
||||
Serial.print(i + 1);
|
||||
Serial.println(" is pressed");
|
||||
}
|
||||
|
||||
if (buttonArray[i].isReleased()) {
|
||||
Serial.print("The button ");
|
||||
Serial.print(i + 1);
|
||||
Serial.println(" is released");
|
||||
}
|
||||
}
|
||||
}
|
||||
31
libraries/ezButton/keywords.txt
Normal file
31
libraries/ezButton/keywords.txt
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For ezButton
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
ezButton KEYWORD1
|
||||
button KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
setDebounceTime KEYWORD2
|
||||
getState KEYWORD2
|
||||
getStateRaw KEYWORD2
|
||||
isPressed KEYWORD2
|
||||
isReleased KEYWORD2
|
||||
setCountMode KEYWORD2
|
||||
getCount KEYWORD2
|
||||
resetCount KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
COUNT_FALLING LITERAL1
|
||||
COUNT_RISING LITERAL1
|
||||
COUNT_BOTH LITERAL1
|
||||
10
libraries/ezButton/library.properties
Normal file
10
libraries/ezButton/library.properties
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
name=ezButton
|
||||
version=1.0.4
|
||||
author=ArduinoGetStarted.com
|
||||
maintainer=ArduinoGetStarted.com (ArduinoGetStarted@gmail.com)
|
||||
sentence=Button library for Arduino
|
||||
paragraph=Button library supports debounce, pressed/released events and the press counting. It is easy to use with multiple buttons. The library can be used for push-button, momentary switches, toggle switch, magnetic contact switch (door sensor)... It is designed for not only beginners but also experienced users.
|
||||
category=Signal Input/Output
|
||||
url=https://arduinogetstarted.com/tutorials/arduino-button-library
|
||||
architectures=*
|
||||
includes=ezButton.h
|
||||
127
libraries/ezButton/src/ezButton.cpp
Normal file
127
libraries/ezButton/src/ezButton.cpp
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2019, ArduinoGetStarted.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of the ArduinoGetStarted.com nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ARDUINOGETSTARTED.COM "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ARDUINOGETSTARTED.COM BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <ezButton.h>
|
||||
|
||||
ezButton::ezButton(int pin): ezButton(pin, INPUT_PULLUP) {};
|
||||
|
||||
ezButton::ezButton(int pin, int mode) {
|
||||
btnPin = pin;
|
||||
debounceTime = 0;
|
||||
count = 0;
|
||||
countMode = COUNT_FALLING;
|
||||
|
||||
pinMode(btnPin, mode);
|
||||
|
||||
previousSteadyState = digitalRead(btnPin);
|
||||
lastSteadyState = previousSteadyState;
|
||||
lastFlickerableState = previousSteadyState;
|
||||
|
||||
lastDebounceTime = 0;
|
||||
}
|
||||
|
||||
void ezButton::setDebounceTime(unsigned long time) {
|
||||
debounceTime = time;
|
||||
}
|
||||
|
||||
int ezButton::getState(void) {
|
||||
return lastSteadyState;
|
||||
}
|
||||
|
||||
int ezButton::getStateRaw(void) {
|
||||
return digitalRead(btnPin);
|
||||
}
|
||||
|
||||
bool ezButton::isPressed(void) {
|
||||
if(previousSteadyState == HIGH && lastSteadyState == LOW)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ezButton::isReleased(void) {
|
||||
if(previousSteadyState == LOW && lastSteadyState == HIGH)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void ezButton::setCountMode(int mode) {
|
||||
countMode = mode;
|
||||
}
|
||||
|
||||
unsigned long ezButton::getCount(void) {
|
||||
return count;
|
||||
}
|
||||
|
||||
void ezButton::resetCount(void) {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
void ezButton::loop(void) {
|
||||
// read the state of the switch/button:
|
||||
int currentState = digitalRead(btnPin);
|
||||
unsigned long currentTime = millis();
|
||||
|
||||
// check to see if you just pressed the button
|
||||
// (i.e. the input went from LOW to HIGH), and you've waited long enough
|
||||
// since the last press to ignore any noise:
|
||||
|
||||
// If the switch/button changed, due to noise or pressing:
|
||||
if (currentState != lastFlickerableState) {
|
||||
// reset the debouncing timer
|
||||
lastDebounceTime = currentTime;
|
||||
// save the the last flickerable state
|
||||
lastFlickerableState = currentState;
|
||||
}
|
||||
|
||||
if ((currentTime - lastDebounceTime) >= debounceTime) {
|
||||
// whatever the reading is at, it's been there for longer than the debounce
|
||||
// delay, so take it as the actual current state:
|
||||
|
||||
// save the the steady state
|
||||
previousSteadyState = lastSteadyState;
|
||||
lastSteadyState = currentState;
|
||||
}
|
||||
|
||||
if(previousSteadyState != lastSteadyState){
|
||||
if(countMode == COUNT_BOTH)
|
||||
count++;
|
||||
else if(countMode == COUNT_FALLING){
|
||||
if(previousSteadyState == HIGH && lastSteadyState == LOW)
|
||||
count++;
|
||||
}
|
||||
else if(countMode == COUNT_RISING){
|
||||
if(previousSteadyState == LOW && lastSteadyState == HIGH)
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
69
libraries/ezButton/src/ezButton.h
Normal file
69
libraries/ezButton/src/ezButton.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2019, ArduinoGetStarted.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of the ArduinoGetStarted.com nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ARDUINOGETSTARTED.COM "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ARDUINOGETSTARTED.COM BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef ezButton_h
|
||||
#define ezButton_h
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define COUNT_FALLING 0
|
||||
#define COUNT_RISING 1
|
||||
#define COUNT_BOTH 2
|
||||
|
||||
class ezButton
|
||||
{
|
||||
private:
|
||||
int btnPin;
|
||||
unsigned long debounceTime;
|
||||
unsigned long count;
|
||||
int countMode;
|
||||
|
||||
int previousSteadyState; // the previous steady state from the input pin, used to detect pressed and released event
|
||||
int lastSteadyState; // the last steady state from the input pin
|
||||
int lastFlickerableState; // the last flickerable state from the input pin
|
||||
|
||||
unsigned long lastDebounceTime; // the last time the output pin was toggled
|
||||
|
||||
public:
|
||||
ezButton(int pin);
|
||||
ezButton(int pin, int mode);
|
||||
void setDebounceTime(unsigned long time);
|
||||
int getState(void);
|
||||
int getStateRaw(void);
|
||||
bool isPressed(void);
|
||||
bool isReleased(void);
|
||||
void setCountMode(int mode);
|
||||
unsigned long getCount(void);
|
||||
void resetCount(void);
|
||||
void loop(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
492
libraries/modSoftSerial/modSoftwareSerial.cpp
Normal file
492
libraries/modSoftSerial/modSoftwareSerial.cpp
Normal file
|
|
@ -0,0 +1,492 @@
|
|||
/*
|
||||
modSoftwareSerial.cpp (formerly NewSoftSerial.cpp) -
|
||||
Multi-instance software serial library for Arduino/Wiring
|
||||
-- Interrupt-driven receive and other improvements by ladyada
|
||||
(http://ladyada.net)
|
||||
-- Tuning, circular buffer, derivation from class Print/Stream,
|
||||
multi-instance support, porting to 8MHz processors,
|
||||
various optimizations, PROGMEM delay tables, inverse logic and
|
||||
direct port writing by Mikal Hart (http://www.arduiniana.org)
|
||||
-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
|
||||
-- 20MHz processor support by Garrett Mace (http://www.macetech.com)
|
||||
-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
|
||||
|
||||
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
|
||||
|
||||
The latest version of this library can always be found at
|
||||
http://arduiniana.org.
|
||||
*/
|
||||
|
||||
// When set, _DEBUG co-opts pins 11 and 13 for debugging with an
|
||||
// oscilloscope or logic analyzer. Beware: it also slightly modifies
|
||||
// the bit times, so don't rely on it too much at high baud rates
|
||||
#define _DEBUG 0
|
||||
#define _DEBUG_PIN1 11
|
||||
#define _DEBUG_PIN2 13
|
||||
//
|
||||
// Includes
|
||||
//
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "Arduino.h"
|
||||
#include "modSoftwareSerial.h"
|
||||
//
|
||||
// Lookup table
|
||||
//
|
||||
typedef struct _DELAY_TABLE
|
||||
{
|
||||
long baud;
|
||||
unsigned short rx_delay_centering;
|
||||
unsigned short rx_delay_intrabit;
|
||||
unsigned short rx_delay_stopbit;
|
||||
unsigned short tx_delay;
|
||||
} DELAY_TABLE;
|
||||
|
||||
#if F_CPU == 16000000
|
||||
|
||||
static const DELAY_TABLE PROGMEM table[] =
|
||||
{
|
||||
// baud rxcenter rxintra rxstop tx
|
||||
{ 115200, 1, 17, 17, 12, },
|
||||
{ 57600, 10, 37, 37, 33, },
|
||||
{ 38400, 25, 57, 57, 54, },
|
||||
{ 31250, 31, 70, 70, 68, },
|
||||
{ 28800, 34, 77, 77, 74, },
|
||||
{ 19200, 54, 117, 117, 114, },
|
||||
{ 14400, 74, 156, 156, 153, },
|
||||
{ 9600, 114, 236, 236, 233, },
|
||||
{ 4800, 233, 474, 474, 471, },
|
||||
{ 2400, 471, 950, 950, 947, },
|
||||
{ 1200, 947, 1902, 1902, 1899, },
|
||||
{ 300, 3804, 7617, 7617, 7614, },
|
||||
};
|
||||
|
||||
const int XMIT_START_ADJUSTMENT = 5;
|
||||
|
||||
#elif F_CPU == 8000000
|
||||
|
||||
static const DELAY_TABLE table[] PROGMEM =
|
||||
{
|
||||
// baud rxcenter rxintra rxstop tx
|
||||
{ 115200, 1, 5, 5, 3, },
|
||||
{ 57600, 1, 15, 15, 13, },
|
||||
{ 38400, 2, 25, 26, 23, },
|
||||
{ 31250, 7, 32, 33, 29, },
|
||||
{ 28800, 11, 35, 35, 32, },
|
||||
{ 19200, 20, 55, 55, 52, },
|
||||
{ 14400, 30, 75, 75, 72, },
|
||||
{ 9600, 50, 114, 114, 112, },
|
||||
{ 4800, 110, 233, 233, 230, },
|
||||
{ 2400, 229, 472, 472, 469, },
|
||||
{ 1200, 467, 948, 948, 945, },
|
||||
{ 300, 1895, 3805, 3805, 3802, },
|
||||
};
|
||||
|
||||
const int XMIT_START_ADJUSTMENT = 4;
|
||||
|
||||
#elif F_CPU == 20000000
|
||||
|
||||
// 20MHz support courtesy of the good people at macegr.com.
|
||||
// Thanks, Garrett!
|
||||
|
||||
static const DELAY_TABLE PROGMEM table[] =
|
||||
{
|
||||
// baud rxcenter rxintra rxstop tx
|
||||
{ 115200, 3, 21, 21, 18, },
|
||||
{ 57600, 20, 43, 43, 41, },
|
||||
{ 38400, 37, 73, 73, 70, },
|
||||
{ 31250, 45, 89, 89, 88, },
|
||||
{ 28800, 46, 98, 98, 95, },
|
||||
{ 19200, 71, 148, 148, 145, },
|
||||
{ 14400, 96, 197, 197, 194, },
|
||||
{ 9600, 146, 297, 297, 294, },
|
||||
{ 4800, 296, 595, 595, 592, },
|
||||
{ 2400, 592, 1189, 1189, 1186, },
|
||||
{ 1200, 1187, 2379, 2379, 2376, },
|
||||
{ 300, 4759, 9523, 9523, 9520, },
|
||||
};
|
||||
|
||||
const int XMIT_START_ADJUSTMENT = 6;
|
||||
|
||||
#else
|
||||
|
||||
#error This version of modSoftwareSerial supports only 20, 16 and 8MHz processors
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// Statics
|
||||
//
|
||||
modSoftwareSerial *modSoftwareSerial::active_object = 0;
|
||||
char modSoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF];
|
||||
volatile uint8_t modSoftwareSerial::_receive_buffer_tail = 0;
|
||||
volatile uint8_t modSoftwareSerial::_receive_buffer_head = 0;
|
||||
|
||||
//
|
||||
// Debugging
|
||||
//
|
||||
// This function generates a brief pulse
|
||||
// for debugging or measuring on an oscilloscope.
|
||||
inline void DebugPulse(uint8_t pin, uint8_t count)
|
||||
{
|
||||
#if _DEBUG
|
||||
volatile uint8_t *pport = portOutputRegister(digitalPinToPort(pin));
|
||||
|
||||
uint8_t val = *pport;
|
||||
while (count--)
|
||||
{
|
||||
*pport = val | digitalPinToBitMask(pin);
|
||||
*pport = val;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Private methods
|
||||
//
|
||||
|
||||
/* static */
|
||||
inline void modSoftwareSerial::tunedDelay(uint16_t delay) {
|
||||
uint8_t tmp=0;
|
||||
|
||||
asm volatile("sbiw %0, 0x01 \n\t"
|
||||
"ldi %1, 0xFF \n\t"
|
||||
"cpi %A0, 0xFF \n\t"
|
||||
"cpc %B0, %1 \n\t"
|
||||
"brne .-10 \n\t"
|
||||
: "+r" (delay), "+a" (tmp)
|
||||
: "0" (delay)
|
||||
);
|
||||
}
|
||||
|
||||
// This function sets the current object as the "listening"
|
||||
// one and returns true if it replaces another
|
||||
bool modSoftwareSerial::listen()
|
||||
{
|
||||
if (active_object != this)
|
||||
{
|
||||
_buffer_overflow = false;
|
||||
uint8_t oldSREG = SREG;
|
||||
cli();
|
||||
_receive_buffer_head = _receive_buffer_tail = 0;
|
||||
active_object = this;
|
||||
SREG = oldSREG;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// The receive routine called by the interrupt handler
|
||||
//
|
||||
void modSoftwareSerial::recv()
|
||||
{
|
||||
|
||||
#if GCC_VERSION < 40302
|
||||
// Work-around for avr-gcc 4.3.0 OSX version bug
|
||||
// Preserve the registers that the compiler misses
|
||||
// (courtesy of Arduino forum user *etracer*)
|
||||
asm volatile(
|
||||
"push r18 \n\t"
|
||||
"push r19 \n\t"
|
||||
"push r20 \n\t"
|
||||
"push r21 \n\t"
|
||||
"push r22 \n\t"
|
||||
"push r23 \n\t"
|
||||
"push r26 \n\t"
|
||||
"push r27 \n\t"
|
||||
::);
|
||||
#endif
|
||||
|
||||
uint8_t d = 0;
|
||||
|
||||
// If RX line is high, then we don't see any start bit
|
||||
// so interrupt is probably not for us
|
||||
if (_inverse_logic ? rx_pin_read() : !rx_pin_read())
|
||||
{
|
||||
// Wait approximately 1/2 of a bit width to "center" the sample
|
||||
tunedDelay(_rx_delay_centering);
|
||||
DebugPulse(_DEBUG_PIN2, 1);
|
||||
|
||||
// Read each of the 8 bits
|
||||
for (uint8_t i=0x1; i; i <<= 1)
|
||||
{
|
||||
tunedDelay(_rx_delay_intrabit);
|
||||
DebugPulse(_DEBUG_PIN2, 1);
|
||||
uint8_t noti = ~i;
|
||||
if (rx_pin_read())
|
||||
d |= i;
|
||||
else // else clause added to ensure function timing is ~balanced
|
||||
d &= noti;
|
||||
}
|
||||
|
||||
// skip the stop bit
|
||||
tunedDelay(_rx_delay_stopbit);
|
||||
DebugPulse(_DEBUG_PIN2, 1);
|
||||
|
||||
if (_inverse_logic)
|
||||
d = ~d;
|
||||
|
||||
// if buffer full, set the overflow flag and return
|
||||
if ((_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF != _receive_buffer_head)
|
||||
{
|
||||
// save new data in buffer: tail points to where byte goes
|
||||
_receive_buffer[_receive_buffer_tail] = d; // save new byte
|
||||
_receive_buffer_tail = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if _DEBUG // for scope: pulse pin as overflow indictator
|
||||
DebugPulse(_DEBUG_PIN1, 1);
|
||||
#endif
|
||||
_buffer_overflow = true;
|
||||
}
|
||||
}
|
||||
|
||||
#if GCC_VERSION < 40302
|
||||
// Work-around for avr-gcc 4.3.0 OSX version bug
|
||||
// Restore the registers that the compiler misses
|
||||
asm volatile(
|
||||
"pop r27 \n\t"
|
||||
"pop r26 \n\t"
|
||||
"pop r23 \n\t"
|
||||
"pop r22 \n\t"
|
||||
"pop r21 \n\t"
|
||||
"pop r20 \n\t"
|
||||
"pop r19 \n\t"
|
||||
"pop r18 \n\t"
|
||||
::);
|
||||
#endif
|
||||
}
|
||||
|
||||
void modSoftwareSerial::tx_pin_write(uint8_t pin_state)
|
||||
{
|
||||
if (pin_state == LOW)
|
||||
*_transmitPortRegister &= ~_transmitBitMask;
|
||||
else
|
||||
*_transmitPortRegister |= _transmitBitMask;
|
||||
}
|
||||
|
||||
uint8_t modSoftwareSerial::rx_pin_read()
|
||||
{
|
||||
return *_receivePortRegister & _receiveBitMask;
|
||||
}
|
||||
|
||||
//
|
||||
// Interrupt handling
|
||||
//
|
||||
|
||||
/* static */
|
||||
inline void modSoftwareSerial::handle_interrupt()
|
||||
{
|
||||
if (active_object)
|
||||
{
|
||||
active_object->recv();
|
||||
}
|
||||
}
|
||||
|
||||
ISR(PCINT2_vect)
|
||||
{
|
||||
modSoftwareSerial::handle_interrupt();
|
||||
}
|
||||
|
||||
//
|
||||
// Constructor
|
||||
//
|
||||
modSoftwareSerial::modSoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */) :
|
||||
_rx_delay_centering(0),
|
||||
_rx_delay_intrabit(0),
|
||||
_rx_delay_stopbit(0),
|
||||
_tx_delay(0),
|
||||
_buffer_overflow(false),
|
||||
_inverse_logic(inverse_logic)
|
||||
{
|
||||
setTX(transmitPin);
|
||||
setRX(receivePin);
|
||||
}
|
||||
|
||||
//
|
||||
// Destructor
|
||||
//
|
||||
modSoftwareSerial::~modSoftwareSerial()
|
||||
{
|
||||
end();
|
||||
}
|
||||
|
||||
void modSoftwareSerial::setTX(uint8_t tx)
|
||||
{
|
||||
pinMode(tx, OUTPUT);
|
||||
digitalWrite(tx, HIGH);
|
||||
_transmitBitMask = digitalPinToBitMask(tx);
|
||||
uint8_t port = digitalPinToPort(tx);
|
||||
_transmitPortRegister = portOutputRegister(port);
|
||||
}
|
||||
|
||||
void modSoftwareSerial::setRX(uint8_t rx)
|
||||
{
|
||||
pinMode(rx, INPUT);
|
||||
if (!_inverse_logic)
|
||||
digitalWrite(rx, HIGH); // pullup for normal logic!
|
||||
_receivePin = rx;
|
||||
_receiveBitMask = digitalPinToBitMask(rx);
|
||||
uint8_t port = digitalPinToPort(rx);
|
||||
_receivePortRegister = portInputRegister(port);
|
||||
}
|
||||
|
||||
//
|
||||
// Public methods
|
||||
//
|
||||
|
||||
void modSoftwareSerial::begin(long speed)
|
||||
{
|
||||
_rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0;
|
||||
|
||||
for (unsigned i=0; i<sizeof(table)/sizeof(table[0]); ++i)
|
||||
{
|
||||
long baud = pgm_read_dword(&table[i].baud);
|
||||
if (baud == speed)
|
||||
{
|
||||
_rx_delay_centering = pgm_read_word(&table[i].rx_delay_centering);
|
||||
_rx_delay_intrabit = pgm_read_word(&table[i].rx_delay_intrabit);
|
||||
_rx_delay_stopbit = pgm_read_word(&table[i].rx_delay_stopbit);
|
||||
_tx_delay = pgm_read_word(&table[i].tx_delay);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up RX interrupts, but only if we have a valid RX baud rate
|
||||
if (_rx_delay_stopbit)
|
||||
{
|
||||
if (digitalPinToPCICR(_receivePin))
|
||||
{
|
||||
*digitalPinToPCICR(_receivePin) |= _BV(digitalPinToPCICRbit(_receivePin));
|
||||
*digitalPinToPCMSK(_receivePin) |= _BV(digitalPinToPCMSKbit(_receivePin));
|
||||
}
|
||||
tunedDelay(_tx_delay); // if we were low this establishes the end
|
||||
}
|
||||
|
||||
#if _DEBUG
|
||||
pinMode(_DEBUG_PIN1, OUTPUT);
|
||||
pinMode(_DEBUG_PIN2, OUTPUT);
|
||||
#endif
|
||||
|
||||
listen();
|
||||
}
|
||||
|
||||
void modSoftwareSerial::end()
|
||||
{
|
||||
if (digitalPinToPCMSK(_receivePin))
|
||||
*digitalPinToPCMSK(_receivePin) &= ~_BV(digitalPinToPCMSKbit(_receivePin));
|
||||
}
|
||||
|
||||
|
||||
// Read data from buffer
|
||||
int modSoftwareSerial::read()
|
||||
{
|
||||
if (!isListening())
|
||||
return -1;
|
||||
|
||||
// Empty buffer?
|
||||
if (_receive_buffer_head == _receive_buffer_tail)
|
||||
return -1;
|
||||
|
||||
// Read from "head"
|
||||
uint8_t d = _receive_buffer[_receive_buffer_head]; // grab next byte
|
||||
_receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF;
|
||||
return d;
|
||||
}
|
||||
|
||||
int modSoftwareSerial::available()
|
||||
{
|
||||
if (!isListening())
|
||||
return 0;
|
||||
|
||||
return (_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head) % _SS_MAX_RX_BUFF;
|
||||
}
|
||||
|
||||
size_t modSoftwareSerial::write(uint8_t b)
|
||||
{
|
||||
if (_tx_delay == 0) {
|
||||
setWriteError();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t oldSREG = SREG;
|
||||
cli(); // turn off interrupts for a clean txmit
|
||||
|
||||
// Write the start bit
|
||||
tx_pin_write(_inverse_logic ? HIGH : LOW);
|
||||
tunedDelay(_tx_delay + XMIT_START_ADJUSTMENT);
|
||||
|
||||
// Write each of the 8 bits
|
||||
if (_inverse_logic)
|
||||
{
|
||||
for (byte mask = 0x01; mask; mask <<= 1)
|
||||
{
|
||||
if (b & mask) // choose bit
|
||||
tx_pin_write(LOW); // send 1
|
||||
else
|
||||
tx_pin_write(HIGH); // send 0
|
||||
|
||||
tunedDelay(_tx_delay);
|
||||
}
|
||||
|
||||
tx_pin_write(LOW); // restore pin to natural state
|
||||
}
|
||||
else
|
||||
{
|
||||
for (byte mask = 0x01; mask; mask <<= 1)
|
||||
{
|
||||
if (b & mask) // choose bit
|
||||
tx_pin_write(HIGH); // send 1
|
||||
else
|
||||
tx_pin_write(LOW); // send 0
|
||||
|
||||
tunedDelay(_tx_delay);
|
||||
}
|
||||
|
||||
tx_pin_write(HIGH); // restore pin to natural state
|
||||
}
|
||||
|
||||
SREG = oldSREG; // turn interrupts back on
|
||||
tunedDelay(_tx_delay);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void modSoftwareSerial::flush()
|
||||
{
|
||||
if (!isListening())
|
||||
return;
|
||||
|
||||
uint8_t oldSREG = SREG;
|
||||
cli();
|
||||
_receive_buffer_head = _receive_buffer_tail = 0;
|
||||
SREG = oldSREG;
|
||||
}
|
||||
|
||||
int modSoftwareSerial::peek()
|
||||
{
|
||||
if (!isListening())
|
||||
return -1;
|
||||
|
||||
// Empty buffer?
|
||||
if (_receive_buffer_head == _receive_buffer_tail)
|
||||
return -1;
|
||||
|
||||
// Read from "head"
|
||||
return _receive_buffer[_receive_buffer_head];
|
||||
}
|
||||
112
libraries/modSoftSerial/modSoftwareSerial.h
Normal file
112
libraries/modSoftSerial/modSoftwareSerial.h
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
SoftwareSerial.h (formerly NewSoftSerial.h) -
|
||||
Multi-instance software serial library for Arduino/Wiring
|
||||
-- Interrupt-driven receive and other improvements by ladyada
|
||||
(http://ladyada.net)
|
||||
-- Tuning, circular buffer, derivation from class Print/Stream,
|
||||
multi-instance support, porting to 8MHz processors,
|
||||
various optimizations, PROGMEM delay tables, inverse logic and
|
||||
direct port writing by Mikal Hart (http://www.arduiniana.org)
|
||||
-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
|
||||
-- 20MHz processor support by Garrett Mace (http://www.macetech.com)
|
||||
-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
|
||||
|
||||
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
|
||||
|
||||
The latest version of this library can always be found at
|
||||
http://arduiniana.org.
|
||||
*/
|
||||
|
||||
#ifndef SoftwareSerial_h
|
||||
#define SoftwareSerial_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <Stream.h>
|
||||
|
||||
/******************************************************************************
|
||||
* Definitions
|
||||
******************************************************************************/
|
||||
|
||||
#define _SS_MAX_RX_BUFF 64 // RX buffer size
|
||||
#ifndef GCC_VERSION
|
||||
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||||
#endif
|
||||
|
||||
class modSoftwareSerial : public Stream
|
||||
{
|
||||
private:
|
||||
// per object data
|
||||
uint8_t _receivePin;
|
||||
uint8_t _receiveBitMask;
|
||||
volatile uint8_t *_receivePortRegister;
|
||||
uint8_t _transmitBitMask;
|
||||
volatile uint8_t *_transmitPortRegister;
|
||||
|
||||
uint16_t _rx_delay_centering;
|
||||
uint16_t _rx_delay_intrabit;
|
||||
uint16_t _rx_delay_stopbit;
|
||||
uint16_t _tx_delay;
|
||||
|
||||
uint16_t _buffer_overflow:1;
|
||||
uint16_t _inverse_logic:1;
|
||||
|
||||
// static data
|
||||
static char _receive_buffer[_SS_MAX_RX_BUFF];
|
||||
static volatile uint8_t _receive_buffer_tail;
|
||||
static volatile uint8_t _receive_buffer_head;
|
||||
static modSoftwareSerial *active_object;
|
||||
|
||||
// private methods
|
||||
void recv();
|
||||
uint8_t rx_pin_read();
|
||||
void tx_pin_write(uint8_t pin_state);
|
||||
void setTX(uint8_t transmitPin);
|
||||
void setRX(uint8_t receivePin);
|
||||
|
||||
// private static method for timing
|
||||
static inline void tunedDelay(uint16_t delay);
|
||||
|
||||
public:
|
||||
// public methods
|
||||
modSoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false);
|
||||
~modSoftwareSerial();
|
||||
void begin(long speed);
|
||||
bool listen();
|
||||
void end();
|
||||
bool isListening() { return this == active_object; }
|
||||
bool overflow() { bool ret = _buffer_overflow; _buffer_overflow = false; return ret; }
|
||||
int peek();
|
||||
|
||||
virtual size_t write(uint8_t byte);
|
||||
virtual int read();
|
||||
virtual int available();
|
||||
virtual void flush();
|
||||
|
||||
using Print::write;
|
||||
|
||||
// public only for easy access by interrupt handlers
|
||||
static inline void handle_interrupt();
|
||||
};
|
||||
|
||||
// Arduino 0012 workaround
|
||||
#undef int
|
||||
#undef char
|
||||
#undef long
|
||||
#undef byte
|
||||
#undef float
|
||||
#undef abs
|
||||
#undef round
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue