本期我们将介绍一个51单片机的电压表及时钟项目并介绍他的原理图以及初步仿真和注意要点。
这是项目的原理图,主要有以下几个部分组成。
- ** 单片机系统 **
51单片机的系统,包含复位以及晶振电路。
- ** 实时时钟 **
DS12887实时时钟。DS12887是一种实时钟(RTC)和NV
RAM芯片,广泛应用于计算机和其他电子设备中,用于提供精确的时间和日期信息,并存储掉电时需要保存的数据。 提供秒、分、小时、日、星期、月和年的时间信息。
支持12小时和24小时两种格式,并具有AM/PM指示器。 包含闰年补偿,可以自动处理每月的天数和闰年。
- ** AD转换器 **
ICL7135是一种高精度、4½位A/D转换器(Analog to Digital
Converter)使用双积分转换技术,具有高噪声抑制能力和低噪声特性。我们使用它来进行电压测量。
- ** 数码管驱动及显示 **
数码管驱动部分包含了74HC273锁存器,其可以根据CLK的时钟信号更新将Q0-7的内容锁存。之后接了一个2803,这里我推测是ULN2803典型的达林顿驱动阵列用以驱动数码管。
这里的2803驱动整列用以循环点亮数码管实现动态扫描。 上面的具体显示也是利用74HC273锁存器,将其内容进行锁存之后显示。
其他内容主要是一些降压、通讯、负电源等等,这里不做过多介绍,我们本期的主要内容是在Proteus对 ** 实时时钟的内容 ** 进行仿真。
当然这里也是有些注意点的。
- 关于仿真图的注意事项
虽然我们的P0是作为地址/数据复用总线使用的,但是不知道是仿真的关系还是什么,我们需要为P0加上上拉电阻才可以正常工作。
其次是数码管驱动部分的2803,这里额,应该是也要加上上拉电阻的。
因为其内部的是达林顿管结构,这里需要加上上拉电阻 才能够正常工作。但是原理图中没有上拉电阻,也许是省略了。
关于芯片部分,他的MOT引脚是决定通讯方式的,我想这个可能是摩托罗拉公司的缩写。
当这个引脚上拉的时候的时候将会选择摩托罗拉通讯协议,拉低的话则是使用英特尔协议。
这里我们拉低选择英特尔协议。具体的通讯协议在其数据手册说明的比较详细。
当然在仿真中我们还需要注意一些内容。
AS引脚在原理图中被给到了ALE引脚,这里不知道是不是设计者的原因,ALE在标准8051系列是不能被作为IO口使用的,他会以时钟频率的六分之一进行输出,而这个引脚的功能是下降沿是把AD地址总线是值存入,使得内部内存导通,所以肯定是需要我们人物手动控制的。但是STC的芯片是可以选择把这个引脚作为IO使用的。
所以这里我怀疑是设计者的问题,当然在仿真的过程中,我们还是不能将这个IO连至ALE引脚,我们应该选择一个普通IO进行控制。
关于DS12887的注意事项
首先是一点可能很多人会碰到的时钟不走的问题。
正常来说这个时间是会走的。但是很多人会发现这个时钟它不走。
这里我总结一下可能是有两点问题:
- 总线没标记好
我们这里拉出来的总线需要打上AD[0..7]的总线标记,可能很多小伙伴忽略了这一点,导致即使我们代码没有什么问题可能会因为这里的总线标签而导致不能工作。
- 没有正确的初始化
我们需要对寄存器A写入命令令其开始振荡才能工作开始振荡,当然在实际使用的时候可能只需要写入一次即可,但是仿真条件下确是需要写入命令才可以开始振荡。
注意以上这两点就可以正确的仿真我们的时钟了。 以下是附带的源码:
#include <REGX52.H>#include "DS12887.h"#include "Delay.h"
sbit CS = P2^7;sbit RW = P3^6;sbit AS = P2^4;sbit DS = P3^7;// 读 DS12887 寄存器// 定义DS12887的地址数据线连接到P0口#define DS12887_DATA P0
void DS12887_write(unsigned char add,unsigned char date){ AS=1; DS=1; RW=1; CS=0; P0=add; AS=0; RW=0; P0=date; RW=1; AS=1; CS=1; }
// 从DS12887读取数据unsigned char DS12887_read(unsigned char addr) { unsigned char Data; CS = 0; AS = 1; DS = 1; RW = 1; P0 = addr; AS = 0; DS = 0; Delay_us(10); Data = P0; DS = 1; AS = 1; CS = 1; return Data;}
void main(){ unsigned char seconds; //Timer0Init(); INT0IO = 0; DS12887_write(0x0A,0x21);//开启振荡 DS12887_write(0x0B,0x1E);//相关配置 while(1) {// seconds = DS12887_read(0x00); // 假设0x00是秒钟寄存器地址// Second = seconds;// P1 = seconds;// seconds = DS12887_read(0x02); // 假设0x00是秒钟寄存器地址// Min = seconds;// P1 = seconds; seconds = DS12887_read(0x02); // 假设0x00是秒钟寄存器地址 //Hour = seconds&0x7F; P1 = seconds; //TimeShow_Bit(1,seconds/10);// DS12887_write(0x0C,0x00); }}