ljp_03071628 发表于 2008-4-12 12:03:00

DS1302做的万年历-1602C液晶显示(atmega16-ICC)

http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_249802.JPG
接线电路图 (原文件名:未命名.JPG)


//========================================================
/*接线图如下:
_______________         ______________
               |      --1|GND         |
               |      --2|+5V         |
               |      --3|V0            |
               |         |            |
            PD5|--------4|RS            |
            PD6|--------5|RW            |
            PD7|--------6|E             |
CPU         |         |            |
ATmmega16L PA0|--------7|D0LCD20x4   |
            PA1|--------8|D1            |
            PA2|--------9|D2            |
            PA3|-------10|D3            |
            PA4|-------11|D4            |
            PA5|-------12|D5            |
            PA6|-------13|D6            |
            PA7|-------14|D7            |
               |         |            |
               |   --15|+LED          |
               |   --16|-LED          |
_______________|         |______________| */
//========================================================
#include<iom16v.h> //CPU_ATmmega16L
#include <macros.h>
#define RS_H    asm("sbi 0x12,5")//RS设为高电平
#define RS_L    asm("cbi 0x12,5")//RS设为低电平
#define RW_H    asm("sbi 0x12,6")//RW设为高电平
#define RW_L    asm("cbi 0x12,6")//RW设为低电平
#define E_H   asm("sbi 0x12,7")//E设为高电平
#define E_L   asm("cbi 0x12,7")//E设为低电平

//=======================================================
//微秒级延时程序
void delay_us(int time)
{ char i;
   while(time--)
   {
   for(i=0;i<8;i++);
   }
}
//=======================================================
//毫秒级延时程序
void delay_ms(unsigned int time)
{
    while(time != 0)
    {               
      delay_us(1000);
      time--;
    }
}

//=======================================================
//读取lcd是否内部操作(忙碌)状态
char Lcd_Busy()
{
    char r;
    DDRA = 0x00;       //端口A栉淙敕绞?
    E_L;RS_L;RW_H;   //E=0(致能),RS=0(命令),RW=1(读)
    delay_us(2);       //液晶延时子程序
    E_H;
    delay_us(2);       //液晶延时子程序
    r = PINA & 0x80;   //读取lcd_data第八位
    E_L;
    DDRA=0xff;         //端口A设为输出方式
    return r;          //读取结果返回 */
       
       
}

//=======================================================
//向Lcd发送命令程序
void Lcd_Command(unsigned char Command)
{

    while(Lcd_Busy()); //判断lcd是否内部操作状态
    E_L;RS_L;RW_L;   //E=0(致能),RS=0(命令),RW=0(写)
    delay_us(2);       //液晶延时子程序
    E_H;
        DDRA = 0xff;
    PORTA = Command;   //向Lcd发送命令
    delay_us(2);       //液晶延时子程序
    E_L;
   
}

//=======================================================
//向lcd写入一个字符程序
void Lcd_Write(unsigned char Data)
{
    while(Lcd_Busy()); //判断lcd是否内部操作状态
    E_L;
        RS_H;
        RW_L;   //E=0(致能),RS=1(数据),RW=0(写)
    delay_us(2);       //液晶延时子程序
    E_H;
        DDRA = 0xff;
    PORTA =Data;   //向lcd写入一个字符
delay_us(2);       //液晶延时子程序
    E_L;
}


/*=======================================================
LCD第1行显示地址1~20(0x80~0x8f)
LCD第2行显示地址1~20(0xc0~0xcf)


=======================================================*/
//初始化LCD_8位接口,2行x16字符的工作方式
void Lcd_Init()
{
    DDRA = 0xff;       //端口A设为输出方式
    DDRD = 0xff;       //端口D设为输出方式
    Lcd_Command(0x38); //
        delay_ms(5);
    Lcd_Command(0x38); //
        delay_ms(5);
    Lcd_Command(0x38); //
        delay_ms(5);
    Lcd_Command(0x38); //
    Lcd_Command(0x08); //令显示器off
    Lcd_Command(0x01); //清除显示器
    Lcd_Command(0x06); //令LCD每接收到1Byte数据后,AC自动加1
    Lcd_Command(0x0c); //令光标,0x0c=不显示,0x0d=显示闪动.
}

//=======================================================
//写ASCII字符串程序
void asc_tran(unsigned char *asc)
{
    while((*asc) != 0)   //判断字是否结束
    {
      Lcd_Write(*asc); //向lcd写入字符串
      asc++;         //移下一个字符
    }
}

//=======================================================
//测试主LCD主程序
/* void main()
{
    Lcd_Init(); //初始化LCD
    while(1)
    {
       Lcd_Command(0x80);               //设置显示位址
                //asc_tran("harbingongchengdaxue");
      asc_tran("I Love Gao Yan");      //显示字符串
      Lcd_Command(0xc0);               //设置显示位址
                asc_tran("maybe I can't");      //显示字符串
      delay_ms(600);                  //延迟1秒
      Lcd_Command(0x01);               //清除显示器

      Lcd_Command(0x80);               //设置显示位址
      asc_tran("-----^_^------");      //显示字符串
      Lcd_Command(0xc0);               //设置显示位址
      asc_tran("www.baidu.com"); //显示字符串
      delay_ms(600);                  //延迟
      Lcd_Command(0x01);               //清除显示器
               
               
      Lcd_Command(0x80);               //设置显示位址
      asc_tran("-----__@------");      //显示字符串
      Lcd_Command(0xc0);               //设置显示位址
      asc_tran("08-03-30-Sunday"); //显示字符串
      delay_ms(600);                  //延迟
      Lcd_Command(0x01);               //清除显示器
    }
}*/

ljp_03071628 发表于 2008-4-12 12:03:34

//ICC-AVR application builder
// Target : M16
// Crystal: 7.3728Mhz

#include <iom16v.h>
#include <macros.h>
unsigned char buffer3={0x45,0x00,0x55,0x00,0x66,0x00,0x00};
void port_init(void)
{
PORTA = 0xFF;
DDRA= 0x00;
PORTB = 0xFF;
DDRB= 0x00;
PORTC = 0xff; //m103 output only
DDRC= 0xFF;
PORTD = 0xFF;
DDRD= 0x00;
}

//call this routine to initialise all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();

MCUCR = 0x00;
GICR= 0x00;
TIMSK = 0x00; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialised
}

/*********************************************************************/
/* 实时时钟模块 时钟芯片型号:DS1302 */
/*********************************************************************/
#define        T_CLK 0
#define        T_IO1
#define        T_RST 7
/******************************************************************** */

#define        SETBIT(x,y) (x|=(1<<y))      //set bit y in byte x
#define        CLRBIT(x,y) (x&=(~(1<<y)))   //clear bit y in byte x
#define        CHKBIT(x,y) (x&(1<<y))       //check bit y in byte x
/******************************************************************** */


void nop(void)
{
char i;
for (i=0;i<1;i++)
;
}

void initialize_1302(void)
{
write_1302(0x8e,0x00);//写允许
write_1302(0x90,0xA5);//
write_1302(0x80,0x00);//写禁止
}
/********************************************************************
* 名称: ds1302_write_a_byte
* 说明:
* 功能: 往DS1302写入1Byte数据
* 调用:
* 输入: ucDa 写入的数据
* 返回值: 无
***********************************************************************/
void ds1302_write_a_byte(unsigned char ucDa)
{
    unsigned char i;
    for(i=8; i>0; i--)
    {
          CLRBIT(PORTC,T_CLK);
                if (ucDa&1) SETBIT(PORTC,T_IO);
                  else CLRBIT(PORTC,T_IO);
                SETBIT(PORTC,T_CLK);
                ucDa>>=1;
    }
}

/********************************************************************
*
* 名称: unsigned char ds1302_read_a_byte
* 说明:
* 功能: 从DS1302读取1Byte数据
* 调用:
* 输入:
* 返回值: t
***********************************************************************/
unsigned char ds1302_read_a_byte(void)
{
    unsigned char i,t;
        CLRBIT(DDRC,T_IO);
        CLRBIT(PORTC,T_IO);
    for(i=8; i>0; i--)
    {
      t>>=1;
                SETBIT(PORTC,T_CLK);
                nop();
                CLRBIT(PORTC,T_CLK);
                nop();
                if(CHKBIT(PINC,T_IO))t|=0x80;
        }
    SETBIT(DDRC,T_IO);
        return(t);
}


/********************************************************************
* 名称: write_1302
* 说明: 先写地址,后写命令/数据
* 功能: 往DS1302写入数据
* 调用: ds1302_write_a_byte()
* 输入: ucAddr: DS1302地址, ucDa: 要写的数据
* 返回值: 无
***********************************************************************/
void write_1302(unsigned char ucAddr, unsigned char ucDa)
{
    //DDRC=0xff;
    CLRBIT(PORTC,T_RST);   //T_RST=0
        //;;nop();
        CLRBIT(PORTC,T_CLK);       //T_CLK=0;
        //;;nop();
        SETBIT(PORTC,T_RST);       //T_RST=1

    ds1302_write_a_byte(ucAddr); /* 地址,命令 */
        CLRBIT(PORTC,T_CLK);
    ds1302_write_a_byte(ucDa); /* 写1Byte数据*/
        CLRBIT(PORTC,T_CLK);      //T_CLK=1
        //;;nop();
        CLRBIT(PORTC,T_RST);          //T_RST=0
}

/********************************************************************
* 名称: read_1302
* 说明: 先写地址,后读命令/数据
* 功能: 读取DS1302某地址的数据
* 调用: ds1302_write_a_byte() , ds1302_read_a_byte()
* 输入: ucAddr: DS1302地址
* 返回值: ucDa :读取的数据
***********************************************************************/
unsigned char read_1302(unsigned char ucAddr)
{
    unsigned char ucDa;
        CLRBIT(PORTC,T_RST);
        //;;nop();
        CLRBIT(PORTC,T_CLK);
        //;;nop();
        SETBIT(PORTC,T_RST);


    ds1302_write_a_byte(ucAddr); /* 地址,命令 */
    ucDa = ds1302_read_a_byte(); /* 读1Byte数据 */
        CLRBIT(PORTC,T_CLK);
        //;;nop();
        CLRBIT(PORTC,T_RST);
        //;;nop();
    return(ucDa);
}

/********************************************************************
* 名称: v_BurstW1302T
* 说明: 先写地址,后写数据(时钟多字节方式)
* 功能: 往DS1302写入时钟数据(多字节方式)
* 调用: ds1302_write_a_byte()
* 输入: pSecDa: 时钟数据地址 格式为: 秒 分 时 日 月 星期 年 控制
* 8Byte (BCD码) 1B 1B 1B 1B 1B 1B 1B 1B
* 返回值: 无
***********************************************************************/
void v_BurstW1302T(unsigned char *pSecDa)
{
    unsigned char i;
    write_1302(0x8e,0x00); /* 控制命令,WP=0,写操作?*/
        CLRBIT(PORTC,T_RST);
        CLRBIT(PORTC,T_CLK);
        SETBIT(PORTC,T_RST);

    ds1302_write_a_byte(0xbe); /* 0xbe:时钟多字节写命令 */
    for (i=8;i>0;i--) /*8Byte = 7Byte 时钟数据 + 1Byte 控制*/
    {
      ds1302_write_a_byte(*pSecDa);/* 写1Byte数据*/
      pSecDa++;
    }
        SETBIT(PORTC,T_CLK);
        CLRBIT(PORTC,T_RST);
}

/********************************************************************
* 名称: v_BurstR1302T
* 说明: 先写地址,后读命令/数据(时钟多字节方式)
* 功能: 读取DS1302时钟数据
* 调用: ds1302_write_a_byte() , ds1302_read_a_byte()
* 输入: pSecDa: 时钟数据地址 格式为: 秒 分 时 日 月 星期 年
* 7Byte (BCD码) 1B 1B 1B 1B 1B 1B 1B
* 返回值: ucDa :读取的数据
***********************************************************************/
void v_BurstR1302T(unsigned char *pSecDa)
{
    unsigned char i;
        //DDRC=0xff;
        CLRBIT(PORTC,T_RST);
        CLRBIT(PORTC,T_CLK);
        SETBIT(PORTC,T_RST);
    ds1302_write_a_byte(0xbf); /* 0xbf:时钟多字节读命令 */
    for (i=8; i>0; i--)
    {
      *pSecDa = ds1302_read_a_byte(); /* 读1Byte数据 */
      pSecDa++;
    }
        //DDRC=0xff;
        SETBIT(PORTC,T_CLK);
        CLRBIT(PORTC,T_RST);
}

/********************************************************************
* 名称: v_BurstW1302R
* 说明: 先写地址,后写数据(寄存器多字节方式)
* 功能: 往DS1302寄存器数写入数据(多字节方式)
* 调用: ds1302_write_a_byte()
* 输入: pReDa: 寄存器数据地址
* 返回值: 无
***********************************************************************/
void v_BurstW1302R(unsigned char *pReDa)
{
    unsigned char i;
    write_1302(0x8e,0x00); /* 控制命令,WP=0,写操作?*/
        CLRBIT(PORTC,T_RST);
        CLRBIT(PORTC,T_CLK);
        SETBIT(PORTC,T_RST);
    ds1302_write_a_byte(0xfe); /* 0xfe:寄存器多字节写命令 */
    for (i=31;i>0;i--) /*31Byte 寄存器数据 */
    {
      ds1302_write_a_byte(*pReDa); /* 写1Byte数据*/
      pReDa++;
    }
        SETBIT(PORTC,T_CLK);
        CLRBIT(PORTC,T_RST);
}


/********************************************************************
* 名称: v_BurstR1302R
* 说明: 先写地址,后读命令/数据(寄存器多字节方式)
* 功能: 读取DS1302寄存器数据
* 调用: ds1302_write_a_byte() , ds1302_read_a_byte()
* 输入: pReDa: 寄存器数据地址
* 返回值: 无
***********************************************************************/
void v_BurstR1302R(unsigned char *pReDa)
{
    unsigned char i;
        //DDRC=0xff;
        CLRBIT(PORTC,T_RST);
        CLRBIT(PORTC,T_CLK);
        SETBIT(PORTC,T_RST);
    ds1302_write_a_byte(0xff); /* 0xff:寄存器多字节读命令 */
    for (i=31; i>0; i--) /*31Byte 寄存器数据 */
    {
      *pReDa = ds1302_read_a_byte(); /* 读1Byte数据 */
      pReDa++;
    }
        //DDRC=0xff;
        SETBIT(PORTC,T_CLK);
        CLRBIT(PORTC,T_RST);
}

/********************************************************************
* 名称: v_Set1302
* 说明:
* 功能: 设置初始时间
* 调用: write_1302()
* 输入: pSecDa: 初始时间地址。初始时间格式为: 秒 分 时 日 月 星期 年
* 7Byte (BCD码) 1B 1B 1B 1B 1B 1B 1B
* 返回值: 无
//////IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
***********************************************************************/
void v_Set1302(unsigned char *pSecDa)
{
    unsigned char i;
    //unsigned char ucAddr = 0x80;
        unsigned char ucAddr = 0x8C;
    write_1302(0x8e,0x00); /* 控制命令,WP=0,写操作?*/
    for(i =7;i>0;i--)
    {
      write_1302(ucAddr,*pSecDa); /* 秒 分 时 日 月 星期 年 */

      pSecDa++;
       // ucAddr +=2;
           ucAddr -=2;
    }
    write_1302(0x8e,0x80); /* 控制命令,WP=1,写保护?*/
}
////IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
/********************************************************************
* 名称: v_Get1302
* 说明:
* 功能: 读取DS1302当前时间
* 调用: read_1302()
* 输入: ucCurtime: 保存当前时间地址。当前时间格式为: 秒 分 时 日 月 星期 年
* 7Byte (BCD码) 1B 1B 1B 1B 1B 1B 1B
* 返回值: 无
***********************************************************************/
void v_Get1302(unsigned char ucCurtime[])
{
    unsigned char i;
    //unsigned char ucAddr = 0x81;
        unsigned char ucAddr = 0x8D;
    for (i=0;i<7;i++)
    {
      ucCurtime = read_1302(ucAddr);/*格式为: 秒 分 时 日 月
      星期 年 */
      ucAddr -= 2;
    }
        CLRBIT(PORTC,T_CLK);
}

/*enable power charge of 1302*/

void LCD_1302(void)
{
   int i,j,k;
   for(i=0;i<7;i++)
   {
   j=buffer3/16;
   k=buffer3%16;
   Lcd_Write(j+48);
   Lcd_Write(k+48);
   }
}

const unsigned char WeekTab[] = {
      //闰年月星期表
(3 << 5) + 31,///1月
(6 << 5) + 29,///2月
(0 << 5) + 31,///3月
(3 << 5) + 30,///4月
(5 << 5) + 31,//5月
(1 << 5) + 30,//6月
(3 << 5) + 31,//7月
(6 << 5) + 31,//8月
(1 << 5) + 30,//9月
(4 << 5) + 31,//10月
(0 << 5) + 30,//11月
(2 << 5) + 31 //12月
};

/*!------------------------------------------------------------------------------
                              2000年~2099年星期算法
-------------------------------------------------------------------------------*/
unsigned char WeekDay20(unsigned char y, unsigned char m, unsigned char d)
{
unsigned char week, day;
day = WeekTab;///月表
week = day >> 5;///月星期数
day &= 0x1f;//月天数
if ((m < 3) && (y & 0x03))
                {///平年
    if (m == 2) day--;///平年月天数
    week++;///平年月表+1
}
y = y + (y >> 2);//年+年/4
week = (week +y + d + 2) % 7;///(星期=年+年/4+月表+2日)%7
return week;///返回星期
}
unsigned char BcdToBin(unsigned char val)
{
val = (val >> 4) *10+(val &0x0f); ///将BCD码转换为10进制数
return val; ///返回10进制数
}

unsigned char BinToBcd(unsigned char val)
{
return ((val / 10) *16+val % 10);
}

void main()
{
//unsigned char buffer2={0x45,0x07,0x20,0x11,0x04,0x5,0x08}; //初始数秒,分,时,日,
//月,星期,年
unsigned char buffer2={0x08,0x7,0x12,0x31,0x23,0x59,0x57}; //初始数秒,分,时,日,
//月,星期,年
buffer2=WeekDay20(BcdToBin(buffer2),BcdToBin(buffer2),BcdToBin(buffer2));

init_devices();
Lcd_Init(); //初始化LCD
initialize_1302();
v_Set1302(buffer2);



while(1)
{
Lcd_Command(0x80);               //设置显示位址
//asc_tran("2008-04-10-19-11");
v_Get1302(buffer3);
LCD_1302();
}
}

ljp_03071628 发表于 2008-4-12 12:06:05

说明:
液晶的ADJ端接50K的电位器,调整液晶的背光
有什么问题 Q:767085002

ljp_03071628 发表于 2008-4-12 12:08:48

非原创,移值+自己修改
菜鸟一个,多多指教

ljp_03071628 发表于 2008-4-12 12:12:17

在DS1302的8脚接电池供电,可以保证在单片机掉电的情况下时钟正常工作

stevenlu 发表于 2008-4-12 13:30:58

没有按键??我最近也在做这个

arale 发表于 2008-4-12 18:17:21

共同学习了,没有按键有点遗憾

eddia2000 发表于 2008-4-12 22:39:52

看下思路也不错。

ljp_03071628 发表于 2008-4-13 19:12:22

自己做着玩,提醒一句:DS1302的供电电压不是5V
5V时钟跑飞
3.3-4V

luyongganglyg 发表于 2013-12-13 14:25:52

{:biggrin:}

AMANHE 发表于 2014-4-20 13:43:17

{:lol:}{:lol:}{:lol:}{:lol:}{:lol:}{:lol:}{:lol:}{:lol:}

pengyuan0820 发表于 2014-4-28 16:56:05

语言也是C语言,和单片机有点类似

andmain999 发表于 2014-6-1 10:05:29

路过支持一下{:victory:}
页: [1]
查看完整版本: DS1302做的万年历-1602C液晶显示(atmega16-ICC)