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
Lesezeichen