寫在前言
? 此為博主自學江科大51單片機(B站)的筆記,方便后續重溫知識
? 在后面的章節中,為了防止篇幅過長和易于查找,我把一個小節分成兩部分來發,上章節主要是關于本節課的硬件介紹、電路圖、原理圖等理論知識,主要是為下章節的代碼部分打基礎。
? 我的單片機是24年12月在tb普中買的,型號是STC89C52,在原視頻中引腳或接口不對應的我都會改正,保證在我的機子上能運行才發上來的,還有一些文字部分是我的理解,并非照搬,所以可能有理解不到位的現象。
??如有誤或交流,敬請指點提問
本節課一共兩個代碼,LED呼吸燈和直流電機調速
一、直流電機
1.介紹
- 直流電機是一種將電能轉換為機械能的裝置。一般的直流電機有兩個電極,當電極正接時,電機正轉,當電極反接時,電機反轉
- 直流電機主要由永磁體(定子)、線圈(轉子)和換向器組成
- 除直流電機外,常見的電機還有步進電機(機殼裝載了一圈電磁鐵,對相對兩個電磁鐵進行一圈脈沖式通電,優點是嚴格控速精密)、舵機(跟船舵一樣,方便控制轉向)、無刷電機(轉速特別快)、空心杯電機(體積很小)等
- 左1就是我們開發板里的電機,有兩個電極;左1是N20,一個直流電機+減速箱;右1比左2還多帶一個編碼器(測速),PID算法(常用)控制電機速度
2.驅動電路
有兩種方式
-
大功率器件直接驅動?
不能正反轉上面是一個三極管控制開關,下面是一個蓄流二極管,用于保護電路;因為電機(繼電器)是感性負載元件,驅動的時候會出現很高的電壓(電感的特效)
這個ULN2003里面也是一個大功率元件
-
H橋驅動
能正反轉因為我們使第二、四象限的二極管導通其余的截止,就會令電流向右走,如果反過來就可以令電流向左走;因為沒有蓄流二極管保護,所以對mos管和晶體管的耐壓特效要求比較高
二、PWM
PWM是控制直流電機調速的
1.介紹
- PWM(Pulse Width Modulation)即脈沖寬度調制,在具有慣性的系統中,可以通過對一系列脈沖的寬度進行調制,來等效地獲得所需要的模擬參量,常應用于電機控速、開關電源等領域
- PWM重要參數:
- 頻率=1/Ts? 占空比=Ton/Ts? 精度=占空比變化步距
三、代碼實戰
1.LED呼吸燈?
先定義一下引腳
然后再定義一個比較快的延時函數,讓這個LED燈先亮一段時間,再滅一段時間,這就是PWM的工作原理,通常為了保證周期是穩定的,不隨占空比變化而變化,所以亮和滅加起來的時間也要是個固定值
#include <REGX52.H>sbit LED=P2^0;void Delay(unsigned int t)
{while(t--);
}void main()
{while(1){LED=0;Delay(5);LED=1;Delay(95);}
}
接下來就是讓亮和滅的值不斷變化,從而實現呼吸燈的效果
我們就可以定義一個變量Time,讓亮的時間為Time,滅的時間為100-Time,這樣就可以實現兩個數加起來是固定值,然后我們再對Time進行for循環,不斷++
但是這個速度還是比較快,我們讓他每次亮滅變換的時間再久一點,定義一個i,在for循環里嵌套再進行一次for循環,這樣就可以實現LED一直從暗到亮
但是我們還想實現從暗到亮,再從亮到暗又怎么做呢,就是把之前的外層對Time的for循環反過來再依次--
#include <REGX52.H>sbit LED=P2^0;void Delay(unsigned int t)
{while(t--);
}void main()
{unsigned char Time,i;while(1){for(Time=0;Time<100;Time++){for(i=0;i<20;i++){LED=0;Delay(Time);LED=1;Delay(100-Time); }}for(Time=100;Time>0;Time--){for(i=0;i<20;i++){LED=0;Delay(Time);LED=1;Delay(100-Time); }}}
}
這樣就可以實現呼吸燈從暗到亮,再從亮到暗
但是會有一個缺點,就是占用了我們的主循環不斷翻轉IO口,還比較占用CPU
一般都會寫到定時器上,或者從硬件上解決
所以在下面的代碼中我們用定時器來實現
2.直流電機調速
在這個代碼我們就用定時器來實現LED呼吸燈和直流電機調速功能
產生PWM方法
我們通過改變比較值就可以改變占空比?
由于之前的定時器設置有點慢,我們讓他快一點
這個PWM驅動電機在一定范圍內是越快越好,一般設置在10K-20K范圍里,如果頻率比較低,電流就會抖動,如果在1K左右,就會產生一些蜂鳴器的聲音
這個中斷就是每隔100us中斷一次
//timer0.c#include <REGX52.H>/*** @brief 定時器0初始化,100us@12.000MHz* @param 無* @retval 無*/
void Timer0_Init(void)
{TMOD &= 0xF0; //設置定時器模式TMOD |= 0x01; //設置定時器模式TL0 = 0xA4; //設置定時初值TH0 = 0xFF; //設置定時初值TF0 = 0; //清除TF0標志TR0 = 1; //定時器0開始計時ET0=1;EA=1;PT0=0;
}/*定時器中斷函數模板
void Timer0_Routine() interrupt 1
{static unsigned int T0Count;TL0 = 0xA4; //設置定時初值TH0 = 0xFF; //設置定時初值T0Count++;if(T0Count>=1000){T0Count=0;}
}
*/
由上面的圖可以知道要定義兩個值,計數值和比較值,
我們讓計數值從0-100然后清零,實現定時自增
?? ?Counter++;
?? ?Counter%=100;
這樣寫和if(counter==100){清零}是一個效果
接下來再讓計數值和比較值進行比較
可以觀察到如果比較值越大,低電平時間越久,也就是越暗
這樣我們通過控制比較值Compare就可以控制LED的亮度,還剩下下了主循環,接下來我們就實現按鍵功能
#include <REGX52.H>
#include " Delay.h"
#include " Key.h"
#include " Nixie.h"
#include " Timer0.h"sbit LED=P2^0;unsigned char Counter,Compare;void main()
{Timer0_Init();Compare=5;while(1){}}void Timer0_Routine() interrupt 1
{TL0 = 0xA4; //設置定時初值TH0 = 0xFF; //設置定時初值Counter++;Counter%=100;if(Counter<Compare){LED=0;}else{LED=1;}
}
注意后面取的Key函數,如果是拿的定時器掃描按鍵的那章寫的Key函數,要在定時器中寫上這個Key_Loop()
#include <REGX52.H>
#include " Delay.h"
#include " Key.h"
#include " Nixie.h"
#include " Timer0.h"sbit LED=P2^0;unsigned char Counter,Compare;
unsigned char KeyNum,Speed;void main()
{Timer0_Init();Compare=5;while(1){KeyNum=Key();if(KeyNum==1){Speed++;Speed%=4;}Nixie(1,Speed);}}void Timer0_Routine() interrupt 1
{Key_Loop();TL0 = 0xA4; //設置定時初值TH0 = 0xFF; //設置定時初值Counter++;Counter%=100;if(Counter<Compare){LED=0;}else{LED=1;}
}
這樣就可以實現按下按鍵1數碼管顯示++并且過3就清零
接下來將Speed跟Compare比較值對應起來,就可以實現按鍵調速并顯示
這樣就可以實現LED的亮度控制
?? ??? ??? ?if(Speed==0){Compare=5;}
?? ??? ??? ?if(Speed==1){Compare=5;}
?? ??? ??? ?if(Speed==2){Compare=50;}
?? ??? ??? ?if(Speed==3){Compare=100;}?? ?
那我們如果想控制電機,就直接把LED的端口改成電機的端口,而又因為我們的LED是給0亮給1滅,而電機是給1轉給0滅,所以需要把極性反過來
這里有個小問題,在剛上電的時候,電機會轉動,這是硬件的問題,因為單片機在復位的時候,IO口默認高電平,所以電機會轉
#include <REGX52.H>
#include " Delay.h"
#include " Key.h"
#include " Nixie.h"
#include " Timer0.h"sbit Motor=P1^0;unsigned char Counter,Compare;
unsigned char KeyNum,Speed;void main()
{Timer0_Init();Compare=5;while(1){KeyNum=Key();if(KeyNum==1){Speed++;Speed%=4;if(Speed==0){Compare=0;}if(Speed==1){Compare=50;}if(Speed==2){Compare=75;}if(Speed==3){Compare=100;} }Nixie(1,Speed);}}void Timer0_Routine() interrupt 1
{Key_Loop();TL0 = 0xA4; //設置定時初值TH0 = 0xFF; //設置定時初值Counter++;Counter%=100;if(Counter<Compare){Motor=1;}else{Motor=0;}
}
這樣就實現本節課的代碼啦,按下按鍵調節電機的速度并且顯示出來。