2019-03-26 21:29:13 guanjianhe 阅读数 476
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3416 人正在学习 去看看 朱有鹏

前几天,画了块51的板子,晶振用的是12MHz的,调试过程发现串口打印输出一直乱码,用的是STC-ISP(V6.86R)这个工具软件里面的波特率计算器来直接计算波特率,配置如下图所示:

就是这个配置导致了通信乱码,原因是——误差太大了,8.51%的误差,查找原因过程看到有资料说如果误差在2%以上就会出现乱码(具体没有测试过),更别提我这8.51%的误差了。

原因是找到了,解决的方法呢?一是换晶振,换成11.0592MHz的频率,这个误差是0%,对波特率精度要求比较高的可以考虑下这个方案。二是修改配置,如下图所示:

和上面那个配置相比主要是把波特率从9600改成了4800,并且勾上了波特率倍速这个选择框,这样就把误差降到了0.16%,试了一下,腰好了,肾也好了,通信也正常了。

2019-10-26 17:10:07 qq_43400642 阅读数 28
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3416 人正在学习 去看看 朱有鹏

我们知道,F103默认的外部晶振是8M,系统时钟频率是72M,但实际项目中,多数情况下可能会采用16M,25M晶振等等,如果不注意,很容易就超频,导致单片机无法正常运转,此处以16M晶振为例,说明一下时钟频率的修改。

1.修改stm32f10x.h中HSE_Value的值,8M修改为16M。

#define HSE_Value    ((uint32_t)16000000) /*!< Value of the External oscillator in Hz*/

2.修改system_stm32f10x.c中static void SetSysClockTo72(void)函数。

在此函数中,我们不需要修改其他地方,只需修改PLLCLK时钟设置。

/*!< PLLCLK = 8MHz * 9 = 72 MHz */

原来的代码:
//    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
//    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL9);

修改后:
        RCC_PLLConfig(RCC_PLLSource_HSE_Div2, RCC_PLLMul_9);//先将晶振分频,再倍频, 16 / 2 * 9 = 72,之所以使用这个函数,是因为我当前使用的库有些标志没有。

如果大家使用的库有以下标志,建议大家使用下面的两句话。

 /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE_Div2 | RCC_CFGR_PLLMULL9);

2018-04-01 20:18:14 cr2269736819 阅读数 10443
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3416 人正在学习 去看看 朱有鹏
        在设计51系列的单片机系统时,一般选用11.0592MHz的晶振而不选用12MHz的晶振,为什么?12M的晶振,振荡频率明显高于11.0592M的,按理说12MHz的晶振可以提高单片机的性能,那么我们为什么不用12M的呢?这个问题与单片机的串口波特率有关。


        51单片机的串口工作方式有4种,方式0、方式2的波特率是固定的,只与单片机的系统晶振频率有关。方式1、方式3波特率是可变的,不止与系统晶振频率有关,还与定时器T1有关(为什么是T1呢?因为51单片机的波特率发生器只能由定时器T1或定时器T2产生,由于我们使用的是STC98C52单片机,是标准51架构的单片机没有T2模块。)


        对于串口通信来讲最常用的是方式1,以下以串口的模式1来分析。由串口发送原理知,串口发送一次,实际上要发,1位起始位,8位数据位,1位结束位。由于使用模式1没有第9位数据位,所以,串口发送一次,一共要发10位数据,有一点要注意,在串口发送数据时,两次发送之间是没有累计误差的。


串口工作在方式1下的波特率计算公式为:
Baud = ((2^SMOD)/32)*(T1定时器溢出率)
其中SMOD为寄存器PCON的最高位,当SMOD = 0时,串口通信方式1、2、3波特率正常;当SMOD = 1时,串口通信方式1、2、3波特率加倍。

我们这里以不加倍,即SMOD = 0为例。


还有一个问题,由于串口方式1要用到T1定时器,而T1定时器也有4种工作方式,那么用哪一种工作方式呢?
方式0,兼容8048单片机的13位定时器,现在很少用到了,不予考虑;方式3,禁用定时器1,自然也不行;方式1、2都可以使用,那么用哪个更好呢?答案是用方式2,因为如果使用方式1,在中断中手动装载初值的方法来求溢出率的话,由于在进入中断、装值、出中断这个过程中,很容易产生时间上的微小误差,当多次操作时微小误差不断累积,终会产生错误。而方式2,由于当定时器计满溢出后单片机自动为其装载初值,并且无需进入中断服务程序进行任何处理,这样定时器溢出的速率就会相对更稳定。
综上所述,我们这里使用串口模式1、定时器模式2、SMOD = 0,由此查阅数据手册,得到以下计算公式:
Baud = Fosc/(256 - REDLOAD)/32/12
Fosc = 晶振频率
RELOAD = 自动重装载值
上述公式可以改写为
Baud = Fosc/(256 - RELOAD)/2/16/12

有几点注意一下,由图知:



        51单片机串口工作在方式1,上时,给串口使用的时钟频率要先除2,再除16,为什么要除2呢?因为实际上对于单片机的串口及外部的通信模块来说,单片机的晶振频率即使在12分频后,依然太快,所以先除2,降低串口模块所使用的的时钟频率。为什么要除16呢?因为在串口通信中为了保证所接收的数据的正确性,先对每位信号采集16次,再取其中的7、8、9次,如果有两次是高电平,就认定这一位是1,如果有2位是低电平,就认定这一位是0,所以,公式中频率要除16,。至于为什么要除12是因为公式中的频率Fosc是晶振频率,但是单片机所使用的的频率是经过了12分频的。所以对单片机而言一个机器周期等于12个时钟周期,为了理解上诉公式,有以下知识点需了解:

1个时钟周期  =1/晶振周期 = 1/Fosc

1个机器周期 =  12*(1/Fosc)

定时器T1的计数值每经过一个机器周期加1,即每经过12*(1/Fosc)秒,TL1加1,当TL1等于256就溢出,TH1将值重新赋给TL1,TL1开始重新计数。

如此我们设经过Y个机器周期TL1溢出,则:

Y*(12/Fosc) = (1/Baud)/2/16

Y =Fosc/Baud/32/12

由于使用T1的模式2,所以,设自动重装载值为RELOAD,则:

RELOAD= 256 – Y

     = 256- (Fosc/Baud/32/12)

Baud =Fosc/(256 - RELOAD)/32/12

由高中物理知识知,误差等于实际值减理论值,再除理论值,再乘以100%,所以误差计算公式为:

Error= ((Baud – Baud0)/Baud0 )*100%

Baud0= 标准波特率

Baud =实际波特率

 

综上所述,可以得到以下公式:

RELAOD= 256 – INF(Fosc/Baud0/32/12   +  0.5)

Baud =Fosc/(256 - RELOAD)/32/12

Error= (Baud – Baud0)/Baud0  * 100%

 

 

RELOAD= 自动重装载值

Baud0= 标准波特率

Baud =实际波特率

Fosc =晶振频率

Error = 偏差

INF()表示取整运算(RELOAD只能为整数),即去掉小数,0.5可以达到四舍五入的目的。

当Baud0 =9600时,使用12MHz晶振:

RELOAD= 256 – INF(Fosc/Baud0/32/12  +  0.5)

     = 256 - 3

     = 253

Buad =Fosc/(256 - RELOAD)/32/12

   = 12 * 10^6/3/32/12

   = 10416.67

Error= (Buad – Buad0)/Buad0 * 100%

    =8.51%

当Baud0 =9600时,使用11.059200MHz晶振:

RELOAD= 256 – INF(Fosc/Baud0/32/12    +  0.5)

             = 253

Buad =Fosc/(256 -RELOAD)/32/12

          = 9600

Error = 0


 

        由上图知,理论上,要使采集的数为正确的,则第8位必须正确,则允许发送一字节累加误差不能超过50%,单个的位误差不能超过50/10*100% = 5%,由此可知在9600的波特率下,使用12MHz的晶振时,单个位超过5%,必定会出现传错的位。

实际上,单位误差控制在2%以内可以比较可靠的通信,超过5%串口通信就不可靠了,附上常用波特率使用12MHz晶振和11.0592MHz晶振的误差表:





        由表知,使用12MHz的晶振在2400波特率下还是可以忍受的,但是超过2400后通信变得极不可靠。


注:
        关于通信波特率为什么要用4800、9600、19200等类似的数,有一种说法是,根据电、传输介质等的物理特性给串口设备的要求:
        为了保证有效通讯,根据电、传输介质等的物理特性结合串口设备的使用要求,确定RS232最大传输速率只能是115200,然后逐级二分得到57600、28800、19200。。。。为适应这些速率设计的相应的晶振频率。
另一种说法是,这是由电信线路特性决定的:
电话线路的带通是300—3KHz,当时HAYES先搞得modem,所以用的2400Hz信号,对应波特率是2400,由于基本频率确定了,以后采用的提高通信速率的方法都是2400基础上倍频的,所以形成了9600、19200。。。。
不管哪种说法都是先有波特率在有晶振频率的,也就是,波特率是前人在试验下得出的最佳的通信速率,我们使用的时候直接用现有的通信速率就行,但是要注意单片机使用的晶振频率,使用时会不会使串口产生误差,如果误差太大就会产生通信错误。


2018/4/1 青岛理工大学琴岛学院计算机工程系 -- 离远,本文为原创,转载请注明出处。


参考文献:
《手把手教你学51单片机(C语言版)》清华大学出版社,宋雪松、李冬明、崔长胜编著
《51单片机C语言教程——入门、提高、开发、拓展全攻略》电子工业出版社,郭天祥编著
STC89C52的数据手册
参考网络资料:


https://wenku.baidu.com/view/c1ca295684868762cbaed597.html
http://blog.sina.com.cn/s/blog_6202cb4101011udd.html
http://bbs.21ic.com/icview-207428-1-1.html
















2018-08-19 21:00:31 weixin_39563584 阅读数 707
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3416 人正在学习 去看看 朱有鹏

本来很早就想写博客了,但是太懒了。今天心血来潮,想把自己这几年在大学里面积累的东西在后面分享给大家。

现在将晶振的值定为12M,这是一个很常用的值,在计算定时的时间时会比较方便。12M的晶振表示这个晶振在一秒之内产生12*10^6次脉冲信号,则一次脉冲的时间为1/12*10^6秒(1/12us),51单片机的一个机器周期等于12个时钟周期,所以一个时钟周期为1us,这样子我们就能很轻松的来计算定时的时间了。定时器工作方式1最长定时为65536×1×10^-6=65.536ms。

如果要输出周期为1s的任意占空比的方波。那可以把1s分为100份,每份中断一次。然后在中断里面计数(比如全局变量num)加一。加到100之后,表示一个周期结束。这样就可以控制每一份的电平的高低了。如果,占空比为30%,那么也就是num小于等于100×30%=30的时候,输出高电平,其余输出低电平就可以了。如果占空比为a(百分号的形式),那么也就是num小于等于100×a的时候输出高电平,其余输出低电平就可以了。

现在考虑定时器的初值如何设定,由于定时器需要在1s/100也就是10ms的时候进入一次中断进行判断。如果采用方式1,那么因为(216 − X) *1 *10^−6 = 10 *10^−3,所以定时器的初始值为X=65536 – 1000。

 注意事项:定时器的装载值(即定时的时间)不能太快,太快的话,程序不停的进入中断,会影响其他代码的执行。

#include<reg52.h> //头文件
sbit output=P1^1; //输出端
unsigned char  num=1; //辅助计时
unsigned int a = 0.5;占空比a可以任意设定
void Init(void) //初始化函数
{
    //对于定时器一般初始化需要六步
    TMOD=0x01;
    TH0=(65536-1000)/256; //(65536-1000)为定时器初值,定时10ms
    TL0=(65536-1000)%256;
    EA=1;
    ET0=1;
    TR0=1;
}
int main(void)
{
    Init();
    while(1)
    {
        if(num<=100*a)output=1; //使占空比为a
        else output=0;
    }
}
void Timer_0(void) interrupt 1 //中断函数
{
    TH0=(65536-1000)/256;    //重新装载数值
    TL0=(65536-1000)%256;
    num++;
    if(num>100) num=1;
}

 

2016-12-22 19:04:42 superjunenaruto 阅读数 6478
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3416 人正在学习 去看看 朱有鹏

单片机晶振大多为11.0592的原因:

1.这里有郭天祥老师的解释:


2.分析:

但是,在这里博主还是存在一些疑问,为什么不是其他数呢?或者说11.0592M这个数则么产生的?

我们假定0-12_000_000之间有一个数满足以下条件的时候,这个数比较适合晶振的频率:

1.当初值在0-255的情况下,这个数能够整除较多的数(整除的数越多,便可获得能够整除的波特率的种 类越 多);

2.而且这个数应该较大,晶振频率越快,波特率越大,传输的速度越快;

3.在SOMD加倍和不加倍的情况下,这个数都能够整除较多的数。

因此,我们选出在SOMD加倍和不加倍的两种情况下,都可以整除较多数的频率(将两种情况的加在一起)。

注:

1.这里我们分析填充初值的范围为0-255,(因为大多数的串口波特率设定使用定时器由硬件自动重装初值的方式二)。

2.这里我们示范分析定时器方式一的。

3.这里晶振的频率测试范围为0-12000000。

4.当SMOD为0时,除数 32*1200,当SMOD为1时,除数 16*1200。(这里考虑到波特率一般是100的倍数,除数由计算公式得出)


涉及的波特率计算公式有:


实例:


3.测试代码

#include<stdio.h>
void main()
{
	int x=0,i=0,num=0,num1=0,num2=0,pp=0,p=0,p1=0,p2=0;
	const int n1=32*1200;
	const int n2=16*1200;
	int jg1=0,jg2=0;
	printf("结果一:\n个数	频率	个数	频率\n");
	while(x<=12000000)
	{
		x++;
		if((x%n1)==0)
		{
			p=x/n1;
			while(i<=256)
			{
				i++;
				if((p%i)==0)
					num1++;
			}
			i=0;
		}
		if((x%n2)==0)
		{
			p=x/n2;
			while(i<=256)
			{
				i++;
				if((p%i)==0)
					num2++;
			}
			i=0;
		}
		if((num1>15)&&(num2>15)) printf("%d,%d	%d,%d\n",num1,x,num2,x);	//在SMOD为0时,输出大于15个的;在SMOD为1时,输出大于15个的
		if(num>(num1+num2)) num=num;
		else {num=(num1+num2);pp=x;}
		num1=0;
		num2=0;
	}
	printf("输出整除最多的那个频率:%d,%d\n",num,pp);	//输出整除最多的那个数


	printf("结果二:\n当晶振为11520000:\n");
	x=0;
	printf("初值	SMOD=0    SMOD=1\n");
	while(x<=254)
	{
		x++;
		p1=(1*115200)/(32*12);
		p2=(2*115200)/(32*12);
		pp=(256-x);
		if(((p1%pp)==0)&&((p2%pp)==0))
		{
			printf("%d	",x);
			jg1=(11520000*1/32/12)/(256-x);
			jg2=(11520000*2/32/12)/(256-x);
			printf("%d	%d\n",jg1,jg2);
		}
	}
}

4.测试结果

注:
1.结果一:左边的是SMOD为0,右边的是SMOD为1;
2.个数的含义是:在初值为0-255之间时,可以整除的个数;
3.当整除的个数大于15时,才会输出结果。


5.结果分析

我们最后一组输出的是,在SMOD等于0或1时,整除的个数最多的一个频率,我们发现居然不是11059200,而是9216000。
进一步分析11059200频率较大,在可获得在计算过程中能够整除的波特率的种类数差别不大的情况下,我们选频率较大的11059200。
另外,我们发现还有一个数相对来说比11059200好,这个数是11520000,如果计算一下这个晶振频率可以获得的波特率有哪些的时候,会发现可获得的波特率也很好(结果二中),为什么没有选用这个晶振对应的波特率为国际上标准波特率,原因可能有其他,但是从这里的分析可以看出选用11.0592M的晶振的好处。

没有更多推荐了,返回首页