久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

專注電子技術學習與研究
當前位置:單片機教程網 >> MCU設計實例 >> 瀏覽文章

基于AVR單片機的上下課自動打鈴系統的實現(放出原理圖+程序原碼)

作者:佚名   來源:本站原創   點擊數:  更新時間:2013年10月29日   【字體:
昨晚花一晚上把這些資料整理了一下,全部發出來了。
由于補課沒有鈴。3月份做了這個東西,已實際使用,穩定運行一個學期。
上運行圖:

 

硬件如下:AVR ATmega16單片機,開發板(用到上面的:繼電器、LED走馬燈、兩個按鈕)、門鈴、LED若干、16Mhz無源晶振。
 
硬件照片:
開發板:
AVR單片機:
晶振:

 

——————————好了 照片曬完了,下面開始正文——————————
原理圖如下:
好吧我的能耐真大,這電路圖不是用什么CAD專業軟件畫的,而是用Windows畫 圖板用鼠標一筆一劃畫的。。。所以效果不是很好,湊合著看吧,知道個大概就行了。(開發板上肯定還有其他資源,電路圖中的資源也不止開發板上的。這個電路 圖是本系統的原理圖而不是開發板的全部電路圖,畫的只是和本系統有關的東西,開發板上其他無關的就不畫了,也不需要畫)
簡單說明下:
L1~L8對應開發板上的8LEDD2~D6對應上面運行圖上的那5個紅色“上課指示燈”;D1為一盞綠色的LED(運行圖上注意點看,用透明膠包住的那個綠色LED),用于監視程序是否在運行(晶振是否起振,是否死機);K1 K2用于選擇上午下午(上午有早讀,下午沒有)。繼電器不用說了,控制門鈴開關用。
下面放出源程序。(剛剛我已在程序中加入了很多注釋了,后面還是要做下解析):
————源程序(本程序版權歸李彥鋒所有)————
#define  uchar unsigned char
#define  uint  unsigned int
#define  ulong unsigned long int
volatile uint nowtime;//計時變量。然后下面的幾個變量是一些邏輯控制的
volatile uint ledmode;
volatile uint shangkeledmode;
volatile uint shangkeledtime;
volatile uint class;//上下課邏輯,上課為1,下課為0,見主函數

#include <iom16v.h>
#include <macros.h>

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本系統中用于控制上下課指示燈閃爍
#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本系統中用于上課時間和下課時間計時

#pragma interrupt_handler timer1_ovf_isr:iv_TIM1_OVF
void timer1_ovf_isr(void)
{
tm1rsf();//哈哈可能有人漏看了這里,回調函數執行另一個函數,這樣程序看起來更整潔,這是我的編程習慣^v^

TCNT1H = 0x0B;
TCNT1L = 0xDC; //重載高低值

//timer1回調函數
}


void init_devices(void)
{
CLI();
port_init();
timer0_init();
timer1_init();
MCUCR = 0x00;
GICR  = 0x00;
TIMSK = 0x05;
SEI();
}


void delay(uint ms) //這個就不用說了 死循環延遲
{
    uint i,j;
    for(i=0;i<ms;i++)
            {
                    for (j=0;j<2300;j++);
                }
}

void tm0rsf()//控制上課指示燈閃爍的函數,不喜歡寫在回調函數里,這樣程序看起來更工整。。。
{

if(class==1)//是否上下課,上課就閃,下課就不閃。
{
shangkeledtime++;
    if (shangkeledtime==150)//150ms閃一下。其他自己看吧。。。。
    {
        shangkeledtime=0;
            if(shangkeledmode==1) //開燈,相應IO輸出高電平
            {
                PORTA|=0X54;
                    PORTC|=0x02;
                        PORTD|=0x20;
                    shangkeledmode=0;
            }
            else //關燈,相應IO輸出低電平(接地)
            {
                PORTA&=0X03;
                    PORTC&=0xFC;
                        PORTD&=0XDF;
                shangkeledmode=1;//邏輯自己看吧。。。。
            }
    }
}
else
{
    PORTA&=0X03;
        PORTC&=0xFC;
        PORTD&=0XDF;
}
}

void tm1rsf()//timer1回調函數執行的函數
{
nowtime++;//計時變量自增
if(ledmode==1)//嗯這個就是控制D0 LED閃爍的了,主要就是看timer1是不是在走。
{
    ledmode=0;
        PORTA|=0x01;
}
else
{
    ledmode=1;
        PORTA&=0XFE;
}

}

void ring()//響鈴函數,控制繼電器的。。(PC7輸出高電平)
{
PORTC=0xFF;//因為PC口只有用到一個PC7所以不管這么多懶得算了直接全部輸出高電位
delay(300);
PORTC=0x00;
delay(8300);
PORTC=0xFF;
delay(300);
PORTC=0x00;
delay(8300);
}
uchar key_press()//檢測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()//檢測是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()//好了主函數開始了。。。
{
    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)
          {//判斷按的哪個
             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;//早讀上課時跑馬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分鐘,接下來自己看吧
                        {
                           
                                
                                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;//早讀結束,LED亮完上面4盞。。
        }//然后跳出早讀while,進入到下面正常上課while--上課40分鐘,下課10分鐘,上課,下課…………無限循環。。。
}
}

if (mode==2)//按下K2,也就是下午用的
{
    PORTB=0X0F;
        class=1;//邏輯,上課為1下課為0
                            ring();
                                ring();
                                PORTC=0xFF;
                                delay(300);
                                PORTC=0x00;//這都是打鈴用的。。上課比較吵,要打5遍。(一個ring打兩遍,兩個ring后直接在這里控制IO再打一遍)
}

nowtime=0;

while(1)//正常上課while,這里就不解釋太多了,邏輯和上面早讀的差不多的

{


     if (class==1)
    {
                    if (nowtime==2400)//是否夠40分鐘
                        {
                                class=0;
                                nowtime=0;//計時變量清零
                                ring();//打鈴,下課打2遍就好了(一個ring兩遍,具體看上面ring函數)
                        }
    }
        else
        {
                    if (nowtime==600)
                        {
                           
                                
                                class=1;
                                nowtime=0;
                            ring();
                                ring();
                                PORTC=0xFF;
                                delay(300);
                                PORTC=0x00;//上課打5遍鈴,其他就不解釋這么多了,邏輯一樣的自己看就行。
                        }
        }
}
}
————源程序(本程序版權歸李彥鋒所有)————
再簡單說下吧,程序中的邏輯就不說了。
1.點亮L1~L8PB0~PB7輸出低電平(接地),因為那頭接的是VCC +5V的正電壓。
2.PC7輸出高電位,繼電器BC導通,接通門鈴,就響了。
3.D1~D6我是直接把LED的正負接在IO口上的,所以輸出電位的時候一高一低。其實可以IO口上全接正然后統一接地,但是這樣麻煩,反正有足夠的IO口,就這么干了。
附:最早是用內部時鐘,然后后來跑不準,折騰了我一個星期,后來才發現是內部時鐘的問題,上了個晶振,解決問題。。。
好了就說到這里,結束。
關閉窗口

相關文章

主站蜘蛛池模板: 日本免费一区二区三区 | 在线精品观看 | 久久久久久久网 | 久久久精品影院 | 国产欧美一区二区三区久久手机版 | 日韩欧美在线观看视频 | 久久综合av | 九九99精品 | 网黄在线| 男女视频免费 | 国产精品久久久久久婷婷天堂 | 久久久精 | 亚洲xx在线| 欧美一区二区免费在线 | 久久国产亚洲 | 人成久久 | 中文字幕在线精品 | 日韩免费在线观看视频 | 成人网av | 欧美阿v | 九九热re| 中文字幕免费在线 | 中文字幕欧美一区 | 国产一级片在线播放 | 天堂一区二区三区 | 欧洲视频一区 | 欧美成人免费在线 | 97色在线视频 | 国产成人精品亚洲日本在线观看 | 成年视频在线观看福利资源 | 巨大黑人极品videos精品 | 午夜影院| 中文字幕一区二区三区四区五区 | 精品久久久久久红码专区 | 欧美视频成人 | 久久久性 | 秋霞电影一区二区 | 久久中文字幕一区 | 青青草这里只有精品 | 亚洲三级在线观看 | 一级片网站视频 |