diff --git a/defs.h b/defs.h new file mode 100644 index 0000000..9b17b73 --- /dev/null +++ b/defs.h @@ -0,0 +1,39 @@ +/** + * @file defs.h + * + * @date 01.02.2015 + * @author Pascal Gollor + * web http://www.pgollor.de + * + * @copyright Dieses Werk ist unter einer Creative Commons Lizenz vom Typ + * Namensnennung - Weitergabe unter gleichen Bedingungen 3.0 Deutschland zugänglich. + * Um eine Kopie dieser Lizenz einzusehen, konsultieren Sie + * http://creativecommons.org/licenses/by-sa/3.0/de/ oder wenden Sie sich + * brieflich an Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. + * + * -- englisch version -- + * @n This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Germany License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. + * + */ + +#ifndef __DEFS_H__ +#define __DEFS_H__ + +/** + * @brief define Uart baudrate + */ +#define UART_BAUDRATE 9600 + +/** + * @brief UART line ending + */ +#define CR "\r\n" + + +#ifndef TRUE + #define TRUE 0x01 + #define FALSE 0x00 +#endif + + +#endif // __DEFS_H__ diff --git a/keypad.c b/keypad.c new file mode 100644 index 0000000..b0a89e3 --- /dev/null +++ b/keypad.c @@ -0,0 +1,165 @@ +/** + * @file keypad.c + * + * @date 01.02.2015 + * @author Pascal Gollor + * web http://www.pgollor.de + * + * @copyright Dieses Werk ist unter einer Creative Commons Lizenz vom Typ + * Namensnennung - Weitergabe unter gleichen Bedingungen 3.0 Deutschland zugänglich. + * Um eine Kopie dieser Lizenz einzusehen, konsultieren Sie + * http://creativecommons.org/licenses/by-sa/3.0/de/ oder wenden Sie sich + * brieflich an Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. + * + * -- englisch version -- + * @n This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Germany License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. + * + */ + +#include "keypad.h" + +#include // PROGMEM +#include // delay_ms +#ifdef KEYPAD_DEBUG + #include "defs.h" + #include "uart.h" +#endif + + +/** + * @brief keypad keys + * + * for each key you can use everything value from 0-254 + * 255 means: no valid key + */ +PROGMEM const uint8_t g_keypad_key[KEYPAD_ROWS][KEYPAD_COLUMNS] = { + {'a', 'b', '#', '*'}, + {'1', '2', '3', 'c'}, + {'4', '5', '6', 'd'}, + {'7', '8', '9', 'e'}, + {'<', '0', '>', 'f'} +}; + + +/** + * @brief init io ports for keypad + */ +void keypad_init(void) +{ + // columns + KEYPAD_COLUMN_REGISTER |= KEYPAD_COLUMN_BITS; // define columns as output + KEYPAD_COLUMN_OUT &= ~(KEYPAD_COLUMN_BITS); // set columns to zero + + // rows + KEYPAD_ROW_REGISTER &= ~(KEYPAD_ROW_BITS); // define rows as input + KEYPAD_ROW_OUT |= KEYPAD_ROW_BITS; // enable pullup for rows +} + + +/** + * @brief get key from keypad + */ +uint8_t keypad_getKey(void) +{ + uint8_t col = KEYPAD_NO_VALID_KEY; + uint8_t row = 0; + + // read row channels + row = ((~KEYPAD_ROW_IN) & KEYPAD_ROW_BITS) >> KEYPAD_ROW_FIRST_CHANNEL; + if (row == 0) + { + // no key is pressed + return KEYPAD_NO_VALID_KEY; + } + + // wait for debounce + _delay_ms(10); + if (row != ((~KEYPAD_ROW_IN) & KEYPAD_ROW_BITS) >> KEYPAD_ROW_FIRST_CHANNEL) + { + return KEYPAD_NO_VALID_KEY; + } + + // set columns to zero + KEYPAD_COLUMN_OUT &= ~(KEYPAD_COLUMN_BITS); + _delay_us(1); + + // check for pressed column + for (uint8_t i = KEYPAD_COLUMN_FIRST_CHANNEL; i < (KEYPAD_COLUMN_FIRST_CHANNEL + KEYPAD_COLUMNS); i++) + { + KEYPAD_COLUMN_OUT |= (1 << i); + _delay_us(1); + + if ((KEYPAD_ROW_IN & KEYPAD_ROW_BITS) == KEYPAD_ROW_BITS) + { + // debounce + _delay_ms(10); + + if ((KEYPAD_ROW_IN & KEYPAD_ROW_BITS) != KEYPAD_ROW_BITS) + { + col = KEYPAD_NO_VALID_KEY; + break; + } + + col = i - KEYPAD_COLUMN_FIRST_CHANNEL; + break; + } + + KEYPAD_COLUMN_OUT &= ~(1 << i); + _delay_us(1); + } + + // set columns to zero + KEYPAD_COLUMN_OUT &= ~(KEYPAD_COLUMN_BITS); + + if (col == KEYPAD_NO_VALID_KEY) + { + // no column detected + return KEYPAD_NO_VALID_KEY; + } + + // detect row + for (uint8_t i = 0; i < KEYPAD_ROWS; i++) + { + if (row >> i == 1) + { + row = i; + break; + } + } + + if (row >= KEYPAD_ROWS) + return KEYPAD_NO_VALID_KEY; + +#ifdef KEYPAD_DEBUG + printf("row: %i" CR, row); + printf("column: %i" CR, col); + uart_flush(); +#endif + + // return key from keylist + return pgm_read_byte(&g_keypad_key[row][col]); +} + + +/** + * @brief get key and wait to for loosing + */ +uint8_t keypad_getKeyAndWait(void) +{ + uint8_t key = keypad_getKey(); + uint8_t last_key = KEYPAD_NO_VALID_KEY; + + if (key == KEYPAD_NO_VALID_KEY) + { + return KEYPAD_NO_VALID_KEY; + } + + last_key = key; + while (key != KEYPAD_NO_VALID_KEY) + { + key = keypad_getKey(); + } + + return last_key; +} + diff --git a/keypad.h b/keypad.h new file mode 100644 index 0000000..ce4d02f --- /dev/null +++ b/keypad.h @@ -0,0 +1,69 @@ +/** + * @file keypad.h + * + * @date 01.02.2015 + * @author Pascal Gollor + * web http://www.pgollor.de + * + * @copyright Dieses Werk ist unter einer Creative Commons Lizenz vom Typ + * Namensnennung - Weitergabe unter gleichen Bedingungen 3.0 Deutschland zugänglich. + * Um eine Kopie dieser Lizenz einzusehen, konsultieren Sie + * http://creativecommons.org/licenses/by-sa/3.0/de/ oder wenden Sie sich + * brieflich an Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. + * + * -- englisch version -- + * @n This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Germany License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. + * + */ + +#ifndef __KEYPAD_H__ +#define __KEYPAD_H__ + + +#include + + +/** + * @brief define x-axis channels (columns) + * + * all channels have to be at the same port site by site + */ +#define KEYPAD_COLUMNS 4 +#define KEYPAD_COLUMN_REGISTER DDRC +#define KEYPAD_COLUMN_IN PINC +#define KEYPAD_COLUMN_OUT PORTC +#define KEYPAD_COLUMN_FIRST_CHANNEL 4 // 4 means PC4, PC5, PC6, PC7 for 4 columns + +/** + * @brief define y-axis channels (rows) + * + * all channels have to be at the same port site by site + */ +#define KEYPAD_ROWS 5 +#define KEYPAD_ROW_REGISTER DDRA +#define KEYPAD_ROW_IN PINA +#define KEYPAD_ROW_OUT PORTA +#define KEYPAD_ROW_FIRST_CHANNEL 3 // 3 means PA3, PA4, PA5, PA6, PA7 for 5 rows + + +/** + * @brief uncomment this to enable debug output over uart + */ +//#define KEYPAD_DEBUG + + +// do not change afters this +#define KEYPAD_COLUMN_BITS ( ((2 << (KEYPAD_COLUMNS - 1)) - 1) << KEYPAD_COLUMN_FIRST_CHANNEL ) +#define KEYPAD_ROW_BITS ( ((2 << (KEYPAD_ROWS - 1)) - 1) << KEYPAD_ROW_FIRST_CHANNEL ) +//#define KEYPAD_COLUMN_BITS 0b11110000 +//#define KEYPAD_ROW_BITS 0b11111000 + +#define KEYPAD_NO_VALID_KEY 0xff + + +void keypad_init(void); +uint8_t keypad_getKey(void); +uint8_t keypad_getKeyAndWait(void); + + +#endif // __KEYPAD_H__ diff --git a/main.c b/main.c new file mode 100644 index 0000000..4de5b07 --- /dev/null +++ b/main.c @@ -0,0 +1,55 @@ +/** + * @file main.c + * + * @date 01.02.2015 + * @author Pascal Gollor + * web http://www.pgollor.de + * + * @copyright Dieses Werk ist unter einer Creative Commons Lizenz vom Typ + * Namensnennung - Weitergabe unter gleichen Bedingungen 3.0 Deutschland zugänglich. + * Um eine Kopie dieser Lizenz einzusehen, konsultieren Sie + * http://creativecommons.org/licenses/by-sa/3.0/de/ oder wenden Sie sich + * brieflich an Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. + * + * -- englisch version -- + * @n This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Germany License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. + * + */ + + +#include "defs.h" + +#include +#include // delay_ms +#include // sei + +#include "uart.h" +#include "keypad.h" + + +int main(void) +{ + // Initialize UART library + uart_init(UART_BAUD_SELECT(UART_BAUDRATE, F_CPU)); + sei(); // enable interrupts for uart + + keypad_init(); // init keypad io ports + + uart_puts_P(CR "----- matrix 5x4 -----" CR CR); + uart_flush(); + + + while (1) + { + // get key from keypad + uint8_t key = keypad_getKeyAndWait(); + if (key != KEYPAD_NO_VALID_KEY) + { + printf("key: %c" CR CR, key); + } + + _delay_ms(50); + } + + return 0; +} diff --git a/uart.c b/uart.c new file mode 100644 index 0000000..c68bde8 --- /dev/null +++ b/uart.c @@ -0,0 +1,824 @@ +/************************************************************************* +Title: Interrupt UART library with receive/transmit circular buffers +Author: Peter Fleury http://jump.to/fleury +File: $Id: uart.c,v 1.9 2012/11/10 12:59:31 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 +#include +#include +#include + +#include "uart.h" +#include "defs.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< 0xff) + { + uart_putc((i>>8) & 0xff); + uart_putc(i & 0xff); + } + else + { + uart_putc(0); + uart_putc(i); + } +} + + +/************************************************************************* +Function: uart_puts_p() +Purpose: transmit string from program memory to UART +Input: program memory string to be transmitted +Returns: none +**************************************************************************/ +void uart_puts_p(const char *progmem_s ) +{ + register char c; + + while ( (c = pgm_read_byte(progmem_s++)) ) + uart_putc(c); + +}/* uart_puts_p */ + + +/* + * these functions are only for ATmegas with two USART + */ +#if defined( ATMEGA_USART1 ) + +ISR(UART1_RECEIVE_INTERRUPT) +/************************************************************************* +Function: UART1 Receive Complete interrupt +Purpose: called when the UART1 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 = UART1_STATUS; + data = UART1_DATA; + + /* */ + lastRxError = (usr & (_BV(FE1)|_BV(DOR1)) ); + + /* calculate buffer index */ + tmphead = ( UART1_RxHead + 1) & UART_RX_BUFFER_MASK; + + if ( tmphead == UART1_RxTail ) { + /* error: receive buffer overflow */ + lastRxError = UART_BUFFER_OVERFLOW >> 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<0) + { + str_null_buffer[0] = by; + str_null_buffer[1] = '\0'; + move = atoi(str_null_buffer); + by = pgm_read_byte(Buffer++); + } + + int b; + + switch (by) + { + case '%': + uart_putc('%'); + break; + case 's': + ptr = va_arg(ap,char *); + while(*ptr) { uart_putc(*ptr++); } + break; + case 'b': + Base = 2; + goto ConversionLoop; + case 'c': + //Int to char + format_flag = va_arg(ap,int); + uart_putc(format_flag++); + break; + case 'i': + Base = 10; + goto ConversionLoop; + case 'u': + itoa(va_arg(ap,unsigned int),str_buffer,10); + goto ConversionLoopSecond; + case 'l': + ltoa(va_arg(ap,long),str_buffer,10); + goto ConversionLoopSecond; + case 'o': + Base = 8; + goto ConversionLoop; + case 'x': + Base = 16; + + //**************************** + ConversionLoop: + //**************************** + itoa(va_arg(ap,int),str_buffer,Base); + + //**************************** + ConversionLoopSecond: + //**************************** + + b=0; + while (str_buffer[b++] != 0){}; + b--; + if (b 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 + */ + +/**@{*/ + +#include + + +#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 64 +#endif +/** Size of the circular transmit buffer, must be power of 2 */ +#ifndef UART_TX_BUFFER_SIZE +#define UART_TX_BUFFER_SIZE 64 +#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 0x01ff /* 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); + +extern uint8_t uart_getc_wait(uint8_t); + +extern void uart_flush (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); + +extern void uart_puti_noasci(const uint16_t); + + +/** + * @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)) + +/**@}*/ + + +void usart_write_P (const char *Buffer,...); +#define printf(format, args...) usart_write_P(PSTR(format), ## args); + + +#endif // UART_H +