Why is it that I have to set TI from software before I can get my printf() to execute ?
I seems printf() busy waits in TI ?
Why is this so ?
Is not TI supposed to be set by the hardware ?
You should only need to do that if you use printf() for the first time after a reset - because the reset value of TI is 0.
After the first byte sent, TI is set by the hardware.
another "why does it not work like a PC"
FYI IT DON'T
the '51 ain't no PC
Erik
Actually, I'd think that a PC UART would behave the same way ... if you actually go down to the hardware level while programming it.
I'd rather attribute the question to not thoroughly reading the datasheet. Even though the reset values of various registers are among the most important information one can get from the datasheet.
Actually, I'd think that a PC UART would behave the same way ... if you actually go down to the hardware level while programming it. I can easily see the possibility that "a PC UART would behave the same way" however in a PC environment such is taken care of by the BIOS and thus not a C issue. So, if the '51 was a PC there would be no need to set TI.
I'd rather attribute the question to not thoroughly reading the datasheet a) absolutely b) and that would require effort c) if you think the '51 is a PC you do not need to make the effort d) so why not think the '51 is 'like a PC' that removes the need for the effort
Even though the reset values of various registers are among the most important information one can get from the datasheet that information does not help you much if you do not know what the bits do
I did infact read the datasheet, and I remember reading that TI was being set after the UART had sent it's 8 bit.
I know it's 0 by default/reset, but I am under the impression that, the only thing that the software should do is reset it while the hardware would set it.
What I don't get is why I have to set it the first time to get my first printf() get out of busy wait.
Did I miss something in the datasheet ?
I love to stand corrected with more details. Always.
Did you have a look at the source code of the putchar() function (it's in the lib folder) ? printf() uses this routine.
Basically, putchar() does a
while(!TI);
before sending anything.
From "the bible", about TI:
Set by hardware at the end of the 8th bit time in Mode 0, or at the beginning of the stop bit in the other modes, in any serial transmission.
This says exactly when the hardware will set TI. For the hardware to set TI, it requires sending a byte. If the software never sends a byte, TI will not get set by the hardware.
Since you have the source code of putchar(), you may modify it to suit your needs.
It's really very simple ...
With the code that printf uses, a loop is entered that waits for the TI bit to be set. When the condition is met, the bit is then cleared and a character written to SBUF.
The TI bit is normally set when a character has been fully transmitted; but, after a reset, the TI bit is clear and would normally remain so until a character has been transmitted.
So to get things kicked off - The code could write the first character to the UART without waiting for the TI bit to be set.
But this might require some extra logic in the code to determine 'is this the first or subsequent character'.
It is far simpler to emulate the complete transmission of the first character by setting the TI flag - Then the code simply assumes that what is required for the first and subsequent character is the same.
Hope this helps.
"What I don't get is why I have to set it the first time to get my first printf() get out of busy wait."
To answer any such question about the operation of a Library function, you should consult the documentation for that function in the specific compiler Manual: http://www.keil.com/support/man/docs/c51/c51_printf.htm
It says, "This function is implementation-specific and is based on the operation of the _getkey and putchar functions. These functions, as provided in the standard library, read and write characters using the microcontroller's serial port. Custom functions may use other I/O devices."
So your next step would be to look up putchar in the Manual Unhelpfully, Keil don't provide a clickable link, but it's easy to find in the navigation pane to the left of the screen: http://www.keil.com/support/man/docs/c51/c51_putchar.htm
It says, "Source code is provide in the LIB folder."
So you can look in the LIB folder, and see what it does - which includes:
while (!TI); TI = 0; return (SBUF = c);
Now you can see why you need to "manually" set TI the very first time...
This is clearly illustrated in the "Hello, world" example program:
void main (void) { /*------------------------------------------------ Setup the serial port for 1200 baud at 16MHz. ------------------------------------------------*/ #ifndef MONITOR51 SCON = 0x50; /* SCON: mode 1, 8-bit UART, enable rcvr */ TMOD |= 0x20; /* TMOD: timer 1, mode 2, 8-bit reload */ TH1 = 221; /* TH1: reload value for 1200 baud @ 16MHz */ TR1 = 1; /* TR1: timer 1 run */ TI = 1; /* TI: set TI to send first char of UART */ #endif /*------------------------------------------------ Note that an embedded program never exits (because there is no operating system to return to). It must loop and execute forever. ------------------------------------------------*/ while (1) { P1 ^= 0x01; /* Toggle P1.0 each time we print */ printf ("Hello World\n"); /* Print "Hello World" */ } }
For an example of customising serial IO (specifically, using interrupts), see: http://www.keil.com/support/docs/788.htm http://www.keil.com/download/docs/71.asp http://www.keil.com/download/docs/200.asp