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

项目描述:
用单片机实现0 ~ 99s的计时,将计时实时显示在LCD上,并用24C02实现掉电记忆。
仿真原理图如下:
单片机实现具有掉电记忆功能的计时器_第1张图片
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--);
}

你可能感兴趣的:(C51)