diff --git a/Rmodule/default/Makefile b/Rmodule/default/Makefile new file mode 100644 index 0000000..f3bb8d5 --- /dev/null +++ b/Rmodule/default/Makefile @@ -0,0 +1,86 @@ +############################################################################### +# Makefile for the project Rmodule +############################################################################### + +## General Flags +PROJECT = Rmodule +MCU = atmega8 +TARGET = Rmodule.elf +CC = avr-gcc + +CPP = avr-g++ + +## Options common to compile, link and assembly rules +COMMON = -mmcu=$(MCU) + +## Compile options common for all C compilation units. +CFLAGS = $(COMMON) +CFLAGS += -Wall -gdwarf-2 -std=gnu99 -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d + +## Assembly specific flags +ASMFLAGS = $(COMMON) +ASMFLAGS += $(CFLAGS) +ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2 + +## Linker flags +LDFLAGS = $(COMMON) +LDFLAGS += -Wl,-Map=Rmodule.map + + +## Intel Hex file production flags +HEX_FLASH_FLAGS = -R .eeprom -R .fuse -R .lock -R .signature + +HEX_EEPROM_FLAGS = -j .eeprom +HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load" +HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings + + +## Objects that must be built in order to link +OBJECTS = main.o uart.o onewire.o uart_addon.o + +## Objects explicitly added by the user +LINKONLYOBJECTS = + +## Build +all: $(TARGET) Rmodule.hex Rmodule.eep Rmodule.lss size + +## Compile +main.o: ../main.c + $(CC) $(INCLUDES) $(CFLAGS) -c $< + +uart.o: ../uart/uart.c + $(CC) $(INCLUDES) $(CFLAGS) -c $< + +onewire.o: ../onewire/onewire.c + $(CC) $(INCLUDES) $(CFLAGS) -c $< + +uart_addon.o: ../uart/uart_addon.c + $(CC) $(INCLUDES) $(CFLAGS) -c $< + +##Link +$(TARGET): $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) $(LINKONLYOBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET) + +%.hex: $(TARGET) + avr-objcopy -O ihex $(HEX_FLASH_FLAGS) $< $@ + +%.eep: $(TARGET) + -avr-objcopy $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0 + +%.lss: $(TARGET) + avr-objdump -h -S $< > $@ + +size: ${TARGET} + @echo + @avr-size -C --mcu=${MCU} ${TARGET} + +## Clean target +.PHONY: clean +clean: + -rm -rf $(OBJECTS) Rmodule.elf dep/* Rmodule.hex Rmodule.eep Rmodule.lss Rmodule.map + + +## Other dependencies +-include $(shell mkdir dep 2>NUL) $(wildcard dep/*) + diff --git a/Rmodule/main.c b/Rmodule/main.c new file mode 100644 index 0000000..824a365 --- /dev/null +++ b/Rmodule/main.c @@ -0,0 +1,62 @@ +// Прошивка для удаленного радиомодуля + +#include +#include +#include +#include "uart/uart.h" +#include "uart/uart_addon.h" +#include "res/strings.h" +#include "onewire/onewire.h" + + +#define UART_BAUD_RATE 19200 + +unsigned char getcmd(void){ + unsigned int res; + do{ + res = uart_getc(); + } while(res & UART_NO_DATA); + return (unsigned char) res; +} + +void getListDevices(void){ + uint8_t i; + uint8_t id[OW_ROMCODE_SIZE]; + uint8_t diff, nSensors; + + uart_puts_p("\r\nScanning 1-wire bus\r\n"); + ow_reset(); + nSensors = 0; + diff = OW_SEARCH_FIRST; + while ( diff != OW_LAST_DEVICE) { + diff = ow_rom_search( diff, &id[0] ); + if ( diff != OW_PRESENCE_ERR && diff != OW_DATA_ERR && diff != OW_LAST_DEVICE ) { + for ( i=0; i < OW_ROMCODE_SIZE; i++ ){ + uart_puthex_byte(id[i]); + uart_puts_p( " " ); + } + uart_puts("\r\n"); + } + nSensors++; + } +} + +int main(void) +{ + uart_init(UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU)); + char cmd = '0'; + while (cmd != 'q'){ + uart_puts_p(MainMenuItemTitle); + uart_puts_p(MainMenuItem1); + uart_puts_p(MainMenuItem2); + uart_puts_p(MainMenuItemQuit); + uart_puts_p(MainMenuItemPrompt); + cmd = getcmd(); + if (cmd == '1'){ + getListDevices(); + } + } + + while(1){ } + +} diff --git a/Rmodule/onewire/crc8.c b/Rmodule/onewire/crc8.c new file mode 100644 index 0000000..6a0fc00 --- /dev/null +++ b/Rmodule/onewire/crc8.c @@ -0,0 +1,63 @@ +/* please read copyright-notice at EOF */ + +#include + +#define CRC8INIT 0x00 +#define CRC8POLY 0x18 //0X18 = X^8+X^5+X^4+X^0 + +uint8_t crc8( uint8_t *data, uint16_t number_of_bytes_in_data ) +{ + uint8_t crc; + uint16_t loop_count; + uint8_t bit_counter; + uint8_t b; + uint8_t feedback_bit; + + crc = CRC8INIT; + + for (loop_count = 0; loop_count != number_of_bytes_in_data; loop_count++) + { + b = data[loop_count]; + + bit_counter = 8; + do { + feedback_bit = (crc ^ b) & 0x01; + + if ( feedback_bit == 0x01 ) { + crc = crc ^ CRC8POLY; + } + crc = (crc >> 1) & 0x7F; + if ( feedback_bit == 0x01 ) { + crc = crc | 0x80; + } + + b = b >> 1; + bit_counter--; + + } while (bit_counter > 0); + } + + return crc; +} + +/* +This code is from Colin O'Flynn - Copyright (c) 2002 +only minor changes by M.Thomas 9/2004 + +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. +*/ diff --git a/Rmodule/onewire/crc8.h b/Rmodule/onewire/crc8.h new file mode 100644 index 0000000..bf82365 --- /dev/null +++ b/Rmodule/onewire/crc8.h @@ -0,0 +1,40 @@ +#ifndef CRC8_H_ +#define CRC8_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +uint8_t crc8( uint8_t* data, uint16_t number_of_bytes_in_data ); + +#ifdef __cplusplus +} +#endif + +#endif + +/* +This is based on code from : + +Copyright (c) 2002 Colin O'Flynn + +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. +*/ + diff --git a/Rmodule/onewire/onewire.c b/Rmodule/onewire/onewire.c new file mode 100644 index 0000000..de131ea --- /dev/null +++ b/Rmodule/onewire/onewire.c @@ -0,0 +1,287 @@ +/* +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 "onewire.h" + +#ifdef OW_ONE_BUS + +#define OW_GET_IN() ( OW_IN & (1< 1usec accoding to timing-diagramm + if ( b ) { + OW_DIR_IN(); // to write "1" release bus, resistor pulls high +#if OW_USE_INTERNAL_PULLUP + OW_OUT_HIGH(); +#endif + } + + // "Output data from the DS18B20 is valid for 15usec after the falling + // edge that initiated the read time slot. Therefore, the master must + // release the bus and then sample the bus state within 15ussec from + // the start of the slot." + _delay_us(15-2-OW_CONF_DELAYOFFSET); + + if( OW_GET_IN() == 0 ) { + b = 0; // sample at end of read-timeslot + } + + _delay_us(60-15-2+OW_CONF_DELAYOFFSET); +#if OW_USE_INTERNAL_PULLUP + OW_OUT_HIGH(); +#endif + OW_DIR_IN(); + + if ( with_parasite_enable ) { + ow_parasite_enable(); + } + + } /* ATOMIC_BLOCK */ + + _delay_us(OW_RECOVERY_TIME); // may be increased for longer wires + + return b; +} + +uint8_t ow_bit_io( uint8_t b ) +{ + return ow_bit_io_intern( b & 1, 0 ); +} + +uint8_t ow_byte_wr( uint8_t b ) +{ + uint8_t i = 8, j; + + do { + j = ow_bit_io( b & 1 ); + b >>= 1; + if( j ) { + b |= 0x80; + } + } while( --i ); + + return b; +} + +uint8_t ow_byte_wr_with_parasite_enable( uint8_t b ) +{ + uint8_t i = 8, j; + + do { + if ( i != 1 ) { + j = ow_bit_io_intern( b & 1, 0 ); + } else { + j = ow_bit_io_intern( b & 1, 1 ); + } + b >>= 1; + if( j ) { + b |= 0x80; + } + } while( --i ); + + return b; +} + + +uint8_t ow_byte_rd( void ) +{ + // read by sending only "1"s, so bus gets released + // after the init low-pulse in every slot + return ow_byte_wr( 0xFF ); +} + + +uint8_t ow_rom_search( uint8_t diff, uint8_t *id ) +{ + uint8_t i, j, next_diff; + uint8_t b; + + if( ow_reset() ) { + return OW_PRESENCE_ERR; // error, no device found <--- early exit! + } + + ow_byte_wr( OW_SEARCH_ROM ); // ROM search command + next_diff = OW_LAST_DEVICE; // unchanged on last device + + i = OW_ROMCODE_SIZE * 8; // 8 bytes + + do { + j = 8; // 8 bits + do { + b = ow_bit_io( 1 ); // read bit + if( ow_bit_io( 1 ) ) { // read complement bit + if( b ) { // 0b11 + return OW_DATA_ERR; // data error <--- early exit! + } + } + else { + if( !b ) { // 0b00 = 2 devices + if( diff > i || ((*id & 1) && diff != i) ) { + b = 1; // now 1 + next_diff = i; // next pass 0 + } + } + } + ow_bit_io( b ); // write bit + *id >>= 1; + if( b ) { + *id |= 0x80; // store bit + } + + i--; + + } while( --j ); + + id++; // next byte + + } while( i ); + + return next_diff; // to continue search +} + + +static void ow_command_intern( uint8_t command, uint8_t *id, uint8_t with_parasite_enable ) +{ + uint8_t i; + + ow_reset(); + + if( id ) { + ow_byte_wr( OW_MATCH_ROM ); // to a single device + i = OW_ROMCODE_SIZE; + do { + ow_byte_wr( *id ); + id++; + } while( --i ); + } + else { + ow_byte_wr( OW_SKIP_ROM ); // to all devices + } + + if ( with_parasite_enable ) { + ow_byte_wr_with_parasite_enable( command ); + } else { + ow_byte_wr( command ); + } +} + +void ow_command( uint8_t command, uint8_t *id ) +{ + ow_command_intern( command, id, 0); +} + +void ow_command_with_parasite_enable( uint8_t command, uint8_t *id ) +{ + ow_command_intern( command, id, 1 ); +} + diff --git a/Rmodule/onewire/onewire.h b/Rmodule/onewire/onewire.h new file mode 100644 index 0000000..5f25f8a --- /dev/null +++ b/Rmodule/onewire/onewire.h @@ -0,0 +1,93 @@ +#ifndef ONEWIRE_H_ +#define ONEWIRE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/*******************************************/ +/* Hardware connection */ +/*******************************************/ + +/* Define OW_ONE_BUS if only one 1-Wire-Bus is used + in the application -> shorter code. + If not defined make sure to call ow_set_bus() before using + a bus. Runtime bus-select increases code size by around 300 + bytes so use OW_ONE_BUS if possible */ +// #define OW_ONE_BUS + +#ifdef OW_ONE_BUS + +#define OW_PIN PD6 +#define OW_IN PIND +#define OW_OUT PORTD +#define OW_DDR DDRD +#define OW_CONF_DELAYOFFSET 0 + +#else +#if ( F_CPU < 1843200 ) +#warning | Experimental multi-bus-mode is not tested for +#warning | frequencies below 1,84MHz. Use OW_ONE_WIRE or +#warning | faster clock-source (i.e. internal 2MHz R/C-Osc.). +#endif +#define OW_CONF_CYCLESPERACCESS 13 +#define OW_CONF_DELAYOFFSET ( (uint16_t)( ((OW_CONF_CYCLESPERACCESS) * 1000000L) / F_CPU ) ) +#endif + +// Recovery time (T_Rec) minimum 1usec - increase for long lines +// 5 usecs is a value give in some Maxim AppNotes +// 30u secs seem to be reliable for longer lines +//#define OW_RECOVERY_TIME 5 /* usec */ +//#define OW_RECOVERY_TIME 300 /* usec */ +#define OW_RECOVERY_TIME 10 /* usec */ + +// Use AVR's internal pull-up resistor instead of external 4,7k resistor. +// Based on information from Sascha Schade. Experimental but worked in tests +// with one DS18B20 and one DS18S20 on a rather short bus (60cm), where both +// sensores have been parasite-powered. +#define OW_USE_INTERNAL_PULLUP 1 /* 0=external, 1=internal */ + +/*******************************************/ + + +#define OW_MATCH_ROM 0x55 +#define OW_SKIP_ROM 0xCC +#define OW_SEARCH_ROM 0xF0 + +#define OW_SEARCH_FIRST 0xFF // start new search +#define OW_PRESENCE_ERR 0xFF +#define OW_DATA_ERR 0xFE +#define OW_LAST_DEVICE 0x00 // last device found + +// rom-code size including CRC +#define OW_ROMCODE_SIZE 8 + +extern uint8_t ow_reset(void); + +extern uint8_t ow_bit_io( uint8_t b ); +extern uint8_t ow_byte_wr( uint8_t b ); +extern uint8_t ow_byte_rd( void ); + +extern uint8_t ow_rom_search( uint8_t diff, uint8_t *id ); + +extern void ow_command( uint8_t command, uint8_t *id ); +extern void ow_command_with_parasite_enable( uint8_t command, uint8_t *id ); + +extern void ow_parasite_enable( void ); +extern void ow_parasite_disable( void ); +extern uint8_t ow_input_pin_state( void ); + +#ifndef OW_ONE_BUS +extern void ow_set_bus( volatile uint8_t* in, + volatile uint8_t* out, + volatile uint8_t* ddr, + uint8_t pin ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Rmodule/res/strings.h b/Rmodule/res/strings.h new file mode 100644 index 0000000..84fcbe2 --- /dev/null +++ b/Rmodule/res/strings.h @@ -0,0 +1,10 @@ +#include + +// Главное меню +const char MainMenuItemTitle[] PROGMEM = "\r\n---==== Main menu ---"; +const char MainMenuItem1[] PROGMEM = "\r\n1) List devices"; +const char MainMenuItem2[] PROGMEM = "\r\n2) Selected device : "; +const char MainMenuItemQuit[] PROGMEM = "\r\nq) Quit"; +const char MainMenuItemPrompt[] PROGMEM = "\r\n# "; + + diff --git a/Rmodule/rmodule.aws b/Rmodule/rmodule.aws new file mode 100644 index 0000000..c41f4a0 --- /dev/null +++ b/Rmodule/rmodule.aws @@ -0,0 +1 @@ + diff --git a/Rmodule/uart/uart.c b/Rmodule/uart/uart.c new file mode 100644 index 0000000..3cb2a81 --- /dev/null +++ b/Rmodule/uart/uart.c @@ -0,0 +1,663 @@ +/************************************************************************* +Title: Interrupt UART library with receive/transmit circular buffers +Author: Peter Fleury http://jump.to/fleury +File: $Id: uart.c,v 1.10 2013/06/02 07:27:04 peter Exp $ +Software: AVR-GCC 4.1, AVR Libc 1.4.6 or higher +Hardware: any AVR with built-in UART, +License: GNU General Public License + +DESCRIPTION: + An interrupt is generated when the UART has finished transmitting or + receiving a byte. The interrupt handling routines use circular buffers + for buffering received and transmitted data. + + The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define + the buffer size in bytes. Note that these variables must be a + power of 2. + +USAGE: + Refere to the header file uart.h for a description of the routines. + See also example test_uart.c. + +NOTES: + Based on Atmel Application Note AVR306 + +LICENSE: + Copyright (C) 2006 Peter Fleury + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*************************************************************************/ +#include +#include +#include +#include "uart.h" + + +/* + * constants and macros + */ + +/* size of RX/TX buffers */ +#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1) +#define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1) + +#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK ) +#error RX buffer size is not a power of 2 +#endif +#if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK ) +#error TX buffer size is not a power of 2 +#endif + +#if defined(__AVR_AT90S2313__) \ + || defined(__AVR_AT90S4414__) || defined(__AVR_AT90S4434__) \ + || defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__) \ + || defined(__AVR_ATmega103__) + /* old AVR classic or ATmega103 with one UART */ + #define AT90_UART + #define UART0_RECEIVE_INTERRUPT UART_RX_vect + #define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect + #define UART0_STATUS USR + #define UART0_CONTROL UCR + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__) + /* old AVR classic with one UART */ + #define AT90_UART + #define UART0_RECEIVE_INTERRUPT UART_RX_vect + #define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \ + || defined(__AVR_ATmega323__) + /* ATmega with one USART */ + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT USART_RXC_vect + #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined (__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT USART_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega163__) + /* ATmega163 with one UART */ + #define ATMEGA_UART + #define UART0_RECEIVE_INTERRUPT UART_RX_vect + #define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega162__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT USART0_RXC_vect + #define UART1_RECEIVE_INTERRUPT USART1_RXC_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART1_RECEIVE_INTERRUPT USART1_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega161__) + /* ATmega with UART */ + #error "AVR ATmega161 currently not supported by this libaray !" +#elif defined(__AVR_ATmega169__) + /* ATmega with one USART */ + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega48__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) \ + || defined(__AVR_ATmega3250__) || defined(__AVR_ATmega3290__) ||defined(__AVR_ATmega6450__) || defined(__AVR_ATmega6490__) + /* ATmega with one USART */ + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT USART_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATtiny2313__) + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT USART_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega329__) || \ + defined(__AVR_ATmega649__) || \ + defined(__AVR_ATmega325__) || \ + defined(__AVR_ATmega645__) + /* ATmega with one USART */ + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega640__) +/* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART1_RECEIVE_INTERRUPT USART1_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega644__) + /* ATmega with one USART */ + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATmega164P__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART1_RECEIVE_INTERRUPT USART1_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#else + #error "no UART definition for MCU available" +#endif + + +/* + * module global variables + */ +static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE]; +static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE]; +static volatile unsigned char UART_TxHead; +static volatile unsigned char UART_TxTail; +static volatile unsigned char UART_RxHead; +static volatile unsigned char UART_RxTail; +static volatile unsigned char UART_LastRxError; + +#if defined( ATMEGA_USART1 ) +static volatile unsigned char UART1_TxBuf[UART_TX_BUFFER_SIZE]; +static volatile unsigned char UART1_RxBuf[UART_RX_BUFFER_SIZE]; +static volatile unsigned char UART1_TxHead; +static volatile unsigned char UART1_TxTail; +static volatile unsigned char UART1_RxHead; +static volatile unsigned char UART1_RxTail; +static volatile unsigned char UART1_LastRxError; +#endif + + + +ISR (UART0_RECEIVE_INTERRUPT) +/************************************************************************* +Function: UART Receive Complete interrupt +Purpose: called when the UART has received a character +**************************************************************************/ +{ + unsigned char tmphead; + unsigned char data; + unsigned char usr; + unsigned char lastRxError; + + + /* read UART status register and UART data register */ + usr = UART0_STATUS; + data = UART0_DATA; + + /* */ +#if defined( AT90_UART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#elif defined( ATMEGA_USART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#elif defined( ATMEGA_USART0 ) + lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) ); +#elif defined ( ATMEGA_UART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#endif + + /* calculate buffer index */ + tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK; + + if ( tmphead == UART_RxTail ) { + /* error: receive buffer overflow */ + lastRxError = UART_BUFFER_OVERFLOW >> 8; + }else{ + /* store new index */ + UART_RxHead = tmphead; + /* store received data in buffer */ + UART_RxBuf[tmphead] = data; + } + UART_LastRxError |= lastRxError; +} + + +ISR (UART0_TRANSMIT_INTERRUPT) +/************************************************************************* +Function: UART Data Register Empty interrupt +Purpose: called when the UART is ready to transmit the next byte +**************************************************************************/ +{ + unsigned char tmptail; + + + if ( UART_TxHead != UART_TxTail) { + /* calculate and store new buffer index */ + tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK; + UART_TxTail = tmptail; + /* get one byte from buffer and write it to UART */ + UART0_DATA = UART_TxBuf[tmptail]; /* start transmission */ + }else{ + /* tx buffer empty, disable UDRE interrupt */ + UART0_CONTROL &= ~_BV(UART0_UDRIE); + } +} + + +/************************************************************************* +Function: uart_init() +Purpose: initialize UART and set baudrate +Input: baudrate using macro UART_BAUD_SELECT() +Returns: none +**************************************************************************/ +void uart_init(unsigned int baudrate) +{ + UART_TxHead = 0; + UART_TxTail = 0; + UART_RxHead = 0; + UART_RxTail = 0; + +#if defined( AT90_UART ) + /* set baud rate */ + UBRR = (unsigned char)baudrate; + + /* enable UART receiver and transmmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|_BV(RXEN)|_BV(TXEN); + +#elif defined (ATMEGA_USART) + /* Set baud rate */ + if ( baudrate & 0x8000 ) + { + UART0_STATUS = (1<>8); + UBRRL = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|(1<>8); + UBRR0L = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE0)|(1<>8); + UBRR = (unsigned char) baudrate; + + /* Enable UART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|(1<> 8; + }else{ + /* store new index */ + UART1_RxHead = tmphead; + /* store received data in buffer */ + UART1_RxBuf[tmphead] = data; + } + UART1_LastRxError |= lastRxError; +} + + +ISR(UART1_TRANSMIT_INTERRUPT) +/************************************************************************* +Function: UART1 Data Register Empty interrupt +Purpose: called when the UART1 is ready to transmit the next byte +**************************************************************************/ +{ + unsigned char tmptail; + + + if ( UART1_TxHead != UART1_TxTail) { + /* calculate and store new buffer index */ + tmptail = (UART1_TxTail + 1) & UART_TX_BUFFER_MASK; + UART1_TxTail = tmptail; + /* get one byte from buffer and write it to UART */ + UART1_DATA = UART1_TxBuf[tmptail]; /* start transmission */ + }else{ + /* tx buffer empty, disable UDRE interrupt */ + UART1_CONTROL &= ~_BV(UART1_UDRIE); + } +} + + +/************************************************************************* +Function: uart1_init() +Purpose: initialize UART1 and set baudrate +Input: baudrate using macro UART_BAUD_SELECT() +Returns: none +**************************************************************************/ +void uart1_init(unsigned int baudrate) +{ + UART1_TxHead = 0; + UART1_TxTail = 0; + UART1_RxHead = 0; + UART1_RxTail = 0; + + + /* Set baud rate */ + if ( baudrate & 0x8000 ) + { + UART1_STATUS = (1<>8); + UBRR1L = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART1_CONTROL = _BV(RXCIE1)|(1< http://jump.to/fleury +File: $Id: uart.h,v 1.12 2012/11/19 19:52:27 peter Exp $ +Software: AVR-GCC 4.1, AVR Libc 1.4 +Hardware: any AVR with built-in UART, tested on AT90S8515 & ATmega8 at 4 Mhz +License: GNU General Public License +Usage: see Doxygen manual + +LICENSE: + Copyright (C) 2006 Peter Fleury + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +************************************************************************/ + +/** + * @defgroup pfleury_uart UART Library + * @code #include @endcode + * + * @brief Interrupt UART library using the built-in UART with transmit and receive circular buffers. + * + * This library can be used to transmit and receive data through the built in UART. + * + * An interrupt is generated when the UART has finished transmitting or + * receiving a byte. The interrupt handling routines use circular buffers + * for buffering received and transmitted data. + * + * The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE constants define + * the size of the circular buffers in bytes. Note that these constants must be a power of 2. + * You may need to adapt this constants to your target and your application by adding + * CDEFS += -DUART_RX_BUFFER_SIZE=nn -DUART_RX_BUFFER_SIZE=nn to your Makefile. + * + * @note Based on Atmel Application Note AVR306 + * @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury + */ + +/**@{*/ + + +#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304 +#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !" +#endif + + +/* +** constants and macros +*/ + +/** @brief UART Baudrate Expression + * @param xtalcpu system clock in Mhz, e.g. 4000000UL for 4Mhz + * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 + */ +#define UART_BAUD_SELECT(baudRate,xtalCpu) (((xtalCpu) + 8UL * (baudRate)) / (16UL * (baudRate)) -1UL) + +/** @brief UART Baudrate Expression for ATmega double speed mode + * @param xtalcpu system clock in Mhz, e.g. 4000000UL for 4Mhz + * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 + */ +#define UART_BAUD_SELECT_DOUBLE_SPEED(baudRate,xtalCpu) ( ((((xtalCpu) + 4UL * (baudRate)) / (8UL * (baudRate)) -1UL)) | 0x8000) + + +/** Size of the circular receive buffer, must be power of 2 */ +#ifndef UART_RX_BUFFER_SIZE +#define UART_RX_BUFFER_SIZE 32 +#endif +/** Size of the circular transmit buffer, must be power of 2 */ +#ifndef UART_TX_BUFFER_SIZE +#define UART_TX_BUFFER_SIZE 32 +#endif + +/* test if the size of the circular buffers fits into SRAM */ +#if ( (UART_RX_BUFFER_SIZE+UART_TX_BUFFER_SIZE) >= (RAMEND-0x60 ) ) +#error "size of UART_RX_BUFFER_SIZE + UART_TX_BUFFER_SIZE larger than size of SRAM" +#endif + +/* +** high byte error return code of uart_getc() +*/ +#define UART_FRAME_ERROR 0x1000 /* Framing Error by UART */ +#define UART_OVERRUN_ERROR 0x0800 /* Overrun condition by UART */ +#define UART_PARITY_ERROR 0x0400 /* Parity Error by UART */ +#define UART_BUFFER_OVERFLOW 0x0200 /* receive ringbuffer overflow */ +#define UART_NO_DATA 0x0100 /* no receive data available */ + + +/* +** function prototypes +*/ + +/** + @brief Initialize UART and set baudrate + @param baudrate Specify baudrate using macro UART_BAUD_SELECT() + @return none +*/ +extern void uart_init(unsigned int baudrate); + + +/** + * @brief Get received byte from ringbuffer + * + * Returns in the lower byte the received character and in the + * higher byte the last receive error. + * UART_NO_DATA is returned when no data is available. + * + * @param void + * @return lower byte: received byte from ringbuffer + * @return higher byte: last receive status + * - \b 0 successfully received data from UART + * - \b UART_NO_DATA + *
no receive data available + * - \b UART_BUFFER_OVERFLOW + *
Receive ringbuffer overflow. + * We are not reading the receive buffer fast enough, + * one or more received character have been dropped + * - \b UART_OVERRUN_ERROR + *
Overrun condition by UART. + * A character already present in the UART UDR register was + * not read by the interrupt handler before the next character arrived, + * one or more received characters have been dropped. + * - \b UART_FRAME_ERROR + *
Framing Error by UART + */ +extern unsigned int uart_getc(void); + + +/** + * @brief Put byte to ringbuffer for transmitting via UART + * @param data byte to be transmitted + * @return none + */ +extern void uart_putc(unsigned char data); + + +/** + * @brief Put string to ringbuffer for transmitting via UART + * + * The string is buffered by the uart library in a circular buffer + * and one character at a time is transmitted to the UART using interrupts. + * Blocks if it can not write the whole string into the circular buffer. + * + * @param s string to be transmitted + * @return none + */ +extern void uart_puts(const char *s ); + + +/** + * @brief Put string from program memory to ringbuffer for transmitting via UART. + * + * The string is buffered by the uart library in a circular buffer + * and one character at a time is transmitted to the UART using interrupts. + * Blocks if it can not write the whole string into the circular buffer. + * + * @param s program memory string to be transmitted + * @return none + * @see uart_puts_P + */ +extern void uart_puts_p(const char *s ); + +/** + * @brief Macro to automatically put a string constant into program memory + */ +#define uart_puts_P(__s) uart_puts_p(PSTR(__s)) + + + +/** @brief Initialize USART1 (only available on selected ATmegas) @see uart_init */ +extern void uart1_init(unsigned int baudrate); +/** @brief Get received byte of USART1 from ringbuffer. (only available on selected ATmega) @see uart_getc */ +extern unsigned int uart1_getc(void); +/** @brief Put byte to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_putc */ +extern void uart1_putc(unsigned char data); +/** @brief Put string to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts */ +extern void uart1_puts(const char *s ); +/** @brief Put string from program memory to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts_p */ +extern void uart1_puts_p(const char *s ); +/** @brief Macro to automatically put a string constant into program memory */ +#define uart1_puts_P(__s) uart1_puts_p(PSTR(__s)) + +/**@}*/ + + +#endif // UART_H + diff --git a/Rmodule/uart/uart_addon.c b/Rmodule/uart/uart_addon.c new file mode 100644 index 0000000..b2544da --- /dev/null +++ b/Rmodule/uart/uart_addon.c @@ -0,0 +1,118 @@ +/************************************************************************* +Title: UART addon-library +Author: Martin Thomas + http://www.siwawi.arubi.uni-kl.de/avr_projects +Software: AVR-GCC 3.3/3.4, Peter Fleury's UART-Library + +DESCRIPTION: + +USAGE: + Refere to the header file uart_addon.h for a description of the routines. + +*************************************************************************/ + +#include + +#include +#include "uart.h" + + +/************************************************************************* +Function: uart_put_int() +Purpose: transmit integer as ASCII to UART +Input: integer value +Returns: none +**************************************************************************/ +void uart_put_int( const int val ) +{ + char buffer[10]; + uart_puts( itoa( val, buffer, 10 ) ); +} /* uart_puti */ + +/************************************************************************* +Function: uart_put_longint() +Purpose: transmit long integer as ASCII to UART +Input: integer value +Returns: none +**************************************************************************/ +void uart_put_longint( const long int val ) +{ + char buffer[15]; + uart_puts( ltoa( val, buffer, 10 ) ); +} /* uart_puti */ + +/************************************************************************* +Function: uart_put_ulongint() +Purpose: transmit long integer as ASCII to UART +Input: integer value +Returns: none +**************************************************************************/ +void uart_put_ulongint( const unsigned long int val ) +{ + char buffer[15]; + uart_puts( utoa( val, buffer, 10 ) ); +} /* uart_puti */ + +/************************************************************************* +Function: uart_puthex_nibble() +Purpose: transmit lower nibble as ASCII-hex to UART +Input: byte value +Returns: none +**************************************************************************/ +void uart_puthex_nibble(const unsigned char b) +{ + unsigned char c = b & 0x0f; + if ( c > 9 ) { + c += 'A'-10; + } + else { + c += '0'; + } + uart_putc(c); +} /* uart_puthex_nibble */ + +/************************************************************************* +Function: uart_puthex_byte() +Purpose: transmit upper and lower nibble as ASCII-hex to UART +Input: byte value +Returns: none +**************************************************************************/ +void uart_puthex_byte( const unsigned char b ) +{ + uart_puthex_nibble( b >> 4 ); + uart_puthex_nibble( b ); +} /* uart_puthex_byte */ + +/************************************************************************* +Function: uart_puthex_long() +Purpose: transmit unsigned long as ASCII-hex to UART +Input: uint32_t value +Returns: none +**************************************************************************/ +void uart_puthex_long( const unsigned long l ) +{ + uart_puthex_byte( (unsigned char)( l >> 24 ) ); + uart_puthex_byte( (unsigned char)( l >> 16 ) ); + uart_puthex_byte( (unsigned char)( l >> 8 ) ); + uart_puthex_byte( (unsigned char)( l ) ); +} /* uart_puthex_byte */ + + +/************************************************************************* +Function: uart_putbin_byte() +Purpose: transmit byte as ASCII-bin to UART +Input: byte value +Returns: none +**************************************************************************/ +void uart_putbin_byte( const unsigned char b ) +{ + signed char i; + for ( i= 7;i >= 0;i-- ) { + if ( b & ( 1 << i ) ) { + uart_putc( '1' ); + } + else { + uart_putc( '0' ); + } + } +} /* uart_putbin_byte */ diff --git a/Rmodule/uart/uart_addon.h b/Rmodule/uart/uart_addon.h new file mode 100644 index 0000000..3c4ff91 --- /dev/null +++ b/Rmodule/uart/uart_addon.h @@ -0,0 +1,121 @@ +#ifndef UART_ADDON_H +#define UART_ADDON_H +/************************************************************************ +Title: UART addon-library +Author: Martin Thomas + http://www.siwawi.arubi.uni-kl.de/avr_projects +Software: AVR-GCC 3.3/3.4, Peter Fleury's UART-Library +************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup UART library-addon + * @code #include @endcode + * + * @brief Additional functions for send numbers as decimal and hex to UART + * + * @note needs Peter Fleury's UART-Library http://jump.to/fleury + * @author Martin Thomas eversmith@heizung-thomas.de + */ + +/*@{*/ + +/** + * @brief Put long integer to ringbuffer for transmitting via UART. + * + * The integer is converted to a string which is buffered by the uart + * library in a circular buffer and one character at a time is transmitted + * to the UART using interrupts. + * + * @param value to transfer + * @return none + * @see uart_puts_p + */ +extern void uart_put_longint( long int i ); + + +/** + * @brief Put unsigned long integer to ringbuffer for transmitting via UART. + * + * The integer is converted to a string which is buffered by the uart + * library in a circular buffer and one character at a time is transmitted + * to the UART using interrupts. + * + * @param value to transfer + * @return none + * @see uart_puts_p + */ +extern void uart_put_ulongint( unsigned long int i ); + + +/** + * @brief Put integer to ringbuffer for transmitting via UART. + * + * The integer is converted to a string which is buffered by the uart + * library in a circular buffer and one character at a time is transmitted + * to the UART using interrupts. + * + * @param value to transfer + * @return none + * @see uart_puts_p + */ +extern void uart_put_int( int i ); + + +/** + * @brief Put nibble as hex to ringbuffer for transmit via UART. + * + * The lower nibble of the parameter is convertet to correspondig + * hex-char and put in a circular buffer and one character at a time + * is transmitted to the UART using interrupts. + * + * @param value to transfer (byte, only lower nibble converted) + * @return none + * @see uart_putc + */ +extern void uart_puthex_nibble( const unsigned char b ); + +/** + * @brief Put byte as hex to ringbuffer for transmit via UART. + * + * The upper and lower nibble of the parameter are convertet to + * correspondig hex-chars and put in a circular buffer and one + * character at a time is transmitted to the UART using interrupts. + * + * @param value to transfer + * @return none + * @see uart_puthex_nibble + */ +extern void uart_puthex_byte( const unsigned char b ); + +/** + * @brief Put unsigned long as ASCII to ringbuffer for transmit via UART. + * + * @param value to transfer + * @return none + * @see none + */ +extern void uart_puthex_long( unsigned long l ); + +/** + * @brief Put byte as bin to ringbuffer for transmit via UART. + * + * @param value to transfer + * @return none + * @see uart_putc + */ +extern void uart_putbin_byte( const unsigned char b ); + + +/*@}*/ + +#ifdef __cplusplus +} +#endif + + +#endif /* UART_ADDON_H */ +