原创 ATMEGA16 & DS12887加上串口通信显示时钟程序-查询方式

2009-5-6 21:51 3733 8 8 分类: MCU/ 嵌入式

/******************************************************/
//Title:ATMEGA128 & DS12887加上串口通信显示时钟程序-查询方式
//ICC-AVR : 2009-3-4 17:04:40
// Target : M16
// Crystal: 1.0000Mhz ~8.0000Mhz都好使
//Author  :borlittle


//QQ:634172943
//Function:usart+DS12887 RTC test
//备注   :本程序经调试好使,如果程序不好使,请注意检查硬件连线,内部时钟
//记得要校验准,串口才能发送正确,该程序也可以移植到ATMAGE128中,经


//验证能正常工作的
// AVR 执行时间:8MHZ ->0.125us  4MHZ->0.25us  //有串口,模拟总线最简版
//               2MHZ->0.5us      *1MHZ->1us ,每句后延时2句
// at89s52  执行时间:11.0592MHZ->2.17us
//
//
/****************************************************/


#include <iom16v.h>       
#include <macros.h>


#define uchar unsigned char  //定义无符号字符为 uchar
#define uint  unsigned int       //定义无符号整型
#define Crystal 8000000   //晶振8MHZ
#define Baud 9600         //波特率


uchar y1,y2,y3,y4,y5,y6; //用于调试用,在JTAG仿真器与AVR Studio 中查看是否读取正确
uchar y[19]={0,0,'.',0,0,'.',0,0,' ',0,0,':',0,0,':',0,0,' ',' '}; //09.3.4 17:06:50
//上位机接收到得时间数据格式
/**********************接口定义*********************************/
//GND <--   MOT     VCC  -->VCC
//   .     SQW
//   .     .
//PA_0<--  AD0        .    
//PA_1<--  AD1     .
//PA_2<--  AD2        IRQ   -->PB_0
//PA_3<--  AD3        REET  -->VCC
//PA_4<--  AD4     DS  -->PB_1
//PA_5<--  AD5     .
//PA_6<--  AD6     R/W  -->PB_2
//PA_7<--  AD7     AS  -->PB_3
//      GND     CS    -->GND--可以用端口控制以省电降功耗
/*********************引脚说明***********************************/
//DS12887       16    器件
//数据线       PA口    数据地址公用总线
//DS_IRQ        PB0    时间中断    
//DS_DS         PB1    数据选通
//DS_RW      PB2    读写控制
//DS_AS   PB3    地址选通
//DS_CS         PB4    芯片片选
//DS_MOT        GND    模式选择


/*******************数据地址定义*************************************/
#define DS12887_Second  0x00 //秒
#define DS12887_Minute  0x02 //分
#define DS12887_Hour  0x04 //时
#define DS12887_Week  0x06 //星期
#define DS12887_Day      0x07 //日
#define DS12887_Month  0x08 //月
#define DS12887_Year  0x09 //年


//引脚电平定义
#define P_DS_1 PORTB|=BIT(PB1)    //DS_DS为1
#define P_DS_0 PORTB&=~BIT(PB1)  //DS_DS为0
#define D_DS_1 DDRB |=BIT(PB1)      //设为输出


#define P_RW_1  PORTB|=BIT(PB2)     //DS_RW为1
#define P_RW_0  PORTB&=~BIT(PB2) //DS_RW为0
#define D_RW_1   DDRB |=BIT(PB2)    //设为输出


#define P_AS_1 PORTB|=BIT(PB3)  //DS_AS为1
#define P_AS_0 PORTB&=~BIT(PB3)     //DS_AS为0
#define D_AS_1  DDRB |=BIT(PB3)     //设为输出


#define P_CS_1 PORTB|=BIT(PB4)     //DS_CS为1
#define P_CS_0 PORTB&=~BIT(PB4)    //DS_CS为0    
#define D_CS_1  DDRB |=BIT(PB4)     //设为输出


    
//数据端口定义
#define AD_DDR DDRA    //AD(地址/数据服用线)的输入/输出控制
#define AD_PORT PORTA   //AD(地址/数据服用线)的输出电平控制
#define AD_PIN PINA   //AD(地址/数据服用线)的输入电平控制


//定义时间类型,结构体数据类型
typedef struct _SYSTEMTIME_
{
 unsigned  char Second;
 unsigned  char Minute;
 unsigned  char Hour;
 unsigned  char Week;
 unsigned  char Day;
 unsigned  char Month;
 unsigned  char Year;
 unsigned  char DateString[9];
 unsigned  char TimeString[9];
}SYSTEMTIME;   


/***********************函数声明*****************************/
void DS12887_Init(void);           //DS12887初始化
void DS12887_Write( uchar Address,  uchar Value);  //DS12887指定地址写入数据
uchar DS12887_Read(uchar Address);     //DS12887指定地址中读出数据 
void DS12887_SetTime( uchar Address,  uchar Value); //设置时间函数
void DS12887_GetTime(SYSTEMTIME *Time);        //读出时间
void port_init(void);
void init_devices(void);


void usart_char_send(uchar i);
void usart_str_send(char *s);
uchar usart_char_receive(void);


/*****************串口初始化*********************************/
void usart_init(void)
{
 UCSRB = 0x00;                     //禁止发送和接收
 UCSRA = 0x02;                     //倍速异步模式USX=1
 UCSRC = 0x06;                     //0000 0110,UCSZ1=1,UCSZ0=1;8位字符,1位停止位
 UBRRL=(Crystal/8/(Baud+1))%256;   //若为正常异步模式USX0=0则位(Crystal/16/(Baud+1))%256
 UBRRH=(Crystal/8/(Baud+1))/256;   //参见ATMAGE16使用手册
 UCSRB = 0x18;                     //允许发送和接收
}
/******************端口初始化*******************************/
void port_init(void)
{
  DDRB  = 0xFF;
 PORTB = 0xFF; //设为输出高电平
 
 DDRA  = 0x00;
 PORTA = 0x00; //设为高阻态
 
 PORTD = 0xFF;   //设置RXD0和TXD0
 DDRD  = 0x02;


}


//****************发送一个字符******************************
void usart_char_send(uchar i)
{
while(!(UCSRA&(1<<UDRE)));
UDR=i;
}
/******************发送一个字符串*************************/
void usart_str_send(char *s)
{
 while(*s)
 {
 usart_char_send(*s);
 s++;
 }
}
/*****************发送数组数据**************************************/
void usart_send_arry(void)
{
uchar i;
for(i=0;i<19;i++)
usart_char_send(y);
}
/*****************接收一个字符****************************/
uchar usart_char_receive(void)
{
while(!(UCSRA&(1<<RXC)));
return UDR;
}


/*******DS12887指定地址写入数据 ,严格按照INTERL的时序,程序**********/
void DS12887_Write( uchar Address, uchar Value)
{
 
 P_AS_0;
    _NOP();
    _NOP();    
    P_DS_1;
 _NOP();
    _NOP();
    P_RW_1;            //给出读信号
    _NOP();
    _NOP();   
    P_AS_1;            //锁存信号高电平
    _NOP();
    _NOP();
    AD_DDR = 0xFF;          //数据口设置为输出
    _NOP();
    _NOP();
 _NOP();
 _NOP();
    AD_PORT = Address;       //给出地址
    _NOP();
    _NOP(); 
 _NOP();
    _NOP();
 _NOP();
 _NOP();                     //
    P_AS_0;            //锁存信号低电平
    _NOP();
    _NOP(); 
    P_RW_0;            //给出写信号
    _NOP();
    _NOP();
    _NOP();
    AD_PORT = Value;  //写出数据
    _NOP();
    _NOP();
    _NOP();
    _NOP();
 _NOP();
 _NOP();
 _NOP();
 _NOP();
    P_RW_1;            //给出读信号
    _NOP();
    _NOP();
    _NOP();
    P_AS_1;            //片选信号高电平
    _NOP();
    _NOP(); 
}
/*********DS12887指定地址中读出数据,严格按照INTERL的时序!!!!!********/
uchar DS12887_Read( uchar Address)
{  
  unsigned char temp = 0;    
    P_AS_0;            //锁存信号高电平
    _NOP();
    _NOP();
 P_DS_1;
 _NOP();
    _NOP();
    P_RW_1;            //给出读信号   
    _NOP();
    _NOP();
    P_AS_1;            //锁存信号高电平
    _NOP();
    _NOP();
    AD_DDR = 0xFF;         //数据口设置为输出
 _NOP();
 _NOP();
 _NOP();
 _NOP();
    AD_PORT = Address;       //给出地址
    _NOP();
    _NOP();
  _NOP();
    _NOP();
 _NOP();
 _NOP();
 _NOP();
 _NOP();
    P_AS_0;            //锁存信号低电平
    _NOP();
    _NOP();    
    P_DS_0;            //给出写信号
    _NOP();
    _NOP();
    AD_DDR = 0X00;          //端口方向设置为输入
    _NOP();
    _NOP();
 _NOP();
 _NOP();
    temp = AD_PIN;   //读入数据
    _NOP();
 _NOP();
 _NOP();
 _NOP();
 _NOP();
 _NOP();
 _NOP();
 _NOP();
    P_DS_1;            //
    _NOP();
    _NOP();
 P_AS_1;            //
    _NOP();
    _NOP();
    return temp;
}


//DS12887初始化
void DS12887_Init(void)
{
 DS12887_Write(0x0a, 0x20); //打开振荡器,启动DS12887
 DS12887_Write(0x0b, 0x86); //禁止更新,接下来初始化数据,即写入时间,日期等
 DS12887_Write(0x0b, 0x06); //正常更新,二进制格式,24进制小时
}


 


//设置时间函数
void DS12887_SetTime( uchar Address,  uchar Value)
{
 DS12887_Write(0x0b, 0x86); //禁止更新,接下来初始化数据,即写入时间,日期等
 DS12887_Write(Address,Value);
 DS12887_Write(0x0b, 0x06); //正常更新,二进制格式,24进制小时
}



//读出时间
void DS12887_GetTime(SYSTEMTIME *Time)
{   uchar temp;
 Time->Second = DS12887_Read(DS12887_Second);
 Time->Minute = DS12887_Read(DS12887_Minute);
 Time->Hour   = DS12887_Read(DS12887_Hour  );
 Time->Day    = DS12887_Read(DS12887_Day   );
 //Time->Week   = DS12887_Read(DS12887_Week  );
 Time->Month  = DS12887_Read(DS12887_Month );
 Time->Year   = DS12887_Read(DS12887_Year  );
 
  y1=DS12887_Read(DS12887_Second);
  y2=DS12887_Read(DS12887_Minute);
  y3=DS12887_Read(DS12887_Hour  );
  y4=DS12887_Read(DS12887_Day   );
  y5=DS12887_Read(DS12887_Month );
  y6=DS12887_Read(DS12887_Year  );
}
/*********************日期转化成字符 09-02-19************/
void DateToStr(SYSTEMTIME *Time)
{
 Time->DateString[0] = Time->Year/10 + '0';
 Time->DateString[1] = Time->Year%10 + '0';
 Time->DateString[2] = '-';
 Time->DateString[3] = Time->Month/10 + '0';
 Time->DateString[4] = Time->Month%10 + '0';
 Time->DateString[5] = '-';
 Time->DateString[6] = Time->Day/10 + '0';
 Time->DateString[7] = Time->Day%10 + '0';
 Time->DateString[8] = '\0';


 y[0]=Time->DateString[0];
 y[1]=Time->DateString[1]; //年
 
 y[3]=Time->DateString[3]; 
 y[4]=Time->DateString[4];   //月


 y[6]=Time->DateString[6]; 
 y[7]=Time->DateString[7]; //日


}



/*********************时间转化成字符***********************************/
void TimeToStr(SYSTEMTIME *Time)
{
 Time->TimeString[0] = Time->Hour/10 + '0';
 Time->TimeString[1] = Time->Hour%10 + '0';
 Time->TimeString[2] = ':';
 Time->TimeString[3] = Time->Minute/10 + '0';
 Time->TimeString[4] = Time->Minute%10 + '0';
 Time->TimeString[5] = ':';
 Time->TimeString[6] = Time->Second/10 + '0';
 Time->TimeString[7] = Time->Second%10 + '0';
 Time->TimeString[8] = '\0';


 y[9]=Time->TimeString[0];
 y[10]=Time->TimeString[1]; //时
 
 y[12]=Time->TimeString[3]; 
 y[13]=Time->TimeString[4];   //分


 y[15]=Time->TimeString[6]; 
 y[16]=Time->TimeString[7]; //秒
 
}



/********************初始化器件************************************/
void init_devices(void)
{
 port_init();
 usart_init();
 }
/***************主函数*****************************/
void main(void)
{
 SYSTEMTIME CurrentTime;
    uchar temp;
 init_devices();
 DS12887_Init();  //只读时间的时候可以屏蔽该句
 DS12887_GetTime(&CurrentTime);
/*************时间初始化设置 ,2009-3-4 16:57:00************/
//时钟调准后屏蔽该段程序
//*
DS12887_SetTime(DS12887_Second, 0); //设置秒
DS12887_SetTime(DS12887_Minute, 57); //设置分
DS12887_SetTime(DS12887_Hour,16);  //设置时
DS12887_SetTime(DS12887_Day, 4);  //设置天
DS12887_SetTime(DS12887_Month, 3); //设置月
DS12887_SetTime(DS12887_Year, 9);  //设置年
//*/
 usart_str_send("DS12887工作中.......");
 while(1)
 {
 DS12887_GetTime(&CurrentTime);
 DateToStr(&CurrentTime);
 TimeToStr(&CurrentTime);
 temp=usart_char_receive();
 if(temp=='0')   //字符0----数据传送启动指令
 usart_str_send("现在时间是:");
 usart_send_arry();//传送时间数据
  usart_str_send("  "); 
 }
 } 
//可以根据你的需要稍改写就可以移植到你的应用中去,16模拟的INTERL总线读写虽然没用51或者ATMEGA128等有总线结构的单片机直接用总线读写软件省事些,但是也有其好处,用于模拟时序的端口引脚可以更为自由地配置,尤其是若用51或者ATMEGA128必须用到低位的地址数据复用端口8个引脚而且还要占用高位地址选通端口的引脚,在某些应用中会因端口配置时受限。


串口调试时的截图:


27e41fee-e10c-4a40-b804-d213ee5b943e.jpg

文章评论0条评论)

登录后参与讨论
我要评论
0
8
关闭 站长推荐上一条 /2 下一条