单片机实现具有掉电记忆功能的计时器

发布者:电子设计探索者最新更新时间:2020-04-17 来源: eefocus关键字:单片机  掉电记忆功能  计时器 手机看文章 扫描二维码
随时随地手机看文章

项目描述:

用单片机实现0 ~ 99s的计时,将计时实时显示在LCD上,并用24C02实现掉电记忆。

仿真原理图如下:

在这里插入图片描述

C语言代码如下:


/*------------------------

FileName: clock.h

Function: 头文件

Author: Zhang Kaizhou

Date: 2019-6-12 18:07:29

------------------------*/

#include

#include

#include

#define uchar unsigned char

#define uint unsigned int

/*IIC总线端口定义*/

sbit SDA = P2^0;

sbit SCL = P2^1;


/*LCD1602显示模块端口定义*/

sbit lcdrs = P1^2;

sbit lcdrw = P1^3;

sbit lcden = P1^4;


/*主函数模块函数声明*/

void writeData24C02(uchar address, uchar dat);

void readData24C02(uchar address, uchar * dat);

void checkData(uchar * dat);

void timerInit();


/*IIC总线模块函数声明*/

void initIIC();

void startIIC();

void responseIIC();

void stopIIC();

void writeDataIIC(uchar dat);

void readDataIIC(uchar * dat);


/*LCD1602显示模块函数声明*/

void LCDInit();

void display(uchar dat1, uchar dat2);

void writeCommand(uchar command);

void writeDataLCD(uchar dat);

void delay(uchar xms);


/*--------------------------------------------

FileName: main.c

Function: 用单片机实现0 ~ 99s的计时,

将计时实时显示在LCD上,并用24C02实现掉电记忆;

Author: Zhang Kaizhou

Date: 2019-6-12 18:06:18

--------------------------------------------*/

#include "clock.h"


/*定义全局变量*/

uchar second = 0, count = 0;

bit flag = 0;


void main(){

LCDInit();

initIIC();

readData24C02(1, &second); // 通过IIC总线将24C02的第1个存储单元中的数据读取到变量second中

checkData(&second); // 首次读取数据时,原来芯片中的数据可能超过100(非法数据)

timerInit();

TR0 = 1; // 开始计时

while(1){

display(second / 10, second % 10);

if(flag){

flag = 0;

writeData24C02(1, second);

}

}

}


/*向24C02的任意地址address处写入数据dat*/

void writeData24C02(uchar address, uchar dat){

startIIC();

writeDataIIC(0xa0); // 向IIC总线发送寻址信号,并声明要进行写操作

responseIIC();

writeDataIIC(address);

responseIIC();

writeDataIIC(dat);

responseIIC();

stopIIC();

}


/*从24C02的任意地址address处读出数据到变量dat*/

void readData24C02(uchar address, uchar * dat){

startIIC();

writeDataIIC(0xa0);

responseIIC();

writeDataIIC(address);

responseIIC();

startIIC();

writeDataIIC(0xa1); // 向IIC总线发送寻址信号,并声明要进行读操作

responseIIC();

readDataIIC(dat);

stopIIC();

}


/*检测从24C02读取的数据是否合法*/

void checkData(uchar * dat){

if((* dat) > 100){

* dat = 0;

}

}


/*timer初始化*/

void timerInit(){

TMOD = 0x01; // timer0 定时模式 工作方式1(16位定时器)

TH0 = (65536 - 46080) / 256; // 系统晶振为11.0592MHz,定时50ms

TL0 = (65536 - 46080) % 256;

ET0 = 1; // 开定时器0溢出中断

EA = 1; // 开全局中断

}


/*timer0溢出中断服务程序*/

void timer0Service() interrupt 1{

TH0 = (65536 - 46080) / 256; // 重装初值

TL0 = (65536 - 46080) % 256;

count++;

if(count == 20){ // 50ms * 20 = 1s

count = 0;

second++;

flag = 1;

if(second == 100){ // 0 ~ 99s

second = 0;

}

}

}


/*------------------------------

FileName: IIC.c

Function: 实现IIC总线的基本操作

Author: Zhang Kaizhou

Date: 2019-6-12 18:08:47

------------------------------*/

#include "clock.h"


/*IIC总线初始化*/

void initIIC(){

SCL = 1;

_nop_();

SDA = 1;

_nop_();

}


/*IIC总线启动信号*/

void startIIC(){ // 在SCL高电平期间,SDA产生一个下降沿表示启动

SDA = 1;

_nop_();

SCL = 1;

_nop_();

SDA = 0;

_nop_();

}


/*IIC总线应答信号*/

void responseIIC(){ // 从机在SCL高电平期间将SDA拉低表示应答

SDA = 0;

_nop_();

SCL = 1;

_nop_();

SCL = 0;

_nop_();

}


/*IIC总线停止信号*/

void stopIIC(){ // 在SCL高电平期间,SDA产生一个上升沿表示停止

SDA = 0;

_nop_();

SCL = 1;

_nop_();

SDA = 1;

_nop_();

}


/*向IIC总线写一个字节数据*/

void writeDataIIC(uchar dat){

uchar i, temp;

temp = dat;

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

temp = temp << 1;

SCL = 0;

_nop_();

SDA = CY;

_nop_();

SCL = 1;

_nop_();

}

SCL = 0;

_nop_();

SDA = 1;

_nop_();

}


/*从IIC总线读一个字节数据*/

void readDataIIC(uchar * dat){

uchar i;

SCL = 0;

_nop_();

SDA = 1;

_nop_();

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

SCL = 1;

_nop_();

* dat = ((* dat) << 1) | SDA;

SCL = 0;

_nop_();

}

}


/*-----------------------------

FileName:display.c

Function: LCD1602显示函数

Author: Zhang Kaizhou

Date: 2019-6-12 18:09:16

------------------------------*/

#include "clock.h"


uchar code table0[] = {"Timekeeping"};

uchar code table1[] = {"Time:"};

uchar code table2[] = {"0123456789"};

uchar num = 0;


/*初始化LCD1602的设置*/

void LCDInit(){

uchar i;

lcden = 0; // 拉低使能端,准备产生使能高脉冲信号

writeCommand(0x38); // 显示模式设置(16x2, 5x7点阵,8位数据接口)

writeCommand(0x0c); // 开显示,不显示光标

writeCommand(0x06); // 写一个字符后地址指针自动加1

writeCommand(0x01); // 显示清零,数据指针清零

/*LCD上电界面*/

writeCommand(0x80); // 将数据指针定位到第一行首

for(i = 0; i < strlen(table0); i++){

writeDataLCD(table0[i]);

delay(5);

}

writeCommand(0x80 + 0x40); // 将数据指针定位到第二行首

for(i = 0; i < strlen(table1); i++){

writeDataLCD(table1[i]);

delay(5);

}

}


/*LCD显示函数*/

void display(uchar dat1, uchar dat2){

writeCommand(0x80 + 0x40 + strlen(table1));

writeDataLCD(table2[dat1]);

delay(5);

writeCommand(0x80 + 0x40 + strlen(table1) + 1);

writeDataLCD(table2[dat2]);

delay(5);

}


/*写指令函数*/

void writeCommand(uchar command){

lcdrs = 0; // 命令选择

lcdrw = 0;

P0 = command;

delay(5);

lcden = 1; // 产生一个正脉冲使能信号

delay(5);

lcden = 0;

}


/*写数据函数*/

void writeDataLCD(uchar dat){

lcdrs = 1; // 数据选择

lcdrw = 0;

P0 = dat;

delay(5);

lcden = 1;

delay(5);

lcden = 0;

}


/*延时xms函数*/

void delay(uchar xms){

uchar i, j;

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

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

}

关键字:单片机  掉电记忆功能  计时器 引用地址:单片机实现具有掉电记忆功能的计时器

上一篇:51单片机之计时器
下一篇:51单片机计时器实现1000以内的计数功能

推荐阅读最新更新时间:2024-11-08 15:50

MCS-51单片机定时系统
定时/计数器和中断源的多少直接决定单片机的性能。MCS-51单片机内部有两个可编程的16位定时/计数器和5个中断源,具有较强的实时处理能力和对外部应急事件的处理能力。要充分发挥单片机的功能,必须充分利用定时和中断。 定时器/计数器 一、定时和延时的区别 在单片机程序清单中,经常看到延时子程序和定时(中断)子程序。它们都能使单片机间隔一段时间后再做另一件事。例如,控制两组灯的交替闪亮。以1999年第38期九版图13为例,下面分别是用延时和定时方法的源程序。 程序1: ORG 0000H AJMP MAIN ORG 50H MAIN:MOV P1,#0AAH;第一组灯亮 ACALL DELAY ;调延时子程序 MOV P1,#55H
[单片机]
MCS-51<font color='red'>单片机</font>定时系统
学51单片机定时器
在这里,小编带你一起 从零开始学51单片机定时器。基于单片机的定时器电路原理图如下所示:   我们学单片机是首先学的就是 led 闪烁,那是用延时程序做的,现在回想起来,这样做不很恰当,为什么呢?我们的主程序做了灯的闪烁,就不能再干其它的事了,难道单片机只能这样工作吗?当然不是,我们能用定时器来实现灯的闪烁的功能。   例 1:查询方式   ORG 0000H   AJMP START   ORG 30H   START:   MOV P1,#0FFH ;关所 灯   MOV TMOD,#00000001B ;定时/计数器 0 工作于方式 1   MOV TH0,#15H   MOV TL0,#0A0H ;
[单片机]
学51<font color='red'>单片机</font>定时器
单片机ADC采样算法----递推平均值采样法
在上一篇文章单片机ADC采样算法---平均值采样法中分析了平均值采样法的使用,上篇文章中的平均值采样法是连续采样100个数据,然后求平均值,这种方法存在一个问题,就是采集100个值之后,下一次又重新采集100个新的值,这两次采集的值是不连续的,相当于每次都是独立的采集来100个值,然后求平均值。这样计算出来的值有可能看不出来数据的变化趋势。希望在求平均值的时候每次读取到一个新的值,就将最早读取的旧值丢弃一个,相当于水管中的流水一样,有新的水流进来,就让最早进来的水流出去。这样采集到的数据就是连续变化的。这样通过采样值就能看出来采样数据是否发生了波动。 算法如下: #define N 100 unsigned int filte
[单片机]
<font color='red'>单片机</font>ADC采样算法----递推平均值采样法
细说MCS-51单片机的物理存储空间
我们在学习传统的MCS-51单片机的时候,一定学习过51单片机的存储结构。传统的MCS-51存储器有三个空间,分别是片内RAM(内部数据存储器)、片外RAM(外部扩展的数据存储器) 和 ROM(内部或者外部程序存储器)。按照具体数据的物理存储空间来说,MCS-51单片机在有四个物理存储空间,它们分别是:片内程序存储器(片内ROM)、片外程序存储器(片外ROM)、片内数据存储器(片内RAM)、片外数据存储器(片外RAM)。 1 片内RAM空间 上述的这四种物理存储空间中,最早的8031单片机,只有数据存储器即内部RAM是标配的,其他都需要外扩,而到来的8051兼容机中,内部的数据存储器(RAM)和内部的程序存储器(ROM)都成了
[单片机]
细说MCS-51<font color='red'>单片机</font>的物理存储空间
基于单片机控制的电动车锂电池组设计
随着电动自行车的逐渐普及,电动自行车的主要能源---锂电池也成为众人关心的焦点。 锂电池与镍镉、镍氢电池不太一样,因其能量密度高,对充放电要求很高。 当过充、过放、过流及短路保护等情况发生时,锂电池内的压力与热量大量增加,容易产生爆炸,因此通常都会在电池包内加保护电路,用以提高锂电池的使用寿命。 针对目前电动车锂电池组所用的保护电路大多都由分立原件构成,存在控制精度不够高、技术指标低、不能有效保护锂电池组等特点,本文中提出一种基于单片机的电动车36 V锂电池组(由10节3. 6 V锂电池串联而成)保护电路设计方案,利用高性能、低功耗的ATmega16L 单片机作为检测和控制核心,用由MC34063构成的DC /DC变换控制电路为整
[单片机]
基于<font color='red'>单片机</font>控制的电动车锂电池组设计
基于Infineon单片机的CAN网关研究
 控制器局域网CAN(Controller Area Network)是德国Robert Bosch公司在20世纪80年代初为汽车业开发的一种车载专用串行数据通信总线,经过多年的发展,现在越来越多地被众多汽车厂商所认可。CAN不仅在汽车领域,而且在工业控制领域也得到了广泛的应用,如工业现场控制、小区安防、环境监控等。由于在具体工程应用中往往需要连接2路或者多路CAN子网,因此,CAN网关是必不可少的,是组网的关键设备之一。  在欧洲乃至世界上的很多汽车厂家,大部分的车内电子控制单元大量使用原德国西门子半导体部门英飞凌科技(Infineon Technologies)的微控制器,特别是C166系列MCU,其优良特性得到各大汽车厂家的公
[单片机]
基于Infineon<font color='red'>单片机</font>的CAN网关研究
一“芯”二用,MCU+DSP处理器大盘点
  近年来,越来越多的领域需要用到高性能,高集成度的DSP器件,功能日益增加的多媒体处理器对DSP的需求也日益剧增,于是,基于MCU+DSP架构的集成芯片也随之应运而生,更低的成本、更小的封装和更微的功耗所开辟的,是一条属于DSP或者MCU厂商们的“阳光大道“而未来,它们还将沿着这条新路继续前行。本系列文章将为你介绍市面上比较流行的基于MCU+DSP架构的处理器或者解决方案。    飞思卡尔DSP56800E   飞思卡尔在DSP与MCU领域深耕数年,为满足市场发展需求,公司率先在56800内核基础上又推出了新一代增强型内核56800E,该产品可在单一内核上提供DSP和MCU双重功能。56800E 系列DSP将为不断增长的工业、
[嵌入式]
一“芯”二用,<font color='red'>MCU</font>+DSP处理器大盘点
有关51单片机读端口、读引脚的问题
80C51单片机有P0-P3四个P口,以P0为例说明: 要搞清这个问题,就要明白p0口的内部结构。P0口是由锁存器经两个驱动场效应管和外部引脚相连的。 读引脚的意思就是直接读P0外部引脚的电位,而读端口(锁存器)读的是内部与数据总线链接的锁存器的电位。 两者不同。一般来说,读取P0的数据,都是读引脚,目的是获取与P0相连的外部电路的状态。而读端口是在执行下述语句时由CPU自行完成的: inc P0;给p0加1 执行这个语句时 ,采用“读-改-写”的过程,先读取p0的端口数据,再加1,然后送到p0锁存器里。注意这个端口数据跟p0的引脚状态不一样,比如你事先给p0写进69H,p0里数据就是69H,而引脚上的状态因为你没有执行MOV A
[单片机]
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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