0
\$\begingroup\$

Note: I am beginner :) MCU: Atemega328p

In Method 1, I am using a UDRn data register empty interrupt once the transmit buffer is empty and inputting characters from snum into the UDR0 register within the ISR. I want the serial monitor to print "65534" repeatedly. However it shows this: enter image description here

Method 1 Code:

#define F_CPU 16000000UL
#define BAUD 9600
#define BRC  ((F_CPU/16/BAUD)-1)       
char snum[20];
int num = 65534;
int i;
sei();
int main (void)
{
    uarttransmitenable();
    while (1)
    {
        utoa(num, snum, 10);
    }
}

ISR(USART_UDRE_vect)
{
     for (i=0; i< strlen(snum); i++)
     {
         UDR0 = (char)snum[i];
     }  
}
        
void uarttransmitenable(void)
{
    UBRR0H = (BRC >> 8);
    UBRR0L = BRC;
        
    UCSR0B = (1<<TXEN0)| (1<<RXEN0) | (1<<UDRE0); 
    UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
}

My thinking was that the while loop would covert the 65534 into an array of characters and then every time the interrupt occurred the next char in snum would be sent, and would be sent in order, so 6 first, followed by 5,5,3,4.

In Method 2 I do the int to char conversion and poll the UDREn bit to see if the transmit buffer is ready within the while loop. I don't use ISR at all. This shows "65534" fine on the serial monitor.enter image description here

Method 2:

#define F_CPU 16000000UL
#define BAUD 9600
#define BRC  ((F_CPU/16/BAUD)-1)
char snum[20];
int num = 65534;
int i;
int main (void)
{
    uarttransmitenable();
    while (1)
    {
        utoa(num, snum, 10);
        for (i=0; i< strlen(snum); i++)
        {
            while (( UCSR0A & (1<<UDRE0))  == 0){}
            UDR0 = (char)snum[i];
        }
    }

void uarttransmitenable(void){
    UBRR0H = (BRC >> 8);
    UBRR0L = BRC;

    UCSR0B = (1<<TXEN0)| (1<<RXEN0);
    UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
}

I wanted to use the UDRE interrupt as I thought it would result in better performance, but the figures have come out differently.

I understand that using FIFO buffers would be a good idea for this task in general but I just wanted to understand why method 1 does not work.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ But you can't use for loop to transmit multiple characters in the single UDRE interrupt. It only means the data register is empty, and you can fit one character into data register. You can't also use strlen() in an interrupt, it would take too long, and especially, not use strlen on a string that you are constantly writing to in main loop. \$\endgroup\$
    – Justme
    Jan 5 at 21:05
  • 1
    \$\begingroup\$ @user13174343 -- You don't even need a fifo buffer. any kind of buffer will do. in fact the string itself is a perfectly good buffer. have the interrupt 'walk' a pointer along the string until it reaches the termination. pretend like each call to the interrupt is one time around your 'for' loop \$\endgroup\$
    – Pete W
    Jan 5 at 21:32
3
\$\begingroup\$

Your method 1 does not work, because in a single interrupt, you are writing all characters of the string to the Uart Data Register. When an UDRE interrupt happens, it is ready to accept one (1) character until another UDRE interrupt happens.

Which is the reason why your method 2 works, because it expicitly waits for the Uart Data Register to be empty before writing a single character and waiting again before it is ready for the next character.

\$\endgroup\$
2
  • \$\begingroup\$ To confirm does the data register only take 1 byte at a time? So wouldn't method one also take one character at a time as well? \$\endgroup\$ Jan 5 at 21:36
  • 1
    \$\begingroup\$ Yes, Uart Data Register takes in only one byte when it is ready for one byte, so writing multiple bytes when it is ready for one byte will not work. Your method one will write multiple bytes in a for loop, when the UART has signaled with the UDRE interrupt that is is ready to take in one byte, so writing multiple bytes in a for loop is wrong, because UART only acceps one byte per UDRE interrupt. \$\endgroup\$
    – Justme
    Jan 5 at 22:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.