stc15f204单片机使用ds1302调试

使用stc单片机的准IO口模式,驱动能力太弱,导致操作1302不正常,逻辑分析仪看到是写给1302的地址就出错了,但正常和错误交替出现,非常奇怪,后来把IO配置为推挽输出后,可以稳定读写1302,附程序:

一部分程序操作也是在网上下载的,使用下面的程序可以正常读写ds1302.


#include "ds1302.h"


#define ds1302_sec_add 0x80 //秒数据地址
#define ds1302_min_add 0x82 //分数据地址
#define ds1302_hr_add 0x84 //时数据地址
#define ds1302_date_add 0x86 //日数据地址
#define ds1302_month_add 0x88 //月数据地址
#define ds1302_day_add 0x8a //星期数据地址
#define ds1302_year_add 0x8c //年数据地址
#define ds1302_control_add 0x8e //控制数据地址
#define ds1302_charger_add 0x90


sbit CS = P1^3;
sbit SCLK = P1^4;
sbit SDA = P1^5;


BYTE ds1302_read(BYTE cmd);
void ds1302_write(BYTE cmd,BYTE dat);
BYTE bcd_to_dec(BYTE value);
BYTE dec_to_bcd(BYTE value);


void ds1302_init(void)
{
SDA = 0;
SCLK = 0;
CS = 0;
}


BYTE get_curr_hour(void)
{
return bcd_to_dec(ds1302_read(ds1302_hr_add));
}


BYTE get_curr_minute(void)
{
return  bcd_to_dec(ds1302_read(ds1302_min_add));
}


void save_curr_hour(BYTE value)
{
value = dec_to_bcd(value);
EA = 0;
ds1302_write(ds1302_control_add, 0x00); //关闭写保护
ds1302_write(ds1302_sec_add,0x80);   //暂停
ds1302_write(ds1302_hr_add, value);
ds1302_write(ds1302_sec_add,0x00);   //开启
ds1302_write(ds1302_control_add, 0x80); //打开写保护
EA = 1;
}


void save_curr_minute(BYTE value)
{
value = dec_to_bcd(value);
ds1302_write(ds1302_control_add, 0x00); //关闭写保护
ds1302_write(ds1302_sec_add,0x80);   //暂停
ds1302_write(ds1302_min_add, value);
ds1302_write(ds1302_sec_add,0x00);   //开启
ds1302_write(ds1302_control_add, 0x80); //打开写保护
}


void ds1302_write(BYTE cmd,BYTE dat)
{
BYTE dattmp = 0;
BYTE i = 0;

P1M0 |= 0x20;  //1 << 5 //一定要配置为强上啦输出
P1M1 &= 0xdf;  // ~(1 << 5)


CS=1;// 初始CE置为1 ,传输开始
//ds1302_write_byte(cmd);//传输命令字,要写入的时间日历地址
//ds1302_write_byte(dat);// 写入要修改的时间 /日期
dattmp = cmd;
for(i = 0; i < 8; ++i)// 开始传输8个字节的数据
{
if(dattmp & 0x01){ // 取最低位,注意ds1302的数据和地址都是从最低位开始传输的
SDA = 1;
}else{
SDA = 0;
}
delay2us();
SCLK=1; //时钟线拉高,制造上升沿,SDA的数据被传输
delay2us();
SCLK=0; //时钟线拉低,为下一个上升沿做准备
dattmp >>= 1; // 数据右移一位,准备传输下一位数据
}
dattmp = dat;
for(i = 0; i < 8; ++i)// 开始传输8个字节的数据
{
if(dattmp & 0x01){ // 取最低位,注意ds1302的数据和地址都是从最低位开始传输的
SDA = 1;
}else{
SDA = 0;
}
delay2us();
SCLK=1; //时钟线拉高,制造上升沿,SDA的数据被传输
delay2us();
SCLK=0; //时钟线拉低,为下一个上升沿做准备
dattmp >>= 1; // 数据右移一位,准备传输下一位数据
}
CS=0;// 读取结束,CE置为0,结束数据的传输
//SCLK=1;// 时钟线拉高  这个线不能拉高,否则出错
SDA = 1;
P1M1 &= 0xdf;
P1M0 &= 0xdf;
}


BYTE ds1302_read(BYTE cmd)
{
BYTE dat = 0;
BYTE cmdtmp = cmd;
BYTE dattmp = 0;
BYTE i = 0;
P1M1 &= 0xdf;//要先把io配置为强上拉输出
P1M0 |= 0x20;
CS=1; // 初始CE置为1 ,传输开始
cmdtmp |= 0x01;//读命令的最低位固定为1
dattmp = cmdtmp;
for(i = 0; i < 8; ++i)// 开始传输8个字节的数据
{
if(dattmp & 0x01){ // 取最低位,注意ds1302的数据和地址都是从最低位开始传输的
SDA = 1;
}else{
SDA = 0;
}
delay2us();
SCLK=1; //时钟线拉高,制造上升沿,SDA的数据被传输
delay2us();
SCLK=0; //时钟线拉低,为下一个上升沿做准备
dattmp >>= 1; // 数据右移一位,准备传输下一位数据
}
//
P1M1 &= 0xdf; //准io口方式
P1M0 &= 0xdf;
SDA = 1;
delay2us();
for(i=0;i<8;i++)
{
dat >>= 1; // 要返回的数据右移一位
 
if(SDA == 1){ //当数据线为高时,证明该位数据为1
dat|=0x80; // 要传输数据的当前值置为1,若不是 ,则为0
}
SCLK=1; //拉高时钟线
delay2us();
SCLK=0; //制造下降沿
SDA = 1;
delay2us();
}
CS=0; // 读取结束,CE置为0,结束数据的传输
//SCLK=1; // 时钟线拉高 ,这个线不能拉高,否则出错
return dat;// 返回得到的时间/ 日期
}


BYTE bcd_to_dec(BYTE value)
{
BYTE tmp = 0;
tmp = ((value & 0xf0) >> 4) * 10 + (value & 0x0f);
return tmp;
}


BYTE dec_to_bcd(BYTE value)
{
BYTE tmp = 0;
tmp = ((value / 10) << 4) & 0xf0;
tmp |= (value % 10) & 0x0f;
return tmp;
}

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