51单片机入门学习 第九天

提示:今天是学习51单片机的第九天,以下就是今天的笔记(我买的是普中的开发板,学习笔记是根据普中的视频进行学习)今天学习的内容是I2C和温度传感器和时钟。

目录

创建多文件工程

I2C-EEPROM 实验

1.I2C 介绍

1.1 I2C 物理层

1.2 I2C 协议层

3.硬件设计

4.软件设计

DS18B20 温度传感器实验

1 DS18B20 介绍

(1)初始化时序

(2)写时序

(3)读时序

2 硬件设计 

3 软件设计

DS1302 时钟实验

 1.DS1302 时钟芯片介绍

1.1 DS1302简介

1.2 DS1302使用

  (1)控制寄存器

  (2)日历/时钟寄存器

  (3)DS1302 的读写时序

2.硬件设计

3.软件设计


创建多文件工程

创建一个全新的工程,目的是方便日后工程管理、程序移植和维护、易读等

在电脑上创建一个实验文件夹,然后在该文件夹内新建 App、Obj、Public、User 四个文件夹,

App 文件夹:用于存放外设驱动文件,如 LED、数码管、定时器等。

Obj 文件夹:用于存放编译产生的 c/汇编/链接的列表清单、调试信息、 hex 文件、预览信息、封装库等文件。

Public 文件夹:用于存放 51 单片机公共的文件,如延时、51 头文件、变量 类型重定义等。

User 文件夹:用于存放用户主函数文件,如 main.c。

一个main.c 文件中的代码量非常冗长,极其不便于程序的阅读、移植和维护,因此可用多文件管理的 办法来使工程易于阅读、移植和维护。操作方法如下:

  1. 新建工程 :首先打开 KEILC51 软件,新建一个工程,这个在将工程命名并保存在文件夹下,然后选择芯片类型为“AT89C52”,不使用系统创建启动文件,上述与前面介绍的创建工程模板是一样的,下面才开始在工程中进行分组管理。
  2.  向工程添加文件 :按照需要给工程分组并添加对应文件,这里我们在工程中分 3 组,User、App、 Publi,至于前面创建的 Obj 文件夹是在工程中无需体现,因为只是编译器生成 的一些中间文件和.hex 执行文件。通常在工程组的命名与创建的文件夹名保持 一致,方便查找到源文件位置。分组后,在工程中就会出现刚才的分组列表。 然后就是给每个组添加对应的.c 源文件。
  3. 配置魔术棒选项卡 :这一步的配置工作非常重要,很多人编写完程序编译后发现找不到 HEX 文件,还有的人直接编译前面添加好文件的工程出现报错,这些问题都是在这个地 方没有配置好导致的。 (1)Output 选项卡中把输出文件夹定位到我们实验目录下的 Obj 文件夹, 如果想在编译的过程中生成 hex 文件,那么 Create HEX File 选项勾上。(3)Listing 选项卡中把输出文件夹也定位到我们实验目录下的 Obj 文件夹。其它设置默认。(4)C51 选项卡配置,此处目的是将我们前面添加到工程组中的文件路径包括进来,否则程序中调用其他文件夹的头文件则会报错找不到头文件路径, 添加的头文件路径是指,在实验文件夹下里面,哪些文件夹内 含有.h 头文件,并且需要被调用到的,通常我们会把只要含有头文件的文件夹 都选择进去。比如本例程中 App 内含有很多子文件夹,它们里面都含有头文件, 因此要分别添加,Public 也含有头文件,所以也要添加。
  4. 51 仿真器配置

至此,我们就成功创建好一个多文件工程模板。在以后的实验中,凡是涉及 到多个外设资源模块的都可以使用该工程模板,尤其是对重复利用已编写过的外设驱动。 

I2C-EEPROM 实验

学习如何使用 51 单片机的 IO 口模拟 I2C 时序,并实现与 AT24C02(EEPROM)之间的双向通信。开发板板载了 1 个 EEPROM 模块,可实现 IIC 通信。EEPROM (Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器。是一种掉电后数据不丢失的存储芯片。 EEPROM 可以在电脑上或专用设备上擦除已有信息,重新编程。一般用在即插即用。内容如下:

  • 1.I2C 介绍
  • 2.AT24C02 介绍
  • 3.硬件设计
  • 4.软件设计 

1.I2C 介绍

I2C(Inter-Integrated Circuit)总线是由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形式,具有接口线少,控制方式简单, 器件封装形式小,通信速率较高等优点。I2C 总线只有两根双向信号线。一根是数据线 SDA,另一根是时钟线SCL。由于其管脚少,硬件实现简单,可扩展性强等特点,因此被广泛的使用在各大集成芯片内。我们就从 I2C 的物理层与 协议层来了解I2C。

1.1 I2C 物理层

I2C 通信设备常用的连接方式如下图所示:

51单片机入门学习 第九天_第1张图片

  它的物理层有如下特点:

(1)它是一个支持多设备的总线。“总线”指多个设备共用的信号线。在 一个 I2C 通讯总线中,可连接多个 I2C 通讯设备,支持多个通讯主机及多个通讯从机。

(2)一个 I2C 总线只使用两条总线线路,一条双向串行数据线(SDA),一 条串行时钟线(SCL)。数据线即用来表示数据,时钟线用于数据收发同步。

(3)每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。

(4)总线通过上拉电阻接到电源。当 I2C 设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。

(5)多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定 由哪个设备占用总线。 (6)具有三种传输模式:标准模式传输速率为 100kbit/s,快速模式为 400kbit/s,高速模式下可达 3.4Mbit/s,但目前大多 I2C 设备尚不支持高速模 式。

(7)连接到相同总线的 IC 数量受到总线的最大电容 400pF 限制。

下面我们来了解下 I2C 总线常用的一些术语:

  • 主机:启动数据传送并产生时钟信号的设备;
  • 从机:被主机寻址的器件;
  • 多主机:同时有多于一个主机尝试控制总线但不破坏传输;
  • 主模式:用 I2CNDAT 支持自动字节计数的模式: 位 I2CRM,I2CSTT,I2CSTP 控制数据的接收和发送;
  • 从模式:发送和接收操作都是由 I2C 模块自动控制的;
  • 仲裁:是一个在有多个主机同时尝试控制总线但只允许其中一个控制总线并使传输不被破坏的过程;
  • 同步:两个或多个器件同步时钟信号的过程;
  • 发送器:发送数据到总线的器件;
  • 接收器:从总线接收数据的器件 。

1.2 I2C 协议层

I2C 的协议定义了通信的起始和停止信号、数据有效性、响应(是否发送信息)、仲裁(寻址相应从机)、时钟同步和地址广播(数据的传送)等环节。

(1)数据有效性规定

I2C 总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保 持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。如下图:

51单片机入门学习 第九天_第2张图片

 每次数据传输都以字节为单位,每次传输的字节数不受限制。

(2)起始和停止信号

SCL 线为高电平期间,SDA 线由高电平向低电平的变化表示起始信号;SCL 线为高电平期间,SDA 线由低电平向高电平的变化表示终止信号。如下图:

51单片机入门学习 第九天_第3张图片

起始和终止信号都是由主机发出的,在起始信号产生后,总线就处于被占用 的状态;在终止信号产生后,总线就处于空闲状态。

(3)应答响应

每当发送器件传输完一个字节的数据后,后面必须紧跟一个校验位,这个校验位是接收端通过控制 SDA(数据线)来实现的,以提醒发送端数据我这边已经接收完成,数据传送可以继续进行。这个校验位其实就是数据或地址传输过程中的响应。响应包括“应答(ACK)”和“非应答(NACK)”两种信号。作为数据接收端时,当设备(无论主从机)接收到 I2C 传输的一个字节数据或地址后,若希望对方继续发送数据,则需要向对方发送“应答(ACK)”信号即特定的低电平脉冲, 发送方会继续发送下一个数据;若接收端希望结束数据传输,则向对方发送“非 应答(NACK)”信号即特定的高电平脉冲,发送方接收到该信号后会产生一个停止信号,结束信号传输。应答响应时序图如下:

51单片机入门学习 第九天_第4张图片

 每一个字节必须保证是 8 位长度。数据传送时,先传送最高位(MSB),每 一个被传送的字节后面都必须跟随一位应答位(即一帧共有 9 位)。 由于某种原因从机不对主机寻址信号应答时(如从机正在进行实时性的处理 工作而无法接收总线上的数据),它必须将数据线置于高电平,而由主机产生一个终止信号以结束总线的数据传送。 如果从机对主机进行了应答,但在数据传送一段时间后无法继续接收更多的数据时,从机可以通过对无法接收的第一个数据字节的“非应答”通知主机,主 机则应发出终止信号以结束数据的继续传送。 当主机接收数据时,它收到最后一个数据字节后,必须向从机发出一个结束 传送的信号。这个信号是由对从机的“非应答”来实现的。然后,从机释放 SDA 线,以允许主机产生终止信号。 这些信号中,起始信号是必需的,结束信号和应答信号都可以不要。

(4)总线的寻址方式(寻找从机)

I2C 总线寻址按照从机地址位数可分为两种,一种是 7 位,另一种是 10 位。采用 7 位的寻址字节(寻址字节是起始信号后的第一个字节)的位定义如下:

 D7~D1 位组成从机的地址。D0 位是数据传送方向位,为“ 0”时表示主机 向从机写数据,为“1”时表示主机由从机读数据。 10 位寻址和 7 位寻址兼容,而且可以结合使用。10 位寻址不会影响已有 的 7 位寻址,有 7 位和 10 位地址的器件可以连接到相同的 I2C 总线。

我们 就以 7 位寻址为例进行介绍。 当主机发送了一个地址后,总线上的每个器件都将头 7 位与它自己的地址比较,如果一样,器件会判定它被主机寻址,其他地址不同的器件将被忽略后面的数据信号。至于是从机接收器还是从机发送器,都由 R/W 位决定的。从机的 地址由固定部分和可编程部分组成。在一个系统中可能希望接入多个相同的从 机,从机地址中可编程部分决定了可接入总线该类器件的最大数目。如一个从机 的 7 位寻址位有 4 位是固定位,3 位是可编程位,这时仅能寻址 8 个同样的 器件,即可以有 8 个同样的器件接入到该 I2C 总线系统中。

(5)数据传输

I2C 总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据 信号。在起始信号后必须传送一个从机的地址(7 位),第 8 位是数据的传送方向位(R/W),用“ 0”表示主机发送(写)数据(W),“ 1”表示主机接收数据(R)。每次数据传送总是由主机产生的终止信号结束。但是,若主机希望 继续占用总线进行新的数据传送,则可以不产生终止信号,马上再次发出起始信 号对另一从机进行寻址。 在总线的一次数据传送过程中,可以有以下几种组合方式:

a、主机向从机发送数据,数据传送方向在整个传送过程中不变

  注意:有阴影部分表示数据由主机向从机传送,无阴影部分则表示数据由从机向主机传送。A 表示应答,A 非表示非应答(高电平)。S 表示起始信号,P 表 示终止信号。

b、主机在第一个字节后,立即从从机读数据

 c、在传送过程中,当需要改变传送方向时,起始信号和从机地址都被重复产生一次,但两次读/写方向位正好相反

1.2 AT24C02 介绍

AT24C01/02/04/08/16...是一个 1K/2K/4K/8K/16K 位串行 CMOS,内部含128/256/512/1024/2048 个 8 位字节,AT24C01 有一个 8 字节页写缓冲器, AT24C02/04/08/16 有一个 16 字节页写缓冲器。该器件通过 I2C 总线接口进行操作,它有一个专门的写保护功能。我们开发板上使用的是 AT24C02(EEPROM) 265 芯片,此芯片具有 I2C 通信接口,芯片内保存的数据在掉电情况下都不丢失, 所以通常用于存放一些比较重要的数据等。AT24C02 芯片管脚及外观图如下图所示:

51单片机入门学习 第九天_第5张图片

  芯片管脚说明如下图所:

51单片机入门学习 第九天_第6张图片

 AT24C02 器件地址为 7 位,高 4 位固定为 1010,低 3 位由 A0/A1/A2 信 号线的电平决定。 因为传输地址或数据是以字节为单位传送的,当传送地址时, 器件地址占 7 位,还有最后一位(最低位 R/W)用来选择读写方向,它与地址 无关。其格式如下:

我们开发板已经将芯片的 A0/A1/A2 连接到 GND,所以器件地址为 1010000,即 0x50(未计算最低位)。如果要对芯片进行写操作时,R/W 即为 0, 写器件地址即为 0XA0;如果要对芯片进行读操作时,R/W 即为 1,此时读器件 地址为 0XA1。开发板上也将 WP 引脚直接接在 GND 上,此时芯片允许数据正常读写。 

3.硬件设计

(1)独立按键(K1-K4) (2)动态数码管 (3)EEPROM 模块电路(AT24C02)

从图中可以看出,芯片的 SCL 和 SDA 管脚是连接在单片机的 P2.1 和 P2.0 上, 在介绍 IIC 总线的时候我们说过,为了让 IIC 总线默认为高电平,通常会在 IIC 总线上接上拉电阻,在图中并没有看到 SCL 和 SDA 管脚有上拉电阻,这是因为开 发板单片机 IO 都外接了 10K 上拉电阻,当单片机 IO 口连接到芯片的 SCL 和 SDA 脚时即相当于它们外接上拉电阻,所以此处可以省去。

51单片机入门学习 第九天_第7张图片

4.软件设计

系统运行时,数码管右 3 位显示 0,按 K1 键将数据 写入到 EEPROM 内保存,按 K2 键读取 EEPROM 内保存的数据,按 K3 键显示数据加 1,按 K4 键显示数据清零,最大能写入的数据是 255。 程序框架如下:

  • (1)编写按键检测功能
  • (2)编写数码管显示功能
  • (3)编写 IIC 驱动,包括起始、停止、应答信号等
  • (4)编写 AT24C02 读写功能
  • (5)编写主函数 

1.I2C 读写字节函数

#include "iic.h"
/********************************************************************
***********
* 函 数 名 : iic_start
* 函数功能 : 产生 IIC 起始信号
* 输 入 : 无
* 输 出 : 无
*********************************************************************
**********/
void iic_start(void)
{
IIC_SCL=1;
IIC_SDA=1;
delay_10us(1);
IIC_SDA=0; //当 SCL 为高电平时,SDA 由高变为低
delay_10us(1);
IIC_SCL=0;//钳住 I2C 总线,准备发送或接收数据
}
/********************************************************************
***********
* 函 数 名 : iic_stop
* 函数功能 : 产生 IIC 停止信号
* 输 入 : 无
* 输 出 : 无
*********************************************************************
**********/
void iic_stop(void)
{
IIC_SCL=1;
IIC_SDA=0;
delay_10us(1);
IIC_SDA=1; //当 SCL 为高电平时,SDA 由低变为高
delay_10us(1);
}
/********************************************************************
***********
* 函 数 名 : iic_ack
* 函数功能 : 产生 ACK 应答
* 输 入 : 无
* 输 出 : 无
*********************************************************************
**********/
void iic_ack(void)
{
IIC_SCL=0;
IIC_SDA=0; //SDA 为低电平
delay_10us(1);
IIC_SCL=1;
delay_10us(1);
IIC_SCL=0;
}
/********************************************************************
***********
* 函 数 名 : iic_nack
* 函数功能 : 产生 NACK 非应答
* 输 入 : 无
* 输 出 : 无
*********************************************************************
**********/
void iic_nack(void)
{
IIC_SCL=0;
IIC_SDA=1; //SDA 为高电平
delay_10us(1);
IIC_SCL=1;
delay_10us(1);
IIC_SCL=0;
}
/********************************************************************
***********
* 函 数 名 : iic_wait_ack
* 函数功能 : 等待应答信号到来
* 输 入 : 无
* 输 出 : 1,接收应答失败
0,接收应答成功
*********************************************************************
**********/
u8 iic_wait_ack(void)
{
u8 time_temp=0;
IIC_SCL=1;
delay_10us(1);
while(IIC_SDA) //等待 SDA 为低电平
{
time_temp++;
if(time_temp>100)//超时则强制结束 IIC 通信
{
iic_stop();
return 1;
}
}
IIC_SCL=0;
return 0;
}
/********************************************************************
***********
* 函 数 名 : iic_write_byte
* 函数功能 : IIC 发送一个字节
* 输 入 : dat:发送一个字节
* 输 出 : 无
*********************************************************************
**********/
void iic_write_byte(u8 dat)
{
u8 i=0;
IIC_SCL=0;
for(i=0;i<8;i++) //循环 8 次将一个字节传出,先传高再传低位
{
if((dat&0x80)>0)
IIC_SDA=1;
else
IIC_SDA=0;
dat<<=1;
delay_10us(1);
IIC_SCL=1;
delay_10us(1);
IIC_SCL=0;
delay_10us(1);
}
}
/********************************************************************
***********
* 函 数 名 : iic_read_byte
* 函数功能 : IIC 读一个字节
* 输 入 : ack=1 时,发送 ACK,ack=0,发送 nACK
* 输 出 : 应答或非应答
*********************************************************************
**********/
u8 iic_read_byte(u8 ack)
{
u8 i=0,receive=0;
for(i=0;i<8;i++ ) //循环 8 次将一个字节读出,先读高再传低位
{
IIC_SCL=0;
delay_10us(1);
IIC_SCL=1;
receive<<=1;
if(IIC_SDA)receive++;
delay_10us(1);
}
if (!ack)
iic_nack();
else
iic_ack();
return receive;
}

2.AT24C02 读写字节函数

#include "24c02.h"
#include "iic.h"
/********************************************************************
***********
* 函 数 名 : at24c02_write_one_byte
* 函数功能 : 在 AT24CXX 指定地址写入一个数据
286
* 输 入 : addr:写入数据的目的地址
dat:要写入的数据
* 输 出 : 无
*********************************************************************
**********/
void at24c02_write_one_byte(u8 addr,u8 dat)
{
iic_start();
iic_write_byte(0XA0); //发送写命令
iic_wait_ack();
iic_write_byte(addr);//发送写地址
iic_wait_ack();
iic_write_byte(dat); //发送字节
iic_wait_ack();
iic_stop(); //产生一个停止条件
delay_ms(10);
}
/********************************************************************
***********
* 函 数 名 : at24c02_read_one_byte
* 函数功能 : 在 AT24CXX 指定地址读出一个数据
* 输 入 : addr:开始读数的地址
* 输 出 : 读到的数据
*********************************************************************
**********/
u8 at24c02_read_one_byte(u8 addr)
{
u8 temp=0;
iic_start();
iic_write_byte(0XA0); //发送写命令
iic_wait_ack();
iic_write_byte(addr); //发送写地址
iic_wait_ack();
iic_start();
iic_write_byte(0XA1); //进入接收模式
iic_wait_ack();
temp=iic_read_byte(0); //读取字节
iic_stop(); //产生一个停止条件
return temp;
}

3.主函数

下载程序后,数码管右 4 位显示 0,按 K1 键将数据写入到 EEPROM 内保存, 按 K2 键读取 EEPROM 内保存的数据,按 K3 键显示数据加 1,按 K4 键显示数据清 零, 最大能写入的数据是 255。

#include "public.h"
#include "24c02.h"
#include "key.h"
#include "smg.h"
#define EEPROM_ADDRESS 0 //定义数据存入 EEPROM 的起始地址
/********************************************************************
***********
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*********************************************************************
**********/
void main()
{
u8 key_temp=0;
u8 save_value=0;
u8 save_buf[3];
while(1)
{
key_temp=key_scan(0);
if(key_temp==KEY1_PRESS)
{
at24c02_write_one_byte(EEPROM_ADDRESS,save_value);
}
else if(key_temp==KEY2_PRESS)
{
save_value=at24c02_read_one_byte(EEPROM_ADDRESS);
}
else if(key_temp==KEY3_PRESS)
{
save_value++;
if(save_value==255)save_value=255;
}
else if(key_temp==KEY4_PRESS)
{
save_value=0;
}
save_buf[0]=save_value/100;
save_buf[1]=save_value%100/10;
save_buf[2]=save_value%100%10;
smg_display(save_buf,6);
}
}

DS18B20 温度传感器实验

学习了如何使用单片机 IO 口模拟 IIC 总线时序。继续学习精度较高的外部 DS18B20 数字温度传感器,由于此传感器是单总线接口,所以需要使用 51 单片机的一个 IO 口模拟单总线时序与 DS18B20 通信, 将检测的环境温度读取出来。如下几部分内容:

  • 1 DS18B20 介绍
  • 2 硬件设计
  • 3 软件设计

1 DS18B20 介绍

DS18B20 是由 DALLAS 半导体公司推出的一种的“一线总线(单总线)”接 口的温度传感器。与传统的热敏电阻等测温元件相比,它是一种新型的体积小、 适用电压宽、与微处理器接口简单的数字化温度传感器。 DS18B20 温度传感器具有如下特点:

  • 1、适应电压范围更宽,电压范围:3.0~5.5V,在寄生电源方式下可由数据 线供电。
  • 2、独特的单线接口方式,DS18B20 在与微处理器连接时仅需要一条口线即 可实现微处理器与 DS18B20 的双向通讯。
  • 3、DS18B20 支持多点组网功能,多个 DS18B20 可以并联在唯一的三线上, 实现组网多点测温。
  • 4、DS18B20 在使用中不需要任何外围元件,全部传感元件及转换电路集成 在形如一只三极管的集成电路内。
  • 5、温度范围-55℃~+125℃,在-10~+85℃时精度为±0.5℃
  • 6、可编程的分辨率为 9~12 位,对应的可分辨温度分别为 0.5℃、0.25℃、 0.125℃ 和 0.0625℃,可实现高精度测温。
  • 7、在 9 位分辨率时最多在 93.75ms 内把温度转换为数字,12 位分辨率时 最多在 750ms 内把温度值转换为数字,速度更快。
  • 8、测量结果直接输出数字温度信号,以"一根总线"串行传送给 CPU,同时 可传送 CRC 校验码,具有极强的抗干扰纠错能力。
  • 9、负压特性:电源极性接反时,芯片不会因发热而烧毁,但不能正常工作。

从 DS18B20 外观图可以看到,正对传感器切面(传感器型号字符那一面)时,传感器的管脚顺序是从左到右排列。管脚 1 为 GND,管脚 2 为数据 DQ,管脚 3 为 VDD。如果把传感器插反,那么电源将短路,传感器就会发烫, 很容易损坏,通常我们在开发板上都会标出传感器的凸起出,所以只需要把传感器凸起的方向对着开发板凸起方向插入即可。

DS18B20 内部结构如下图所示:

51单片机入门学习 第九天_第8张图片

 ROM 中的 64 位序列号是出厂前被光刻好的,它可以看作是该 DS18B20 的地址序列号。64 位光刻 ROM 的排列是:开始 8 位(28H)是产品类型标号,接着的 48 位是该 DS18B20 自身的序列号,最后 8 位是前面 56 位的循环冗余校验码。光刻 ROM 的作用是使每一个 DS18B20 都各不相同,这样就可以实现一根总线上挂接多个 DS18B20 的目的。

DS18B20 温度传感器的内部存储器包括一个高速的暂存器 RAM 和一个非易 失性的可电擦除的 EEPROM,后者存放高温度和低温度触发器 TH、TL 和配置寄存器。 配置寄存器是配置不同的位数来确定温度和数字的转化,配置寄存器结构如下:

 低五位一直都是"1",TM 是测试模式位,用于设置 DS18B20 在工作模式还 是在测试模式。在 DS18B20 出厂时该位被设置为 0,用户不需要去改动。R1 和 R0 用来设置 DS18B20 的精度(分辨率),可设置为 9,10,11 或 12 位,对 应的分辨率温度是 0.5℃,0.25℃,0.125℃和 0.0625℃。R0 和 R1 配置如下图:

51单片机入门学习 第九天_第9张图片

 在初始状态下默认的精度是 12 位,即 R0=1、R1=1。高速暂存存储器由 9 个 字节组成,其分配如下:

51单片机入门学习 第九天_第10张图片

当温度转换命令(44H)发布后,经转换所得的温度值以二字节补码形式存 放在高速暂存存储器的第 0 和第 1 个字节。存储的两个字节,高字节的前 5 位 是符号位 S,单片机可通过单线接口读到该数据,读取时低位在前,高位在后, 数据格式如下:

51单片机入门学习 第九天_第11张图片

 如果测得的温度大于 0,这 5 位为‘ 0’,只要将测到的数值乘以 0.0625 (默认精度是 12 位)即可得到实际温度;如果温度小于 0,这 5 位为‘ 1’, 测到的数值需要取反加 1 再乘以 0.0625 即可得到实际温度。温度与数据对应 关系如下: 比如我们要计算+85 度,数据输出十六进制是 0X0550,因为高字节的高 5 位为 0,表明检测的温度是正温度,0X0550 对应的十进制为 1360,将这个值乘 以 12 位精度 0.0625,所以可以得到+85 度。 知道了怎么计算温度,接下来我们就来看看如何读取温度数据,由于 DS18B20 是单总线器件,所有的单总线器件都要求采用严格的信号时序,以保证 数据的完整性。

DS18B20 时序包括如下几种:初始化时序、写(0 和 1)时序、 读(0 和 1)时序。 DS18B20 发送所有的命令和数据都是字节的低位在前

(1)初始化时序

51单片机入门学习 第九天_第12张图片

单总线上的所有通信都是以初始化序列开始。主机输出低电平,保持低电平 时间至少 480us(该时间的时间范围可以从 480 到 960 微妙),以产生复位脉 冲。接着主机释放总线,外部的上拉电阻将单总线拉高,延时 15~60 us,并进 入接收模式。接着 DS18B20 拉低总线 60~240 us,以产生低电平应答脉冲,若 为低电平,还要做延时,其延时的时间从外部上拉电阻将单总线拉高算起最少要 480 微妙。

(2)写时序

51单片机入门学习 第九天_第13张图片

写时序包括写 0 时序和写 1 时序。所有写时序至少需要 60us,且在 2 次 独立的写时序之间至少需要 1us 的恢复时间,两种写时序均起始于主机拉低总线。写 1 时序:主机输出低电平,延时 2us,然后释放总线,延时 60us。写 0 时序:主机输出低电平,延时 60us,然后释放总线,延时 2us。

(3)读时序

51单片机入门学习 第九天_第14张图片

 单总线器件仅在主机发出读时序时,才向主机传输数据,所以,在主机发出 读数据命令后,必须马上产生读时序,以便从机能够传输数据。所有读时序至少 需要 60us,且在 2 次独立的读时序之间至少需要 1us 的恢复时间。每个读时 序都由主机发起,至少拉低总线 1us。主机在读时序期间必须释放总线,并且在 时序起始后的 15us 之内采样总线状态。 典型的读时序过程为:主机输出低电平延时 2us,然后主机转入输入模式延 时 12us,然后读取单总线当前的电平,然后延时 50us。

在了解了单总线时序之后,我们来看看 DS18B20 的典型温度读取过程, DS18B20 的典型温度读取过程为:复位→发 SKIP ROM 命令(0XCC)→发开始转换命令(0X44)→延时→复位→发送 SKIP ROM 命令(0XCC)→发读存储器命令 (0XBE)→连续读出两个字节数据(即温度)→结束。 

2 硬件设计 

(1)动态数码管 (2)DS18B20 

3 软件设计

插上 DS18B20 温度传感器,数码管显示检测的温度 值。

程序框架: (1)编写数码管显示功能 (2)编写 DS18B20 读取温度功能 (3)编写主函数

初始化

/********************************************************************
***********
* 函 数 名 : ds18b20_init
* 函数功能 : 初始化 DS18B20 的 IO 口 DQ 同时检测 DS 的存在
* 输 入 : 无
* 输 出 : 1:不存在,0:存在
*********************************************************************
**********/
u8 ds18b20_init(void)
{
ds18b20_reset();
return ds18b20_check();
}
/********************************************************************
***********
* 函 数 名 : ds18b20_reset
299
* 函数功能 : 复位 DS18B20
* 输 入 : 无
* 输 出 : 无
*********************************************************************
**********/
void ds18b20_reset(void)
{
DS18B20_PORT=0; //拉低 DQ
delay_10us(75); //拉低 750us
DS18B20_PORT=1; //DQ=1
delay_10us(2); //20US
}
/********************************************************************
***********
* 函 数 名 : ds18b20_check
* 函数功能 : 检测 DS18B20 是否存在
* 输 入 : 无
* 输 出 : 1:未检测到 DS18B20 的存在,0:存在
*********************************************************************
**********/
u8 ds18b20_check(void)
{
u8 time_temp=0;
while(DS18B20_PORT&&time_temp<20) //等待 DQ 为低电平
{
time_temp++;
delay_10us(1);
}
if(time_temp>=20)return 1; //如果超时则强制返回 1
else time_temp=0;
while((!DS18B20_PORT)&&time_temp<20) //等待 DQ 为高电平
{
time_temp++;
delay_10us(1);
}
if(time_temp>=20)return 1; //如果超时则强制返回 1
return 0;
}

温度读取函数

/********************************************************************
***********
* 函 数 名 : ds18b20_read_temperture
* 函数功能 : 从 ds18b20 得到温度值
* 输 入 : 无
* 输 出 : 温度数据
*********************************************************************
**********/
float ds18b20_read_temperture(void)
{
float temp;
u8 dath=0;
u8 datl=0;
u16 value=0;
ds18b20_start();//开始转换
ds18b20_reset();//复位
ds18b20_check();
ds18b20_write_byte(0xcc);//SKIP ROM
ds18b20_write_byte(0xbe);//读存储器
datl=ds18b20_read_byte();//低字节
dath=ds18b20_read_byte();//高字节
value=(dath<<8)+datl;//合并为 16 位数据
if((value&0xf800)==0xf800)//判断符号位,负温度
{
value=(~value)+1; //数据取反再加 1
temp=value*(-0.0625);//乘以精度
}
else //正温度
{
temp=value*0.0625;
}
return temp;
}
/********************************************************************
***********
* 函 数 名 : ds18b20_start
* 函数功能 : 开始温度转换
* 输 入 : 无
* 输 出 : 无
*********************************************************************
**********/
void ds18b20_start(void)
{
ds18b20_reset();//复位
ds18b20_check();//检查 DS18B20
ds18b20_write_byte(0xcc);//SKIP ROM
ds18b20_write_byte(0x44);//转换命令
}

主函数

/********************************************************************
****************** 实验名称:DS18B20 温度传感器实验
接线说明:
实验现象:下载程序后,插上 DS18B20 温度传感器,数码管显示检测的温度值
注意事项:注意温度传感器的方向,在接口处我们已经用丝印画了一个凸起,
所以只需要将温度传感器对应插入即可
*********************************************************************
******************/
#include "public.h"
#include "smg.h"
#include "ds18b20.h"
/********************************************************************
302
***********
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*********************************************************************
**********/
void main()
{
u8 i=0;
int temp_value;
u8 temp_buf[5];
ds18b20_init();//初始化 DS18B20
while(1)
{
i++;
if(i%50==0)//间隔一段时间读取温度值,间隔时间要大于温度传感器转换温度时间
temp_value=ds18b20_read_temperture()*10;//保留温度值小数后一位
if(temp_value<0)//负温度
{
temp_value=-temp_value;
temp_buf[0]=0x40;//显示负号
}
else
temp_buf[0]=0x00;//不显示
temp_buf[1]=gsmg_code[temp_value/1000];//百位
temp_buf[2]=gsmg_code[temp_value%1000/100];//十位
temp_buf[3]=gsmg_code[temp_value%1000%100/10]|0x80;//个位+小数
点
temp_buf[4]=gsmg_code[temp_value%1000%100%10];//小数点后一位
smg_display(temp_buf,4);
}
}

DS1302 时钟实验

我们学习了如何使用单片机IO 口模拟(IIC 总线、单总线时序)。 我们继续学习 DS1302 时钟芯片,该芯片是 3 线 SPI 接口,所以需要使用 51 单片机的 3 个 IO 口模拟 SPI 时序与 DS1302 时钟芯片通信,将时钟日历数据读取出来。开发板上集成了 1 个 DS1302 时钟模块,可使用它设计一个多功能电子时钟。内容如下:(时钟和前面两个很相似就不再过多说明)

  • 1.DS1302 时钟芯片介绍
  • 2.硬件设计
  • 3.软件设计 

 1.DS1302 时钟芯片介绍

1.1 DS1302简介

DS1302 是 DALLAS 公司推出的涓流充电时钟芯片,内含有一个实时时钟/日 历和 31 字节静态 RAM,通过简单的串行接口与单片机进行通信。实时时钟/日 历电路提供秒、分、时、日、周、月、年的信息,每月的天数和闰年的天数可自 动调整。时钟操作可通过 AM/PM 指示决定采用 24 或 12 小时格式。DS1302 与 单片机之间能简单地采用同步串行的方式进行通信,仅需用到三根通信线:①RES 复位②I/O 数据线③SCLK 串行时钟。时钟/RAM 的读/写数据以一个字节或多达 31 个字节的字符组方式通信。DS1302 工作时功耗很低保持数据和时钟信息时功 率小于 1mW。 DS1302 由 DS1202 改进而来增加了以下的特性:双电源管脚用于主电源和 备份电源供应,Vcc1 为可编程涓流充电电源,附加七个字节存储器。它广泛应 用于电话、传真、便携式仪器以及电池供电的仪器仪表等产品领域下面。

51单片机入门学习 第九天_第15张图片

管脚1接电。管教2 3 接晶振。GND接电,管脚8备用电源,SCLK 时钟,I/O口为管脚六其中SPI是为四根总线读和写这里是只有一个。CE使能。 

1.2 DS1302使用

先控制寄存器,在根据时序图来写程序。(其中对于单片机来说若有外接口,只是控制相应的寄存器就行。若没有外接口就要配置相应的芯片在来配置寄存器和根据时序图来写驱动程序 己建) 

  (1)控制寄存器

 其中高位7为固定,6为1时RAM,0时为寄存器。54321为,为 RAM 或者寄存器的地址。

51单片机入门学习 第九天_第16张图片

51单片机入门学习 第九天_第17张图片

  (2)日历/时钟寄存器

51单片机入门学习 第九天_第18张图片

51单片机入门学习 第九天_第19张图片

  (3)DS1302 的读写时序

51单片机入门学习 第九天_第20张图片

 这里IO口图是有问题的应该是先写低位再写高位(写的这个图有问题)。读的时候先读高位在读低位。

2.硬件设计

51单片机入门学习 第九天_第21张图片

3.软件设计

本章所要实现的功能是:数码管上显示电子时钟时分秒,格式为“XX-XX-XX

你可能感兴趣的:(51单片机,单片机)