mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik STM32F303 USART in Kombination mit Timer+ADC+DMA der 2te


Autor: Andreas T. (skycurve)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

es geht darum, dass die serielle Kommunikation per UART die ADCs und den 
DMA stört.

Ein Java Programm auf dem PC soll verschiedene Variablen des 
Mikrocontrollers abfragen können. Der uC sendet nur dann etwas, wenn er 
gefragt wird.

Aufbau einer solchen Abfrage:
|STX|Var_Number_Byte_1|Var_Number_Byte_0|'?'|ETX|

(Weil ich mehr als 256 Variablen monitoren können möchte, indexiere ich 
die Variable über 2 Bytes)

Eine Abfrage kann beispielsweise so aussehen:
   2 0                  1     '?'  3


2 -> STX
0 -> MSByte der Variablen Nummer
1 -> LSByte der Variablen Nummer
'?' -> "Computer möchte lesen"
3 -> ETX

hier möchte der Computer den Wert der Variable 01 lesen.
Es kann sich dabei um unterschiedliche Datentypen handeln: Int, UInt, 
Float.
Alle Variablen sind 32bit groß, deshalb werden sie als ein 4 Byte großes 
Packet gesendet und mit einem ETX abgeschlossen.
Das Array "variables" enthält die Adressen der Variablen, die abgefragt 
werden können. Es kann Adressen eines Ints, UInts und Floats enthalten.

Quellcode der seriellen Kommunikation:
#define rx_buffer_size 20

void init_serial(void)
{
  // config GPIOs
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_7);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_7);


    // config NVIC
    NVIC_InitTypeDef NVIC_InitStructure; //create NVIC structure
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);


  // config USART1
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

  USART_InitTypeDef USART_Initialisation;
  USART_Initialisation.USART_BaudRate = 9600;
  USART_Initialisation.USART_WordLength = USART_WordLength_8b;
  USART_Initialisation.USART_StopBits = USART_StopBits_1;
  USART_Initialisation.USART_Parity = USART_Parity_No;
  USART_Initialisation.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_Initialisation.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  /* USART configuration */
  USART_Init(USART1, &USART_Initialisation);

  /* Enable the USART1 Receive interrupt */
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

  /* Enable USART */
  USART_Cmd(USART1, ENABLE);

}

int variables[20];

int var_number = 0;
int working_variable = 0;

volatile char rx_buffer[rx_buffer_size];

volatile int rx_buffer_index = 0;
volatile int data_ready = 0;

char tx_data_byte_0;
char tx_data_byte_1;
char tx_data_byte_2;
char tx_data_byte_3;

void USART1_IRQHandler(void)
{
  if (USART_GetITStatus(USART1,USART_IT_RXNE) == SET)
    {
        USART_ClearITPendingBit(USART1,USART_IT_RXNE);


        switch (USART1->RDR) {
      case 2: // STX received
        rx_buffer_index = 0;
        break;
      case 3: // ETX received
        data_ready = 1;
        break;
      default: // usual data
        rx_buffer[rx_buffer_index] = USART1->RDR;
        rx_buffer_index++;
        if(rx_buffer_index >= rx_buffer_size) // prevent rx_buffer overflow
        {
          rx_buffer_index--;
        }
        break;
    }

    }
}




void serial_monitor(void)
{
  if(data_ready == 0) // wenn keine neuen Daten vorhanden oder der Datensatz noch nicht zu Ende übertragen wurde
  {
    return;
  }


  // ermittle, welche Variable gerade angesprochen wird
  var_number = (rx_buffer[0] << 8) + rx_buffer[1];

  working_variable = variables[var_number];

  if(rx_buffer[2] == 63) // 63 == '?' -> PC will lesen
  {
    tx_data_byte_3 = ((char *)(working_variable))[0];
    tx_data_byte_2 = ((char *)(working_variable))[1];
    tx_data_byte_1 = ((char *)(working_variable))[2];
    tx_data_byte_0 = ((char *)(working_variable))[3];


    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    USART_SendData(USART1, tx_data_byte_3);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    USART_SendData(USART1, tx_data_byte_2);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    USART_SendData(USART1, tx_data_byte_1);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    USART_SendData(USART1, tx_data_byte_0);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    USART_SendData(USART1, 3); // send ETX
  }

  data_ready = 0;
}



void init_variables(void)
{
  variables[0] = (int) &tmp_uint;
  variables[1] = (int) &tmp_int;
  variables[2] = (int) &tmp_float;
}

(Die Funktion 'serial_monitor()' wird immer wieder in der main while(1) 
Schleife aufgerufen)

Alles funktioniert soweit. Zusätzlich soll ein Timer für PWM laufen, 
welcher mit seinem TRGO2 zwei ADCs im Dualmode triggert. Die ADCs 
sampeln mehrere Channel, die Sampelwerte werden per DMA abgeholt. 
Nachdem alle Channel gesampelt wurden, soll der DMA1_Channel1_IRQHandler 
aufgerufen werden.

Quellcode der Konfiguration:
/**************************************************************************************/
void TIM1_Configuration(void)
{
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

  // Pin configuration
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_Init(GPIOB, &GPIO_InitStructure);


  // Table 14. STM32F303 alternate function mapping
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_6);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_6);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_6);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_6);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_6);
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, GPIO_AF_6);


  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_OCInitTypeDef TIM_OCInitStructure;


  TIM_TimeBaseStructure.TIM_Prescaler = 0;
  TIM_TimeBaseStructure.TIM_Period = 1600; // Auto reload value
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1;
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

  TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);


  TIM_OCStructInit(&TIM_OCInitStructure);
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 0;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
  TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;




  TIM_OC1Init(TIM1, &TIM_OCInitStructure);
  TIM_OC2Init(TIM1, &TIM_OCInitStructure);
  TIM_OC3Init(TIM1, &TIM_OCInitStructure);
  TIM_OC5Init(TIM1, &TIM_OCInitStructure);
  TIM1->CCR5 = TIM1->ARR-1;


  TIM_BDTRInitTypeDef TIM_BDTRInitStructure;

  /* Automatic Output enable, Break, dead time and lock configuration*/
  TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Disable;
  TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Disable;
  TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
  TIM_BDTRInitStructure.TIM_DeadTime = 7; // (TIM_DeadTime/SystemCoreCLock) = us
  TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
  TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
  TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable;

  TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);


  TIM_ARRPreloadConfig(TIM1, ENABLE);

  TIM1->CR1 |= TIM_CR1_ARPE;  // Enable auto reload


  TIM_Cmd(TIM1, ENABLE);
  /* TIM1 Main Output Enable */
  TIM_CtrlPWMOutputs(TIM1, ENABLE);

  TIM_SelectOutputTrigger2(TIM1, TIM_TRGO2Source_OC5Ref);
}
/**************************************************************************************/
void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  /* Enable DMA1 channel1 IRQ Channel */
  NVIC_InitStructure.NVIC_IRQChannel = /*11;//*/DMA1_Channel1_IRQn;
  NVIC_Init(&NVIC_InitStructure);


}
/**************************************************************************************/
void ADC_GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

  /* Enable GPIOA and GPIOB Periph clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB, ENABLE);

  /* ADC Channels configuration */
  /* Configure  as analog input */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_7;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/**************************************************************************************/
void ADC12_DMA_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure;

  /* Enable DMA1 clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  /* DMA configuration */
  /* DMA1 Channel1 Init Test */
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC12_CDR_ADDRESS;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC12DualConvertedValue[0];
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = SAMPLES;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  DMA_Init(DMA1_Channel1, &DMA_InitStructure); // ADC1
}
/**************************************************************************************/
void ADC_Configuration(void)
{
    ADC_InitTypeDef        ADC_InitStructure;
    ADC_CommonInitTypeDef  ADC_CommonInitStructure;
  volatile int i;
//    uint16_t CalibrationValue[4];

  /* Configure the ADC clocks */
  RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div1);

  /* Enable ADC1/2/3/4 clocks */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE);

  /* ADC GPIO configuration */
  ADC_GPIO_Configuration();

  /* ADC DMA Channel configuration */
  ADC12_DMA_Configuration();

  /* ADC Calibration procedure */
  ADC_VoltageRegulatorCmd(ADC1, ENABLE);
  ADC_VoltageRegulatorCmd(ADC2, ENABLE);


  /* Insert delay */
  for(i=0; i<10000; i++);

  ADC_SelectCalibrationMode(ADC1, ADC_CalibrationMode_Single);
  ADC_StartCalibration(ADC1);

  ADC_SelectCalibrationMode(ADC2, ADC_CalibrationMode_Single);
  ADC_StartCalibration(ADC2);



  while(ADC_GetCalibrationStatus(ADC1) != RESET );
  CalibrationValue[0] = ADC_GetCalibrationValue(ADC1);

  while(ADC_GetCalibrationStatus(ADC2) != RESET );
  CalibrationValue[1] = ADC_GetCalibrationValue(ADC2);

  /* ADC Dual mode configuration */
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_RegSimul;
  ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode;
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; // 12-bit
  ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_Circular;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = 10;

  ADC_CommonInit(ADC1, &ADC_CommonInitStructure);

  /* */
  ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Disable; // Triggered
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_RisingEdge;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Disable;
  ADC_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable;
  ADC_InitStructure.ADC_NbrOfRegChannel = 3;

  ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_10; // Entspricht dem TRGO2 des TIM1

  ADC_Init(ADC1, &ADC_InitStructure);
  ADC_Init(ADC2, &ADC_InitStructure);



  /*
  ____|Seq1|Seq2|Seq3|
  ADC1|PB0 |PA0 |PA1 |
  ADC2|PA7 |-   | -  |
  */

  /* ADC1 regular configuration */
  ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_7Cycles5); // PB0
  /* ADC2 regular configuration */
  ADC_RegularChannelConfig(ADC2, ADC_Channel_4, 1, ADC_SampleTime_7Cycles5); // PA7


  /* ADC1 regular configuration */
  ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_7Cycles5); // PA0


  /* ADC1 regular configuration */
  ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_7Cycles5); // PA1


  /* Configures the ADC DMA */
  ADC_DMAConfig(ADC1, ADC_DMAMode_Circular);

  /* Enable the ADC DMA */
  ADC_DMACmd(ADC1, ENABLE);

  /* Enable ADC[1..2] */
  ADC_Cmd(ADC1, ENABLE);
  ADC_Cmd(ADC2, ENABLE);


  /* wait for ADC1 ADRDY */
  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_RDY));

  /* wait for ADC2 ADRDY */
  while(!ADC_GetFlagStatus(ADC2, ADC_FLAG_RDY));


  /* Enable the DMA channel */
  DMA_Cmd(DMA1_Channel1, ENABLE);

  /* Enable DMA1 Channel1 Transfer Complete interrupt */
  DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);


  /* Start ADC1 Software Conversion */
  ADC_StartConversion(ADC1);

}
/**************************************************************************************/
void DMA1_Channel1_IRQHandler(void)
{
  /* Test on DMA1 Channel1 Transfer Complete interrupt */
  if (DMA_GetITStatus(DMA1_IT_TC1))
  {

    /* Clear DMA1 Channel1 Half Transfer, Transfer Complete and Global interrupt pending bits */
    DMA_ClearITPendingBit(DMA1_IT_GL1);

    adc_interrupt();

  }
}

void Periph_Configuration(void)
{
  SystemInit();
  TIM1_Configuration();

  ADC_Configuration();

  /* Enable DMA1 Channel1 Transfer Complete interrupt */
  DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);

  NVIC_Configuration();

}
/**************************************************************************************/
int main(void)
{
        init_variables();
  init_serial();
  Periph_Configuration();

  while(1)
  {
    serial_monitor();
  }
}


Funktioniert alles soweit auch: Es werden Daten seriell an den PC 
übertragen, PWM Signale werden generiert, ADCs sampeln die Channel, 
Sampelwerte werden per DMA abgeholt und es wird
in den DMA1_Channel1_IRQHandler gewechselt. Dort wird vorerst nur eine 
Float Variable um 0.1 erhöht.
Nach einer gewissen, unbestimmbaren Zeit (1-60s) hören die ADCs 
plötzlich auf zu sampeln und es wird nicht in den 
DMA1_Channel1_IRQHandler gesprungen.
Die serielle Kommunikation läuft problemlos weiter. Es werden weiterhin 
richtige Werte an den PC übertragen.
Ohne serieller Kommunikation tritt das Problem nicht auf.

Wie könnte das zusammenhängen?

Gruß

Autor: Jim M. (turboj)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas T. schrieb:
> Dort wird vorerst nur eine
> Float Variable um 0.1 erhöht.

Das geht aber nur eine bestimmte Zeit gut, denn Float hat nur 5-6 
signifikante Stellen. Irgendwann sind Deine 0.1 zu klein um noch die 
Mantisse bei der großen Zahl beeinflussen zu können. Dann hat die 
Addition der kleinen Zahl keinen Effekt mehr.

Nimm lieber einen unsigned int als Zähler.

Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas T. schrieb:
> Dort wird vorerst nur eine
> Float Variable um 0.1 erhöht.

Schlechte Idee. 0.1 dezimal hat keine exakte Entsprechung im float, 
ähnlich wie man 1/3 nicht mit einer endlichen Dezimal-Kommadarstellung 
haben kann.

Als Zähler nimmt man Integer. Die nächstbessere Lösung ist es, 
Intervalle wie 1/2, 1/4, 1/8 usw. zu nehmen, weil die eine exakte 
Darstellung haben.

Mußt Du wirklich Intervalle von 0.1 haben, dann nimmt man einen Integer 
und konvertiert ihn vor der Intervallauswertung nach float, dann 
dividiert man das durch 10.0f.

Autor: Andreas T. (skycurve)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich verwende diese Float Variable nicht als Zähler oder ähnliches. Ich 
kann hier genauso einen Integer nehmen und ihn um 1 erhöhen oder auch 
gar nichts machen -> das Problem tritt genau so auf.

Gruß

: Bearbeitet durch User
Autor: W.S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oje oje, was für einen riesigen Batzen Quellcode hast du da gepostet. 
Wer soll statt deiner sich da durchquälen?

Nun, wenn ich beim Überfliegen deiner Quelle sowas sehe:

Andreas T. schrieb:
> void USART1_IRQHandler(void)
> {
>   if (USART_GetITStatus(USART1,USART_IT_RXNE) == SET)
>     {
>         USART_ClearITPendingBit(USART1,USART_IT_RXNE);
>
>         switch (USART1->RDR) {

..dann wird mir schlecht.

Warum um alles in der Welt schaffen es die heutigen Programmierer nicht, 
die Dinge und deren Ebenen sauber auseinander zu halten? In jeder 
Firmware gibt es ne Hierarchie:
1. Hardware
2. LoLevelTreiber
3. ggf.höhere Treiber (Protokolle)
4. Algorithmen, also das, was die Firmware eigentlich tun soll

Schreibe dir einen Treiber für deinen USART, der eben diesen USART 
sauber abstrahiert und den Datenstrom in beiden Richtungen puffert und 
organisiert. UND NICHT MEHR!

Was hat dich geritten, daß du in deinen Treiber eine Auswertung der 
Daten schreibst? (switch (USART.RDR)...) Sowas gehört dort 
allerkeinstenfalls hin.

Zweitens: dein Usart_Clear_PendingBit ist mir suspekt. Lies das 
Refmanual. Soweit mir erinnerlich, ist sowas ein Bug. Das RX-Bit wird 
von der Hardware automatisch gelöscht, sobald RDR gelesen wurde. Das 
bedeutet übrigens auch, daß du RDR nur ein einziges Mal pro empfangenem 
Byte lesen darfst. Also, die Regel ist:
1. Status lesen und auswerten, geht m.W. beliebig oft
2. RDR auslesen (geht nur 1x) und Byte wegspeichern.
(Falls das Lesen von RDR bei dir ausnahmsweise mehrfach geht, dann ist 
das entweder ein Zufall oder der Compiler hat den zweiten Zugriff 
wegoptimiert oder das Startbit des nächste Bytes am Pin ist noch nicht 
detektiert.

Ich geb dir mal ein funktionierendes Beispiel (hab das hier schon 
mehrfach gepostet). Läuft gut, wertet allerdings Fehlersituationen nicht 
aus.
__irq void USART1_IRQHandler (void)
{ char c;
  int  i, j;

  if (USART1_ISR & ((1<<5)|(1<<3))) // RX: Zeichen empfangen oder Overrun
  { // hier ggf. Overrun, Parity, Frame u.a. Errors auswerten
    
    // Zeichen abholen
    c = USART1_RDR;
    i = U1Buf.InWP;
    j = (i+1) & (IBLEN-1);
    if (j!=U1Buf.InRP)
    { U1Buf.InBuf[i] = c;
      U1Buf.InWP = j;
    }
  }

  if  (USART1_ISR & (1<<7))              // TX: Sendepuffer leer geworden
  { i = U1Buf.OutRP;
    if (i!=U1Buf.OutWP)                  // ob es was zu senden gibt
    { USART1_TDR  = U1Buf.OutBuf[i];
      U1Buf.OutRP = (i+1) & (OBLEN-1);
    }
    else
    { USART1_CR1 &= ~(3<<6);             // nö, TXEIE und TCIE ausschalten
    }
  }
}

W.S.

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.