-         

Ergebnis 1 bis 4 von 4

Thema: [gelöst]Sporadischer Fehler von PC an mega168

  1. #1
    Benutzer Stammmitglied
    Registriert seit
    17.12.2006
    Beiträge
    39

    [gelöst]Sporadischer Fehler von PC an mega168

    Anzeige

    Hallo

    ich habe ein Problem beim Senden von Daten vom PC an einen Atmega168.
    Ich verwende WinAVR 20081205.
    Das board ist ein RN-Mini-Control von Robotikhardware.de (Fertig gekauft)
    An dieses möchte ich vom PC den Wert einer "Trackbar" (0 bis 255) senden um die geschwindigkeit eines Motors zu einzustellen.
    Dazu sollen zwei Byte übertragen werden: Als erstes eine Befehlsnummer, in diesem Fall eine 1 die dem Controller mitteilen soll das nun der Wert für die PWM des Motors kommt. Und als zweites Byte der Wert selbst.

    Vom PC werden die zwei Bytes auch korrekt gesendet. Ich habe das mit hilfe eines Nullmodemkabels überprüft. Der PC kann von COM4 zu COM1 soviele Bytes senden wie er will es kommen immer alle korrekt an.
    Bei der Kommunikation mit dem Controller kommt es allerdings sporadisch zu Fehlern! Zwischendurch springt der Motor einfach auf volle Geschwindigkeit und beim nächsten Wert ist wieder alles normal.

    Hier ist der komplette Code:
    Code:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <inttypes.h>
    #include <util/delay.h>
    
    #define BAUD 9600UL
    #define UBRR_BAUD ((F_CPU/(16UL*BAUD))-1)
    
    #define UART_SEND_READY 	(UCSR0A & (1<<UDRE0))  // UDRE in UCSRA gesetzt
    #define UART_RECEIVED 		(UCSR0A & (1<<RXC0))
    #define ADC_START_CONV		(ADCSRA |= (1<<ADSC)) 
    #define DATAOVERRUN 		(UCSR0A & (1<<DOR0)) 
    #define FRAMEERROR			(UCSR0A & (1<<FE0))
    
    
    #define PWM_VALUE OCR2A
    
    #define nop() asm volatile ("nop")
    
    
    #define SENDENSIZE 		9
    #define EMPFANGENSIZE 	2
    
    #define DATENAUSLESEN 	1
    #define RESET 			2
    #define PWM_SETZEN		1
    #define DATENSENDEN		1
    
    volatile uint8_t senden[SENDENSIZE];					// volatile ist wichtig damit die 
    volatile uint8_t empfangen[EMPFANGENSIZE];				// variable auch in der ISR verwendet werden kann
    volatile uint8_t empfangbyte=0;
    volatile uint8_t ADC_channel=0;
    volatile uint8_t ADC_byte=1;
    volatile uint8_t empfangsbefehl=0;
    
    void Uart_Init(void)
    {
    
    	
    	UBRR0 = UBRR_BAUD;
    	
    	//Enable receiver and transmitter
    	UCSR0B = (1<<RXEN0)|(1<<TXEN0) | (1<<RXCIE0);
    	
    	// Set frame format: 8data, 1stop bit 
    	UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
    
    }
    
    
    void PWM_Init(void)
    {
    	TCCR2A = (1<<COM2A1) | (1<<WGM20);
    	TCCR2B = (1<<CS22);
    	DDRB |= (1<<3);
    	PWM_VALUE=0;
    	
    }
    
    
    void Input_Capture_Init(void)
    {
    	//ICNC1 = Noise Filter , CS10-12 Vorteiler auswählen
    	TCCR1B = (1<<CS10) | (1<<CS12) | (1<<ICNC1);
    	
    	//ICIE1 = Interrupt enable , TOIE = Interrupt bei überlauf
    	TIMSK1 = (1<<ICIE1) | (1<<TOIE1);
    	
    	DDRB &= ~(1<<0);		// Pin B0 als eingang
    	PORTB |= (1<<0);		// Pullup an Pin B0 einschalten
    }
    
    
    void ADC_channel_select(uint8_t channel)
    {
    		
    	ADMUX = channel;		//ADC port auswählen
    	
    	//Referenzspannung AVCC
    	ADMUX |= (1<<REFS0); 
    
    	// ADEN = ADC-Enable ; ADSP0-2 = Vorteiler auf 128 setzen
    	ADCSRA = (1<<ADEN) | (1<<ADIE) | (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2);
    
    }
    
    
    void Senden(uint8_t anzahlbytes, volatile uint8_t data[])
    {
    	uint8_t byte;	
    
    	for(byte=0 ; byte<anzahlbytes ; byte++)		//für alle bytes
    	{
    		while(!UART_SEND_READY) { nop(); }		//Solange noch gesendet wird warten
    		UDR0 = data[byte];	//Byte aus dem Sendearray senden
    	}
    }
    
    void pin_init(void)
    {
    	DDRD |=(1<<6);
    	DDRD |=(1<<7);
    	DDRB |=(1<<5);
    	PORTB |=(1<<5);
    	PORTD |=(1<<6);
    	PORTD &=~(1<<7);
    
    }
    
    
    void anmelden(void)          // Sendet eine 63 bis diese vom PC entdeckt und mit einer 42 beantwortet wird
    {								// der pc weiß dann an welchen COM-port der Controller angeschlossen ist
    	while(UDR0!=42)
    	{
    		while(!UART_SEND_READY) { nop(); }		//Solange noch gesendet wird warten
    		UDR0=63;
    		_delay_ms(100);
    	}
    }
    
    void empty_buffer(void)
    {
    	uint8_t buffer;
    	// Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte) 
        do 
        { 
            buffer = UDR0; 
        } 
        while (UART_RECEIVED); 
    }
    
    int main(void)
    {
    
    	Uart_Init();
    	ADC_channel_select(0);
    	Input_Capture_Init();
    	PWM_Init();
    	pin_init();
    	
    	anmelden();			//am pc anmelden
    	
    	sei();
    	
    	while (1) {		
    		_delay_ms(100);
    		
    		if (DATAOVERRUN | FRAMEERROR) empty_buffer();    
    		
    		if (empfangen[0]==PWM_SETZEN && !DATAOVERRUN && !FRAMEERROR) PWM_VALUE = empfangen[1]; 
    		
    		if (ADC_channel == 0) 
    		{
    			senden[0]=DATENSENDEN;			//erstes byte gibt an was der controller vom pc möchte
    			Senden(SENDENSIZE, senden);		//alle daten senden
    			ADC_START_CONV;					//adc's neu auslesen
    		}
    	}
    }
    
    
    ISR (TIMER1_CAPT_vect)
    {
    	TCNT1=0;							// Timer1 zurücksetzten
    	senden[7]=ICR1L;					//icr low byte
    	senden[8]=ICR1H;					//icr high byte
    }
    
    ISR (USART_RX_vect)
    {
    	empfangen[empfangbyte]=UDR0;		//empfangenes byte ins empfangsarray schreiben
    	empfangbyte++;						// index raufzählen
    	if (empfangbyte == EMPFANGENSIZE) 	// wenn alles empfangen wurde 
    	{
    		empfangbyte=0;					// index zurücksetzen
    	}	
    }
    
    
    ISR (ADC_vect)
    {
    	senden[ADC_byte]=ADCL;			//Lowbyte des ADCs ins Sendearray schreiben
    	senden[ADC_byte+1]=ADCH;		//Highbyte des ADCs ins Sendearray schreiben
    	ADC_byte +=2;					//Bytenr für die nächste wandlung um 2 erhöhen
    	ADC_channel++;					//channel nr erhöhen
    	ADC_channel_select(ADC_channel);	//channel auswählen
    	if (ADC_channel < 3) ADCSRA |= (1<<ADSC);	//ADSC = ADC Start Conversion 
    	else	//wenn alle channel durch sind
    	{
    		ADC_channel=0;   //wieder bei 0 beginnen
    		ADC_byte=1;
    		ADC_channel_select(ADC_channel); //channel 0 auswählen
    	}
    }
    
    ISR (TIMER1_OVF_vect)		//Wenn der Timer überlauft wird er auf 60000 zurückgesetzt
    {							//Wenn der Intervall zu groß ist pendelt der Timer immer zwischen 60000 und 65536 
    	TCNT1=60000;		
    }
    Jemand ne Ahnung woran das liegen könnte ?
    Jede Idee könnte helfen

    MfG
    Jens

  2. #2
    Super-Moderator Robotik Visionär Avatar von PicNick
    Registriert seit
    23.11.2004
    Ort
    Wien
    Beiträge
    6.836
    Nur so als erster Eindruck:
    Du hast in den ISR-Routinen 'ne menge sende-befehle. Bei Baud 9600 dauert ein byte senden ~ 1mS.
    Für den Input ist er dann taub, da kann schon was verloren gehen, wenn sich das überlappt.
    mfg robert
    Wer glaubt zu wissen, muß wissen, er glaubt.

  3. #3
    Benutzer Stammmitglied
    Registriert seit
    17.12.2006
    Beiträge
    39
    Danke für deine Antwort.
    In den ISR's sind allerdings keine Senden befehle. Ich belade nur das array "senden[]" mit Werten. Gesendet wird nur in der main mit dem befehl "Senden(SENDENSIZE, senden);"

  4. #4
    Benutzer Stammmitglied
    Registriert seit
    17.12.2006
    Beiträge
    39
    Hallo,

    ich habe den Fehler gefunden \/ \/ \/

    es lag an der Masseverbindung des RS232 Steckers. Dummerweise habe ich mich beim anschließen der Kabel auf ein FALSCH BESCHRIFTETES Bild verlassen. Jetzt wo die Masseverbindung über Pin 5 läuft werden keine Falschen Werte mehr empfangen =)

    Ich bin extrem erleichtert!

    Gruß Jens

Berechtigungen

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