📄 完全实用化的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 + -