0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何利用DS3231构建一个基于Atmega16的数字挂钟

科技观察员 来源:circuitdigest 作者:萨达姆 2022-09-08 15:34 次阅读

每个数字时钟内部都有一个晶体来跟踪时间。这种晶体不仅存在于时钟中,而且存在于所有计算实时系统中。该晶体产生时钟脉冲,这是时序计算所必需的。虽然还有其他一些方法可以获得更高的精度和频率的时钟脉冲,但最首选的方法是使用晶体来跟踪时间。在这里,我们将DS3231 RTC IC 构建一个基于 Atmega16 的数字挂钟。DS3231 RTC 内部有一个高精度晶体,因此不需要外部晶体振荡器

在这个数字时钟项目中,十个 0.8 英寸的共阳极 7 段显示器用于显示时间和日期。这里使用七段显示器来显示小时、分钟、日期、月份和年份。我们的 PCB 设计还具有显示秒数和温度的选项,可以通过添加更多显示单元来显示。

所需组件

ATmega16 AVR 微控制器

DS3231 实时时钟集成电路

共阳极0.8寸七段显示器(比普通尺寸显示器(0.56寸)大)

按钮

纽扣电池 3v

7805稳压器

1000uf电容

蜂鸣器(可选)

晶体管 BC547 和 BC557

10uf电容

100 欧姆电阻

1k电阻

10k电阻

PCB板

跳线

小贴士

电源适配器

用户也可以使用 Atmega32,它需要在生成十六进制之前在编译器中进行配置。

电路图及说明

这个数字挂钟电路有两个部分,一个是显示部分,在五个不同的 PCB 板上有 5 对 7 段,另一个是控制单元部分,负责从 RTC 芯片获取时间并将数据和时间发送到7段显示。由于我们使用了 10 个七段显示器,因此我们无法将每个显示器连接到单独的 IO 端口。因此,这里使用了多路复用技术,使用较少的微控制器引脚连接多个七段。

poYBAGMZmsKATJwjAAARItgKMP0899.png

七段显示器的 LED 引脚 a、b、c、d、e、f、g、h 与 atmega16 的 PORTB 并联。这里我们使用了 10 个七段显示器,所以我们需要 10 个控制引脚连接在 PORTD、PORTA 和 PORTC。

具有内部晶体的 RTC DS3231 连接到 PORTC 的 SDA 和 SCL 引脚,因为该芯片工作在 I2C 通信上。该芯片的接口方法与 DS1307 相同。我们已经将DS1307 与 Arduino、Raspberry Pi和8051 MCU一起使用。DS3231 和 DS1307 可以使用相同的代码。

两个 10k 上拉电阻连接在 SDA 和 SCL 线上。一个 3v 纽扣电池用于为 RTC 芯片供电,即使在主电源关闭时也能跟踪时间。每当电源再次恢复时,时间将开始显示在七段显示器上。现在我们在 PORT A 有一些设置时间的按钮,完整的过程在最后给出的视频中解释。5v 稳压器用于将输入电压转换为 5v。所有连接都显示在下面的电路图中:

poYBAGMZmr6AHcCtAAKWIdhrQ_Q507.png

对于一个显示板,使用两个七段显示器和 2 个 LED。所以这里我们有五个不同的显示板来显示小时和分钟 (HH-MM) 中的时间,以及 DD-MM-YY 中的日期。

pYYBAGMZmrqAOmv-AADHhpTZcx0647.png

poYBAGMZmreAP5iBAANcsU0PB3k991.png

数字时钟的 PCB 设计和制造

对于这个基于 Atmega16 的挂钟项目,我们设计了两个 PCB。一是控制单元,用于控制项目的所有操作,二是用于在七段显示器上显示时间和日期。显示部分包含五对0.8英寸七段显示器。因此,通过组装 5 个零件,我们就拥有了完整的数字时钟。多路复用 7 段显示器,5 块 PCB 的数据线将连接到控制单元的同一个端口,控制线连接到控制单元的不同引脚。

下面是一个显示板的 PCB 布局的顶视图和底视图,该显示板由两个七段显示器组成:

poYBAGMZmrKAVChJAAFpzC3WlLo095.png

下面是控制单元 PCB 的顶视图和底视图

poYBAGMZmq2AR1CTAAF2hUo2ETA374.png

焊接后的几张电路板图片 如下所示。

pYYBAGMZmqqAH_LLAARLL_am00c714.png

pYYBAGMZmqaAIhf4AAXGzGJrEqU912.png

测试数字时钟

教程末尾给出了完整的代码,只需按照电路图连接PCB并将代码上传到Atmega16。您将在十个七段显示屏上看到时间和日期。

pYYBAGMZmqKAU6R_AASuKdpT6Qk540.png

可以使用控制单元上的四个按钮设置时间​​和日期。

/*

* 数字时钟.c

#include

#define F_CPU 8000000UL

#include

#include

int day=6,dd=1,mm=3,yy=19;

无符号整数秒,分钟=13,小时=4;

常量无符号整数[]={0X40,0X79,0X24,0X30,0X19,0X12,0X02,0X78,0X00,0X10};

诠释 d0,d1,d2,d3,d4,d5,d6,d7,d8,d9;

易失的无符号整数计数,计数1;

#定义数字13

#define 数据端口 PORTB

#define controlPortD 端口

#define controlPortC PORTC

#define controlPortA PORTA

#define controlPortD_Mask 0x83

#define controlPortC_Mask 0x03

#define controlPortA_Mask 0x7F

#define 段关闭 -1

#define sw PINA

#定义集 4

#定义好 3

#向上定义2

#向下定义 1

#define setEvent (sw & (1<))<>

#define okEvent (sw & (1<))<>

#define upEvent (sw & (1<))<>

#define downEvent (sw & (1<))<>

#define LEDPORT PORTA

#define secLed 5

#define BUZPORT 端口

#定义蜂鸣器 7

字符闪烁标志;

易失性字符 onFlag=0x00;

#define timeFormat 24

枚举

{

小时=1,

分钟,

日期,

月,

年,

};

字符 segOn[12]={0x04,0x08,0x10,0x20,0x40,0x80,0x40,0x80,0x10,0x20,0x04,0x08};

无效显示();

无效更新时间();

ISR(TIMER1_OVF_vect)

{

展示();

TCNT1 = 64000;

}

无效选择段(整数计数)

{

如果(计数 < 5)

{

controlPortA&=controlPortA_Mask;

controlPortC&=controlPortC_Mask;

controlPortD&=controlPortD_Mask;

controlPortD|=segOn[计数];

}

否则如果(计数 == 5)

{

controlPortA|=segOn[计数];

controlPortC&=controlPortC_Mask;

controlPortD&=controlPortD_Mask;

}

否则如果(计数 == -1)

{

controlPortA&=controlPortA_Mask;

controlPortC&=controlPortC_Mask;

controlPortD&=controlPortD_Mask;

}

别的

{

controlPortA&=controlPortA_Mask;

controlPortC&=controlPortC_Mask;

controlPortD&=controlPortD_Mask;

controlPortC|=segOn[计数];

}

}

无效段(整数计数,整数段)

{

如果(闪烁标志 == 段)

{

如果(onFlag)

选择段(段关闭);

别的

选择段(计数);

}

别的

{

选择段(计数);

}

}

无效显示()

{

计数1++;

如果(计数 1>400)

{

计数1=0;

onFlag=!onFlag;

}

计数++;

如果(计数>数字)

计数=0;

开关(count%digit)

{

案例0:

段(计数,分钟);

数据端口=num[d0];

休息;

情况1:

段(计数,分钟);

数据端口=num[d1];

休息;

案例2:

段(计数,小时);

数据端口=num[d2];

休息;

案例3:

段(计数,小时);

数据端口=数字[d3];

休息;

案例4:

段(计数,日期);

数据端口=num[d4];

休息;

案例5:

段(计数,日期);

数据端口=数字[d5];

休息;

案例6:

段(计数,月);

数据端口=数字[d6];

休息;

案例7:

段(计数,月);

数据端口=数字[d7];

休息;

案例8:

段(计数,年份);

数据端口=数字[d8];

休息;

案例9:

段(计数,年份);

数据端口=num[d9];

休息;

}

}

无效 timer1_init()

{

// 使用预分频器 = 8 设置定时器

TCCR1B |= (1 << CS11);

//TCCR1B &= ~(1 << CS10);

//TCCR1B &= (1 << CS11);

//TCCR1B &= ~(1 << CS12);

TCNT1 = 63500;

TIMSK |= (1 << TOIE1);

sei();

}

int bcdtochar(字符数)

{

返回 ((num/16 * 10) + (num % 16));

}

int decobcd(字符数)

{

返回 ((num/10)<<4) + (num % 10);

}

无效 RTC_start()

{

TWCR=(1<)|(1<

而((TWCR&0x80)==0x00);

}

无效设备()

{

TWDR=0xD0;//RTC写入(从地址)

TWCR=(1<)|(1<

而(!(TWCR&(1<)));<>

TWDR=0x00;// 字地址写入

TWCR=(1<)|(1<

而(!(TWCR&(1<)));<>

}

无效 RTC_stp()

{

TWCR=(1<)|(1<

}

无效 RTC_read()

{

TWCR=(1<)|(1<

而((TWCR&0x80)==0x00);

TWDR=0xD0;//RTC写入(从地址)

TWCR=(1<)|(1<

而(!(TWCR&(1<)));<>

TWDR=0x00;//RTC写入(字地址)

TWCR=(1<)|(1<

而(!(TWCR&(1<)));<>

TWCR=(1<)|(1<

而 ((TWCR&0x80)==0x00);

TWDR=0xD1;// RTC 命令读取

TWCR=(1<)|(1<

而(!(TWCR&(1<)));<>

}

无效 sec_init(无符号字符 d)

{

TWDR=d; //第二次初始化

TWCR=(1<)|(1<

而(!(TWCR&(1<)));<>

}

void min_init(unsigned char d)

{

TWDR=d; //分钟初始化

TWCR=(1<)|(1<

而(!(TWCR&(1<)));<>

}

无效 hr_init(无符号字符 d)

{

TWDR=d; //小时初始化

TWCR=(1<)|(1<

而(!(TWCR&(1<)));<>

}

void day_init(unsigned char d)

{

TWDR=d; //天数初始化

TWCR=(1<)|(1<

而(!(TWCR&(1<)));<>

}

无效日期初始化(无符号字符 d)

{

TWDR=d; //日期初始化

TWCR=(1<)|(1<

而(!(TWCR&(1<)));<>

}

无效month_init(无符号字符d)

{

TWDR=d; //月份初始化

TWCR=(1<)|(1<

而(!(TWCR&(1<)));<>

}

无效 yr_init(无符号字符 d)

{

TWDR=d; //年份初始化

TWCR=(1<)|(1<

而(!(TWCR&(1<)));<>

}

int sec_rw()

{

诠释克[3];

TWCR|=(1<)|(1<

而((TWCR & 0x80)==0x00);

返回 bcdtochar(TWDR)​​;

}

int min_rw()

{

TWCR|=(1<);>

TWCR|=(1<);<>

而((TWCR & 0x80)==0x00);

返回 bcdtochar(TWDR)​​;

}

int hr_rw()

{

TWCR|=(1<)|(1<

而((TWCR & 0x80)==0x00);

返回 bcdtochar(TWDR)​​;

}

int day_rd()

{

TWCR|=(1<)|(1<

而((TWCR&0x80)==0x00);

返回 bcdtochar(TWDR)​​;

}

int date_rw()

{

TWCR|=(1<)|(1<

而((TWCR & 0x80)==0x00);

返回 bcdtochar(TWDR)​​;

}

int month_rw()

{

TWCR|=(1<)|(1<

而((TWCR & 0x80)==0x00);

返回 bcdtochar(TWDR)​​;

}

int yr_rw()

{

TWCR|=(1<);>

TWCR&=(~(1<));<>

而((TWCR & 0x80)==0x00);

返回 bcdtochar(TWDR)​​;

}

无效的设置时间()

{

RTC_start();

设备();

sec_init(0);

min_init(dectobcd(min));

hr_init(dectobcd(hr));

day_init(dectobcd(天));

date_init(dectobcd(dd));

month_init(dectobcd(mm));

yr_init(dectobcd(yy));

RTC_stp();

}

无效 RTC()

{

RTC_read();

sec=sec_rw();

min=min_rw();

hr=hr_rw();

day=day_rd();

dd=date_rw();

mm=month_rw();

yy=yr_rw();

RTC_stp();

}

char getPara(字符数)

{

而(1)

{

更新时间();

如果(!upEvent)

{

计数1=0;

onFlag=0x00;

计数++;

如果(闪烁标志 == 小时)

{

如果(时间格式 == 12)

{

如果(计数>12)

计数=0;

}

别的

{

如果(计数 > 23)

计数=0;

}

小时=计数;

}

否则如果(blinkFlag == 分钟)

{

如果(计数> 59)

计数=0;

分钟=计数;

}

否则如果(blinkFlag == 月)

{

如果(计数 > 12)

计数=1;

毫米=计数;

}

否则如果(blinkFlag == 日期)

{

if(mm == 4 || mm == 6 || mm == 9 || mm == 11)

{

如果(计数 > 30)

计数=1;

}

否则 if(mm == 1 || mm == 3 || mm == 5 || mm == 7 || mm == 8 || mm == 10 || mm == 12)

{

如果(计数 >31)

计数=1;

}

别的

{

int y=2000+yy;

如果(y/4 == 0 && y/400 == 0)

{

如果(计数 > 29)

计数=1;

}

别的

{

如果(计数 > 28)

计数=1;

}

}

dd=计数;

}

否则如果(blinkFlag == 年)

{

如果(计数 >99)

计数=0;

YY=计数;

}

_delay_ms(200);

}

否则如果(!(downEvent))

{

数数 - ;

如果(闪烁标志 == 年)

{

如果(计数<0)

计数=99;

}

_delay_ms(100);

}

否则如果(!okEvent)

{

_delay_ms(1000);

返回计数;

}

}

}

无效设置时间()

{

闪烁标志=1;

hr=getPara(hr);

闪烁标志++;

min=getPara(min);

闪烁标志++;

dd=getPara(dd);

闪烁标志++;

mm=getPara(mm);

闪烁标志++;

yy=getPara(yy);

闪烁标志=0;

}

无效更新时间()

{

d0=min%10;

d1=分钟/10;

d2=hr%10;

d3=小时/10;

d4=dd%10;

d5=dd/10;

d6=mm%10;

d7=mm/10;

d8=yy%10;

d9=yy/10;

}

诠释主要(无效)

{

无符号长整数时间;

DDRB=0xff;

DDRA=0xE0;

端口=0x1E;

DDRD=0xff;

DDRC=0xff;

timer1_init();

而(1)

{

实时时钟();

更新时间();

_delay_ms(500);

LEDPORT|=1<;<>

_delay_ms(500);

LEDPORT&=~(1<);<>

如果(!setEvent)

{

设置时间();

设置时间();

}

}

}

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • ATmega16
    +关注

    关注

    5

    文章

    154

    浏览量

    45557
  • DS3231
    +关注

    关注

    2

    文章

    51

    浏览量

    23732
  • 数字时钟
    +关注

    关注

    2

    文章

    144

    浏览量

    20118
收藏 人收藏

    评论

    相关推荐

    基于DS3231的高精度时钟接口设计

    、工作原理以及引脚功能,设计其与微控制器进行通信时的软件、硬件接口,并给出相应的原理图与流程图,此方案对DS3231般的电路系统设计中具有通用性。由于DS3231是目前精度最高,并集成有温补振荡器
    发表于 04-24 09:01

    实时时钟芯片DS3231应用笔记,使用指南,FAQ全集

    ,并采用低成本、标准型、16引脚SOIC封装。在-40°C至+85°C温度范围内,计时精度为±2分钟/年。这出色性能使DS3231成为当前要求高计时精度应用的最佳解决方案。而RTC的其它集成功能也
    发表于 03-14 11:05

    【以前的小制作分享】基于ATMEGA16DS3231DS18B20的高精度日历温度显示

    最近论坛申请板子,听说分享帖可以为申请加分。这是很早之前完成的日历温度显示,ATMEGA16为8位AVR单片机,DS3231DS18B20分为是DALLAS公司的高精度RTC和高精度温度芯片。1.
    发表于 11-04 22:06

    DS3231的接线方法及源代码

    3.DS3231的接线方法 DS3231时钟模块,通信用的是IIC接口在这只用到DS3231时钟模块的SCL,SDA,VCC,GND四针脚即可设定读出时间和温度,下面是接线方法。
    发表于 08-17 14:43

    DS3231时钟星期不对

    做了DS3231时钟,可是星期每次都不对,加上autoweek函数后,按键的的值就写不到DS3231中了,不加autoweek可以挑时间,可以走,就是星期不对。求解答?
    发表于 06-20 04:35

    DS3231时钟芯片结构

    目录、模块简介DS3231时钟芯片结构原理引脚图内部结构图DS3231典型应用电路DS3231时钟芯片结构二、与stm32通信1、配置IO2、初始化与函数3、主函数调用4、使用源码
    发表于 08-09 06:31

    DS3231时钟芯片读写程序分享

    @[TOC](咚咚咚————【封装驱动】DS3231时钟芯片读写程序,分享交流自己编写的程序。/********************************************主控芯片
    发表于 12-13 07:14

    如何将DS3231 RTC模块与NodeMCU连接

    ESP8266智能灯项目​viadean.com接口如何将DS3231 RTC模块与NodeMCU连接。学习在串行监视器上设置和显示DS3231的时间。首先,让我们从DS3231实时时钟模块的基础知识...
    发表于 01-25 07:23

    如何使用NUC240利用I2C控制DS3231

    应用:示例使用 NUC240 来使用 I2C 控制 DS3231 BSP 版本: NUC230/240 Series BSP CMSIS v3.01.001 硬件
    发表于 08-22 06:44

    DS3231芯片手册中文版

    DS3231芯片手册中文版,内部存储BCD码
    发表于 12-11 11:00 0次下载

    ds3231时钟模块怎么用_DS3231的操作与使用

    DS3231是一款高精度I2C实时时钟器件,具有集成的温度补偿晶体振荡器。该器件包含电池输入端,断开主电源时仍可保持精确计时。集成的晶体振荡器可提高器件的长期精确度。DS3231的寄存器能保存秒、分、时、星期、日期、月、年和闹钟设置等信息。
    发表于 01-29 11:23 10.1w次阅读
    <b class='flag-5'>ds3231</b>时钟模块怎么用_<b class='flag-5'>DS3231</b>的操作与使用

    ATmega8单片机与时钟器件DS3231的接口设计

    软件设计中,首先要对AVR单片机ATmega8与实时钟器件DS3231进行初始化,给DS3231准确的日期和时间。不论主控模式还是被控模式,都应当将TWI控制寄存器TWCR的TWEN位置为1,从而使能TWI模块
    发表于 01-29 14:54 4295次阅读
    <b class='flag-5'>ATmega</b>8单片机与时钟器件<b class='flag-5'>DS3231</b>的接口设计

    ds3231中文资料汇总(ds3231引脚图及特性参数_应用电路)

    精确的计时。集成晶振提高了器件的长期精确度,并减少了生产线的元件数量。DS3231提供商用级和工业级温度范围,采用16引脚300mil的SO封装。
    发表于 04-10 17:02 7.8w次阅读
    <b class='flag-5'>ds3231</b>中文资料汇总(<b class='flag-5'>ds3231</b>引脚图及特性参数_应用电路)

    匠辉电子DS3231芯片介绍

    匠辉电子DS3231芯片介绍。
    发表于 05-27 09:47 0次下载

    基于Arduino Mege 2560的数字挂钟

    使用 Arduino Mega 2560、5054 LED 灯条、DS3231 RTC、IRFZ44N MOSFET 晶体管和铝型材制作大型数字挂钟
    发表于 12-08 17:50 3次下载