深圳市英锐恩科技有限公司:台湾麦肯单片机(Micon MDT单片机)亚太地区A级代理商
QLdsPIC3]实时时钟[C30+dsPIC30F6014A]
//实验目的:熟悉时钟芯片PCF8583以及IIC通信
//软件规划:
// 1,通过按下按键K7往时钟芯片内写入预设时间和日期为,包括毫秒、秒、分、时、日、月、年、星期
// 2、通过查询时钟芯片触发的中断读取时间(1秒执行一次)
// 3、时间和日期送LCD1602显示,显示格式如下:
// ------------------------
// | HH:MM:SS |
// | Y:y M:mm D:dd W |
// ------------------------
//硬件要求:拨码开关S13全部置ON
// 拨码开关S2第2位置ON
// 跳线J18全部接通
#include //dsPIC30F6014标准头文件
_FOSC(CSW_FSCM_OFF & XT_PLL4); //4倍频晶振,Failsafe 时钟关闭
_FWDT(WDT_OFF); //关闭看门狗定时器
_FBORPOR(PBOR_OFF & MCLR_EN); //掉电复位禁止,MCLR复位使能。
_FGS(CODE_PROT_OFF); //代码保护禁止
#define i_o PORTGbits.RG3 //定义DS1302的数据口
#define sclk PORTGbits.RG2 //定义DS1302的时钟口
#define intr PORTAbits.RA12 //定义DS1302的复位口
#define rs LATBbits.LATB4 //定义LCD控制位(注意这里只能用LATB寄存器,不能直接用PORTB寄存器)
#define rw LATBbits.LATB5
#define e LATBbits.LATB6
// unsigned char time_rx;
unsigned char __attribute__((address(0x900))) rd_data[6]={0,0,0,0,0,0}; //定义接收寄存器
// LCD显示数据
unsigned char __attribute__((address(0x920))) lcd[16]={' ',' ',' ',' ',0,0,':',0,0,':',0,0,' ',' ',' ',' '};
unsigned char __attribute__((address(0x940))) lcd1[16]={'Y',':',0,' ','M',':',0,0,' ','D',':',0,0,' ',' ',0};
//定义待设置的时间:豪秒、 秒、 分、 时、 日/年、 月/星期
const char table[]={ 0, 88, 88, 18 ,41 ,50};
// 0豪秒;58秒;58分;12时 0年29日 12月星期1
//****************************延时程序**************************************
void delay() //延时程序
{
int i; //定义整形变量
for(i=0;i<10;i++); //延时
}
//***************************写PCF8583程序**********************************
void wr_data(unsigned char temp)
{
I2CTRN=temp; //数据送IIC的发送寄存器
while(!IFS0bits.MI2CIF); //等待发送完成
IFS0bits.MI2CIF=0;
}
//**************************等待总线空闲为空程序****************************
void finish()
{
while(!IFS0bits.MI2CIF); //等待总线空闲
IFS0bits.MI2CIF=0;
}
//*************************写LCD程序****************************************
//写一个字节数据函数
//在电平发生改变后需要插入一段延时时间,否则LCD反应不过来。
void write(unsigned int x)
{
PORTD=x; //待显示数据送PORTD口
delay();
rs=1; //该字节数据为数据,而不是命令
delay();
rw=0; //此次操作为写,而不是读
delay();
e=0; //拉低使能信号
delay(); //保持使能信号为低一段时间
e=1; //拉高使能信号,建立LCD操作所需要的上升沿
delay();
}
//********************LCD显示设置函数**************************************
//在电平发生改变后需要插入一段延时时间,否则LCD反应不过来。
void lcd_enable()
{
delay();
rs=0; //该字节数据为命令,而不是数据
delay();
rw=0; //此次操作为写,而不是读
delay();
e=0; //拉低使能信号
delay(); //保持使能信号为低一段时间
e=1; //拉高使能信号,建立LCD操作所需要的上升沿
delay();
}
//**********************IIC初始化函数***************************************
void i2c_init()
{
TRISB=0X0000; //设置B口为输出
TRISD=0X0000; //设置D口为输出
TRISC=0XFFFF;
TRISG=0XFFFF;
I2CCON=0;
I2CSTAT=0;
I2CBRG=15; //400K
I2CCONbits.I2CEN=1; //使能IIC
}
//*********************LCD初始化函数**************************************
void lcd_init()
{
PORTD=0X1; //清除显示
lcd_enable();
PORTD=0X38; //8位2行5*7点阵
lcd_enable();
PORTD=0X0e; //显示开,光标开,闪烁
lcd_enable();
PORTD=0X06; //文字不动,光标右移
lcd_enable();
}
//*******************PCF8583中断使能函数***********************************
void i2c_interrupt_init()
{
// IPC4=7; //优先级别最高
IEC1bits.INT1IE=0; //使用查询方式
IFS1bits.INT1IF=0; //清除中断标志位
INTCON2bits.INT1EP=1; //负边沿触发
I2CCONbits.SEN=1; //发送起始位
finish(); //等待完成
wr_data(0xa0); //发送控制命令和写命令
wr_data(0); //写8583的第0单元
wr_data(4); //写入数据4(使能中断功能)
I2CCONbits.RSEN=1; //发重启动位
finish(); //等待完成
wr_data(0xa0); //发送控制命令和写命令
wr_data(8); //写8583的第8单元
wr_data(9); //写入数据9(计时中断功能)
I2CCONbits.PEN=1; //发停止位
finish(); //等待完成
}
//***********************LCD显示函数************************************
void lcd_display()
{
unsigned char i,j;
PORTD=0X80; /显示地址
lcd_enable();
for(i=0;i<16;i++) //一共16字节数据
{
write(lcd[i]); //查表获取数据并调用写一个字节数据函数送LCD显示
for(j=0;j<5;j++) //延时一段时间(主要是为了控制显示的速度)
{delay();}
}
PORTD=0X00c0; //日期时间显示地址
lcd_enable();
for(i=0;i<16;i++) //一共16字节数据
{
write(lcd1[i]); //查表获取数据并调用写一个字节数据函数送LCD显示
for(j=0;j<5;j++) //延时一段时间(主要是为了控制显示的速度)
{delay();}
}
}
//***********************设置初始时间函数******************************
void i2c_write()
{
unsigned char i;
I2CCONbits.SEN=1; //发送启动位
finish(); //等待完成
wr_data(0xa0); //发送控制命令和写命令
wr_data(1); //待修改的8583起始单元地址(毫秒单元;地址自动+1)
for(i=0;i<6;i++) //共修改6个单元(时间跟日期)
{
wr_data(table[i]); //查表写数据
}
I2CCONbits.PEN=1; //发送停止位
finish(); //等待完成
}
//************************读时间函数***********************************
void i2c_read()
{
unsigned char i;
I2CCONbits.SEN=1; //发送起始位
finish(); //等待完成
wr_data(0xa0); //发送控制命令和写命令
wr_data(2); //读时间的起始单元
I2CCONbits.RSEN=1; //发重启动位
finish(); //等待完成
wr_data(0xa1); //发送控制命令和读命令
for(i=0;i<7;i++) //读取时间
{
I2CCONbits.RCEN=1; //使能IIC的读功能
rd_data[i]=I2CRCV; //保存读取到的时间
finish(); //等待完成
I2CCONbits.ACKEN=1; //使能应答功能
if(i==6) I2CCONbits.ACKDT=1; //不是最好一个数据,应答信号为0,继续读数据
else I2CCONbits.ACKDT=0; //做后一个数据,应答信号为1
while(!IFS0bits.MI2CIF);
IFS0bits.MI2CIF=0;
}
I2CCONbits.PEN=1; //发送停止位
finish(); //等待完成
}
//*************读取时间转换成BCD码并存储到LCD显示缓冲单元*************
void hex2bcd()
{
lcd[11]=(rd_data[1]&0xf)+0x30; // 1/10 second
lcd[10]=(rd_data[1]>>4)+0x30; // second
lcd[8]=(rd_data[2]&0xf)+0x30; // 1/10 minute
lcd[7]=(rd_data[2]>>4)+0x30; // minute
lcd[5]=(rd_data[3]&0xf)+0x30; // 1/10 hour
lcd[4]=(rd_data[3]>>4)+0x30; // hour
lcd1[12]=(rd_data[4]&0xf)+0x30; // 1/10 date
lcd1[11]=((rd_data[4]>>4)&3)+0x30; // data
lcd1[2]=(rd_data[4]>>6)+0x30; // year
lcd1[7]=(rd_data[5]&0xf)+0x30; // 1/10 month
lcd1[6]=((rd_data[5]>>4)&1)+0x30; // month
lcd1[15]=(rd_data[5]>>5)+0x30; // weekday
}
//***********************主函数**************************************
int main(void)
{
i2c_init(); //系统初始化
lcd_init(); //LCD初始化
i2c_interrupt_init(); //芯片中断使能
while(1)
{
while(!PORTCbits.RC3)
{
i2c_write(); //设置初始时间
while(!PORTCbits.RC3);
}
while(IFS1bits.INT1IF) //等待中断
{
IFS1bits.INT1IF=0;
i2c_interrupt_init(); //重新初始化中断,以便清除8583芯片内中断标志位
i2c_read(); //读取时间
hex2bcd(); /结果转换成BCD码
lcd_display(); /送LCD显示
}
}
}