#include #include //this is a universal uart driver for 8N1 Frames and 57,6k speed //on 12Mhz clock for atmega8 with 28 Pins //only enable Global interrupts makes it working -> sei(); //uart send/receive terminations are defined as -1 static volatile uint8_t cntIn; static volatile uint8_t cntOut; static volatile uint8_t* inBuffer; static volatile uint8_t* outBuffer; static volatile enum _c1 {rx_idle,rx_busy,rx_ready} rxConditions; static volatile enum _c2 {tx_idle,tx_busy,tx_ready} txConditions; static volatile uint8_t inBufferSize; static volatile uint8_t outBufferSize; //===================Interface methods=================== //start that first, global interrupts must enabled ->sei(); void init_uart() { cntIn =0; cntOut =0; rxConditions =rx_idle; txConditions = tx_idle; //config com port UBRRL = 0xC; //baudrate 57600 on 12Mhz clock UCSRB |=(1<< TXEN ); //enable tx UCSRB |=(1<< RXEN ); //enable rx //no Parity, 1 stopbit, 8 databits per default (if changes nessasary, note that UCSRC Register shares the same I/O location as the UBRRH) //enable RX+TX IRQ's later } // Sends the String to UART byte by byte. When buffer length has // reached or a hex 0xFF is found into string then transfer is complete // String examples for length = 6: // {'h','e','l','o','\0',0xFF} -> uart sends: "helo{null}{0xFF}" Note: considering the conventions -> every string should end with null // {'a','b','\0',0xFF,'\0','\0'} -> uart sends: "ab{null}{0xFF}" // {'1','2','3','4','5','6'} -> uart sends: "12345{0xFF}" // Return value: // Returns true if transfer is complete. As long as transfer is busy the // function does nothing and returns false uint8_t sendUartString(uint8_t* str, uint8_t bufLen) { switch(txConditions) { case tx_idle: cntOut =0; //buffer resets outBuffer = str; outBufferSize = bufLen; txConditions = tx_busy; UCSRB |= (1 << UDRIE); //enable tx-IRQ return 0; case tx_busy: return 0; case tx_ready: txConditions = tx_idle; return 1; } return 0; } // This function starts listening at UART. From now, every incoming byte // is dumped to the buffer. If a -1 (0xFF) or a CR is received or the // buffer size has reached then transfer is complete // examples for buffer length = 4: // UART gets: 12{CarrigeReturn} buffer dump is: {1,2,-1,{undefined}} Note that buffer is NOT cleared before reading // UART gets: "blahblah" buffer dump is: {'b','l','a',0xFF} // Return value: // Returns true if transfer is complete. As long as transfer is busy the // function does nothing and returns false uint8_t readUartString(uint8_t* str, uint8_t bufLen) { switch (rxConditions) { case rx_idle: cntIn =0; //buffer resets inBuffer = str; inBufferSize = bufLen; uint8_t c = UDR; //clear inregister and Interrupt rxConditions = rx_busy; UCSRB |= (1 << RXCIE); //enable rx-IRQ return 0; case rx_busy: return 0; case rx_ready: rxConditions = rx_idle; return 1; } return 0; } //=====================END Interface=========================== //Interrupt subroutine 'tx buffer empty' ISR(USART_UDRE_vect) { if (txConditions == tx_busy) { uint8_t c = outBuffer[cntOut]; if (c==0xFF|| cntOut >= (outBufferSize-1)) //if transfer complete { UDR = 0xFF; //send termination to uart UCSRB &= ~(1 << UDRIE); //disable tx-IRQ txConditions = tx_ready; } else { UDR = c; //send next char to uart and clear interrupt cntOut++; } } UCSRA &= ~(1 << UDRE); //clear interrupt flag } //interrupt subroutine '1 byte received' ISR(USART_RXC_vect) { uint8_t c = UDR; //read+clear interrupt if (rxConditions == rx_busy) { if (c==0xFF|| c=='\r' || cntIn >= (inBufferSize-1)) //if receive complete { inBuffer[cntIn] = 0xFF; //put termination to buffer UCSRB &= ~(1 << RXCIE); //disable rx-IRQ rxConditions = rx_ready; } else { inBuffer[cntIn] = c; //put next char to array cntIn++; } } } //testroutine int main(void) { //Reqirements init_uart(); sei();//start global interrupts //testloop volatile uint8_t buffer[10]; //memory allocation by application layer while(1) { while(!readUartString(buffer,10)); //wait until receive complete while(!sendUartString(buffer,10)); //wait until tranceive complete } }