commit aad2cc40d4e2dfc6e4ec86595f5d7dcdc7533f36 Author: Arnaud Date: Fri Apr 29 11:30:56 2016 +0200 Ajout initial diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a36911e --- /dev/null +++ b/Makefile @@ -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 +# +# - 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 diff --git a/analog.c b/analog.c new file mode 100644 index 0000000..a851376 --- /dev/null +++ b/analog.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#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; +} diff --git a/analog.h b/analog.h new file mode 100644 index 0000000..cbc8ae1 --- /dev/null +++ b/analog.h @@ -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 diff --git a/crc8.h b/crc8.h new file mode 100644 index 0000000..64011ba --- /dev/null +++ b/crc8.h @@ -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; +} diff --git a/debug.c b/debug.c new file mode 100644 index 0000000..5a378db --- /dev/null +++ b/debug.c @@ -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'); + } +} diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..eaaca0e --- /dev/null +++ b/debug.h @@ -0,0 +1,7 @@ +#include "uart.h" +#include +#define DEBUG 1 + + +void debug (char* ptr); +void debughex (char* ptr,uint8_t len); diff --git a/defines.h b/defines.h new file mode 100644 index 0000000..1a30381 --- /dev/null +++ b/defines.h @@ -0,0 +1,47 @@ +#ifndef defines_h +#define defines_h + +#include +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 diff --git a/dht11.c b/dht11.c new file mode 100644 index 0000000..fb1a2f4 --- /dev/null +++ b/dht11.c @@ -0,0 +1,79 @@ +#include "dht11.h" +#include +#include +#include +#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; +} diff --git a/dht11.h b/dht11.h new file mode 100644 index 0000000..94f8d1a --- /dev/null +++ b/dht11.h @@ -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 diff --git a/eeprom b/eeprom new file mode 100644 index 0000000..44a49a3 --- /dev/null +++ b/eeprom @@ -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 diff --git a/eeprom.bin b/eeprom.bin new file mode 100644 index 0000000..28037ec Binary files /dev/null and b/eeprom.bin differ diff --git a/lib/Hamming.c b/lib/Hamming.c new file mode 100644 index 0000000..cb1fba3 --- /dev/null +++ b/lib/Hamming.c @@ -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 + +#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 +} diff --git a/lib/Hamming.h b/lib/Hamming.h new file mode 100644 index 0000000..7778a59 --- /dev/null +++ b/lib/Hamming.h @@ -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 diff --git a/lib/HammingCalculateParityFast.c b/lib/HammingCalculateParityFast.c new file mode 100644 index 0000000..6cc5df6 --- /dev/null +++ b/lib/HammingCalculateParityFast.c @@ -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 + +#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])); +} diff --git a/lib/HammingCalculateParitySmall.c b/lib/HammingCalculateParitySmall.c new file mode 100644 index 0000000..d446f8f --- /dev/null +++ b/lib/HammingCalculateParitySmall.c @@ -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); +} + diff --git a/lib/HammingCalculateParitySmallAndFast.c b/lib/HammingCalculateParitySmallAndFast.c new file mode 100644 index 0000000..ad27bf8 --- /dev/null +++ b/lib/HammingCalculateParitySmallAndFast.c @@ -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 + +#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); +} diff --git a/lib/HammingCalculateParityTextbook.c b/lib/HammingCalculateParityTextbook.c new file mode 100644 index 0000000..08e5cca --- /dev/null +++ b/lib/HammingCalculateParityTextbook.c @@ -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 + + diff --git a/main.c b/main.c new file mode 100644 index 0000000..ba4b47e --- /dev/null +++ b/main.c @@ -0,0 +1,277 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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(); + } +} + diff --git a/nRF24L01.h b/nRF24L01.h new file mode 100644 index 0000000..2012ce6 --- /dev/null +++ b/nRF24L01.h @@ -0,0 +1,125 @@ +/* + Copyright (c) 2007 Stefan Engelke + + 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 diff --git a/onewire.c b/onewire.c new file mode 100644 index 0000000..74d81bc --- /dev/null +++ b/onewire.c @@ -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 +#include +#include +#include + +#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< 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; +} diff --git a/onewire.h b/onewire.h new file mode 100644 index 0000000..5b497fe --- /dev/null +++ b/onewire.h @@ -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__ diff --git a/rf24.c b/rf24.c new file mode 100644 index 0000000..69f4150 --- /dev/null +++ b/rf24.c @@ -0,0 +1,270 @@ + +#include "rf24.h" +#include + + +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<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< +#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 + diff --git a/spi.c b/spi.c new file mode 100644 index 0000000..cb4a1b8 --- /dev/null +++ b/spi.c @@ -0,0 +1,79 @@ +#include "spi.h" +#include + + +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 +} + diff --git a/spi.h b/spi.h new file mode 100644 index 0000000..eabdb91 --- /dev/null +++ b/spi.h @@ -0,0 +1,29 @@ +#ifndef tinySPI_h +#define tinySPI_h + +#include +#include +#include + +#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 + + diff --git a/uart.S b/uart.S new file mode 100644 index 0000000..c8e59ee --- /dev/null +++ b/uart.S @@ -0,0 +1,76 @@ +//UART Functions per AVR Application Note #305 +#include +//#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 diff --git a/uart.h b/uart.h new file mode 100644 index 0000000..4c42557 --- /dev/null +++ b/uart.h @@ -0,0 +1,4 @@ +//asynchronous 8n1 serial transmission per AVR AppNote #305 +void SerialPutChar (char); +char SerialGetChar(void); +