Hello,
I want to transmit data over serial port with printf() and meet a strange thing.
Code 1:
unsigned char buf1[] = {0xAA, 0x52, 0xCC, 0x33, 0xC3, 0x3C, '\0'}; printf("%s", buf1);
Data will NOT be transmitted.
Code 2:
unsigned char buf1[] = {0xAA, 0x52, 0xCC, 0x33, 0xC3, 0x3C, '\0'}; ASC0_vSendData(0x12); printf("%s", buf1); void ASC0_vSendData(uword uwData) { ASC0_TBIC_IR = 0; // reset transmit buffer interrupt request ASC0_TBUF = uwData; // load transmit buffer register }
Data will be transmitted successfully (0x12, 0xAA, 0x52, 0xCC, 0x33, 0xC3, 0x3C). I just can't understand why ASC0_vSendData() has to be called before printf(). Can anybody help me?
Thanks Senmeis
void ASC0_vSendData(uword uwData) { ASC0_TBIC_IR = 0; // reset transmit buffer interrupt request ASC0_TBUF = uwData; // load transmit buffer register }
Is that the key?
I don't know C166, but in the C51 implementation, it is necessary to "manually" tweak the TI (UART Transmit Interrupt) flag to get things started for the very first use of printf.
Check Keil's examples - eg, "Hello World" - and the documentation for the target-specific customisation - including source code:
http://www.keil.com/support/man/docs/c166/c166_printf.htm http://www.keil.com/support/man/docs/c166/c166_lib_source.htm http://www.keil.com/support/man/docs/c166/c166_ap_basicio.htm
It's quite common for processors to not generate a transmit-empty interrupt unless the UART has first sent something. I.e. the transmit interrupt is generated by a "flank" condition.
Some compiler manufacturers has some code lines in the printout to check if the UART is busy or not. If not busy, then the first byte is dropped into the send register. If busy, then the data is just queued in a buffer and the next transmit interrupt will draw in the next character to send.
But since there is no standard what is correct, you always have to check the implementation for your specific compiler and runtime library. The important thing is to just recognize this issue.
So why doesn't Keil automagically start any transfer? Well, by leaving the choice to the developer, we may use whatever buffer strategies we want. Turn-key solutions don't allow us to choose.
In fact the key is
ASC0_TBUF = uwData; // load transmit buffer register
not
ASC0_TBIC_IR = 0; // reset transmit buffer interrupt request
That means, an irrelavent byte must be sent at first to trigger the transmitter.
There is another problem. Printf() cannot send ‘0x00’. Will only readable ASCII characters be sent?
"an irrelavent byte must be sent at first to trigger the transmitter"
Not necessarily an irrelevant byte!
"There is another problem. Printf() cannot send ‘0x00’"
That's not a problem - that is the defined operation of printf!
Remember, 'C' uses 0x00 to mark the end of a string - so no string in 'C' can ever contain 0x00!
If you want to treat the data as pure binary, then you can't use any of the 'C' string handling functions!
"Will only readable ASCII characters be sent?"
Again, you need to read the documentation for the specific implementation; there may be some interpretation of some of the ASCII control characters - particularly CR and/or LF.
Again, if want to treat the data as pure binary, then you can not use any of the 'C' string handling functions!
"then you can not use any of the 'C' string handling functions!"
Note that this is standard, 'C' textbook stuff - nothing specific to Keil or the C166 or embedded...