1. 程式人生 > >點陣之路_STC15微控制器+8*16點陣+DS1302時鐘

點陣之路_STC15微控制器+8*16點陣+DS1302時鐘

資源共享一下,8*16點陣系列的程式,自己參考例程寫的,不太完善還望多多包涵!

對應此文章應該是檔名字為下圖的資料夾!

硬體介紹

1. 主控: STC15F2K60S2

      

2. 點陣: 1588BR 8*8點陣 經過測試發現型號為 788BS的8*8的點陣引腳也如下,可以通用,只是大小不一樣!

       

3. 放大電路:S8050 NPN三極體,5.1k電阻,470Ω電阻。

4. 時鐘電路:DS1302 時鐘模組

實物圖片

1. 主控,STC-15最小系統板

2. DS1302時鐘模組

3. 點陣顯示及放大部分(之前陽極用的1k的電阻,驅動電流有點大,三極體也燙手,導致點陣燒了很多LED,後來換成5.1k電阻,三極體也不那麼燙了,這個只是初步的,後邊在做點陣的話,可以用74HC138,或者TM1640(這個晶片特別好用),然後現在就想從基礎的開始,自己焊接一下電路板什麼的。)

4. 整體的,時間顯示

5. 整體的,日期顯示

6. 整體的,星期顯示

7. 整體的,年份顯示

設計思路

  • 程式簡單電路圖

大概的電路簡圖就是這個樣子的,但是有一點需要特別注意

整個點陣模組的供電不要接在微控制器最小系統上,需要另外接5V,或者3.3V單獨供電,然後再與最小系統板共地。

如果點陣模組的供電接在最小系統,可能出現的問題是,微控制器重新編譯並下載程式後,可能程式還沒開始執行,但是點陣已經通電了,出現的情況就是,點陣全滅,需要重新給點陣通電才可以,這個時候如果另外接點陣的供電電源即可解決問題!

點陣取模

行:第一塊點陣和第二塊點陣的陽極接一塊,經過S8050,5.1K電阻接微控制器P2口,最上邊第一行是I/O口高位,取模時要注意!

列:兩塊點陣的陰極分別接S8050,5.1K電阻接到微控制器,第一塊接P0口,第二塊接P1口,每塊最左邊均是I/O口最低位!

取模方式如下,不太懂的好好看看取模說明,另外,取模只跟硬體連線有關,一旦硬體確定,取模方式也隨之固定,不會因為程式寫法不一樣而改變取模方式,之前我都把這點搞錯了!

下邊這個是我自己取的模,可以參考一下!想要什麼圖案,都可以自己用軟體去畫,或者直接用字元生成即可。

// 靜態陣列 數字庫 3*8點陣取模
u8 code number_library[] = {
0x7F,0x41,0x7F,/*"0",0*/
0x21,0x7F,0x01,/*"1",0*/
0x4F,0x49,0x79,/*"2",0*/
0x49,0x49,0x7F,/*"3",0*/
0x78,0x08,0x7F,/*"4",0*/
0x79,0x49,0x4F,/*"5",0*/
0x7F,0x49,0x4F,/*"6",0*/
0x40,0x40,0x7F,/*"7",0*/
0x7F,0x49,0x7F,/*"8",0*/
0x79,0x49,0x7F,/*"9",0*/	
};

// 靜態陣列  中間冒號字型檔 	2*8點陣取模
u8 code sign_library[] = {
0x36,0x36,		/*   冒號    */
0x08,0x08,		/*    --    */
};	

// 靜態陣列  星期陣列庫		10*8點陣取模
u8 code week_library[] = {
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,/*"週一",0*/
0x04,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x04,/*"週二",0*/
0x02,0x22,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x22,0x02,/*"週三",0*/
0x7F,0x41,0x45,0x7D,0x41,0x41,0x7D,0x45,0x41,0x7F,/*"週四",0*/
0x00,0x21,0x29,0x29,0x3F,0x29,0x29,0x2F,0x21,0x00,/*"週五",0*/
0x11,0x12,0x14,0x18,0x70,0x70,0x18,0x14,0x12,0x11,/*"週六",0*/
0x00,0x00,0x7F,0x49,0x49,0x49,0x49,0x7F,0x00,0x00,/*"週日",0*/
};

程式

簡單的對程式進行一個介紹,裡邊很多註釋,應該可以看的懂。

  • 程式變數,陣列定義

disbuffer_sign :是一個標誌位,當標誌位為0/1的時候,改變動態陣列 disbuffer1 裡邊的內容,為1/0,改變 disbuffer2。這樣做的好處是,當前正用於顯示的 陣列 不會在顯示的時候被改變陣列內容。防止亂碼出現,比如正在顯示 disbuffer1 數組裡邊的內容,就改變 disbuffer2 數組裡邊的內容。

u8 *disbuffer :全域性指標,用來代替陣列 disbuffer1,disbuffer2裡邊的內容。

如下圖,在顯示結束後,不要忘記把標誌位取反!

disbuffer1,disbuffer2 :就是兩個動態陣列,用來儲存要顯示的內容。

table :用來存放行重新整理的資料,對應的P2口,由於是第一行是最高位,所以第一行顯示就是0x80,一次類推!

  • 延時函式

  • 定時器0初始化函式

要用到定時器0中斷,每隔5ms,或者1ms進中斷重新整理一次顯示函式,這樣就不用每次寫的時候就要考慮加顯示函數了!

  • I/O口初始化函式

  • 顯示重新整理函式

這個函式也是放在中斷處理裡邊的 顯示重新整理函式。

u8 *disbuff :定義在顯示函式內部的區域性指標變數,只用在此函式內,避免與全域性指標變數重複,作用一樣!

column1,column2是兩塊點陣的列全部清0,相當於初始化。

k1到k16則是16列,每一列對應 disbuff 數組裡邊的 模值,disbuff[0] & table[hang],則應該是行重新整理的,只有在選中此行的時候才顯示對應行的碼值,如果不雨一下的話,可能出現亂碼,可以自己嘗試一下,反正是程式碼除錯嘛,不在乎多下載幾次。如果不知道為啥取模取出來是這個樣子的話,你可以把每一列單獨看作一個8位的二進位制,把取出來的十六進位制數代入進去,在對應一下顯示出來的內容,應該就可以理解為啥這個模是這個樣子的。

row = table[hang] :則是顯示行重新整理,然後 hang++,然後如果 hang > 7 的話,初始化為0,因為只有8行,這個可以根據實際需要更改!

  • DS1302 顯示(時間,日期,星期,年份都類似)
/************************* DS1302時鐘 時間顯示 *************************************/
void Time_DS1302()
{
	
	if(disbuffer_sign == 1)
		disbuffer = disbuffer1;
	else
		disbuffer = disbuffer2;
	

	
	// 時 十位 列 1 2 3
	disbuffer[0] = number_library[(TIME[2]/16) * 3];
	disbuffer[1] = number_library[(TIME[2]/16) * 3 + 1];
	disbuffer[2] = number_library[(TIME[2]/16) * 3 + 2];
	
	disbuffer[3] = 0x00;
	
	// 時 個位 列 1 2 3
	disbuffer[4] = number_library[(TIME[2]%16) * 3];
	disbuffer[5] = number_library[(TIME[2]%16) * 3 + 1];
	disbuffer[6] = number_library[(TIME[2]%16) * 3 + 2];
	
	// 分 十位 列 1 2 3
	disbuffer[9] = number_library[(TIME[1]/16) * 3];
	disbuffer[10] = number_library[(TIME[1]/16) * 3 + 1];
	disbuffer[11] = number_library[(TIME[1]/16) * 3 + 2];
	
	disbuffer[12] = 0x00;
	
	// 分 個位 列 1 2 3
	disbuffer[13] = number_library[(TIME[1]%16) * 3];
	disbuffer[14] = number_library[(TIME[1]%16) * 3 + 1];
	disbuffer[15] = number_library[(TIME[1]%16) * 3 + 2];

	
	
	// 冒號 列 1 2
	if((TIME[0]%16) % 2)
	{		
		if(disbuffer_sign == 1)
			disbuffer = disbuffer1;
		else
			disbuffer = disbuffer2;
		
		disbuffer[7] = sign_library[0];
		disbuffer[8] = sign_library[1];

		disbuffer_sign = ~disbuffer_sign;
		
		delay(60000);
		delay(60000);
	}
	else
	{
		if(disbuffer_sign == 1)
			disbuffer = disbuffer1;
		else
			disbuffer = disbuffer2;
		
		disbuffer[7] = 0x00;
		disbuffer[8] = 0x00;

		disbuffer_sign = ~disbuffer_sign;
		
		delay(60000);
		delay(60000);
	}
	
	
//	// 秒 測試
//	disbuffer[9] = number_library[(TIME[0]/16) * 3];
//	disbuffer[10] = number_library[(TIME[0]/16) * 3 + 1];
//	disbuffer[11] = number_library[(TIME[0]/16) * 3 + 2];
//	
//	disbuffer[13] = number_library[(TIME[0]%16) * 3];
//	disbuffer[14] = number_library[(TIME[0]%16) * 3 + 1];
//	disbuffer[15] = number_library[(TIME[0]%16) * 3 + 2];
	
	disbuffer_sign = ~disbuffer_sign;
	
}

一共16列,每一列都送進去對應得數,另外要注意,DS1302模組的陣列,TIME[ ],裡邊是BCD碼,轉換成十進位制數,十位要除以16,個位要求餘16!然後比如初始化的秒是 0x23,則要注意這個是十六進位制的數,加滿16才進一,因此求餘16得到的是最後一個3,對應陣列顯示的字元碼應該是第9個到第11個,因此要 *3 ,然後依次加1加2。同理除以16得到的是第一個數2,對應的陣列從6開始,到8結束!

中間第7 8 列,冒號跟隨秒數的變化而閃爍,當秒的個位為奇數的時候,冒號亮,偶數的時候滅,在這個裡邊也要分別更改兩個動態陣列,標誌位也要隨之取反。

這個上邊註釋掉的是對秒顯示的一個測試,可以不用寫這麼多,可以直接在要顯示的對應位置上,把TIME[ ]陣列取出來的數改到秒就好!

  • 主函式

首先是對 I/O 口的初始化,定時器0的初始化,DS1302的初始化,接著在while迴圈裡邊,每次要先讀取DS1302裡邊的時間,然後讓時間顯示30秒,日期顯示10秒,星期顯示10秒,年份顯示10秒, 來回切換即可!

  • 定時器0中斷

P2 也就是行,是對點陣的一個消隱程式,接著就是隻有一個顯示函式,每次定時滿多長時間,就進來執行一次顯示函式!

附錄總結

1. 程式程式碼還可以優化一下,另外之前試過列重新整理,沒有行重新整理顯示的快,因此還有很多寫程式碼的方式可以改進。

2. 一定不要讓點陣的電流過大,我這個點陣就是燒壞了很多LED,需要控制一下電流大小!

3. 切換方式有點單一,後續學習過後會繼續改進!

4. 有錯誤的地方還望指點,有不懂的也可以評論問我哦!