Forum: Compiler & IDEs ATMEGA16 USART mit Interrupt


von Jano (Gast)


Lesenswert?

hallo,
mache eine versuche mit einem atmega16.
empfangen + senden. es functionniert ohne interrupt
jetzt moechte ich das epfangen und senden auf interrupt-gesteuert 
umstellen,
kann jemand mir sagen wie ich das machen kann?
hier ist meine code die richtig functionniert ohne interrupt
Danke
Jano


#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>




 /*Size of the circular receive buffer, must be power of 2*/
 #ifndef UART_RX_BUFFER_SIZE
 #define UART_RX_BUFFER_SIZE 32
 #endif

/*Size of the circular Transmit buffer, must be power of 2*/
 #ifndef UART_TX_BUFFER_SIZE
 #define UART_TX_BUFFER_SIZE 32
 #endif



// CHECK F_CPU WITH HARDWARE OSZILLATOR SETTING !!!!
#define F_CPU 1000000UL
#define UART_BAUD 9600

/*
 *  module global variables
 */
int g_idx;
int MAX_BUFFER_SIZE;
MAX_BUFFER_SIZE=UART_TX_BUFFER_SIZE;
unsigned char Buf[UART_TX_BUFFER_SIZE];
int bxoff = 0;
unsigned char c;

void uart_init(void);
unsigned int uart_getdata(void);
//unsigned char uart_getc(void);
void uart_putdata(unsigned char c);
//int uart_putc(unsigned char c);
void uart_puts (char *s);

int main(void)
{
   unsigned char c;



   uart_init();

   uart_puts("hello world!\r\n\r\n");

   while(1)
   {
      // Poll
      c = uart_getdata();



      // Echo
      uart_putdata(c);
   }

   return 0;
}

void uart_init(void)

/******************************************************************
 Function: Uart_init()
 Purpose: Initialise UART and set baudrate
 Input: baudrate
 Returns: none
 ******************************************************************/

{


  UCSRB |= (1<<TXEN) |(1<<RXEN);  // tx/rx enable
    UCSRC |= (1<<URSEL)|(3<<UCSZ0); // Asynchron 8N1

#if F_CPU < 2000000UL && defined(U2X)
    UCSRA |= (1<<U2X);   /* improve baud rate error by using 2x clk */
    UBRRL = (F_CPU / (8UL * UART_BAUD)) - 1;
#else
    UBRRL = (F_CPU / (16UL * UART_BAUD)) - 1;
#endif
}



void uart_putdata(unsigned char c)
{
    int n;
  n = g_idx;

    g_idx = 0;

   while (n>0){

     c = Buf[g_idx];
     g_idx++;

  while (!(UCSRA & (1<<UDRE)))// Warten bis senden möglich
  {
   }
     UDR=c;
   n-=1;
    }

  bxoff=0;
  return UDR;
  }



void uart_puts (char *s)


/**********************************************************************
 Function: Uart_puts()
 Purpose: Transmit string to UART
 Input: String to be transmitted
 Returns: none
 **********************************************************************/

{
    while (*s)
    {   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
        uart_putdata(*s);
        s++;
    }
}



unsigned int uart_getdata(void)
{
  if (bxoff == 0)
 {

  while (g_idx < MAX_BUFFER_SIZE){


  while (!(UCSRA & (1<<RXC)))

  c=UDR;
   if (c == '\r'){
   return c;
   }
   else
   Buf[g_idx]=c;
   g_idx++;
   }

  bxoff=1;
    return;
   }
 }

von Jano (Gast)


Lesenswert?

Hallo Kann jemand mir helfen? Bitte
Danke
Jano

von hjm (Gast)


Lesenswert?

Hallo Jano,

geht recht einfach:

1. IRQ's scharf machen
   Bit 7 (RXCIE Rx complete IRQ) in UCSRB setzen
   Bit 5 (USART Data register empty) in UCSRB setzen
  alterativ geht auch Bit 6, Transmit Complete, doch Data register empty 
hat
  den Vorteil, das sozusagen in den Zwischenspeicher geschrieben wird 
und
  damit ein kontinuierlicher Datenstrom auf der Leitung entsteht.

2. Routine erstellen
 ISR (USART_RXC_vect)
 ISR (USART_UDRE_vect)

3. IRQ's im Hauptprogramm freischalten mit sei();

Bitte daran denken, das Variablen die auch in den IRQ's genutzt werden
als volatile gekennzeichnet sein müßen

z.B.
volatile unsigned short ms;  // ms Zeitgeber

Grüße
Hans-Josef

von Jano (Gast)


Lesenswert?

danke hjm, noch einigen problemen: nach dem ich habe die IRQ mit sei() 
und die RXCIE und UDRIE im hauptprogramm freigeschaltet wie soll die 
Routinen aussehen? ich meine was soll in ISR(USART_RXC_Vect) und in 
ISR(USART_UDRE_Vect) stehen? gibt mir nur ein bsp um mir zu zeigen wie 
die routinen aussehen können. noch was soll ich etwa in meine vorherrige 
code ohne INterrupt ändern?
danke vor die Hilfe
Jano

von Hans J. (hjm)


Lesenswert?

Hallo Jano,

was willst Du denn mit den Routinen machen?

Soll was empfangen werden und gleichzeitig wieder gesendet werden, oder 
wie sieht Dein Ablauf aus?

Dann kann man eher sagen wie man es am besten macht.

In der Regel empfängt man mit Interrupt und sendet im Pollbetrieb,

da das Prg, seine Daten erst los werden muß.

Zu Deinem Prg, da gibts sicher ein paar Stellen die verbesserungswürdig 
sind,
aber wenns funktioniert!!!

Grüße
Hans-Josef

von Jano (Gast)


Lesenswert?

mein Programm soll daten empfangen und im Puffer speicher und dannach 
hole ich wieder wieder die daten im puffer und senden die.
grüße.  ich bin offen für jeden verbesserung in meinem Programm
Jano.

von Hans J. (hjm)


Lesenswert?

Hallo Jano,

präzisiere bitte Deine Angaben.

Denn:

 - wenn Du Daten in einem definierten Paket empfängst kann es bei hoher
   Baudrate passieren, das beim senden einige Daten im Empfangskanal 
verloren
   gehen,

 - wenn Du Daten mit definiertem Aussehen empfängst kann man genau einen 
Satz
   abwarten und lesen und diesen dann komplett versenden,

Hast Du noch mehr Infos zu Datenrate, Telegramm- oder Datengröße, wie 
oft und
wie diese versenden werden.

Grüße
Hans-Josef

von Wolfram (Gast)


Lesenswert?

>Zu Deinem Prg, da gibts sicher ein paar Stellen die verbesserungswürdig
>sind,aber wenns funktioniert!!!
Das ist eine Einstellung die geradewegs vor die Wand führt.

@Jano:
Du benutzt die Variable g_idx uninitialisiert. In uart_putdata weist du 
sie n zu und benutzt dann n um Schleifendurchläufe zu steuern. Die 
Anzahl der Schleifendurchläufe ist damit unbestimmt! Gewöhn dir eine 
derartige Programmierweise erst gar nicht an.
Außerdem erhöhst du deinen Pufferzeiger g_idx immer wenn du sendest und 
empfängst. Beim Senden setzt du ihn am Anfang auf 0. Wenn ich das 
richtig sehe passiert folgendes:
Angenommen du sendest 20 Zeichen. Damit steht g_idx auf 19. Damit kannst 
du im nachhinein nur noch Puffergröße - (Anzahl gesendete Zeichen beim 
letzten Aufruf von uart_putdata) empfangen. Erst durch erneutes Senden 
kannst du mehr Empfangen. Ich glaube kaum das du dies wolltest. Ich 
nehme mal an du wolltest den gesamten Puffer als Empfangspuffer 
benutzen.

Schreib lieber dein jetziges Programm erstmal ordentlich, bevor du zum 
nächsten Schritt übergehst.

von Hans J. (hjm)


Lesenswert?

Hallo Wolfram,

das ist schön das Du Dich hier mit einklinkst, aber der Ton macht die 
Musik.

Jano möchte ein Prg mit dem er empfangen und senden kann im Interrupt.

Sicherlich sind Deine Statements richtig, aber seine Frage zielte nicht 
auf die Prüfung der Korrektheit seines Progs hin, sondern wie sich so 
was mittels IRQ's realisieren läßt.

Um einen Lerneffekt zu erzielen, wäre es daher gut wenn man (Du) im ein 
entsprechendes Prg-Gerüst aufzeigen könnte.

Damit wäre Ihm sicherlich mehr geholfen als mit "6 Setzen" "Neumachen".

Ist nicht böse gemeint und soll auch nicht so aufgefasset werden, hier 
im Forum wird teilweise schon genung gestritten.

Grüße
Hans-Josef

von Jano (Gast)


Lesenswert?

Hallo Josef, hallo Wolfram,
zu erst ich bedanke mich das sie mir so helfen.

du deinen fragen Josef kann ich nur sagen für eine esrte mal ich will 
daten von Pc zu den controller sendendie daten sind Tastatur Zeichen und 
sie werden ungefähr 100 zeichen. diesen danten soll der controller 
empfangen und danach mehr mal zum PC Zurrück schicken.das wäre das esrte 
test das ich machen will

Aber später könnte sein das die Datenströme nicht begrenzt sind und 
damit das die daten nicht verloren gehen soll ich die Datenaustauscht 
mit Hardware handshake dirrigieren so das wenn mein Puffer voll ist 
signalisiere ich zu der sender das er keine daten mehr senden nach diese 
schritt leere ich mein puffer aus und schalte ich wieder das Senden 
frei.

Die Datenrate in beide richtung ist 9600bps

Danke im voraus
Jano

von Falk B. (falk)


Lesenswert?

@ Jano (Gast)

>du deinen fragen Josef kann ich nur sagen für eine esrte mal ich will
>daten von Pc zu den controller sendendie daten sind Tastatur Zeichen und
>sie werden ungefähr 100 zeichen. diesen danten soll der controller
>empfangen und danach mehr mal zum PC Zurrück schicken.das wäre das esrte
>test das ich machen will

Na da solltest du die Tutorials durcharbeiten und umsetzen. Von den 
Interrupts solltest du vorerst die Finger lassen, das ist was für die 
höheren Semester. Das kommt später.

AVR-Tutorial: UART
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Der_UART

>Die Datenrate in beide richtung ist 9600bps

Schnarchlangsam für einen uC.

MfG
Falk

von Hans J. (hjm)


Lesenswert?

Hallo Jano,

irgendwie habe ich das ganze schon einmal gelesen.

Hier: Beitrag "receive und Transmit via dem UART (ATmega16)", gings ums gleiche 
Problem.

Dort ist auch eine Lösung mittels Fleury-Lib, die übrigens gut 
dokumentiert ist.

Schau Dir das einmal an und nutze das Demo "testuart.c" aus der Lib, 
dort wir mittes IRQ empfangen und gesendet, obwohl bei der angegebenen 
Baudrate das sicherlich nicht notwendig sein sollte.

Grüße
Hans-Josef

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.