- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
Ergebnis 1 bis 4 von 4

Thema: [gelöst] ATmega88 Probleme mit UART

  1. #1
    Benutzer Stammmitglied
    Registriert seit
    16.08.2006
    Beiträge
    34

    [gelöst] ATmega88 Probleme mit UART

    Anzeige

    LiFePo4 Akku selber bauen - Video
    Hallo,

    so, jetzt ist es soweit, ich brauche auch mal Eure Hilfe. Bis jetzt hab ich mir durch dieses Forum immer selbst helfen können, hab fleißig die Suche und das Wiki benutzt und alles hat am Ende so funktioniert wie es sollte. Aber jetzt komm ich einfach nicht weiter, vielleicht kann mir ja hier einer helfen.

    Und zwar möchte ich die Kommunikation zwischen PC und µC endlich auf die Reihe kriegen: Die Variante 1 aus dem Wiki mittels Polling funktioniert in beide Richtungen, aber bei Variante 2 (mit Interrupts) funktioniert nur das Senden, beim Empfangen tut sich nichts.

    [Problem_gelöst]
    Zuerst aber ein kurioses Problem: Ich muss im Terminal eine Baudrate von 1200 einstellen, beim µC habe ich eine Baudrate von 9600 eingestellt. Ansonsten funktioniert es nicht - Ich habe keine Ahnung warum, vielleicht weiß ja auch das einer von euch.
    [/Problem_gelöst]

    Hier meine Codes:

    uart.h:
    Code:
    #ifndef _UART_H_
    #define _UART_H_
    
    #include <avr/io.h>
    
    extern void uart_init();
    extern int uart_putc(const uint8_t);
    extern uint8_t uart_getc_wait();
    extern int	   uart_getc_nowait();
    extern int getcount();
    
    static inline void uart_flush()
    {
    	while (UCSR0B & (1<<UDRIE0));
    }
    
    #endif
    uart.c:
    Code:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include "uart.h"
    #include "fifo.h"
    
    #define BAUDRATE	9600
    
    // FIFO-Objekte und Puffer für die Ein- und Ausgabe
    #define BUFSIZE_IN 0x40
    uint8_t inbuf[BUFSIZE_IN];
    fifo_t infifo;
    
    #define BUFSIZE_OUT 0x40
    uint8_t outbuf[BUFSIZE_OUT];
    fifo_t outfifo;
    
    
    
    void uart_init()
    {
    	uint8_t sreg = SREG;
    	uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16L*BAUDRATE) - 1);
    	
    	UBRR0H = (uint8_t) (ubrr>>8);
    	UBRR0L = (uint8_t) (ubrr);
    	
    	// Interrupts kurz deaktivieren
    	cli();
    
    	// UART Receiver und Transmitter anschalten
    	// Data mode 8N1, asynchron
    	UCSR0B = (1<<RXEN0) | (1<<TXEN0);
    	UCSR0C = (1<<UMSEL01) | (1<<UCSZ01) | (1<<UCSZ00);
    	
    	//Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte)
    	do
    	{
    		UDR0;
    	}
    	while (UCSR0A & (1<<RXC0));
    	
    	// Rücksetzen von Receive und Transmit Complete-Flags
    	UCSR0A = (1<<RXC0)|(1<<TXC0);
    	
    	// Global Interrupt-Flag wiederherstellen
    	SREG = sreg;
    	
    	// FIFOs für Ein- und Ausgabe initialisieren
    	fifo_init (&infifo,   inbuf, BUFSIZE_IN);
    	fifo_init (&outfifo, outbuf, BUFSIZE_OUT);
    }
    
    int uart_putc(const uint8_t c)
    {
    	int ret = fifo_put(&outfifo, c);
    	
    	UCSR0B |= (1<<UDRIE0);
    	
    	return ret;
    }
    
    void uart_puts(const char *s)
    {
    	do
    	{
    		uart_putc(*s);
    	}
    	while(*s++);
    }
    
    int uart_getc_nowait()
    {
    	return fifo_get_nowait(&infifo);
    }
    
    uint8_t uart_getc_wait()
    {
    	return fifo_get_wait(&infifo);
    }
    
    
    // Empfangene Zeichen werden in die Eingangs-FIFO gespeichert und warten dort
    SIGNAL(SIG_USART_RECV)
    {
    	_inline_fifo_put(&infifo, UDR0);
    }
    
    // Ein Zeichen aus der Ausgabe-FIFO lesen und ausgeben
    // Ist das Zeichen fertig ausgegeben, wird ein neuer SIG_UART_DATA_IRQ getriggert
    // Ist die FIFO leer, deaktiviert die ISR ihren eigenen IRQ.
    SIGNAL(SIG_USART_DATA)
    {
    	if (outfifo.count > 0)
    		UDR0 = _inline_fifo_get(&outfifo);
    	else
    		UCSR0B &= ~(1<<UDRIE0);
    }
    Und das Hauptprogramm:
    Code:
     
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <stdavr.h>
    #include <stdlib.h>
    #include "fifo.h"
    #include "uart.h"
    #include "lcd.h"
    #include <inttypes.h>
    
    int main()
    {
    	char c = 'a';
    	
    	uart_init();
    	lcd_init(LCD_DISP_ON);
    	
    	sei();
    	
    	while(1){
    		
    		lcd_gotoxy(0,0);
    		lcd_puts("Test");
    		
    		lcd_gotoxy(0,1);
    		lcd_putc(c);
    		
    		uart_puts("Test");
    		
    		c = uart_getc_wait();
    	}
    }
    Am Terminal kommt der Text ("Test") an, nur wenn ich ein Zeiche sende, passiert nichts. Normal müßte ja nach dem Senden des Zeichens die Schleife wieder von vorne losgehen und weitere "Test"s auf dem Terminal ankommen. Tuts aber nicht. Es hängt also irgendwo am Empfangen, bzw. am FFIO.

    Ich würde mich sehr freuen, wenn mal jemand von Euch über den Code gucken könnte und sieht, ob irgendwo ein Fehler ist..

    Vielen Dank, Markus

  2. #2
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    19.03.2005
    Ort
    Villach
    Alter
    32
    Beiträge
    995
    Hi

    Ich kenn dein problem. Es brauchte ca 1 woche (und darin mehrere nächte) um eine UART Kommunikation zu machen. ^^

    Es gibt bei den Fusebits ein Fusebit namens:

    DIVIDE CLOCK BY 8

    mehr sag ich nicht. das fusebit gab es bei den alten avrs noch nicht deswegen denkt man nicht dran und setzt es versehentlich oder so.

    lg

  3. #3
    Benutzer Stammmitglied
    Registriert seit
    16.08.2006
    Beiträge
    34
    Hallo Superhirn,

    danke, das ging ja schnell. Du hattest Recht, das divide-by-8-Bit war gesetzt, keine Ahnung, warum. Auf jeden Fall hat es bewirkt, dass ich die Baudrate jetzt bei beiden gleich einstellen kann.

    Leider funktioniert das Empfangen mit der Interrupt-Variante immer noch nicht. Irgendwo hängts beim FIFO oder der IRQ. Senden ist kein Problem. Mit der Polling-Variante klappts einwandfrei, in beide Richtungen.

    Hat sonst noch jemand eine Idee?? Wäre echt super.

    Oder könntest Du mir deinen Code mal schicken, damit ich den mal ausprobieren kann?

    Vielen Dank, Markus

  4. #4
    Benutzer Stammmitglied
    Registriert seit
    16.08.2006
    Beiträge
    34

    Problem gelöst

    Juchuuu,

    so, habe mir jetzt mal die Zeit genommen, das Datenblatt ganz durchzulesen (jaja, ich weiß, soll man sowieso immer machen, ich hab halt geglaubt, dass der Quelltext im Wiki funktioniert....) und siehe da, die Aktivierung vom Receive-Interrupt hat gefehlt...

    Und für alle die das gleiche Problem haben, bzw. einen (bei mir) funktionierenden Quelltext haben wollen, hier isser:

    Test.c:
    Code:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>
    #include "fifo.h"
    #include "uart.h"
    #include "lcd.h"
    
    
    int main(void)
    {
    	char c = 'a';
    	
    	uart_init();
    	lcd_init(LCD_DISP_ON);
    	
    	sei();
    	
    	while(1){
    		
    		lcd_gotoxy(0,0);
    		lcd_puts("Test");
    
    		c = (char) uart_getc_wait();
    		
    		lcd_gotoxy(0,1);
    		lcd_putc(c);
    		
    		uart_putc(c);
    	}
    }
    uart.h:
    Code:
    #ifndef _UART_H_
    #define _UART_H_
    
    #include <avr/io.h>
    
    extern void uart_init(void);
    extern int uart_putc(const uint8_t);
    extern uint8_t uart_getc_wait(void);
    extern int	   uart_getc_nowait(void);
    //extern void uart_write_fifo(const uint8_t);
    
    static inline void uart_flush(void)
    {
    	while (UCSR0B & (1<<UDRIE0));
    }
    
    #endif
    und uart.c:
    Code:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include "uart.h"
    #include "fifo.h"
    
    #define BAUDRATE	9600
    
    // FIFO-Objekte und Puffer für die Ein- und Ausgabe
    #define BUFSIZE_IN 0x40
    uint8_t inbuf[BUFSIZE_IN];
    fifo_t infifo;
    
    #define BUFSIZE_OUT 0x40
    uint8_t outbuf[BUFSIZE_OUT];
    fifo_t outfifo;
    
    void uart_init()
    {
    	uint8_t sreg = SREG;
    	uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16L*BAUDRATE) - 1);
    	
    	UBRR0H = (uint8_t) (ubrr>>8);
    	UBRR0L = (uint8_t) (ubrr);
    	
    	// Interrupts kurz deaktivieren
    	cli();
    
    	// UART Receiver und Transmitter anschalten
    	// Data mode 8N1, asynchron
    	UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0);
    	UCSR0C = (1<<USBS0) | (3<<UCSZ00);
    	
    	//Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte)
    	do
    	{
    		UDR0;
    	}
    	while (UCSR0A & (1<<RXC0));
    	
    	// Rücksetzen von Receive und Transmit Complete-Flags
    	UCSR0A = (1<<RXC0)|(1<<TXC0);
    	
    	// Global Interrupt-Flag wiederherstellen
    	SREG = sreg;
    	
    	// FIFOs für Ein- und Ausgabe initialisieren
    	fifo_init (&infifo,   inbuf, BUFSIZE_IN);
    	fifo_init (&outfifo, outbuf, BUFSIZE_OUT);
    }
    
    int uart_putc(const uint8_t c)
    {
    	int ret = fifo_put(&outfifo, c);
    	
    	UCSR0B |= (1<<UDRIE0);
    	
    	return ret;
    }
    
    void uart_puts(const char *s)
    {
    	do
    	{
    		uart_putc(*s);
    	}
    	while(*s++);
    }
    
    int uart_getc_nowait()
    {
    	return fifo_get_nowait(&infifo);
    }
    
    uint8_t uart_getc_wait()
    {
    	return fifo_get_wait(&infifo);
    }
    
    // Empfangene Zeichen werden in die Eingangs-FIFO gespeichert und warten dort
    SIGNAL(SIG_USART_RECV)
    {
    	_inline_fifo_put(&infifo, UDR0);
    }
    
    // Ein Zeichen aus der Ausgabe-FIFO lesen und ausgeben
    // Ist das Zeichen fertig ausgegeben, wird ein neuer SIG_UART_DATA_IRQ getriggert
    // Ist die FIFO leer, deaktiviert die ISR ihren eigenen IRQ.
    SIGNAL(SIG_USART_DATA)
    {
    	if (outfifo.count > 0)
    		UDR0 = _inline_fifo_get(&outfifo);
    	else
    		UCSR0B &= ~(1<<UDRIE0);
    }
    Vielen Dank auch an Superhirn wegen des Tips mit dem divide-by-8-Bits.

    Markus

Berechtigungen

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

Labornetzteil AliExpress