avr DS1302 数码管 时钟电路 protues仿真 出现问题

2019-07-18 13:37发布

// Target : M16
// Crystal: 8Mhz
#include <iom16v.h>
#include <macros.h>
#define uint unsigned int
#define uchar unsigned char
#define DS1302_RST 5 //pD5
#define DS1302_SDA 4//pD4
#define DS1302_SCLK 6 //pD6
//ds1302相关
//DS1302_RST=1
#define Set_DS1302_RST() PORTD|=1<<DS1302_RST
//DS1302_RST=0
#define Clr_DS1302_RST() PORTD&=~(1<<DS1302_RST)
//DS1302_SDA=1
#define Set_DS1302_SDA() PORTD|=1<<DS1302_SDA
//DS1302_SDA=0
#define Clr_DS1302_SDA() PORTD&=~(1<<DS1302_SDA)
//DS1302_SCLK=1
#define Set_DS1302_SCLK() PORTD|=1<<DS1302_SCLK
//DS1302_SCLK=0
#define Clr_DS1302_SCLK() PORTD&=~(1<<DS1302_SCLK)
//DS1302的SDA置为输出脚
#define Set_DS1302_DDRSDA() DDRD|=1<<DS1302_SDA
//DS1302的SDA置为输入脚
#define Clr_DS1302_DDRSDA() DDRD&=~(1<<DS1302_SDA)
uchar const bit_tab[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//位选表,用来选择哪一只数码管进行显示
char ledxs[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};  // 年-月-日   LED显示
unsigned char ReadRTC_Flag=1 ;
unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};
                                 //共阴数码管 0-9  '-' '熄灭‘表
unsigned char l_tmpdate[7]={0,0,12,15,5,3,8};//秒分时日月周年08-05-15 12:00:00
#define DS1302_SEC_Reg 0x80
#define DS1302_MIN_Reg 0x82
#define DS1302_HR_Reg 0x84
#define DS1302_DATE_Reg 0x86
#define DS1302_MONTH_Reg 0x88
#define DS1302_DAY_Reg 0x8a
#define DS1302_YEAR_Reg 0x8c
#define DS1302_CONTROL_Reg 0x8e
#define DS1302_CHARGER_Reg 0x90
#define DS1302_CLKBURST_Reg 0xbe
#define DELAY() {NOP();NOP();NOP();NOP();}
//全局变量
//为了方便,我把个位和十位分开了
uchar year1=0x88;
uchar year0=0x88;
uchar month1=0x88;
uchar month0=0x88;
uchar date0=0x88;
uchar date1=0x88;
uchar day=0x88;
uchar hour1=0x88;
uchar hour0=0x88;
uchar minute1=0x88;
uchar minute0=0x88;
uchar second1=0x88;
uchar second0=0x88;
  void DS1302_portinit(void)                  
{
DDRD|=BIT(DS1302_SCLK)|BIT(DS1302_SDA)|BIT(DS1302_RST);//将时钟端(RTC_CLK)数据端(RTC_DATA)片选端(RTC_CS)设置为输出
}
//自程序开始
void DS1302_Write(uchar reg,uchar data)
{
uchar i;
Set_DS1302_DDRSDA();
Clr_DS1302_RST();
asm("nop");
asm("nop");
DELAY();
Clr_DS1302_SCLK();
asm("nop");
asm("nop");
DELAY();
Set_DS1302_RST();
asm("nop");
asm("nop");
DELAY();
for(i=8;i>0;i--)
{
if(reg&0x01)
Set_DS1302_SDA();
else
Clr_DS1302_SDA();
asm("nop");
asm("nop");
DELAY();
Set_DS1302_SCLK();
asm("nop");
asm("nop");
DELAY();
Clr_DS1302_SCLK();
asm("nop");
asm("nop");
DELAY();
reg>>=1;
}
for(i=8;i>0;i--)
{
if(data&0x01) Set_DS1302_SDA();
else Clr_DS1302_SDA();
asm("nop");
asm("nop");
DELAY();
Set_DS1302_SCLK();
asm("nop");
asm("nop");
DELAY();
Clr_DS1302_SCLK();
asm("nop");
asm("nop");
DELAY();
data>>=1;
}
Clr_DS1302_RST();
asm("nop");
asm("nop");
DELAY();
Clr_DS1302_DDRSDA();
}

/* 读出DS1302数据*/
uchar DS1302_Read(uchar reg)
{
uchar data=0,i;
reg+=1;//读标志
Set_DS1302_DDRSDA();
Clr_DS1302_RST();
asm("nop");
asm("nop");
DELAY();
Clr_DS1302_SCLK();
asm("nop");
asm("nop");
DELAY();
Set_DS1302_RST();
asm("nop");
asm("nop");
DELAY();
for(i=8;i>0;i--)
{

if(reg&0x01) Set_DS1302_SDA();
else Clr_DS1302_SDA();
asm("nop");
asm("nop");
DELAY();
Set_DS1302_SCLK();
asm("nop");
asm("nop");
DELAY();
Clr_DS1302_SCLK();
asm("nop");
asm("nop");
DELAY();
reg>>=1;
}
Clr_DS1302_DDRSDA();
for(i=8;i>0;i--)
{
data>>=1;
if((PIND&(1<<DS1302_SDA))==(1<<DS1302_SDA)) data|=0x80;
Set_DS1302_SCLK();
asm("nop");
asm("nop");
DELAY();
Clr_DS1302_SCLK();
asm("nop");
asm("nop");
DELAY();
}
Clr_DS1302_RST();
asm("nop");
asm("nop");
DELAY();
return(data);
}

uchar Check_DS1302(void)
{
DS1302_Write(DS1302_CONTROL_Reg,0x80);
if(DS1302_Read(DS1302_CONTROL_Reg)==0x80) return 1;
return 0;
}
void DS1302_init(void)
{
DS1302_Write(DS1302_CONTROL_Reg,0x00);//关闭写保护
DS1302_Write(DS1302_SEC_Reg,0x80);//暂停
DS1302_Write(DS1302_CHARGER_Reg,0xa9);//涓流充电
DS1302_Write(DS1302_YEAR_Reg,0x04); //年
DS1302_Write(DS1302_MONTH_Reg,0x12); //月
DS1302_Write(DS1302_DATE_Reg,0x09); //日
DS1302_Write(DS1302_DAY_Reg,0x04); //周
DS1302_Write(DS1302_HR_Reg,0x10); //时
DS1302_Write(DS1302_MIN_Reg,0x25); //分
DS1302_Write(DS1302_SEC_Reg,0x00); //秒
DS1302_Write(DS1302_CONTROL_Reg,0x80);//打开写保护
}

/*  读时钟数据*/     
void ReadTime(void)
{
uchar data;
data=DS1302_Read(DS1302_YEAR_Reg);//年
year0=data&0x0f;
year1=data>>4;
data=DS1302_Read(DS1302_MONTH_Reg);//月
month0=data&0x0f;
month1=(data>>4)&0x01;
data=DS1302_Read(DS1302_DATE_Reg);//日
date0=data&0x0f;
date1=(data>>4)&0x03;
data=DS1302_Read(DS1302_DAY_Reg);//周
day=data&0x07;
data=DS1302_Read(DS1302_HR_Reg);//时
hour0=data&0x0f;
hour1=(data>>4)&0x03;
data=DS1302_Read(DS1302_MIN_Reg);//分
minute0=data&0x0f;
minute1=(data>>4)&0x07;
data=DS1302_Read(DS1302_SEC_Reg);//秒
second0=data&0x0f;
second1=(data>>4)&0x07;
}

void port_init(void)
{
PORTA = 0xFF;
DDRA  = 0xFF;
//PORTB = 0xff;
//DDRB  = 0xff;
PORTC = 0xFF; //m103 output only
DDRC  = 0XFF;
//PORTD = 0xff;
//DDRD  = 0xff;
}
void timer0_init(void)
{SEI();
TCCR0 = 0x00; //stop/*定时器停止,TCCR0寄存器完全控制timer0的运行情况,详细可参考数据手册。*/
TCNT0 = 0xF0; //set count/*定时器寄存器开始值*/
OCR0  = 0x83;  //set compare/*定时器比较值*/
TIMSK=0X01;
TIFR=0X01;
TCCR0 = 0x05; //start timer/*定时器开始64分频*/
}

/*#pragma interrupt_handler timer0_comp_isr:20
void timer0_comp_isr(void)
{
//compare occured TCNT0=OCR0 /*定时器比较匹配中断,这里没有添加任何语句,实际操作中可以用此实现自制PWM
}
*/
#pragma interrupt_handler timer0_ovf_isr:10
void timer0_ovf_isr(void)
{static unsigned char i,num;
TCNT0 = 0xF0; //reload counter value /*定时器溢出后需要重载TCNTn,然后在之后添加用户程序,
                          // 记住不要在定时器中断里添加特别耗时的程序。*/
PORTA=table[ledxs[i]];
switch(i)                                          
             {            
                        case 0:PORTC=bit_tab[0]; break;         
                case 1:PORTC=bit_tab[1]; break;                    
                case 2:PORTC=bit_tab[2]; break;
                case 3:PORTC=bit_tab[3]; break;
                        case 4:PORTC=bit_tab[4]; break;
                        case 5:PORTC=bit_tab[5]; break;
                        case 6:PORTC=bit_tab[6]; break;
                        case 7:PORTC=bit_tab[7]; break;
                            
                        /*case 0:PORTC=(0<<PC2)|(0<<PC3)|(0<<PC4); break;         
                case 1:PORTC=(1<<PC2)|(0<<PC3)|(0<<PC4); break;                    
                case 2:PORTC=(0<<PC2)|(1<<PC3)|(0<<PC4); break;
                case 3:PORTC=(1<<PC2)|(1<<PC3)|(0<<PC4); break;
                        case 4:PORTC=(0<<PC2)|(0<<PC3)|(1<<PC4); break;
                        case 5:PORTC=(1<<PC2)|(0<<PC3)|(1<<PC4); break;
                        case 6:PORTC=(0<<PC2)|(1<<PC3)|(1<<PC4); break;
                        case 7:PORTC=(1<<PC2)|(1<<PC3)|(1<<PC4); break;*/
                       
             }
i++;
if(i==8)
          {
           i=0;
           num++;
           if(10==num)       //隔段时间读取1302的数据。时间间隔可以调整
             {
                ReadRTC_Flag=1; //使用标志位判断
                 num=0;
                 }
          }
}

//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
timer0_init();
DS1302_portinit();
//MCUCR = 0x00;
//GICR  = 0x00;
//TIMSK = 0x01; //timer interrupt sources/*这里设定允许Timer0比较中断和溢出中断。*/
SEI(); //re-enable interrupts
}
void main(void)
{
init_devices();
  DS1302_init(); // 设置初始时间
while(1)
    {  
if(ReadRTC_Flag)        //下面有介绍,为了隔一段时间更新读取DS1302数据
          {
            ReadRTC_Flag=0;
       ReadTime();   //取得当前时间
       ledxs[0]=hour1;
       ledxs[1]=hour0;  // 时
       ledxs[2]=10;        // -
       ledxs[3]=minute1;
       ledxs[4]=minute0;  // 分
       ledxs[5]=10;       // -
       ledxs[6]=second1;
       ledxs[7]=second0;  // 秒
      }
   }

}


protues仿真 protues仿真
错误提示逻辑冲突 错误提示逻辑冲突
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。