Ajout initial
This commit is contained in:
commit
aad2cc40d4
27 changed files with 2321 additions and 0 deletions
228
Makefile
Normal file
228
Makefile
Normal file
|
|
@ -0,0 +1,228 @@
|
||||||
|
# Arduino makefile
|
||||||
|
#
|
||||||
|
# This makefile allows you to build sketches from the command line
|
||||||
|
# without the Arduino environment (or Java).
|
||||||
|
#
|
||||||
|
# The Arduino environment does preliminary processing on a sketch before
|
||||||
|
# compiling it. If you're using this makefile instead, you'll need to do
|
||||||
|
# a few things differently:
|
||||||
|
#
|
||||||
|
# - Give your program's file a .cpp extension (e.g. foo.cpp).
|
||||||
|
#
|
||||||
|
# - Put this line at top of your code: #include <WProgram.h>
|
||||||
|
#
|
||||||
|
# - Write prototypes for all your functions (or define them before you
|
||||||
|
# call them). A prototype declares the types of parameters a
|
||||||
|
# function will take and what type of value it will return. This
|
||||||
|
# means that you can have a call to a function before the definition
|
||||||
|
# of the function. A function prototype looks like the first line of
|
||||||
|
# the function, with a semi-colon at the end. For example:
|
||||||
|
# int digitalRead(int pin);
|
||||||
|
#
|
||||||
|
# Instructions for using the makefile:
|
||||||
|
#
|
||||||
|
# 1. Copy this file into the folder with your sketch.
|
||||||
|
#
|
||||||
|
# 2. Below, modify the line containing "TARGET" to refer to the name of
|
||||||
|
# of your program's file without an extension (e.g. TARGET = foo).
|
||||||
|
#
|
||||||
|
# 3. Modify the line containg "ARDUINO" to point the directory that
|
||||||
|
# contains the Arduino core (for normal Arduino installations, this
|
||||||
|
# is the lib/targets/arduino sub-directory).
|
||||||
|
#
|
||||||
|
# 4. Modify the line containing "PORT" to refer to the filename
|
||||||
|
# representing the USB or serial connection to your Arduino board
|
||||||
|
# (e.g. PORT = /dev/tty.USB0). If the exact name of this file
|
||||||
|
# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*).
|
||||||
|
#
|
||||||
|
# 5. At the command line, change to the directory containing your
|
||||||
|
# program's file and the makefile.
|
||||||
|
#
|
||||||
|
# 6. Type "make" and press enter to compile/verify your program.
|
||||||
|
#
|
||||||
|
# 7. Type "make upload", reset your Arduino board, and press enter to
|
||||||
|
# upload your program to the Arduino board.
|
||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
|
||||||
|
#Bootloader Port
|
||||||
|
PORT = /dev/ttyU0
|
||||||
|
# /dev/serial/by-id/usb-Arduino_LLC_Arduino_Micro-if00
|
||||||
|
#Device Port (for autoreset)
|
||||||
|
RESETPORT = /dev/ttyU0
|
||||||
|
#/dev/serial/by-id/usb-Loupiottes.fr_DMXv3_Micro-if00
|
||||||
|
|
||||||
|
|
||||||
|
TARGET = sonde
|
||||||
|
SRC = main.c debug.c analog.c rf24.c spi.c lib/Hamming.c lib/HammingCalculateParitySmallAndFast.c onewire.c
|
||||||
|
CXXSRC =
|
||||||
|
ASRC = uart.S
|
||||||
|
MCU = attiny84a
|
||||||
|
F_CPU = 8000000L
|
||||||
|
FORMAT = ihex
|
||||||
|
UPLOAD_RATE = 20000
|
||||||
|
|
||||||
|
# Name of this Makefile (used for "make depend").
|
||||||
|
MAKEFILE = Makefile
|
||||||
|
|
||||||
|
# Debugging format.
|
||||||
|
# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
|
||||||
|
# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
|
||||||
|
DEBUG = stabs
|
||||||
|
|
||||||
|
OPT = s -ffunction-sections -fdata-sections -finline-functions -finline-functions-called-once -finline-small-functions -fmerge-constants -fomit-frame-pointer
|
||||||
|
|
||||||
|
# Place -D or -U options here
|
||||||
|
CDEFS = -DF_CPU=$(F_CPU)
|
||||||
|
CXXDEFS = -DF_CPU=$(F_CPU)
|
||||||
|
|
||||||
|
# Place -I options here
|
||||||
|
CINCS = -Ilib
|
||||||
|
CXXINCS = -Ilib
|
||||||
|
|
||||||
|
# Compiler flag to set the C Standard level.
|
||||||
|
# c89 - "ANSI" C
|
||||||
|
# gnu89 - c89 plus GCC extensions
|
||||||
|
# c99 - ISO C99 standard (not yet fully implemented)
|
||||||
|
# gnu99 - c99 plus GCC extensions
|
||||||
|
CSTANDARD = -std=gnu99
|
||||||
|
CDEBUG = -g$(DEBUG)
|
||||||
|
CWARN = -Wall
|
||||||
|
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
|
||||||
|
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
|
||||||
|
|
||||||
|
CFLAGS = $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA)
|
||||||
|
CXXFLAGS = $(CDEFS) $(CINCS) -O$(OPT) -fno-exceptions
|
||||||
|
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
|
||||||
|
LDFLAGS = -lm -Wl,--gc-sections
|
||||||
|
|
||||||
|
|
||||||
|
# Programming support using avrdude. Settings and variables.
|
||||||
|
AVRDUDE_PROGRAMMER = linuxspi
|
||||||
|
AVRDUDE_PORT = /dev/spidev0.0
|
||||||
|
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex:i
|
||||||
|
AVRDUDE_FLAGS = -F -pattiny84 -P$(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) -b $(UPLOAD_RATE)
|
||||||
|
|
||||||
|
# Program settings
|
||||||
|
CC = avr-gcc
|
||||||
|
CXX = avr-g++
|
||||||
|
OBJCOPY = avr-objcopy
|
||||||
|
OBJDUMP = avr-objdump
|
||||||
|
SIZE = avr-size
|
||||||
|
NM = avr-nm
|
||||||
|
AVRDUDE = avrdude
|
||||||
|
REMOVE = rm -f
|
||||||
|
MV = mv -f
|
||||||
|
|
||||||
|
OPATH = /tmp/sbuild
|
||||||
|
|
||||||
|
# Define all object files.
|
||||||
|
OBJ = $(SRC:%.c=$(OPATH)/%.c.o) $(CXXSRC:.cpp=$(OPATH)/%.cpp.o) $(ASRC:%.S=$(OPATH)/%.S.o)
|
||||||
|
|
||||||
|
# Define all listing files.
|
||||||
|
LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst)
|
||||||
|
|
||||||
|
# Combine all necessary flags and optional flags.
|
||||||
|
# Add target processor to flags.
|
||||||
|
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
|
||||||
|
ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS)
|
||||||
|
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
||||||
|
|
||||||
|
|
||||||
|
# Default target.
|
||||||
|
all: $(OPATH) $(OPATH)/lib build
|
||||||
|
|
||||||
|
build: elf hex eep
|
||||||
|
|
||||||
|
elf: $(TARGET).elf
|
||||||
|
hex: $(TARGET).hex
|
||||||
|
eep: $(TARGET).eep
|
||||||
|
lss: $(TARGET).lss
|
||||||
|
sym: $(TARGET).sym
|
||||||
|
|
||||||
|
|
||||||
|
# Program the device.
|
||||||
|
upload: $(TARGET).hex $(TARGET).eep
|
||||||
|
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
|
||||||
|
|
||||||
|
|
||||||
|
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
|
||||||
|
COFFCONVERT=$(OBJCOPY) --debugging \
|
||||||
|
--change-section-address .data-0x800000 \
|
||||||
|
--change-section-address .bss-0x800000 \
|
||||||
|
--change-section-address .noinit-0x800000 \
|
||||||
|
--change-section-address .eeprom-0x810000
|
||||||
|
|
||||||
|
|
||||||
|
coff: $(TARGET).elf
|
||||||
|
$(COFFCONVERT) -O coff-avr $(TARGET).elf $(TARGET).cof
|
||||||
|
|
||||||
|
|
||||||
|
extcoff: $(TARGET).elf
|
||||||
|
$(COFFCONVERT) -O coff-ext-avr $(TARGET).elf $(TARGET).cof
|
||||||
|
|
||||||
|
|
||||||
|
.SUFFIXES: .elf .hex .eep .lss .sym
|
||||||
|
|
||||||
|
.elf.hex:
|
||||||
|
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
|
||||||
|
|
||||||
|
.elf.eep:
|
||||||
|
-$(OBJCOPY) -O $(FORMAT) -j .eeprom --set-section-flags=.eeprom=alloc,load \
|
||||||
|
--no-change-warnings --change-section-lma .eeprom=0 $< $@
|
||||||
|
|
||||||
|
# Create extended listing file from ELF output file.
|
||||||
|
.elf.lss:
|
||||||
|
$(OBJDUMP) -h -S $< > $@
|
||||||
|
|
||||||
|
# Create a symbol table from ELF output file.
|
||||||
|
.elf.sym:
|
||||||
|
$(NM) -n $< > $@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Link: create ELF output file from object files.
|
||||||
|
$(TARGET).elf: $(OBJ)
|
||||||
|
$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
|
||||||
|
$(SIZE) -C --mcu=$(MCU) $@
|
||||||
|
|
||||||
|
|
||||||
|
# Compile: create object files from C++ source files.
|
||||||
|
$(OPATH)/%.cpp.o: %.cpp
|
||||||
|
$(CXX) -c -g $(ALL_CXXFLAGS) $< -o $@
|
||||||
|
|
||||||
|
# Compile: create object files from C source files.
|
||||||
|
$(OPATH)/%.c.o: %.c
|
||||||
|
$(CC) -c -g $(ALL_CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
# Compile: create assembler files from C source files.
|
||||||
|
%.c.s: %.c
|
||||||
|
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
# Assemble: create object files from assembler source files.
|
||||||
|
$(OPATH)/%.S.o: %.S
|
||||||
|
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
||||||
|
|
||||||
|
$(OPATH) $(OPATH)/lib:
|
||||||
|
@mkdir -p $@
|
||||||
|
|
||||||
|
# Target: clean project.
|
||||||
|
clean:
|
||||||
|
$(REMOVE) $(TARGET).hex $(TARGET).eep $(TARGET).cof $(TARGET).elf \
|
||||||
|
$(TARGET).map $(TARGET).sym $(TARGET).lss \
|
||||||
|
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d)
|
||||||
|
|
||||||
|
depend:
|
||||||
|
if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
|
||||||
|
then \
|
||||||
|
sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \
|
||||||
|
$(MAKEFILE).$$$$ && \
|
||||||
|
$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \
|
||||||
|
fi
|
||||||
|
echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \
|
||||||
|
>> $(MAKEFILE); \
|
||||||
|
$(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE)
|
||||||
|
|
||||||
|
.PHONY: all build elf hex eep lss sym program coff extcoff clean depend
|
||||||
87
analog.c
Normal file
87
analog.c
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
#include <avr/sleep.h>
|
||||||
|
#include <avr/power.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <avr/eeprom.h>
|
||||||
|
#include "analog.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define EE_Ref 1 // 4395600L;
|
||||||
|
|
||||||
|
unsigned long refval =0;// = 4395600L;
|
||||||
|
|
||||||
|
void initADC(){
|
||||||
|
bitClear(PRR,PRADC); // clearing the ADC Power Reduction bit
|
||||||
|
// bitSet(ADCSRA,ADEN);
|
||||||
|
ADCSRA = _BV(ADEN)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopADC(){
|
||||||
|
bitClear(ADCSRA,ADEN);
|
||||||
|
bitSet(PRR,PRADC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static volatile byte ADC_complete;
|
||||||
|
ISR(ADC_vect) { ADC_complete = true; }
|
||||||
|
|
||||||
|
long readADC(){
|
||||||
|
set_sleep_mode(SLEEP_MODE_ADC);
|
||||||
|
ADCSRA |= _BV(ADIE);
|
||||||
|
ADC_complete=false;
|
||||||
|
sleep_enable();
|
||||||
|
while(!ADC_complete){sei(); sleep_cpu(); }
|
||||||
|
sleep_disable();
|
||||||
|
return ADC;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readref(){
|
||||||
|
refval = eeprom_read_dword((const uint32_t *)EE_Ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
long readVcc() {
|
||||||
|
if(refval==0) readref();
|
||||||
|
long result = 0;
|
||||||
|
// Read 1.1V reference against AVcc
|
||||||
|
ADMUX = _BV(MUX5) | _BV(MUX0);
|
||||||
|
_delay_ms(1); // Wait for Vref to settle
|
||||||
|
uint8_t i=16 ;
|
||||||
|
while(i--) result += readADC();
|
||||||
|
result >>= 2;
|
||||||
|
//result = 4418850L / result; // Back-calculate AVcc in mV
|
||||||
|
result = refval / result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
long readtemp(){
|
||||||
|
|
||||||
|
// Temp at ADC2, TempVcc at PA3
|
||||||
|
// switch PA3 on
|
||||||
|
bitSet(TEMP_SENSOR_VCC_DDR,TEMP_SENSOR_VCC_BIT);
|
||||||
|
bitSet(TEMP_SENSOR_VCC_PORT,TEMP_SENSOR_VCC_BIT);
|
||||||
|
|
||||||
|
long vref=readVcc();
|
||||||
|
ADMUX = TEMP_SENSOR_ADMUX;
|
||||||
|
//_delay_ms(1); // Wait for LTM86 to settle
|
||||||
|
readADC();
|
||||||
|
long res =0;
|
||||||
|
uint8_t cpt =16;
|
||||||
|
while (cpt--) res+= readADC();
|
||||||
|
res >>= 2;
|
||||||
|
|
||||||
|
long temp = vref * res / 4096 ;
|
||||||
|
|
||||||
|
// temp = (sqrt(118.548544+0.01388*(1777.3-temp))-10.888)*144.09221902 + 30;
|
||||||
|
// Serial.print("TEMP ");Serial.println(temp);
|
||||||
|
// digitalWrite(tempvcc,HIGH);
|
||||||
|
|
||||||
|
// Stop Sensor
|
||||||
|
bitClear(TEMP_SENSOR_VCC_PORT,TEMP_SENSOR_VCC_BIT);
|
||||||
|
// bitClear(TEMP_SENSOR_VCC_DDR,TEMP_SENSOR_VCC_BIT);
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
float calctemp(long t){
|
||||||
|
return (sqrt(118.548544+0.01388*(1777.3-t))-10.888)*144.09221902 + 30;
|
||||||
|
}
|
||||||
25
analog.h
Normal file
25
analog.h
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TEMP_SENSOR_VCC_DDR DDRB
|
||||||
|
#define TEMP_SENSOR_VCC_PORT PORTB
|
||||||
|
#define TEMP_SENSOR_VCC_BIT PB1
|
||||||
|
|
||||||
|
#define TEMP_SENSOR_ADMUX ( _BV(MUX1) | _BV(MUX0) ) // ADC3 / PA3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void initADC();
|
||||||
|
void stopADC();
|
||||||
|
long readADC();
|
||||||
|
|
||||||
|
long readVcc();
|
||||||
|
long readtemp();
|
||||||
|
float calctemp(long t);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
17
crc8.h
Normal file
17
crc8.h
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
static __inline__ uint8_t
|
||||||
|
_crc8_ccitt_update(uint8_t __crc, uint8_t __data)
|
||||||
|
{
|
||||||
|
uint8_t __i, __pattern;
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
" eor %0, %4" "\n\t"
|
||||||
|
" ldi %1, 8" "\n\t"
|
||||||
|
" ldi %2, 0x07" "\n\t"
|
||||||
|
"1: lsl %0" "\n\t"
|
||||||
|
" brcc 2f" "\n\t"
|
||||||
|
" eor %0, %2" "\n\t"
|
||||||
|
"2: dec %1" "\n\t"
|
||||||
|
" brne 1b" "\n\t"
|
||||||
|
: "=r" (__crc), "=d" (__i), "=d" (__pattern)
|
||||||
|
: "0" (__crc), "r" (__data));
|
||||||
|
return __crc;
|
||||||
|
}
|
||||||
16
debug.c
Normal file
16
debug.c
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
|
||||||
|
void debug (char* ptr) {
|
||||||
|
while (*ptr) SerialPutChar(*(ptr++));
|
||||||
|
}
|
||||||
|
|
||||||
|
void debughex (char* ptr,uint8_t len) {
|
||||||
|
while (len--) {
|
||||||
|
uint8_t c = *(ptr++);
|
||||||
|
uint8_t ch= c>>4;
|
||||||
|
c &= 0x0F;
|
||||||
|
SerialPutChar(ch>9?ch+'A'-10:ch+'0');
|
||||||
|
SerialPutChar(c>9?c+'A'-10:c+'0');
|
||||||
|
}
|
||||||
|
}
|
||||||
7
debug.h
Normal file
7
debug.h
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "uart.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#define DEBUG 1
|
||||||
|
|
||||||
|
|
||||||
|
void debug (char* ptr);
|
||||||
|
void debughex (char* ptr,uint8_t len);
|
||||||
47
defines.h
Normal file
47
defines.h
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef defines_h
|
||||||
|
#define defines_h
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
typedef unsigned int word;
|
||||||
|
|
||||||
|
#define bit(b) (1UL << (b))
|
||||||
|
|
||||||
|
typedef uint8_t boolean;
|
||||||
|
|
||||||
|
typedef uint8_t byte;
|
||||||
|
|
||||||
|
#define HIGH 0x1
|
||||||
|
#define LOW 0x0
|
||||||
|
|
||||||
|
|
||||||
|
#define PI 3.1415926535897932384626433832795
|
||||||
|
#define HALF_PI 1.5707963267948966192313216916398
|
||||||
|
#define TWO_PI 6.283185307179586476925286766559
|
||||||
|
#define DEG_TO_RAD 0.017453292519943295769236907684886
|
||||||
|
#define RAD_TO_DEG 57.295779513082320876798154814105
|
||||||
|
|
||||||
|
#define min(a,b) ((a)<(b)?(a):(b))
|
||||||
|
#define max(a,b) ((a)>(b)?(a):(b))
|
||||||
|
//#define abs(x) ((x)>0?(x):-(x))
|
||||||
|
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||||
|
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||||
|
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||||
|
#define sq(x) ((x)*(x))
|
||||||
|
|
||||||
|
#define interrupts() sei()
|
||||||
|
#define noInterrupts() cli()
|
||||||
|
|
||||||
|
#define lowByte(w) ((uint8_t) ((w) & 0xff))
|
||||||
|
#define highByte(w) ((uint8_t) ((w) >> 8))
|
||||||
|
|
||||||
|
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
|
||||||
|
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
|
||||||
|
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
|
||||||
|
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
|
||||||
|
|
||||||
|
void setup(void);
|
||||||
|
void loop(void);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
79
dht11.c
Normal file
79
dht11.c
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
#include "dht11.h"
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
|
int dht11_humidity;
|
||||||
|
int dht11_temperature;
|
||||||
|
|
||||||
|
int dht11_read(){
|
||||||
|
|
||||||
|
// Init Timer1 for timekeeping
|
||||||
|
TIMSK1=0; // no interrupt
|
||||||
|
TCNT1 = 0; // start at 0
|
||||||
|
TCCR1A = 0; // nothing to do w timer
|
||||||
|
TCCR1B = _BV(CS11); // start w 1us tick
|
||||||
|
|
||||||
|
// BUFFER TO RECEIVE
|
||||||
|
uint8_t bits[5];
|
||||||
|
uint8_t cnt = 7;
|
||||||
|
uint8_t idx = 0;
|
||||||
|
|
||||||
|
// EMPTY BUFFER
|
||||||
|
for (int i=0; i< 5; i++) bits[i] = 0;
|
||||||
|
// REQUEST SAMPLE
|
||||||
|
bitSet(DHT11_DDDR,DHT11_DBIT); //pinMode(pin, OUTPUT);
|
||||||
|
bitSet(DHT11_DPORT,DHT11_DBIT); // digitalWrite(pin, HIGH);
|
||||||
|
_delay_ms(30);
|
||||||
|
bitClear(DHT11_DPORT,DHT11_DBIT); //digitalWrite(pin, LOW);
|
||||||
|
_delay_ms(18);
|
||||||
|
bitSet(DHT11_DPORT,DHT11_DBIT); // digitalWrite(pin, HIGH);
|
||||||
|
_delay_us(20);
|
||||||
|
bitClear(DHT11_DDDR,DHT11_DBIT); //pinMode(pin, INPUT);
|
||||||
|
bitSet(DHT11_DPORT,DHT11_DBIT);
|
||||||
|
|
||||||
|
// ACKNOWLEDGE or TIMEOUT
|
||||||
|
unsigned int loopCnt = 10000;
|
||||||
|
while( bitRead(DHT11_DPIN,DHT11_DBIT) == LOW)
|
||||||
|
if (loopCnt-- == 0) return DHT11_ERROR_TIMEOUT2;
|
||||||
|
|
||||||
|
loopCnt = 10000;
|
||||||
|
while( bitRead(DHT11_DPIN,DHT11_DBIT) == HIGH)
|
||||||
|
if (loopCnt-- == 0) return DHT11_ERROR_TIMEOUT2;
|
||||||
|
|
||||||
|
// READ OUTPUT - 40 BITS => 5 BYTES or TIMEOUT
|
||||||
|
for (int i=0; i<40; i++)
|
||||||
|
{
|
||||||
|
loopCnt = 10000;
|
||||||
|
while(bitRead(DHT11_DPIN,DHT11_DBIT) == LOW)
|
||||||
|
if (loopCnt-- == 0) return DHT11_ERROR_TIMEOUT;
|
||||||
|
|
||||||
|
unsigned long t = TCNT1;
|
||||||
|
|
||||||
|
|
||||||
|
loopCnt = 10000;
|
||||||
|
while(bitRead(DHT11_DPIN,DHT11_DBIT) == HIGH)
|
||||||
|
if (loopCnt-- == 0) return DHT11_ERROR_TIMEOUT;
|
||||||
|
|
||||||
|
unsigned long t2 = TCNT1;
|
||||||
|
|
||||||
|
if ((t2 - t) > 40) bits[idx] |= (1 << cnt);
|
||||||
|
if (cnt == 0) // next byte?
|
||||||
|
{
|
||||||
|
cnt = 7; // restart at MSB
|
||||||
|
idx++; // next byte!
|
||||||
|
}
|
||||||
|
else cnt--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// WRITE TO RIGHT VARS
|
||||||
|
// as bits[1] and bits[3] are allways zero they are omitted in formulas.
|
||||||
|
dht11_humidity = bits[0];
|
||||||
|
dht11_temperature = bits[2];
|
||||||
|
|
||||||
|
uint8_t sum = bits[0] + bits[2];
|
||||||
|
|
||||||
|
if (bits[4] != sum) return DHT11_ERROR_CHECKSUM;
|
||||||
|
return DHT11_OK;
|
||||||
|
}
|
||||||
22
dht11.h
Normal file
22
dht11.h
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
#define DHT11_OK 0
|
||||||
|
#define DHT11_ERROR_CHECKSUM -1
|
||||||
|
#define DHT11_ERROR_TIMEOUT -2
|
||||||
|
#define DHT11_ERROR_TIMEOUT2 -3
|
||||||
|
|
||||||
|
#define DHT11_DPIN PINB
|
||||||
|
#define DHT11_DDDR DDRB
|
||||||
|
#define DHT11_DPORT PORTB
|
||||||
|
#define DHT11_DBIT PB2
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int dht11_humidity;
|
||||||
|
extern int dht11_temperature;
|
||||||
|
int dht11_read();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
1
eeprom
Normal file
1
eeprom
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
|
||||||
BIN
eeprom.bin
Normal file
BIN
eeprom.bin
Normal file
Binary file not shown.
174
lib/Hamming.c
Normal file
174
lib/Hamming.c
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
/*
|
||||||
|
Hamming Error-Correcting Code (ECC)
|
||||||
|
Optimized for avr-gcc 4.8.1 in Atmel AVR Studio 6.2
|
||||||
|
August 12, 2014
|
||||||
|
|
||||||
|
You should include Hamming.c, Hamming.h, and only one of the other Hamming files in your project.
|
||||||
|
The other Hamming files implement the same methods in different ways, that may be better or worse for your needs.
|
||||||
|
|
||||||
|
This was created for LoFi in the TheHackadayPrize contest.
|
||||||
|
http://hackaday.io/project/1552-LoFi
|
||||||
|
|
||||||
|
Copyright 2014 David Cook
|
||||||
|
RobotRoom.com
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
|
||||||
|
#include "Hamming.h"
|
||||||
|
|
||||||
|
/****************************/
|
||||||
|
/* */
|
||||||
|
/* Constants and structures */
|
||||||
|
/* */
|
||||||
|
/****************************/
|
||||||
|
|
||||||
|
#ifndef null
|
||||||
|
#define null ((void*) 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// If transmitting/writing only, you don't need to include this file.
|
||||||
|
// If receiving/reading, then this provides the methods to correct bit errors.
|
||||||
|
|
||||||
|
#define UNCORRECTABLE 0xFF
|
||||||
|
#define ERROR_IN_PARITY 0xFE
|
||||||
|
#define NO_ERROR 0x00
|
||||||
|
|
||||||
|
|
||||||
|
/****************************/
|
||||||
|
/* */
|
||||||
|
/* Global variables */
|
||||||
|
/* */
|
||||||
|
/****************************/
|
||||||
|
|
||||||
|
// Private table. Faster and more compact than multiple if statements.
|
||||||
|
static const byte _hammingCorrect128Syndrome[16] PROGMEM =
|
||||||
|
{
|
||||||
|
NO_ERROR, // 0
|
||||||
|
ERROR_IN_PARITY, // 1
|
||||||
|
ERROR_IN_PARITY, // 2
|
||||||
|
0x01, // 3
|
||||||
|
ERROR_IN_PARITY, // 4
|
||||||
|
0x02, // 5
|
||||||
|
0x04, // 6
|
||||||
|
0x08, // 7
|
||||||
|
ERROR_IN_PARITY, // 8
|
||||||
|
0x10, // 9
|
||||||
|
0x20, // 10
|
||||||
|
0x40, // 11
|
||||||
|
0x80, // 12
|
||||||
|
UNCORRECTABLE, // 13
|
||||||
|
UNCORRECTABLE, // 14
|
||||||
|
UNCORRECTABLE, // 15
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************/
|
||||||
|
/* */
|
||||||
|
/* Private methods */
|
||||||
|
/* */
|
||||||
|
/****************************/
|
||||||
|
|
||||||
|
// Give a pointer to a received byte,
|
||||||
|
// and given a nibble difference in parity (parity ^ calculated parity)
|
||||||
|
// this will correct the received byte value if possible.
|
||||||
|
// It returns the number of bits corrected:
|
||||||
|
// 0 means no errors
|
||||||
|
// 1 means one corrected error
|
||||||
|
// 3 means corrections not possible
|
||||||
|
static byte HammingCorrect128Syndrome(byte* value, byte syndrome)
|
||||||
|
{
|
||||||
|
// Using only the lower nibble (& 0x0F), look up the bit
|
||||||
|
// to correct in a table
|
||||||
|
byte correction = pgm_read_byte(&(_hammingCorrect128Syndrome[syndrome & 0x0F]));
|
||||||
|
|
||||||
|
if (correction != NO_ERROR)
|
||||||
|
{
|
||||||
|
if (correction == UNCORRECTABLE || value == null)
|
||||||
|
{
|
||||||
|
return 3; // Non-recoverable error
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( correction != ERROR_IN_PARITY)
|
||||||
|
{
|
||||||
|
*value ^= correction;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1; // 1-bit recoverable error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // No errors
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************/
|
||||||
|
/* */
|
||||||
|
/* Public methods */
|
||||||
|
/* */
|
||||||
|
/****************************/
|
||||||
|
|
||||||
|
// Given a pointer to a received byte and the received parity (as a lower nibble),
|
||||||
|
// this calculates what the parity should be and fixes the received value if needed.
|
||||||
|
// It returns the number of bits corrected:
|
||||||
|
// 0 means no errors
|
||||||
|
// 1 means one corrected error
|
||||||
|
// 3 means corrections not possible
|
||||||
|
byte HammingCorrect128(byte* value, nibble parity)
|
||||||
|
{
|
||||||
|
byte syndrome;
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
return 3; // Non-recoverable error
|
||||||
|
}
|
||||||
|
|
||||||
|
syndrome = HammingCalculateParity128(*value) ^ parity;
|
||||||
|
|
||||||
|
if (syndrome != 0)
|
||||||
|
{
|
||||||
|
return HammingCorrect128Syndrome(value, syndrome);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // No errors
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Given a pointer to a first value and a pointer to a second value and
|
||||||
|
// their combined given parity (lower nibble first parity, upper nibble second parity),
|
||||||
|
// this calculates what the parity should be and fixes the values if needed.
|
||||||
|
// It returns the number of bits corrected:
|
||||||
|
// 0 means no errors
|
||||||
|
// 1 means one corrected error
|
||||||
|
// 2 means two corrected errors
|
||||||
|
// 3 means corrections not possible
|
||||||
|
byte HammingCorrect2416(byte* first, byte* second, byte parity)
|
||||||
|
{
|
||||||
|
byte syndrome;
|
||||||
|
|
||||||
|
if (first == null || second == null)
|
||||||
|
{
|
||||||
|
return 3; // Non-recoverable error
|
||||||
|
}
|
||||||
|
|
||||||
|
syndrome = HammingCalculateParity2416(*first, *second) ^ parity;
|
||||||
|
|
||||||
|
if (syndrome != 0)
|
||||||
|
{
|
||||||
|
return HammingCorrect128Syndrome(first, syndrome) + HammingCorrect128Syndrome(second, syndrome >> 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // No errors
|
||||||
|
}
|
||||||
68
lib/Hamming.h
Normal file
68
lib/Hamming.h
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
Hamming Error-Correcting Code (ECC)
|
||||||
|
Optimized for avr-gcc 4.8.1 in Atmel AVR Studio 6.2
|
||||||
|
August 12, 2014
|
||||||
|
|
||||||
|
You should include Hamming.c, Hamming.h, and only one of the other Hamming files in your project.
|
||||||
|
The other Hamming files implement the same methods in different ways, that may be better or worse for your needs.
|
||||||
|
|
||||||
|
This was created for LoFi in the TheHackadayPrize contest.
|
||||||
|
http://hackaday.io/project/1552-LoFi
|
||||||
|
|
||||||
|
Copyright 2014 David Cook
|
||||||
|
RobotRoom.com
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HAMMING_H
|
||||||
|
#define _HAMMING_H
|
||||||
|
|
||||||
|
#ifndef _AVR_H
|
||||||
|
typedef unsigned char byte;
|
||||||
|
typedef unsigned char nibble;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**** These are needed to transmit and receive ****/
|
||||||
|
|
||||||
|
// Given a byte to transmit, this returns the parity as a nibble
|
||||||
|
nibble HammingCalculateParity128(byte value);
|
||||||
|
|
||||||
|
// Given two bytes to transmit, this returns the parity
|
||||||
|
// as a byte with the lower nibble being for the first byte,
|
||||||
|
// and the upper nibble being for the second byte.
|
||||||
|
byte HammingCalculateParity2416(byte first, byte second);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**** These are needed only to receive ****/
|
||||||
|
|
||||||
|
// Given a pointer to a received byte and the received parity (as a lower nibble),
|
||||||
|
// this calculates what the parity should be and fixes the received value if needed.
|
||||||
|
// It returns the number of bits corrected:
|
||||||
|
// 0 means no errors
|
||||||
|
// 1 means one corrected error
|
||||||
|
// 3 means corrections not possible
|
||||||
|
byte HammingCorrect128(byte* value, nibble parity);
|
||||||
|
|
||||||
|
// Given a pointer to a first value and a pointer to a second value and
|
||||||
|
// their combined given parity (lower nibble first parity, upper nibble second parity),
|
||||||
|
// this calculates what the parity should be and fixes the values if needed.
|
||||||
|
// It returns the number of bits corrected:
|
||||||
|
// 0 means no errors
|
||||||
|
// 1 means one corrected error
|
||||||
|
// 2 means two corrected errors
|
||||||
|
// 3 means corrections not possible
|
||||||
|
byte HammingCorrect2416(byte* first, byte* second, byte parity);
|
||||||
|
|
||||||
|
#endif // _HAMMING_H
|
||||||
67
lib/HammingCalculateParityFast.c
Normal file
67
lib/HammingCalculateParityFast.c
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
Hamming Error-Correcting Code (ECC)
|
||||||
|
Optimized for avr-gcc 4.8.1 in Atmel AVR Studio 6.2
|
||||||
|
August 12, 2014
|
||||||
|
|
||||||
|
You should include Hamming.c, Hamming.h, and only one of the other Hamming files in your project.
|
||||||
|
The other Hamming files implement the same methods in different ways, that may be better or worse for your needs.
|
||||||
|
|
||||||
|
This was created for LoFi in the TheHackadayPrize contest.
|
||||||
|
http://hackaday.io/project/1552-LoFi
|
||||||
|
|
||||||
|
Copyright 2014 David Cook
|
||||||
|
RobotRoom.com
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
|
||||||
|
#include "Hamming.h"
|
||||||
|
|
||||||
|
|
||||||
|
// This contains all of the precalculated parity values for a byte (8 bits).
|
||||||
|
// This is very fast, but takes up more program space than calculating on the fly.
|
||||||
|
static const byte _hammingCalculateParityFast128[256] PROGMEM =
|
||||||
|
{
|
||||||
|
0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
|
||||||
|
9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
|
||||||
|
10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
|
||||||
|
3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
|
||||||
|
11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
|
||||||
|
2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
|
||||||
|
1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
|
||||||
|
8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
|
||||||
|
12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
|
||||||
|
5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
|
||||||
|
6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
|
||||||
|
15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
|
||||||
|
7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
|
||||||
|
14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
|
||||||
|
13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
|
||||||
|
4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Given a byte to transmit, this returns the parity as a nibble
|
||||||
|
nibble HammingCalculateParity128(byte value)
|
||||||
|
{
|
||||||
|
return pgm_read_byte(&(_hammingCalculateParityFast128[value]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given two bytes to transmit, this returns the parity
|
||||||
|
// as a byte with the lower nibble being for the first byte,
|
||||||
|
// and the upper nibble being for the second byte.
|
||||||
|
byte HammingCalculateParity2416(byte first, byte second)
|
||||||
|
{
|
||||||
|
return (pgm_read_byte(&(_hammingCalculateParityFast128[second]))<<4) | pgm_read_byte(&(_hammingCalculateParityFast128[first]));
|
||||||
|
}
|
||||||
99
lib/HammingCalculateParitySmall.c
Normal file
99
lib/HammingCalculateParitySmall.c
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
Hamming Error-Correcting Code (ECC)
|
||||||
|
Optimized for avr-gcc 4.8.1 in Atmel AVR Studio 6.2
|
||||||
|
August 12, 2014
|
||||||
|
|
||||||
|
You should include Hamming.c, Hamming.h, and only one of the other Hamming files in your project.
|
||||||
|
The other Hamming files implement the same methods in different ways, that may be better or worse for your needs.
|
||||||
|
|
||||||
|
This was created for LoFi in the TheHackadayPrize contest.
|
||||||
|
http://hackaday.io/project/1552-LoFi
|
||||||
|
|
||||||
|
Copyright 2014 David Cook
|
||||||
|
RobotRoom.com
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Hamming.h"
|
||||||
|
|
||||||
|
/****************************/
|
||||||
|
/* */
|
||||||
|
/* Public methods */
|
||||||
|
/* */
|
||||||
|
/****************************/
|
||||||
|
|
||||||
|
// This is slower than using a table, but faster than
|
||||||
|
// using the textbook method.
|
||||||
|
|
||||||
|
// Given a byte to transmit, this returns the parity as a nibble
|
||||||
|
nibble HammingCalculateParity128(byte value)
|
||||||
|
{
|
||||||
|
// Exclusive OR is associative and commutative, so order of operations and values does not matter.
|
||||||
|
nibble parity;
|
||||||
|
|
||||||
|
if ( ( value & 1 ) != 0 )
|
||||||
|
{
|
||||||
|
parity = 0x3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parity = 0x0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ( value & 2 ) != 0 )
|
||||||
|
{
|
||||||
|
parity ^= 0x5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ( value & 4 ) != 0 )
|
||||||
|
{
|
||||||
|
parity ^= 0x6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ( value & 8 ) != 0 )
|
||||||
|
{
|
||||||
|
parity ^= 0x7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ( value & 16 ) != 0 )
|
||||||
|
{
|
||||||
|
parity ^= 0x9;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ( value & 32 ) != 0 )
|
||||||
|
{
|
||||||
|
parity ^= 0xA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ( value & 64 ) != 0 )
|
||||||
|
{
|
||||||
|
parity ^= 0xB;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ( value & 128 ) != 0 )
|
||||||
|
{
|
||||||
|
parity ^= 0xC;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given two bytes to transmit, this returns the parity
|
||||||
|
// as a byte with the lower nibble being for the first byte,
|
||||||
|
// and the upper nibble being for the second byte.
|
||||||
|
byte HammingCalculateParity2416(byte first, byte second)
|
||||||
|
{
|
||||||
|
return (HammingCalculateParity128(second) << 4) | HammingCalculateParity128(first);
|
||||||
|
}
|
||||||
|
|
||||||
64
lib/HammingCalculateParitySmallAndFast.c
Normal file
64
lib/HammingCalculateParitySmallAndFast.c
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
Hamming Error-Correcting Code (ECC)
|
||||||
|
Optimized for avr-gcc 4.8.1 in Atmel AVR Studio 6.2
|
||||||
|
August 12, 2014
|
||||||
|
|
||||||
|
You should include Hamming.c, Hamming.h, and only one of the other Hamming files in your project.
|
||||||
|
The other Hamming files implement the same methods in different ways, that may be better or worse for your needs.
|
||||||
|
|
||||||
|
This was created for LoFi in the TheHackadayPrize contest.
|
||||||
|
http://hackaday.io/project/1552-LoFi
|
||||||
|
|
||||||
|
Copyright 2014 David Cook
|
||||||
|
RobotRoom.com
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
|
||||||
|
#include "Hamming.h"
|
||||||
|
|
||||||
|
/****************************/
|
||||||
|
/* */
|
||||||
|
/* Global variables */
|
||||||
|
/* */
|
||||||
|
/****************************/
|
||||||
|
|
||||||
|
// This contains all of the precalculated parity values for a nibble (4 bits).
|
||||||
|
static const byte _hammingCalculateParityLowNibble[] PROGMEM =
|
||||||
|
{ 0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7 };
|
||||||
|
|
||||||
|
static const byte _hammingCalculateParityHighNibble[] PROGMEM =
|
||||||
|
{ 0, 9, 10, 3, 11, 2, 1, 8, 12, 5, 6, 15, 7, 14, 13, 4 };
|
||||||
|
|
||||||
|
|
||||||
|
/****************************/
|
||||||
|
/* */
|
||||||
|
/* Public methods */
|
||||||
|
/* */
|
||||||
|
/****************************/
|
||||||
|
|
||||||
|
// Given a byte to transmit, this returns the parity as a nibble
|
||||||
|
nibble HammingCalculateParity128(byte value)
|
||||||
|
{
|
||||||
|
return pgm_read_byte(&(_hammingCalculateParityLowNibble[value&0x0F])) ^ pgm_read_byte(&(_hammingCalculateParityHighNibble[value >> 4]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given two bytes to transmit, this returns the parity
|
||||||
|
// as a byte with the lower nibble being for the first byte,
|
||||||
|
// and the upper nibble being for the second byte.
|
||||||
|
byte HammingCalculateParity2416(byte first, byte second)
|
||||||
|
{
|
||||||
|
return HammingCalculateParity128(second) << 4 | HammingCalculateParity128(first);
|
||||||
|
}
|
||||||
100
lib/HammingCalculateParityTextbook.c
Normal file
100
lib/HammingCalculateParityTextbook.c
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
Hamming Error-Correcting Code (ECC)
|
||||||
|
Optimized for avr-gcc 4.8.1 in Atmel AVR Studio 6.2
|
||||||
|
August 12, 2014
|
||||||
|
|
||||||
|
You should include Hamming.c, Hamming.h, and only one of the other Hamming files in your project.
|
||||||
|
The other Hamming files implement the same methods in different ways, that may be better or worse for your needs.
|
||||||
|
|
||||||
|
This was created for LoFi in the TheHackadayPrize contest.
|
||||||
|
http://hackaday.io/project/1552-LoFi
|
||||||
|
|
||||||
|
Copyright 2014 David Cook
|
||||||
|
RobotRoom.com
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Hamming.h"
|
||||||
|
|
||||||
|
// This performs poorly on a processor that can't do multiple shifts in one instruction
|
||||||
|
#define BitToBool(byte, n) ((byte>>(n-1)) & 1)
|
||||||
|
|
||||||
|
// This is a private method that calculates half the parity
|
||||||
|
// while shifting over any previously calculated parity for another byte.
|
||||||
|
// This was designed for processors that cannot shift more than one bit place at a time
|
||||||
|
nibble HammingCalculateParity2416Half(byte value, byte paritySoFar)
|
||||||
|
{
|
||||||
|
// Calculate the most significant bit
|
||||||
|
paritySoFar |= BitToBool(value, 5) ^ BitToBool(value, 6) ^ BitToBool(value, 7) ^ BitToBool(value, 8);
|
||||||
|
// Shift it over
|
||||||
|
paritySoFar <<= 1;
|
||||||
|
|
||||||
|
// Calculate the next most significant bit
|
||||||
|
paritySoFar |= BitToBool(value, 2) ^ BitToBool(value, 3) ^ BitToBool(value, 4) ^ BitToBool(value, 8);
|
||||||
|
// Shift it over, as well as the previously calculated bit
|
||||||
|
paritySoFar <<= 1;
|
||||||
|
|
||||||
|
// Calculate the next most significant bit
|
||||||
|
paritySoFar |= BitToBool(value, 1) ^ BitToBool(value, 3) ^ BitToBool(value, 4) ^ BitToBool(value, 6) ^ BitToBool(value, 7);
|
||||||
|
// Shift it over, as well as the previously calculated bits
|
||||||
|
paritySoFar <<= 1;
|
||||||
|
|
||||||
|
// Calculate the least significant bit
|
||||||
|
paritySoFar |= BitToBool(value, 1) ^ BitToBool(value, 2) ^ BitToBool(value, 4) ^ BitToBool(value, 5) ^ BitToBool(value, 7);
|
||||||
|
|
||||||
|
return paritySoFar;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a byte to transmit, this returns the parity as a nibble
|
||||||
|
nibble HammingCalculateParity128(byte value)
|
||||||
|
{
|
||||||
|
return HammingCalculateParity2416Half(value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If your processor can shift multiple bit places in a single instruction, then set this to 1.
|
||||||
|
// It will be twice as fast.
|
||||||
|
// If your processor cannot, then set this to 0, otherwise it will be slow and large.
|
||||||
|
#define CPU_HAS_MULTIPLE_SHIFT_INSTRUCTION 0
|
||||||
|
|
||||||
|
#if CPU_HAS_MULTIPLE_SHIFT_INSTRUCTION
|
||||||
|
// Given two bytes to transmit, this returns the parity
|
||||||
|
// as a byte with the lower nibble being for the first byte,
|
||||||
|
// and the upper nibble being for the second byte.
|
||||||
|
byte HammingCalculateParity2416(byte first, byte second)
|
||||||
|
{
|
||||||
|
// This is the textbook way to calculate hamming parity.
|
||||||
|
return ((BitToBool(first, 1) ^ BitToBool(first, 2) ^ BitToBool(first, 4) ^ BitToBool(first, 5) ^ BitToBool(first, 7))) +
|
||||||
|
((BitToBool(first, 1) ^ BitToBool(first, 3) ^ BitToBool(first, 4) ^ BitToBool(first, 6) ^ BitToBool(first, 7))<<1) +
|
||||||
|
((BitToBool(first, 2) ^ BitToBool(first, 3) ^ BitToBool(first, 4) ^ BitToBool(first, 8))<<2) +
|
||||||
|
((BitToBool(first, 5) ^ BitToBool(first, 6) ^ BitToBool(first, 7) ^ BitToBool(first, 8))<<3) +
|
||||||
|
|
||||||
|
((BitToBool(second, 1) ^ BitToBool(second, 2) ^ BitToBool(second, 4) ^ BitToBool(second, 5) ^ BitToBool(second, 7))<<4) +
|
||||||
|
((BitToBool(second, 1) ^ BitToBool(second, 3) ^ BitToBool(second, 4) ^ BitToBool(second, 6) ^ BitToBool(second, 7))<<5) +
|
||||||
|
((BitToBool(second, 2) ^ BitToBool(second, 3) ^ BitToBool(second, 4) ^ BitToBool(second, 8))<<6) +
|
||||||
|
((BitToBool(second, 5) ^ BitToBool(second, 6) ^ BitToBool(second, 7) ^ BitToBool(second, 8))<<7);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// Given two bytes to transmit, this returns the parity
|
||||||
|
// as a byte with the lower nibble being for the first byte,
|
||||||
|
// and the upper nibble being for the second byte.
|
||||||
|
byte HammingCalculateParity2416(byte first, byte second)
|
||||||
|
{
|
||||||
|
// This makes two calls, one for each byte.
|
||||||
|
// It passes the result of the second byte into the calculation for the first
|
||||||
|
// such that the four shift instructions and the 'or' instruction are free.
|
||||||
|
return HammingCalculateParity2416Half(first, HammingCalculateParity2416Half(second, 0) << 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
277
main.c
Normal file
277
main.c
Normal file
|
|
@ -0,0 +1,277 @@
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/sleep.h>
|
||||||
|
#include <avr/wdt.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <avr/power.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include <avr/eeprom.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "debug.h"
|
||||||
|
#include "analog.h"
|
||||||
|
//#include "dht11.h"
|
||||||
|
#include "rf24.h"
|
||||||
|
#include "lib/Hamming.h"
|
||||||
|
#include "crc8.h"
|
||||||
|
#include "onewire.h"
|
||||||
|
|
||||||
|
#define EE_Num 0
|
||||||
|
|
||||||
|
uint8_t ADDR[5]={0xE7,0xE7,0xE7,0xE7,0xE7}; //{0xE7,0xE7,0xE7,0xE7,0xE7}; //
|
||||||
|
|
||||||
|
|
||||||
|
#define PKTLEN 24
|
||||||
|
|
||||||
|
#define CMD_DATA 0x20
|
||||||
|
#define CMD_BIN 0x30
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
char debugbuf[32];
|
||||||
|
uint16_t totaltime;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char buffer[18];
|
||||||
|
char* text = buffer +4;
|
||||||
|
uint8_t sendbuffer[24];
|
||||||
|
uint8_t id;
|
||||||
|
uint8_t pid=0;
|
||||||
|
|
||||||
|
volatile bool wdt_flag=false;
|
||||||
|
volatile bool pcint_flag=false;
|
||||||
|
|
||||||
|
ISR(WATCHDOG_vect){
|
||||||
|
wdt_flag=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(PCINT0_vect){
|
||||||
|
pcint_flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void sleep(){
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
uint16_t time = TCNT1;
|
||||||
|
totaltime +=time;
|
||||||
|
//debughex(&time,2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
|
||||||
|
cli();
|
||||||
|
sleep_enable();
|
||||||
|
//sleep_bod_disable();
|
||||||
|
sei();
|
||||||
|
sleep_cpu();
|
||||||
|
sleep_disable();
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
TCCR1A =0;
|
||||||
|
TCCR1C =0;
|
||||||
|
TCNT1 = 0;
|
||||||
|
TCCR1B = 2;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wait_for_next(){
|
||||||
|
int cnt=6;
|
||||||
|
#ifdef DEBUG
|
||||||
|
cnt=2;
|
||||||
|
#endif
|
||||||
|
while (cnt--){
|
||||||
|
wdt_enable(WDTO_8S);
|
||||||
|
WDTCSR |= _BV(WDIE);
|
||||||
|
sleep();
|
||||||
|
}
|
||||||
|
cnt = rand()%6;
|
||||||
|
while (cnt--){
|
||||||
|
wdt_enable(WDTO_1S);
|
||||||
|
WDTCSR |= _BV(WDIE);
|
||||||
|
sleep();
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
debughex(&totaltime,2);
|
||||||
|
totaltime=0;
|
||||||
|
debug("\r");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void power_down(){
|
||||||
|
stopADC();
|
||||||
|
power_all_disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait_for_radio(){
|
||||||
|
|
||||||
|
wdt_enable(WDTO_120MS);
|
||||||
|
wdt_flag=false;
|
||||||
|
pcint_flag = false;
|
||||||
|
|
||||||
|
cli();
|
||||||
|
// Sleep until radio ready or wdt 60ms
|
||||||
|
while (bit_is_set(PINA,PA7) || (!wdt_flag) ){
|
||||||
|
WDTCSR |= _BV(WDIE);
|
||||||
|
sleep();
|
||||||
|
cli(); // disable interrupts before testing wdt_flag
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable radio -> low power until next tx
|
||||||
|
rf24_powerDown();
|
||||||
|
|
||||||
|
if(!wdt_flag) // radio ok... wait until 60ms
|
||||||
|
{
|
||||||
|
WDTCSR |= _BV(WDIE); // reenable wdt interrupt
|
||||||
|
sleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupRadio(){
|
||||||
|
// Static values in ram.
|
||||||
|
rf24_CONFIG = 0;
|
||||||
|
rf24_RF_CH = 90;
|
||||||
|
rf24_RF_SETUP = 0x26;
|
||||||
|
rf24_FEATURE = 0;//_BV(EN_DPL)|_BV(EN_ACK_PAY)|_BV(EN_DYN_ACK);
|
||||||
|
rf24_DYNPD = 0x00;
|
||||||
|
rf24_RX_PW[0]=PKTLEN;
|
||||||
|
rf24_RX_PW[1]=PKTLEN;
|
||||||
|
rf24_SETUP_RETR = 0x00;
|
||||||
|
rf24_EN_AA = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initRadio(){
|
||||||
|
power_usi_enable();
|
||||||
|
rf24_init();
|
||||||
|
rf24_writeRegister(RX_ADDR_P0,(uint8_t*)ADDR,5);
|
||||||
|
rf24_writeRegister(TX_ADDR,(uint8_t*)ADDR,5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void txData(){
|
||||||
|
uint8_t crc,cpt,a,b,len;
|
||||||
|
uint8_t *in, *out;
|
||||||
|
|
||||||
|
|
||||||
|
// Pkt ID
|
||||||
|
buffer[1] = id;
|
||||||
|
buffer[2] = pid++;
|
||||||
|
|
||||||
|
len = buffer[0] & 0x0F;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
debughex(buffer,len);
|
||||||
|
debug("\r");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// CRC Calc
|
||||||
|
buffer[3] = 0; // CRC =0 in crc calc;
|
||||||
|
crc=0; cpt= len; in=(uint8_t*)buffer;
|
||||||
|
while(cpt--) crc = _crc8_ccitt_update(crc,*(in++));
|
||||||
|
buffer[3] = crc;
|
||||||
|
|
||||||
|
// Hamming compute
|
||||||
|
cpt= len ;
|
||||||
|
if(cpt & 1) buffer[cpt++]=0; // odd number => add one 0
|
||||||
|
cpt/=2; in=(uint8_t*)buffer; out = sendbuffer;
|
||||||
|
|
||||||
|
while(cpt--){
|
||||||
|
a = *(out++)= *(in++);
|
||||||
|
b = *(out++)= *(in++);
|
||||||
|
*(out++) = HammingCalculateParity2416(a,b);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpt=4;
|
||||||
|
while (cpt--){
|
||||||
|
rf24_send(sendbuffer,PKTLEN);
|
||||||
|
wait_for_radio();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
DDRB |= _BV(PB0);
|
||||||
|
debug("Sonde Start \r");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t rvcc=0;
|
||||||
|
|
||||||
|
int vcc;
|
||||||
|
// Setup
|
||||||
|
power_down();
|
||||||
|
setupRadio();
|
||||||
|
id = eeprom_read_byte((const uint8_t*)EE_Num);
|
||||||
|
// random seed
|
||||||
|
|
||||||
|
initADC();
|
||||||
|
srand((int)readVcc() * id );
|
||||||
|
|
||||||
|
|
||||||
|
DDRB |= _BV(PB1) ;
|
||||||
|
PORTB &= ~_BV(PB1);
|
||||||
|
|
||||||
|
while(1){
|
||||||
|
|
||||||
|
|
||||||
|
if(!(rvcc--)){
|
||||||
|
initADC();
|
||||||
|
|
||||||
|
// Read VCC
|
||||||
|
vcc = readVcc();
|
||||||
|
stopADC();
|
||||||
|
rvcc=4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do 8 temp reads over 4s
|
||||||
|
/* int i = 7;
|
||||||
|
long lt=readtemp();
|
||||||
|
while(i--){
|
||||||
|
power_down();
|
||||||
|
wdt_enable(WDTO_500MS);
|
||||||
|
WDTCSR |= _BV(WDIE);
|
||||||
|
sleep();
|
||||||
|
power_up();
|
||||||
|
initADC();
|
||||||
|
lt += readtemp();
|
||||||
|
}
|
||||||
|
wdt_enable(WDTO_8S);
|
||||||
|
float temp = calctemp(lt / 8);*/
|
||||||
|
|
||||||
|
w1_start();
|
||||||
|
wdt_enable(WDTO_15MS);
|
||||||
|
WDTCSR |= _BV(WDIE);
|
||||||
|
sleep();
|
||||||
|
|
||||||
|
start_meas();
|
||||||
|
wdt_enable(WDTO_1S);
|
||||||
|
WDTCSR |= _BV(WDIE);
|
||||||
|
sleep();
|
||||||
|
|
||||||
|
uint16_t t_i = read_meas();//=temp*100;
|
||||||
|
w1_stop();
|
||||||
|
|
||||||
|
// Send data
|
||||||
|
initRadio();
|
||||||
|
|
||||||
|
buffer[0] = 0x0A | CMD_BIN; // 10 octets :
|
||||||
|
*(uint16_t*)(buffer+4) = 0x0002; // BIN v2 = vcc+tempDS
|
||||||
|
*(uint16_t*)(buffer+6) = vcc; // 2 o
|
||||||
|
*(uint16_t*)(buffer+8) = t_i; // 2 o
|
||||||
|
txData(buffer);
|
||||||
|
|
||||||
|
|
||||||
|
//radio off
|
||||||
|
rf24_powerDown();
|
||||||
|
|
||||||
|
power_down();
|
||||||
|
wait_for_next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
125
nRF24L01.h
Normal file
125
nRF24L01.h
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2007 Stefan Engelke <mbox@stefanengelke.de>
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Memory Map */
|
||||||
|
#define CONFIG 0x00
|
||||||
|
#define EN_AA 0x01
|
||||||
|
#define EN_RXADDR 0x02
|
||||||
|
#define SETUP_AW 0x03
|
||||||
|
#define SETUP_RETR 0x04
|
||||||
|
#define RF_CH 0x05
|
||||||
|
#define RF_SETUP 0x06
|
||||||
|
#define STATUS 0x07
|
||||||
|
#define OBSERVE_TX 0x08
|
||||||
|
#define CD 0x09
|
||||||
|
#define RX_ADDR_P0 0x0A
|
||||||
|
#define RX_ADDR_P1 0x0B
|
||||||
|
#define RX_ADDR_P2 0x0C
|
||||||
|
#define RX_ADDR_P3 0x0D
|
||||||
|
#define RX_ADDR_P4 0x0E
|
||||||
|
#define RX_ADDR_P5 0x0F
|
||||||
|
#define TX_ADDR 0x10
|
||||||
|
#define RX_PW_P0 0x11
|
||||||
|
#define RX_PW_P1 0x12
|
||||||
|
#define RX_PW_P2 0x13
|
||||||
|
#define RX_PW_P3 0x14
|
||||||
|
#define RX_PW_P4 0x15
|
||||||
|
#define RX_PW_P5 0x16
|
||||||
|
#define FIFO_STATUS 0x17
|
||||||
|
#define DYNPD 0x1C
|
||||||
|
#define FEATURE 0x1D
|
||||||
|
|
||||||
|
/* Bit Mnemonics */
|
||||||
|
#define MASK_RX_DR 6
|
||||||
|
#define MASK_TX_DS 5
|
||||||
|
#define MASK_MAX_RT 4
|
||||||
|
#define EN_CRC 3
|
||||||
|
#define CRCO 2
|
||||||
|
#define PWR_UP 1
|
||||||
|
#define PRIM_RX 0
|
||||||
|
#define ENAA_P5 5
|
||||||
|
#define ENAA_P4 4
|
||||||
|
#define ENAA_P3 3
|
||||||
|
#define ENAA_P2 2
|
||||||
|
#define ENAA_P1 1
|
||||||
|
#define ENAA_P0 0
|
||||||
|
#define ERX_P5 5
|
||||||
|
#define ERX_P4 4
|
||||||
|
#define ERX_P3 3
|
||||||
|
#define ERX_P2 2
|
||||||
|
#define ERX_P1 1
|
||||||
|
#define ERX_P0 0
|
||||||
|
#define AW 0
|
||||||
|
#define ARD 4
|
||||||
|
#define ARC 0
|
||||||
|
#define PLL_LOCK 4
|
||||||
|
#define RF_DR 3
|
||||||
|
#define RF_PWR 6
|
||||||
|
#define RX_DR 6
|
||||||
|
#define TX_DS 5
|
||||||
|
#define MAX_RT 4
|
||||||
|
#define RX_P_NO 1
|
||||||
|
#define TX_FULL 0
|
||||||
|
#define PLOS_CNT 4
|
||||||
|
#define ARC_CNT 0
|
||||||
|
#define TX_REUSE 6
|
||||||
|
#define FIFO_FULL 5
|
||||||
|
#define TX_EMPTY 4
|
||||||
|
#define RX_FULL 1
|
||||||
|
#define RX_EMPTY 0
|
||||||
|
#define DPL_P5 5
|
||||||
|
#define DPL_P4 4
|
||||||
|
#define DPL_P3 3
|
||||||
|
#define DPL_P2 2
|
||||||
|
#define DPL_P1 1
|
||||||
|
#define DPL_P0 0
|
||||||
|
#define EN_DPL 2
|
||||||
|
#define EN_ACK_PAY 1
|
||||||
|
#define EN_DYN_ACK 0
|
||||||
|
|
||||||
|
/* Instruction Mnemonics */
|
||||||
|
#define R_REGISTER 0x00
|
||||||
|
#define W_REGISTER 0x20
|
||||||
|
#define REGISTER_MASK 0x1F
|
||||||
|
#define ACTIVATE 0x50
|
||||||
|
#define R_RX_PL_WID 0x60
|
||||||
|
#define R_RX_PAYLOAD 0x61
|
||||||
|
#define W_TX_PAYLOAD 0xA0
|
||||||
|
#define W_ACK_PAYLOAD 0xA8
|
||||||
|
#define FLUSH_TX 0xE1
|
||||||
|
#define FLUSH_RX 0xE2
|
||||||
|
#define REUSE_TX_PL 0xE3
|
||||||
|
#define NOP 0xFF
|
||||||
|
|
||||||
|
/* Non-P omissions */
|
||||||
|
#define LNA_HCURR 0
|
||||||
|
|
||||||
|
/* P model memory Map */
|
||||||
|
#define RPD 0x09
|
||||||
|
|
||||||
|
/* P model bit Mnemonics */
|
||||||
|
#define RF_DR_LOW 5
|
||||||
|
#define RF_DR_HIGH 3
|
||||||
|
#define RF_PWR_LOW 1
|
||||||
|
#define RF_PWR_HIGH 2
|
||||||
231
onewire.c
Normal file
231
onewire.c
Normal file
|
|
@ -0,0 +1,231 @@
|
||||||
|
/*
|
||||||
|
Access Dallas 1-Wire Devices with ATMEL AVRs
|
||||||
|
Author of the initial code: Peter Dannegger (danni(at)specs.de)
|
||||||
|
modified by Martin Thomas (mthomas(at)rhrk.uni-kl.de)
|
||||||
|
9/2004 - use of delay.h, optional bus configuration at runtime
|
||||||
|
10/2009 - additional delay in ow_bit_io for recovery
|
||||||
|
5/2010 - timing modifcations, additonal config-values and comments,
|
||||||
|
use of atomic.h macros, internal pull-up support
|
||||||
|
7/2010 - added method to skip recovery time after last bit transfered
|
||||||
|
via ow_command_skip_last_recovery
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
#include "onewire.h"
|
||||||
|
|
||||||
|
#define NULL 0
|
||||||
|
|
||||||
|
|
||||||
|
inline void OUT_LOW(void){
|
||||||
|
W1_DDR |= _BV(W1_PIN); // OUT
|
||||||
|
W1_OUT &= ~(_BV(W1_PIN)); // LOW
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void OUT_HIGH(void){
|
||||||
|
W1_DDR |= _BV(W1_PIN); // OUT
|
||||||
|
W1_OUT |= _BV(W1_PIN); // HIGH
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PULL_UP(void){
|
||||||
|
W1_DDR &= ~(_BV(W1_PIN));
|
||||||
|
W1_OUT |= _BV(W1_PIN); // pull up
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t w1_reset(void)
|
||||||
|
{
|
||||||
|
uint8_t err;
|
||||||
|
|
||||||
|
OUT_LOW();
|
||||||
|
|
||||||
|
_delay_us(480);
|
||||||
|
|
||||||
|
cli();
|
||||||
|
|
||||||
|
PULL_UP();
|
||||||
|
|
||||||
|
_delay_us(66);
|
||||||
|
|
||||||
|
err = bit_is_set(W1_IN,W1_PIN); // no presence detect
|
||||||
|
|
||||||
|
sei();
|
||||||
|
|
||||||
|
_delay_us(414); // 480 - 66
|
||||||
|
|
||||||
|
if( bit_is_clear(W1_IN,W1_PIN)) // short circuit
|
||||||
|
err = 1;
|
||||||
|
|
||||||
|
OUT_HIGH();
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t w1_bit_io(uint8_t b)
|
||||||
|
{
|
||||||
|
cli();
|
||||||
|
OUT_LOW();
|
||||||
|
|
||||||
|
_delay_us(1);
|
||||||
|
if( b ){
|
||||||
|
PULL_UP();
|
||||||
|
}
|
||||||
|
_delay_us(14); // 15 - 1
|
||||||
|
if( bit_is_clear(W1_IN,W1_PIN))
|
||||||
|
b = 0;
|
||||||
|
|
||||||
|
_delay_us(45); // 60 - 15
|
||||||
|
|
||||||
|
OUT_HIGH();
|
||||||
|
sei();
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t w1_byte_wr(uint8_t b)
|
||||||
|
{
|
||||||
|
uint8_t i = 8, j;
|
||||||
|
do{
|
||||||
|
j = w1_bit_io( b & 1 );
|
||||||
|
b >>= 1;
|
||||||
|
if( j )
|
||||||
|
b |= 0x80;
|
||||||
|
}while( --i );
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t w1_byte_rd(void)
|
||||||
|
{
|
||||||
|
return w1_byte_wr( 0xFF );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t w1_rom_search(uint8_t diff, uint8_t* id)
|
||||||
|
{
|
||||||
|
uint8_t i, j, next_diff;
|
||||||
|
uint8_t b;
|
||||||
|
|
||||||
|
if( w1_reset() )
|
||||||
|
return PRESENCE_ERR; // error, no device found
|
||||||
|
w1_byte_wr( SEARCH_ROM ); // ROM search command
|
||||||
|
next_diff = LAST_DEVICE; // unchanged on last device
|
||||||
|
i = 8 * 8; // 8 bytes
|
||||||
|
do{
|
||||||
|
j = 8; // 8 bits
|
||||||
|
do{
|
||||||
|
b = w1_bit_io( 1 ); // read bit
|
||||||
|
if( w1_bit_io( 1 ) ){ // read complement bit
|
||||||
|
if( b ) // 11
|
||||||
|
return DATA_ERR; // data error
|
||||||
|
}else{
|
||||||
|
if( !b ){ // 00 = 2 devices
|
||||||
|
if( diff > i ||
|
||||||
|
((*id & 1) && diff != i) ){
|
||||||
|
b = 1; // now 1
|
||||||
|
next_diff = i; // next pass 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w1_bit_io( b ); // write bit
|
||||||
|
*id >>= 1;
|
||||||
|
if( b ) // store bit
|
||||||
|
*id |= 0x80;
|
||||||
|
i--;
|
||||||
|
}while( --j );
|
||||||
|
id++; // next byte
|
||||||
|
}while( i );
|
||||||
|
return next_diff; // to continue search
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void w1_stop()
|
||||||
|
{
|
||||||
|
//W1_DDR |= 1<<W1_PIN; // Output
|
||||||
|
W1_OUT &= ~(_BV(W1_PIN));
|
||||||
|
W1_DDR &= ~(_BV(W1_PIN));
|
||||||
|
}
|
||||||
|
void w1_start()
|
||||||
|
{
|
||||||
|
OUT_HIGH();
|
||||||
|
}
|
||||||
|
|
||||||
|
void w1_command(uint8_t command, uint8_t* id)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
w1_reset();
|
||||||
|
if( id ){
|
||||||
|
w1_byte_wr( MATCH_ROM ); // to a single device
|
||||||
|
i = 8;
|
||||||
|
do{
|
||||||
|
w1_byte_wr( *id );
|
||||||
|
id++;
|
||||||
|
}while( --i );
|
||||||
|
}else{
|
||||||
|
w1_byte_wr( SKIP_ROM ); // to all devices
|
||||||
|
}
|
||||||
|
w1_byte_wr( command );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void start_meas(void)
|
||||||
|
{
|
||||||
|
if (bit_is_set(W1_IN,W1_PIN)) {
|
||||||
|
w1_command( CONVERT_T, NULL );
|
||||||
|
OUT_HIGH();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t read_meas(void)
|
||||||
|
{
|
||||||
|
/* uint8_t id[8], diff;
|
||||||
|
//uint8_t s[30];
|
||||||
|
uint8_t i;*/
|
||||||
|
uint16_t temp = 0;
|
||||||
|
|
||||||
|
/*for( diff = SEARCH_FIRST; diff != LAST_DEVICE; ){
|
||||||
|
diff = w1_rom_search( diff, id );
|
||||||
|
|
||||||
|
if( diff == PRESENCE_ERR ){
|
||||||
|
//uputsnl( "No Sensor found" );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if( diff == DATA_ERR ){
|
||||||
|
//uputsnl( "Bus Error" );
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
if( id[0] == 0x28 || id[0] == 0x10 ){ // temperature sensor
|
||||||
|
//uputs( "ID: " );
|
||||||
|
for( i = 0; i < 8; i++ ){
|
||||||
|
//sprintf( s, "%02X ", id[i] );
|
||||||
|
//uputs( s );
|
||||||
|
}
|
||||||
|
w1_byte_wr( READ ); // read command
|
||||||
|
temp = w1_byte_rd(); // low byte
|
||||||
|
temp |= (uint16_t)w1_byte_rd() << 8; // high byte
|
||||||
|
if( id[0] == 0x10 ) // 9 -> 12 bit
|
||||||
|
temp <<= 3;
|
||||||
|
//sprintf( s, " T: %04X = ", temp ); // hex value
|
||||||
|
//uputs( s );
|
||||||
|
//sprintf( s, "%4d.%01d¯C", temp >> 4, (temp << 12) / 6553 ); // 0.1¯C
|
||||||
|
//uputsnl( s );
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
//uputsnl( "" );
|
||||||
|
|
||||||
|
if(w1_reset()) return -1;
|
||||||
|
//w1_command(SKIP_ROM,NULL);
|
||||||
|
w1_byte_wr( SKIP_ROM );
|
||||||
|
w1_byte_wr( READ );
|
||||||
|
temp = w1_byte_rd();
|
||||||
|
temp |= (uint16_t)w1_byte_rd() << 8;
|
||||||
|
// temp <<= 3;
|
||||||
|
|
||||||
|
return temp ;//(temp >> 4) * 100 + ((temp << 12) / 6553) * 10;
|
||||||
|
//return temp >> 4;
|
||||||
|
}
|
||||||
57
onewire.h
Normal file
57
onewire.h
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
Access Dallas 1-Wire Devices with ATMEL AVRs
|
||||||
|
Author of the initial code: Peter Dannegger (danni(at)specs.de)
|
||||||
|
modified by Martin Thomas (mthomas(at)rhrk.uni-kl.de)
|
||||||
|
9/2004 - use of delay.h, optional bus configuration at runtime
|
||||||
|
10/2009 - additional delay in ow_bit_io for recovery
|
||||||
|
5/2010 - timing modifcations, additonal config-values and comments,
|
||||||
|
use of atomic.h macros, internal pull-up support
|
||||||
|
7/2010 - added method to skip recovery time after last bit transfered
|
||||||
|
via ow_command_skip_last_recovery
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ONEWIRE_H__
|
||||||
|
#define ONEWIRE_H__
|
||||||
|
|
||||||
|
#define W1_PIN PA0
|
||||||
|
#define W1_IN PINA
|
||||||
|
#define W1_OUT PORTA
|
||||||
|
#define W1_DDR DDRA
|
||||||
|
|
||||||
|
#define MATCH_ROM 0x55
|
||||||
|
#define SKIP_ROM 0xCC
|
||||||
|
#define SEARCH_ROM 0xF0
|
||||||
|
|
||||||
|
#define CONVERT_T 0x44 // DS1820 commands
|
||||||
|
#define READ 0xBE
|
||||||
|
#define WRITE 0x4E
|
||||||
|
#define EE_WRITE 0x48
|
||||||
|
#define EE_RECALL 0xB8
|
||||||
|
|
||||||
|
#define SEARCH_FIRST 0xFF // start new search
|
||||||
|
#define PRESENCE_ERR 0xFF
|
||||||
|
#define DATA_ERR 0xFE
|
||||||
|
#define LAST_DEVICE 0x00 // last device found
|
||||||
|
// 0x01 ... 0x40: continue searching
|
||||||
|
|
||||||
|
uint8_t w1_reset(void);
|
||||||
|
|
||||||
|
uint8_t w1_byte_wr(uint8_t b);
|
||||||
|
uint8_t w1_byte_rd(void);
|
||||||
|
|
||||||
|
uint8_t w1_rom_search(uint8_t diff, uint8_t* id);
|
||||||
|
|
||||||
|
void w1_stop();
|
||||||
|
void w1_start();
|
||||||
|
|
||||||
|
|
||||||
|
void w1_command(uint8_t command, uint8_t* id);
|
||||||
|
|
||||||
|
|
||||||
|
// temperature
|
||||||
|
void start_meas(void);
|
||||||
|
uint16_t read_meas(void);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ONEWIRE_H__
|
||||||
270
rf24.c
Normal file
270
rf24.c
Normal file
|
|
@ -0,0 +1,270 @@
|
||||||
|
|
||||||
|
#include "rf24.h"
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t PTX=0;
|
||||||
|
uint8_t rf24_CONFIG = _BV(EN_CRC) | _BV(CRCO);
|
||||||
|
uint8_t rf24_EN_AA = 0x3F; //ENAA_P0 - ENAA_P5
|
||||||
|
uint8_t rf24_EN_RXADDR = _BV(ERX_P0)|_BV(ERX_P1);
|
||||||
|
uint8_t rf24_SETUP_AW = 0x03; // 5 bytes addresses
|
||||||
|
uint8_t rf24_SETUP_RETR = 0x03;
|
||||||
|
uint8_t rf24_RF_CH = 0x02; // Channel
|
||||||
|
uint8_t rf24_RF_SETUP = _BV(RF_DR_HIGH) | _BV(RF_PWR_LOW) | _BV(RF_PWR_HIGH);
|
||||||
|
uint8_t rf24_FEATURE = 0;
|
||||||
|
uint8_t rf24_DYNPD= 0;
|
||||||
|
uint8_t rf24_RX_PW[6] = { 32,32,0,0,0,0 };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void inline rf24_ceHi(){
|
||||||
|
//CE_PIN_PORT |= _BV(CE_PIN_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void inline rf24_ceLow(){
|
||||||
|
//CE_PIN_PORT &= ~_BV(CE_PIN_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void inline rf24_csnHi(){
|
||||||
|
CSN_PIN_PORT |= _BV(CSN_PIN_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void inline rf24_csnLow(){
|
||||||
|
CSN_PIN_PORT &= ~_BV(CSN_PIN_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf24_init()
|
||||||
|
{
|
||||||
|
//CE_PIN_DDR |= _BV(CE_PIN_BIT);
|
||||||
|
CSN_PIN_DDR |= _BV(CSN_PIN_BIT);
|
||||||
|
|
||||||
|
rf24_ceLow();
|
||||||
|
rf24_csnHi();
|
||||||
|
|
||||||
|
// Initialize spi module
|
||||||
|
spi_begin();
|
||||||
|
_delay_ms(2);
|
||||||
|
rf24_configure();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void inline rf24_transferSync(uint8_t *dataout,uint8_t *datain,uint8_t len){
|
||||||
|
uint8_t i;
|
||||||
|
for(i = 0;i < len;i++){
|
||||||
|
datain[i] = spi_transfer(dataout[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void inline rf24_transmitSync(uint8_t *dataout,uint8_t len){
|
||||||
|
uint8_t i;
|
||||||
|
for(i = 0;i < len;i++){
|
||||||
|
spi_transfer(dataout[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void inline rf24_configRegister(uint8_t reg, uint8_t value)
|
||||||
|
// Clocks only one byte into the given MiRF register
|
||||||
|
{
|
||||||
|
rf24_csnLow();
|
||||||
|
spi_transfer(W_REGISTER | (REGISTER_MASK & reg));
|
||||||
|
spi_transfer(value);
|
||||||
|
rf24_csnHi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void inline rf24_readRegister(uint8_t reg, uint8_t * value, uint8_t len)
|
||||||
|
// Reads an array of bytes from the given start position in the MiRF registers.
|
||||||
|
{
|
||||||
|
rf24_csnLow();
|
||||||
|
spi_transfer(R_REGISTER | (REGISTER_MASK & reg));
|
||||||
|
rf24_transferSync(value,value,len);
|
||||||
|
rf24_csnHi();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void inline rf24_writeRegister(uint8_t reg, uint8_t * value, uint8_t len)
|
||||||
|
// Writes an array of bytes into inte the MiRF registers.
|
||||||
|
{
|
||||||
|
rf24_csnLow();
|
||||||
|
spi_transfer(W_REGISTER | (REGISTER_MASK & reg));
|
||||||
|
rf24_transmitSync(value,len);
|
||||||
|
rf24_csnHi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf24_getData(uint8_t * data,uint8_t len)
|
||||||
|
{
|
||||||
|
rf24_csnLow(); // Pull down chip select
|
||||||
|
spi_transfer( R_RX_PAYLOAD ); // Send cmd to read rx payload
|
||||||
|
rf24_transferSync(data,data,len); // Read payload
|
||||||
|
rf24_csnHi(); // Pull up chip select
|
||||||
|
// NVI: per product spec, p 67, note c:
|
||||||
|
// "The RX_DR IRQ is asserted by a new packet arrival event. The procedure
|
||||||
|
// for handling this interrupt should be: 1) read payload through SPI,
|
||||||
|
// 2) clear RX_DR IRQ, 3) read FIFO_STATUS to check if there are more
|
||||||
|
// payloads available in RX FIFO, 4) if there are more data in RX FIFO,
|
||||||
|
// repeat from step 1)."
|
||||||
|
// So if we're going to clear RX_DR here, we need to check the RX FIFO
|
||||||
|
// in the dataReady() function
|
||||||
|
rf24_configRegister(STATUS,(1<<RX_DR)); // Reset status register
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t rf24_getDataDL(uint8_t * data,uint8_t len)
|
||||||
|
// Reads payload bytes into data array
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t to_read;
|
||||||
|
|
||||||
|
rf24_csnLow(); // Pull down chip select
|
||||||
|
spi_transfer( R_RX_PL_WID ); // Send cmd to read rx payload len
|
||||||
|
to_read = spi_transfer(0); // Read payload
|
||||||
|
rf24_csnHi(); // Pull up chip select
|
||||||
|
|
||||||
|
if(len>to_read && to_read>0 ) len=to_read;
|
||||||
|
|
||||||
|
rf24_csnLow(); // Pull down chip select
|
||||||
|
spi_transfer( R_RX_PAYLOAD ); // Send cmd to read rx payload
|
||||||
|
rf24_transferSync(data,data,len); // Read payload
|
||||||
|
|
||||||
|
if(to_read!=len){
|
||||||
|
to_read-=len;
|
||||||
|
while((to_read--)>0) // read remaining
|
||||||
|
spi_transfer(0);
|
||||||
|
}
|
||||||
|
rf24_csnHi(); // Pull up chip select
|
||||||
|
// NVI: per product spec, p 67, note c:
|
||||||
|
// "The RX_DR IRQ is asserted by a new packet arrival event. The procedure
|
||||||
|
// for handling this interrupt should be: 1) read payload through SPI,
|
||||||
|
// 2) clear RX_DR IRQ, 3) read FIFO_STATUS to check if there are more
|
||||||
|
// payloads available in RX FIFO, 4) if there are more data in RX FIFO,
|
||||||
|
// repeat from step 1)."
|
||||||
|
// So if we're going to clear RX_DR here, we need to check the RX FIFO
|
||||||
|
// in the dataReady() function
|
||||||
|
rf24_configRegister(STATUS,(1<<RX_DR)); // Reset status register
|
||||||
|
return to_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t inline rf24_dataReady()
|
||||||
|
// Checks if data is available for reading
|
||||||
|
{
|
||||||
|
// See note in getData() function - just checking RX_DR isn't good enough
|
||||||
|
uint8_t status = rf24_getStatus();
|
||||||
|
|
||||||
|
// We can short circuit on RX_DR, but if it's not set, we still need
|
||||||
|
// to check the FIFO for any pending packets
|
||||||
|
if ( status & (1 << RX_DR) ) return 1;
|
||||||
|
return !rf24_rxFifoEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t inline rf24_rxFifoEmpty(){
|
||||||
|
uint8_t fifoStatus;
|
||||||
|
|
||||||
|
rf24_readRegister(FIFO_STATUS,&fifoStatus,sizeof(fifoStatus));
|
||||||
|
return (fifoStatus & (1 << RX_EMPTY));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rf24_send(uint8_t * value,uint8_t len)
|
||||||
|
// Sends a data package to the default address. Be sure to send the correct
|
||||||
|
// amount of bytes as configured as payload on the receiver.
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
status = rf24_getStatus();
|
||||||
|
|
||||||
|
if((status & ((1 << TX_DS) | (1 << MAX_RT)))){
|
||||||
|
rf24_configRegister(STATUS,(1 << TX_DS) | (1 << MAX_RT));
|
||||||
|
}
|
||||||
|
|
||||||
|
rf24_ceLow();
|
||||||
|
|
||||||
|
rf24_powerUpTx(); // Set to transmitter mode , Power up
|
||||||
|
|
||||||
|
rf24_csnLow(); // Pull down chip select
|
||||||
|
spi_transfer( FLUSH_TX ); // Write cmd to flush tx fifo
|
||||||
|
rf24_csnHi(); // Pull up chip select
|
||||||
|
|
||||||
|
rf24_csnLow(); // Pull down chip select
|
||||||
|
spi_transfer( W_TX_PAYLOAD ); // Write cmd to write payload
|
||||||
|
rf24_transmitSync(value,len); // Write payload
|
||||||
|
rf24_csnHi(); // Pull up chip select
|
||||||
|
|
||||||
|
rf24_ceHi(); // Start transmission
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t inline rf24_isSending(){
|
||||||
|
uint8_t status;
|
||||||
|
if(PTX){
|
||||||
|
status = rf24_getStatus();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if sending successful (TX_DS) or max retries exceded (MAX_RT).
|
||||||
|
*/
|
||||||
|
|
||||||
|
if((status & ((1 << TX_DS) | (1 << MAX_RT)))){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t inline rf24_getStatus(){
|
||||||
|
uint8_t rv;
|
||||||
|
rf24_csnLow();
|
||||||
|
rv=spi_transfer(NOP);
|
||||||
|
rf24_csnHi();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void inline rf24_powerUpRx(){
|
||||||
|
PTX = 0;
|
||||||
|
rf24_ceLow();
|
||||||
|
rf24_configRegister(CONFIG, rf24_CONFIG | ( (1<<PWR_UP) | (1<<PRIM_RX) ) );
|
||||||
|
rf24_ceHi();
|
||||||
|
rf24_configRegister(STATUS,(1 << TX_DS) | (1 << MAX_RT));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void inline rf24_flushRx(){
|
||||||
|
rf24_csnLow();
|
||||||
|
spi_transfer( FLUSH_RX );
|
||||||
|
rf24_csnHi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void inline rf24_powerUpTx(){
|
||||||
|
PTX = 1;
|
||||||
|
rf24_configRegister(CONFIG, rf24_CONFIG | ( (1<<PWR_UP) | (0<<PRIM_RX) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void inline rf24_powerDown(){
|
||||||
|
rf24_ceLow();
|
||||||
|
rf24_configRegister(CONFIG, rf24_CONFIG );
|
||||||
|
}
|
||||||
|
|
||||||
|
void rf24_configure(){
|
||||||
|
uint8_t data;
|
||||||
|
rf24_configRegister(CONFIG,rf24_CONFIG);
|
||||||
|
rf24_configRegister(FEATURE,rf24_FEATURE);
|
||||||
|
// Check Feature register ...
|
||||||
|
rf24_readRegister(FEATURE,&data,1);
|
||||||
|
if(rf24_FEATURE != data){ // ACTIVATE & retry
|
||||||
|
rf24_csnLow();
|
||||||
|
spi_transfer(ACTIVATE);
|
||||||
|
spi_transfer(0x73);
|
||||||
|
rf24_csnHi();
|
||||||
|
rf24_configRegister(FEATURE,rf24_FEATURE);
|
||||||
|
}
|
||||||
|
rf24_configRegister(EN_AA,rf24_EN_AA);
|
||||||
|
rf24_configRegister(EN_RXADDR,rf24_EN_RXADDR);
|
||||||
|
rf24_configRegister(SETUP_AW,rf24_SETUP_AW);
|
||||||
|
rf24_configRegister(SETUP_RETR,rf24_SETUP_RETR);
|
||||||
|
rf24_configRegister(RF_CH,rf24_RF_CH);
|
||||||
|
rf24_configRegister(RF_SETUP,rf24_RF_SETUP);
|
||||||
|
rf24_configRegister(DYNPD,rf24_DYNPD);
|
||||||
|
|
||||||
|
for(int i=0; i<6;i++)
|
||||||
|
rf24_configRegister(RX_PW_P0+i,rf24_RX_PW[i]);
|
||||||
|
|
||||||
|
}
|
||||||
72
rf24.h
Normal file
72
rf24.h
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
#include "nRF24L01.h"
|
||||||
|
#include "spi.h"
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void rf24_init();
|
||||||
|
|
||||||
|
void rf24_configRegister(uint8_t reg, uint8_t value);
|
||||||
|
void rf24_readRegister(uint8_t reg, uint8_t * value, uint8_t len);
|
||||||
|
void rf24_writeRegister(uint8_t reg, uint8_t * value, uint8_t len);
|
||||||
|
|
||||||
|
void rf24_getData(uint8_t * data,uint8_t len);
|
||||||
|
uint8_t rf24_getDataDL(uint8_t * data,uint8_t len);
|
||||||
|
uint8_t rf24_dataReady();
|
||||||
|
uint8_t rf24_rxFifoEmpty();
|
||||||
|
|
||||||
|
|
||||||
|
void rf24_send(uint8_t * value,uint8_t len);
|
||||||
|
uint8_t rf24_isSending();
|
||||||
|
uint8_t rf24_getStatus();
|
||||||
|
|
||||||
|
void rf24_powerUpRx();
|
||||||
|
void rf24_powerUpTx();
|
||||||
|
void rf24_powerDown();
|
||||||
|
void rf24_flushRx();
|
||||||
|
void rf24_configure();
|
||||||
|
|
||||||
|
|
||||||
|
extern uint8_t rf24_CONFIG;
|
||||||
|
extern uint8_t rf24_EN_AA;
|
||||||
|
extern uint8_t rf24_EN_RXADDR;
|
||||||
|
extern uint8_t rf24_SETUP_AW;
|
||||||
|
extern uint8_t rf24_SETUP_RETR;
|
||||||
|
extern uint8_t rf24_RF_CH;
|
||||||
|
extern uint8_t rf24_RF_SETUP;
|
||||||
|
extern uint8_t rf24_FEATURE;
|
||||||
|
extern uint8_t rf24_DYNPD;
|
||||||
|
extern uint8_t rf24_RX_PW[6];
|
||||||
|
|
||||||
|
#if defined (__AVR_ATtiny84__) || defined (__AVR_ATtiny84A__)
|
||||||
|
|
||||||
|
#define CE_PIN_PORT UNDEF
|
||||||
|
#define CE_PIN_DDR UNDEF
|
||||||
|
#define CE_PIN_BIT UNDEF
|
||||||
|
|
||||||
|
#define CSN_PIN_PORT PORTB
|
||||||
|
#define CSN_PIN_DDR DDRB
|
||||||
|
#define CSN_PIN_BIT PB2
|
||||||
|
|
||||||
|
#elif defined(__AVR_ATmega32U4__)
|
||||||
|
|
||||||
|
#define CE_PIN_PORT PORTD
|
||||||
|
#define CE_PIN_DDR DDRD
|
||||||
|
#define CE_PIN_BIT PD4
|
||||||
|
|
||||||
|
#define CSN_PIN_PORT PORTC
|
||||||
|
#define CSN_PIN_DDR DDRC
|
||||||
|
#define CSN_PIN_BIT PC6
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
79
spi.c
Normal file
79
spi.c
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
#include "spi.h"
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
|
||||||
|
void spi_begin() {
|
||||||
|
#if defined(SPCR)
|
||||||
|
#error to write ...
|
||||||
|
// Set SS to high so a connected chip will be "deselected" by default
|
||||||
|
digitalWrite(SS, HIGH);
|
||||||
|
// When the SS pin is set as OUTPUT, it can be used as
|
||||||
|
// a general purpose output port (it doesn't influence
|
||||||
|
// SPI operations).
|
||||||
|
pinMode(SS, OUTPUT);
|
||||||
|
// Warning: if the SS pin ever becomes a LOW INPUT then SPI
|
||||||
|
// automatically switches to Slave, so the data direction of
|
||||||
|
// the SS pin MUST be kept as OUTPUT.
|
||||||
|
SPCR |= _BV(MSTR);
|
||||||
|
SPCR |= _BV(SPE);
|
||||||
|
// Set direction register for SCK and MOSI pin.
|
||||||
|
// MISO pin automatically overrides to INPUT.
|
||||||
|
// By doing this AFTER enabling SPI, we avoid accidentally
|
||||||
|
// clocking in a single bit since the lines go directly
|
||||||
|
// from "input" to SPI control.
|
||||||
|
// http://code.google.com/p/arduino/issues/detail?id=888
|
||||||
|
pinMode(SCK, OUTPUT);
|
||||||
|
pinMode(MOSI, OUTPUT);
|
||||||
|
#else
|
||||||
|
PRR &= ~(_BV(PRUSI));
|
||||||
|
USICR = _BV(USIWM0);
|
||||||
|
USCK_DDR |= _BV(USCK_BIT); //set the USCK pin as output
|
||||||
|
DO_DDR |= _BV(DO_BIT); //set the DO pin as output
|
||||||
|
DI_DDR &= ~_BV(DI_BIT); //set the DI pin as input
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t spi_transfer(uint8_t b) {
|
||||||
|
#if defined(SPCR)
|
||||||
|
SPDR = b;
|
||||||
|
while (!(SPSR & _BV(SPIF)));
|
||||||
|
return SPDR;
|
||||||
|
#else
|
||||||
|
USIDR = b;
|
||||||
|
USISR = _BV(USIOIF);
|
||||||
|
do {
|
||||||
|
USICR = _BV(USIWM0) | _BV(USICS1) | _BV(USICLK) | _BV(USITC);
|
||||||
|
// _delay_ms(1);
|
||||||
|
}while ((USISR & _BV(USIOIF)) == 0);
|
||||||
|
return USIDR;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void spi_end() {
|
||||||
|
#if defined(SPCR)
|
||||||
|
SPCR &= ~_BV(SPE);
|
||||||
|
#else
|
||||||
|
USICR &= ~(_BV(USIWM1) | _BV(USIWM0));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void spi_setBitOrder(uint8_t bitOrder)
|
||||||
|
{
|
||||||
|
#if defined(SPCR)
|
||||||
|
if(bitOrder == LSBFIRST) {
|
||||||
|
SPCR |= _BV(DORD);
|
||||||
|
} else {
|
||||||
|
SPCR &= ~(_BV(DORD));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void spi_setDataMode(uint8_t mode)
|
||||||
|
{
|
||||||
|
#if defined(SPCR)
|
||||||
|
SPCR = (SPCR & ~SPI_MODE_MASK) | mode;
|
||||||
|
#else
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
29
spi.h
Normal file
29
spi.h
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef tinySPI_h
|
||||||
|
#define tinySPI_h
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <util/atomic.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//SPI data modes
|
||||||
|
#define SPI_MODE0 0x00
|
||||||
|
#define SPI_MODE1 0x04
|
||||||
|
|
||||||
|
void spi_begin(void);
|
||||||
|
void spi_setDataMode(uint8_t spiDataMode);
|
||||||
|
uint8_t spi_transfer(uint8_t spiData);
|
||||||
|
void spi_end(void);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
76
uart.S
Normal file
76
uart.S
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
//UART Functions per AVR Application Note #305
|
||||||
|
#include <avr/io.h>
|
||||||
|
//#include "uLogTimer.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
//half bit delay
|
||||||
|
//
|
||||||
|
//#define b 31 //38400 bps@8MHz with 0.3% error
|
||||||
|
#define b 66 //19200 bps@8MHz with 0.6% error
|
||||||
|
UARTDelay:
|
||||||
|
ldi r17, b
|
||||||
|
UARTDelay1:
|
||||||
|
dec r17
|
||||||
|
brne UARTDelay1
|
||||||
|
ret
|
||||||
|
|
||||||
|
//
|
||||||
|
//asynchronous 8n1 serial transmit byte
|
||||||
|
//
|
||||||
|
#define TX_PIN 6 //TX pin is PA6
|
||||||
|
|
||||||
|
.global SerialPutChar
|
||||||
|
SerialPutChar:
|
||||||
|
push r16
|
||||||
|
push r17
|
||||||
|
ldi r16, 10 ;1 start + 8 data + 1 stop bits (bit count)
|
||||||
|
com r24 ;Invert it (r24 = xmit byte)
|
||||||
|
sec ;Start bit
|
||||||
|
putchar0:
|
||||||
|
brcc putchar1 ;If carry set
|
||||||
|
cbi _SFR_IO_ADDR(PORTB), PB0 ;send a '0'
|
||||||
|
rjmp putchar2 ;else
|
||||||
|
putchar1:
|
||||||
|
sbi _SFR_IO_ADDR(PORTB), PB0 ;send a '1'
|
||||||
|
nop
|
||||||
|
putchar2:
|
||||||
|
rcall UARTDelay ;1/2 bit delay +
|
||||||
|
rcall UARTDelay ;1/2 bit delay = 1bit delay
|
||||||
|
lsr r24 ;Get next bit
|
||||||
|
dec r16 ;If not all bits sent
|
||||||
|
brne putchar0 ;send next
|
||||||
|
;else
|
||||||
|
pop r17
|
||||||
|
pop r16
|
||||||
|
ret ;return
|
||||||
|
|
||||||
|
//
|
||||||
|
//asynchronous 8n1 serial receive byte
|
||||||
|
//
|
||||||
|
#define RX_PIN 5 //RX pin is PA5
|
||||||
|
|
||||||
|
.global SerialGetChar
|
||||||
|
SerialGetChar:
|
||||||
|
push r16
|
||||||
|
push r17
|
||||||
|
ldi r16, 9 ;8 data bits + 1 stop bit
|
||||||
|
getchar1:
|
||||||
|
sbic _SFR_IO_ADDR(PINB), PB1 ;Wait for start bit
|
||||||
|
rjmp getchar1
|
||||||
|
rcall UARTDelay ;1.5bit delay after start bit edge
|
||||||
|
getchar2:
|
||||||
|
rcall UARTDelay ;1 bit delay from here
|
||||||
|
rcall UARTDelay
|
||||||
|
clc ;clear carry
|
||||||
|
sbic _SFR_IO_ADDR(PINB), PB1 ;if RX pin high
|
||||||
|
sec ;
|
||||||
|
dec r16 ;If bit is stop bit
|
||||||
|
breq getchar3 ; return
|
||||||
|
;else
|
||||||
|
ror r24 ; shift bit into r24 (rec'd byte)
|
||||||
|
rjmp getchar2 ; go get next
|
||||||
|
getchar3:
|
||||||
|
ldi r25, 0x00 ;zero extend r24:r25 for return
|
||||||
|
pop r17
|
||||||
|
pop r16
|
||||||
|
ret
|
||||||
4
uart.h
Normal file
4
uart.h
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
//asynchronous 8n1 serial transmission per AVR AppNote #305
|
||||||
|
void SerialPutChar (char);
|
||||||
|
char SerialGetChar(void);
|
||||||
|
|
||||||
Loading…
Reference in a new issue