Перейти к содержанию
    

Тема может быть избита. не понимаю как оргнизовать работу UART по прерывания(+)

Нашел примеры работы UART-a / которые выкладывал VAI? но у него используется только перрывание на прием. Я же хочу чтобы и на передачу и на прием работало по прерваниям

 

Мой код

в основной программе

Uart0PutChar(0x30); прерывание проходит

Uart0PutStr("qwe"); тут как карта ляжет, программа зацикливается

....

while(*str){

Uart0Tx.PtrWrByte = ++Uart0Tx.PtrWrByte & UART_BUFFER_MASK;

while (Uart0Tx.PtrWrByte == Uart0Tx.PtrRdByte) {} // программа зацикливается

Как я понимаю, происходит изменение указателя а в это время возникает прерывание на TX и указатель Uart0Tx.PtrRdByte принимает значение Uart0Tx.PtrWrByte

 

-----------------------------------------

Модуль Uart.c

#pragma vector=USART0TX_VECTOR
__interrupt void irq_Uart0_Tx(void)
{
    if (Uart0Tx.PtrWrByte != Uart0Tx.PtrRdByte){
        Uart0Tx.PtrRdByte = ++Uart0Tx.PtrRdByte & UART_BUFFER_MASK;
        TXBUF0 = Uart0Tx.Buffer[Uart0Tx.PtrRdByte];
    }    //
    else{
         //
         // флаг на завершение Tx и необходимости переключится на прием
         //
//         if (EventFlags & fwRxWaitTime){
//             //bSwitchTxToRx = 1;                 // EventFlags |= fwSwitchTxToRx;
//             pRS485Tx = 0;                      // приемопередатчик на Rx
//         }

    }

#pragma vector=USART0RX_VECTOR
__interrupt void irq_Uart0_Rx(void)
{
    volatile char dummy;
    unsigned char RxData;

    if ( FE+PE+OE+BRK+RXERR ){                          // overflow or framing error -
        URCTL1 &= ~ (FE+PE+OE+BRK+RXERR);               // Clear error flags
        dummy = RXBUF0;                                 // dummy read to clear RXE flag
        }
    else{
         RxData = RXBUF0;                               // Read the received data
         if ((Uart0Rx.PtrWrByte + 1) != Uart0Rx.PtrRdByte){
            Uart0Rx.PtrWrByte = ++Uart0Rx.PtrWrByte & UART_BUFFER_MASK;
            Uart0Rx.Buffer[Uart0Rx.PtrWrByte] = RxData;
         }
    }
}

void Uart0PutChar(unsigned char TxData)
{
    Uart0Tx.PtrWrByte = ++Uart0Tx.PtrWrByte & UART_BUFFER_MASK;
    while (Uart0Tx.PtrWrByte == Uart0Tx.PtrRdByte) {
        //
        //  Сброс сторожевого таймера
        //
    }   // Wait for incomming data
    Uart0Tx.Buffer[Uart0Tx.PtrWrByte] = TxData;
    if  ((IFG1 & UTXIFG0) != UTXIFG0)           //    UART0_ENABLE_TX_INTERRUPT;
        IFG1 |= UTXIFG0;
}

void Uart0PutStr(unsigned char *str)
{
//    while(*str) Uart0PutChar(*str++);  //*s++=Tmpchar;
    while(*str){
        Uart0Tx.PtrWrByte = ++Uart0Tx.PtrWrByte & UART_BUFFER_MASK;
        while (Uart0Tx.PtrWrByte == Uart0Tx.PtrRdByte) {}   // Wait for incomming data

        Uart0Tx.Buffer[Uart0Tx.PtrWrByte] = *str++;
        if  ((IFG1 & UTXIFG0) != UTXIFG0)       //UART0_ENABLE_TX_INTERRUPT;
            IFG1 |= UTXIFG0;
    }
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Позволю себе сделать несколько замечаний.

1. При работе не атомарными операциями с разделяемыми переменными надо или вводить атомарные флаги или запрещать прерывания, как Вы правильно заметили.

2. При работе с RS485 я лично делаю так: при начале передачи даю разрешение на драйвер и отключаю прерывание RX, чтобы не принять свою собственную посылку если что. В конце передачи запрещаю драйвер, читаю RXBUF дабы очистить флаги и уже потом разрешаю прерывание RX. Такая схема откатана и работает. Делаю так всегда, даже если у чипа RS485 есть запрещение приёма.

3. Не совсем понимаю логику работы с TX. Не проще ли сделать так:

При необходимости передать один байт и подождать завершения передачи - запретить прерывание TX, положить байт в TXBUF и ждать флага.

При необходимости передать один байт и не ждать завершения - запретить прерывание TX, положить байт в TXBUF и больше ничего не делать.

При необходимости передать несколько байт и подождать завершения передачи - разрешить прерывание TX, положить байт в TXBUF и передавать остальные байты по прерыванию.

4. Код прерываний у Вас, похоже, рабочий. Еще не совсем понятна конструкция

    
URCTL1 &= ~ (FE+PE+OE+BRK+RXERR);               // Clear error flags

ибо Reading UxRXBUF resets the receive-error bits, the RXWAKE bit, and URXIFGx. И еще причем здесь URCTL1? Вы ведь испольуете первый USART?

Изменено пользователем HARMHARM

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2. При работе с RS485 я лично делаю так: при начале передачи даю разрешение на драйвер и отключаю прерывание RX, чтобы не принять свою собственную посылку если что. В конце передачи запрещаю драйвер, читаю RXBUF дабы очистить флаги и уже потом разрешаю прерывание RX. Такая схема откатана и работает. Делаю так всегда, даже если у чипа RS485 есть запрещение приёма.

ну вообщем-то код пишетс яне только для работы по Rs485. Так и сделал уже(запрещаю прерывания)

Код прерываний у Вас, похоже, рабочий. Еще не совсем понятна конструкция

    
URCTL1 &= ~ (FE+PE+OE+BRK+RXERR);               // Clear error flags

ибо Reading UxRXBUF resets the receive-error bits, the RXWAKE bit, and URXIFGx. И еще причем здесь URCTL1? Вы ведь испольуете первый USART?

Ошибочка закралась, да и точно снимаются они чтением UxRXBUF

Спасибо :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не успел добавить комментарии, прочтите моё сообщение еще раз ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Модуль Uart.c

    if  ((IFG1 & UTXIFG0) != UTXIFG0)           //    UART0_ENABLE_TX_INTERRUPT;
        IFG1 |= UTXIFG0;

Не совсем красиво разрешать/запрещать прерывания дергая флаг. Он ведь может измениться аппаратно пока вы пытаетесь его изменить программно. У вас в комментариях написано ENABLE_TX_INTERRUPT, так и делайте это при помощи специально предназначенного для этого бита.

Про атомарность HARMHARM правильно заметил, опять же про volatile не забываем. Вот мой код, в нем обращения атомарны, запреты прерываний не нужны:

#include    <msp430x14x.h>
#include    <stdio.h>
#include    <stdint.h>

#include    "Hardware.h"

#define RX_BUFF_SIZE    32  // must be power of two
#define TX_BUFF_SIZE    16  // must be power of two

char RxBuffer[RX_BUFF_SIZE];
char TxBuffer[TX_BUFF_SIZE];
uint8_t volatile RxHead, RxTail, TxHead, TxTail;

void UART_Init (void) {
    U0BR0 = (SMCLK / UART_BAUDRATE) & 0xFF;
    U0BR1 = (SMCLK / UART_BAUDRATE) >> 8;
    U0MCTL = 0;
    U0CTL = (0 * PENA) | (0 * SPB) | (1 * CHAR) | (0 * LISTEN) | (0 * SYNC) | (0 * SWRST);
    U0TCTL = (1 * SSEL1) | (0 * SSEL0) | (1 * TXEPT);

    ME1 = URXE0 | UTXE0;            // enable tx & rx
    P3SEL |= (1<<5) | (1<<4);       // enable pins
    IE1 = URXIE0;                   // enable RX int
}

#pragma vector = USART0TX_VECTOR
__interrupt void Tx232(void) {
    uint8_t Tmp = TxTail;           // temp. variable because TxTail is volatile

    U0TXBUF = TxBuffer[Tmp++];
    TxTail = (Tmp + 1) & (TX_BUFF_SIZE - 1);

    if(Tmp == TxHead)               // buffer empty
        IE1 &= ~UTXIE0;             // disable tx int
}

#pragma vector = USART0RX_VECTOR
__interrupt void Rx232 (void) {
    uint8_t Tmp = RxHead;           // temp. variable because RxHead is volatile
    
    RxBuffer[Tmp] = U0RXBUF;
    RxHead = (Tmp + 1) & (RX_BUFF_SIZE - 1);
}

int putchar(int symbol) {
    uint8_t Tmp = TxHead;           // temp. variable because TxHead is volatile
    
    while(( (Tmp - TxTail) & (TX_BUFF_SIZE - 1)) == (TX_BUFF_SIZE - 1));    // wait while buffer full

    TxBuffer[Tmp] = symbol;
    TxHead = (Tmp + 1) & (TX_BUFF_SIZE - 1);

    IE1 |= UTXIE0;                  // enable tx int
    return (1);
}

int getchar(void) {
    uint8_t Tmp = RxTail;           // temp. variable because RxTail is volatile
    int Symbol;

    while(RxHead == Tmp);           // wait while buffer empty

    Symbol = RxBuffer[Tmp];
    RxTail = (Tmp + 1) & (RX_BUFF_SIZE - 1);
    return Symbol;
}

int hasinput(void) {
    uint8_t Tmp = RxTail;           // temp. variable because RxTail is volatile
    return RxHead - Tmp;
}

int puts(const char * string) {
    char c;
    while (c = *string++)
        putchar(c);
}

 

 

2. При работе с RS485 я лично делаю так: при начале передачи даю разрешение на драйвер и отключаю прерывание RX, чтобы не принять свою собственную посылку если что. В конце передачи запрещаю драйвер, читаю RXBUF дабы очистить флаги и уже потом разрешаю прерывание RX.
Зачем такие сложности если можно отключить прием ( ME1 &= ~URXE0 )?

 

 

Код прерываний у Вас, похоже, рабочий.
Похоже, что нет. Когда все передано прерывание передачи не запрещается и в буфер ничего не пишется. Таким образом программа постоянно после выхода из обработчика передачи снова попадает в него же.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Похоже, что нет. Когда все передано прерывание передачи не запрещается и в буфер ничего не пишется. Таким образом программа постоянно после выхода из обработчика передачи снова попадает в него же.

я не утвержадю что рабочий на все 100, но повторного вхождни я впрерывание не проихслжит поскольку аппаратно в перрывание снимается бит UTXIFG0

 

Попробую использовать ваш код

 

вот еще возникла пролемка, если не сложно прокомментируйте

 

while(*str) Uart0PutChar(*str++); //*s++=Tmpchar;

 

странно передает н мой текст а часть его плюс мусор в отлачике по шагам проходит в run-time не всегда, чаще нет, видимо используемые регистры в перрывание изменяются :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Посматрите AppNotes на сайте TI. Для каждого семейства есть примеры работы. Например slac015k

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня рабочий код. Пока тут в грязь не ткнули :)

Пожалуйста ;)

Линейный буфер, slave,

timer декрементируется 1мс, Service вставляется в основной цикл программы.

 

 

//pc DOMP protocol
char rx_buf1[RxBufSize1];
char *rx_head1;
char *rx_tail1;
char tx_buf1[TxBufSize1];
char *tx_head1;
char *tx_tail1;
char domp_status;
char usart1_last_received;

void Uart1Configuration9600(void)
{
    U1CTL = CHAR+SWRST;            // 8-bit character and reset, 8N1
      U1TCTL = SSEL0+SSEL1;          // UCLK = SMCLK (8MHz)
      U1BR0 = 0x00;                  // 7372800/9600 - 768 or 300h
      U1BR1 = 0x03;                  //
      U1MCTL = 0x00;           
      ME2 &= ~(UTXE1 | URXE1);  // Disable USART1 TXD/RXD
       U1CTL &=~SWRST;                 // end of reset     
      rx_tail1=rx_buf1;
      rx_head1=rx_buf1;
      IE2 &= ~(URXIE1|UTXIE1);                // Disable USART1 RX and TX interrupt
}

void ClearTxBuffer1(void)
{     __disable_interrupt();    
    tx_tail1 = tx_head1 = tx_buf1;
    __enable_interrupt();
}

void ClearRxBuffer1(void)
{    rx_tail1 = rx_head1 = rx_buf1;
}

void EnableReceiver1 ( void )
{    ClearRxBuffer1();                //
  ME2|= URXE1;  //    receiver enable
  IE2|=URXIE1;        // receive interrupt enable
//    UCSR0A &= ~ ( 1 << RXC0 );        // set receiver empty bit
}    


void Uart1Configuration(void)
{ Uart1Configuration9600();
  tx_tail1 = tx_head1 = tx_buf1; // without interrupt enable
  EnableReceiver1();
}

void EnableTransmitter1 ( void )
{//    tx_tail1=tx_buf1;        // transmitt from beginning
  ME2|= UTXE1;  //    transmitter enable
    IFG2|=UTXIFG1; // set transmitter empty bit
  IE2|=UTXIE1;  //  transmitt interrupt enable
}



#pragma vector=UART1TX_VECTOR
__interrupt void USART1_transmit(void)
{     if ((domp_status==DompTransmitting) &&
     (tx_tail1<tx_head1))
        {      TXBUF1 =*tx_tail1;
            tx_tail1++;
        } else
        { IE2&=~UTXIE1;  //  transmitt interrupt disable
//      ME2&= UTXE1;  //    transmitter enable
      IFG2&=~UTXIFG1; // clear transmitter empty bit
        domp_status_timer = 2;
        domp_status = DompWaitReceiving;
    }
}


#pragma vector = UART1RX_VECTOR
__interrupt void USART1_receive(void)
{    
      usart1_last_received=U1RXBUF;
//    this two lines for Echo
//    TXBUF1 = b;
//    EnableTransmitter1();

      if (domp_status == DompWaiting)
    {    if (usart1_last_received == START_RX_CHAR)
        {    rx_head1 = rx_buf1;
            domp_status = DompReceiving;
        }
        else return;
    }
    if (domp_status == DompReceiving)
    {    *rx_head1 = usart1_last_received;
        rx_head1 ++;
        if (rx_head1 >= rx_buf1+RxBufSize1)
        domp_status=DompProcessing;
        if (usart1_last_received == END_RX_CHAR) domp_status=DompProcessing;

    }
}
/*
#pragma vector = USART0_TXC_vect
__interrupt void USART_transmit_complete(void)
{    usart_status_timer = 2;
    domp_status = UsartWaitReceiving;
}
*/

void DompService(void)
{    char b;
    switch (domp_status)

{    case DompUnconfigured:    
            Uart1Configuration();
//            SetReceiveDirection;
            ClearRxBuffer1();
            domp_status = DompWaiting;
      break;
    case DompWaiting:    
            domp_status_timer = 2000; // time for receiving
            break;
    case DompReceiving:
            if (!domp_status_timer) domp_status = DompUnconfigured;
            break;
    case DompProcessing:    
            b = MyCorrectCommand();
            if (!b)
            {    ExecuteCommandAndPrepareAnswer();
        domp_status = DompWaitTransmitting;
                domp_status_timer=5;
            }
            else     
            {    
        domp_status = DompWaitReceiving;
                domp_status_timer = 1;
            }
            break;
    case DompWaitTransmitting:    
            if     (domp_status_timer == 0)
            {    
        SetTransmitDirection;
                domp_status = DompTransmitting;
                domp_status_timer = 500;
        tx_tail1=tx_buf1;
//                EnableTransmitter1();     !!!
            }
            break;
    case DompTransmitting:    
            if (!domp_status_timer)
              {    domp_status = DompUnconfigured; }
    
            break;
    case DompWaitReceiving:
            if (domp_status_timer == 0)
            {    ClearRxBuffer1();
              SetReceiveDirection;
                domp_status = DompWaiting;//UsartReceiving;
            }
            break;
    }                        
}

char Usart1EchoTest(void)
{   char b;
    Delay(2);
    b=rtc_data[rtcSecond];
    TXBUF1=b;
    ME2|= UTXE1|URXE1;
    Delay(10);
    if (U1RXBUF==b) b=1;
    else b=0;
    domp_status=DompUnconfigured;
    return(b);
}

 

Жуткие следы выбора размера табуляций и портирования с АВР :blink:

Изменено пользователем Dog Pawlowa

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Код прерываний у Вас, похоже, рабочий.

Похоже, что нет. Когда все передано прерывание передачи не запрещается и в буфер ничего не пишется. Таким образом программа постоянно после выхода из обработчика передачи снова попадает в него же.

Переход по вектору прерывания от передатчика автоматически сбрасывает флаг вызова прерывания. Так что лишний вызов произойдет только один раз по окончании передачи.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Похоже, что нет. Когда все передано прерывание передачи не запрещается и в буфер ничего не пишется. Таким образом программа постоянно после выхода из обработчика передачи снова попадает в него же.

я не утвержадю что рабочий на все 100, но повторного вхождни я впрерывание не проихслжит поскольку аппаратно в перрывание снимается бит UTXIFG0

В каком месте снимается? Я вижу что если передавать больше нечего то все закомментировано.

while(*str) Uart0PutChar(*str++); //*s++=Tmpchar;

странно передает н мой текст а часть его плюс мусор в отлачике по шагам проходит в run-time не всегда, чаще нет, видимо используемые регистры в перрывание изменяются :(

Uart0Tx.PtrWrByte и Uart0Tx.PtrRdByte объявлены как volatile? Скорее всего нет, иначе компилятор выдавал бы предупреждения на конструкции вроде if (Uart0Tx.PtrWrByte != Uart0Tx.PtrRdByte). Дальше уже может твориться все что угодно. Еще может не хватать стека - для начала увеличьте его размер.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сергей Борщ Попробовал использовать Ваш код, получил тоже само что и было у мен явначале

программа зациклилась

    while(( (Tmp - TxTail) & (TX_BUFF_SIZE - 1)) == (TX_BU

причем

Uart0PutChar(0x30); - выполняется,

а

Uart0PutStr("qwe"); зацикливается

Изменено пользователем AlHakim

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А я был уверен, что выкладывал и прием и передачу по прерыванию.

Исправляюсь.

UART.rar

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сергей Борщ Попробовал использовать Ваш код, получил тоже само что и было у мен явначале

программа зациклилась

    while(( (Tmp - TxTail) & (TX_BUFF_SIZE - 1)) == (TX_BU

причем

Uart0PutChar(0x30); - выполняется,

а

Uart0PutStr("qwe"); зацикливается

Извиняюсь, в прерывании ошибку допустил. Должно быть так:

#pragma vector = USART0TX_VECTOR
__interrupt void Tx232(void) {
    uint8_t Tmp = TxTail;           // temp. variable because TxTail is volatile

    U0TXBUF = TxBuffer[Tmp];
    TxTail = Tmp = (Tmp + 1) & (TX_BUFF_SIZE - 1);

    if(Tmp == TxHead)               // buffer empty
        IE1 &= ~UTXIE0;             // disable tx int
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

http://www.ti.com/litv/zip/slac015k

тут простейшие и наипонятнийшие примеры.

например uart07_09600

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...