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

发布者:blq0681最新更新时间:2012-08-02 来源: 21ic 关键字:模拟串口  自动测量  波特率 手机看文章 扫描二维码
随时随地手机看文章

我这个程序能够测量串口的波特率,并且将自身的波特率设置到通讯波特率。
这个在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
#include
#include
#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;
    }
}[page]

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");
    }
}

关键字:模拟串口  自动测量  波特率 引用地址:模拟串口自动测量波特率的单片机程序

上一篇:从信号分析的运用中回眸傅里叶算法
下一篇:写给要接触单片机和刚接触单片机的人

推荐阅读最新更新时间:2024-03-16 13:04

RS232C信号特性、电缆长度及波特率
  为了确保正确地发送二进制数据和正确地执行设备控制,RS232C标准为数据和管制信号提供了电压标准及范围。当RS232C的线路上没有通信的数据信号时,DTE端的发送信号保持-15V的电压。电压标准如表所示。   RS232C标准规定电缆长度限定在15m以内,串行数据传速率的范围为0~20000b/s。这一规定足以覆盖个人计算机使用的50~9 600b/s范围。电缆长度也足以满足大多数个人计算机通信的要求。RS232C的电气接口是单端、双极性电源供电电路,两个传输方向共用一根信号地线,接口使用不平衡收发器,可能在各种信号成分间产生干扰。   德阳四星电子技术开发中心的RS232光隔离长线收发器(又名:串口泵),将RS2
[嵌入式]
PIC16模拟串口以及采样正弦波
最近两周用了两个IC(PIC16系列与STM8S系列)做了个产品,首次接触,遇到些问题,总结如下: 1:PIC16模拟串口发送数据,一定要在中断服务函数中执行 static void interrupt SystemISR(void) { if(TMR0IE && TMR0IF) //32MHz 104us { if(txCount) //检测数据是否发送完毕 { TXD=(txData&0x01); //输出数据 txData=(txData 1); //移位数据 --txCount; } else //发送完毕后进行停止位发送 { if(txFlag) { TXD=1
[单片机]
hi3531串口波特率计算
波特率配置 通过配置寄存器UART_IBRD 和UART_FBRD 可以设置UART 工作的波特率,波特率 计算公式为: 当前波特率=UART 参考时钟频率(1/2 总线时钟频率)/(16 x 分频系数) 分频系数有整数和小数两部分组成,分别对应寄存器UART_IBRD 和UART_FBRD。 例如:UART 参考时钟频率为60MHz,如果配置UART_IBRD 为0x1E,UART_FBRD 为0x00,按照波特率计算公式,则当前的波特率为60/(16 x 30)=0.125Mbit/s。 UART 波特率配置的典型值为:9,600bit/s、14,400bit/s、19,200bit/s、38,400bit/s、 57,600
[单片机]
12M晶振下,STM32串口波特率设置问题
使用外接12MHz的晶振,会造成很多的问题,如USART的波特率不正确,Systick走时不准等问题,在无论是在实际调试还是在软件模拟中都会发现这个情况,其实,这不能怪ST官方,我们必须肯定ST官方为方便用户开发所做的努力,下面我们就通过简单的三个步骤就可以让你随意的使用4—16MHz之内任何频点的晶振,我们以STM32F10x_StdPeriph_Lib_V3.4.0为例说明。 第一步,打开stm32f10x.h,将 #define HSE_VALUE ((uint32_t)8000000) 修改为: #define HSE_VALUE ((uint32_t)12000000) 第二步,打开system_stm32f10x.c,
[单片机]
stm32模拟串口(基于高精度延时)
上一篇实现了高精度延时,这一节我们利用已实现的高精度延时接口来模拟串口发生数据(接收数据暂时没用到,所以偷懒没实现),直接上代码。 一、softserial.h #ifndef _SOFTWARE_SERIAL_H #define _SOFTWARE_SERIAL_H #include stm32f1xx.h void soft_serial_init(void); void serial_write(uint8_t const data); void serial_transimt(const uint8_t *p_txdata,uint16_t size); void serial_transmit
[单片机]
CAN特殊波特率如何计算
CAN 总线采用的是异步串行通信,也就是没有单独的时钟线来保证各个收发器之间时钟的一致,每个收发器是按事先设置的 波特率 来对总线上的电平进行分位。因此波特率设置准确对CAN总线的稳定通信来说非常重要。 CAN总线里我们可以通过对CAN 节点里的位定时寄存器的控制来实现不同波特率的通信。CAN协议里将一个位时间分为同步段、传播段、相位缓冲段1和相位缓冲段2。每个段的时间长度都可以用一个整数的基本时间单位表示,该基本时间单位由系统的时钟振荡器分频得到。 同步段位于一个位的起始位置,CAN-bus规定跳变沿为同步信号,但是发送节点发送一个位跟接收节点接收到这个位之间存在网络传播延迟,传播段则是为了补偿这段传播延迟,由于
[嵌入式]
CAN特殊<font color='red'>波特率</font>如何计算
基于一体化系统集成芯片实现专用电缆自动测量系统的设计
1 引言 在现代装甲通信指挥装备中,功能强大、控制精确、运行可靠的装备,均由越来越多的电子分机、部件通过密集的线缆、线束、网络连接而成。 线缆、网络连接的正确性和可靠性,在保障整个电子系统可靠运行中起了重要的作用。对复杂线缆、线束、网络的导通、绝缘等指标的自动测试和检验,是线缆装配、生产过程中不可缺少的一个环节。传统的低压、低电流的手工、半自动测试,已经远远不能满足现代高可靠电子设备生产的需要。 目前装甲通信指挥装备的线缆检测,均采用传统的、落后的手工检测方式,用三用表、蜂鸣器及自制简单的测试台检测通断。手工检测方法存在不能克服的许多缺陷,已不能满足大批量、高精度、高可靠性线缆检测的要求: (1)1人或2人配合逐点检测,效
[测试测量]
基于一体化系统集成芯片实现专用电缆<font color='red'>自动</font><font color='red'>测量</font>系统的设计
高级外设CAN之波特率计算
在做技术支持的时候,经常接到这样的客户电话, 在使用开发板上的CAN通信时,VPB时钟为和光盘例程里的不一样,CAN波特率怎么设置?我们希望用到的CAN波特率有5K、10K、50K、500K、1000K等 。CAN波特率设置不正确将导致CAN无法通信,于是,就波特率计算的方法我写了这篇文章,以后再有客户问这类问题,便可以直接把这篇文章发给客户。 CAN波特率的计算公式如下: 其中tcan是CAN系统时钟的一个周期,tbit是一个CAN位周期。 以VPB时钟Fpclk=24MHz,选择采样点位置在85%左右为佳,即使TESG1/(TESG1+TESG2)在85%左右,2 TESG1 15,1 TESG2 7,由
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved