新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 第五節:蜂鳴器的驅動程序

        第五節:蜂鳴器的驅動程序

        作者: 時間:2016-11-22 來源:網絡 收藏
        開場白:

        上一節講了利用累計定時中斷次數實現LED燈閃爍,這個例子同時也第一次展示了我最完整的實戰程序框架:用switch語句實現狀態機,外加定時中斷。這個框架看似簡單,實際上就是那么簡單。我做的所有開發項目都是基于這個簡單框架,但是非常好用。上一節只有一個單任務的LED燈在閃爍,這節開始,我們多增加一個蜂鳴器報警的任務,要教會大家四個知識點:

        本文引用地址:http://www.104case.com/article/201611/319803.htm

        第一點:蜂鳴器的驅動程序框架編寫。

        第二點:多任務處理的程序框架。

        第三點:如何控制蜂鳴器聲音的長叫和短叫。

        第四點:如何知道1秒鐘需要多少個定時中斷,也就是如何按比例修正時間精度。

        具體內容,請看源代碼講解。

        (1)硬件平臺:基于朱兆祺51單片機學習板。

        (2)實現功能:同時跑兩個任務,第一個任務讓一個LED燈1秒鐘閃爍一次。第二個任務讓蜂鳴器在前面3秒發生一次短叫報警,在后面6秒發生一次長叫報警,反復循環。

        (3)源代碼講解如下:

        #include "REG52.H"

        /* 注釋一:

        * 如何知道1秒鐘需要多少個定時中斷?

        * 這個需要編寫一段小程序測試,得到測試的結果后再按比例修正。

        * 步驟:

        * 第一步:在程序代碼上先寫入1秒鐘大概需要200個定時中斷。

        * 第二步:基于以上1秒鐘的基準,編寫一個60秒的簡單測試程序(如果編寫超過

        * 60秒的時間,這個精度還會更高)。比如,編寫一個用蜂鳴器的聲音來識別計時的

        * 起始和終止的測試程序。

        * 第三步:把程序燒錄進單片機后,上電開始測試,手上同步打開手機里的秒表。

        * 如果單片機僅僅跑了27秒。

        * 第四步:那么最終得出1秒鐘需要的定時中斷次數是:const_time_1s=(200*60)/27=444

        */

        #define const_time_05s 222 //0.5秒鐘的時間需要的定時中斷次數

        #define const_time_1s 444 //1秒鐘的時間需要的定時中斷次數

        #define const_time_3s 1332 //3秒鐘的時間需要的定時中斷次數

        #define const_time_6s 2664 //6秒鐘的時間需要的定時中斷次數

        #define const_voice_short 40 //蜂鳴器短叫的持續時間

        #define const_voice_long 200 //蜂鳴器長叫的持續時間

        void initial_myself();

        void initial_peripheral();

        void delay_long(unsigned int uiDelaylong);

        void led_flicker();

        void alarm_run();

        void T0_time(); //定時中斷函數

        sbit beep_dr=P2^7; //蜂鳴器的驅動IO口

        sbit led_dr=P3^5; //LED燈的驅動IO口

        unsigned char ucLedStep=0; //LED燈的步驟變量

        unsigned int uiTimeLedCnt=0; //LED燈統計定時中斷次數的延時計數器

        unsigned char ucAlarmStep=0; //報警的步驟變量

        unsigned int uiTimeAlarmCnt=0; //報警統計定時中斷次數的延時計數器

        unsigned int uiVoiceCnt=0; //蜂鳴器鳴叫的持續時間計數器

        void main()

        {

        initial_myself();

        delay_long(100);

        initial_peripheral();

        while(1)

        {

        led_flicker(); //第一個任務LED燈閃爍

        alarm_run(); //第二個任務報警器定時報警

        }

        }

        void led_flicker() //第三區 LED閃爍應用程序

        {

        switch(ucLedStep)

        {

        case 0:

        if(uiTimeLedCnt>=const_time_05s) //時間到

        {

        uiTimeLedCnt=0; //時間計數器清零

        led_dr=1; //讓LED亮

        ucLedStep=1; //切換到下一個步驟

        }

        break;

        case 1:

        if(uiTimeLedCnt>=const_time_05s) //時間到

        {

        uiTimeLedCnt=0; //時間計數器清零

        led_dr=0; //讓LED滅

        ucLedStep=0; //返回到上一個步驟

        }

        break;

        }

        }

        void alarm_run() //第三區 報警器的應用程序

        {

        switch(ucAlarmStep)

        {

        case 0:

        if(uiTimeAlarmCnt>=const_time_3s) //時間到

        {

        uiTimeAlarmCnt=0; //時間計數器清零

        /* 注釋二:

        * 只要變量uiVoiceCnt不為0,蜂鳴器就會在定時中斷函數里啟動鳴叫,并且自減uiVoiceCnt

        * 直到uiVoiceCnt為0時才停止鳴叫。因此控制uiVoiceCnt變量的大小就是控制聲音的長短。

        */

        uiVoiceCnt=const_voice_short; //蜂鳴器短叫

        ucAlarmStep=1; //切換到下一個步驟

        }

        break;

        case 1:

        if(uiTimeAlarmCnt>=const_time_6s) //時間到

        {

        uiTimeAlarmCnt=0; //時間計數器清零

        uiVoiceCnt=const_voice_long; //蜂鳴器長叫

        ucAlarmStep=0; //返回到上一個步驟

        }

        break;

        }

        }

        void T0_time() interrupt 1

        {

        TF0=0; //清除中斷標志

        TR0=0; //關中斷

        if(uiTimeLedCnt<0xffff) //設定這個條件,防止uiTimeLedCnt超范圍。

        {

        uiTimeLedCnt++; //LED燈的時間計數器,累加定時中斷的次數,

        }

        if(uiTimeAlarmCnt<0xffff) //設定這個條件,防止uiTimeAlarmCnt超范圍。

        {

        uiTimeAlarmCnt++; //報警的時間計數器,累加定時中斷的次數,

        }

        /* 注釋三:

        * 為什么不把驅動蜂鳴器這段代碼放到main函數的循環里去?

        * 因為放在定時中斷里,能保證蜂鳴器的聲音長度是一致的,

        * 如果放在main循環里,聲音的長度就有可能受到某些必須

        * 一氣呵成的任務干擾,得不到及時響應,影響聲音長度的一致性。

        */

        if(uiVoiceCnt!=0)

        {

        uiVoiceCnt--; //每次進入定時中斷都自減1,直到等于零為止。才停止鳴叫

        beep_dr=0; //蜂鳴器是PNP三極管控制,低電平就開始鳴叫。

        }

        else

        {

        ; //此處多加一個空指令,想維持跟if括號語句的數量對稱,都是兩條指令。不加也可以。

        beep_dr=1; //蜂鳴器是PNP三極管控制,高電平就停止鳴叫。

        }

        TH0=0xf8; //重裝初始值(65535-2000)=63535=0xf82f

        TL0=0x2f;

        TR0=1; //開中斷

        }

        void delay_long(unsigned int uiDelayLong)

        {

        unsigned int i;

        unsigned int j;

        for(i=0;i

        {

        for(j=0;j<500;j++) //內嵌循環的空指令數量

        {

        ; //一個分號相當于執行一條空語句

        }

        }

        }

        void initial_myself() //第一區 初始化單片機

        {

        beep_dr=1; //用PNP三極管控制蜂鳴器,輸出高電平時不叫。

        led_dr=0; //LED滅

        TMOD=0x01; //設置定時器0為工作方式1

        TH0=0xf8; //重裝初始值(65535-2000)=63535=0xf82f

        TL0=0x2f;

        }

        void initial_peripheral() //第二區 初始化外圍

        {

        EA=1; //開總中斷

        ET0=1; //允許定時中斷

        TR0=1; //啟動定時中斷

        }

        總結陳詞:

        本節程序已經展示了一個多任務處理的基本思路,假如要實現一個獨立按鍵檢測,能不能也按照這種思路來處理呢?欲知詳情,請聽下回分解-----在主函數中利用累計主循環次數來實現獨立按鍵的檢測。



        關鍵詞: 蜂鳴器驅動程

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 麟游县| 黄骅市| 河池市| 老河口市| 会东县| 沙洋县| 体育| 汨罗市| 运城市| 新津县| 松滋市| 巴里| 中山市| 马公市| 兴国县| 高台县| 文成县| 永胜县| 中西区| 安阳县| 高密市| 奉化市| 古田县| 克什克腾旗| 江北区| 三穗县| 横山县| 巴中市| 利津县| 石家庄市| 英吉沙县| 自治县| 凤台县| 嘉义县| 兴业县| 客服| 望奎县| 翁源县| 隆尧县| 泰宁县| 普宁市|