用MEGA88的I/O口模拟I2C读写PCF8563的程序,已经调试成功.送给需要的朋友!
//该程序LCD用的PORTB0,1,2,3口;//模拟I2C口是SDA为PORTD6.SCL为PORTD5
#include<avr/io.h>
#include<avr/signal.h>
#include<avr/interrupt.h>
#define uint unsigned int
#define uchar unsigned char
#define PCF8536_ADDR 0XA2
#define TW_WRITE0
#define TW_READ1
uchar g_aTimeBuf={0,0x02,0x50,0x44,0x10,0x12,0x05,0x01,0x07,0x45,0x80,0x80,0x80,0x00,0x00,0x00};
//写入2007年01月12日,10:44:50,分钟报警功能有效(45)其他功能无效
uchar g_aTimeBin;//时钟/日历bcd格式缓冲区
/***********************端口初始化************************/
//*******PC4=SDA;*******PC5=SCL
//用PC4、5来模拟
void port_init(void)
{
DDRC=_BV(PC4)|_BV(PC5);
PORTC=0X00;
PORTC|=_BV(PC4)|_BV(PC5);
DDRD=0x00;//中断入口置为输入
PORTD=0xff;//使能内部上拉电阻
}
/***************************中断初始化***********************/
//如果要用到PCF8563的中断功能,只需要把PCF8563的INT/引脚接到单片机的外部中断0或1
//在这里我接的是中断1口
void INT_init(void)
{
EICRA=0x00;//外部中断1低电平触发
EIMSK=0x02;//使能外部中断1
}
/*************PCF8536 操作********************开始**************/
//*******PC4=SDA;*******PC5=SCL
//DDRC _SFR_IO8 (0x07)
//PORTC _SFR_IO8 (0x08)
void DELAY_us(void)//延时5US
{
asm volatile("nop"::);
asm volatile("nop"::);
asm volatile("nop"::);
asm volatile("nop"::);
asm volatile("nop"::);
}
void i2c_start(void)//起始信号
{
asm volatile ("cbi 0x08,5"::);
asm volatile("nop"::);//延时1US
asm volatile ("sbi 0x08,5"::);
asm volatile("nop"::);//延时1US
asm volatile ("sbi 0x08,4"::);
DELAY_us();
asm volatile ("cbi 0x08,4"::);
DELAY_us();
asm volatile ("cbi 0x08,5"::);
asm volatile("nop"::);//延时1US
}//起始信号后SCL,SDA都为低电平
void i2c_stop(void)//停止信号
{
asm volatile ("cbi 0x08,5"::);
asm volatile("nop"::);//延时1US
asm volatile ("cbi 0x08,4"::);
DELAY_us();
asm volatile ("sbi 0x08,5"::);
DELAY_us();
asm volatile ("sbi 0x08,4"::);
}//停止信号后SCL,SDA都为高电平
void i2c_ack(uchar ack_data) //读PCF8563时用的
{
//asm volatile ("cbi 0x08,5"::);
//asm volatile("nop"::);//延时1US
if(ack_data==0)
asm volatile ("cbi 0x08,4"::);//应答拉低SDA
else
asm volatile ("sbi 0x08,4"::);//不应答拉高SDA
DELAY_us();
asm volatile ("sbi 0x08,5"::);
DELAY_us();
asm volatile ("cbi 0x08,5"::);
asm volatile("nop"::);//延时1US
}
/****************************************************************/
uchar i2c_writebyte(uchar c)
{//将字节发送出去,可以是地址,也可以是数据,发完后等待应答并返回
uchar ack_flag;
for(uchar i=0;i<8;i++)
{
if((c<<i)&0x80)
asm volatile ("sbi 0x08,4"::);
else
asm volatile ("cbi 0x08,4"::);
DELAY_us();
asm volatile ("sbi 0x08,5"::); //置时钟线为高,通知被控器开始接收数据位
DELAY_us();//保证时钟高电平周期大于4μs
asm volatile ("cbi 0x08,5"::);
}
DELAY_us();
asm volatile ("cbi 0x08,4"::);
asm volatile ("cbi 0x07,4"::);//SDA引脚位变为输入
asm volatile("nop"::);
asm volatile ("sbi 0x08,5"::);
DELAY_us();
DELAY_us();
if(PINC&0x10)//判断是否接收到应答信号
ack_flag=0;
else
ack_flag=1;//有应答信号
asm volatile ("sbi 0x07,4"::);//SDA引脚位变为输出
asm volatile("nop"::);
asm volatile ("cbi 0x08,5"::);
asm volatile("nop"::);
return(ack_flag);
}
uchar i2c_readbyte(void) //读一个字节
{
uchar get_data=0;
asm volatile ("cbi 0x07,4"::);//SDA引脚位变为输入
for(uchar i=0;i<8;i++)
{
asm volatile("nop"::);
asm volatile ("cbi 0x08,5"::);//置时钟线为低,准备接收数据位
DELAY_us();//时钟低电平周期5μs;
asm volatile ("sbi 0x08,5"::); //置时钟线为高使数据线上数据有效
get_data<<=1;
if(PINC&0x10)//如果SDA数据线为高电平
get_data++;
asm volatile("nop"::);
asm volatile("nop"::);
}
asm volatile ("cbi 0x08,5"::);
asm volatile ("sbi 0x07,4"::);//SDA引脚位变为输出
asm volatile("nop"::);
return(get_data);
}
//当对PCF8563连续读的时候最后一个字节不需要主接受器应答
/********************************************************************/
uchar write_8563(uchar addr,uchar *buf,uchar len)//对PCF8536 连续的写操作
{
uchar i;
i2c_start();//起始信号
i2c_writebyte(PCF8536_ADDR|TW_WRITE);
i2c_writebyte(addr);//write address
for(i=0;i<len;i++)
i2c_writebyte(buf);
i2c_stop();
}
uchar read_8563(uchar addr,uchar *buf,uchar len)//对PCF8536 连续的读操作
{
uchar i;
i2c_start();
i2c_writebyte(PCF8536_ADDR|TW_WRITE);
i2c_writebyte(addr);//write word address
i2c_start();
i2c_writebyte(PCF8536_ADDR|TW_READ);
for(i=0;i<len-1;i++)
{
buf=i2c_readbyte();
i2c_ack(0);
}
buf=i2c_readbyte();
i2c_ack(1);
i2c_stop();
}
void PCF8563_CAF(void)//在中断函数里清除8563AF标志位
{
uchar TimeBuf;
read_8563(0x01, TimeBuf,1);
TimeBuf&=0x17;
write_8563(0x01,TimeBuf,1);//清除AF
}
/*-------------------------------------------------------------------------
功能:将读出的时间数据的无关位屏蔽掉
说明:PCF8563时钟寄存器的有些无关位的状态是不定的,所以应该将无效位屏蔽掉
---------------------------------------------------------------------------*/
void Data_ajust(void) //时间无效位屏蔽
{
g_aTimeBin=g_aTimeBin&0x7f;//秒时间无效位的屏蔽
g_aTimeBin=g_aTimeBin&0x7f;//分钟时间无效位的屏蔽
g_aTimeBin=g_aTimeBin&0x3f;//小时时间无效位的屏蔽
g_aTimeBin=g_aTimeBin&0x3f;//日时间无效位的屏蔽
g_aTimeBin=g_aTimeBin&0x07;//星期时间无效位的屏蔽
g_aTimeBin=g_aTimeBin&0x1f;//月/世纪时间无效位的屏蔽,如果最高位0,世纪为21,
g_aTimeBin=g_aTimeBin&0xff;//年时间无效位的屏蔽
} 应该鼓励一下 呵呵很好,谢谢! 有硬接口不用? 顶! mark 留个记号先! 向LZ学习,觉的编译器inline assembly这个功能很好!谢谢。。。 请教楼主一下 关闭闹铃的操作使用您的这种AF的方法 还是把闹铃位都屏蔽掉? 留个记号先!
页:
[1]