| 
				打卡等级:以坛为家III打卡总天数:600最近打卡:2025-10-31 06:34:52  已绑定手机超级版主 
 
	积分12070 
 | 
 
| 本开源程序实现如题目所示的三个功能: 
 1、串口收发框架:
 使用硬件UART中断方式实现串口收发,中断方式相对查询方式和GPIO软件模拟的优点在此就不多赘述了;使用定时器实现串口接收超时复位,避免接收到错误数据或数据未发完就终止时,错误的状态始终保留,导致再发送正确的数据,正确的数据又和之前错误的数据拼接成一个错误的数据;收发缓存为全局变量,使用指针在中断函数中实现自动处理,不需要在主程序中轮询某些状态和标志,中断程序简单高效,全状态机控制,不会耽误大量时间,不使用软件延时。
 
 2、printf重定向:使用标准库stdio.h、stdarg.h实现变量格式化,printf重定向到UART输出,然后就可以愉快的使用printf了,缺点是和直接写数组相比会消耗更多code空间。
 
 3、圆周率计算:使用莱布尼茨法计算圆周率,用于printf输出变量,由于莱布尼茨法是收敛的无穷级数且偶数项为正奇数项为负,程序中保留上一次迭代结果并和本次迭代结果求平均值以加速收敛,实测454次迭代结果为3.141592,如不求相邻两次平均值,则需上万次迭代,且由于浮点数精度的限制,几万次迭代后误差会越来越大。
 
 单片机STC8G1K08A-8PIN,时钟频率11.0592MHz,UART1 9600bps 8N1,为便于观察,主程序中延迟50ms,串口默认为阻塞模式,即上一个数据包未发完又发新的数据包时会等待串口状态复位,即发送长度为0(Uart_Send_Lenth=0),该变量为全局变量,数据包发送完毕后在中断程序中清零表示数据包发送完毕,该模式在软件发送频率大于硬件发送频率时,软件发送频率会被拖慢,但不会发送错误的数据,注释掉while(Uart_Send_Lenth)即可改为覆盖模式,该模式上一个数据包未发完又发新的数据包时,新的数据包会覆盖掉原数据包且串口状态被重置,发送的数据包会被打断,但软件发送不会被拖慢,如在阻塞模式下没有达到预期速度或在覆盖模式下发送数据错误,请降低发送频率或提高波特率,该串口收发框架100%自行编写,无抄袭。
 
 如不想使用printf函数,直接写发送缓存,以下为范例程序:
 
 T_Buffer[0]='T';
 T_Buffer[1]='=';
 T_Buffer[2]=Hex_to_Ascii[t%10000/1000];
 T_Buffer[3]=Hex_to_Ascii[t%1000/100];
 T_Buffer[4]='.';
 T_Buffer[5]=Hex_to_Ascii[t%100/10];
 T_Buffer[6]=Hex_to_Ascii[t%10];
 T_Buffer[7]='C';
 T_Buffer[8]=' ';
 T_Buffer[9]='P';
 T_Buffer[10]='=';
 T_Buffer[11]=Hex_to_Ascii[p%1000000/100000];
 T_Buffer[12]=Hex_to_Ascii[p%100000/10000];
 T_Buffer[13]=Hex_to_Ascii[p%10000/1000];
 T_Buffer[14]='.';
 T_Buffer[15]=Hex_to_Ascii[p%1000/100];
 T_Buffer[16]=Hex_to_Ascii[p%100/10];
 T_Buffer[17]=Hex_to_Ascii[p%10];
 T_Buffer[18]='K';
 T_Buffer[19]='P';
 T_Buffer[20]='a';
 T_Buffer[21]=0x0d;
 T_Buffer[22]=0x0a;
 UART_Send(23);
 
 
 对发送缓存数组赋值后调用UART_Send(x)即可,x为发送长度。
 
 因没有使用串口接收功能,串口接收程序是个半成品,需用户按照具体协议编写解析程序,以下为范例程序:
 
 void Uart_Isr(void) interrupt 4
 {
 static unsigned int tp;
 unsigned int temp,lenth,i;
 if(RI)
 {
 RI=0;
 Uart_Start();
 R_Buffer[RP]=SBUF;
 if(RP==1)
 {
 temp=(R_Buffer[0]<<8)+R_Buffer[1];
 if(temp>0x0200)
 {
 R_Buffer[1]&=0x07;
 switch(R_Buffer[0])
 {
 case 'R':
 Uart_Send_Iap(R_Buffer[1]);
 Sector=0xFF;
 break;
 case 'W':
 Sector=R_Buffer[1];
 Iap_Erase_Sector(Sector*0x0200);
 Uart_Printf("扇区%bd已擦除\xFD,请切换到HEX模式写入数\xFD据\r\n",Sector);
 break;
 }
 Uart_Stop();
 }
 else if(temp>2&&temp<=512)
 {
 lenth=temp;
 }
 }
 if(RP==lenth-1&&lenth>2&&Sector<8)
 {
 for(i=0;i<lenth;i++)
 {
 Iap_Program_Byte(Sector*0x0200+i,R_Buffer);
 Uart_Start();
 }
 Uart_Stop();
 Uart_Printf("扇区%bd写入%d字节\r\n",Sector,lenth);
 Sector=0xFF;
 }
 else if(RP==R_Buffer_Len-1)
 {
 Uart_Stop();
 }
 else if(TR0)
 {
 RP++;
 }
 }
 if(TI)
 {
 TI=0;
 if(Uart_Send_Lenth!=0)
 {
 SBUF=(T_Buffer[TP]);
 TP++;
 }
 if(TP==Uart_Send_Lenth)
 {
 TP=0;
 Uart_Send_Lenth=0;
 }
 }
 }
 
 这是一个接收不固定长度数据包的程序,前两个字节为长度,最大长度512字节,如您也需要接收这么长的数据包,则需要修改接收缓存长度R_Buffer_Len大于数据包长度,注意接收到除了包尾的每个字节后都要调用Uart_Start()函数以重置超时定时器,在接收到期望的数据包(正确数据包或错误数据包)后调用Uart_Stop()函数立即重置状态即可,如不立即重置状态,在超时后也会自动重置状态,但在此期间又收到数据会发生数据接收错误。
 该例程包含汉字0xFD问题的解决方法供参考。
 
 以下是完整程序:
 
 /*----------------------------分割线----------------------------*/
 
 #include <STC8G.H>
 #include "define.h"
 #include <intrins.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdarg.h>
 #define                RXD                P30
 #define                TXD                P31
 #define                FOSC                11059200UL
 #define                BAUD                9600UL
 #define                BRT                        (0x10000-FOSC/BAUD/4)
 #define                R_Buffer_Len        64        //Uart1接收缓存长度
 #define                T_Buffer_Len        64        //Uart1发送缓存长度
 
 unsigned char                RP;                                                        //Uart1接收指针
 unsigned char                TP;                                                        //Uart1发送指针
 unsigned char                Uart_Send_Lenth;                        //Uart1发送长度
 unsigned char xdata        R_Buffer[R_Buffer_Len];                //Uart1接收缓存
 unsigned char xdata        T_Buffer[T_Buffer_Len];                //Uart1发送缓存
 
 ///*----------------------------延时10us@STC-Y6@11.0592MHz----------------------------*/
 //void Delay_10us(void)
 //{
 //        unsigned char i;
 //        i=35;
 //        while(--i);
 //}
 
 ///*----------------------------延时x10us----------------------------*/
 //void Delay_x10us(unsigned char x)
 //{
 //        while(x--)
 //                Delay_10us();
 //}
 
 /*----------------------------延时10ms@STC-Y6@11.0592MHz----------------------------*/
 void Delay_10ms(void)
 {
 unsigned char i,j;
 _nop_();
 _nop_();
 i=144;
 j=157;
 do
 {
 while(--j);
 }while(--i);
 }
 
 /*----------------------------延时x10ms----------------------------*/
 void Delay_x10ms(unsigned char x)
 {
 while(x--)
 Delay_10ms();
 }
 
 void UART_Send(unsigned int x)
 {
 TP=0;
 Uart_Send_Lenth=x;
 TI=1;
 }
 
 void Uart_Printf(unsigned char *v,...)
 {
 va_list ap;
 va_start(ap,v);
 while(Uart_Send_Lenth);
 UART_Send(vsprintf(T_Buffer,v,ap));
 va_end(ap);
 }
 
 void Init(void)
 {
 P_SW2|=EAXFR;
 
 P3M0=0x00;
 P3M1=0x00;
 
 AUXR=0x40;                //设置定时器0时钟为12T模式,设置定时器1为1T模式,设置定时器1为波特率发生器
 TMOD=0x01;                //设置定时器0为16位不自动重装载模式,设置定时器1为16位自动重装载模式
 TL0=0x00;                //设置定时器0初始值(5ms)
 TH0=0xEE;                //设置定时器0初始值(5ms)
 TF0=0;                        //清除TF0中断标志位
 ET0=1;                        //启用定时器0中断
 
 SCON=0x50;                //设置UART1模式为8位数据可变波特率
 TL1=BRT;                //设置UART1波特率
 TH1=BRT>>8;                //设置UART1波特率
 TR1=1;                        //打开定时器1
 ES=1;                        //启用UART1中断
 
 EA=1;                        //启用总中断
 }
 
 void main(void)
 {
 unsigned int x;
 float pi,pi_last;
 Init();
 x=0;
 pi=0.0F;
 while(1)
 {
 x%2?(pi-=4.0F/((float)x*2.0F+1.0F)):(pi+=4.0F/((float)x*2.0F+1.0F));
 Uart_Printf("x=%U pi=%1.6F\r\n",x,(pi+pi_last)/2);
 pi_last=pi;
 if(x==454)
 while(1);
 x++;
 Delay_x10ms(5);
 }
 }
 
 void Uart_Start(void)
 {
 TL0=0x00;
 TH0=0xEE;
 TR0=1;
 }
 
 void Uart_Stop(void)
 {
 TR0=0;
 TL0=0x00;
 TH0=0xEE;
 RP=0;
 memset(R_Buffer,0x00,sizeof R_Buffer);
 }
 
 void Timer0_Isr(void) interrupt 1
 {
 Uart_Stop();
 }
 
 void Uart_Isr(void) interrupt 4
 {
 if(RI)
 {
 RI=0;
 Uart_Start();
 R_Buffer[RP]=SBUF;
 if(RP==R_Buffer_Len-1)
 {
 Uart_Stop();
 }
 else if(TR0)
 {
 RP++;
 }
 }
 if(TI)
 {
 TI=0;
 if(Uart_Send_Lenth!=0)
 {
 SBUF=(T_Buffer[TP]);
 TP++;
 }
 if(TP==Uart_Send_Lenth)
 {
 TP=0;
 Uart_Send_Lenth=0;
 }
 }
 }
 
 /*----------------------------分割线----------------------------*/
 
 完整工程见附件:
 
 
  printf.zip
(13.51 KB, 下载次数: 417) 
 
 | 
3
喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
 
 +1楼主威武~
 +1楼主威武~
 +1楼主威武~
 |