新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 基于AVR單片機的上下課自動打鈴系統的實現

        基于AVR單片機的上下課自動打鈴系統的實現

        作者: 時間:2016-11-30 來源:網絡 收藏
        簡單說明下:
        L1~L8對應開發板上的8個LED;D2~D6對應上面運行圖上的那5個紅色“上課指示燈”;D1為一盞綠色的LED(運行圖上注意點看,用透明膠包住的那個綠色LED),用于監視程序是否在運行(晶振是否起振,是否死機);K1 K2用于選擇上午下午(上午有早讀,下午沒有)。繼電器不用說了,控制門鈴開關用。
        下面放出源程序。(剛剛我已在程序中加入了很多注釋了,后面還是要做下解析):
        ————源程序(本程序版權歸李彥鋒所有)————
        #defineuchar unsigned char
        #defineuintunsigned int
        #defineulong unsigned long int
        volatile uint nowtime;//計時變量。然后下面的幾個變量是一些邏輯控制的
        volatile uint ledmode;
        volatile uint shangkeledmode;
        volatile uint shangkeledtime;
        volatile uint class;//上下課邏輯,上課為1,下課為0,見主函數

        #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本系統中用于控制上下課指示燈閃爍
        #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 {
        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~L8為PB0~PB7輸出低電平(接地),因為那頭接的是VCC +5V的正電壓。
        2.PC7輸出高電位,繼電器B和C導通,接通門鈴,就響了。
        3.D1~D6我是直接把LED的正負接在IO口上的,所以輸出電位的時候一高一低。其實可以IO口上全接正然后統一接地,但是這樣麻煩,反正有足夠的IO口,就這么干了。
        附:最早是用內部時鐘,然后后來跑不準,折騰了我一個星期,后來才發現是內部時鐘的問題,上了個晶振,解決問題。。。
        好了就說到這里,結束。
        上一頁 1 2 下一頁

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 杭锦旗| 子洲县| 六盘水市| 大足县| 顺昌县| 平昌县| 牙克石市| 昌平区| 色达县| 泰和县| 玛沁县| 高密市| 临颍县| 芒康县| 正镶白旗| 沈丘县| 自贡市| 施甸县| 同德县| 凤城市| 大安市| 丰县| 潜山县| 兴宁市| 彭阳县| 六枝特区| 垦利县| 丰县| 拉萨市| 蒙城县| 景宁| 曲水县| 胶南市| 大足县| 锡林浩特市| 太原市| 淮阳县| 西安市| 塔河县| 辉南县| 韶山市|