⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 20041117124558.c

📁 完全实用化的020 SMBUS程序(与时钟PCF8563通信).rar经调试,很正确的.
💻 C
字号:
//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 + -