本文包含原理图、PCB、源代码、封装库、中英文PDF等资源
您需要 登录 才可以下载或查看,没有账号?注册会员
×
我做了一个一秒钟的计数器,用中断精确定时,采用IIc总线挂接的AT24C08作为存储器,用来储存计数器计的数值,防止掉电数据
丢失!结果我一下载到单片机内,却不能产生我想要的效果!能正确计数,但每次断电后,重新计数时,却不从我断电时的数字计
而是从另外一个数计,而且这个数还时不时的变!请各位高手帮我看看程序,是不是不合理!谢谢!!
#include<reg52.h>
#include<intrins.h> //包含函数_nop_()的头文件
#define OP_WRITE 0XA0 //宏定义 表示写操作
#define OP_READ 0XA1 //表示读操作
sbit SCL=P3^4;
sbit SDA=P3^5; //定义端口
sbit K7=P1^6; //按键定义
bit write=0; 写//写24C08标志位
unsigned char count; //中断次数计数变量
unsigned char sec=0; //秒变量
unsigned char code tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //数码管显示数组
/*********************
延时函数 延时约1ms
********************/
void delay1ms()
{
unsigned char i,j;
for(i=0;i<10;i++)
for(j=0;j<33;j++)
;
}
/************************
延时若干毫秒
***********************/
void delaynms(unsigned char n)
{
unsigned char i;
for(i=0;i<n;i++)
delay1ms();
}
/************************
开始数据传送
************************/
void start()
// 开始位
{
SDA = 1; //SDA初始化为高电平“1”
SCL = 1; //开始数据传送时,要求SCL为高电平“1”
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
SDA = 0; //SDA的下降沿被认为是开始信号
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
SCL = 0; //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递)
}
/**************************
停止数据传送
*************************/
void stop()
{
SCL=1;
SDA=0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SDA=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SDA=0;
SCL=0;
}
/****************************
检测应答
返回值ask_bit;0,应答;1未应答
**************************/
bit ASK()
{
bit ask_bit;
SDA=1;
_nop_();
_nop_();
SCL=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
ask_bit=SDA;
SCL=0;
return ask_bit;
}
/****************************
从24C08中读取数据
****************************/
unsigned char ReadData()
// 从AT24Cxx移入数据到MCU
{
unsigned char i;
unsigned char K; //储存从AT24Cxx中读出的数据
for(i = 0; i < 8; i++)
{
SCL = 1; //SCL置为高电平
K<<=1; //将x中的各二进位向左移一位
K|=(unsigned char)SDA; //将SDA上的数据通过按位“或“运算存入x中
SCL = 0; //在SCL的下降沿读出数据
}
return(K); //将读取的数据返回
}
/***********************************
将数据写入24C08中
***********************************/
void WriteCurrent(unsigned char y)
{
unsigned char i;
for(i = 0; i < 8; i++) // 循环移入8个位
{
SDA = (bit)(y&0x80); //通过按位“与”运算将最高位数据送到S
//因为传送时高位在前,低位在后
_nop_(); //等待一个机器周期
SCL = 1; //在SCL的上升沿将数据写入AT24Cxx
_nop_(); //等待一个机器周期
_nop_(); //等待一个机器周期
SCL = 0; //将SCL重新置为低电平,以在SCL线形成传送数据所需的8个脉冲
y <<= 1; //将y中的各二进位向左移一位
}
}
/**************************************
在指定位置写入数据
*************************************/
void WriteSet(unsigned char add, unsigned char dat)
// 在指定地址addr处写入数据WriteCurrent
{
start(); //开始数据传递
WriteCurrent(OP_WRITE); //选择要操作的AT24Cxx芯片,并告知要对其写入数据
ASK();
WriteCurrent(add); //写入指定地址
ASK();
WriteCurrent(dat); //向当前地址(上面指定的地址)写入数据
ASK();
stop(); //停止数据传递
delaynms(4); //1个字节的写入周期为1ms, 最好延时1ms以上
}
/********************************
从24C08当前位置读取数据
*******************************/
unsigned char ReadCurrent()
{
unsigned char T;
start(); //开始数据传递
WriteCurrent(OP_READ); //选择要操作的AT24Cxx芯片,并告知要读其数据
ASK();
T=ReadData(); //将读取的数据存入x
stop(); //停止数据传递
return T; //返回读取的数据
}
/********************************
在24C08指定位置读取数据
*******************************/
unsigned char ReadSet(unsigned char set_addr)
// 在指定地址读取
{
start(); //开始数据传递
WriteCurrent(OP_WRITE); //选择要操作的AT24Cxx芯片,并告知要对其写入数据
ASK();
WriteCurrent(set_addr); //写入指定地址
ASK();
return(ReadCurrent()); //从指定地址读出数据并返回
}
/*******************************
数码管显示函数
****************************/
void display()
{
P2=0XBF;
P0=tab[sec/10];
delaynms(2);
P2=0X7F;
P0=tab[sec%10];
delaynms(2);
P2=0XFF;
P0=0XFF;
delaynms(2);
}
/***************************
主函数
****************************/
void main(void)
{
TMOD=0x01; //定时器0工作在方式1
ET0=1;
EA=1;
TH0=(65536-50000)/256; //对TH0 TL0赋值
TL0=(65536-50000)%256; //使定时器0.05秒中断一次
SDA = 1; // SDA=1,SCL=1,使主从设备处于空闲状态
SCL = 1;
sec=ReadSet(2);//读出保存的数据赋于sec
TR0=1; //开始计时
while(1)
{
display();
if(write==1) //判断计时器是否计时一秒
{
write=0; //清零
WriteSet(2,sec); //在24c08的地址2中写入数据sec
}
if(K7==0){
delaynms(10);
if(K7==0){ ///按键消抖
sec=0;
}
}
}
}
void t0(void) interrupt 1 using 0 //定时中断服务函数
{ TR0=0;
TH0=(65536-50000)/256; //对TH0 TL0赋值
TL0=(65536-50000)%256; //重装计数初值
count++; //每过50ms tcnt加一
if(count==20) //计满20次(1秒)时
{
count=0; //重新再计
sec++;
write=1; //1秒写一次24C08
if(sec==100) //定时100秒,在从零开始计时
{sec=0;}
}
TR0=1;
} |
|