diff --git a/usart/main.cpp b/usart/main.cpp index fbf9773..577d594 100644 --- a/usart/main.cpp +++ b/usart/main.cpp @@ -10,13 +10,13 @@ int main() { - USART0 cUSART; + USART0 &cUSART = USART0::inst(); cUSART.init(); uint32_t ui32Counter = 0; - constexpr size_t sizeBufferSize = 64; - char szBuffer[sizeBufferSize]; + constexpr size_t sizeBUFFER_SIZE = 64; + char szBuffer[sizeBUFFER_SIZE]; cUSART.transmitString( "\r\nSizes: \r\n" ); @@ -83,7 +83,7 @@ int main() cUSART.transmitString( szBuffer ); cUSART.transmitString( "\" seconds!\r\n" ); - if( !cUSART.receiveLine( szBuffer, sizeBufferSize, "\r" ) ) + if( !cUSART.receiveLine( szBuffer, sizeBUFFER_SIZE, "\r" ) ) { cUSART.transmitString( "Receive error: " ); } @@ -95,7 +95,13 @@ int main() cUSART.transmitString( szBuffer ); cUSART.transmitString( "\r\n" ); - _delay_ms( 1000 ); + uint8_t ui8Byte; + + if( cUSART.receiveByte( ui8Byte, 1000 ) ) + { + cUSART.transmitByte( ui8Byte ); + cUSART.transmitString( "\r\n" ); + } } return 0; diff --git a/usart/usart.cpp b/usart/usart.cpp index 313ce27..037e95e 100644 --- a/usart/usart.cpp +++ b/usart/usart.cpp @@ -1,5 +1,35 @@ #include "usart.h" +////////////////////////////////////////////////////////////////////////// +USART0 USART0::sm_cInstance; + +////////////////////////////////////////////////////////////////////////// +USART0::USART0() +{ + #ifdef USART_SHAREDIO + m_vui8pUCSRA = &UCSRA; + m_vui8pUCSRB = &UCSRB; + m_vui8pUCSRC = &UCSRC; + m_vui8pUBRRH = &UBRRH; + m_vui8pUBRRL = &UBRRL; + m_vui8pUDR = &UDR; + #endif + + #ifndef USART_SHAREDIO + m_vui8pUCSRA = &UCSR0A; + m_vui8pUCSRB = &UCSR0B; + m_vui8pUCSRC = &UCSR0C; + m_vui8pUBRRH = &UBRR0H; + m_vui8pUBRRL = &UBRR0L; + m_vui8pUDR = &UDR0; + #endif + + m_vsizeRXBufferHead = 0; + m_vsizeRXBufferTail = 0; + m_vsizeTXBufferHead = 0; + m_vsizeTXBufferTail = 0; +} + ////////////////////////////////////////////////////////////////////////// uint8_t USART0::readUCSRC() { @@ -51,6 +81,32 @@ void USART0::setTXState( bool bEnable ) } } +////////////////////////////////////////////////////////////////////////// +void USART0::setRXInterrupt( bool bEnable ) +{ + if( bEnable ) + { + *m_vui8pUCSRB |= ( 1 << RXCIE_D ); + } + else + { + *m_vui8pUCSRB &= ~( 1 << RXCIE_D ); + } +} + +////////////////////////////////////////////////////////////////////////// +void USART0::setUDREInterrupt( bool bEnable ) +{ + if( bEnable ) + { + *m_vui8pUCSRB |= ( 1 << UDRIE_D ); + } + else + { + *m_vui8pUCSRB &= ~( 1 << UDRIE_D ); + } +} + ////////////////////////////////////////////////////////////////////////// void USART0::setBaudRate( uint32_t ui32BaudRate ) { @@ -180,31 +236,11 @@ void USART0::setMode( Mode enmMode ) } ////////////////////////////////////////////////////////////////////////// -USART0::USART0() +USART0& USART0::inst() { -#ifdef USART_SHAREDIO - m_vui8pUCSRA = &UCSRA; - m_vui8pUCSRB = &UCSRB; - m_vui8pUCSRC = &UCSRC; - m_vui8pUBRRH = &UBRRH; - m_vui8pUBRRL = &UBRRL; - m_vui8pUDR = &UDR; -#endif - -#ifndef USART_SHAREDIO - m_vui8pUCSRA = &UCSR0A; - m_vui8pUCSRB = &UCSR0B; - m_vui8pUCSRC = &UCSR0C; - m_vui8pUBRRH = &UBRR0H; - m_vui8pUBRRL = &UBRR0L; - m_vui8pUDR = &UDR0; -#endif + return sm_cInstance; } -////////////////////////////////////////////////////////////////////////// -USART0::~USART0() -{} - ////////////////////////////////////////////////////////////////////////// void USART0::init( uint32_t ui32BaudRate /* = 9600 */, uint8_t ui8DataBits /* = 8 */, Parity enmParity /* = Parity::DISABLED */, StopBit enmStopBits /* = StopBit::ONE */, Mode enmMode /* = Mode::ASYNCHRONOUS */ ) { @@ -216,34 +252,42 @@ void USART0::init( uint32_t ui32BaudRate /* = 9600 */, uint8_t ui8DataBits /* = setRXState( true ); setTXState( true ); + setRXInterrupt( true ); + setUDREInterrupt( false ); + + sei(); } ////////////////////////////////////////////////////////////////////////// -bool USART0::receiveByte( uint8_t &ui8Data, uint32_t ui32DelayMS ) +bool USART0::receiveByte( uint8_t &ui8Data ) { - const uint8_t ui8ClockCyclesPerIteration = 6; - double dDelayS = ui32DelayMS / 1000.0; - - uint32_t ui32Iterations = static_cast( ( dDelayS * F_CPU ) / ui8ClockCyclesPerIteration ); - - do + if( m_vsizeRXBufferHead == m_vsizeRXBufferTail ) { - if( ( *m_vui8pUCSRA & ( 1 << RXC_D ) ) ) - { - ui8Data = *m_vui8pUDR; - return true; - } - } while( --ui32Iterations > 0 ); - - return false; + return false; + } + + ui8Data = m_vui8aRXBuffer[m_vsizeRXBufferTail]; + m_vsizeRXBufferTail = ( m_vsizeRXBufferTail + 1 ) % sm_sizeRXBUFFER_SIZE; + + return true; } ////////////////////////////////////////////////////////////////////////// -uint8_t USART0::receiveByte() +bool USART0::receiveByte( uint8_t &ui8Data, uint16_t ui16DelayMS ) { - while( !( *m_vui8pUCSRA & ( 1 << RXC_D ) ) ); - - return *m_vui8pUDR; + uint16_t ui16DelayCounter = 0; + + while( !receiveByte( ui8Data ) ) + { + _delay_ms( 1 ); + + if( ui16DelayCounter++ >= ui16DelayMS ) + { + return false; + } + } + + return true; } ////////////////////////////////////////////////////////////////////////// @@ -253,7 +297,10 @@ bool USART0::receiveLine( char *szBuffer, size_t sizeLength, const char *szLineT while( sizeReceived < sizeMaxSize - 1 && sizeReceived < sizeLength - 1 ) { - szBuffer[sizeReceived++] = receiveByte(); + uint8_t ui8ReceiveByte; + + while( !receiveByte( ui8ReceiveByte ) ); + szBuffer[sizeReceived++] = ui8ReceiveByte; szBuffer[sizeReceived] = '\0'; if( strstr( szBuffer, szLineTerminator ) ) @@ -268,20 +315,70 @@ bool USART0::receiveLine( char *szBuffer, size_t sizeLength, const char *szLineT ////////////////////////////////////////////////////////////////////////// void USART0::transmitByte( uint8_t ui8Data ) { - while( !( *m_vui8pUCSRA & ( 1 << UDRE_D ) ) ); - - *m_vui8pUDR = ui8Data; + if( m_vsizeTXBufferHead == m_vsizeTXBufferTail && *m_vui8pUCSRA & ( 1 << UDRE_D ) ) + { + *m_vui8pUDR = ui8Data; + return; + } + + size_t sizeIndex = ( m_vsizeTXBufferHead + 1 ) % sm_sizeTXBUFFER_SIZE; + + while( sizeIndex == m_vsizeTXBufferTail ); + + m_vui8aTXBuffer[m_vsizeTXBufferHead] = ui8Data; + m_vsizeTXBufferHead = sizeIndex; + + setUDREInterrupt( true ); } ////////////////////////////////////////////////////////////////////////// void USART0::transmitString( const char *szString ) { - while( *szString != '\0' ) + while( *szString ) { transmitByte( *szString++ ); } } +////////////////////////////////////////////////////////////////////////// +void USART0::receiveInterruptHandler() +{ + uint8_t ui8ReceivedByte = *m_vui8pUDR; + size_t sizeIndex = ( m_vsizeRXBufferHead + 1 ) % sm_sizeRXBUFFER_SIZE; + + if( sizeIndex != m_vsizeRXBufferTail ) + { + m_vui8aRXBuffer[m_vsizeRXBufferHead] = ui8ReceivedByte; + m_vsizeRXBufferHead = sizeIndex; + } +} + +////////////////////////////////////////////////////////////////////////// +void USART0::transmitInterruptHandler() +{ + uint8_t ui8TransmitByte = m_vui8aTXBuffer[m_vsizeTXBufferTail]; + m_vsizeTXBufferTail = ( m_vsizeTXBufferTail + 1 ) % sm_sizeTXBUFFER_SIZE; + + *m_vui8pUDR = ui8TransmitByte; + + if( m_vsizeTXBufferHead == m_vsizeTXBufferTail ) + { + setUDREInterrupt( false ); + } +} + +////////////////////////////////////////////////////////////////////////// +ISR( USART0_RX_vect_D ) +{ + USART0::inst().receiveInterruptHandler(); +} + +////////////////////////////////////////////////////////////////////////// +ISR( USART0_UDRE_vect_D ) +{ + USART0::inst().transmitInterruptHandler(); +} + #ifdef SECOND_USART ////////////////////////////////////////////////////////////////////////// @@ -295,8 +392,4 @@ USART1::USART1() m_vui8pUDR = &UDR1; } -////////////////////////////////////////////////////////////////////////// -USART1::~USART1() -{} - #endif \ No newline at end of file diff --git a/usart/usart.h b/usart/usart.h index 4ac3d57..7591f74 100644 --- a/usart/usart.h +++ b/usart/usart.h @@ -1,30 +1,41 @@ /* * Copyright (c) by BlackMark 2015-2016 * Date 20/05/2016 -* Version 2.5 +* Version 2.6 */ #ifndef USART_H #define USART_H #include +#include #include #include #include "clock.h" #if defined (__AVR_ATmega168A__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega1284P__) #define USART_SPI +#define USART0_RX_vect_D USART_RX_vect +#define USART0_UDRE_vect_D USART_UDRE_vect #endif #if defined (__AVR_ATmega32A__) || (__AVR_ATmega8__) #define USART_SHAREDIO +#define USART0_RX_vect_D USART_RXC_vect +#define USART0_UDRE_vect_D USART_UDRE_vect #endif #if defined (__AVR_ATmega1284P__) #define SECOND_USART +#define USART0_RX_vect_D USART0_RX_vect +#define USART1_RX_vect_D USART1_RX_vect +#define USART0_UDRE_vect_D USART0_UDRE_vect +#define USART1_UDRE_vect_D USART1_UDRE_vect #endif #ifdef USART_SHAREDIO #define RXEN_D RXEN #define TXEN_D TXEN +#define RXCIE_D RXCIE +#define UDRIE_D UDRIE #define UCSZ0_D UCSZ0 #define UCSZ1_D UCSZ1 #define UCSZ2_D UCSZ2 @@ -36,6 +47,8 @@ #else #define RXEN_D RXEN0 #define TXEN_D TXEN0 +#define RXCIE_D RXCIE0 +#define UDRIE_D UDRIE0 #define UCSZ0_D UCSZ00 #define UCSZ1_D UCSZ01 #define UCSZ2_D UCSZ02 @@ -78,6 +91,9 @@ public: TWO = 2 }; + static constexpr size_t sm_sizeRXBUFFER_SIZE = 16; + static constexpr size_t sm_sizeTXBUFFER_SIZE = 16; + protected: volatile uint8_t *m_vui8pUCSRA; volatile uint8_t *m_vui8pUCSRB; @@ -86,12 +102,26 @@ protected: volatile uint8_t *m_vui8pUBRRL; volatile uint8_t *m_vui8pUDR; + volatile size_t m_vsizeRXBufferHead; + volatile size_t m_vsizeRXBufferTail; + volatile size_t m_vsizeTXBufferHead; + volatile size_t m_vsizeTXBufferTail; + + volatile uint8_t m_vui8aRXBuffer[sm_sizeRXBUFFER_SIZE]; + volatile uint8_t m_vui8aTXBuffer[sm_sizeTXBUFFER_SIZE]; + + USART0(); + private: + static USART0 sm_cInstance; + uint8_t readUCSRC(); void setUCSRC( uint8_t ui8UCSRC ); void setRXState( bool bEnable ); void setTXState( bool bEnable ); + void setRXInterrupt( bool bEnable ); + void setUDREInterrupt( bool bEnable ); void setBaudRate( uint32_t ui32BaudRate ); void setDataBits( uint8_t ui8DataBits ); void setParity( Parity enmParity ); @@ -99,17 +129,21 @@ private: void setMode( Mode enmMode ); public: - USART0(); - ~USART0(); + static USART0& inst(); + USART0( const USART0& ) = delete; + void operator=( const USART0& ) = delete; void init( uint32_t ui32BaudRate = 9600, uint8_t ui8DataBits = 8, Parity enmParity = Parity::DISABLED, StopBit enmStopBits = StopBit::ONE, Mode enmMode = Mode::ASYNCHRONOUS ); - bool receiveByte( uint8_t &ui8Data, uint32_t ui32DelayMS ); - uint8_t receiveByte(); + bool receiveByte( uint8_t &ui8Data ); + bool receiveByte( uint8_t &ui8Data, uint16_t ui16DelayMS ); bool receiveLine( char *szBuffer, size_t sizeLength, const char *szLineTerminator = "\r\n", size_t sizeMaxSize = 512 ); void transmitByte( uint8_t ui8Data ); void transmitString( const char *szString ); + + void receiveInterruptHandler(); + void transmitInterruptHandler(); }; #ifdef SECOND_USART @@ -118,7 +152,6 @@ class USART1 : public USART0 { public: USART1(); - ~USART1(); }; #endif