AVR單片機8位數碼管顯示的程序實現


2016-10-26 16:30

我們接着來完成 數碼管的顯示實驗。現在我們開始動手編寫程序;

根據前面的介紹,我們應該已經能夠知道編寫一個 的C語言程序的基本步驟和方法了。

下面給出這個程序的主程序文件,在這個程序中我們應該能夠知道這個程序都包含了那幾塊,具體來説我們應該能夠在這個程序中把以下幾個部分找出來:預編譯語句、 的定義、函數的聲明、主函數、函數定義。如果你還不能夠準確找出這幾部分,那麼需要把前面的內容再詳細閲讀一下。

主程序代碼

#include < /io.h> //io端口寄存器配置文件,必須包含
#include <util/delay.h> //GCC中的延時函數頭文件
#include "hc .h"
//unsigned char Led_Disbuf[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //共陰極
unsigned char Led_Disbuf[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; //共陽極
unsigned char ComBuf[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
//函數聲明
extern void Delayus(unsigned int lus); //us延時函數
extern void Delayms(unsigned int lms); //ms延時函數
int main(void) //GCC中main文件必須為返回整形值的函數,沒有參數
{
unsigned char i;
PORTB = 0xff; //PORTB輸出低電平,使 熄滅
DDRB = 0xFF; //配置端口PB全部為輸出口
HC595_port_init();
while(1)
{
for(i = 0; i < 8;i++)
{
PORTB = Led_Disbuf; //送段碼
HC595_Send_Data(ComBuf); //選通位選端口
Delayus(70); //延時
HC595_Send_Data(0x00); //位選通關閉
}
}
}
//us級別的延時函數
void Delayus(unsigned int lus)
{
while(lus--)
{
_delay_loop_2(4); //_delay_loop_2(1)是延時4個時鐘週期,參數為4則延時16
//個時鐘週期,本實驗用16M晶體,則16個時鐘週期為16/16=1us
}
}
//ms級別的延時函數
void Delayms(unsigned int lms)
{
while(lms--)
{
Delayus(1000); //延時1ms
}
}

在這個主程序文件中有人可能會注意到有一些我們前面沒有介紹過的內容,比如extern這個單詞,它在這裏起什麼作用?

這就牽涉到C語言的關鍵字了,關於C語言的關鍵字,我們可以到相關的C語言教材中去做詳細瞭解,在這裏我們只針對extern這個關鍵字作出解釋,我們注意到extern用在一個函數聲明的地方,它的作用就是把這個函數聲明為外部函數,這樣我們在整個項目的所有文件中就都可以調用這個函數了。同理extern也可以用來聲明一個變量為外部變量。

我們可能還會有一個疑惑:#include "hc595.h"這個頭文件包含語句中的hc595.h有什麼作用,它是GCC提供的還是我們自己編寫的?

這裏我們就要學習C語言中的一個重要的概念:模塊化程序設計。何為模塊化程序設計?它實現什麼功能?如果要鋪開來講的話,可能需要一本書的內容。我們耗不起這個時間和精力。其實我們只需要知道,模塊化程序設計是為了簡化程序容量而採取的一種將一個程序分成不同的模塊,然後通過特定的方法將這些模塊組合起來共同完成同一個目標。通俗的説就是化整為零。

在我們剛開始學習 的時候,我們編寫的程序都很簡單,程序量也不大,所以往往涉及不到模塊化程序設計,但是這是一種很好的編程思路,我們有必要掌握。本實例就是採用的這種方法。

模塊化程序設計的思路是:將實現相同功能的程序單獨編寫,然後實現一個綜合的功能,舉個例子,我們想實現一個液晶顯示的温度測量程序,那麼我們可以把液晶顯示相關的程序放在一個文件中,把温度測量的程序放在另一個文件中,最後在主程序中調用這兩個文件來實現整體的功能。

通常我們在進行模塊化程序設計的時候,常常將 ,端口設置,函數聲明等部分保存在一個.h文件中,而將函數定義部分放在一個.c文件中,在編寫主程序文件的時候,用預處理命令#include將.h文件包含起來,而在編譯的時候將所有用到的.c文件一起編譯。這樣就實現了模塊化文件的整合。

在本實例中,我們將74HC595相關的變量定義,端口定義,函數聲明放在74HC595.h文件中,而主程序中的#include "hc595.h"這句話實現了將這個文件包含到主程序中的功能。

下面是本實例中模塊化程序設計的.h文件

/*****************************

.h

***********************************/

/*74hc595與 的引腳連接

/MR(10腳) VCC 低點平時將 的數據清零。通常將它接Vcc

/OE(13腳) PG4 高電平時禁止輸出(高阻態)。

如果 的引腳不緊張,用一個引腳控制它,

可以方便地產生閃爍和熄滅效果。比通過數據端移位控制要省時省力。

ST_CP(12腳) PG1 上升沿時移位寄存器的數據進入數據存儲寄存器,

下降沿時存儲寄存器數據不變。通常將RCK置為低電平,

當移位結束後,在RCK端產生一個正脈衝(5V時,大於幾十納秒就行了。

通常都選微秒級),更新顯示數據。

SH_CP(11腳) PG0 上升沿時數據寄存器的數據移位。QA-->QB-->QC-->...-->QH;

下降沿移位寄存器數據不變。(脈衝寬度:5V時,大於幾十納秒就行了。

通常都選微秒級)

DS(14) PG2 串行數據輸入端。

*/
#ifndef __HC595_H__
#define __HC595_H__
#include <avr/io.h> //io端口寄存器配置文件,必須包含
#include <util/delay.h> //GCC中的延時函數頭文件
#define HC595_latch (1 << PG1) //上升沿數據打入8位鎖存器,下降沿鎖存器數據不變
#define HC595_sclk (1 << PG0) //上升沿數據移位,下降沿數據不變
#define HC595_oe (1 << PG4) //低電平,8位數據鎖存器輸出,高電平輸出高組態
#define HC595_data (1 << PG2) //串行數據輸入端
#define SET_HC595_latch (PORTG |= (1 << PG1))
#define CLR_HC595_latch (PORTG &= ~(1 << PG1))
#define SET_HC595_sclk (PORTG |= (1 << PG0))
#define CLR_HC595_sclk (PORTG &= ~(1 << PG0))
#define SET_HC595_data (PORTG |= (1 << PG2))
#define CLR_HC595_data (PORTG &= ~(1 << PG2))
#define SET_HC595_oe (PORTG |= (1 << PG4))
#define CLR_HC595_oe (PORTG &= ~(1 << PG4))
void HC595_port_init(void); //595端口初始化
void HC595_Send_Data(unsigned char byte); //發送一個字節
void HC595_Output_Data(unsigned char data); //發送字符串
#endif
同時我們將與74HC595相關的函數定義部分放在74HC595.c文件中,如下
/********************************
74hc595.c
**************************************/
#include "hc595.h"
//595端口初始化
void HC595_port_init(void)
{
PORTG = 0x00;
DDRG |= (1 << PG0) | (1 << PG1) | (1 << PG2) | (1 << PG4);
}
//發送一個字節
void HC595_Send_Data(unsigned char byte)
{
unsigned char i;
//CLR_HC595_latch;
for(i = 0;i < 8;i++)
{
if(byte & 0x80)
{
SET_HC595_data;
}
else
{
CLR_HC595_data;
}
byte <<=1;
SET_HC595_sclk; //上升沿數據移位
CLR_HC595_sclk;
}
SET_HC595_latch;
CLR_HC595_latch;
}
//發送字符串
void HC595_Output_Data(unsigned char data)
{
CLR_HC595_latch; //下降沿鎖存器數據不變
HC595_Send_Data(data);
SET_HC595_latch; //上升沿數據打入8位鎖存器
}

在主程序中我們使用預定義語句將.h文件包含到了主程序文件中,那麼我們怎樣實現將.c文件編譯到整個項目程序中呢?在這裏我們只要在makefile文件中將這個.c文件加進去就可以了,如下圖所示,在SRC = $(TARGET).C的後面空一格,然後輸入我們所定義的.c文件的名稱,然後保存makefile文件的更改。最後進行編譯就可以了,編譯的時候如果我們仔細觀察編譯器的輸出信息,會發現不但編譯了main.c文件,同時也編譯了74hc595.c文件。

@青山不移,文筆不息。學習,堅持,夢想青春!