?? 完全實用化的020 smbus程序(與時鐘pcf8563通信).txt
字號:
完全實用化的020 SMBUS程序(與時鐘PCF8563通信)
完全實用化的020 SMBUS程序(與時鐘PCF8563通信)
收集:楊本榮 來源: 網絡 發表于 2005-9-3
//C8051F 單片機:完全實用化的020 SMBUS程序(與時鐘PCF8563通信)
#include <intrins.h>
#include <stdio.h>
#include <absacc.h>
#include <C8051F020.h>
#define _Nop_() _nop_()
#define uint unsigned int
#define uchar unsigned char
#define ulong unsigned long
#define MY_ADD 0x00 //SMBus從地址,B0是應答呼叫地址允許位(1允許),
/*---------------------------定義PCD8583有關地址-----------------------------*/
#define write_pcf8563 0xA2
#define read_pcf8563 0xA3
#define pcf8563_control1 0x00
#define pcf8563_control2 0x01
#define pcf8563_second 0x02
#define pcf8563_minute 0x03
#define pcf8563_hour 0x04 //B7=0/1--24/12h B6=0/1--AM/PM
B5B4(ten hours 0 to 2) B3~B0(Unit hours)
#define pcf8563_date 0x05 //B7B6(year 0 to 3) B5B4(ten days 0
to 3) B3~B0(Unit days)
#define pcf8563_week 0x06 //B7_B5(Weekdays 0 to 6) B4(ten
months) B3~B0(Unit months)
#define pcf8563_month 0x07
#define pcf8563_year 0x08
#define pcf8563_min_arm 0x09
#define pcf8563_hou_arm 0x0a
#define pcf8563_dat_arm 0x0b
#define pcf8563_wek_arm 0x0c
#define pcf8563_clk_reg 0x0d
#define pcf8563_arm_reg 0x0e
#define pcf8563_tim_arm 0x0F
/*---------------------------PCF8583有關的變量----------------------------*/
bit dis_clock_flag,read_clock_flag,set_clock_flag;
uchar year,year1,month,day,week,hour,minute,second;
/*---------------------------SMBUS接口相關變量----------------------------*/
bit iic_error_flag,sm_busy;
uchar watch_buf[20];
uchar iic_read_buf[20]={0};
uchar iic_write_buf[20]={0};
uchar
slave_add,iic_ram_add,send_byte,write_start_num,read_start_num;
uchar
iic_send_count,iic_receive_count,iic_send_len,iic_receive_len,watch,i;
uchar hex_bcd(uchar hex_value)//完成HEX(99以內)到BCD(兩位)的確轉換
{
return(((hex_value/10)<<4)|(hex_value%10));
}
void enable_wdog(void)
{
WDTCN=0xA5;
//允許看門狗定時器工作
}
void disable_wdog(void) //禁止看門狗定時器工作
{
WDTCN=0xDE;
WDTCN=0xAD;
}
void init_sysclk (void)
{
uint i=0;
OSCXCN=0x67; // start
//external oscillator with 12MHz crystal
for(i=0;i<256;i++); // XTLVLD blanking
while(!(OSCXCN & 0x80)); // Wait for crystal osc. to settle
OSCICN=0x08;
// OSCICN=0x17; //bit7=0:禁止時鐘丟失檢測 bit3=1:選擇外部時鐘
}
void init_smbus(void)
{
SMB0CN=0x44; //IIC總線控制寄存器01000100
SMB0CR=0xc4; //-(SYSCLK/2*SCL_BAUD);IIC總線速率寄存器SCL=100K
SMB0ADR=MY_ADD; //設置從方式時將要應答的從地址 EIE1=EIE1|0x02;
//允許IIC總線中斷,標志位是SI(SMB0CN.3)
EIP1=EIP1|0x02; //SMBUS中斷為高優先級
}
void init_ioport()
{
XBR0=0x07; //b2=1 TXD0-P0.0 RXD0-P0.1,b1=1
SPI_SCK--P0.2,SPI_MISO--P0.3
//SPI_MOSI--P0.4,SPI_NSS--P0.5,b0=1 SDA--P0.6,SCL--P0.7,
XBR1=0x24; //b2=1 int0--P1.0,b4=1 int1--P1.1
XBR2=0x40; //端口I/O弱上拉允許,交叉開關允許
P0MDOUT=0x00; //端口0輸出方式寄存器:1--推挽方式,0--漏極開路
P0=0xff;
P1MDIN=0XFF; //端口1輸入方式寄存器:1--配置為模擬輸入,0--配置為數字輸入
P1MDOUT=0xff; //端口1輸出方式寄存器:1--推挽方式,0--漏極開路
P1=0xff;
P2MDOUT=0x38; //端口2輸出方式寄存器:1--推挽方式,0--漏極開路
P2=0xff; //在該程序中P2.012為鍵盤掃描輸入,如果為推挽方式則不可靠膸
P3MDOUT=0X00; //端口3輸出方式寄存器:1--推挽方式,0--漏極開路
P3=0xff;
P74OUT=0x01; //端口7-4輸出方式寄存器:1--推挽方式,0--漏極開路
P4=0xff;
P5=0xff;
P6=0xff;
P7=0xff;
}
void smbus_send (uchar chip_select,byte_address,write_num)
{
while(sm_busy); // Wait for SMBus to be free.
sm_busy=1; // Occupy SMBus (set to busy)
write_start_num=0;
slave_add=chip_select; // Chip select + WRITE
iic_ram_add=byte_address; // PCF8563的寄存器地址
iic_send_len=write_num; // 寫PCF8563字節數
STA=1; // Start transfer
while (sm_busy);
}
void smbus_receive (uchar chip_select,receive_num)
{
while (sm_busy); // Wait for bus to be free.
sm_busy=1; // Occupy SMBus (set to busy)
read_start_num=0;
slave_add=chip_select; // Chip select + READ
iic_receive_len=receive_num;
STA=1; // Start transfer
while(sm_busy); // Wait for transfer to finish
}
void write_8563(uchar ram_add,write_num)
{
smbus_send(write_pcf8563,ram_add,write_num);
}
void read_8563(uchar read_num)
{
smbus_receive(read_pcf8563,read_num);
}
void set_clock(void)
{
iic_write_buf[0]=hex_bcd(second); //設置秒
iic_write_buf[1]=hex_bcd(minute); //設置分
iic_write_buf[2]=hex_bcd(hour); //設置時
iic_write_buf[3]=hex_bcd(day);
iic_write_buf[4]=hex_bcd(week);
iic_write_buf[5]=hex_bcd(month);
iic_write_buf[6]=hex_bcd(year);
write_8563(pcf8563_second,0x07);
}
void read_clock(void)
{
write_8563(pcf8563_second,0x00);
smbus_receive(read_pcf8563,0x07);
second=iic_read_buf[0]&0x7f;
second=((second&0xf0)>>4)*10+(second&0x0f);//將BCD碼轉換成HEX
minute=iic_read_buf[1]&0x7f;
minute=((minute&0xf0)>>4)*10+(minute&0x0f);//將BCD碼轉換成HEX
hour=iic_read_buf[2]&0x3f;
hour=((hour&0xf0)>>4)*10+(hour&0x0f);//將BCD碼轉換成HEX
day=iic_read_buf[3]&0x3f;
day=((day&0xf0)>>4)*10+(day&0x0f);//將BCD碼轉換成HEX
week=iic_read_buf[4]&0x07;
week=((week&0xf0)>>4)*10+(week&0x0f);//將BCD碼轉換成HEX
month=iic_read_buf[5]&0x1f;
month=((month&0xf0)>>4)*10+(month&0x0f);//將BCD碼轉換成HEX
year=iic_read_buf[6];
year=((year&0xf0)>>4)*10+(year&0x0f);//將BCD碼轉換成HEX
}
void init_pcf8563(void)
{
iic_write_buf[0]=0x00;
write_8563(pcf8563_control1,0x01);
iic_write_buf[0]=0x00;
write_8563(pcf8563_control2,0x01);
iic_write_buf[0]=0x80;
write_8563(pcf8563_clk_reg,0x01);//CLK輸出頻率32.768K
iic_write_buf[0]=0x00;
write_8563(pcf8563_min_arm,0x01);//分報警無效
iic_write_buf[0]=0x00;
write_8563(pcf8563_hou_arm,0x01);//時報警無效
iic_write_buf[0]=0x00;
write_8563(pcf8563_dat_arm,0x01);//日報警無效
iic_write_buf[0]=0x00;
write_8563(pcf8563_wek_arm,0x01);//星期報警無效
}
void smbus(void) interrupt 7 using 2 //SMBUS中斷服務程序
{
watch=SMB0STA;
switch (watch)
//SMBUS狀態寄存器SMB0STA
{
//iic_error_flag=1說明SMBus有問題
case 0x08:
//主發送/接收:起始條件已發出.
STA=0;iic_error_flag=0;AA=1; //人工清除起始位STA
iic_receive_count=0;iic_send_count=0;
SMB0DAT=slave_add;
//從地址+讀/寫標志送SMB0DAT,
break;
case 0x10:
//主發送/接收:重復起始條件已發出。
STA=0;AA=1;
//人工清除起始位STA
SMB0DAT=slave_add;
//從地址+讀/寫標志送SMB0DAT
iic_receive_len=iic_receive_len+iic_receive_count;
iic_send_len=iic_send_len+iic_send_count;
iic_receive_count=0;iic_send_count=0;
break;
case 0x18: //主發送器:從地址+寫標志已發出,收到ACK
SMB0DAT=iic_ram_add;write_start_num=0;//將要發送的數據裝入SMB0DAT.
break;
case 0x20:
//主發送器:從地址+寫標志已發出,收到NACK
write_start_num++;
if(write_start_num>5)
{STO=1;sm_busy=0;iic_error_flag=1;}//如果超過5次不成功則釋放總線
else{STO=1;STA=1;} //確認查詢重復,置位STO+STA。
break;
case 0x28: //數據字節已發出,收到ACK,將下一字節裝入SMB0DAT;
switch(iic_send_len)
{
case 0x00:
STO=1;sm_busy=0; //如果數據已經發送結束則釋放總線
break;
default :
SMB0DAT=iic_write_buf[iic_send_count++];iic_send_len--;
break;
}
break;
case 0x30: //主發送器:數據字節已發出,收到NACK,
write_start_num++;
if(write_start_num>5)
{ STO=1;sm_busy=0;iic_error_flag=1;}//如果超過5次不成功則釋放總線
else
{STO=1;STA=1;} //重試傳輸或置位STO
break;
case 0x38: //主發送器:競爭失敗,保存當前數據
write_start_num++;
if(write_start_num>5)
{STO=1;sm_busy=0;iic_error_flag=1;} //如果超過5次不成功則釋放總線
{STO=1;STA=1;}
break;
case 0x40:
read_start_num=0; //主接收器:從地址+讀標志已發出,收到ACK,
if(iic_receive_len<2)AA=0; //如果只接收一個字節,清AA位(收到字節后發NACK),等待接收數據
break;
case 0x48: //主接收器:從地址+讀標志已發出,收到NACK,
read_start_num++;
if(read_start_num>5)
{STO=1;sm_busy=0;iic_error_flag=1;} //如果超過5次不成功則釋放總線
else
{STO=1;STA=1;}
break; //確認查詢重復,置位STO+STA。
case 0x50: //主接收器:數據字節收到,ACK已發出;讀SMB0DAT,等待
iic_read_buf[iic_receive_count++]=SMB0DAT;
iic_receive_len--;
if(iic_receive_len<2)AA=0; //下一個字節,如下一個字節是最后字節,清除AA。
break;
case 0x58: //主接收器:數據字節收到,NACK已發出,置位STO。
iic_read_buf[iic_receive_count++]=SMB0DAT;
//讀操作已經完成,讀數據寄存器并且發出STOP.
iic_receive_len--;
STO=1;sm_busy=0; //Free SMBus
break;
default:
STO=1;sm_busy=0;iic_error_flag=1; //Reset communication.
break;
}
SI=0; //clear interrupt flag
}
main()
{
disable_wdog();
init_sysclk();
init_ioport();
init_smbus();
EA=1;i=0;
init_pcf8563();
for(;;)
{
read_clock();
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -