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

QQ登錄

只需一步,快速開(kāi)始

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

單片機(jī)流水燈與呼吸燈結(jié)合-滴水燈程序及詳細(xì)教程

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:81203 發(fā)表于 2015-5-26 19:22 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
TWAS手把手教你做呼吸燈-基于51單片機(jī)學(xué)習(xí)板
內(nèi)容比較簡(jiǎn)單,發(fā)這個(gè)貼主要是針對(duì)新手!
什么是呼吸燈?
    顧名思義,燈光在微電腦控制之下完成由亮到暗的逐漸變化,感覺(jué)像是在呼吸。用專業(yè)的話來(lái)說(shuō)是通過(guò)控制PWM的占空比來(lái)完成對(duì)LED亮度的控制
什么是PWM和占空比?
    脈沖寬度調(diào)制(Pulse Width Modulation,簡(jiǎn)稱PWM),是利用微處理器的數(shù)字輸出來(lái)對(duì)模擬電路進(jìn)行控制的一種技術(shù)。
    占空比:高電平在一個(gè)周期之內(nèi)所占的時(shí)間比率。
呼吸燈原理
    當(dāng)一顆LED在高速閃爍,閃爍的頻率已經(jīng)超過(guò)了人眼的感知的范圍,那么我們看到這顆LED就是一直亮的,也就是視覺(jué)暫留現(xiàn)象(余暉效應(yīng))。如果

我們控制一次閃爍中亮和滅的時(shí)間(修改占空比),就可以控制亮度。
    代碼實(shí)現(xiàn):
/*******************************************************
*  程序名稱:main.c
*  程序功能:實(shí)現(xiàn)呼吸燈的主程序文件
*  程序作者:TWAS
*  創(chuàng)建時(shí)間:2015-1-22
*  修改時(shí)間:
*  程序版本:V0.1
*******************************************************/


/* 包含的頭文件 */
#include <reg52.h>


/* 尋址變量定義 */
sbit LED_Drive = P3^5;         /* 定義驅(qū)動(dòng)LED的IO口,LED為共陽(yáng) */




/******************************************************
* 函數(shù)名稱:main
* 函數(shù)功能:主函數(shù)
* 入口參數(shù):NULL
* 出口參數(shù):NULL
*******************************************************/
int main()
{
    unsigned char i;
    /* 初始化 */
        LED_Drive = 1;


        /* 主循環(huán) */
        while(1)
        {
            for(i = 0; i < 200; i++)
                {


                    /* 外邊的for循環(huán)共循環(huán)200次,前面10次點(diǎn)亮LED,后面180次熄滅LED
                         * 通過(guò)修改if后面的值,就可以改變占空比
                         */
                        if(i < 10)
                        {
                                LED_Drive = 0;
                        }
                        else
                        {
                                LED_Drive = 1;
                        }
             }   
        }


        return 0;
}


/******************************************
*                      程序結(jié)束
*****************************************/

可以明顯看出我們所控制的LED比電源燈暗許多,既然我們會(huì)控制亮度,想實(shí)現(xiàn)呼吸燈也就變的簡(jiǎn)單了
    代碼實(shí)現(xiàn):(為了節(jié)約空間和界面簡(jiǎn)潔,只貼出主要實(shí)現(xiàn)的部分)
int main()
{
   
    unsigned char         i;
        unsigned char ucNum = 0;                 /* 新增兩個(gè)變量,ucNum控制占空比*/
        bit            bAdd = 1;                 /* bAdd選擇是增大占空比還是減小占空比 */
    /* 初始化 */
        LED_Drive = 1;


        /* 主循環(huán) */
        while(1)
        {
            
            for(i = 0; i < 200; i++)
                {


                    /* 外邊的for循環(huán)共循環(huán)200次,前面10次點(diǎn)亮LED,后面180次熄滅LED
                         * 通過(guò)修改if后面的值,就可以改變占空比
                         */
                        if(i < ucNum)
                        {
                                LED_Drive = 0;
                        }
                        else
                        {
                                LED_Drive = 1;
                        }
             }
                 /* 選擇是增大占空比還是減小占空比 */
                 if (1 == bAdd)
                 {
                     ucNum++;
                 }
                 else
                 {
                     ucNum--;
                 }
                 
                 /* 當(dāng)Num等于200也就是最大值時(shí),bAdd置0,Num開(kāi)始減小 */
                 if (200 == ucNum)
                 {
                     bAdd = 0;
                 }
                 /* 當(dāng)Num等于200也就是最大值時(shí),bAdd置1,Num開(kāi)始增大 */
                 else if (0 == ucNum)
                 {
                     bAdd = 1;
                 }
                    
        }


        return 0;
}
     由于圖片看不到效果,這個(gè)地方就不貼圖了,根據(jù)測(cè)試,我們的所需要的功能實(shí)現(xiàn)了!
但是這時(shí)候有的人就有疑問(wèn)了,這是很普通的LED,那如果是特殊一點(diǎn)的呢?比如我所用的
學(xué)習(xí)板上面,16顆LED是用595驅(qū)動(dòng)的,那呼吸燈又該如何實(shí)現(xiàn)呢?
    其實(shí)很簡(jiǎn)單,我們把驅(qū)動(dòng)LED的函數(shù)封裝一下,直接替換,其它不變就行了!
    代碼實(shí)現(xiàn):(為了節(jié)約空間和界面簡(jiǎn)潔,只貼出主要實(shí)現(xiàn)的部分)
for(i = 0; i < 200; i++)
{


    /* 外邊的for循環(huán)共循環(huán)200次,前面10次點(diǎn)亮LED,后面180次熄滅LED
         * 通過(guò)修改if后面的值,就可以改變占空比
         */
        if(i < ucNum)
        {
                DriveLED(0x0003);   /* LED驅(qū)動(dòng),點(diǎn)亮D1和D2 */
        }
        else
        {
                DriveLED(0x0002);   /* LED驅(qū)動(dòng),熄滅D1點(diǎn)亮D2 */
        }
}
     當(dāng)我把程序改成這樣的時(shí)候,出了一點(diǎn)問(wèn)題,不能呼吸,變成閃爍了!等等,先把LED驅(qū)動(dòng)部分發(fā)一下:

/******************************************************
* 函數(shù)名稱:SendData
* 函數(shù)功能:74HC595數(shù)據(jù)的發(fā)送
* 入口參數(shù):unsigned int uiDataOne, unsigned int uiDataTwo
* 出口參數(shù):void
*******************************************************/
void SendData(unsigned char ucDataOne, unsigned char ucDataTwo)
{
         
    unsigned int i = 0;
        
          /* 將片選信號(hào)置為低電平 */
          HC595RCK = 0;
        
          /* 輸入第一個(gè)數(shù)據(jù):uiDataOne */
          for (i = 0; i < 8; i++)
          {
        /* 給出脈沖信號(hào),首先將CLK置為0 */
                          HC595CLK = 0;
                          if (0 != (ucDataOne & 0x80))
                                {
            HC595DATA = 1;   
        }
                                else
                                {
            HC595DATA = 0;
        }
                                /* 給出脈沖信號(hào),首先將CLK置為1 */
                                HC595CLK = 1;
                                /* 準(zhǔn)備第二個(gè)數(shù)據(jù) */
                                ucDataOne = ucDataOne << 1;
    }
               
          /* 輸入第二個(gè)數(shù)據(jù):uiDataTwo */
          for (i = 0; i < 8; i++)
          {
        /* 給出脈沖信號(hào),首先將CLK置為0 */
                          HC595CLK = 0;
                          if (0 != (ucDataTwo & 0x80))
                                {
            HC595DATA = 1;   
        }
                                else
                                {
            HC595DATA = 0;
        }
                                /* 給出脈沖信號(hào),首先將CLK置為1 */
                                HC595CLK = 1;
                                /* 準(zhǔn)備第二個(gè)數(shù)據(jù) */
                                ucDataTwo = ucDataTwo << 1;
    }
               
                /* 將片選信號(hào)置為高電平 */
          HC595RCK = 1;
}


/********************************************************
*  函數(shù)名稱:DriveLED
*  函數(shù)功能:595驅(qū)動(dòng)程序是分兩個(gè)數(shù)據(jù)發(fā)的,
*            本函數(shù)把它合并成一個(gè)數(shù)據(jù)
*  入口參數(shù):uiData:16顆LED需要顯示的數(shù)據(jù)
*  出口參數(shù):NULL
*******************************************************/
void DriveLED(unsigned int uiData)
{
    SendData(uiData >> 8,uiData);
}

     繼續(xù)剛剛的問(wèn)題,呼吸燈變成閃爍了,怎么回事呢?在程序邏輯上是沒(méi)有問(wèn)題的,
我們只是更改了LED的驅(qū)動(dòng)部分,看來(lái)就是LED驅(qū)動(dòng)的問(wèn)題了!先來(lái)Debug看一下,執(zhí)行
DriveLED這個(gè)函數(shù),時(shí)間是接近400微妙,循環(huán)200次,就是差不多80毫秒,那么LED的
閃爍頻率為12.5HZ(都是大概的值,沒(méi)有精確計(jì)算),還不足以形成視覺(jué)暫留現(xiàn)象。
那怎么辦呢,減少循環(huán)次數(shù)為50,頻率增大到50HZ左右,像這樣:
for(i = 0; i < 50; i++)
{



         /* 通過(guò)修改ucNum的值,就可以改變占空比 */
        if(i < ucNum)
        {
                DriveLED(0x0003);   /* LED驅(qū)動(dòng),點(diǎn)亮D1和D2 */
        }
        else
        {
                DriveLED(0x0002);   /* LED驅(qū)動(dòng),熄滅D1點(diǎn)亮D2 */
        }
}
經(jīng)過(guò)驗(yàn)證!成功了!
如有錯(cuò)誤的地方,希望大家批評(píng)指正!
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏8 分享淘帖 頂1 踩

相關(guān)帖子

回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:82588 發(fā)表于 2015-6-14 10:42 | 只看該作者
學(xué)習(xí)的是一種思維的方法,感覺(jué)挺好,收藏待練習(xí)
回復(fù)

使用道具 舉報(bào)

板凳
ID:83294 發(fā)表于 2015-6-20 17:40 | 只看該作者
剛剛驗(yàn)證了一下,確實(shí)可以實(shí)現(xiàn),樓主厲害
回復(fù)

使用道具 舉報(bào)

地板
ID:581062 發(fā)表于 2019-7-9 16:45 | 只看該作者
樓主我也遇到麻煩為啥用PWM。調(diào)光的呼吸燈的程序變成流水燈程序的一個(gè)函數(shù)調(diào)用的形式。結(jié)果只有流水沒(méi)有呼吸。
求救大佬:'(
#include"reg52.h"
#include<intrins.h>
typedef unsigned int u16;
typedef unsigned char u8;


sbit led1=P2;
int PWM_Low,Clock=500;
#define led P2
void delay(u16 a)
{while(a--);
}


           void main1(int t)
           {       
                          
                             for(PWM_Low=Clock;PWM_Low>0;PWM_Low--)
                                  {t=1;
                                delay(PWM_Low);
                                {int b;
for (b=0;b<PWM_Low;b++);}
                                t=0;
                                delay(Clock-PWM_Low);
                                        {int b;
for (b=0;b<Clock-PWM_Low;b++);}
       
                                }        }
                                 
void main()
{u8 i,t,t1,t2;
t1=0xfe;
t2=0x7f;
for(i=0;i<4;i++)
{t=t1&t2;
led=t;
main1(t);
delay(50000);

t1=_crol_(t1,1);
t2=_cror_(t2,1);}  }
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

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

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

快速回復(fù) 返回頂部 返回列表