专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

再次发模拟串口,51自适应波特率(牛)

作者:万致远   来源:本站原创   点击数:  更新时间:2012年08月02日   【字体:

   这个是在12T的8051上面用的模拟串口程序,配合22.1184M的晶振,加上6T的双倍速,波特率可以上38400……但是我认为和某些STC的芯片比,还是差了一点,所以说,看官门看注释吧。开启帧请发送没有连续低电平的字符,类似0×55,0xff,0x7f如此等等,如果有连续低电平很容易造成判断失误……这个程序可以用在STC的自动冷启动模块里(STC15F101系列就行,很便宜的,注意是八位装载模式顺便把T1X12关了~然后补偿可以顺便减小一点,顺便说一句,用AT89C51来做也行)。这个在24M/22.1184M/11.0592M均工作正常,11.0592能到9600,24能到38400。不过,我提个醒,如果看官们真拿这个做STC冷启的时候一定要限制波特率小于等于4800。要不然的话。串口正常通讯的时候,这个模块同步上去,把你的电断了,连接掐了,然后估计你会拼命找程序是不是跑飞,浪费很多时间,……

顺便说一句,这个程序也有另外一个用途,在晶振不准的时候仍然可以和电脑以标准波特率通讯。方法就是规定好帧格式,然后上位机不停换波特率找到没有误码率的波特率,然后根据下位机的应答计算出下位机的时钟频率,这个是受了老妖ISP的启发才想到的~大家可以参考我发布的另2篇文章:模拟串口自动测量波特率的单片机程序http://www.51hei.com/mcu/1537.html ,下面这个网页是用11.0592兆的晶振模拟串口接收发发送的已经通过本人测试http://www.51hei.com/mcu/1418.html

上代码:

/*
 * 自适应波特率模拟串口程序,
 * BY 万致远@rwzy.co.cc
 * CRYSTAL:任意
 */
#include <hwconfig.h>
#include <type-def.h>
#include <stdio.h>
#define MIS_0 0
#define MIS_2 1
#define MIS_4 2
#define MIS_8 3 
#define MIS_16 4 

BYTE min_mode;//减倍模式
void WaitTF1()
{
	while(!TF1);
	TF1=0;
	if(min_mode==MIS_2)
	{// /2
		while(!TF1);
		TF1=0;
	}
	else if(min_mode == MIS_4)
	{// /4
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
	}
	else if(min_mode == MIS_8)
	{// /8
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
	}
	else if(min_mode == MIS_16)
	{// /16
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
		while(!TF1);
		TF1=0;
	}
}

void WByte(BYTE out)
{
    //发送启始位
    BYTE i=8;
    BYTE tmp=out;
    TR1=1;//开定时器
    TX1=0;
    WaitTF1();
    //发送8位数据位
    while(i--)
    {
        TX1=(tmp&0x01);     //先传低位
        tmp=tmp>>1;
        WaitTF1();
    }
    //发送校验位(无)
    //发送结束位
    TX1=1;
    WaitTF1();
    TR1=0;
}    
void putchar(char ch)
{
	WByte(ch);
}
BYTE RByte()
{
	BYTE in=0;
	BYTE cnt;
	while(RX1==1);//等待RXD变低,启动定时器,这个是阻塞模式
	TR1=1;//同步开定时器//这里……
	//while(!TF1);
	//TF1=0;	
	WaitTF1();
	if(min_mode !=0)
	{
		while(!TF1);//注意这里的周期稍微长。要补偿
		TF1=0;
	}
	for(cnt=0;cnt<8;cnt++)
	{
		in=in >>1;//从高移到低
		if(RX1==1) in = in | 0x80;//如果RXD=1,则最高置位
		WaitTF1();//等待一位过去
	}
	while(!TF1);//注意这里的周期稍微长。要补偿
	TF1=0;
	TR1=0;//关闭定时器
	return in;
}

UINT f_Test(void)//测试脉宽
{
	TMOD=0x10;//设置计数器1为方式一计数器模式
	TH1=0;
	TL1=0;//定时器CLR
	while(!RX1);//等待频率脚变高,这个是测低电平的
	while(RX1);//等待脚变低,更换符号可以测正脉冲
	TR1=1;//开启定时器
	while(!RX1);//等待变高
	TR1=0;//停止计数
	//cyc=TH0<<8;
	//cyc=cyc+TL0;
	return (TH1<<8)+TL1;
}
void baud_t()
{
	BYTE k;//复用变量 
	ULONG frq=0; //周期变量
	for(k=0;k<5;k++)// 变量复用大法
	{
		frq=frq+f_Test();//测试
	}//测量5次取平均
	frq=frq/5;
	if(frq<0xff)
	{
		k=0x100-(frq&0xff);
		min_mode=MIS_0;
	}
	else
	{
		if(frq / 2 < 0xff)
		{//2400baud
			k=0x100-((frq/2)&0xff); //2分频
			min_mode=MIS_2;
		}
		else if(frq / 4 < 0xff)
		{//1200baud
			k=0x100-((frq/4)&0xff);//4分频
			min_mode=MIS_4;
		}
		else if(frq / 8 < 0xff)
		{//1200baud
			k=0x100-((frq/8)&0xff);//8分频
			min_mode=MIS_8;
		}
		else if(frq / 16 < 0xff)
		{//1200baud
			k=0x100-((frq/16)&0xff);//16分频
			min_mode=MIS_16;
		}
	}
	if(k > 0x50)
	{
		k=k+6;//加补偿,因为if语句让机器周期加长
		//如果对于STC的新MCU,这里要按照情况调整
	}
	TMOD=0x20;//设置定时器1为自动装载模式
	TH1=k;//载入新波特率
	TL1=k;
}
void main()
{
	while(1)
	{
		baud_t();//测量波特率,阻塞模式
		printf("Hello world!\n");
		printf("Here:mode=%d,T1=0x%X\r\n",min_mode,TH1);
		printf("Could you please test another baudrate?\r\n");
		printf("But I think that I couldn't to do.....\r\n");
	}
}

完整的源代码下载:http://www.51hei.com/f/molic.rar
转自:万致远的博客http://www.rwzy.co.cc

顺便说一下,根据重载值计算波特率的公式是:

R=重载值 
Clock=系统时钟(HZ) 
B=波特率 

Clock=12(256-R)*B

关闭窗口

相关文章