Guten Abend!
Beim warten auf die Sammelbestellung fuchse ich mich gerade in das Setup der IDE, die Sketches, die Platinen etc. rein.
Momentan habe ich das Problem, dass unter der Arduino-IDE 1.6.0 und Arduino-tiny (1.5) die SoftwareSerial Library nicht verfügbar ist. Ich bekomme diese Fehlermeldung, sobald ich diese include:
fatal error: SoftwareSerial.h: No such file or directory
compilation terminated.
Error compiling.
Leider nur, wenn ich den ATtiny84 als Board auswähle. Wähle ich zum Beispiel den Arduino Uno aus, gehts. Kennt jemand das Problem und die Lösung dafür? Als Workaround habe ich aus dem Arduino-IDE-Program-Pfad die SoftwareSerial Library in mein Sketchbook kopiert. Dann klappt das Kompilieren. Aus Ermangelung an TinyTX-Hardware kann ich leider nicht versuchen ob es auch WIRKLICH funktioniert:-(
Versucht habe ich es unter Debian-Linux und auf dem Mac. Bei beiden das gleiche Verhalten.
Ich habe aber etwas gebastelt und würde mich freuen, wenn das mal jemand versuchen könnte: Ich habe versucht, die aktuelle RF12Demo für das TinyRX4 Board anzupassen. Der Sketch müsste mit 8,134 bytes GERADE SO auf den Attiny84 passen.
Möchte das mal jemand probieren - würde sooo gerne selbst ran...
/// @dir RF12demo
/// Configure some values in EEPROM for easy config of the RF12 later on.
// 2009-05-06 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
// this version adds flash memory support, 2009-11-19
// Adding frequency features, author JohnO, 2013-09-05
// Major EEPROM format change, refactoring, and cleanup for v12, 2014-02-13
// this version is aimed for TinyRX4-board, uses SoftwareSerial, optimized for space of Attiny84, author stahlfabrik, 2014-03-02
#include <SoftwareSerial.h>
#include <JeeLib.h>
#include <util/crc16.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include <util/parity.h>
#define rxPin 7 // D7, PA3
#define txPin 3 // D3, PA7
#define SERIAL_BAUD 9600
#define LEDpin 8 // D8, PA2 - set to 0 to disable LED
#define MAJOR_VERSION RF12_EEPROM_VERSION // bump when EEPROM layout changes
#define MINOR_VERSION 2 // bump on other non-trivial changes
#define VERSION "[RF12demo.12]" // keep in sync with the above
/*
+-\/-+
VCC 1| |14 GND
(D0) PB0 2| |13 AREF (D10)
(D1) PB1 3| |12 PA1 (D9)
RESET 4| |11 PA2 (D8)
INT0 PWM (D2) PB2 5| |10 PA3 (D7)
PWM (D3) PA7 6| |9 PA4 (D6)
PWM (D4) PA6 7| |8 PA5 (D5) PWM
+----+
*/
// Initialise UART
SoftwareSerial mySerial(rxPin, txPin);
/// Save a few bytes of flash by declaring const if used more than once.
const char INITFAIL[] PROGMEM = "Config save failed\n";
/// "override" rf12_configDump for SoftwareSerial
void my_rf12_configDump () {
uint8_t nodeId = eeprom_read_byte(RF12_EEPROM_ADDR);
uint8_t flags = eeprom_read_byte(RF12_EEPROM_ADDR + 3);
uint16_t freq = eeprom_read_word((uint16_t*) (RF12_EEPROM_ADDR + 4));
// " A i1 g178 @ 868 MHz "
mySerial.print(' ');
mySerial.print((char) ('@' + (nodeId & RF12_HDR_MASK)));
mySerial.print(" i");
mySerial.print(nodeId & RF12_HDR_MASK);
if (flags & 0x04)
mySerial.print('*');
mySerial.print(" g");
mySerial.print(eeprom_read_byte(RF12_EEPROM_ADDR + 1));
mySerial.print(" @ ");
uint8_t band = nodeId >> 6;
mySerial.print(band == RF12_433MHZ ? 433 :
band == RF12_868MHZ ? 868 :
band == RF12_915MHZ ? 915 : 0);
mySerial.print(" MHz");
if (flags & 0x04) {
mySerial.print(" c1");
}
if (freq != 1600) {
mySerial.print(" o");
mySerial.print(freq);
}
if (flags & 0x08) {
mySerial.print(" q1");
}
if (flags & 0x03) {
mySerial.print(" x");
mySerial.print(flags & 0x03);
}
mySerial.println();
}
static unsigned long now () {
// FIXME 49-day overflow
return millis() / 1000;
}
static void activityLed (byte on) {
#ifdef LED_PIN
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, !on);
#endif
}
static void printOneChar (char c) {
mySerial.print(c);
}
static void showString (PGM_P s) {
for (;;) {
char c = pgm_read_byte(s++);
if (c == 0)
break;
if (c == '\n')
printOneChar('\r');
printOneChar(c);
}
}
static void displayVersion () {
showString(PSTR(VERSION));
showString(PSTR(" for TinyRX4"));
}
// RF12 configuration area
typedef struct {
byte nodeId; // used by rf12_config, offset 0
byte group; // used by rf12_config, offset 1
byte format; // used by rf12_config, offset 2
byte hex_output :2; // 0 = dec, 1 = hex, 2 = hex+ascii
byte collect_mode :1; // 0 = ack, 1 = don't send acks
byte quiet_mode :1; // 0 = show all, 1 = show only valid packets
byte spare_flags :4;
word frequency_offset; // used by rf12_config, offset 4
byte pad[RF12_EEPROM_SIZE-8];
word crc;
} RF12Config;
static RF12Config config;
static char cmd;
static word value;
static byte stack[RF12_MAXDATA+4], top, sendLen, dest;
static byte testCounter;
static void showNibble (byte nibble) {
char c = '0' + (nibble & 0x0F);
if (c > '9')
c += 7;
mySerial.print(c);
}
static void showByte (byte value) {
if (config.hex_output) {
showNibble(value >> 4);
showNibble(value);
} else
mySerial.print((word) value);
}
static word calcCrc (const void* ptr, byte len) {
word crc = ~0;
for (byte i = 0; i < len; ++i)
crc = _crc16_update(crc, ((const byte*) ptr)[i]);
return crc;
}
static void loadConfig () {
// eeprom_read_block(&config, RF12_EEPROM_ADDR, sizeof config);
// this uses 166 bytes less flash than eeprom_read_block(), no idea why
for (byte i = 0; i < sizeof config; ++ i)
((byte*) &config)[i] = eeprom_read_byte(RF12_EEPROM_ADDR + i);
}
static void saveConfig () {
config.format = MAJOR_VERSION;
config.crc = calcCrc(&config, sizeof config - 2);
// eeprom_write_block(&config, RF12_EEPROM_ADDR, sizeof config);
// this uses 170 bytes less flash than eeprom_write_block(), no idea why
eeprom_write_byte(RF12_EEPROM_ADDR, ((byte*) &config)[0]);
for (byte i = 0; i < sizeof config; ++ i)
eeprom_write_byte(RF12_EEPROM_ADDR + i, ((byte*) &config)[i]);
if (rf12_configSilent())
my_rf12_configDump();
else
showString(INITFAIL);
}
static byte bandToFreq (byte band) {
return band == 4 ? RF12_433MHZ : band == 8 ? RF12_868MHZ : band == 9 ? RF12_915MHZ : 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// OOK transmit code
// Turn transmitter on or off, but also apply asymmetric correction and account
// for 25 us SPI overhead to end up with the proper on-the-air pulse widths.
// With thanks to JGJ Veken for his help in getting these values right.
static void ookPulse(int on, int off) {
rf12_onOff(1);
delayMicroseconds(on + 150);
rf12_onOff(0);
delayMicroseconds(off - 200);
}
static void fs20sendBits(word data, byte bits) {
if (bits == 8) {
++bits;
data = (data << 1) | parity_even_bit(data);
}
for (word mask = bit(bits-1); mask != 0; mask >>= 1) {
int width = data & mask ? 600 : 400;
ookPulse(width, width);
}
}
static void fs20cmd(word house, byte addr, byte cmd) {
byte sum = 6 + (house >> 8) + house + addr + cmd;
for (byte i = 0; i < 3; ++i) {
fs20sendBits(1, 13);
fs20sendBits(house >> 8, 8);
fs20sendBits(house, 8);
fs20sendBits(addr, 8);
fs20sendBits(cmd, 8);
fs20sendBits(sum, 8);
fs20sendBits(0, 1);
delay(10);
}
}
static void kakuSend(char addr, byte device, byte on) {
int cmd = 0x600 | ((device - 1) << 4) | ((addr - 1) & 0xF);
if (on)
cmd |= 0x800;
for (byte i = 0; i < 4; ++i) {
for (byte bit = 0; bit < 12; ++bit) {
ookPulse(375, 1125);
int on = bitRead(cmd, bit) ? 1125 : 375;
ookPulse(on, 1500 - on);
}
ookPulse(375, 375);
delay(11); // approximate
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char helpText[] PROGMEM =
"\n"
"Set:\n"
" <nn> i - node ID 1-30\n"
" <n> b - MHz band 4,8,9\n"
" <nnnn> o - frequency offset. def 1600. 96-3903\n"
" <nnn> g - network group 212, 0:any\n"
" <n> c - collect mode 0\n"
" <n> q - quiet mode 0,1\n"
" <n> x - report format 0:d,1:hx,2:hx+asci\n"
"Send:\n"
" t - bcast mx-size test pkt, req ack\n"
" ...,<nn> a - send pkt to <nn>, req ack\n"
" ...,<nn> s - send pkt to <nn>, no ack\n"
"Remote cntrl:\n"
" <hchi>,<hclo>,<addr>,<cmd> f - FS20 cmd 868 MHz\n"
" <addr>,<dev>,<on> k - KAKU cmd 433 MHz\n"
"123 z - power down, needs reset\n"
;
static void showHelp () {
showString(helpText);
showString(PSTR("Conf:\n"));
my_rf12_configDump();
}
static void handleInput (char c) {
if ('0' <= c && c <= '9') {
value = 10 * value + c - '0';
return;
}
if (c == ',') {
if (top < sizeof stack)
stack[top++] = value; // truncated to 8 bits
value = 0;
return;
}
if ('a' <= c && c <= 'z') {
showString(PSTR("> "));
for (byte i = 0; i < top; ++i) {
mySerial.print((word) stack[i]);
printOneChar(',');
}
mySerial.print(value);
mySerial.println(c);
}
// keeping this out of the switch reduces code size (smaller branch table)
if (c == '>') {
// special case, send to specific band and group, and don't echo cmd
// input: band,group,node,header,data...
stack[top++] = value;
// TODO: frequency offset is taken from global config, is that ok?
rf12_initialize(stack[2], bandToFreq(stack[0]), stack[1],
config.frequency_offset);
rf12_sendNow(stack[3], stack + 4, top - 4);
rf12_sendWait(2);
rf12_configSilent();
} else if (c > ' ') {
switch (c) {
case 'i': // set node id
config.nodeId = (config.nodeId & 0xE0) + (value & 0x1F);
saveConfig();
break;
case 'b': // set band: 4 = 433, 8 = 868, 9 = 915
value = bandToFreq(value);
if (value) {
config.nodeId = (value << 6) + (config.nodeId & 0x3F);
config.frequency_offset = 1600;
saveConfig();
}
break;
case 'o': { // Increment frequency within band
// Stay within your country's ISM spectrum management guidelines, i.e.
// allowable frequencies and their use when selecting operating frequencies.
if ((value > 95) && (value < 3904)) { // supported by RFM12B
config.frequency_offset = value;
saveConfig();
}
break;
}
case 'g': // set network group
config.group = value;
saveConfig();
break;
case 'c': // set collect mode (off = 0, on = 1)
config.collect_mode = value;
saveConfig();
break;
case 't': // broadcast a maximum size test packet, request an ack
cmd = 'a';
sendLen = RF12_MAXDATA;
dest = 0;
for (byte i = 0; i < RF12_MAXDATA; ++i)
stack[i] = i + testCounter;
showString(PSTR("test "));
showByte(testCounter); // first byte in test buffer
++testCounter;
break;
case 'a': // send packet to node ID N, request an ack
case 's': // send packet to node ID N, no ack
cmd = c;
sendLen = top;
dest = value;
break;
case 'f': // send FS20 command: <hchi>,<hclo>,<addr>,<cmd>f
rf12_initialize(0, RF12_868MHZ, 0);
activityLed(1);
fs20cmd(256 * stack[0] + stack[1], stack[2], value);
activityLed(0);
rf12_configSilent();
break;
case 'k': // send KAKU command: <addr>,<dev>,<on>k
rf12_initialize(0, RF12_433MHZ, 0);
activityLed(1);
kakuSend(stack[0], stack[1], value);
activityLed(0);
rf12_configSilent();
break;
case 'z': // put the ATmega in ultra-low power mode (reset needed)
if (value == 123) {
showString(PSTR(" Zzz...\n"));
rf12_sleep(RF12_SLEEP);
cli();
Sleepy::powerDown();
}
break;
case 'q': // turn quiet mode on or off (don't report bad packets)
config.quiet_mode = value;
saveConfig();
break;
case 'x': // set reporting mode to decimal (0), hex (1), hex+ascii (2)
config.hex_output = value;
saveConfig();
break;
case 'v': //display the interpreter version and configuration
displayVersion();
my_rf12_configDump();
break;
case 'l': // turn activity LED on or off
activityLed(value);
break;
default:
showHelp();
}
}
value = top = 0;
}
static void displayASCII (const byte* data, byte count) {
for (byte i = 0; i < count; ++i) {
printOneChar(' ');
char c = (char) data[i];
printOneChar(c < ' ' || c > '~' ? '.' : c);
}
mySerial.println();
}
void setup () {
activityLed(1);
pinMode(rxPin, INPUT);
pinMode(txPin, OUTPUT);
mySerial.begin(SERIAL_BAUD);
mySerial.println();
displayVersion();
delay(2000);
if (rf12_configSilent()) {
loadConfig();
} else {
memset(&config, 0, sizeof config);
config.nodeId = 0x81; // 868 MHz, node 1
config.group = 0xD4; // default group 212
config.frequency_offset = 1600;
config.quiet_mode = true; // Default flags, quiet on
saveConfig();
rf12_configSilent();
}
my_rf12_configDump();
showHelp();
activityLed(0);
}
void loop () {
if (mySerial.available())
handleInput(mySerial.read());
if (rf12_recvDone()) {
byte n = rf12_len;
if (rf12_crc == 0)
showString(PSTR("OK"));
else {
if (config.quiet_mode)
return;
showString(PSTR(" ?"));
if (n > 20) // print at most 20 bytes if crc is wrong
n = 20;
}
if (config.hex_output)
printOneChar('X');
if (config.group == 0) {
showString(PSTR(" G"));
showByte(rf12_grp);
}
printOneChar(' ');
showByte(rf12_hdr);
for (byte i = 0; i < n; ++i) {
if (!config.hex_output)
printOneChar(' ');
showByte(rf12_data[i]);
}
mySerial.println();
if (config.hex_output > 1) { // also print a line as ascii
showString(PSTR("ASC "));
if (config.group == 0) {
showString(PSTR(" II "));
}
printOneChar(rf12_hdr & RF12_HDR_DST ? '>' : '<');
printOneChar('@' + (rf12_hdr & RF12_HDR_MASK));
displayASCII((const byte*) rf12_data, n);
}
if (rf12_crc == 0) {
activityLed(1);
if (RF12_WANTS_ACK && (config.collect_mode) == 0) {
showString(PSTR(" -> ack\n"));
rf12_sendStart(RF12_ACK_REPLY, 0, 0);
}
activityLed(0);
}
}
if (cmd && rf12_canSend()) {
activityLed(1);
showString(PSTR(" -> "));
mySerial.print((word) sendLen);
showString(PSTR(" b\n"));
byte header = cmd == 'a' ? RF12_HDR_ACK : 0;
if (dest)
header |= RF12_HDR_DST | dest;
rf12_sendStart(header, stack, sendLen);
cmd = 0;
activityLed(0);
}
}
Alles anzeigen