每個數字時鐘內部都有一個晶體來跟蹤時間。這種晶體不僅存在于時鐘中,而且存在于所有計算實時系統中。該晶體產生時鐘脈沖,這是時序計算所必需的。雖然還有其他一些方法可以獲得更高的精度和頻率的時鐘脈沖,但最首選的方法是使用晶體來跟蹤時間。在這里,我們將DS3231 RTC IC 構建一個基于 Atmega16 的數字掛鐘。DS3231 RTC 內部有一個高精度晶體,因此不需要外部晶體振蕩器。
在這個數字時鐘項目中,十個 0.8 英寸的共陽極 7 段顯示器用于顯示時間和日期。這里使用七段顯示器來顯示小時、分鐘、日期、月份和年份。我們的 PCB 設計還具有顯示秒數和溫度的選項,可以通過添加更多顯示單元來顯示。
所需組件
ATmega16 AVR 微控制器
共陽極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<))<>
#define LEDPORT PORTA
#define secLed 5
#define BUZPORT 端口
#定義蜂鳴器 7
字符閃爍標志;
易失性字符 onFlag=0x00;
枚舉
{
小時=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瀏覽量
45819 -
DS3231
+關注
關注
2文章
51瀏覽量
23834 -
數字時鐘
+關注
關注
2文章
150瀏覽量
20332
發布評論請先 登錄
相關推薦
評論