- SF800 Solar Speicher Tutorial         
Ergebnis 1 bis 10 von 29

Thema: Senden und empfangen auf dem UART mit ISR kompatibel zur bisherigen RP6lib

Baum-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Roboter-Spezialist Avatar von RolfD
    Registriert seit
    07.02.2011
    Beiträge
    414

    Senden und empfangen auf dem UART mit ISR kompatibel zur bisherigen RP6lib

    Hallo...
    ich hab vor einiger Zeit mal versuchsweise die RP6uart.c umgeschrieben so das sie per ISR sendet.
    da ich den Code grade wieder vor liegen habe, poste ich ihn mal zur allgemeinen Begutachtung.
    Anlass für die Änderungen waren immer wieder Laufzeitprobleme im Zusammenhang mit UART
    Ausgaben sowie teilweise Datenmüll auf der Receiver.

    Es wurden noch ein paar Dinge korrigiert.
    U.a kann man nun das Zeichen 0x00 zuverlässig empfangen.
    Die Sendefunktion blockt nur bis im Software SendeBuffer wieder Platz ist, sonst wird normal weiter gearbeitet.
    Den Rest erledigt die SendeISR. Die ReceiverISR prüft nun auf Fehler und nimmt nur Zeichen an wenn kein Datenmüll anliegt.
    Bei erkanntem Software Bufferoverrun setzt die Lesefunktion den LeseBuffer zurück.
    Die dazu aufgerufene Funktion clearReceptionBuffer(); kann man gut für eigenes Debuging nutzen.
    Man kann alle alten Funktionen wie gehabt nutzen, es gibt aber zusätlich 2 Ersatzfunktionen
    mit Namen serial_sendc und serial_getc, serial_sendc macht das gleiche wie writeChar, serial_getc
    liest das Zeichen jedoch auf ein Pointer (eines buffers) und gibt im Returnwert 0/1 zurück ob ein Zeichen
    gelesen wurde. Wenn serial_getc eine 1 zurück gibt ist das Zeichen auf der Bufferadresse gültig!
    Auch wenn 0x00 übertragen wurde. Der Sende und Empfangsteil ist unabhängig voneinander,
    man kann auch unterschiedlich große Buffer in der .h einstellen. Die Pointer in den Ringbuffern
    nutzen jeweils nur noch head und tail. Die Codegröße hat sich kaum verändert, einige Vars
    konnte ich einsparen, dafür kommt nun ein weiterer SendeBuffer mit aktuell 32 byte Ram hinzu.

    Ich hoffe, die geänderte lib findet Anklang, vielleicht baut man sie sich ja dauerhaft ein.
    Wäre schön wenn dazu Feedback kommt.

    Dazu die alten Dateien RP6uart.c und RP6uart.h umbenennen -> z.b. so _RP6...
    Neue Dateien in den Verzeichnissen anlegen und den Code unten rein schieben.
    Oder einfach die angehängten Dateien nutzen.

    Die RP6uart.c
    Code:
    /* ****************************************************************************
     * File: RP6uart.c
     *
     * ISR(USART_RXC_vect) geändert. erkennt Frame errors
     * Umbau auf serial_getc, erkennt nun 0x00 chars
     * ISR zum senden
     */
     
    /*****************************************************************************/
    // Includes:
    
    #include "RP6uart.h"
    
    /*****************************************************************************/
    // new UART transmit functions:
    // Data for Ringbuffer
    
    static volatile t_txbuffer tx_buff;
    
    /**
     * UART send ISR.
     * Handles transmission from circular buffer.
     */
    ISR(USART_UDRE_vect, ISR_BLOCK) {
        if (tx_buff.head != tx_buff.tail) {
            UDR = tx_buff.ring[tx_buff.tail];
            tx_buff.tail = (tx_buff.tail + 1) % UART_SEND_BUFFER_SIZE;
        }
        else 
            UCSRB &= ~(1 << UDRIE);
    }
    
    /**
     * send function, nonblocking if free space in buffer
     */
    
    uint8_t serial_sendc(unsigned char data) {
        
        uint8_t next = ((tx_buff.head + 1) % UART_SEND_BUFFER_SIZE);
        while (next == tx_buff.tail);
        tx_buff.ring[tx_buff.head] = data;
        tx_buff.head = next;
        UCSRB |= (1 << UDRIE);
        return 1;
    }
    
    /**
     * compatibility implementation
     * old writeChar function, use serial_sendc instead
     */
    void writeChar(char ch)
    {
        serial_sendc(ch); 
    }
    
    /**
     * Writes a null terminated string or buffer from SRAM to UART.
     * Uses serial_sendc
     * Example:
     *            writeString("RP6 Robot System\n");
     */
    void writeString(char *string)
    {
        while(*string)
            serial_sendc(*string++);
    }
            
    /**
     * Writes a null terminated string from flash program memory to UART.
     * Uses serial_sendc
     * Example:
     *            writeNStringP(PSTR("RP6 Robot System\n"));
     *            // There is also a Macro that makes life easier and
     *            // you can simply write:
     *            writeString_P("RP6 Robot System\n");
      */
    void writeNStringP(const char *pstring)
    {
        unsigned char c;
        for (;(c = pgm_read_byte_near(pstring++));serial_sendc(c));
    }
    
    /**
     * Writes a string with specified length and offset from SRAM to UART.
     * Uses serial_sendc
     * Example:
     *            writeStringLength("RP6 Robot Sytem\n",16,0);
     *            // would output: "RP6 Robot Sytem\n"
     *            writeStringLength("RP6 Robot Sytem\n",11,4);
     *            // would output: "Robot System"
     *             writeStringLength("RP6 Robot Sytem\n",40,4);
     *            // would output: "Robot System\n"
     *            // No matter if the specified length is 40 characters!
     */
    void writeStringLength(char *string, uint8_t length, uint8_t offset)
    {
        for(string = &string[offset]; *string && length; length--)
            serial_sendc(*string++);
    }
    
    /**
     * Write a number (with specified base) to the UART.
     * Example:
     *            // Write a hexadecimal number to the UART:
     *            writeInteger(0xAACC,16);
     *            // Instead of 16 you can also write "HEX" as this is defined in the
     *            // RP6RobotBaseLib.h :
     *            writeInteger(0xAACC, HEX);
     *            // Other Formats:
     *            writeInteger(1024,DEC);      // Decimal
     *            writeInteger(044,OCT);        // Ocal
     *            writeInteger(0b11010111,BIN); // Binary
     */
    void writeInteger(int16_t number, uint8_t base)
    {
        char buffer[17];
        itoa(number, &buffer[0], base);
        writeString(&buffer[0]);
    }
    
    /**
     * Same as writeInteger, but with defined length.
     * Example:
     *            // Write a hexadecimal number to the UART:
     *            writeIntegerLength(0xAACC, 16, 8);
     *            // Instead of 16 you can also write "HEX" as this is defined in the
     *            // RP6RobotBaseLib.h :
     *            writeIntegerLength(0xAACC, HEX, 8);
     *            // Other Formats:
     *            writeIntegerLength(1024,DEC,6);      // Decimal
     *            writeIntegerLength(044,OCT,4);        // Ocal
     *            writeIntegerLength(0b11010111,BIN,8); // Binary
     */
    void writeIntegerLength(int16_t number, uint8_t base, uint8_t length)
    {
        char buffer[17];
        itoa(number, &buffer[0], base);
        int8_t cnt = length - strlen(buffer);
        if(cnt > 0) {
            for(; cnt > 0; cnt--, writeChar('0'));
            writeString(&buffer[0]);
        }
        else 
            writeStringLength(&buffer[0],length,-cnt);
    }
    
    /*****************************************************************************/
    // new UART receive functions:
    // Data for Ringbuffer
    
    static volatile t_rxbuffer rx_buff;
    
    /**
     * UART receive ISR.
     * Handles reception to circular buffer, handles errors.
     */
    ISR(USART_RXC_vect, ISR_BLOCK) {
        if ( ! (UCSRA & ((1<<FE)|(1<<DOR)|(1<<PE)))) {
            volatile uint8_t data = UDR;
            volatile uint8_t next = ((rx_buff.head + 1) % UART_RECEIVE_BUFFER_SIZE);
            if (next != rx_buff.tail) {
                rx_buff.ring[rx_buff.head] = data;
                rx_buff.head = next;
            } else
                rx_buff.uart_error=rx_buff.uart_error + 0x80;
        }
        else {
            volatile uint8_t data __attribute__((unused)) = UDR;
            rx_buff.uart_error++;
        }
    }
    
    /**
     * Read a char from the circular buffer to a pointer. 
     * Reset error counter on frame errors, do buffer reset on overflow
     * returns 1 if a valid char is received, 0 if not
     * Example:
     *
     * // [...]
     * if(getBufferLength())
          if (serial_getc(&receivedData[data_position++]))
             found_a_char();
     * // [...]
     *
     */
    uint8_t serial_getc(unsigned char *data) {
        if (rx_buff.uart_error < 0x80){
            if (rx_buff.head == rx_buff.tail)
                return 0;
            *data = rx_buff.ring[rx_buff.tail];
            rx_buff.tail = (rx_buff.tail + 1) % UART_RECEIVE_BUFFER_SIZE;
            rx_buff.uart_error = 0;
            return 1;
        } else {
            clearReceptionBuffer();
            return 0;
        }
    }
    
    /**
     * compatibility implementation 
     * old readChar function, use serial_getc instead
     * -> there was no way to check if a received char was NULL or the buffer was even empty
     * Example:
     * // [...]
     * if(getBufferLength())         
     *       receivedData[data_position++] = readChar();
     * // [...]
     *
     */
    char readChar(void)
    {
        unsigned char data = 0;
        serial_getc(&data);
        return data;
    }
    
    /**
     * this function copies numberOfChars chars to buf. 
     * It also returns the number of characters really copied to the buffer! 
     * Just in case that there were fewer chars in the buffer...
     */
    uint8_t readChars(unsigned char *buf, uint8_t numberOfChars)
    {
        uint8_t i = 0;
        while(serial_getc(&buf[i]) && (i != numberOfChars))
            i++;
        return i;    
    }
    
    /**
     * Returns the current number of elements in the buffer.
     * Example:
     * s. readChar function above!
     */
    uint8_t getBufferLength(void)
    {
        return ((rx_buff.head + UART_RECEIVE_BUFFER_SIZE - rx_buff.tail) % UART_RECEIVE_BUFFER_SIZE);
    }
    
    /**
     * Clears the reception buffer - it disables UART Receive interrupt for a short period of time.
     * if we execute this, something is going really wrong with the buffer (overflow)
     */
    void clearReceptionBuffer(void)
    {
        UCSRB &= ~(1 << RXCIE);
        rx_buff.head = 0;
        rx_buff.tail = 0;
        rx_buff.uart_error = 0;
        UCSRB |= (1 << RXCIE);
        
        // alert the Programmer urgently, we are in heavy trouble
    }
    
    // EOF
    und die passende RP6uart.h

    Code:
    /* ****************************************************************************
     * File: RP6uart.h
     * Version: new 1.00
     * Target: RP6 Base & Processor Expansion - ATMEGA32 @8.00 or 16.00MHz
     * ****************************************************************************
     */
    
    #ifndef RP6UART_H
    #define RP6UART_H
    
    /*****************************************************************************/
    // Includes:
    
    #include <avr/pgmspace.h>     // Program memory (=Flash ROM) access routines.
    #include <stdlib.h>            // C standard functions (e.g. itoa...)
    #include <string.h>
    #include <avr/io.h>            // I/O Port definitions
    #include <avr/interrupt.h>    // Interrupt macros (e.g. cli(), sei())
    
    /*****************************************************************************/
    // UART
    
    // TX:
    
    uint8_t serial_sendc(unsigned char);
    void writeChar(char);
    void writeStringLength(char *, uint8_t, uint8_t );
    void writeString(char *);
    void writeNStringP(const char *);
    #define writeString_P(__pstr) writeNStringP((PSTR(__pstr)))
    
    #define UART_SEND_BUFFER_SIZE 32 // Default buffer size is 32!
    
    typedef struct {
        volatile uint8_t ring[UART_SEND_BUFFER_SIZE];
        volatile uint8_t head;
        volatile uint8_t tail;
    } t_txbuffer;
    
    #define HEX 16
    #define DEC 10
    #define OCT 8
    #define BIN 2
    void writeInteger(int16_t, uint8_t);
    void writeIntegerLength(int16_t, uint8_t, uint8_t);
    
    
    // RX:
    #define UART_RECEIVE_BUFFER_SIZE 32 // Default buffer size is 32!
    
    // t_buffer.uart_error shoud be always 0, if it contains Values from 1-127,
    // we found Hardware Problems like Baud mismatch and its reseting by serial_getchar.
    // if it contains values over 127, we found buffer overruns.
    typedef struct {
        volatile uint8_t ring[UART_RECEIVE_BUFFER_SIZE];
        volatile uint8_t head;
        volatile uint8_t tail;
        volatile uint8_t uart_error;
    } t_rxbuffer;
    
    uint8_t serial_getc(unsigned char *);
    char readChar(void);
    uint8_t readChars(unsigned char *, uint8_t);
    uint8_t getBufferLength(void);
    void clearReceptionBuffer(void);
    
    #endif
    
    // EOF
    Gruß
    Angehängte Dateien Angehängte Dateien
    Geändert von RolfD (18.04.2014 um 23:45 Uhr)
    Sind Sie auch ambivalent?

Ähnliche Themen

  1. IR Senden und Empfangen mit ATtiny
    Von bnitram im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 5
    Letzter Beitrag: 03.03.2012, 12:32
  2. Problem mit dem senden von Zeichen per UART
    Von KingTobi im Forum C - Programmierung (GCC u.a.)
    Antworten: 14
    Letzter Beitrag: 30.10.2008, 20:29
  3. Atmega32/STK500 -UART senden/empfangen klappt nicht
    Von Leuchtturm im Forum C - Programmierung (GCC u.a.)
    Antworten: 12
    Letzter Beitrag: 16.01.2007, 14:02
  4. Uart senden empfangen Interrups
    Von ronald im Forum AVR Hardwarethemen
    Antworten: 15
    Letzter Beitrag: 06.03.2006, 20:24
  5. UART ermöglicht Senden, aber kann nicht Empfangen
    Von batti112 im Forum C - Programmierung (GCC u.a.)
    Antworten: 3
    Letzter Beitrag: 18.09.2004, 15:05

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

LiFePO4 Speicher Test