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:
Jemand ne Ahnung woran das liegen könnte ?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; }
Jede Idee könnte helfen
MfG
Jens







Zitieren

Lesezeichen