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

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 4967|回復(fù): 4
打印 上一主題 下一主題
收起左側(cè)

屏棄Delay(),高效率單片機(jī)

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:103513 發(fā)表于 2016-1-16 22:36 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式

//2015.09.06  于廈門軟二. 程序思想轉(zhuǎn)變
    單片機(jī)已經(jīng)學(xué)了4、5年頭了,一直用慣了delay()函數(shù),意識(shí)到電子工程師們的硬件編程思想與PC機(jī)底層編程思想上的很多不同,引發(fā)了一些思考。

學(xué)單片機(jī)時(shí),老師都教我們用Delay()函數(shù)。

絕大多數(shù)8位的單片機(jī)程序,它們的單片機(jī)99.9%的工作時(shí)間都在打空轉(zhuǎn),(是否嚇了一跳,竟然讓單片機(jī)空轉(zhuǎn)以實(shí)現(xiàn)和外界同步,這怎么可能?試想,如果PC機(jī)CPU空轉(zhuǎn)一秒,那么音樂會(huì)斷一秒、畫面會(huì)停頓一秒、下載文件會(huì)斷一秒,這怎么可行?)這是一種教條的思想,把書讀死了

99.9%大家可能感到有些危言聳聽,那就讓我們算一算:

已內(nèi)部8M頻的AVR單片機(jī)來說,單指令周期僅為1/8 = 0.125us,那一毫秒可以執(zhí)行多少個(gè)單周期指令? 1%0.125*1000 = 8000個(gè)而我看到論壇里下到的絕大多數(shù)程序,兩個(gè)延時(shí)函數(shù)之間代碼的執(zhí)行時(shí)間要遠(yuǎn)遠(yuǎn)小于8000個(gè)指令周期。

說實(shí)話,很多16K以上的程序,把所有延時(shí)函數(shù)去掉,總體能執(zhí)行幾毫秒就不錯(cuò)了。換句話說,我說單片機(jī)的利用率小于0.01%還是口下留情了。

要說怎么解決問題,就要先找到問題,我問問大家,程序中,我們?yōu)槭裁囱訒r(shí)?原因很多,可能是外設(shè)速度太慢,也可能是為了躲過人眼視覺停留時(shí)間,等等。總之就是與外界不同步,而我們想要同步。

所以說這些延時(shí)應(yīng)該是很有道理的,我不否定這一點(diǎn),但問題的關(guān)鍵這些延時(shí)空轉(zhuǎn),我們?yōu)槭裁床荒馨堰@些時(shí)間回收起來做一些別的事呢?

試想,如果把這99.9%的時(shí)間回收,那可以一筆相當(dāng)巨大的資源。

有很多人有些特殊方法回收過這些空轉(zhuǎn)時(shí)間,比如說在延時(shí)函數(shù)中做點(diǎn)事。

但這些往往都不通用,下面我說一些我的兩種方法:

 

 1.從點(diǎn)亮LED(發(fā)光二極管)開始

在市面上眾多的單片機(jī)學(xué)習(xí)資料中,最基礎(chǔ)的實(shí)驗(yàn)無疑于點(diǎn)亮LED了,即控制單片機(jī)的I/O的電平的變化。

如同如下實(shí)例代碼一般

void main(void)

{

    LedInit() ;

    While(1) 

    { 

        LED = ON ;

        DelayMs(500) ;

        LED = OFF ;

        DelayMs(500) ;

        }

}

程序很簡單,從它的結(jié)構(gòu)可以看出,LED先點(diǎn)亮500MS,然后熄滅500MS,如此循環(huán)下去,形成的效果就是LED以1HZ的頻率進(jìn)行閃爍。下面讓我們分析上面的程序有沒有什么問題。

看來看出,好像很正常的啊,能有什么問題呢?這個(gè)時(shí)候我們應(yīng)該換一個(gè)思路去想了。試想,整個(gè)程序除了控制LED = ON ; LED = OFF; 這兩條語句外,其余的時(shí)間,全消耗在了DelayMs(500)這兩個(gè)函數(shù)上。而在實(shí)際應(yīng)用系統(tǒng)中是沒有哪個(gè)系統(tǒng)只閃爍一只LED就其它什么事情都不做了的。因此,在這里我們要想辦法,把CPU解放出來,讓它不要白白浪費(fèi)500MS的延時(shí)等待時(shí)間。寧可讓它一遍又一遍的掃描看有哪些任務(wù)需要執(zhí)行,也不要讓它停留在某個(gè)地方空轉(zhuǎn)消耗CPU時(shí)間。

 

從上面我們可以總結(jié)出

(1)    無論什么時(shí)候我們都要以實(shí)際應(yīng)用的角度去考慮程序的編寫。

(2)    無論什么時(shí)候都不要讓CPU白白浪費(fèi)等待,尤其是延時(shí)(超過1MS)這樣的地方。

 

下面讓我們從另外一個(gè)角度來考慮如何點(diǎn)亮一顆LED。 先看看我們的硬件結(jié)構(gòu)是什么樣子的。

紅色的壓降為1.82-1.88V,電流5-8mA,

綠色的壓降為1.75-1.82V,電流3-5mA,

橙色的壓降為1.7-1.8V,電流3-5mA

蘭色的壓降為3.1-3.3V,電流8-10mA,

白色的壓降為3-3.2V,電流10-15mA,

(供電電壓5V,LED直徑為5mm)

 

74HC573真值表如下:

一般的LED的正常發(fā)光電流為10~20MA而低電流LED的工作電流在2mA以下(亮度與普通發(fā)光管相同)。在上圖中我們可知,當(dāng)Q1~Q8引腳上面的電平為低電平時(shí),LED發(fā)光。通過LED的電流約為(VCC - Vd)/ RA2 。其中Vd為LED導(dǎo)通后的壓降,約為1.7V左右。這個(gè)導(dǎo)通壓降根據(jù)LED顏色的不同,以及工作電流的大小的不同,會(huì)有一定的差別。下面一些參數(shù)是網(wǎng)上有人測出來的,供大家參考。

需要注意的是,通過74HC573的最大電流是有限制的,否則可能會(huì)燒壞74HC573這個(gè)芯片。 上面這個(gè)圖是從74HC573的DATASHEET中截取出來的,從上可以看出,每個(gè)引腳允許通過的最大電流為35mA 整個(gè)芯片允許通過的最大電流為75mA。在我們?cè)O(shè)計(jì)相應(yīng)的驅(qū)動(dòng)電路時(shí)候,這些參數(shù)是相當(dāng)重要的,而且是最容易被初學(xué)者所忽略的地方。同時(shí)在設(shè)計(jì)的時(shí)候,要留出一定量的余量出來,不能說單個(gè)引腳允許通過的電流為35mA,你就設(shè)計(jì)為35mA,這個(gè)時(shí)候你應(yīng)該把設(shè)計(jì)的上限值定在20mA左右才能保證能夠穩(wěn)定的工作。

(設(shè)計(jì)相應(yīng)驅(qū)動(dòng)電路時(shí)候,應(yīng)該仔細(xì)閱讀芯片的數(shù)據(jù)手冊(cè),了解每個(gè)引腳的驅(qū)動(dòng)能力,以及整個(gè)芯片的驅(qū)動(dòng)能力)

 

了解了相應(yīng)的硬件后,我們?cè)賮砭帉戲?qū)動(dòng)程序。

#include<reg52.h>

sbit LED_SEG  = P1^4;       //數(shù)碼管段選

sbit LED_DIG  = P1^5;       //數(shù)碼管位選

sbit LED_CS11 = P1^6;       //led控制位

sbit ir=P1^7;

//首先定義LED的接口然后為亮滅常數(shù)定義一個(gè)宏

#define LED P0                     //定義LED接口

bit  g_bSystemTime1Ms = 0 ;                            // 1MS系統(tǒng)時(shí)標(biāo)

//下面到了重點(diǎn)了,究竟該如何釋放CPU,避免其做延時(shí)空等待這樣的事情呢。

很簡單,我們?yōu)橄到y(tǒng)產(chǎn)生一個(gè)1MS的時(shí)標(biāo)。假定LED需要亮500MS,熄滅500MS,那么我們可以對(duì)這個(gè)1MS的時(shí)標(biāo)進(jìn)行計(jì)數(shù),當(dāng)這個(gè)計(jì)數(shù)值達(dá)到500時(shí)候,清零該計(jì)數(shù)值,同時(shí)把LED的狀態(tài)改變。

unsigned int  g_u16LedTimeCount = 0 ;       //LED計(jì)數(shù)器

unsigned char g_u8LedState = 0 ;              //LED狀態(tài)標(biāo)志, 0表示亮,1表示熄滅

 

#define LED_ON()       LED = 0x00 ;              //所有LED亮

#define LED_OFF()       LED = 0xff ;              //所有LED熄滅

 

void Timer0Init(void)              //定時(shí)器初始化

{

    TMOD &= 0xf0 ;

    TMOD |= 0x01 ;                     //定時(shí)器0工作方式1

    TH0  =  0xfc ;                     //定時(shí)器初始值

    TL0  =  0x66 ;

    TR0  = 1 ;

    ET0  = 1 ;

}

void LedProcess(void)              //計(jì)時(shí)到_執(zhí)行LED動(dòng)作

{

    if(0 == g_u8LedState)       //如果LED的狀態(tài)為亮,則點(diǎn)亮LED

    { 

        LED_ON() ;

    } 

    else                                   //否則熄滅LED 

    { 

        LED_OFF() ;

    } 

}

 

void LedStateChange(void)        //1ms計(jì)時(shí)到_執(zhí)行動(dòng)作

{

       if(g_bSystemTime1Ms)                                   //系統(tǒng)1MS時(shí)標(biāo)到

       {

              g_bSystemTime1Ms = 0 ;

              //在我們的定時(shí)器中斷函數(shù)中對(duì)其置位,其它函數(shù)使用該變量后,應(yīng)該對(duì)其復(fù)位(清0)

              g_u16LedTimeCount++ ;                            //LED計(jì)數(shù)器加一

              if(g_u16LedTimeCount >= 500)              //計(jì)數(shù)達(dá)到500,即500MS到了,改變LED的狀態(tài)。

              {

                     g_u16LedTimeCount = 0 ;               //LED計(jì)數(shù)器_清0

                     g_u8LedState  = ! g_u8LedState;       //LED狀態(tài)標(biāo)志, 0表示亮,1表示熄滅

              }

    }

}

//因?yàn)長ED的亮或者滅依賴于LED狀態(tài)變量(g_u8LedState)的改變,而狀態(tài)變量的改變,又依賴于LED計(jì)數(shù)器的計(jì)數(shù)值(g_u16LedTimeCount ,只有計(jì)數(shù)值達(dá)到一定后,狀態(tài)變量才改變)所以,兩個(gè)函數(shù)都沒有堵塞CPU的地方。

void main(void)

{

    Timer0Init() ;

    EA = 1 ;

       LED_CS11 = 1 ; //74HC595輸出允許

    LED_SEG = 0 ;  //數(shù)碼管段選和位選禁止(因?yàn)樗鼈兒蚅ED共用P0口)

    LED_DIG = 0 ;

    while(1) 

    { 

        LedProcess() ;              //

        LedStateChange() ;       //計(jì)時(shí)到_執(zhí)行動(dòng)作

    } 

} 

 

void Time0Isr(void) interrupt 1

{

       TH0=0xfc;                            //定時(shí)器重新賦初值

    TL0=0x66;                            //每1ms溢出1次

    g_bSystemTime1Ms=1;              //1ms時(shí)標(biāo)“標(biāo)志位”置位 

}

因?yàn)長ED的亮或者滅依賴于LED狀態(tài)變量(g_u8LedState)的改變,而狀態(tài)變量的改變,又依賴于LED計(jì)數(shù)器的計(jì)數(shù)值(g_u16LedTimeCount ,只有計(jì)數(shù)值達(dá)到一定后,狀態(tài)變量才改變)所以,兩個(gè)函數(shù)都沒有堵塞CPU的地方。讓我們來從頭到尾分析一遍整個(gè)程序的流程。

 

程序首先執(zhí)行LedProcess() ;函數(shù)因?yàn)間_u8LedState 的初始值為0 (見定義,對(duì)于全局變量,在定義的時(shí)候最好給其一個(gè)確定的值)所以LED被點(diǎn)亮,然后退出LedStateChange()函數(shù),執(zhí)行下一個(gè)函數(shù)LedStateChange()

在函數(shù)LedStateChange()內(nèi)部首先判斷1MS的系統(tǒng)時(shí)標(biāo)是否到了,如果沒有到就直接退出函數(shù),如果到了,就把時(shí)標(biāo)清0以便下一個(gè)時(shí)標(biāo)消息的到來,同時(shí)對(duì)LED計(jì)數(shù)器加一,然后再判斷LED計(jì)數(shù)器是否到達(dá)我們預(yù)先想要的值500,如果沒有,則退出函數(shù),如果有,對(duì)計(jì)數(shù)器清0,以便下次重新計(jì)數(shù),同時(shí)把LED狀態(tài)變量取反,然后退出函數(shù)。

由上面整個(gè)流程可以知道,CPU所做的事情,就是對(duì)一些計(jì)數(shù)器加一,然后根據(jù)條件改變狀態(tài),再根據(jù)這個(gè)狀態(tài)來決定是否點(diǎn)亮LED。這些函數(shù)執(zhí)行所花的時(shí)間都是相當(dāng)短的,如果主程序中還有其它函數(shù),則CPU會(huì)順次往下執(zhí)行下去。對(duì)于其它的函數(shù)(如果有的話)也要采取同樣的措施,保證其不堵塞CPU,如果全部基于這種方法設(shè)計(jì),那么對(duì)于不是非常龐大的系統(tǒng),我們的系統(tǒng)依舊可以保證多個(gè)任務(wù)(多個(gè)函數(shù))同時(shí)執(zhí)行。系統(tǒng)的實(shí)時(shí)性得到了一定的保證,從宏觀上看來,就是多個(gè)任務(wù)并發(fā)執(zhí)行。

 

好了,這一章就到此為止,讓我們總結(jié)一下,究竟有哪些需要注意的吧。

(1)    無論什么時(shí)候我們都要以實(shí)際應(yīng)用的角度去考慮程序的編寫。

(2)    無論什么時(shí)候都不要讓CPU白白浪費(fèi)等待,尤其是延時(shí)(超過1MS)這樣的地方。

(3)    設(shè)計(jì)相應(yīng)驅(qū)動(dòng)電路時(shí)候,應(yīng)該仔細(xì)閱讀芯片的數(shù)據(jù)手冊(cè),了解每個(gè)引腳的驅(qū)動(dòng)能力,以及整個(gè)芯片的驅(qū)動(dòng)能力

(4)    最重要的是,如何去釋放CPU(參考本章的例子),這是寫出合格程序的基礎(chǔ)。

 

 

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏4 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:149451 發(fā)表于 2019-5-25 13:18 | 只看該作者
LZ軟硬兼修,佩服佩服...................
回復(fù)

使用道具 舉報(bào)

板凳
ID:522695 發(fā)表于 2019-6-1 12:00 | 只看該作者
總感覺就這樣用去了一個(gè)定時(shí)器。。。。有點(diǎn)浪費(fèi)或許會(huì)有更好解決cpu堵塞的方法
回復(fù)

使用道具 舉報(bào)

地板
ID:569384 發(fā)表于 2020-6-23 10:58 | 只看該作者
一直都是用計(jì)數(shù)的方法來延時(shí),如果用while或者for循環(huán)的話程序就會(huì)卡在循環(huán)里等待,如果我的產(chǎn)品是有按鍵的話就很影響使用,所以一定要用計(jì)數(shù)的方法來延時(shí)。
回復(fù)

使用道具 舉報(bào)

5#
ID:569384 發(fā)表于 2020-6-23 11:02 | 只看該作者
鉆研旋律 發(fā)表于 2019-6-1 12:00
總感覺就這樣用去了一個(gè)定時(shí)器。。。。有點(diǎn)浪費(fèi)或許會(huì)有更好解決cpu堵塞的方法

樓主說的應(yīng)該是這樣一個(gè)概念,肯定有其他的方法。比如我寫程序的時(shí)候如果延時(shí)時(shí)間不需要太精準(zhǔn),我就會(huì)直接在主函數(shù)或子函數(shù)中讓變量++,到了一個(gè)值后(比如500)再清零,讓后執(zhí)行命令。這樣也能做到延時(shí)效果。如果要時(shí)間要精準(zhǔn)就一定要用定時(shí)器來實(shí)現(xiàn)了。
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 狠狠干影院 | 精品久久香蕉国产线看观看亚洲 | 岛国av免费观看 | www.欧美.com| 国内精品久久久久久 | 97偷拍视频| 欧美性jizz18性欧美 | 国产伦精品一区二区三区四区视频 | 不卡一区| 国产精品99一区二区 | 国产成人精品一区二区 | 国产精品mv在线观看 | 美女黄18岁以下禁止观看 | 91精品国产色综合久久不卡蜜臀 | 亚洲成人精品国产 | 成人免费视频久久 | 天天射视频| xx视频在线| 久久久久国产精品午夜一区 | 亚洲一区二区三区在线免费观看 | 中文字幕一区二区三区四区五区 | 国产精品久久久久久亚洲调教 | 丁香综合 | 亚洲一区三区在线观看 | 久久精彩视频 | 欧美成人在线免费 | 欧美亚洲视频 | 日韩av手机在线观看 | 91av导航| 97超碰人人草 | 91精品国产手机 | 男人天堂网址 | 精品91久久 | 欧美手机在线 | 国产99免费视频 | 日韩亚洲视频 | 国产欧美日韩在线播放 | 国产精品91视频 | 福利电影在线 | 一区二区三区中文字幕 | 久久国际精品 |