Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Тема может быть избита. не понимаю как оргнизовать работу UART по прерывания(+)
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > MSP430
AlHakim
Нашел примеры работы 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;
    }
}
HARMHARM
Позволю себе сделать несколько замечаний.
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?
AlHakim
Цитата(HARMHARM @ Jan 8 2007, 15:58) *
2. При работе с RS485 я лично делаю так: при начале передачи даю разрешение на драйвер и отключаю прерывание RX, чтобы не принять свою собственную посылку если что. В конце передачи запрещаю драйвер, читаю RXBUF дабы очистить флаги и уже потом разрешаю прерывание RX. Такая схема откатана и работает. Делаю так всегда, даже если у чипа RS485 есть запрещение приёма.

ну вообщем-то код пишетс яне только для работы по Rs485. Так и сделал уже(запрещаю прерывания)
Код прерываний у Вас, похоже, рабочий. Еще не совсем понятна конструкция
Цитата(HARMHARM @ Jan 8 2007, 15:58) *
Код
    
URCTL1 &= ~ (FE+PE+OE+BRK+RXERR);               // Clear error flags

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

Ошибочка закралась, да и точно снимаются они чтением UxRXBUF
Спасибо smile.gif
HARMHARM
Не успел добавить комментарии, прочтите моё сообщение еще раз wink.gif
Сергей Борщ
Цитата(AlHakim @ Jan 8 2007, 11:58) *
Модуль 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);
}



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


Цитата(HARMHARM @ Jan 8 2007, 15:58) *
Код прерываний у Вас, похоже, рабочий.
Похоже, что нет. Когда все передано прерывание передачи не запрещается и в буфер ничего не пишется. Таким образом программа постоянно после выхода из обработчика передачи снова попадает в него же.
AlHakim
Цитата(Сергей Борщ @ Jan 8 2007, 16:54) *
Похоже, что нет. Когда все передано прерывание передачи не запрещается и в буфер ничего не пишется. Таким образом программа постоянно после выхода из обработчика передачи снова попадает в него же.

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

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

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

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

странно передает н мой текст а часть его плюс мусор в отлачике по шагам проходит в run-time не всегда, чаще нет, видимо используемые регистры в перрывание изменяются sad.gif
jorikdima
Посматрите AppNotes на сайте TI. Для каждого семейства есть примеры работы. Например slac015k
Dog Pawlowa
У меня рабочий код. Пока тут в грязь не ткнули smile.gif
Пожалуйста wink.gif
Линейный буфер, 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.gif
rezident
Цитата(Сергей Борщ @ Jan 8 2007, 16:54) *
Цитата(HARMHARM @ Jan 8 2007, 15:58) *

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

Переход по вектору прерывания от передатчика автоматически сбрасывает флаг вызова прерывания. Так что лишний вызов произойдет только один раз по окончании передачи.
Сергей Борщ
Цитата(AlHakim @ Jan 8 2007, 14:05) *
Цитата(Сергей Борщ @ Jan 8 2007, 16:54) *

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

я не утвержадю что рабочий на все 100, но повторного вхождни я впрерывание не проихслжит поскольку аппаратно в перрывание снимается бит UTXIFG0
В каком месте снимается? Я вижу что если передавать больше нечего то все закомментировано.
Цитата
while(*str) Uart0PutChar(*str++); //*s++=Tmpchar;
странно передает н мой текст а часть его плюс мусор в отлачике по шагам проходит в run-time не всегда, чаще нет, видимо используемые регистры в перрывание изменяются sad.gif
Uart0Tx.PtrWrByte и Uart0Tx.PtrRdByte объявлены как volatile? Скорее всего нет, иначе компилятор выдавал бы предупреждения на конструкции вроде if (Uart0Tx.PtrWrByte != Uart0Tx.PtrRdByte). Дальше уже может твориться все что угодно. Еще может не хватать стека - для начала увеличьте его размер.
AlHakim
Сергей Борщ Попробовал использовать Ваш код, получил тоже само что и было у мен явначале
программа зациклилась
Код
    while(( (Tmp - TxTail) & (TX_BUFF_SIZE - 1)) == (TX_BU

причем
Uart0PutChar(0x30); - выполняется,
а
Uart0PutStr("qwe"); зацикливается
VAI
А я был уверен, что выкладывал и прием и передачу по прерыванию.
Исправляюсь.
Сергей Борщ
Цитата(AlHakim @ Jan 8 2007, 14:41) *
Сергей Борщ Попробовал использовать Ваш код, получил тоже само что и было у мен явначале
программа зациклилась
Код
    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
}
jorikdima
http://www.ti.com/litv/zip/slac015k
тут простейшие и наипонятнийшие примеры.
например uart07_09600
AlHakim
Спасбо всем, а в особенности Сергею
Сергей Борщ
Цитата(rezident @ Jan 8 2007, 14:33) *
Переход по вектору прерывания от передатчика автоматически сбрасывает флаг вызова прерывания.
Да, про это я забыл, каюсь.
zltigo
Цитата(Сергей Борщ @ Jan 8 2007, 16:54) *
Вот мой код...

Пытаясь выжать (вдруг я чего-то не понимаю, чего другие понимают sad.gif )из простейшего UART-а MSP430 все возможное, набрел на эту старую тему. По поводу твоего кода, Сергей, перемудрил ты несколько с voltile и c масками. Можно проще, например, передача:
Код
#define TX_BUFF_SIZE    16  // must be power of two
#define TX_BUFF_MASK    (TX_BUFF_SIZE-1)
char TxBuffer[TX_BUFF_SIZE];
uint8_t volatile TxTail;
uint8_t TxHead;

#pragma vector = USART0TX_VECTOR
__interrupt void Tx232(void) {

    U0TXBUF = TxBuffer[TxTail++ & TX_BUFF_MASK];
    if( TxTail == TxHead )               // buffer empty
            IE1 &= ~UTXIE0;             // disable tx int
}

void putchar(int symbol) {

    while( TxHead - TxTail >= TX_BUFF_SIZE );    // wait while buffer full

    TxBuffer[TxHead++ & TX_BUFF_MASK] = symbol;

    IE1 |= UTXIE0;                  // enable tx int
}
AHTOXA
Цитата(zltigo @ May 5 2008, 22:05) *
Можно проще


Правильно ли я понял, что вы сэкономили одно слово volatile и две (вроде бы) операции &=TX_BUFF_MASK?

Или же здесь что-то более концептуальное? :-)
rezident
Цитата(zltigo @ May 5 2008, 22:05) *
Можно проще, например, передача:
Код
void putchar(int symbol) {

    while( TxHead - TxTail >= TX_BUFF_SIZE );    // wait while buffer full

    TxBuffer[TxHead++ & TX_BUFF_MASK] = symbol;

    IE1 |= UTXIE0;                  // enable tx int
}

Для инициации передачи UART недостаточно просто разрешить прерывание. Желательно принудительно (программно) установить флаг UTXIFGx. Иначе нельзя быть на 100% уверенным, что прерывание действительно возникнет. Флаг может быть оказаться сброшен после вызова "лишнего" прерывания при неудачном стечении (программных) обстоятельств.
MrYuran
Цитата(rezident @ May 6 2008, 21:42) *
Для инициации передачи UART недостаточно просто разрешить прерывание. Желательно принудительно (программно) установить флаг UTXIFGx. Иначе нельзя быть на 100% уверенным, что прерывание действительно возникнет. Флаг может быть оказаться сброшен после вызова "лишнего" прерывания при неудачном стечении (программных) обстоятельств.

А я вообще не понимаю, зачем запрещать и разрешать прерывания по TX.
wassat.gif
Может просветите?
Я вот так делаю
Код
//------------------------------------------------------------------------------

#pragma vector = UART0TX_VECTOR
__interrupt void uart0_write_interrupt_handler(void)
{
  
  IFG1 &= ~UTXIFG0; // clear flag TXD0    
  if(MessLen0--)U0TXBUF=*cTXbuf0ptr++;
  
}

//------------------------------------------------------------------------------


Закончили передачу сообщения - просто не кидаем в буфер ничего и прерывание не возникнет.
Зачем же его тогда запрещать?
AHTOXA
Цитата(MrYuran @ May 7 2008, 10:39) *
Я вот так делаю


Тогда при отсутствии передачи надо первый символ кидать не в буфер, а в U0TXBUF, а то прерывание вообще не возникнет. То есть, нужен какой-то флажок, который отслеживает наличие символа в передатчике.
MrYuran
Цитата(AHTOXA @ May 7 2008, 07:59) *
Тогда при отсутствии передачи надо первый символ кидать не в буфер, а в U0TXBUF, а то прерывание вообще не возникнет. То есть, нужен какой-то флажок, который отслеживает наличие символа в передатчике.

ну да, если надо чё-то передать, ставим указатель на нужный буфер, длину сообщения кидаем в MessLen0 и первый байт в U0TXBUF.
AHTOXA
Цитата(MrYuran @ May 7 2008, 11:05) *
ну да, если надо чё-то передать, ставим указатель на нужный буфер, длину сообщения кидаем в MessLen0 и первый байт в U0TXBUF.


И не проверяешь перед этим, не идёт ли передача предыдущего блока? :-)))

Такой подход хорош для передачи блоков данных. Для putchar(), который может вызываться в произвольные моменты времени, это не подходит.
Kurt
вопрос действительно уже не раз поднимавшийся и в этот раз я тыркну сцылку ))
http://kurt.embedders.org/wiki/sources:uart1
zltigo
Цитата(AHTOXA @ May 6 2008, 20:30) *
Или же здесь что-то более концептуальное? :-)

Абсолютно ничего концептуального - правки исключительно в рамках заданной Сергеем концепции. Просто проходя мимо взглядом зацепился.
Сергей Борщ
Цитата(zltigo @ May 7 2008, 08:38) *
Просто проходя мимо взглядом зацепился.
Да, согласен. Так лучше.
rezident
Цитата(MrYuran @ May 7 2008, 10:39) *
А я вообще не понимаю, зачем запрещать и разрешать прерывания по TX.
wassat.gif
Может просветите?
При пакетной передаче я тоже не запрещаю. Потому как в прерывании анализируется состояние буфера передачи (количество символов в очереди). Но для посимвольной передачи прерывание запрещать нужно прямо на выходе из прерывания. Иначе может иметь быть место какое-нибудь дублирование символов.
Цитата(MrYuran @ May 7 2008, 10:39) *
Я вот так делаю

Цитата(MrYuran @ May 7 2008, 10:39) *
Закончили передачу сообщения - просто не кидаем в буфер ничего и прерывание не возникнет.
Дык это у вас как раз случай буферизированной пакетной передачи. Выше же про putchar речь идет, где посимвольная передача.
Цитата(AHTOXA)
Тогда при отсутствии передачи надо первый символ кидать не в буфер, а в U0TXBUF, а то прерывание вообще не возникнет. То есть, нужен какой-то флажок, который отслеживает наличие символа в передатчике.
Флажки все есть UTXIFGx и EPT, нужно только не забывать их проверять.
Сергей Борщ
Цитата(rezident @ May 7 2008, 11:56) *
Флажки все есть UTXIFGx и EPT, нужно только не забывать их проверять.
Да, флажки есть. Но проверка их - лишний код. Приведенный мной код заменой имен регистров и флагов переносится на мегу и AT91SAM7, где флаг сбросить нельзя - он железно связан с признаком пустоты буфера. Зачем мне под каждый процессор специально заточенные алгоритмы, если этот работает так же?
Dog Pawlowa
Оппа...
Понадобилось перевести передачу на прерывания, не работает так как надо.
У меня особенность - в циклический буфер добавляются байты (или строки) если
- передача идет
- если передача стоит

Если оперировать только разрешением прерывания, как у zltigo, то передача после первого байта блокируется. Это понятно - нет фронта флага, он повис.
Если дергать (устанавливать) флаг готовности передачи в момент добавления в буфер очередного символа, то символы пропадают - тоже понятно - срабатывает прерывание по передаче, когда передача еще идет.

Я конечно найду решение до понедельника, но если кто имеет решение, прошу поделиться.
Спасибо.
Genadi Zawidowski
После добавления чего-то в буфер вызвать (запретив прерывания) обычную функцию проверки готовности и разрешения прерывания - первый байт выйдет по опросу, остальные пойдут по прерываниям.
Dog Pawlowa
Цитата(Genadi Zawidowski @ Sep 20 2014, 22:00) *
обычную функцию проверки готовности и разрешения прерывания

Ага, спасибо!
Уже запустил с отдельным флагом, в принципе можно в качестве флага разрешение и использовать, но переделывать уже не буду:

Инициализация:
Код
    OffFlag(tx_over);
    tx_head0=tx_tail0=0;
    IE1 |= URXIE0+UTXIE0;


Укладка в буфер (DI/EI обязательны!)

Код
        __disable_interrupt();    
        PUT_TO_BUFFER(c);

#ifdef TX_INTERRUPT
        if (GetFlag(tx_over))
        {    IFG1 |= UTXIFG0;
            OffFlag(tx_over);
        }
#endif
        __enable_interrupt();


Ну и прерывание:
Код
    if (tx_tail0!=tx_head0)
    {    d=tx_buf0[tx_tail0];
        tx_tail0++;
        if (tx_tail0==TxBufSize0)
            tx_tail0=0;
        TXBUF0 = d;
    }
#ifdef TX_INTERRUPT
    else
        OnFlag(tx_over);
#endif

Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.