原创 C51中printf使用注意

2010-1-4 11:40 11375 7 7 分类: MCU/ 嵌入式

C51printf使用注意<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


C51标准串口发送程序(C<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />8051F120为例,注意C8051F120特殊功能寄存器是分页的)


/***********************************************************


函数名称:send_char_com


函数功能:向串口发送一字节字符


入口参数:unsigned char sendByte 一个字节字符(8 bit)


出口参数:无


注:


***********************************************************/


void send_char_com(unsigned char sendByte)


{


    char SFRPAGE_SAVE = SFRPAGE;   //用到TI0(SCON0.1)SFR页:0


    SFRPAGE = UART0_PAGE;


      SBUF0=sendByte;    


      while (TI0== 0);       //等待发送完毕


                 TI0= 0;     //清发送中断标志TI0


    SFRPAGE = SFRPAGE_SAVE;


}


 


/***********************************************************


函数名称:send_char_com


函数功能:向串口发送一个字符串


入口参数:unsigned char *str   字符串数组首地址


          unsigned int strlen  该字符串长度


出口参数:无


注:


***********************************************************/


void send_string_com( unsigned char *str, unsigned int strlen)


{


     unsigned int k= 0 ;


       do  {


            send_char_com(*(str + k));


               k++;


              }


       while (k < strlen);


}


 


C51中直接使用printf比自己编个串口发送字符串的函数方便,但有几个问题要注意的。


1.      使用printf之前要先包含stdio.h这个头文件


                       #include <stdio.h>


具体stdio.h包含的函数见下面网址


http://www.keil.com/support/man/docs/c51/c51_stdio_h.htm


 


2.


   ES0=0;                       //禁止串口中断


   SFRPAGE_SAVE = SFRPAGE;  //c8051f120特殊功能寄存器分页


   SFRPAGE = UART0_PAGE;


   TI0=1;


   printf ("\n\nTest complete.");


   TI0=0;                        //可以省略


   SFRPAGE = SFRPAGE_SAVE;              


   ES0=1;                       //打开串口中断


 


printf函数是调用putchar函数,从串口发送字符串的,可以从keil反汇编看出这一点。在C51程序中printf的位置设一个断点,运行到断点处后,再一步步执行程序,可以看出,跳转到PRINTF执行。


<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />


 


2d88e356-bbdc-4072-9f35-10063a6f766c.jpg


 


PRINTF有很长一大段汇编,一步步执行。



 

a10bc05d-6507-4961-be82-084a9693eb78.jpg


 


运行到PUTCHAR处,这个就是串口发送字符串的函数。



 


4b793ae1-97f3-47f6-8b18-a44e72f72650.jpg


 


可以看到有这么一句“C:0521    JNB TI0,C:0521


第一次运行到这的时候,如果前面没有TI0=1,那么程序指针PC就一直在这条语句上判断,也就死在这里等待。


所以要使用printf,开头必须要先置TI0(传统51TI)1。那么发送了第一个字节后,发送中断标志位TI0自动置1,再回到“C:0521    JNB TI0,C:0521,接着发送第二个字节。


 



点击看大图


 


因为TI0为中断标志位,但如果程序使用了UAR0中断,那么在printf函数执行过程中就会不断调用中断函数(UART0_Interrupt),所以每次使用printf之前要先禁止串口中断(ES0=0)


 


3.      由上面可以看到使用printf非常麻烦,其实可以用sprintf代替printf,只要在前面先定义一个存放字符串的数组。


……


unsigned char PrintChar[15]


……


SFRPAGE_SAVE = SFRPAGE;   //C8051F120特殊功能寄存器分页


SFRPAGE = UART0_PAGE;      //传统51单片机没有SFR分页


sprintf (PrintChar,"\nTest complete.");


send_string_com(s, 15);


SFRPAGE = SFRPAGE_SAVE;


 


 


上面总结得都是经验教训啊,在这个小小的bug上浪费了几天,记录下来,希望对大家有点帮助。


 


4.      当使用printf循环打印时要注意,下面程序是有问题的


   pchar = XRAM_START;


   for (i = 0; i < RAM_SIZE; i++)


    {


         *pchar= 0;


         ES0=0;


                TI0=1;   


         printf("writing 0x%04x:%u\n",(unsigned)pchar,(unsigned) *pchar);


             ES0=1;


         pchar++;


}


sprintf(PrintChar,"Test complete.\n");


send_string_com(PrintChar,15);


 


串口调试助手接收如下,可以看到第二次打印write时少了w”。sprintf打印Test少了T”。



 

f192f02a-cd5f-4811-a0c7-e87a2e3c7e15.jpg


 


        可以重新看一下PUTCHAR处。



 


222efbb4-c533-41d1-b248-aeeaca5aa66f.jpg


 


第一次发送字符的时候,由于TI0=1,所以在C:0x05B6的位置不会死等,执行C:0x05B9的时候TI0=0,接着A寄存器的值通过SBUF0发送。由于串口发送的速率是很慢的(波特率才19200kBPS),所以,等在执行一遍上面的代码,回到C:0x05B6的时候,TI0还是为0,在C:0x05B6处等TI0变为1。当串口发送完了之后,发送中断标志位TI0才被硬件置1。此时PC机上的串口调试助手才显示刚发送的字符。


当发送最后一个字符时,C:0x05BB,把寄存在A的最后字符的ASCII代码复制给SUBF0后,并没有等待TI0变为1的指令,而是占用了下次for循环发送首字母的C:0x05B6,导致下次for循环首字母没有发送出去。正确的办法是把TI0=1挪到for循环之后。


Test”中的“T”没接收到也是同样的问题,最后一次发送的字符,没有等待TI0硬件置位的过程,造成发送的字符丢失。


正确的代码如下:


   pchar = XRAM_START;


TI0=1;


   for (i = 0; i < RAM_SIZE; i++)


    {


      *pchar= 0;


       ES0=0;


       printf("writing 0x%04x:%u\n",(unsigned)pchar,(unsigned) *pchar);


          ES0=1;


       pchar++;


    }


    while(TI0==0){};


    TI0=0;


   sprintf(PrintChar,"Test complete.\n");


   send_string_com(PrintChar,15);


 


正确的输出如下:


 

043f31fb-e97b-415b-8dc7-6dcc9bf0f74c.jpg

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
7
关闭 站长推荐上一条 /3 下一条