1. PWMとは何ですか?
PWM(Pulse Width Modulation)パルス幅変調。一連のパルスの幅を変調し、必要な波形(形状と振幅を含む)に相当し、アナログ信号レベルをデジタルエンコードします。 素人の言葉で言えば、それは期間内の高レベルと低レベル(高レベル:5 / 3.3V、低レベル:0V)の長さを制御することです。高低レベル時間の変化を調整することにより、信号、エネルギーなどの変化を調整します。写真は、周期が4ミリ秒、デューティサイクルが0.25のPWM波形を示しています。
- 2つの重要な概念、周波数とデューティサイクル
周波数: 1秒あたりに信号が高レベルから低レベルに移動して高レベルに戻る回数を指します。これはPWM波サイクルの逆数です。周波数= 1 /(0.003 + 0.001)上記の図= 250 HZの
デューティサイクルは:期間よりも長い持続ハイレベルを意味時間。上図では、デューティ比= 1 /(1 + 3)= 25%であるため、デューティ比を制御することで出力の等価電圧を制御できます。
したがって、方形波の場合、周波数とデューティサイクルによって波が決まります。
2. PWM波はどのように生成できますか?
方法1:チップの内部モジュールを使用してPWM信号を出力します。ただし、STM32タイマーの場合はTIM6と7を除きます。他のタイマーを使用してPWM出力を生成できます。高度なタイマーTIM1およびTIM8は、最大7つのPWM出力を同時に生成できます。汎用タイマーは同時に最大4つのPWM出力を生成できるため、STM32は同時に最大30のPWM出力を生成できます。だが!!!同じタイマーTIMは1つの周波数のPWM波しか生成できず、デューティサイクルのみを変更できます。特定のルーチンについては、STM32データマニュアルを参照してください。
方法2:IOポートを使用して高レベルと低レベルを変更し、PWM信号を出力します。たとえば、上の図では、最初にレベルを1に設定し、1msを維持し、次にレベルをLowに引き、3msを維持し、次にレベルをHighに設定します。周期4ミリ秒、デューティ比25%のPWM波を発生させることができます。具体的な方法は、IOポートにタイマーを追加し、タイマー割り込みを使用して時間の高レベルと低レベルを切り替えることです。後ろの51MCUコード部分を見てください。
- タイマー
上記の方法2に従って、51個のシングルチップマイクロコンピュータを使用してPWMを生成する場合は、最初にタイマーとは何かを知っておく必要がありますか?タイマーはどのように機能しますか?
タイマー:時間とカウントの両方ができるので、カウンターと同じです。タイマーの本質は、マシン周波数から16ビットレジスタに累積し、累積がオーバーフローしたときに割り込みをトリガーすることです。必要な時間間隔を生成するために。たとえば、1sなので、このレジスタに初期値を設定して、この初期値に累積して1の倍数を生成できるようにする必要があります。このようにして、安定した時間間隔を取得します。
このレジスタは、TH(上位8ビット)とTL(下位8ビット)に分割されます。したがって、計算された初期値をTHとTLの2つの部分に分割する必要があります。
プロセス
最初に、シングルチップマイクロコンピュータの水晶振動子のクロックサイクル、クロックサイクル* 12 =マシンサイクルを知っています。レジスター内の各マシンサイクル+1は、いっぱいになってオーバーフローして割り込みを生成するまで続きます。
たとえば
、シングルチップマイクロコンピュータの外部クロック周波数が12MHzの場合、クロックサイクルは1 /12μs、マシンサイクルは1μs、つまり1μsあたりレジスタ+1です。16ビットレジスタがオーバーフローするのに最大(2 ^ 16)-1 =65535μsかかります。オーバーフローも1マシンサイクルを必要とするため、合計65536μsです。しかし、この値は扱いにくいものであり、必要な1とは何の関係もありません。割り込みを生成するために50,000μsを記憶させたほうがよいので、その初期値は65536-50000 = 15536に設定されます。ただし、この値を上位8桁と下位8桁に配置する必要があるため、この10進数を4桁の16進数に変換し、値を個別に割り当てる必要があります。10進計算方法:TH = 15536/256; TL = 15536%256; 10進システムの計算についてはここでは詳しく説明しません。この場合、50msごとに割り込みが発生します。プログラムを使用するだけで、中断を20回判断し、1秒を数えることができます。
三、PWMの応用
1.アナログ電圧(LEDの明るさ、DCモーターの速度、ブザーの音などを制御)を電圧レベルで出力します
。PWMはアナログ信号のレベルをデジタルエンコードします。コンピューターは0または5Vデジタルしか出力できません。電圧値はアナログ電圧を出力できません。アナログ電圧値(0〜5Vの電圧値)を取得する場合は、高分解能カウンターを使用して方形波のデューティサイクルを変更し、アナログ信号を比較する必要があります。レベルはエンコードされます。電圧は、接続(1)または切断(0)の繰り返しパルスシーケンスによってアナログ負荷にクランプされます。接続はDC電源出力を意味し、切断はDC電源切断を意味します。接続時間と切断時間を制御することにより、帯域幅が十分である限り、最大電圧値以下の任意のアナログ電圧を出力することができます。
出力電圧=(オン時間/パルス時間)*最大電圧値
PWM出力等価電圧
2.
プロジェクトを実行するためにステッパーモーターを制御するプロセスでは、変位の正確な制御が含まれる場合、ステッパーモーターがよく使用されます。
以下のために四線バイポーラステッピングモータ、電気パルス信号は、ロータの回転を制御する角変位モータに変換されます。自動制御装置のアクチュエータとして使用されます。パルス信号が入力されるたびに、ステッピングモーターが一歩前進するため、パルスモーターとも呼ばれます。 !!!ここで、シングルチップマイクロコンピュータを直接制御する場合はパルス制御です。つまり、パルス信号が入ると、ステッパーモーターがステップ角度(通常は0.9°)だけ回転します。したがって、ステッパーモーターの速度を制御する方法は、周波数を制御する ことです (デューティサイクルは通常50%です)が!!!これで、ステッパーモータードライブボードを接続することにより、ステップ角度を細分化することができます。たとえば、2つに分割すると、パルスステッパーモーターは半パルス(0.45°)回転します。
4、51マイクロ波ルーチン
ここでは、51を使用して呼吸光の機能を実現します。同じ原理でDCモーターを制御することもできます。ステッパーモーターは周波数を制御して速度を制御し、ブザーは周波数を制御してトーンを制御します。
配線:P1.0を任意のLDEライトに接続してください!
実装方法には、タイマーなし(遅延)、タイマー
遅延、タイマー使用の
2つがあります。違いは、遅延は遅延関数の変数の加算と減算です。遅延中、マイクロコンピューターは遅延のみを実行できます。ファンクション タイマーの場合、THレジスタとTLレジスタは、割り込みハンドラがオーバーフローしたときに1回実行されるまで継続的に蓄積されます。その間、マイクロコンピュータは他のプログラムも実行できます。
1.タイマーなし(遅延を使用)
/***
*源代码来来自于 https://www.bilibili.com/read/cv4779664
*pwm LED呼吸灯
*现象:亮-灭-亮 循环
*LED接口:P1.0
*思路:改变延时时间实现亮度不一从而实现呼吸的效果
******/
#include <reg52.h> //引用头文件
sbit led=P1^0; //LED接口
bit ledsign=0; //定义一个标志位ledsign==0
void delay(int); //声明延时函数
void main()
{
int i=0; //i:延时控制变量
while(1)
{
if(ledsign==0) //如果b=0(初始0)(灯由亮到灭)
{
led=1; //灭
delay(i); //i秒后(i从小到大)
led=0; //亮
delay(1000-i); //延时1000(可自行定义)-i秒后
i+=2; //增加i(开灯的时间)
if(i>=1000)
{
ledsign=1; //i到最大值(>1000)改变标志位下一阶段(灯由灭到亮)
}
}
else if(ledsign==1) //判断是否进入到下一阶段(灯由灭到亮)
{
led=1; //灭
delay(i); //i秒后(i在上一阶段已到最大值(>1000))
led=0; //亮
delay(1000-i);//延时1000(随手定义)-i秒后
i-=2; //减少i(开灯的时间)
if(i<=0)
{
ledsign=0;//判断是否回到上一阶段
}
}
}
}
void delay(int a) //定义延时函数
{
int i;
for(i=0;i<a;i++);
}
2.タイマーを使用する
#include<reg52.h>
/*************************
**************************/
sbit LED = P1^0;
unsigned char PWM_COUNT; //计数
unsigned int HUXI_COUNT; //占空比更新时间
unsigned char PWM_VLAUE; //占空比比对值
bit direc_flag; //占空比更新方向
void timer0_init(void);
void main()
{
HUXI_COUNT = 0;
PWM_COUNT = 0;
PWM_VLAUE = 5;
direc_flag = 0;
LED = 1; //默认LED熄灭
timer0_init(); //定时器0初始化
while(1);
}
void timer0_init()
{
TMOD=0x02; // 工作于模式2(M1=1,M0=0)
TH0=0x38; //定时器溢出值设置,每隔200us发起一次中断。12M晶振
TL0=0X38;
ET0=1; //开定时器0中断
EA=1; //开总中断
PWM_COUNT =0;
TR0=1; //定时器0开始计时
}
void time0() interrupt 1
{
PWM_COUNT++;
HUXI_COUNT++;
if(PWM_COUNT == PWM_VLAUE) //判断是否到了点亮LED的时候
LED = 0; //点亮LED
if(PWM_COUNT == 10) //当前周期结束
{
LED = 1; //熄灭LED
PWM_COUNT = 0; //重新计时
}
if((HUXI_COUNT == 600) && (direc_flag == 0))
{ //占空比增加10%
HUXI_COUNT = 0;
PWM_VLAUE++;
if(PWM_VLAUE == 9) //占空比更改方向
direc_flag = 1;
}
if((HUXI_COUNT == 600) && (direc_flag == 1))
{ //占空比减少10%
HUXI_COUNT = 0;
PWM_VLAUE--;
if(PWM_VLAUE == 1) //占空比更改方向
direc_flag = 0;
}
}