本文為大家介紹兩個(gè)AVR單片機(jī)8位數(shù)碼管顯示的程序?qū)崿F(xiàn)。
AVR單片機(jī)595驅(qū)動8位數(shù)碼管的顯示的電路實(shí)現(xiàn)
主程序代碼
#include
#include //GCC中的延時(shí)函數(shù)頭文件
#include “hc595.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};
//函數(shù)聲明
extern void Delayus(unsigned int lus); //us延時(shí)函數(shù)
extern void Delayms(unsigned int lms); //ms延時(shí)函數(shù)
int main(void) //GCC中main文件必須為返回整形值的函數(shù),沒有參數(shù)
{
unsigned char i;
PORTB = 0xff; //PORTB輸出低電平,使LED熄滅
HC595_port_init();
while(1)
{
for(i = 0; i < 8;i++)
{
PORTB = Led_Disbuf; //送段碼
HC595_Send_Data(ComBuf); //選通位選端口
Delayus(70); //延時(shí)
HC595_Send_Data(0x00); //位選通關(guān)閉
}
}
}
//us級別的延時(shí)函數(shù)
void Delayus(unsigned int lus)
{
while(lus--)
{
_delay_loop_2(4); //_delay_loop_2(1)是延時(shí)4個(gè)時(shí)鐘周期,參數(shù)為4則延時(shí)16
//個(gè)時(shí)鐘周期,本實(shí)驗(yàn)用16M晶體,則16個(gè)時(shí)鐘周期為16/16=1us
}
}
//ms級別的延時(shí)函數(shù)
void Delayms(unsigned int lms)
{
while(lms--)
{
Delayus(1000); //延時(shí)1ms
}
}
模塊化程序設(shè)計(jì)的.h文件
下面是本實(shí)例中模塊化程序設(shè)計(jì)的.h文件
/*****************************
74hc595.h
***********************************/
/*74hc595與單片機(jī)的引腳連接
/MR(10腳) VCC 低點(diǎn)平時(shí)將移位寄存器的數(shù)據(jù)清零。通常將它接Vcc
/OE(13腳) PG4 高電平時(shí)禁止輸出(高阻態(tài))。
如果單片機(jī)的引腳不緊張,用一個(gè)引腳控制它,
可以方便地產(chǎn)生閃爍和熄滅效果。比通過數(shù)據(jù)端移位控制要省時(shí)省力。
ST_CP(12腳) PG1 上升沿時(shí)移位寄存器的數(shù)據(jù)進(jìn)入數(shù)據(jù)存儲寄存器,
下降沿時(shí)存儲寄存器數(shù)據(jù)不變。通常將RCK置為低電平,
當(dāng)移位結(jié)束后,在RCK端產(chǎn)生一個(gè)正脈沖(5V時(shí),大于幾十納秒就行了。
通常都選微秒級),更新顯示數(shù)據(jù)。
SH_CP(11腳) PG0 上升沿時(shí)數(shù)據(jù)寄存器的數(shù)據(jù)移位。QA-->QB-->QC-->。。。-->QH;
下降沿移位寄存器數(shù)據(jù)不變。(脈沖寬度:5V時(shí),大于幾十納秒就行了。
通常都選微秒級)
DS(14) PG2 串行數(shù)據(jù)輸入端。
*/
#ifndef __HC595_H__
#define __HC595_H__
#include //io端口寄存器配置文件,必須包含
#include //GCC中的延時(shí)函數(shù)頭文件
#define HC595_latch (1 << PG1) //上升沿?cái)?shù)據(jù)打入8位鎖存器,下降沿鎖存器數(shù)據(jù)不變
#define HC595_sclk (1 << PG0) //上升沿?cái)?shù)據(jù)移位,下降沿?cái)?shù)據(jù)不變
#define HC595_oe (1 << PG4) //低電平,8位數(shù)據(jù)鎖存器輸出,高電平輸出高組態(tài)
#define HC595_data (1 << PG2) //串行數(shù)據(jù)輸入端
#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); //發(fā)送一個(gè)字節(jié)
void HC595_Output_Data(unsigned char data); //發(fā)送字符串
#endif
同時(shí)我們將與74HC595相關(guān)的函數(shù)定義部分放在74HC595.c文件中,如下
/********************************
74hc595.c
**************************************/
#include “hc595.h”
//595端口初始化
void HC595_port_init(void)
{
PORTG = 0x00;
DDRG |= (1 << PG0) | (1 << PG1) | (1 << PG2) | (1 << PG4);
}
//發(fā)送一個(gè)字節(jié)
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; //上升沿?cái)?shù)據(jù)移位
CLR_HC595_sclk;
}
SET_HC595_latch;
CLR_HC595_latch;
}
//發(fā)送字符串
void HC595_Output_Data(unsigned char data)
{
CLR_HC595_latch; //下降沿鎖存器數(shù)據(jù)不變
HC595_Send_Data(data);
SET_HC595_latch; //上升沿?cái)?shù)據(jù)打入8位鎖存器
}
AVR單片機(jī)控制8段LED數(shù)碼管同時(shí)顯示
這是一個(gè)簡單的供單片機(jī)入門學(xué)習(xí)者練習(xí)用的8段LED數(shù)碼管控制匯編程序,控制一個(gè)兩位的數(shù)碼管同時(shí)顯示字符(動態(tài)刷新)。用AVR- Studio-4 開發(fā),在AVR單片機(jī)Atmega48上調(diào)試通過。學(xué)習(xí)者可以舉一反三應(yīng)用到其他類型的單片機(jī)芯片。
arget : M48 ;
Crystal: 8.0000Mhz
.include “m48def.inc”
.org $0000 rjmp _main
.org $0020
_port_init:; 端口初始化
clr R2
out 0x5,R2 PortB清零
ldi R24,255
out 0x4,R24 定義PortB為輸出
out 0x8,R2 PortC清零
ldi R24,3
out 0x7,R24 定義PortC.0,Portc.1為輸出
ret
_tabs:;字形定義
.dw 192 0xC0,“0”
.dw 249 0xF9,“1”
.dw 164 0xA4,“2”
.dw 176 0xB0,“3”
.dw 153 0x99,“4”
.dw 146 0x92,“5”
.dw 130 0x82,“6”
.dw 248 0xF8,“7”
.dw 128 0x80,“8”
.dw 152 0x98,“9”
.dw 136 0x88,“A”
.dw 131 0x83,“B”
.dw 198 0xC6,“C”
.dw 161 0xA1,“D”
.dw 134 0x86,“E”
.dw 142 0x8E,“F”
.dw 255 0xFF,“8.”
_delay_1ms: 延時(shí)子程
ldi R16,1
ldi R17,0
L3:
subi R16,255 加1操作
sbci R17,255
cpi R16,232 0xE8
ldi R30,3 0x3E8 = 1000
cpc R17,R30
brlo L3 未達(dá)1000繼續(xù)
ret
_delay:
push r21
push r20
push r17 入口:r16,r17裝的是延時(shí)參數(shù)
push r16
movw R10,R16 將r16,r17的內(nèi)容裝入r10,r11
clr R20
clr R21
L8:
rcall _delay_1ms
subi R20,255 加1操作
sbci R21,255
cp R20,R10 與指定延時(shí)參數(shù)比較
cpc R21,R11
brlo L8 未達(dá)指定延時(shí)參數(shù)繼續(xù)
pop r16
pop r17
pop r20
pop r21
ret
_led_display:
push R20 寄存器r20入棧,r20中帶入字符表的索引
ldi R24,2
mul R24,R20 將r20中的值乘2,結(jié)果在r0中
movw R30,R0 將r0的值賦給r30,作為偏移量
ldi R24,low(_tabs<<1) 獲取字符表基地址
ldi R25,high(_tabs<<1)
add R30,R24 偏移量+基地址構(gòu)成z指針
adc R31,R25
lpm R20,Z+0 取字型送入r20 out 0x5,R20 字型送PortB,輸出 ldi R22,0 循環(huán)100次計(jì)數(shù)寄存器r22清零
L10:
ldi R20,1 r20用于8LED數(shù)碼管輸出位控制,初始為1
L12:
out 0x8,R20 將8LED數(shù)碼管位控制輸出到端口PortC ldi R16,10 延時(shí)參數(shù)低位
ldi R17,0 延時(shí)參數(shù)高位
rcall _delay 調(diào)延時(shí)子程
inc R20 移位r20,準(zhǔn)備顯示另一位
cpi R20,3 判兩位是否顯示完
brlo L12 未顯示完兩位,繼續(xù)
inc R22 r22加1
cpi R22,100 判是否已計(jì)滿100 brlo L10 未計(jì)滿則繼續(xù)
pop R20 r20出棧 ret _main:
clr R20 初始化計(jì)數(shù)寄存器r20 rcall _port_init 初始化端口
L17:
cpi R20,16 比較循環(huán)計(jì)數(shù)
brne L21 未顯示完16個(gè)字符繼續(xù)
clr R20 從新開始
L21:
rcall _led_display 顯示字符
inc R20 計(jì)數(shù)值加1
rjmp L17 返回
ret
評論
查看更多