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

模拟串口自动测量波特率的单片机程序

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

我这个程序能够测量串口的波特率,并且将自身的波特率设置到通讯波特率。
这个在STC89C52/STC15F104(其实主要针对STC15F104,因为它没有串口)上面通过。不过因为是模拟串口,在11.0592 12T的情况下,最多到19200。
然后在STC15F104上面,要适量的减少补偿值……
顺便说一句,编译器建议使用sdcc。keil的SB printf函数搞死我了……在22.1184 6T的情况下大约能到57600.
当然在STC15F系列到115200毫无压力,可是是半双工的。要做全双工只能减倍波特率……
测量波特率的方法很简单。校准他的波特率的方法就是发送没有连续低电平的字符,类似0x55/0xff/0x7f之类的。使用这个特性还可以将它用在STC自动冷启动下载器中。不过注意要限制校准波特率。否则你的正常串口通讯可能会被干扰,因为你比如115200通讯的时候,正好波形类似57600的7F,校准上去了把你的连接掐了,估计很多人都会看看程序是不是跑飞了……所以一定要把同步波特率降到4800以下,因为STC-ISP的默认最低波特率是从1200~4800.
这个也可以适用于不准晶振的单片机和计算机通讯。方法就是计算机以不同波特率发送校准信号,找出误码率最低的波特率,然后发送确认,让单片机在这个重载值下运行,也适用于时钟速度可能变化的单片机/懒得计算重载值的人使用。
然后低于4800的波特率在11.0592的速度下面只能分频,这也是不得已的……
上代码:

/*
* 自适应波特率模拟串口程序,
* 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
#define TX1 P1_0 //发送数据端口
#define RX1 P1_1 //接收数据端口
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);//这里如果你要使用keil请自己写字符串发送函数,和sprintf配合使用
        printf("Could you please test another baudrate?\r\n");
        printf("But I think that I couldn't to do.....\r\n");
    }
}

万致远@rwzy.co.cc
求M~~~

关闭窗口

相关文章