这是我写的一个程序,附上原理图。需要实现的是PIC16F72模拟I2C,通过实时芯片PCF8563LCD实时显示时间。结果是LCD能显示初始化,但用PROTUES仿真显示时间的时候无论怎么设置初始化的时间上排(年月日)一直是2000-01-01,下排一直是00:00:00,并且时间不走(也就是时钟不能正常初始化并且不走) 大家帮我看看错在哪里? 不知道是I2C有问题 还是PCF8563本身出错了?? 请大家多多指教 谢谢了呀
#include<pic.h>
//#include <htc.h>
#include <pic1672.h>
//#include <time.h>
__CONFIG(0x3FF2); //芯片配置字:看门狗关,上电延时 开,低电压复位开,不加密,4M晶体HX振荡
//定义接口
#define E RC6
#define RW RC7
#define RS RC5
#define uchar unsigned char
#define uint unsigned int
#define SCL TRISA3
#define SDA TRISA1 //I2C
//#define up RC1
//#define down RC2
//#define set RC3 //按键
#define CLOCK_DEVNO 0xA2 //8563地址
#define CLOCK_REG 2 //8563内部时间寄存器位置
const uchar wlcome[16]={" welcome! "};
const uchar Enter[16]={" Enter"};
uchar timedata[7]={0x01,0x08,0x00,0x00,0x02,0x10,0x10}; //预设时间设置表 2010年,1月6日,星期1,12点
bit ack;
bit ErrorBit; //I2C 错误返回值
uchar tpmtdata = 36; //温度设置值预设36度
uchar tep;
uchar hour,min,sec,date,week,month, year;
uchar dis_buf1[16]={" 2010-11-24 "}; //lcd上排显示缓冲区
uchar dis_buf2[16]={" 85'C 12:12:12"}; //lcd下排显示缓冲区
//****************************************************
// DELAY
//******************************************************
void delay_1ms(void) //1ms延时函数
{
uint i;
for (i=0;i<1000;i++);
}
void delay_nms(uint n) //N ms延时函数
{
uint i=0;
for (i=0;i<n;i++);
delay_1ms();
}
void delay_1us(void) //1us延时函数
{
asm("nop");
}
void delay_nus(uint n) //N us延时函数
{
uint i=0;
for (i=0;i<n;i++);
delay_1us();
}
//查询LCD是否忙
void Busy ()
{
uchar FLAG;
FLAG=0x00;
RS=0;
RW=1;
while(FLAG&0x80==0x80)
{
PORTB =0xFF; //设置B口为输入
E=1; //E=1
FLAG=PORTB;
E=0;
}
}
///////////////////////LCD//////////////////////////
//LCD写命令函数
void LCD_write_cmd(uchar command)
{
Busy(); //判断液晶是否为忙
RW=0;
RS=0; //为0写命令,为1写数据
PORTB=command;
E=1;
E=0;
}
//LCD写数据函数
void LCD_write_data(uchar data)
{
Busy(); //判断液晶是否为忙
RW=0;
RS=1; //为0写命令,为1写数据
PORTB=data;
E=1;
E=0;
}
//LCD写字符串
void LCD_write_s(uchar *s)
{
while(*s>0)
{
LCD_write_data(*s);
s++;
}
}
//LCD写入显示数据函数
void disp_lcd(uchar addr,uchar *temp1)
{
uchar i;
LCD_write_cmd(addr);
delay_nms(1500);
for(i=0;i<16;i++)
{
LCD_write_data(temp1
);
delay_nms(1500);
}
}
//LCD初始化函数
void LCD_init(void)
{
char i;
for(i=3;i>0;i--)
{
PORTB=0x30;
RS=0;
RW=0;
E=1;
E=0;
delay_nms(1500);
}
PORTB=0x38;
RS=0;
RW=0;
E=1;
E=0;
delay_nms(1500);
}
//LCD显示器复位函数
void LCD_reset(void)
{
delay_nms(150); //启动时必须的延时
LCD_write_cmd(0x38); //双行显示,字型使用5*7点阵
delay_nms(1500);
LCD_write_cmd(0x0e); //出现光标,不闪烁
delay_nms(1500);
LCD_write_cmd(0x06); //每次向右移一位,显示屏不移动
delay_nms(1500);
LCD_write_cmd(0x01); //清除LCD显示屏幕
delay_nms(1500);
}
/**********************************************
I2C
**************************************************/
void I2C_Init()
{
SCL = 1;
delay_nus(5) ;
SDA = 1;
delay_nus(5) ;
}
void I2C_Start(void)
{
SDA=1; /*发送起始条件的数据信号*/
delay_nus(5) ;
SCL=1;
delay_nus(5) ; /*起始条件建立时间大于4.7us,延时*/
SDA=0; /*发送起始信号*/
delay_nus(5) ; /* 起始条件锁定时间大于4μs*/
SCL=0; /*钳住I2C总线,准备发送或接收数据 */
delay_nus(5) ;
}
void I2C_Stop(void)
{
SDA=0; /*发送结束条件的数据信号*/
delay_nus(5); /*发送结束条件的时钟信号*/
SCL=1; /*结束条件建立时间大于4us*/
delay_nus(5);
SDA=1; /*发送I2C总线结束信号*/
delay_nus(8);
}
//应答信号,在第九个时钟周期把SDA拉低表示应答信号
void I2C_Ack(void)
{
uchar i;
SCL=1;
delay_nus(5);
SDA=1;
delay_nus(5);
if((SDA==1)&&(i<100))
i++;
SCL=0;
delay_nus(5);
}
//没有应答信号,
void I2C_NoAck(void)
{
SDA=1; //起始信号//
delay_nus(5);
SCL=1;
delay_nus(5);
SCL=0;
delay_nus(5);
}
bit I2C_TestAck() //应答位检测子函数
{
SCL=1;
delay_nus(5);
ErrorBit=SDA; //SDA=1非应答
SCL=0;
delay_nus(5);
return(ErrorBit);
}
void I2C_Write8Bit(uchar input) //发送一个字节子函数
{
uchar i;
for(i=0;i<8;i++)
{
if((input<<i) & 0x80)
SDA=1; //判断发送位
else SDA=0;
SCL=1;
delay_nus(5);
SCL=0;
delay_nus(8);
}
//SSPBUF=input;
// do{;}
//while (SSPIF==0);
//SSPIF=0;
}
////24CO2B写
void I2C_Write(uchar *buffer,uint address,uchar number,uchar devicNO )//参数:buffer为写入数据缓冲区指针,address为写入数据地址, len为写入数据长度,devicNO为I2C设备的访问地址
{
I2C_Start();
I2C_Write8Bit(devicNO);
I2C_TestAck();
I2C_Write8Bit(address);
I2C_TestAck();
for(;number!=0;number--)
{
I2C_Write8Bit(*buffer);
I2C_TestAck();
buffer++;
}
I2C_Ack(); //应答
I2C_Stop();
delay_nms(5);
}
//
uchar I2C_Read8Bit() //接收1个字节子函数
{
uchar temp,rbyte=0;
SCL=0; //读入数据
delay_nus(5);
SDA=1;
delay_nus(5);
for(temp=8;temp!=0;temp--)
{
SCL=1;
delay_nus(5);
rbyte = ( rbyte << 1 );
rbyte = ( rbyte | ((uchar)(SDA)) );
SCL=0;
delay_nus(5);
}
delay_nus(8);
return(rbyte);
//SDA=0;
//do{;}
//while(SSPIF==0);
// SSPIF=0;
// return SSPBUF;
}
//////24CO2B读
void I2C_Read(uchar *buffer,uint address,uchar bytes,uchar devicNO)//buffer为读出数据缓冲区指针,address为读数据起始地址, len为读出数据长度,devicNO为I2C设备的访问地址
{
I2C_Start();
I2C_Write8Bit(devicNO);
I2C_TestAck();
I2C_Write8Bit(address);
I2C_TestAck();
I2C_Start();
I2C_Write8Bit(devicNO+1);
I2C_TestAck();
while(bytes!=1)
{
*buffer=I2C_Read8Bit();
I2C_Ack(); //应答
buffer++;
bytes--;
}
I2C_Stop();
}
////////////////////////////////////////8563/////////////////////////////////
//BCD到16进制
uchar bcd_convert_hex(uchar bcd_data)
{
uchar shu;
shu=((bcd_data&0xF0>>4)&0x0F)*10+(bcd_data&0x0F);
return (shu);
}
//16进制到BCD
uchar hex_convert_bcd(uchar hex_data)
{
uchar temp;
uchar bcd_data;
temp=hex_data%100;
bcd_data=(temp/10<<4)|(temp%10);
return bcd_data;
}
//8563写
void Write8563(uchar CFG_add,uchar CFG_data)
{
I2C_Start(); // 启动I2C
I2C_Write8Bit(0xA2); // 发送器件所在地址
I2C_Ack(); //调用应答信号
I2C_Write8Bit(CFG_add); // 发送寄存器地址
I2C_Ack();
I2C_Write8Bit(CFG_data); // 发送寄存器数据
I2C_Ack();
I2C_Stop(); // 全部发完则停止
delay_nus(5);
}
//8563读
uchar Read8563(uchar CFG_add)
{
uchar receive_da=0;
I2C_Start();
I2C_Write8Bit(0xA2); //器件写地址
I2C_Ack();
I2C_Write8Bit(CFG_add); //写寄存器地址
I2C_Ack();
I2C_Start();
I2C_Write8Bit(0xA3); //器件读地址
I2C_Ack();
receive_da=I2C_Read8Bit();
I2C_Stop();
return(receive_da);
}
//写时间
void pcf8563_rewrite_time(uchar *ptr)
{
uchar i;
uchar timeBCD[7];
for(i=0;i<7;i++)
{
timeBCD=hex_convert_bcd(ptr);
}
Write8563(0x00,0x20); // PCF8563时钟芯停止运行
I2C_Write(timeBCD,0x02,7,0xA2); // 将设置时间写入PCF8563
Write8563(0x00,0x00); // PCF8563时钟芯开始运行
Write8563(0x01,0x11);
}
//读时间
void pcf8563_get_time()
{
sec=bcd_convert_hex((Read8563(0x02))&0x7F); //
if(sec>=60){sec=0;}
min=bcd_convert_hex((Read8563(0x03))&0x7F); // 分
if(min>=60){min=0;}
hour=bcd_convert_hex((Read8563(0x04))&0x3F); // 小时
if(hour>=24){hour=0;}
date=bcd_convert_hex((Read8563(0x05))&0x3F); // 日
if( date>=32){ date=1;}
week=Read8563(0x06);
if(week>6){week=0;}
month=bcd_convert_hex((Read8563(0x07))&0x1F); // 月
if(month>=13){month=1;}
year=bcd_convert_hex(Read8563(0x08)); // 年
if(year>99){year=0;}
}
//更新显示缓冲区
void update_disbuf(uchar t2[])
{
dis_buf1[4]=year/10+0x30 ;
dis_buf1[5]=year%10+0x30 ;
dis_buf1[7]=month/10+0x30 ;
dis_buf1[8]=month%10+0x30 ;
dis_buf1[10]=date/10+0x30 ;
dis_buf1[11]=date%10+0x30 ;
dis_buf2[2]=t2[0] ; //显示温度
dis_buf2[3]=t2[1] ;
dis_buf2[8]=hour/10+0x30 ;
dis_buf2[9]=hour%10+0x30 ;
dis_buf2[11]=min/10+0x30 ;
dis_buf2[12]=min%10+0x30 ;
dis_buf2[14]=sec/10+0x30 ;
dis_buf2[15]=sec%10+0x30 ;
}
//显示处理程序
void pro_display()
{
disp_lcd(0x80,dis_buf1);
disp_lcd(0xc0,dis_buf2);
}
//初始化8563
void pcf8563_star(void)
{
I2C_Start();
Write8563(0x00,0x00); // PCF8563时钟芯开始运行
Write8563(0x01,0x11);
Write8563(0x0D,0x10);
pcf8563_rewrite_time(timedata);
}
//////////////////////////单片机上电启动///////////////////////
void Start()
{
TRISB=0x00;
TRISC=0x00;
PORTC=0X00;
PORTA=0x00;
TRISA=0x02;
INTCON=0x00;
PCON=0x01;
POR=1;
}
//////////////////////////初始化////////////////////////////////
void Initialize()
{
//ADIE=1; //使能A/D转换中断
SSPCON = 0x0E;
SSPSTAT =0x26; //初始化寄存器
GIE=0; //关闭中断
SSPEN=1; //SSP标志使能
// SSPADD=0x02;
pcf8563_star();
LCD_init(); //LCD初始化
LCD_reset(); //复位
disp_lcd(0x80,wlcome);
disp_lcd(0xc0,Enter);
// delay_nus(3000); //保持3秒显示内容
}
///////////////////////////////主程序///////////////////////////
void main()
{
I2C_Init();
// tep=tpmtdata;
Start(); //调用启动程序
Initialize(); //调用初始化程序
while(1)
{
pcf8563_get_time();
update_disbuf("20");
pro_display();
// if(tpmtdata>tep) //温度上限判断
// {
// PORTA=0x00; //电机关闭
//delay_nus(1000); //延时,使检测不至太频繁
//}
//else if(tpmtdata<tep-0x66) //温度下限判断
//{
//PORTA=0x04; //电机开启
//delay_nus(10);
//ADON =1; //启动下一次转换
//}
}
}
原理图ourdev_535522.pdf(文件大小:420K) (原文件名:PCB_Project1.pdf)
一周热门 更多>