2016-03-18 08:55:33 a1314521531 阅读数 1378
  • 51单片机综合小项目-第2季第4部分

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

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

单片机——DS18B20


宗旨:技术的学习是有限的,分享的精神是无限的。


        DS18B20——温度传感器,单片机可以通过 1-Wire 和 DS18B20 进行通 信,最终将温度读出。1-Wire 总线的硬件接口很简单,只需要把 18B20 的数据引脚和单片 机的一个 IO 口接上就可以通信。最高12为的温度存储值,补码形式存储。

2字节,LSB低字节,MSB高字节,-55~125

 

1、初始化

       检测存在脉冲:总线上存在DS18B20,总线会根据时序要求返回一个低电平脉冲。单片机要拉低这个引脚,持续大概 480us到960us之间 的时间即可,我们的程序中持续了 500us。然后,单片机释放总线,就是给高电平,DS18B20 等待大概 15 到 60us 后,会主动拉低这个引脚大概是 60 到 240us,而后 DS18B20 会主动释放总线,这样 IO 口会被上拉电阻自动拉高。

 

2ROM操作指令

       Skip ROM(跳过ROM):0xCC。当总线上只有一个器件的时候,可以跳过 ROM,不进行ROM 检测。

 

3RAM存储器操作指令

       Read Scratchpad(读暂存寄存器):0xBE—— DS18B20 的温度数据是 2 个字节,我们读取数据的时候,先 读取到的是低字节的低位,读完了第一个字节后,再读高字节的低位,一直到两个字节全部 读取完毕。

Convert Temperature(启动温度转换):0x44—— 12位最大的转换时间是 750ms

 

4DS18B20的位写时序

       当要给 DS18B20 写入‘0’的时候,单片机直接将引脚拉低,持续时间大于 60us 小于120us 就可以了。图上显示的意思是,单片机先拉低 15us 之后,DS18B20 会在从 15us 到60us 之间的时间来读取这一位,DS18B20 最早会 15us 的时刻读取,典型值是 30us 的时刻读取,最多不会超过 60us,DS18B20 必然读取完毕,所以持续时间超过 60us 即可。

       当要给DS18B20 写入‘1’的时候,单片机先将这个引脚拉低,拉低时间大于 1us,然后马上释放总线,即拉高引脚,并且持续时间也要大于 60us。和写‘0’类似的是,DS18B20 会在 15 到 60us 之间来读取这个‘1’。

 

5DS18B20的位读时序

        单片机首先要拉低这个引脚,并且至少保持1us 的时间,然后释放引脚,释放完毕后要尽快读取。从拉低这个引脚到读取引脚状态,不能超过 15us。大家从图 16-17 可以看出来,主机采样时间,也就是 MASTER SAMPLES,是 在15us 之内必须完成的。 

#include<reg52.h>
#include<intrins.h>

typedef unsigned char uchar;

sbit IO_18B20 = P3 ^ 2; //DS18B20通信引脚

/* 软件延时函数,延时时间(t*10)us */
void DelayX10us(uchar t)
{
  do
  {
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    _nop_();
  }
  while (--t);
}
/* 复位总线,获取存在脉冲,以启动一次读写操作*/
bit Get18B20Ack()
{
  bit ack;

  EA = 0;  //禁止总中断
  IO_18B20 = 0;     //产生500us复位脉冲
  DelayX10us(50);
  IO_18B20 = 1;
  DelayX10us(6);    //延时60us
  ack = IO_18B20;   //读取存在脉冲
  while(!IO_18B20); //等待存在脉冲结束
  EA = 1;  //重新使能总中断

  return ack;
}
/* 向DS18B20写入一个字节,dat-待写入字节 */
void Write18B20(uchar dat)
{
  uchar mask;

  EA = 0;  //禁止总中断
  for (mask = 0x01; mask != 0; mask <<= 1) //低位在先,依次移出8个bit
  {
    IO_18B20 = 0;         //产生2us低电平脉冲
    _nop_();
    _nop_();
    if ((mask & dat) == 0) //输出该bit值
    {
      IO_18B20 = 0;
    }
    else
    {
      IO_18B20 = 1;
    }
    DelayX10us(6);        //延时60us
    IO_18B20 = 1;         //拉高通信引脚
  }
  EA = 1;  //重新使能总中断
}
/* 从DS18B20读取一个字节,返回值-读到的字节 */
uchar Read18B20()
{
  uchar dat;
  uchar mask;

  EA = 0;  //禁止总中断
  for (mask = 0x01; mask != 0; mask <<= 1) //低位在先,依次采集8个bit
  {
    IO_18B20 = 0;         //产生2us低电平脉冲
    _nop_();
    _nop_();
    IO_18B20 = 1;         //结束低电平脉冲,等待18B20输出数据
    _nop_();              //延时2us
    _nop_();
    if (!IO_18B20)        //读取通信引脚上的值
    {
      dat &= ~mask;
    }
    else
    {
      dat |= mask;
    }
    DelayX10us(6);        //再延时60us
  }
  EA = 1;  //重新使能总中断

  return dat;
}
/* 启动一次18B20温度转换,返回值-表示是否启动成功 */
bit Start18B20()
{
  bit ack;

  ack = Get18B20Ack();   //执行总线复位,并获取18B20应答
  if (ack == 0)          //如18B20正确应答,则启动一次转换
  {
    Write18B20(0xCC);  //跳过ROM操作
    Write18B20(0x44);  //启动一次温度转换
  }
  return ~ack;   //ack==0表示操作成功,所以返回值对其取反
}
/* 读取DS18B20转换的温度值,返回值-表示是否读取成功 */
bit Get18B20Temp(int *temp)
{
  bit ack;
  uchar LSB, MSB; //16bit温度值的低字节和高字节

  ack = Get18B20Ack();    //执行总线复位,并获取18B20应答
  if (ack == 0)           //如18B20正确应答,则读取温度值
  {
    Write18B20(0xCC);   //跳过ROM操作
    Write18B20(0xBE);   //发送读命令
    LSB = Read18B20();  //读温度值的低字节
    MSB = Read18B20();  //读温度值的高字节
    *temp = ((int)MSB << 8) + LSB; //合成为16bit整型数
  }
  return ~ack;  //ack==0表示操作应答,所以返回值为其取反值
}

2019-02-27 18:06:09 Xiaomo_haa 阅读数 461
  • 51单片机综合小项目-第2季第4部分

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

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

 

 

温度传感器DS18B20

DS18B20是美信公司的一款温度传感器,单片机可以通过1-Wire协议与DS18B20进行通信,最终将温度读出。1-Wire总线的硬件接口很简单,只需要把DS18B20的数据引脚和单片机的一个IO 口接上就可以了。

DS18B20通过编程可以实现最高12位的温度存储值,在寄存器中,以补码的格式存储。

一共 2 个字节,LSB 是低字节,MSB 是高字节,其中 MSb 是字节的高位,LSb 是字节的低位。可以看出来,二进制数字,每一位代表的温度的含义,都表示出来了。其中 S表示的是符号位,低 11 位都是 2 的幂,用来表示最终的温度。DS18B20 的温度测量范围是从-55 度到+125 度,而温度数据的表现形式,有正负温度,寄存器中每个数字如同卡尺的刻度一样分布。如下图所示:

二进制数字最低位变化 1,代表温度变化 0.0625 度的映射关系。当 0 度的时候,那就是0x0000,当温度 125 度的时候,对应十六进制是 0x07D0,当温度是零下 55 度的时候,对应的数字是 0xFC90。反过来说,当数字是 0x0001 的时候,那温度就是 0.0625 度了。

DS18B20工作协议

1、初始化

和I2C的寻址类似,1-Wire总线开始也需要检测这条总线上是否存在DS18B20这个器件。如果这条总线上存在DS18B20,总线会根据时序要求返回一个低电平脉冲,如果不存在的话,也就不会返回脉冲,即总线保持为高电平,所以习惯上称之为检测存在脉冲。此外,获取存在脉冲不仅仅是检测是否存在DS18B20,还要通过这个脉冲过程通知DS18B20准备好,单片机要对它下手了。

通过上图,实粗线是单片机IO口拉低这个引脚,虚粗线是DS18B20拉低这个引脚,细线是单片机和DS18B20释放总线后,依靠上拉电阻的作用把IO口引脚拉上去。

存在脉冲检测过程:首先是单片机要拉低这个引脚,持续大概480~960us之间的时间即可,在持续里持续了500us。然后单片机释放总线,就是给高电平,DS18B20等待大概15~60us之后,会主动拉低这个引脚大概是60~240us,而后DS18B20会主动释放总线,这样IO口会被上拉电阻自动拉高。

根据下面的程序:由于 DS18B20 时序要求非常严格,所以在操作时序的时候,为了防止中断干扰总线时序,先关闭总中断。然后第一步,拉低 DS18B20 这个引脚,持续 500us;第二步,IO释放总线,延时 60us;第三步,读取存在脉冲,并且等待存在脉冲结束。

2、ROM操作指令

总线上可以挂多个器件,通过不同的器件地址来访问不同的器件。同样1-Wire总线也可以挂多个器件,但是它只有一条线,如何区分不同的器件。

在每个DS18B20内部都有一个唯一的64位长的序列号,这个序列号值就存在DS18B20内部的ROM中。开始的8位是产品类型编码(DS18B20是0x10),接着的 48 位是每个器件唯一的序号,最后的 8 位是 CRC 校验码。DS18B20 可以引出去很长的线,最长可以到几十米,测不同位置的温度。单片机可以通过和DS18B20 之间的通信,获取每个传感器所采集到的温度信息,也可以同时给所有的 DS18B20 发送一些指令。

Skip ROM(跳过ROM):0xCC

当总线上只有一个器件的时候,可以跳过 ROM,不进行 ROM 检测。

3、RAM存储器操作指令

RAM读取指令,常用的有两条。

Read Scratchpad(读暂存寄存器):0xBE

这里要注意,DS18B20的温度数据是两个字节,读取数据的时候,先读取到的是低字节的低位,读完了第一个字节后,再读高字节的低位,直到两个字节全部读取完毕。

Convert Temperature(启动温度转换):0x44

当发送一个启动温度转换的指令后,DS18B20开始进行转换。从转换开始到获取温度,DS18B20是需要时间的,而这个时间的长短取决于DS18B20的精度。DS18B20最高可以用12位来存储温度,但是也可以使用11位、10位和9位一共四种格式位数越高,精度越高,9位模式最低位变化1个数字,温度就变化0.5°C,同时转换速度也要相应快一些。

其中寄存器R1和R0决定了转换的位数,出厂默认值就是11,也就是12位表示温度,最大转换时间是750ms。当启动转换之后,至少要再等750ms之后才能读取温度,否则读到的温度有可能是错误的值。

如果读取到的值为85°C,这个值要么是没有启动转换,要么是启动转换了,但还没有等待一次转换彻底完成,,读到的是一个错误的数据。

4、DS18B20的位读写时序

写时序

当要给 DS18B20 写入 0 的时候,单片机直接将引脚拉低,持续时间大于 60us 小于 120us就可以了。图上显示的意思是,单片机先拉低 15us 之后,DS18B20 会在从 15us 到 60us 之间的时间来读取这一位,DS18B20 最早会在 15us 的时刻读取,典型值是在 30us 的时刻读取,最多不会超过 60us,DS18B20 必然读取完毕,所以持续时间超过 60us 即可。

当要给 DS18B20 写入 1 的时候,单片机先将这个引脚拉低,拉低时间大于 1us,然后马上释放总线,即拉高引脚,并且持续时间也要大于 60us。和写 0 类似的是,DS18B20 会在15us 到 60us 之间来读取这个 1。

DS18B20的时序比较严格,,写的过程中最好不要有中断打断。但是在两个“位”之间的间隔,是大于1小于无穷的,在这个时间段,是可以开中断来处理其他程序的。


读时序

当要读取 DS18B20 的数据的时候,我们的单片机首先要拉低这个引脚,并且至少保持1us 的时间,然后释放引脚,释放完毕后要尽快读取。从拉低这个引脚到读取引脚状态,不能超过 15us。从上图可以看出来,主机采样时间,也就是 MASTER SAMPLES,是在 15us 之内必须完成的。

DS18B20所表示的温度值中,有小数和整数两部分。常用的带小数的数据处理方法有两种,一种是定义成浮点型直接处理,第二种是定义成整型,然后把小数和整数部分分离出来,在合适的位置点上小数点即可。

DS18B20封装程序

/*******************************************************************************
* 函数名	:Delayus
* 输入值	:unsigned int us
* 返回值	:none
* 作者		:小默haa
* 时间		:2019年2月17日
* 功能描述:1T单片机延时指定us
* 备注		:最大形参65535,即最大延时65ms
*******************************************************************************/
void Delayus(unsigned int us)
{
	do{
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
	}while(--us);
}

/*******************************************************************************
* 函数名	:Get18B20Ack
* 输入值	:none
* 返回值	:none
* 作者		:小默haa
* 时间		:2019年2月27日
* 功能描述:复位总线,获取18B20存在脉冲,以启动一次读写操作
* 备注		:
*******************************************************************************/
bit Get18B20Ack(void)
{
	bit ack;
	
	EA = 0;					//禁止总中断
	DS18B20_IO = 0;			//产生500us的复位脉冲
	Delayus(500);
	DS18B20_IO = 1;			//延时60us
	Delayus(60);
	ack = DS18B20_IO;		//读取存在脉冲
	while(!DS18B20_IO);	//等待存在脉冲结束
	
	EA = 1;					//重新使能总中断
	
	return ack; 	
}

/*******************************************************************************
* 函数名	:DS18B20Write
* 输入值	:unsigned char dat
* 返回值	:none
* 作者		:小默haa
* 时间		:2019年2月27日
* 功能描述:向18B20写入一个字节
* 备注		:dat为待写入字节
*******************************************************************************/
void DS18B20Write(unsigned char dat)
{
 	unsigned char mask;

	EA = 0;						//禁止总中断						
	for(mask = 0x01; mask != 0; mask <<= 1)	//低位在先,依次移出8个bit
	{
		DS18B20_IO = 0;			//产生2us低电平脉冲
		Delayus(2);
	 	if(dat & mask)		    //输出该bit值
		 	DS18B20_IO = 1;
		else
		 	DS18B20_IO = 0;
		Delayus(60);			//延时60us
		DS18B20_IO = 1;			//拉高通信引脚
	}
	EA = 1;						//重新使能总中断
}

/*******************************************************************************
* 函数名	:DS18B20Read
* 输入值	:none
* 返回值	:unsigend char dat
* 作者		:小默haa
* 时间		:2019年2月27日
* 功能描述:从18B20读取一个字节
* 备注		:返回值为读取到的字节
*******************************************************************************/
unsigned char DS18B20Read(void)
{
 	unsigned char mask, dat = 0;
	
	EA = 0;						//禁止总中断
	for(mask = 0x01; mask != 0; mask <<= 1)	//低位在先,依次采集8个bit
	{
		DS18B20_IO = 0;			//产生2us低电平脉冲
		Delayus(2);
		DS18B20_IO = 1;			//结束低电平脉冲,等待18B20输出数据
		Delayus(2);				//延时2us
	 	if(DS18B20_IO)			//读取通信引脚上的值
		{
		 	dat |= mask;
		}
		Delayus(60);			//再延时60us
	}
	
	EA = 1;						//重新使能总中断
	
	return dat;	
}

/*******************************************************************************
* 函数名	:Start18B20
* 输入值	:none
* 返回值	:bit ~ack
* 作者		:小默haa
* 时间		:2019年2月27日
* 功能描述:启动一次18B20温度转换
* 备注		:返回值为是否启动成功
*******************************************************************************/
bit Start18B20()
{
 	bit ack;

	ack = Get18B20Ack();		//执行总线复位,并获取18B20应答
	if(ack == 0)				//如18B20正确应答,则启动一次转换
	{
	 	DS18B20Write(0xCC);		//跳过ROM操作
		DS18B20Write(0x44);		//启动一次温度转换
	}

	return ~ack;				//ack == 0 表示操作成功,所以返回值对其取反
}

/*******************************************************************************
* 函数名	:Get18B20Temp
* 输入值	:int *temp
* 返回值	:bit ~ack
* 作者		:小默haa
* 时间		:2019年2月27日
* 功能描述:读取18B20转换的温度值
* 备注		:返回值为是否读取成功
*******************************************************************************/
bit Get18B20Temp(int *temp)
{
 	bit ack;
	unsigned char LSB, MSB;		//16bit温度值的低字节和高字节

	ack = Get18B20Ack();		//执行总线复位,并获取18B20应答
	if(ack == 0)				//如18B20正确应答,则读取温度值
	{
	 	DS18B20Write(0xCC);		//跳过ROM操作
		DS18B20Write(0xBE);		//发送读命令
		LSB = DS18B20Read();	//读温度值的低字节
		MSB = DS18B20Read();	//读温度值的高字节
		*temp = ((unsigned int) MSB << 8) + LSB;	//合成16bit的整数
	}

	return ~ack;				//ack == 0 表示操作应答,所以返回值为1其取反值
} 

为使显示精度也能达到0.0625°C,我们可以在程序中做如下处理。

bit res = 0;
int Temp = 0;				        //读取当前的温度值
int Temp_int = 999, Temp_dec = 999;	        //温度值的整数和小数部分

res = Get18B20Temp(&Temp);	                //读取当前温度
if(res)				                //如果读取到
{
	Temp_int = Temp >> 4;			//分离出温度值整数部分
	Temp_dec = Temp & 0xF;		        //分离出温度值小数部分
	Temp_dec = Temp_dec * (10000 / 16);	//二进制小数部分转换为4位十进制
}
Start18B20();					//重新启动下一次转换

 

 

 

2015-03-03 14:23:18 final_21 阅读数 1874
  • 51单片机综合小项目-第2季第4部分

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

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

用两个 89C51 单片机实现双机通讯来做一个时钟,A 机用来产生数据,B 机用来显示。

具体思路是 A 机产生 a、b、c 的具体值,然后把 abc 传给 B 机显示数据。

A 机发送 a, b, c 给 B 机,B 机拿来用。

写出了双方的通信部分,代码可见该问题的网址:

 http://zhidao.baidu.com/question/1731754753643347587.html

为此,从网上找来这张图,显示函数、定时函数...,也都编写出来,供参考。




PROTEUS 仿真电路图如下:



图片链接:

http://xiangce.baidu.com/picture/detail/8d7c506b7ade7f0feb49f353e22d81dfef5453dc

 

//============================================

 

B 机(显示数据)的程序如下:

 

//--------------------------------

 

#include<reg52.h>

 

unsigned char  re_i = 0, r_buf[7] = {0,0,0,0,0,0,0};

unsigned char  a = 13, b = 57, c = 40, d;

 

//--------------------------------

void delayms(unsigned int xms)

{

    unsigned  int i, j;

    for(i = xms; i > 0; i--)  for(j = 110; j > 0; j--);

//--------------------------------

void display()

{   

    char  i, dis[6];

    char code table[] = {

      0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xd8,0x80,0x90};

    char code WEI[] = {1,2,4,8,16,32};

 

    dis[0] = a / 10; dis[1] = a % 10;

    dis[2] = b / 10; dis[3] = b % 10;

    dis[4] = c / 10; dis[5] = c % 10;

 

    for (i = 0; i < 6; i++) {

      P0 = table[dis[i]];

      P2 = WEI[i]; delayms(10); P2 = 0;

    }

}

//--------------------------------

init()

{

    PCON = 0;

    SCON = 0x50;

    TMOD = 0x20;

    TH1 = 0xfd;

    TL1 = 0xfd;

    TR1 = 1;

    ES = 1;

    EA = 1;

}

//--------------------------------

main()        //乙机主函数

{

    init();

    while(1) {

      display();

    }

}

//--------------------------------

recv_abc()  interrupt 4  //乙机接收

{

    if (RI) {

      RI = 0;

      d = SBUF;

      if (d == '$')  re_i = 0;

      r_buf[re_i] = d;

      re_i++;

      if (re_i == 7) {

        re_i = 0;

        a = (r_buf[1] - '0') * 10 + (r_buf[2] - '0');

        b = (r_buf[3] - '0') * 10 + (r_buf[4] - '0');

        c = (r_buf[5] - '0') * 10 + (r_buf[6] - '0');

      }

    }

}

 

//============================================

 

A 机(产生数据)的程序如下:

 

//--------------------------------

 

#include<reg52.h>

 

unsigned char  a = 13, b = 57, c = 40, d;

bit  sec;

//--------------------------------

init()

{

    PCON = 0;

    SCON = 0x50;

    TMOD = 0x21;

    TH1 = 0xfd;

    TL1 = 0xfd;

    TR1 = 1;

    EA = 1;

 

    TH0 = 0x4c;

    TR0 = 1;

    ET0 = 1;

}

//--------------------------------

send(unsigned char x)    //甲机发送

{

    SBUF = x;  while(!TI);  TI = 0;

}

//--------------------------------

main()        //甲机主函数

{

    init();

    while(1) {

      if(sec) {

        sec = 0;

        send('$');

        send(a / 10 + '0'); send(a % 10 + '0');

        send(b / 10 + '0'); send(b % 10 + '0');

        send(c / 10 + '0'); send(c % 10 + '0');

    } }

}

//--------------------------------

T0_INT()  interrupt 1  //50ms定时中断函数

{

    TH0 = 0x4c;

    d++;

    if (d >= 2) {  //20

      d = 0;

      sec = 1;

      c++;

      if (c == 60) {

        c = 0;

        b++;

        if (b == 60) {

          b = 0;

          a++;

          if (a == 24) a = 0;

    } } }

}

 

//============================================

 

上述的两个程序,需分别编译,生成不同 HEX 文件;再分别用两个单片机来装入。

 

程序执行后,即可显示出来前面插图的效果。B 机的显示器,每秒更新一次数据。

 

当把中间的开关断开后,显示的数据便会停顿,不变了。

 

再把中间的开关接通后,显示又会变化,而且数据并不受断开的影响。

 

这说明,显示的内容,明显是从 A 机传送来的。

 

//============================================

 

本题目,需要传送的数据有时、分、秒共三个,这就属于多字节的串行通信。

 

单片机的串行通信,每次只能传送一个字节,即 0~255。

 

多字节的数据传送,需要制订协议。

 

否则,连续传送一个一个的字节,到了接收方,也不知道哪个是时、哪个是分、哪个是秒。

 

这时,一般要采用 ASCII 码来传送。

 

用 0~9,即代表了一系列有用的数据。

 

再用一个 0~9 之外的符号,当做《数据头》,就行了。

 

本程序,就是以美元符 $ 当做数据头。

 

传送了 $ 之后,接着就传送时的十位数、时的个位数、分的十位数、分的位数、秒的个位数。

 

每次发送数据,就连续的发出七个字节。

 

接收方收到了 $ 之后,就把后面再收到的当做时、分、秒的十位、个位保存。

 

当收齐了七个字节,就把这后面的六个字节,送去显示。


2010-01-07 17:54:00 nicole_yaoyao 阅读数 11350
  • 51单片机综合小项目-第2季第4部分

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

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

 

MCS-51系列单片机有21个可寻址的专用寄存器,其中有11个专用寄存器是可以位寻址的。下面把各寄存器的字节地址及位地址并列于表1-6和表1-7中。

1-6  专用寄存器地址表

   

   

    

ACC

B

PSW

累加器

B寄存器

程序状态字

E0H

F0H

D0H

SP

DPTR

 

P0

堆栈指针

数据指针(包括DPHDPL

 

P0口锁存寄存器

81H

82H

83H

80H

P1

P2

P3

P1口锁存寄存器

P2口锁存寄存器

P3口锁存寄存器

90H

A0H

B0H

IP

IE

TMOD

中断优先级控制寄存器

中断允许控制寄存器

定时/计数器工作方式状态寄存器

B8H

A8H

89H

TCON

TH0

TL0

定时/计数器控制寄存器

定时/计数器0(高字节)

定时/计数器0(低字节)

88H

8CH

8AH

TH1

TL1

定时/计数器1(高字节)

定时/计数器1(低字节)

8DH

8BH

SCON

SBUF

PCON

串行口控制寄存器

串行口数据缓冲器

电源控制寄存器

98H

99H

87H

 


1-7  可进行位寻址的SFR的分布

SFR

位地址/位定义

字节地址

MSB                                                        LSB

B0

F7H

F6H

F5H

F4H

F3H

F2H

F1H

F0H

F0H

 

 

 

 

 

 

 

 

ACC

E7H

F6H

E5H

E4H

E3H

E2H

E1H

E0H

E0H

 

 

 

 

 

 

 

 

PSW

D7H

D6H

D5H

D4H

D3H

D2H

D1

D0H

D0H

CY

AC

F0

RS1

RS0

OV

P

IP

BFH

BEH

BDH

BCH

BBH

BAH

B9H

B8H

B8H

 

 

 

PS

PT1

PX1

PT0

PX0

P3

B7

B6

B5

B4

B3

B2

B1

B0

BOH

P3.7

P3.6

P3.5

P3.4

P3.3

P3.2

P3.1

P3.0

IE

AF

AE

AD

AC

AB

AA

A9

A8

A8H

EA

 

 

ES

ET1

EX1

ET0

EX0

P2

A7

A6

A5

A4

A3

A2

A1

A0

A0H

P2.7

P2.6

P2.5

P2.4

P2.3

P2.2

P2.1

P2.0

SCON

9F

9E

9D

9C

9B

9A

99

98

98H

SM0

SM1

SM2

REN

TB8

RB8

TI

RI

P1

97

96

95

94

93

92

91

90

90H

P1.7

P1.6

P1.5

P1.4

P1.3

P1.2

P1.1

P1.0

TCON

8F

8E

8D

8C

8B

8A

89

88

88H

TF1

TR1

TF0

TR0

IE1

IT1

IE0

IT0

P0

87

86

85

84

83

82

81

80

80H

P0.7

P0.6

P0.5

P0.4

P0.3

P0.2

P0.1

P0.0

2015-12-24 21:52:19 ls667 阅读数 3039
  • 51单片机综合小项目-第2季第4部分

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

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

存储器分为程序存储器(ROM)和数据存储器(RAM),两种又都可以分为片内和片外,片外即需要自己在单片机外部扩展。

8051单片机的片内程序存储器有4K,片内数据存储器有256个字节,其中又分为高128字节位特殊功能寄存器区,真正用户能用的RAM只有低128字节。

8052单片机有8K片内程序存储器,而数据存储器除了低128字节外还有扩展的高128字节,地址上跟特殊功能寄存器一样,但物理上是独立的,寻址方式不一样,扩展的高128字节只能间接寻址。


Keil中变量的存储类型:

存储类型

说明

code

程序空间(无需改变的变量)

data

直接访问的内部数据存储器(速度最快)

idata

间接访问的内部数据存储器(可以访问全部256字节RAM)

bdata

可位寻址的内部数据存储器

xdata

外部数据寄存器(最大64K)

pdata

分页的外部数据寄存器(最大256字节,少用)

【如无使用关键字,系统则按默认处理(根据存储模式)】

Keil中的存储模式:

存储模式

说明

Small

变量默认为data型,最大128字节

Compare

变量默认为pdata型,最大256字节

Large

变量默认为xdata型,最大64K

Keil中设置如下图:



我们平常使用的STC单片机,有很多型号,具体存储器大小都要看型号:


【89/90系列的机器周期需要12个或6个时钟周期】


【12/15系列的机器周期只需要1个时钟周期】


51单片机上的FFT算法

最近用增强型51单片机做了一个简易的点阵音乐频谱显示器,最主要是自己刚学完信号处理课程,想自己写一个FFT算法。现将已经能够在51单片机上运行的FFT算法供需要的伙伴们参考。

在51单片机上运行FFT算法,需要注意一下几点:

由于51单片机的内存RAM很小,只有128字节,52有256字节,而16点的浮点数输入,就需要2*4*16=128字节的内存开销,所以只有256字节的做多只能做16点的FFT运算。而且必须要用idata定义才能将其定义在高128字节。所以要做16点以上的FFT运算,必须选用有内部扩展RAM的51系列单片机,然后用xdata定义,并且要将存储模式设为LARGE模式。


51单片机内部ram

阅读数 4178

单片机原理第二章

阅读数 118

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