每个数字时钟内部都有一个晶体来跟踪时间。这种晶体不仅存在于时钟中,而且存在于所有计算实时系统中。该晶体产生时钟脉冲,这是时序计算所必需的。虽然还有其他一些方法可以获得更高的精度和频率的时钟脉冲,但最首选的方法是使用晶体来跟踪时间。在这里,我们将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 端口。因此,这里使用了多路复用技术,使用较少的微控制器引脚连接多个七段。
七段显示器的 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。所有连接都显示在下面的电路图中:
对于一个显示板,使用两个七段显示器和 2 个 led。所以这里我们有五个不同的显示板来显示小时和分钟 (hh-mm) 中的时间,以及 dd-mm-yy 中的日期。
数字时钟的 pcb 设计和制造
对于这个基于 atmega16 的挂钟项目,我们设计了两个 pcb。一是控制单元,用于控制项目的所有操作,二是用于在七段显示器上显示时间和日期。显示部分包含五对0.8英寸七段显示器。因此,通过组装 5 个零件,我们就拥有了完整的数字时钟。多路复用 7 段显示器,5 块 pcb 的数据线将连接到控制单元的同一个端口,控制线连接到控制单元的不同引脚。
下面是一个显示板的 pcb 布局的顶视图和底视图,该显示板由两个七段显示器组成:
下面是控制单元 pcb 的顶视图和底视图
焊接后的几张电路板图片 如下所示。
测试数字时钟
本教程末尾给出了完整的代码,只需按照电路图连接pcb并将代码上传到atmega16。您将在十个七段显示屏上看到时间和日期。
可以使用控制单元上的四个按钮设置时间和日期。
/*
* 数字时钟.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数字)
计数=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&=(~(112)
计数=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)
{
设置时间();
设置时间();
}
}
}
强强联手!普渡携手高通打造行业首款四足配送机器人
“智慧灯杆+车路协同”,浙江绍兴首条智慧快速路正式通车!
房产能否升值还得靠智能家居
Q1季度全球PC市场销量同比下降8%,戴尔是唯一销量上涨的企业
移远通信LTE-A车规级模组AG525R-GL包揽全球重要认证
如何利用DS3231构建一个基于Atmega16的数字挂钟
位置服务:室内定位的现状和室内定位方案的选择
MS9940T电池管理芯片可pin对pin兼容BQ76940
可检测差分GPS校正信号的窄频移数字鉴别器电路
投影仪启动不开是怎么回事_投影仪无法启动如何解决(解决办法)
FLIR公司推出的Boson长波红外热像仪机芯特点及优势介绍
主板自带WiFi网卡与主板自带无线网卡的区别
气体流量开关安装和操作说明书之管道布线篇
颀中科技科创板成功上市!开盘涨34.71%,募资24.2亿扩充12吋封测产能
智能手机充电速度太慢的原因有哪些
为什么手机充电慢 8款手机对比测试
如何准备你自己的平行链项目
宝沃BX7 TS上手体验评测
活动预告|多领域,全流程,华大九天多地技术研讨会邀您参与
气焊的使用方法