餃子を食べるとき、何をつけますか?

PIC12F1822用のPWMの基本動作テストプログラムを作りましたが、PWM出力が意図どおりに得られません。

(XC8のテストプログラムを下に添付。テストパターン1/2の切り替えはコメントアウトをお願いします。
 アナライザの出力を画像で添付しました。)

テスト目的: タイマー0の周期割り込みに合わせて、PWMのデューティー比(または周期)を変更するプログラム  

テストパターン 1 : パルスのデューティー比を変えるテスト

質問1: パルスのデューティー比を変えるテストは、PWM設定の一回おきにCCPからのPWMの出力が出ません

テストパターン 2 : パルスの周波数を変えるテスト

質問2: 周波数を変えるテストはOKに見えるものの、1回目のPWMがHighとなるのと、割り込みの11回目、13回目あたりでPWM出力が欠落する

【回答のお願い】

どうも、PWMのレジスタ設定に手順、またはタイミングがあるのではないかと思いますが、原因がわからず困っております。
PICに詳しい方からのご指導をよろしくお願いいたします。

                                   K.A.
------------------------------------------------------
/*
* File: PIC12F1822 PWC
* Author: K.A.
*
* Created on 2014/07/20
*
* タイマー0の周期割り込みに合わせて、PWMのデューティー比(または周期)を変更するプログラム
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#pragma config FOSC=INTOSC, WDTE=OFF, PWRTE=ON, BOREN=ON, MCLRE=OFF
#define _XTAL_FREQ 8000000 // クロック8MHz

/*
*
*/
// タイマー割込みの処理
int TMR0_Count = 0; // タイマーの割込み発生回数をカウントする変数

void interrupt Timer0(void) {
// タイマー0の割込み発生か? Timer0 は 8bitの オーバーフロー・カウンタ
if (TMR0IF == 1) {
TMR0_Count++;
if (TMR0_Count > 5) {
TMR0_Count = 0;
if (RA5 == 0) RA5 = 1; else RA5 = 0; // RA5は、動作表示用LED
}
TMR0IF = 0; // タイマー0割込フラグをリセット
}
}

int main(int argc, char** argv) {

unsigned int pulse_width = 5;

OSCCON = 0b01110010; // 内部クロックは8MHz
ANSELA = 0b00000000; // すべてをデジタルI/Oに割当
TRISA = 0b00001000; // すべてのピンは出力に割当てる(RA3は入力専用)
PORTA = 0b00000000; // 出力ピンの初期化(全て'0'にする)

RA5 = 0; // 動作確認用LED

// Timer0  Timer0 は 8bitの オーバーフロー・カウンタ
OPTION_REG = 0b00000001; // 内部クロックでTIMER0を使用、プリスケーラカウント値 1:2
// bit5:0=Fosc/4, bit3:0=PreScaler_ON, bit2-0:PreScaler
TMR0 = 0; // タイマー0の初期化 (+2cycle)
TMR0IF = 0; // タイマー0割込フラグを0にする
TMR0_Count = 0; // 割込み発生の回数カウンターを0にする
TMR0IE = 1; // タイマー0割込みを許可する
GIE = 1; // 1: 全割込み処理を許可する

/* PWM */
TRISA2 = 1; // RA2 出力をサスペンド
TMR2IF = 0; // TMR2 フラグをクリア
CCP1SEL = 0b0; // CCP1/P1Aの機能をRA2に割り当てる
CCP1CON = 0x0C; // PWM モード
// Period を 設定する xx ms=((PR2)+1)*4*125ns(8MHz)* PreScaler(x1-x64)
PR2 = 127; // 4.096ms (プリスケーラが x64 の場合)
T2CKPS0 = 0b1; // プリスケーラ 00:x1, 01:x4, 10:x16, 11:x64
T2CKPS1 = 0b1; //
CCPR1L = pulse_width >> 2; // パルス幅上位8bit
CCP1CON = ((pulse_width & 0x0003) << 4) | 0x0C; // パルは幅下位2bit
TMR2ON = 1; // TMR2 カウント開始
while (TMR2IF == 0) { /** / do nothing /**/ }
TRISA2 = 0; // RA2に出力を接続

while (1) {
if (TMR0_Count == 0) {

/**** テストパターン 1 : パルスのデューティー比を変えるテスト ****/
// パルスのデューティー比を変えるテストは、PWM設定の一回おきにCCPがPWMの出力が出ません。 なぜ?

pulse_width = pulse_width + 10;
if (pulse_width > 500) pulse_width = 5;
/**/

/**** テストパターン 2 : パルスの周波数を変えるテスト **** /
// 周波数を変えるテストはOKに見えるが、
// 1回目のPWMがHighとなるのと、割り込みの11回目、13回目あたりでPWM出力が欠落する

PR2 = PR2 - 8 ;
if (PR2 < 8) PR2 = 127;
pulse_width = PR2 ; // Duty 25% に相当
/**/

CCPR1L = pulse_width >> 2;
CCP1CON = ((pulse_width & 0x0003) << 4) | 0x0C;

TMR0_Count++; // 続けて PWMの設定変更をしないためのフラグ代わり
}
}
return (EXIT_SUCCESS);
}

「PICのPWMの正しい使い方について教え」の質問画像

A 回答 (1件)

質問2だけ。


PICのPWM機能は、デューティー比と違い、周波数をいつでも変えられるようには出来ていません。
タイミングによってはタイマーが1周するまで次の変化が起こりません。
この仕様を理解していないため問題が起こっているのではないかと思います。

ところで、もう1つの質問と内容がかぶっているようですので、示しておいた方がよいかと思います。
http://oshiete.goo.ne.jp/qa/8685497.html
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
アセンブラでなくC言語で書いていますので、書き換えのタイミングはお任せになってしまいます。
これは、もっとスピードの速いCPUを使うしかなさそうですね。
ありがとうございました。

お礼日時:2014/08/05 00:54

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


おすすめ情報