深圳市英銳恩科技有限公司:臺灣麥肯單片機(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顯示
}
}
}