. PIC】PICマイコンのPWMの使い方、設定方法(CCP-PWM機能)を紹介する - TRY-AND-ERROR-AND-TRY
PIC】PICマイコンのPWMの使い方、設定方法(CCP-PWM機能)を紹介する - TRY-AND-ERROR-AND-TRY
PIC】PICマイコンのPWMの使い方、設定方法(CCP-PWM機能)を紹介する - TRY-AND-ERROR-AND-TRY

【PIC】PICマイコンのPWMの使い方、設定方法(CCP-PWM機能)を紹介する

PICマイコン勉強中。 ぼちぼち更新していく予定。 PICマイコンの使い方をまとめてみる 割とネットにサンプル集がない & 自分で新規処理作ろうとしたときに設計背景思い出したくなることが多々あ .

PICのPWM機能は若干癖がある

PICマイコンのPWM機能ですが、タイマのレジスタの制約により設定に若干の癖があります。

PWM制御のサンプルプログラム

PIC16F1827の2ピン、RA3ポートからPWM信号を出力する

【Arduiono】Arduinoでタイマ割込みを使用したPWM制御を行う方法を紹介する

今回はArduiono、いや、Arduinoに搭載されたマイコン「ATmega328P」のタイマ機能を使用してPWM制御を行ってみました。 備忘録。 ※本記事ではATmega328PBのデータシートを .

/* PIC16F1827 Configuration Bit Settings */ /* 'C' source line config statements */ /* CONFIG1 */ #pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin) #pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled) #pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR) #pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled) #pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled) #pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled) #pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin) #pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled) #pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled) /* CONFIG2 */ #pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off) #pragma config PLLEN = ON // PLL Enable (4x PLL enabled) #pragma config STVREN = OFF // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset) #pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.) #pragma config LVP = ON // Low-Voltage Programming Enable (Low-voltage programming enabled) /* #pragma config statements should precede project file includes. */ /* Use project enums instead of #define for ON and OFF. */ /*==========================================================================================================================================*/ /* * File: main.c * Author: ICE_MEGANE * * Created on 2021/04/2, 22:26 */ #include #define CLEAR 0 #define SET 1 typedef unsigned char UC; typedef unsigned short US; typedef unsigned long UL; void main(void ); static void register_setup( void ); static void rs_ccp3_dutyset( US us_duty ); /**************************************************************/ /* Function: */ /* main task */ /* */ /**************************************************************/ void main(void) < register_setup(); while(1) < //rs_ccp3_dutyset( (US)1023U ); /* duty100% */ rs_ccp3_dutyset( (US)512U ); /* duty50% */ >> /**************************************************************/ /* Function: */ /* register setup */ /* */ /**************************************************************/ static void register_setup( void ) < /* Oscillator setuo */ OSCCON = 0x70; /* |1|1|1|1|-|1|#|0|0| */ OSCTUNE = 0x00; /* |#|#|0|0|-|0|0|0|0| */ /* Option register setup */ //OPTION_REG = 0xC8; /* |1|1|0|0|-|0|1|1|1| */ /* Alternate pin function setup */ APFCON0 = 0x08; /* |0|0|0|0|-|1|0|0|0| */ APFCON1 = 0x00; /* |x|x|x|x|-|x|x|x|0| */ /* Interrupt setup */ INTCON = 0x20; /* |0|0|1|0|-|0|0|0|0| */ PIE3 = 0x00; /* |x|x|1|1|-|1|x|1|x| */ /* Port setup */ TRISA = 0x00; /* |0|0|0|0|-|0|0|0|0| */ /* Timer4 setup (Timer4 assigned to CCP3) */ TMR4 = 0xFF; T4CON = 0x07; /* |x|0|0|0|-|0|1|1|1| */ PR4 = 0xFF; /* Timer4 Overflow val (PWM period) setup : 8bit MSB */ /* CCP setup */ CCPTMRS = 0x93; /* |1|0|0|1|-|0|0|1|1| */ CCP3CON = 0x0C; /* |0|0|0|0|-|1|1|0|0| */ CCPR3L = 0x00; /* |0|0|0|0|-|0|0|0|0| */ PIR3 &= 0xEF; /* |x|x|x|0|-|x|x|x|x| */ >/**************************************************************/ /* Function: */ /* main task */ /* Set CCP3 module duty */ /**************************************************************/ static void rs_ccp3_dutyset( US us_duty ) < CCPR3L = (UC)( us_duty >> 2 ); /* 0b0011-1111-1111 -> 0b0000-1111-1111-(11) */ us_duty &= 0x0003; us_duty = us_duty 0b0000-0011-0000 */ >

・パルスのキャリア周波数は488.68kHz・パルスのon-dutyは50.004%

static void rs_ccp3_dutyset( US us_duty ) < CCPR3L = (UC)( us_duty >> 2 ); /* 0b0011-1111-1111 -> 0b0000-1111-1111-(11) */ us_duty &= 0x0003; us_duty = us_duty 0b0000-0011-0000 */ >

少し詳細な説明

PICマイコンはArduinoやRasberryPiなどと異なり、目標の動作をさせるためのプログラム(今回ならPWM)以外にも、クロック設定やポート設定等、マイコンを動かすために必要なすべての設定を行っていく必要があります。

お手軽感は皆無ですが、言い方を変えればすべて自分の好みに設定していくことができます。

PICマイコンの内蔵発振器の周波数設定

今回はマイコン内部の内蔵発信器を使用してパルスを発生させ、その周波数を32MHzになるよう設定しました。

/* CONFIG1 */ #pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin) /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ OSCCON = 0x70; /* |1|1|1|1|-|1|#|0|0| */ OSCTUNE = 0x00; /* |#|#|0|0|-|0|0|0|0| */

この文章から、HFINTOSC(High Frequency INternal OSCillator:高速内蔵発振器)の設定が32MHzから31kHzの中で選択できるとわかります。

↓↓↓データシートは読み込めたので、次は実際に設定を行っていきます。↓↓↓

PICマイコンでは基本的なレジスタ設定は代入形式で実施しますが、Configuration Word などの一部の初期設定については、#pragmaセクションで実施することも可能です。(#pragmaセクションでの設定が基本的に高優先度・・・)

MPLABの場合、#pragma関連の設定は、MPLABの「Set Configuration Bits」からコードを生成することが可能です。

設定が完了したら下記の「Generate Source Code to Output」ボタンを押し、表示されるコードをコピーします。

今回は「Internal osscilator block」を使用するので、bit1を1に設定しておけばOKです。bit0はどっちでも可。

以上でPICマイコンの内蔵発振器周りの設定は完了です。

ポート割り当てを設定する ※必要に応じて

/* Alternate pin function setup */ APFCON0 = 0x08; /* |0|0|0|0|-|1|0|0|0| */ APFCON1 = 0x00; /* |x|x|x|x|-|x|x|x|0| */

マイコンには通信やタイマ、PWMなどの様々な機能がありますが、基本的にそれらの特殊機能が使用できるのは特定のピンのみになります。

しかし、マイコンによってはこれらの機能をどのピンに設定するかを、ユーザーが選択できるように設定されているものがあります。

割込み許可の設定 ※必要に応じて

今回はリロード、コンペアマッチ割り込みの両方とも無効化しました。

/* Interrupt setup */ INTCON = 0x20; /* |0|0|1|0|-|0|0|0|0| */ PIE3 = 0x00; /* |x|x|1|1|-|1|x|1|x| */

ちなみにですが、PIC16F1827の最高クロック周波数である32MHzで処理を行っても、500HzぐらいのPWM出力でリロード/コンペアマッチ割り込みを発生させるとスタックオーバーフローして無限にリセットがかかり続けます。(dutyのON/OFFの切り替わり時の割込みは無効にしてます。)

ポートの入出力設定

/* Port setup */ TRISA = 0x00; /* |0|0|0|0|-|0|0|0|0| */

余談ですが、「TRIS-A」のTRISは、「Tri - state A port」の略です。「Tri - state」の「Tri」は、ポートの状態が入力、出力、Hi-Zの3状態を持つため、このように命名されているっぽいです。

今回は「RA3」ポートからPWM信号を出力して波形を確認しているため、「TRISA3」を「0」に設定します。

最初に述べ忘れましたが、基本的にレジスタ関連は 0bit からカウントし、8bit長のレジスタの場合は 0 - 7 bit で指定します。(0始まりです。)

タイマの設定

/* Timer4 setup (Timer4 assigned to CCP3) */ TMR4 = 0xFF; T4CON = 0x07; /* |x|0|0|0|-|0|1|1|1| */

・Fosc/4 の周波数を、・Prescalerで分周し、・分周した周波数で0からカウントアップし、カウント中の値はTMRxレジスタに入る (≒TMRxレジスタでカウントアップ)・PRxレジスタで設定した値とTMRxの現在のカウント値が一致したら、「Reset」を発生させてTMRxレジスタをゼロクリアする・一致した際にイベントを起こしたい場合は、TMRxIFフラグを使用する・一致した際のイベントを何回かに1度にしたい場合、Postscalerを設定して分周する

bit:6, 5, 4, 3 では、TImerxの割込みをどのくらい分周するか、Postscaler を設定します。

注意点ですが、Postscalerはあくまで「割込みの発生回数を変える」だけであり、タイマの出力や動作には影響しません。

CCPモジュールの設定

PR4 = 0xFF; /* Timer4 Overflow val (PWM period) setup : 8bit MSB */ /* CCP setup */ CCPTMRS = 0x93; /* |1|0|0|1|-|0|0|1|1| */ CCP3CON = 0x0C; /* |0|0|0|0|-|1|1|0|0| */ CCPR3L = 0x00; /* |0|0|0|0|-|0|0|0|0| */ PIR3 &= 0xEF; /* |x|x|x|0|-|x|x|x|x| */

・Capture:マイコンのピンに矩形波を入力した場合、H->L、L-Hに切り替わる間隔の時間(パルス幅)を測る・Compare:マイコンであらかじめ決めた時間が来たら、出力を変化させたりする・PWM:PWM出力を行うことができる

今回のサンプルプログラムの例では、タイマにはTImer4を使用し、CCPモジュールを使ってPWM制御を行います。

CCPモジュールで使うタイマを設定する PWMのキャリア周波数を設定する PWMのON-dutyを設定する

ここで注意しなければならない点は、dutyを決めるために複数のレジスタを操作する必要があること、PWMのキャリア周期はPRxレジスタ1つで8bitの指定だったのに対し、ON-dutyは8+2の合計10bitで指定する必要がある、という点です。

PRxレジスタとCCPRxL+CCPxCONの2bitの関係について

「TMRxレジスタ(2は誤記?)は、内部の2bitのシステムクロック(Fosc)に接続され、全体として10bitのタイムベースを構成する。」

つまり、設定できるのは全体のうちの8bitだけど、下位には2bitのクロック状態があって、実際には10bitで動いているよ!ということです。

長々と書いてしまいましたが、以上でPWM出力を行うための設定は完了です。

メイン関数

/**************************************************************/ /* Function: */ /* main task */ /* */ /**************************************************************/ void main(void) < register_setup(); while(1) < rs_ccp3_dutyset( (US)512U ); /* duty50% */ >>

引数には2byteのshort型を用意(typedef US unsigned short)し、受け取った値の上位8bitをCCPR3Lに、下位2bitCCP3CONの5,4bitの位置までビットシフトして代入しています。

/**************************************************************/ /* Function: */ /* main task */ /* Set CCP3 module duty */ /**************************************************************/ static void rs_ccp3_dutyset( US us_duty ) < CCPR3L = (UC)( us_duty >> 2 ); /* 0b0011-1111-1111 -> 0b0000-1111-1111-(11) */ us_duty &= 0x0003; us_duty = us_duty 0b0000-0011-0000 */ >

まとめ

【PICマイコン】PICマイコンの 各種機能の使い方を紹介する

PICマイコン勉強中。 ぼちぼち更新していく予定。 PICマイコンの使い方をまとめてみる 割とネットにサンプル集がない & 自分で新規処理作ろうとしたときに設計背景思い出したくなることが多々あ .

関連記事 【PICマイコン】MPLABで追加したソースファイルが登録されないときの対処法

MPLABの仕様でクソ沼ったので書き留めておきます。 今回沼った案件 今回はMPLABでソースファイルを複数扱う場合のメモを書きたいと思います。 ちょっとした実験系のソースコードであればmain.cの .

【Texas Instruments】TI公式ホームページからマイコンボードを直輸入してみた

どうも、はじめまして。 今回はmouserやdigikeyを介さずに直接TI公式から商品を購入したので、その方法についてまとめておきます。 若干入力が?ってなる部分あったのでその辺も含めて。 公式サイ .

関数の結果をキャストするのと表示結果を切り捨てるのはどちらがいいの?(謎)

う~ん、どっちがいい書き方なんでしょうか。 ちょっと迷ったのでメモとして残しておきます。 問題 1からnまでの整数値の2乗値を表示する単純なプログラム。 ただキャストするか否かで方法が二通り出たが、ど .

【電子回路】MOS-FET_カスコード接続の解析をしてみる

どうも初めまして。 メガネです。 最近ふざけた記事しか書いてなかったので久々に真面目系の記事です。 今回は定電流回路などでよく用いられる?カスコード接続回路の解析に関する記事です。 等価回路を描いて電 .

吾輩はオタクである。 嫁はまだいない。 興味もったものは何でもやるよ

【自作】古いちゃぶ台を改造して作業机を作成する 【自作】究極のトイラジコンを自作する:③制御内容決めと基板設計 【PIC】PICマイコンでDAC機能を使用してアナログ”出力”を行う方法を紹介する 【PIC】PICマイコンのPORTAレジスタとLATAレジスタの違いについて紹介する -リード・モディファイ・ライトについて説明する- 【改造】ユンボのバッテリを別サイズの大型品に換装して始動性アップする 2026年3月 月 火 水 木 金 土 日 1 2345678 9101112131415 16171819202122 23242526272829 3031
📎📎📎📎📎📎📎📎📎📎