當前位置:編程學習大全網 - 編程語言 - 51單片機如何用壹個按鍵和壹個定時器來模擬PWM控制壹個LED燈的亮度

51單片機如何用壹個按鍵和壹個定時器來模擬PWM控制壹個LED燈的亮度

使用定時器T0產生PWM方波,

用按鍵調整占空比,20級可調

控制led燈的亮度等級.

#include "my51.h"

#include "timer0.h"

#define grading 20 //亮度20級變化

sbit keyS3=P3^5; //按鍵調整占空比,PWM_keyChange++

sbit keyS4=P3^6; // PWM_keyChange--

u8 PWM_keyChange=10; //初值,按鍵調整在1~20之間變化

//占空比 PWM_keyChange/grading

void T0_work() //本函數由T0定時器中斷函數調用

{

if(timeMultiple1Flag)

{

led=off(7); //關閉7號燈

timeMultiple1Flag=0; //清定時器復用置位標誌

}

if(timeMultiple2Flag)

{

led=on(7); //打開7號燈

timeMultiple2Flag=0; //清定時器復用置位標誌

}

}

void main() //測試

{

u8 keyFlag=1; //程序中沒有消抖處理,只是簡易的按鍵進出自鎖標誌

led0=ledon; //先打開0號燈,用於和7號燈對比亮度

initT0(1,10,grading); //1毫秒的基本定時,亮的時間1*10毫秒,暗1*(grading-10)毫秒

while(1)

{

if(0==keyS3)

{

if(keyFlag) //防止壹次按鍵中多次執行

{

keyFlag=0; //清標誌,類似同步鎖

if(++PWM_keyChange>grading)

{

PWM_keyChange=grading; //占空比最大100%

}

initT0(1,PWM_keyChange,grading);

}

}

else if(0==keyS4)

{

if(keyFlag)

{

keyFlag=0;

if(0==--PWM_keyChange) //占空比減小

{

PWM_keyChange=1; //最小占空比 1/20

}

initT0(1,PWM_keyChange,grading); //占空比減小

}

}

else

{

keyFlag=1; //按鍵鎖釋放標誌,下壹次按鍵時允許調整占空比

}

}

}

C代碼

#ifndef _MY51_H

#define _MY51_H

#include <reg52.h>

//#include <math.h>

#include <intrins.h>

#include <stdio.h>

#include "mytype.h"

#ifndef _51LED_

#define _51LED_

#define led P1 //P1總線連8個led燈,燈連573鎖存器,P1置低電平點亮

#define LED led

#define ON(x) P1&(~(1<<(x))) //打開某個燈,開多個燈用 ON(m) & ON(n)

#define OFF(x) P1|(1<<(x)) //關閉某個燈,關多個燈用 OFF(m)| OFF(n)

#define on(x) ON(x) //包含大小寫

#define off(x) OFF(x)

#define ledon 0 //某個燈,打開

#define ledoff 1 //某個燈,關閉

sbit led0=P1^0;

sbit led1=P1^1;

sbit led2=P1^2;

sbit led3=P1^3;

sbit led4=P1^4;

sbit led5=P1^5;

sbit led6=P1^6;

sbit led7=P1^7;

sbit ledLock=P2^5; //鎖定當前8個led的狀態,0鎖定 ,1不鎖定

#endif

/*************二進制輸入宏****************************/

#ifndef _LongToBin_

#define LongToBin(n) \

( \

((n >> 21) & 0x80) | \

((n >> 18) & 0x40) | \

((n >> 15) & 0x20) | \

((n >> 12) & 0x10) | \

((n >> 9) & 0x08) | \

((n >> 6) & 0x04) | \

((n >> 3) & 0x02) | \

((n ) & 0x01) \

)

#define bin(n) LongToBin(0x##n##l)

#define BIN(n) bin(n)

#define B(n) bin(n)

#define b(n) bin(n)

#endif

/*************單個數據位的置位宏*********************/

#ifndef _BIT_

#define BIT(n) (1<<n)

#define bit(n) BIT(n)

#endif

#define high 1 //高電平

#define low 0 //低電平

sbit beep=P2^3; //蜂鳴器

extern void delayms(u16 ms);

extern void delayXus(u8 us); //函數執行(8+6x)個機器周期, 即t=(8+6x)*1.085

/////////////////////////////////////////////////////////////////////////////

#endif

C代碼

#ifndef _TIMER0_H

#define _TIMER0_H

#include "my51.h"

extern u8 timeMultiple1Flag; //中斷時間復用置位標誌,須手動清零

extern u8 timeMultiple2Flag; //中斷時間復用置位標誌,須手動清零

extern void T0_work(); //該函數未實現,需外部實現

extern void initT0(u8 ms,u16 t_multiple1,u16 t_multiple2) ; //定時器初始化

#endif

C代碼

#include "timer0.h"

u8 TH0Cout=0 ; //初值

u8 TL0Cout=0 ;

u16 T0IntCouts1=0; //中斷計數

u16 T0IntCouts2=0; //中斷計數

u16 timeMultiple1=0; //中斷復用時間的倍數

u16 timeMultiple2=0; //中斷復用時間的倍數

u8 timeMultiple1Flag=0; //中斷時間復用置位標誌,須手動清零

u8 timeMultiple2Flag=0; //中斷時間復用置位標誌,須手動清零

//開啟定時器,定時完成後需要手動關閉TR0,否則將循環定時

//參數壹是定時的毫秒數,參數二和三是定時基時的倍率數(定時復用)

void initT0(u8 ms,u16 t_multiple1,u16 t_multiple2) //定時器初始化設定,ms取值不超過65

{

u16 N=11059.2*ms/12; //定時器總計數值

TR0=STOP; //停掉定時器

ET0=CLOSE; //關定時器中斷

//對於110592晶振,ms為5的整數倍時沒有計算誤差,但ms最大不超過71毫秒

TH0Cout =(65536-N)/256; //裝入計時值零頭計數初值

TL0Cout =(65536-N)%256;

if(0==t_multiple1) //0倍的基準時間是不合理的,至少1倍

{

t_multiple1=1;

}

if(0==t_multiple2) //0倍的基準時間是不合理的,至少1倍

{

t_multiple2=1;

}

timeMultiple1=t_multiple1; //倍時

timeMultiple2=t_multiple2; //倍時

TMOD &= 0xf0; //清定時器0配置

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

EA =OPEN; //打開總中斷

ET0=OPEN; //打開定時器中斷

TH0=TH0Cout; //定時器裝入初值

TL0=TL0Cout;

TR0=START; //啟動定時器

}

void T0_times() interrupt 1 //T0定時器中斷函數

{

TH0=TH0Cout; //重裝初值

TL0=TL0Cout;

if(++T0IntCouts1==timeMultiple1) //判斷是否復用定時器

{

T0IntCouts1=0; //中斷次數清零,重新計時

timeMultiple1Flag=1; //復用定時器標誌,須在T0_work()中手動清零

}

if(++T0IntCouts2==timeMultiple2) //判斷是否復用定時器

{

T0IntCouts1=0; //這個也要清,防止到達最小公倍數時亂掉

T0IntCouts2=0; //中斷次數清零,重新計時

timeMultiple2Flag=1; //復用定時器標誌,須在T0_work()中手動清零

}

T0_work(); //調用工作函數

}

  • 上一篇:如何在ARM Linux上使用FDT和initrd
  • 下一篇:學習Android應該向JAVA學習什麽?
  • copyright 2024編程學習大全網