极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 130094|回复: 77

发个DS3231的简易时钟,1602液晶显示、串口修改时间

  [复制链接]
发表于 2014-5-20 13:10:57 | 显示全部楼层 |阅读模式
本帖最后由 尕老汉 于 2014-5-20 13:15 编辑

     来极客工坊学习一个多月了,收获很大。以前学过单片机,加上论坛里的各位前辈无私的奉献,现在学arduino很快上手,十分感谢极客工坊这个大家庭。
    最近买了一块DS3231时钟模块,测试了3天,发现走时非常准确,一秒不差。 以前学单片机时用ds1302做过一个简易时钟,一天的误差在5秒左右,需要经常去校时。来上个照片







      在论坛里搜索了一下关于DS3231的应用,发现不是很多,就打算将原来ds1302的程序移植到arduino上,但是将时钟芯片换成DS3231。因为DS3231走时比较准确,不需要经常校时,打算程序里去除用按键修改时间的程序部分。改为用串口发送字符串来修改时间。另外,我个人认为桌面时钟就是看时间用的,加上闹钟的功能并不实用。所以程序里也没有闹钟的功能。

简单介绍一下DS3231:
1、I2C接口;
2、实时时钟产生秒、分、时、星期、日期、月和年计时,并提供有效期到2100年的闰年补偿;
3、两个日历闹钟;
4、内部集成了一个数字温度传感器(64秒更新一次)
5、可编程方波输出

****************************************      硬件连接    ********************************************

1602液晶连接、程序可参考 http://www.geek-workshop.com/thread-78-1-1.html
采用4线接法,顺便盗个图



UNO  与  1602液晶连接
6      ->     D7
7      ->     D6
8      ->     D5
9      ->     D4
10     ->    EN
11     ->    RW
12     ->    RS


DS3231连接、程序可参考 http://www.geek-workshop.com/thread-7564-1-1.html
顺便盗个图



UNO  与  DS3231连接
A4     ->     SDA
A5     ->     SCL

****************************************      程序部分    ********************************************

[pre lang="arduino" line="1" file="DS3231"]
#include <DS3231.h>
#include <Wire.h>

DS3231 Clock;
bool Century=false;
bool h12;
bool PM;
byte ADay, AHour, AMinute, ASecond, ABits;
bool ADy, A12h, Apm;

int year, month, date, DoW,week , hour, minute, second,temperature;

String comdata = "";
int numdata[7] = {0},  mark = 0;
/*1602液晶与UNO连接引脚
6 -> D7
7 -> D6
8 -> D5
9 -> D4
*/

int LCD1602_RS=12;   
int LCD1602_RW=11;   
int LCD1602_EN=10;   
int DB[] = { 6, 7, 8, 9};

char dis1[16]={0},dis2[16]={0};

char self_char[]={                               //1602液晶自定义符号   
        0x08,0x0f,0x12,0x0f,0x0a,0x1f,0x02,0x02, //年
        0x0f,0x09,0x0f,0x09,0x0f,0x09,0x13,0x01, //月
        0x0f,0x09,0x09,0x0f,0x09,0x09,0x0f,0x00, //日
        0x18,0x18,0x07,0x08,0x08,0x08,0x07,0x00, //温度标志— —摄氏度
        0x00,0x04,0x0E,0x1F,0x0E,0x04,0x00,0x00, //符号◆
        0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, //全开
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00         //
                                           };

void LCD_Command_Write(int command)             //写指令
{
int i,temp;
digitalWrite( LCD1602_RS,LOW);
digitalWrite( LCD1602_RW,LOW);
digitalWrite( LCD1602_EN,LOW);

temp=command & 0xf0;
for (i=DB[0]; i <= 9; i++)
{
   digitalWrite(i,temp & 0x80);
   temp <<= 1;
}

digitalWrite( LCD1602_EN,HIGH);
delayMicroseconds(1);
digitalWrite( LCD1602_EN,LOW);

temp=(command & 0x0f)<<4;
for (i=DB[0]; i <= 9; i++)
{
   digitalWrite(i,temp & 0x80);
   temp <<= 1;
}

digitalWrite( LCD1602_EN,HIGH);
delayMicroseconds(1);
digitalWrite( LCD1602_EN,LOW);
}

void LCD_Data_Write(int dat)                //写数据
{
int i=0,temp;
digitalWrite( LCD1602_RS,HIGH);
digitalWrite( LCD1602_RW,LOW);
digitalWrite( LCD1602_EN,LOW);

temp=dat & 0xf0;
for (i=DB[0]; i <= 9; i++)
{
   digitalWrite(i,temp & 0x80);
   temp <<= 1;
}

digitalWrite( LCD1602_EN,HIGH);
delayMicroseconds(1);
digitalWrite( LCD1602_EN,LOW);

temp=(dat & 0x0f)<<4;
for (i=DB[0]; i <= 9; i++)
{
   digitalWrite(i,temp & 0x80);
   temp <<= 1;
}

digitalWrite( LCD1602_EN,HIGH);
delayMicroseconds(1);
digitalWrite( LCD1602_EN,LOW);
}

void LCD_SET_XY( int x, int y )//指定坐标,x为列,0~15,y为行,0为第一行,1为第二行。
{
  int address;
  if (y ==0)    address = 0x80 + x;
  else          address = 0xC0 + x;
  LCD_Command_Write(address);
}

void LCD_Write_Char( int x,int y,int dat)  //指定位置一个字符
{
  LCD_SET_XY( x, y );
  LCD_Data_Write(dat);
}

void LCD_Write_String(int X,int Y,char *s)  //指定位置字符串
{
    LCD_SET_XY( X, Y );    //设置地址
    while (*s)             //写字符串
    {
      LCD_Data_Write(*s);   
      s ++;
    }
}

void setup (void)
{
  Serial.begin(9600);
  int i = 0;
  for (i=6; i <= 12; i++)
   {
     pinMode(i,OUTPUT);
   }

  delay(100);
  LCD_Command_Write(0x28);//4线 2行 5x7
  delay(50);
  LCD_Command_Write(0x06);
  delay(50);
  LCD_Command_Write(0x0c);
  delay(50);
  LCD_Command_Write(0x80);
  delay(50);
  LCD_Command_Write(0x01);
  delay(50);

    diy();              //开机问候
  //Wire.begin();
  Serial.println("set_time :");
  Serial.println("year mouth day week hour minute second");
  Serial.println();
  Serial.println("week : 1 -> Sunday; 2 -> Monday; 3 -> Tuesday:  ....7 -> Saturday");
  Serial.println();
  Serial.println("for example :2014-5-20 Tue 0:33:30  ");
  Serial.println("set_time :");
  Serial.println("14 5 20 3 0 33 30");
  Serial.println();
}
       

void diy()
{
     char a;
  LCD_Command_Write(0x40);   
     for(a=0;a<64;a++)
        {
          LCD_Data_Write(self_char[a]);
          delay(1);
        }
    delay(50);
  LCD_Write_String(0,0," Digital Clock  ");
  LCD_Write_String(0,1," Geek-workshop  ");
  delay(2000);
  LCD_Command_Write(0x01);  
  delay(10);
  LCD_Write_String(0,0,"Today is new day");
  LCD_Write_String(0,1,"Dream come true!");
  delay(2000);
  LCD_Command_Write(0x01);
delay(10);           
}

void ReadDS3231()          //读取DS3231 参数
{
  Wire.begin();

  second=Clock.getSecond();
  minute=Clock.getMinute();
  hour=Clock.getHour(h12,PM);
  week=Clock.getDoW();   
  date=Clock.getDate();
  month=Clock.getMonth(Century);
  year=Clock.getYear();
  temperature=Clock.getTemperature();
  
}

void get_dis()          //1602液晶上每一位上显示的数据
{
  ReadDS3231();
  dis1[0]='2';
  dis1[1]='0';
  dis1[2]=0x30+year/10;
  dis1[3]=0x30+year%10;
  dis1[4]=0;
  dis1[5]=0x30+month/10;
  dis1[6]=0x30+month%10;
  dis1[7]=1;
  dis1[8]=0x30+date/10;
  dis1[9]=0x30+date%10;
  dis1[10]=2;
  dis1[11]=' ';
  dis1[12]=' ';
  switch(week)
  {
        case 2: {
                          dis1[13]='M';
                          dis1[14]='o';
                          dis1[15]='n';
                        }
                        break;
        case 3: {
                          dis1[13]='T';
                          dis1[14]='u';
                          dis1[15]='e';
                        }
                        break;
        case 4: {
                          dis1[13]='W';
                          dis1[14]='e';
                          dis1[15]='d';
                        }
                        break;
        case 5: {
                          dis1[13]='T';
                          dis1[14]='h';
                          dis1[15]='u';
                        }
                        break;
        case 6: {
                          dis1[13]='F';
                          dis1[14]='r';
                          dis1[15]='i';
                        }
                        break;
        case 7: {
                          dis1[13]='S';
                          dis1[14]='a';
                          dis1[15]='t';
                        }
                        break;
        case 1: {
                          dis1[13]='S';
                          dis1[14]='u';
                          dis1[15]='n';
                        }
                        break;
  }
  dis2[0]=' ';
  dis2[1]=0x30+hour/10;
  dis2[2]=0x30+hour%10;
  dis2[3]=':';
  dis2[4]=0x30+minute/10;
  dis2[5]=0x30+minute%10;
  dis2[6]=':';
  dis2[7]=0x30+second/10;
  dis2[8]=0x30+second%10;
  dis2[9]=' ';
  
        dis2[10]=' ';
  dis2[11]=0x30+temperature/10;
  dis2[12]=0x30+temperature%10;
  dis2[13]='.';
  dis2[14]=0x30+0;
  dis2[15]=3;
}
void play()                  //1602显示完整时间
{
       get_dis();

            int k;      
            LCD_SET_XY( 0,0);
            for(k=0;k<16;k++)
            LCD_Data_Write(dis1[k]);
            LCD_SET_XY( 0,1);
            for(k=0;k<16;k++)
            LCD_Data_Write(dis2[k]);

}

void set_time()               //DS3231设置时间
{
Wire.begin();
Clock.setSecond(numdata[6]); //秒
Clock.setMinute(numdata[5]); //分
Clock.setHour(numdata[4]);   //时
Clock.setDoW(numdata[3]);    //周
Clock.setDate(numdata[2]);   //日
Clock.setMonth(numdata[1]);  //月
Clock.setYear(numdata[0]);   //年
}

void loop (void)
{
     int j = 0;
  while (Serial.available() > 0)    //检测串口是否有数据
  {
    comdata += char(Serial.read());
    delay(2);
    mark = 1;
     play();
  }

  if(mark == 1)  
  {
    Serial.println(comdata);             //串口打印检测到的数据
    for(int i = 0; i < comdata.length() ; i++)
    {
      if(comdata == ' ')
      {
        j++;
      }
      else
      {
        numdata[j] = numdata[j] * 10 + (comdata - '0');
      }
    }

    comdata = String("");
   Serial.print("set_time... ");
    set_time();
    Serial.println(" OK ");
    for(int i = 0; i < 7; i++)
    {
      numdata = 0;
    }
    mark = 0;
  }
    play();
}[/code]


其中串口字符串转换部分参考 http://www.geek-workshop.com/thread-260-1-1.html

****************************************      串口校时    ********************************************

打开arduino 串口监视器



输入要设定日期以及时间
格式为(年+空格+月+空格+日+空格+星期+空格+时+空格+分+空格+秒)

设置中星期:01对应星期天;02对应星期一;03对应星期二;……07对应星期六

例如:现在是 2014年5月20日 星期二 13:35:00
那么在串口数据发送栏中输入   : 14 05 20 03 13 35 00



********************************       工作照(请无视凌乱的杜邦线)     ********************************

下面的单片机开发板只是为了给1602液晶引线用,方便接线而已







工作中。。。。。



1602液晶显示的年月日  是不是很有感觉!

喜欢么?喜欢就给赞一个吧!  

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2014-5-20 16:35:00 | 显示全部楼层
   老霍是吧!
回复 支持 反对

使用道具 举报

发表于 2014-5-20 16:36:04 | 显示全部楼层
回复 支持 反对

使用道具 举报

发表于 2014-5-20 21:34:51 | 显示全部楼层
{:soso_e179:}厉害 请问play()这个是神马意思啊?
回复 支持 反对

使用道具 举报

发表于 2014-5-21 08:51:25 | 显示全部楼层
jikecyatmcn 发表于 2014-5-20 21:34
厉害 请问play()这个是神马意思啊?

play()就是将 get_dis()函数换算好的dis1[]、dis2[]数据按2行、每行16个的格式显示在1602液晶上。
回复 支持 反对

使用道具 举报

发表于 2014-5-21 22:40:06 | 显示全部楼层
如何用GPS校时??
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-5-22 15:57:51 | 显示全部楼层
huangshan78 发表于 2014-5-21 22:40
如何用GPS校时??

上面没有提到GPS校时,论坛里有人发过用GPS校时的时钟,你搜一下就知道了
回复 支持 反对

使用道具 举报

发表于 2014-5-28 14:31:42 | 显示全部楼层
找个时间 买块ds3231回来 玩玩
回复 支持 反对

使用道具 举报

发表于 2014-8-27 15:43:44 | 显示全部楼层
装好了,试着不错。就是一开机显示乱码,要按reset重启才能正常显示
回复 支持 反对

使用道具 举报

发表于 2014-8-27 15:44:28 | 显示全部楼层
温度从哪检测的?
回复 支持 反对

使用道具 举报

发表于 2014-8-27 15:54:48 | 显示全部楼层
3231内置温度传感器
回复 支持 反对

使用道具 举报

发表于 2014-9-30 01:04:58 | 显示全部楼层
请问实物图上竖起来的三极管起什么作用?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-9-30 21:11:28 | 显示全部楼层
iambic 发表于 2014-9-30 01:04
请问实物图上竖起来的三极管起什么作用?

温度传感器,lm35,18b20都可以
回复 支持 反对

使用道具 举报

发表于 2014-9-30 22:19:14 | 显示全部楼层
尕老汉 发表于 2014-9-30 21:11
温度传感器,lm35,18b20都可以


温度传感器不是内置的吗? 为什么还有一个外置温度传感器? 是更精确吗?

这个外置的是如何接线?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-10-2 20:08:03 | 显示全部楼层
iambic 发表于 2014-9-30 22:19
温度传感器不是内置的吗? 为什么还有一个外置温度传感器? 是更精确吗?

这个外置的是如何接线?

ds3231是内置温度传感器,但是64秒更新一次,不知道是这芯片本来就是这样设计,还是库代码原因(不会修改库代码)。论坛里有lm35,18b20教程你可以去参考下
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-3-29 18:24 , Processed in 0.041880 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表