新发布一个用模拟I2C操作的DS3231(时钟芯片)完整程序
自己花了两天的时间来调试一个时钟芯片:DS3231,刚开始参考高手写的用硬件I2C来操作DS3231较简单然后自己模仿硬件I2C的工作原理写了一个用模拟I2C来操作的程序,经多次调试之后终于成功.
由于本网站的DS3231程序都不完整,现发布一个完整程序,希望对大家有用.
/**********************************
晶振:11.0592M
模拟I2C总线操作DS3231
2007/11/08
fjh
/**********************************/
#include <iom128v.h>
#include <macros.h>
#include "lcd.c"
#define uchar unsigned char
#define uintunsigned int
#define SCL_HPORTD|=(1<<0)
#define SCL_LPORTD&=~(1<<0)
#define SDA_HPORTD|=(1<<1)
#define SDA_LPORTD&=~(1<<1)
uchar year,month,date,hour,minute,second;
/******************应用程序********************/
void timer1_init(void);
uchar BCD2HEX(uchar val);
uchar B_BCD(uchar val);
void delay(uchar us);
void Start(void);
void Stop(void);
void SendByte(uchar Dat);
uchar ReceiveByte(uchar b);
void I2cByteWrite(uchar device,uint addr,uchar bytedata);
uchar I2cByteRead(uchar device,uint addr);
void get_show_time(void);
/**********************************************/
void port_init(void)
{
PORTA = 0xff;
DDRA= 0xff;
PORTB = 0xff;
DDRB= 0xff;
PORTC = 0xff;
DDRC= 0xff;
PORTD = 0x00;
DDRD= 0xff;
PORTE = 0xff;
DDRE= 0xff;
PORTF = 0xff;
DDRF= 0xff;
PORTG = 0x00;
DDRG= 0x00;
}
// actual value:1.000Sec (0.0%)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1H = 0xD5; //setup
TCNT1L = 0xD1;
OCR1AH = 0x2A;
OCR1AL = 0x2F;
OCR1BH = 0x2A;
OCR1BL = 0x2F;
OCR1CH = 0x2A;
OCR1CL = 0x2F;
ICR1H= 0x2A;
ICR1L= 0x2F;
TCCR1A = 0x00;
TCCR1B = 0x05; //start Timer
TIMSK= 0x04; //timer interrupt sources
}
#pragma interrupt_handler timer1_ovf_isr:15
void timer1_ovf_isr(void)
{
//TIMER1 has overflowed
TCNT1H = 0xD5; //reload counter high value
TCNT1L = 0xD1; //reload counter low value
PORTF=~PORTF;
get_show_time();
}
uchar BCD2HEX(uchar val) //BCD转换为Byte
{
unsigned char i;
i= val&0x0f;
val >>= 4;
val &= 0x0f;
val *= 10;
i += val;
return i;
}
uchar B_BCD(uchar val)//B码转换为BCD码
{
uchar i,j,k;
i=val/10;
j=val%10;
k=j+(i<<4);
return k;
}
void delay(uchar us)
{
while(us--);
}
/************************START***************************/
void Start(void)
{
SDA_H;
delay(5);
SCL_H;
delay(5);
SDA_L;
delay(5);
}
/********************************************************/
/************************STOP****************************/
void Stop(void)
{
SDA_L;
delay(5);
SCL_H;
delay(5);
SDA_H;
delay(5);
}
/********************************************************/
/***********向I2C总线发送一个字节+接收一个ACK************/
void SendByte(uchar Dat)
{
uchar i=0;
uchar T_Data=0;
DDRD|=(1<<1);//输出
SCL_L;
delay(10);
T_Data=Dat;
for(i=0;i<8;i++)
{
if(T_Data&0x80)
SDA_H;
else
SDA_L;
delay(5);
SCL_L;
delay(5);
SCL_H;
delay(5);
T_Data=T_Data<<1;
SCL_L;
delay(5);
}
SDA_H;//释放总线
delay(5);
SCL_L; /*********************/
delay(5);//接收一个ACK,不做处理
SCL_H; /*********************/
delay(5);
SCL_L;
}
/********************************************************/
/**********从I2C总线上读取一个字节+发送一个ACK***********/
uchar ReceiveByte(uchar b)
{
uchar i;
uchar temp;
uchar Dat=0;
/*
SDA_H;
delay(5);
SCL_L;
delay(5);
*/
DDRD&=~(1<<1);//输入
for(i=0;i<8;i++)
{
SCL_H;
delay(5);
Dat=Dat<<1;
delay(5);
temp=PIND;
if(temp&0x02)
Dat|=0x01;
else
Dat|=0x00;
delay(5);
SCL_L;
delay(5);
}
DDRD|=(1<<1);//输出
if(b)//每收一个数后发送ACK或nACK
SDA_H;
else
SDA_L;
delay(5);
SCL_H;
delay(5);
SCL_L;
delay(5);
SDA_H; //释放总线
delay(100);
return Dat;
}
/****************************************************/
/***********将一个字节写入DS3231指定的地址***********/
void I2cByteWrite(uchar device,uint addr,uchar bytedata)
{
Start();
delay(5);
SendByte(device);
delay(5);
SendByte(addr);
delay(5);
SendByte(bytedata);
delay(5);
Stop();
}
/****************************************************/
/************从DS3231指定的地址读一个字节************/
uchar I2cByteRead(uchar device,uint addr)
{
uchar Dat=0;
Start();
SendByte(device);
delay(5);
SendByte(addr);
delay(5);
Start();//Restart
SendByte(0xd1);//读数
delay(5);
Dat=ReceiveByte(1);//只接收一个字节,所以发nACK
Stop();
return Dat;
}
/***************************************************/
/*********************读取时间**********************/
void Readtime(void)
{
year=I2cByteRead(0xd0,0x06);//年
month=I2cByteRead(0xd0,0x05); //月
date=I2cByteRead(0xd0,0x04);//日
hour=I2cByteRead(0xd0,0x02);//时
minute=I2cByteRead(0xd0,0x01);//分
second=I2cByteRead(0xd0,0x00);//秒
}
/***************************************************/
/****************修改时间,BCD码输入*****************/
void ModifyTime(uchar yea,uchar mon,uchar da,uchar hou,uchar min,uchar sec)
{
uchar temp=0;
temp=B_BCD(yea);
I2cByteWrite(0xD0,0x06,temp);//修改年
temp=B_BCD(mon);
I2cByteWrite(0xD0,0x05,temp);//修改月
temp=B_BCD(da);
I2cByteWrite(0xD0,0x04,temp);//修改日
temp=B_BCD(hou);
I2cByteWrite(0xD0,0x02,temp);//修改时
temp=B_BCD(min);
I2cByteWrite(0xD0,0x01,temp);//修改分
temp=B_BCD(sec);
I2cByteWrite(0xD0,0x00,temp);//修改秒
}
/****************************************************/
/****************读取时间 计算 并显示****************/
void get_show_time(void)
{
uchar temp1,temp2,a=0,b=0;
temp1=I2cByteRead(0xd0,0x06);//年
temp2=BCD2HEX(temp1);
a=temp2/10;
b=temp2-a*10;
disp_two_char (0x81,tab,tab);
disp_one_word(0x82,"年");
temp1=I2cByteRead(0xd0,0x05);//月
temp2=BCD2HEX(temp1);
a=temp2/10;
b=temp2-a*10;
disp_two_char (0x83,tab,tab);
disp_one_word(0x84,"月");
temp1=I2cByteRead(0xd0,0x04);//日
temp2=BCD2HEX(temp1);
a=temp2/10;
b=temp2-a*10;
disp_two_char (0x85,tab,tab);
disp_one_word(0x86,"日");
temp1=I2cByteRead(0xd0,0x02);//时 24小时制
temp1&=0x3f;
temp2=BCD2HEX(temp1);
a=temp2/10;
b=temp2-a*10;
disp_two_char (0x91,tab,tab);
disp_one_word(0x92,"时");
temp1=I2cByteRead(0xd0,0x01);//分
temp2=BCD2HEX(temp1);
a=temp2/10;
b=temp2-a*10;
disp_two_char (0x93,tab,tab);
disp_one_word(0x94,"分");
temp1=I2cByteRead(0xd0,0x00);//秒
temp2=BCD2HEX(temp1);
a=temp2/10;
b=temp2-a*10;
disp_two_char (0x95,tab,tab);
disp_one_word(0x96,"秒");
}
/****************************************************/
/*******************MAIN函数*************************/
void main()
{
CLI();
port_init();
init_lcd ();
I2cByteWrite(0xD0,0x0e,0);
I2cByteWrite(0xD0,0x0f,0);
ModifyTime(7,11,20,12,59,00);//初始化时钟,2007/11/20,12/59/00
//小时采用24小时制
timer1_init();
SEI();
lat_disp (0x00,0x00);//显示点阵
while(1)
{
}
} 请问有哪位大侠用过DS3231,给我指点一下,为什么我从温度寄存器里读出来的数值循环递增
我认为温度值应该是不变的才对啊.谢谢! 不错,先行用用,之前用CV编过一个,不管用 我移制到STM32 出现不能读出的问题,大家看看那里的问题
#include "stm32f10x_lib.h"
extern void Delay(vu32 nCount) ; //调用外部函数体函数
extern void ds3231_chang_OUT(void ) ; //
extern void ds3231_chang_IN(void ) ;
extern void LCD_init(void) ; //调用外部函数体函数
extern void LCD_set_xy(unsigned char x, unsigned char y) ; //调用外部函数体函数
extern void xianshishuzi(unsigned char X,unsigned char Y, unsigned int s) ; //调用外部函数体函数
extern void xianshishuzi3(unsigned char X,unsigned char Y, unsigned int s) ; //调用外部函数体函数
extern LCD_Write_char_string(unsigned char X,unsigned char Y, unsigned char *s) ;//调用外部函数体函数
/********************************************************/
#define SCL_H (GPIO_SetBits(GPIOA, GPIO_Pin_0))
#define SCL_L (GPIO_ResetBits(GPIOA, GPIO_Pin_0))
#define SDA_H (GPIO_SetBits(GPIOA, GPIO_Pin_1))
#define SDA_L (GPIO_ResetBits(GPIOA, GPIO_Pin_1))
unsigned char year,month,date,hour,minute,second; //读取时间参数
unsigned char BCD2HEX(unsigned char val) //BCD转换为Byte
{
unsigned char i;
i= val&0x0f;
val>>= 4;
val &= 0x0f;
val *= 10;
i += val;
return i;
}
unsigned char B_BCD(unsigned char val)//B码转换为BCD码
{
unsigned char i,j,k;
i=val/10;
j=val%10;
k=j+(i<<4);
return k;
}
void delay1(unsigned char us)
{
unsigned int i=200;
while(us--)
{
while(i)
{
i--;
}
}
}
/************************START***************************/
void Start(void)
{
SCL_L;
delay1(5);
SDA_H;
delay1(5);
SCL_H;
delay1(5);
SDA_L;
delay1(5);
}
/********************************************************/
/************************STOP****************************/
void Stop(void)
{
SCL_L;
delay1(5);
SDA_L;
delay1(5);
SCL_H;
delay1(10);
SDA_H;
delay1(5);
}
/********************************************************/
/********************************************************/
/***********向I2C总线发送一个字节+接收一个ACK************/
void SendByte(unsigned char Dat)
{
unsigned char i=0;
unsigned char T_Data=0;
SCL_L;
delay1(10);
T_Data=Dat;
for(i=0;i<8;i++)
{
if(T_Data&0x80)
SDA_H;
else
SDA_L;
delay1(5);
SCL_L;
delay1(5);
SCL_H;
delay1(5);
T_Data=T_Data<<1;
SCL_L;
delay1(5);
}
SDA_H;//释放总线
delay1(5);
SCL_L; /*********************/
delay1(5);//接收一个ACK,不做处理
SCL_H; /*********************/
delay1(5);
SCL_L;
}
/********************************************************/
/**********从I2C总线上读取一个字节+发送一个ACK***********/
unsigned char ReceiveByte(unsigned char b)
{
unsigned char i;
unsigned char Dat=0;
ds3231_chang_IN();
SCL_L;
delay1(10);
for(i=0;i<8;i++)
{
SCL_H;
delay1(5);
Dat=Dat<<1;
delay1(5);
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1)==1)
Dat|=0x01;
else
Dat|=0x00;
delay1(5);
SCL_L;
delay1(5);
}
ds3231_chang_OUT();
if(b)//每收一个数后发送ACK或nACK
SDA_H;
else
SDA_L;
delay1(5);
SCL_H;
delay1(5);
SCL_L;
delay1(5);
SDA_H; //释放总线
delay1(100);
return Dat;
}
/***********将一个字节写入DS3231指定的地址***********/
void I2cByteWrite(unsigned char device,unsigned int addr,unsigned char bytedata)
{
Start();
delay1(5);
SendByte(device);
delay1(5);
SendByte(addr);
delay1(5);
SendByte(bytedata);
delay1(5);
Stop();
}
/****************************************************/
/************从DS3231指定的地址读一个字节************/
unsigned char I2cByteRead(unsigned char device,unsigned int addr)
{
unsigned char Dat=0;
Start();
SendByte(device);
delay1(5);
SendByte(addr);
delay1(5);
Start();//Restart
SendByte(0xd1);//读数
delay1(5);
Dat=ReceiveByte(1);//只接收一个字节,所以发nACK
Stop();
return Dat;
}
/***************************************************/
/*********************读取时间**********************/
void Readtime(void)
{
year=I2cByteRead(0xd0,0x06); //年
month=I2cByteRead(0xd0,0x05); //月
date=I2cByteRead(0xd0,0x04); //日
hour=I2cByteRead(0xd0,0x02); //时
minute=I2cByteRead(0xd0,0x01);//分
second=I2cByteRead(0xd0,0x00);//秒
}
/***************************************************/
/***************************************************/
/****************修改时间,BCD码输入*****************/
void ModifyTime(unsigned char yea,unsigned char mon,unsigned char da,unsigned char hou,unsigned char min,unsigned char sec)
{
unsigned char temp=0;
temp=B_BCD(yea);
I2cByteWrite(0xD0,0x06,temp);//修改年
temp=B_BCD(mon);
I2cByteWrite(0xD0,0x05,temp);//修改月
temp=B_BCD(da);
I2cByteWrite(0xD0,0x04,temp);//修改日
temp=B_BCD(hou);
I2cByteWrite(0xD0,0x02,temp);//修改时
temp=B_BCD(min);
I2cByteWrite(0xD0,0x01,temp);//修改分
temp=B_BCD(sec);
I2cByteWrite(0xD0,0x00,temp);//修改秒
}
/****************************************************/
/****************读取时间 计算 并显示****************/
void get_show_time(void)
{
unsigned char temp1,temp2 ;
temp1=I2cByteRead(0xd0,0x06); //年
temp2=BCD2HEX(temp1);
xianshishuzi(2,0,temp2);
/*temp1=I2cByteRead(0xd0,0x05); //月
temp2=BCD2HEX(temp1);
temp1=I2cByteRead(0xd0,0x04); //日
temp2=BCD2HEX(temp1);
temp1=I2cByteRead(0xd0,0x02); //时 24小时制
temp1&=0x3f;
temp2=BCD2HEX(temp1);
temp1=I2cByteRead(0xd0,0x01); //分
temp2=BCD2HEX(temp1);
temp1=I2cByteRead(0xd0,0x00); //秒
temp2=BCD2HEX(temp1);*/
}
/****************************************************/ 我有一个基于fpga的时钟程序,怎么让他来提取这个芯片的时间呢,谢谢 关于3231的闹钟如何用程序控制,那位DX能提供一下程序? nuibility 我用的C8051的I2C例程,折腾了大半天没搞定,与SD2403API通讯,无耐也只好用模拟的I/O口操作,1个多小时就调通了。 例程的中断方式实在不适合有特殊要求的操作方式。 我想用单片机和ds3231进行通信,目前刚刚开始着手,大家多提供一些例程和电路图最好拉。 单片机与ds3231sn通信搞定,按照datasheet一步一步来,没问题 学习,我也在写ARM和DS3231的通讯程序 mark一下,正在调128+3231, mark mark mark mark MARK 回复【楼主位】fjh120
-----------------------------------------------------------------------
mark 记号 楼主的3231计时准确吗?我以前也做过一个,但是时间走时误差很大,不知道是什么原因 正在研究这个,先收藏,慢慢研究下 哥们 stm32上有I2C总线可以不用模拟的I2C吧是不是可以直接调用库里的函数来实现,不知道哥们有没有相关的程序可以参考一下。谢谢!!!予人玫瑰手有余香。 非常感谢,正需要! 你好,你这程序还是不完整啊,disp_two_char ()lcd.c在哪里? 学习一下.... 参考下楼主程序,我用的STC单片机。。。 mark一下,正在调128+3231, 哎用STM8没调通 不知楼主能帮忙指点下不呢 {:cry:} 哎m8没调通 不知楼主能帮忙指点下不呢
页:
[1]