基于AVR單片機(jī)的上下課自動(dòng)打鈴系統(tǒng)的實(shí)現(xiàn)
簡(jiǎn)單說(shuō)明下:
L1~L8對(duì)應(yīng)開發(fā)板上的8個(gè)LED;D2~D6對(duì)應(yīng)上面運(yùn)行圖上的那5個(gè)紅色“上課指示燈”;D1為一盞綠色的LED(運(yùn)行圖上注意點(diǎn)看,用透明膠包住的那個(gè)綠色LED),用于監(jiān)視程序是否在運(yùn)行(晶振是否起振,是否死機(jī));K1 K2用于選擇上午下午(上午有早讀,下午沒有)。繼電器不用說(shuō)了,控制門鈴開關(guān)用。
下面放出源程序。(剛剛我已在程序中加入了很多注釋了,后面還是要做下解析):
————源程序(本程序版權(quán)歸李彥鋒所有)————
#defineuchar unsigned char
#defineuintunsigned int
#defineulong unsigned long int
volatile uint nowtime;//計(jì)時(shí)變量。然后下面的幾個(gè)變量是一些邏輯控制的
volatile uint ledmode;
volatile uint shangkeledmode;
volatile uint shangkeledtime;
volatile uint class;//上下課邏輯,上課為1,下課為0,見主函數(shù)
#include
#include
void port_init(void)
{
DDRB=0xFF;
PORTB=0x00;
DDRC=0xFF;
DDRA=0XFF;
DDRD|=0XF0;
//初始化IO口
}
void timer0_init(void)
{
TCCR0 = 0x00;
TCNT0 = 0x06;
OCR0= 0xFA;
TCCR0 = 0x03;
//初始化timer0
}
//timer0本系統(tǒng)中用于控制上下課指示燈閃爍
#pragma interrupt_handler timer0_ovf_isr:iv_TIM0_OVF
void timer0_ovf_isr(void)
{
tm0rsf();//別看漏
TCNT0 = 0x06;
}
//TIMER1 initialize - prescale:256
// WGM: 0) Normal, TOP=0xFFFF
// desired value: 1Sec
// actual value:1.000Sec (0.0%)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1H = 0x0B; //setup
TCNT1L = 0xDC;
OCR1AH = 0xF4;
OCR1AL = 0x24;
OCR1BH = 0xF4;
OCR1BL = 0x24;
ICR1H= 0xF4;
ICR1L= 0x24;
TCCR1A = 0x00;
TCCR1B = 0x04;//start Timer
//初始化timer1
}
//timer1本系統(tǒng)中用于上課時(shí)間和下課時(shí)間計(jì)時(shí)
#pragma interrupt_handler timer1_ovf_isr:iv_TIM1_OVF
void timer1_ovf_isr(void)
{
tm1rsf();//哈哈可能有人漏看了這里,回調(diào)函數(shù)執(zhí)行另一個(gè)函數(shù),這樣程序看起來(lái)更整潔,這是我的編程習(xí)慣^v^
TCNT1H = 0x0B;
TCNT1L = 0xDC;//重載高低值
//timer1回調(diào)函數(shù)
}
void init_devices(void)
{
CLI();
port_init();
timer0_init();
timer1_init();
MCUCR = 0x00;
GICR= 0x00;
TIMSK = 0x05;
SEI();
}
void delay(uint ms)//這個(gè)就不用說(shuō)了 死循環(huán)延遲
{
uint i,j;
for(i=0;i {
for (j=0;j<2300;j++);
}
}
void tm0rsf()//控制上課指示燈閃爍的函數(shù),不喜歡寫在回調(diào)函數(shù)里,這樣程序看起來(lái)更工整。。。
{
if(class==1)//是否上下課,上課就閃,下課就不閃。
{
shangkeledtime++;
if (shangkeledtime==150)//150ms閃一下。其他自己看吧。。。。
{
shangkeledtime=0;
if(shangkeledmode==1)//開燈,相應(yīng)IO輸出高電平
{
PORTA|=0X54;
PORTC|=0x02;
PORTD|=0x20;
shangkeledmode=0;
}
else//關(guān)燈,相應(yīng)IO輸出低電平(接地)
{
PORTA&=0X03;
PORTC&=0xFC;
PORTD&=0XDF;
shangkeledmode=1;//邏輯自己看吧。。。。
}
}
}
else
{
PORTA&=0X03;
PORTC&=0xFC;
PORTD&=0XDF;
}
}
void tm1rsf()//timer1回調(diào)函數(shù)執(zhí)行的函數(shù)
{
nowtime++;//計(jì)時(shí)變量自增
if(ledmode==1)//嗯這個(gè)就是控制D0 LED閃爍的了,主要就是看timer1是不是在走。
{
ledmode=0;
PORTA|=0x01;
}
else
{
ledmode=1;
PORTA&=0XFE;
}
}
void ring()//響鈴函數(shù),控制繼電器的。。(PC7輸出高電平)
{
PORTC=0xFF;//因?yàn)镻C口只有用到一個(gè)PC7所以不管這么多懶得算了直接全部輸出高電位
delay(300);
PORTC=0x00;
delay(8300);
PORTC=0xFF;
delay(300);
PORTC=0x00;
delay(8300);
}
uchar key_press()//檢測(cè)K1K2是否按下。。
{
uchar j;
DDRD|=0X0F;
PORTD|=0X0F;
DDRD&=0XF0;
j=PIND;
j=j&0X0F;
if(j==0X0F)
{
return 0;
}
else
{
return 1;
}
}
uchar key_scan()//檢測(cè)是K1還是K2按下。。
{
uchar key;
delay(10);
if(key_press())
{
key=PIND;
key&=0X0F;
switch(key)
{
case 0X0E:
key=1;
break;
case 0X0D:
key=2;
break;
default:
key=0;
}
while(key_press());
}
else
{
key=16;
}
return key;
}
void main()//好了主函數(shù)開始了。。。
{
uchar i,j;
uint k,mode;
uint ledmode;
init_devices();//初始化IO。。上面有。
k=0;
ledmode=1;//邏輯自己看,不用解釋。。。
while(k==0)//注意了 這一段是上電后等待按下K1K2的。
{
if(ledmode==1)//上電后LED走馬燈在那狂閃(按下之前)
{
PORTB=0XF0;delay(80);
ledmode=0;
}
else{PORTB=0X0F;delay(80);ledmode=1;}
i=key_press();
if(i)
{//判斷按的哪個(gè)
j=key_scan();
if (j==1)
{mode=1;k=1;}
if (j==2)
{mode=2;k=1;}
}
}
if (mode==1)//如果按的K1,也就是早上用,有早讀的
{
uint overzaodu;
uint canoverzaodu;
overzaodu=0;
canoverzaodu=0;
PORTB=0XF3;//早讀上課時(shí)跑馬LED亮上面2盞(亮上面。。代表上午^v^)
nowtime=0;
class=1;
while(canoverzaodu==0)
{
if (class==1)
{
if (nowtime==1200)//先上20分鐘的早讀
{
class=0;
nowtime=0;
overzaodu++;
ring();//早讀下課打鈴
}
}
else
{
if (nowtime==300)//早讀休息5分鐘,接下來(lái)自己看吧
{
class=1;
nowtime=0;
overzaodu++;
ring();
ring();
PORTC=0xFF;
delay(300);
PORTC=0x00;
}
}
if (overzaodu==1)
{
PORTB=0XF1;//早讀下課,LED多亮一盞
}
if (overzaodu==2)
{
canoverzaodu=1;
PORTB=0XF0;//早讀結(jié)束,LED亮完上面4盞。。
}//然后跳出早讀while,進(jìn)入到下面正常上課while--上課40分鐘,下課10分鐘,上課,下課…………無(wú)限循環(huán)。。。
}
}
if (mode==2)//按下K2,也就是下午用的
{
PORTB=0X0F;
class=1;//邏輯,上課為1下課為0
ring();
ring();
PORTC=0xFF;
delay(300);
PORTC=0x00;//這都是打鈴用的。。上課比較吵,要打5遍。(一個(gè)ring打兩遍,兩個(gè)ring后直接在這里控制IO再打一遍)
}
nowtime=0;
while(1)//正常上課while,這里就不解釋太多了,邏輯和上面早讀的差不多的
{
if (class==1)
{
if (nowtime==2400)//是否夠40分鐘
{
class=0;
nowtime=0;//計(jì)時(shí)變量清零
ring();//打鈴,下課打2遍就好了(一個(gè)ring兩遍,具體看上面ring函數(shù))
}
}
else
{
if (nowtime==600)
{
class=1;
nowtime=0;
ring();
ring();
PORTC=0xFF;
delay(300);
PORTC=0x00;//上課打5遍鈴,其他就不解釋這么多了,邏輯一樣的自己看就行。
}
}
}
}
#defineuchar unsigned char
#defineuintunsigned int
#defineulong unsigned long int
volatile uint nowtime;//計(jì)時(shí)變量。然后下面的幾個(gè)變量是一些邏輯控制的
volatile uint ledmode;
volatile uint shangkeledmode;
volatile uint shangkeledtime;
volatile uint class;//上下課邏輯,上課為1,下課為0,見主函數(shù)
#include
#include
void port_init(void)
{
DDRB=0xFF;
PORTB=0x00;
DDRC=0xFF;
DDRA=0XFF;
DDRD|=0XF0;
//初始化IO口
}
void timer0_init(void)
{
TCCR0 = 0x00;
TCNT0 = 0x06;
OCR0= 0xFA;
TCCR0 = 0x03;
//初始化timer0
}
//timer0本系統(tǒng)中用于控制上下課指示燈閃爍
#pragma interrupt_handler timer0_ovf_isr:iv_TIM0_OVF
void timer0_ovf_isr(void)
{
tm0rsf();//別看漏
TCNT0 = 0x06;
}
//TIMER1 initialize - prescale:256
// WGM: 0) Normal, TOP=0xFFFF
// desired value: 1Sec
// actual value:1.000Sec (0.0%)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1H = 0x0B; //setup
TCNT1L = 0xDC;
OCR1AH = 0xF4;
OCR1AL = 0x24;
OCR1BH = 0xF4;
OCR1BL = 0x24;
ICR1H= 0xF4;
ICR1L= 0x24;
TCCR1A = 0x00;
TCCR1B = 0x04;//start Timer
//初始化timer1
}
//timer1本系統(tǒng)中用于上課時(shí)間和下課時(shí)間計(jì)時(shí)
#pragma interrupt_handler timer1_ovf_isr:iv_TIM1_OVF
void timer1_ovf_isr(void)
{
tm1rsf();//哈哈可能有人漏看了這里,回調(diào)函數(shù)執(zhí)行另一個(gè)函數(shù),這樣程序看起來(lái)更整潔,這是我的編程習(xí)慣^v^
TCNT1H = 0x0B;
TCNT1L = 0xDC;//重載高低值
//timer1回調(diào)函數(shù)
}
void init_devices(void)
{
CLI();
port_init();
timer0_init();
timer1_init();
MCUCR = 0x00;
GICR= 0x00;
TIMSK = 0x05;
SEI();
}
void delay(uint ms)//這個(gè)就不用說(shuō)了 死循環(huán)延遲
{
uint i,j;
for(i=0;i
for (j=0;j<2300;j++);
}
}
void tm0rsf()//控制上課指示燈閃爍的函數(shù),不喜歡寫在回調(diào)函數(shù)里,這樣程序看起來(lái)更工整。。。
{
if(class==1)//是否上下課,上課就閃,下課就不閃。
{
shangkeledtime++;
if (shangkeledtime==150)//150ms閃一下。其他自己看吧。。。。
{
shangkeledtime=0;
if(shangkeledmode==1)//開燈,相應(yīng)IO輸出高電平
{
PORTA|=0X54;
PORTC|=0x02;
PORTD|=0x20;
shangkeledmode=0;
}
else//關(guān)燈,相應(yīng)IO輸出低電平(接地)
{
PORTA&=0X03;
PORTC&=0xFC;
PORTD&=0XDF;
shangkeledmode=1;//邏輯自己看吧。。。。
}
}
}
else
{
PORTA&=0X03;
PORTC&=0xFC;
PORTD&=0XDF;
}
}
void tm1rsf()//timer1回調(diào)函數(shù)執(zhí)行的函數(shù)
{
nowtime++;//計(jì)時(shí)變量自增
if(ledmode==1)//嗯這個(gè)就是控制D0 LED閃爍的了,主要就是看timer1是不是在走。
{
ledmode=0;
PORTA|=0x01;
}
else
{
ledmode=1;
PORTA&=0XFE;
}
}
void ring()//響鈴函數(shù),控制繼電器的。。(PC7輸出高電平)
{
PORTC=0xFF;//因?yàn)镻C口只有用到一個(gè)PC7所以不管這么多懶得算了直接全部輸出高電位
delay(300);
PORTC=0x00;
delay(8300);
PORTC=0xFF;
delay(300);
PORTC=0x00;
delay(8300);
}
uchar key_press()//檢測(cè)K1K2是否按下。。
{
uchar j;
DDRD|=0X0F;
PORTD|=0X0F;
DDRD&=0XF0;
j=PIND;
j=j&0X0F;
if(j==0X0F)
{
return 0;
}
else
{
return 1;
}
}
uchar key_scan()//檢測(cè)是K1還是K2按下。。
{
uchar key;
delay(10);
if(key_press())
{
key=PIND;
key&=0X0F;
switch(key)
{
case 0X0E:
key=1;
break;
case 0X0D:
key=2;
break;
default:
key=0;
}
while(key_press());
}
else
{
key=16;
}
return key;
}
void main()//好了主函數(shù)開始了。。。
{
uchar i,j;
uint k,mode;
uint ledmode;
init_devices();//初始化IO。。上面有。
k=0;
ledmode=1;//邏輯自己看,不用解釋。。。
while(k==0)//注意了 這一段是上電后等待按下K1K2的。
{
if(ledmode==1)//上電后LED走馬燈在那狂閃(按下之前)
{
PORTB=0XF0;delay(80);
ledmode=0;
}
else{PORTB=0X0F;delay(80);ledmode=1;}
i=key_press();
if(i)
{//判斷按的哪個(gè)
j=key_scan();
if (j==1)
{mode=1;k=1;}
if (j==2)
{mode=2;k=1;}
}
}
if (mode==1)//如果按的K1,也就是早上用,有早讀的
{
uint overzaodu;
uint canoverzaodu;
overzaodu=0;
canoverzaodu=0;
PORTB=0XF3;//早讀上課時(shí)跑馬LED亮上面2盞(亮上面。。代表上午^v^)
nowtime=0;
class=1;
while(canoverzaodu==0)
{
if (class==1)
{
if (nowtime==1200)//先上20分鐘的早讀
{
class=0;
nowtime=0;
overzaodu++;
ring();//早讀下課打鈴
}
}
else
{
if (nowtime==300)//早讀休息5分鐘,接下來(lái)自己看吧
{
class=1;
nowtime=0;
overzaodu++;
ring();
ring();
PORTC=0xFF;
delay(300);
PORTC=0x00;
}
}
if (overzaodu==1)
{
PORTB=0XF1;//早讀下課,LED多亮一盞
}
if (overzaodu==2)
{
canoverzaodu=1;
PORTB=0XF0;//早讀結(jié)束,LED亮完上面4盞。。
}//然后跳出早讀while,進(jìn)入到下面正常上課while--上課40分鐘,下課10分鐘,上課,下課…………無(wú)限循環(huán)。。。
}
}
if (mode==2)//按下K2,也就是下午用的
{
PORTB=0X0F;
class=1;//邏輯,上課為1下課為0
ring();
ring();
PORTC=0xFF;
delay(300);
PORTC=0x00;//這都是打鈴用的。。上課比較吵,要打5遍。(一個(gè)ring打兩遍,兩個(gè)ring后直接在這里控制IO再打一遍)
}
nowtime=0;
while(1)//正常上課while,這里就不解釋太多了,邏輯和上面早讀的差不多的
{
if (class==1)
{
if (nowtime==2400)//是否夠40分鐘
{
class=0;
nowtime=0;//計(jì)時(shí)變量清零
ring();//打鈴,下課打2遍就好了(一個(gè)ring兩遍,具體看上面ring函數(shù))
}
}
else
{
if (nowtime==600)
{
class=1;
nowtime=0;
ring();
ring();
PORTC=0xFF;
delay(300);
PORTC=0x00;//上課打5遍鈴,其他就不解釋這么多了,邏輯一樣的自己看就行。
}
}
}
}
————源程序(本程序版權(quán)歸李彥鋒所有)————
再簡(jiǎn)單說(shuō)下吧,程序中的邏輯就不說(shuō)了。
1.點(diǎn)亮L1~L8為PB0~PB7輸出低電平(接地),因?yàn)槟穷^接的是VCC +5V的正電壓。
2.PC7輸出高電位,繼電器B和C導(dǎo)通,接通門鈴,就響了。
3.D1~D6我是直接把LED的正負(fù)接在IO口上的,所以輸出電位的時(shí)候一高一低。其實(shí)可以IO口上全接正然后統(tǒng)一接地,但是這樣麻煩,反正有足夠的IO口,就這么干了。
附:最早是用內(nèi)部時(shí)鐘,然后后來(lái)跑不準(zhǔn),折騰了我一個(gè)星期,后來(lái)才發(fā)現(xiàn)是內(nèi)部時(shí)鐘的問題,上了個(gè)晶振,解決問題。。。
看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人
(function(){
var bp = document.createElement('script');
var curProtocol = window.location.protocol.split(':')[0];
if (curProtocol === 'https') {
bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
}
else {
bp.src = 'http://push.zhanzhang.baidu.com/push.js';
}
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(bp, s);
})();
關(guān)鍵詞:
AVR單片機(jī)上下課自動(dòng)打鈴系
相關(guān)推薦
技術(shù)專區(qū)
- FPGA
- DSP
- MCU
- 示波器
- 步進(jìn)電機(jī)
- Zigbee
- LabVIEW
- Arduino
- RFID
- NFC
- STM32
- Protel
- GPS
- MSP430
- Multisim
- 濾波器
- CAN總線
- 開關(guān)電源
- 單片機(jī)
- PCB
- USB
- ARM
- CPLD
- 連接器
- MEMS
- CMOS
- MIPS
- EMC
- EDA
- ROM
- 陀螺儀
- VHDL
- 比較器
- Verilog
- 穩(wěn)壓電源
- RAM
- AVR
- 傳感器
- 可控硅
- IGBT
- 嵌入式開發(fā)
- 逆變器
- Quartus
- RS-232
- Cyclone
- 電位器
- 電機(jī)控制
- 藍(lán)牙
- PLC
- PWM
- 汽車電子
- 轉(zhuǎn)換器
- 電源管理
- 信號(hào)放大器
評(píng)論