www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Für Experten: Durch den Einsatz von UART werden Variablen außerhalb der Hauptschleife manipuliert?


Autor: Askan Simon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Zusammen,

ich habe jetzt ein ganz interessantes Problem, das eigentlich 
unglaublich aber auch reproduzierbar ist.

Ich habe eine Gyro Werte den ich über Uart ausgeben möchte.
Für das Probgramm brauche ich noch einen Backup-Gyro Wert
den ich, gleich beim Start vor der Hauptschleife definiere.

Jetzt das unglaubliche, start ich die Uart Funktion Putchars
ändert sich der Backup Wert. Es sieht so aus aus würde dieser
immer wieder aufs neue, mit dem aktuellen Gyro-Wert überschrieben
werden.... (????)

Kommtiere ich die Putchars() aus, ändert sich der Wert nicht.

Ist das ein Compilerfehler?

Ich habe jetzt mal das Probramm soweit abgespeckt das man
das Programm hoffentlich leichter verstehen kann.
#include <avr/io.h>
#include <avr/interrupt.h>
#include "lcd_routines.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <util/delay.h>

// Uart
#define F_CPU 16000000UL
#define BAUD 9600UL          // Baudrate
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden

// clear ADC enable & ADC Start Conversion & ADC Interrupt Enable bit
#define ADC_Disable() (ADCSRA &= ~((1<<ADEN)|(1<<ADSC)|(1<<ADIE)))
#define ADC_Enable()  (ADCSRA |=   (1<<ADEN)|(1<<ADSC)|(1<<ADIE))


volatile int sensor_wert = 0;
int sensor_wert_backup = 0;

volatile int32_t i = 0;

// ADC Interrupt
ISR (ADC_vect) {

  ADC_Disable();

  sensor_wert = ADC
  
  ADC_Enable();
}

// Uart Funktionen
int put_char (char c) {
  while(!(UCSR0A & (1 << UDRE))) {
  }
  //loop_until_bit_is_set(UCSR0A, UDRE);
  UDR0 = c;
  return (0);
}
void put_chars (char *s) {
  while(*s) {
    put_char(*s);
    s++;
  }
}
void put_number(int32_t variable) {
   char Buffer[20];
   itoa(variable, Buffer, 10);
   put_chars(Buffer);
}

int main(void) {

  // Uart Initalisieren
  UCSR0B  = (1 << TXEN) | (1 << RXEN);
  UCSR0B |= (1<<RXCIE); // Interrupt freigeben
  UCSR0B |= (1<<TXCIE);
  UBRR0L  = UBRR_VAL; // Teiler setzen

  // ADC initialization
  ADMUX  = 0x00 & 0xff;
  ADCSRA = 0x8F;

  PORTF = 0x00; // Sensor auf Port
  DDRF  = 0x00;

  sei();
  lcd_init();

  // ACD Start
  ADMUX   = ADMUX | 1;
  ADCSRA |= 0x40; // ADSC = 1

  sensor_wert_backup = sensor_wert; // Variable abspeichern
  
  while (1) {

    // Debug
    i++;
    if (i > 250) { 
      i = 0;

      // LCD Ausgabe
      lcd_clear();
      set_cursor(0,1);
      lcd_number(sensor_wert_backup); // Zur Kontrolle...
    
      // Uart Ausgabe
      put_number(0);  // Sobald diese auskommentiert bleibt
                      // die Variable sensor_wert_backup
                      // unverändert
    }
    }
}



Ich arbeite mit einem Atmega64, compiliere mit WinAVR.

Ich sitzt seit heut Nachmittag an dem Problem...

Über Hilfe würde ich mich sehr freuen.

Frohe Weihnachten, vielen Dank
Viele Grüße
Askan

Autor: Der Unbekannte #2 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dein Programm resetet, sobald das erste Zeichen gesendet wird, weil Du 
keine Interrupt-Routine für das UART-Senden deklariert hast, aber 
dennoch die RX/TX-Interrupts einschaltest.

Autor: Hannes Jaeger (pnuebergang)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Keine ISRs für RX und TX Interrupts.

Autor: Askan Simon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

vielen Dank für Eure Hilfe. !!!
Wär ich selbst nie drauf gekommen.

Viele Grüße aus Neuss
Askan

Autor: Askan Simon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

da im Tutorial nich so viel steht, reicht dann einfach
ISR (USART_RXC_vect) {
}
ISR (USART_TXC_vect) {
}

oder muß der Uart grundsätzlich anders aufgebaut werden,

ISR(USART_RXC_vect) {
  PORTB=0xF0;
  register unsigned char akku;
  akku = UDR;
  while (!(UCSRA & (1<<UDRE)));     // warten bis Senden moeglich
  UDR = akku;                          // sende Zeichen
}


Ich habe diesen Teil ja schon in den put_char() Funktionen
gelößt.

Kenn mich hier leider nicht so gut aus.

Vielen Dank & Viele Grüße
Askan

Autor: 6789 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, der Interrupt kommt wenn der puffer leer, resp voll ist, da muss 
man dann nicht mehr warten. DSondern gleich das zeichen in das UART 
schieben, resp ausm UART lesen. Speziell aufpassen muss man am Ende des 
zu sendenden Blockes, dann kommt der Interrupt, man schiebt allerdicngs 
kein neues Zeichen rein. Dann muss man gemaess datenblatt abbrechen.

Autor: crazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Interrupt-Betrieb ist (fast) immer vorzuziehen:

/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.6 Standard
Chip type           : ATmega32
Program type        : Application
Clock frequency     : 16,000000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 512
*****************************************************/

#include <mega32.h>

#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)

// USART Receiver buffer
#define RX_BUFFER_SIZE 16
char rx_buffer[RX_BUFFER_SIZE];

#if RX_BUFFER_SIZE<256
unsigned char rx_wr_index,rx_rd_index,rx_counter;
#else
unsigned int rx_wr_index,rx_rd_index,rx_counter;
#endif

// This flag is set on USART Receiver buffer overflow
bit rx_buffer_overflow;

// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSRA;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
   {
   rx_buffer[rx_wr_index]=data;
   if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
   if (++rx_counter == RX_BUFFER_SIZE)
      {
      rx_counter=0;
      rx_buffer_overflow=1;
      };
   };
}

#ifndef DEBUG_TERMINAL_IO
// Get a character from the USART Receiver buffer
#define ALTERNATE_GETCHAR
#pragma used+
char getchar(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index];
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#asm("cli")
--rx_counter;
#asm("sei")
return data;
}
#pragma used-
#endif

// USART Transmitter buffer
#define TX_BUFFER_SIZE 16
char tx_buffer[TX_BUFFER_SIZE];

#if TX_BUFFER_SIZE<256
unsigned char tx_wr_index,tx_rd_index,tx_counter;
#else
unsigned int tx_wr_index,tx_rd_index,tx_counter;
#endif

// USART Transmitter interrupt service routine
interrupt [USART_TXC] void usart_tx_isr(void)
{
if (tx_counter)
   {
   --tx_counter;
   UDR=tx_buffer[tx_rd_index];
   if (++tx_rd_index == TX_BUFFER_SIZE) tx_rd_index=0;
   };
}

#ifndef DEBUG_TERMINAL_IO
// Write a character to the USART Transmitter buffer
#define ALTERNATE_PUTCHAR
#pragma used+
void putchar(char c)
{
while (tx_counter == TX_BUFFER_SIZE);
#asm("cli")
if (tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0))
   {
   tx_buffer[tx_wr_index]=c;
   if (++tx_wr_index == TX_BUFFER_SIZE) tx_wr_index=0;
   ++tx_counter;
   }
else
   UDR=c;
#asm("sei")
}
#pragma used-
#endif

// Standard Input/Output functions
#include <stdio.h>


// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0xD8;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x67;



// Global enable interrupts
#asm("sei")

while (1)
      {
      // Place your code here

      };
}

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Askan S. wrote:
> Hallo,
>
> da im Tutorial nich so viel steht, reicht dann einfach
Ist schon ok so.

> Ich habe diesen Teil ja schon in den put_char() Funktionen
> gelößt.
Eben. Wenn du das Versenden einfach in einer Schleife machst, dann 
schalte doch den TX-Interrupt einfach ab, den brauchste doch dann 
garnicht -- schließlich prüfst du ja schon in der Schleife, ob der UART 
bereit ist. Und das Interruptflag, das du da prüfst, wird auch gesetzt, 
wenn der Interrupt nicht freigegeben ist.

Und Interrupts sind nicht generell immer vorzuziehen. Im Hauptprogramm 
ists einfach unnötig, die Senderoutine nochmal mit Interrupts 
aufzubrechen, solange du sowieso nix Andres zu tun hast.
Ansonsten rumpuffern, wie der wilde Gaul vorgeschlagen hat :-)

Autor: Askan Simon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

vielen Dank für die Hilfe. Ich denke ich komme jetzt, auch vielen
Dank für das Beispiel, hatte hier schon lange gesucht.

Frohe Weihnachten, Viele Grüße
Askan

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.