====== PWM発振ユニットV2 ======
===== 概要 =====
モータの制御やDC/DCコンバータ(昇圧、降圧)などを行う際には、PWM(Pulse Width Modulation)方式が良く採用されます。
電子工作に置いても、簡単な実験をする際には、PWMの周期やデューティを手軽に設定できるユニットが手元にあれば何かと便利です。
以前にも、簡易信号発生ユニット(PWM)を製作しましたが、周期やデューティの値を視覚的(LCDなどで)に知る事が出来ず不便を強いられていました。
そこで今回は、周期やデューティの値をLCDに表示することにより利便性を向上させました。
<仕様>
* 周期は、128usec(7.81kHz)、512usec(1.95kHz)、2048usec(488.3Hz)の3種を提供する。
* デューティは、0~1023(0x3FF)の1024段階とする。
* デューティの設定は、ボリュームによるスムーズな操作と、スイッチによる微調整を可能とする。
===== 動作原理 =====
基本的な原理は、簡易信号発生ユニット(PWM)を参照してください。
<ボリュームによるデューティの設定>
SW1を押下したまま、ボリューム(R5)を廻すことにより、デューティの値を0%(0)~99.9%(1023)までスムーズに設定することが出来ます。
※A/D変換の精度は、10ビットなので、
* 上位8ビットを、CCPR1Lレジスタにセットし、
* 下位2ビットを、CCP1CONのCCP1XビットとCCP1Yビットにセットします。
<スイッチによるデューティの設定>
SW2を押下する毎に、デューティの値がインクリメント(+1)されていきます。
SW3を押下する毎に、デューティの値がデクリメント(-1)されていきます。
※約0.1%の単位でデューティを設定できます。
<スイッチによる周期の切り替え>
SW4を押下する毎に、周期が【128usec】→【512usec】→【2048usec】→【128usec】。。。。。というふうに切り替わっていきます。
※128usec→TIMER2のプリスケーラを、1/1にセットします。
※512usec→TIMER2のプリスケーラを、1/4にセットします。
※2048usec→TIMER2のプリスケーラを、1/16にセットします。
===== 回路図 =====
{{:imgpaste:202004:htmikan-20200430-111852.png}}
===== ソースコード =====
//**********************************************************************
/*
<PWM発振ユニット>
*/
//**********************************************************************
#define ON 0
#define OFF 1
#define TRUE 255
#define FALSE 0
#define SW1 &PORTA, 2
#define SW2 &PORTA, 3
#define SW3 &PORTA, 4
#define SW4 &PORTA, 5
//**********************************************************************
void Pwm_Change_DutyEx(unsigned int duty_ratio)
{
CCPR1L = duty_ratio >> 2;
CCP1CON.CCP1Y = (duty_ratio & 0b0000000000000001) == 0 ? 0 : 1;
CCP1CON.CCP1X = (duty_ratio & 0b0000000000000010) == 0 ? 0 : 1;
}
//**********************************************************************
static char buf[16];
void display(short Prescale, int duty)
{
static double tmp;
//
switch (Prescale) {
case 0:
Lcd_Custom_Out(2, 10, "7.81kHz");
tmp = (256.0 * 4 * 0.000000125 * 1) * 1000000;
WordToStr(tmp, buf);
Lcd_Custom_Out(2, 1, &buf[1]);
Lcd_Custom_Out(2, 5, "usec");
break;
case 1:
Lcd_Custom_Out(2, 10, "1.95kHz");
tmp = (256.0 * 4 * 0.000000125 * 4) * 1000000;
WordToStr(tmp, buf);
Lcd_Custom_Out(2, 1, &buf[1]);
Lcd_Custom_Out(2, 5, "usec");
break;
case 2:
Lcd_Custom_Out(2, 10, "488.3Hz");
tmp = (256.0 * 4 * 0.000000125 * 16) * 1000000;
WordToStr(tmp, buf);
Lcd_Custom_Out(2, 1, &buf[1]);
Lcd_Custom_Out(2, 5, "usec");
break;
}
//
WordToStr(duty, buf);
Lcd_Custom_Out(1, 9, &buf[1]);
tmp = (duty / 1024.0) * 1000;
WordToStr(tmp, buf);
buf[6] = 0x00;
buf[5] = buf[4];
buf[4] = '.';
Lcd_Custom_Out(1, 1, &buf[1]);
Lcd_Custom_Out(1, 6, "%");
}
//**********************************************************************
void main()
{
static short cnt, Prescale;
static int duty;
static double tmp;
//
OSCCON = 0b01110000; //クロックを8Mhzに設定する。
ANSEL = 0b00000001; //A/D変換は使用しない。
CMCON = 0b00000111; //コンパレータを使用する。
TRISA = 0b11111111; //I/Oポートを設定する。
TRISB = 0b11111111; //I/Oポートを設定する。
//LCDの初期化
Lcd_Custom_Config(&PORTB,7,6,5,4,&PORTB,3,2,1);
Lcd_Custom_Cmd(LCD_CURSOR_OFF);
Lcd_Custom_Cmd(LCD_CLEAR);
Lcd_Custom_Out(1, 1, "PWM OSC v2");
for (cnt = 0; cnt < 16; cnt++) {
Lcd_Custom_Chr(2, cnt + 1, 0xFF);
Delay_ms(100);
}
Lcd_Custom_Cmd(LCD_CLEAR);
//PWMの設定
Pwm_Init(1000); // 1kHz
PR2 = 0xFF;
duty = 512;
Pwm_Change_DutyEx(duty);
Prescale = 0;
T2CON.T2CKPS1 = 0;
T2CON.T2CKPS0 = 0;
Pwm_Start();
//
display(Prescale, duty);
//
while (1) {
//A/D変換データをduty値として使用する。
if (Button(SW1, 10, ON) == TRUE) {
duty = Adc_Read(1);
display(Prescale, duty);
Pwm_Change_DutyEx(duty);
}
//duty値をインクリメントする
if (Button(SW2, 10, ON) == TRUE) {
while (Button(SW2, 10, OFF) == FALSE)
;
//
duty++;
duty = (duty < 1024) ? duty : 0;
display(Prescale, duty);
Pwm_Change_DutyEx(duty);
}
//duty値をデクリメントする
if (Button(SW3, 10, ON) == TRUE) {
while (Button(SW3, 10, OFF) == FALSE)
;
//
duty--;
duty = (duty >= 0) ? duty : 1023;
display(Prescale, duty);
Pwm_Change_DutyEx(duty);
}
//TIMER2のプリスケール値を変更する。
if (Button(SW4, 10, ON) == TRUE) {
while (Button(SW4, 10, OFF) == FALSE)
;
//
Prescale++;
Prescale = (Prescale < 3) ? Prescale : 0;
switch (Prescale) {
case 0:
T2CON.T2CKPS1 = 0;
T2CON.T2CKPS0 = 0;
break;
case 1:
T2CON.T2CKPS1 = 0;
T2CON.T2CKPS0 = 1;
break;
case 2:
T2CON.T2CKPS1 = 1;
T2CON.T2CKPS0 = 0;
break;
}
display(Prescale, duty);
}
}
}
//**********************************************************************
===== 動作確認 =====
{{:imgpaste:202004:htmikan-20200430-112000.png?500}}
周期=128usec(7.81kHz)、デューティ=0%
LCDの左上=デューティ比率
LCDの右上=デューティ値
LCDの左下=周期(時間)
LCDの右下=周期(周波数)
{{:imgpaste:202004:htmikan-20200430-112012.png}}{{:imgpaste:202004:htmikan-20200430-112015.png}}
周期=128usec(7.81kHz)、デューティ=0.1%
{{:imgpaste:202004:htmikan-20200430-112024.png}}{{:imgpaste:202004:htmikan-20200430-112027.png}}
周期=128usec(7.81kHz)、デューティ=1%
{{:imgpaste:202004:htmikan-20200430-112034.png}}{{:imgpaste:202004:htmikan-20200430-112038.png}}
周期=128usec(7.81kHz)、デューティ=10%
{{:imgpaste:202004:htmikan-20200430-112045.png}}{{:imgpaste:202004:htmikan-20200430-112049.png}}
周期=128usec(7.81kHz)、デューティ=50%
{{:imgpaste:202004:htmikan-20200430-112055.png}}{{:imgpaste:202004:htmikan-20200430-112058.png}}
周期=128usec(7.81kHz)、デューティ=90%
{{:imgpaste:202004:htmikan-20200430-112104.png}}{{:imgpaste:202004:htmikan-20200430-112109.png}}
周期=128usec(7.81kHz)、デューティ=99%
{{:imgpaste:202004:htmikan-20200430-112114.png}}{{:imgpaste:202004:htmikan-20200430-112118.png}}
周期=128usec(7.81kHz)、デューティ=99.9%
{{:imgpaste:202004:htmikan-20200430-112124.png}}{{:imgpaste:202004:htmikan-20200430-112127.png}}
左側:周期=512usec(1.95kHz)、デューティ=50%
右側:周期=2048usec(488.3Hz)、デューティ=50%
{{:imgpaste:202004:htmikan-20200430-112134.png}}{{:imgpaste:202004:htmikan-20200430-112138.png}}
このページは稲崎様の閉鎖したHPのコピーで、著作権は稲崎様にあります。[[elechobby:picdic:picdic|詳細]]
This page is a copy of Mr. Inasaki's closed website, and the copyright is held by him.[[elechobby:picdic:picdic|Details]]