goo blog サービス終了のお知らせ 

JH7UBCブログ

アマチュア無線 電子工作 家庭菜園など趣味のブログです

PIC12F1822 MCC Timer Interrupt

2021-05-23 14:24:19 | MPLAB X MCC
 PIC12F1822を使って、MPLAB X MCCを利用して割込み設定のテストをします。
 まず、タイマー割込みのテストで、16bitタイマーTMR1を使ったLED点滅(Lチカ)をやってみます。

 RA0に接続したLEDをTMR1から500msごとに割込みをかけ、割込みのたびに点灯、消灯を交互に行い点滅させます。


まず、System Moduleの設定です。
INTOSC,FOSC,Clock 500KHzのデフォルトのままです。
Low-voltage Programingだけチェックを外しました。

TMR1モジュールを組み込み、Timer Periodを500msに設定します。
Enable Timer Interruptにチェックを入れます。

MCCのGenerateをクリックして、各ファイルを生成し、MCCを終了します。

プログラムです。
--------------------------------------------------------
/*
PIC12F1822 Timer Interrupt test
* 2021.5.22
* JH7UBC Keiji Hata
*/
#include "mcc_generated_files/mcc.h"

#define LED LATA0
volatile unsigned char val = 0;

// Interrupt Service Routine
void ISR(){
val = !val;
LED = val;
}

void main(void)
{
SYSTEM_Initialize(); // initialize the device

TMR1_SetInterruptHandler(ISR);

INTERRUPT_GlobalInterruptEnable();

INTERRUPT_PeripheralInterruptEnable();

LED = 0;
while (1)
{
}
}
-------------------------------------------------------------------

ブレッドボードです。

 500ms(0.5s)ごとに点滅しました。

PIC12F1822 MCC PWM テストその3

2021-05-22 20:27:34 | MPLAB X MCC
 PWMの応用例として、モールス符号練習機を作ってみます。
 
 RA0にKEY(電鍵)をつけ、KEY downの時にPWM信号(800Hz)をRA2(P1A)に出力し、接続した圧電スピーカーから音を出します。音と同時にモニター用のLEDを点灯させます。電源は電池(3V)とします。


MCCで各ピンの入出力を設定します。
RA0は入力とし、WPU(ウィークプルアップ)します。、RA2は出力(PWM用P1A)、RA4も出力(LED用)とします。



 PWM関係のMCC設定は、前の記事と同じです。

プログラムです。
PWM信号をスタートさせるには、TMR2_StartTimer()を
ストップさせるには、TMR2_StopTimer()を使います。
------------------------------------------------------------------------------
/*
* PIC12F1822 Morse Trainer
* 2021.05.22
* JH7UBC Keiji Hata
*/
#include "mcc_generated_files/mcc.h"

#define LED LATA4
void main()
{
SYSTEM_Initialize(); // initialize the device


LED = 0;
TMR2_StopTimer();
unsigned char val = 1;
unsigned char old_val =0;

while (1)
{
val = RA0;
if(val != old_val){
if(val == 0){
LED = 1;
TMR2_StartTimer();
}else{
LED = 0;
TMR2_StopTimer();
}
old_val = val;
__delay_ms(10);
}
}
}
---------------------------------------------------------------------------
 ブレッドボードです。
 KEYの代わりにタクトスイッチがつけてあります。



 タクトスイッチを押すとLEDが点灯し、800Hzの音が圧電スピーカーから出ます。圧電スピーカーの音はあまりよくありませんが、モールス符号の練習用に使えると思います。

 PWM信号にローパスフィルタをつけ、アンプとスピーカーをつければ、もっと良い音になると思います。

PIC12F1822 MCC PWM テストその2

2021-05-21 15:52:39 | MPLAB X MCC
 前の記事のテストでMCCを使えば、PICで簡単にPWMを行うことができることが分かりました。

 それでは、PWMの周波数を変えるのにはどうしたらよいのでしょうか。
 まず、PWMの動作原理を見てみましょう。PIC12F1822の説明書の解説図です。
 詳しい説明は、他のWebサイトを見ていただくか、私のホームページのここを見てください。

 PWMの周期を決めているのは、TMR2とPR2です。根本的には、システムクロックFOSCで、更にTMR2に接続されているプリスケーラ(分周期)も関係しています。

 FOSCの周波数を決定し、prescalerの比率が決まれば、PWMの周期の上限と下限が決まります。次に、PR2の値を設定すれば周期が決まることになります。MCCでは、周期の上限と下限の間で周期を決めると、PR2の値を算出しセットしてくれます。

 例として、FOSC=16MHz,prescaler 1:16とし、PWM period=1000us=1msとしてみます。

 TMR2モジュールで、Timer ClockのPrescalerを1:16とするとTimer Periodの設定範囲が4us以上1.024ms以下と表示されます。1msを入力するとActual Period(実際の周期)は1msになりました。

ECCPモジュールを開いてみるとTMR2で設定した値が反映されています。
PWMの周期1ms、周波数1KHzになります。

Generateして、MCCを終了します。プログラムは、何も書かなくてもOKです。
SYSTEM Initialize()の中で、TMR2とECCPのinitializeが行われ、PWMは自動的にスタートします。
---------------------------------------------
void main(void)
{
// initialize the device
SYSTEM_Initialize();

while (1)
{
}
}
---------------------------------------------
build,PICに書き込みをして、周波数を測定してみました。


 1000Hzが出力されました。

次に、CWのサイドトーンを意識して、800Hzを発生させてみましょう。
FOSC=4MHz,TMR2 prescaler 1:16としました。
800Hzは、周期では、1/800=0.00125s=1.25ms=1250usとなりますので、1.25msを入力しました。Actual Period は 1.248msとなりました。
ECCPモジュールを見ると
PWM Period 1.248ms.PWM Frequency 801.28Hzとなりました。


実測してみました。

 801Hzが発生しました。

 ということで、FOSC,TMR2 prescalerの値と周期の設定で、いろいろな周波数のPWMを発生させることができます。

PIC12F1822 MCC PWM テストその1

2021-05-20 17:12:10 | MPLAB X MCC
 PIC12F1822を使って、MCCで設定してPWMのテストをします。
 テストをする回路図です。
 RA0(AN0)で10kΩのボリュームの電圧をAD変換して0~1023で取り込み、その値でPWM出力して、LEDの明るさを変化させるプログラムを組んでみます。

 プロジェクト作成後、MCCを開きます。

 System Moduleの設定です。INTOSC,FOSC,16MHz,PLLなしとしました。
 

 AD変換についての設定は、前の記事と同じです。

 PWMの設定は、ECCP(Enhanced Captuer Compare PWM)モジュールで行いますので、ECCPモジュールを組み込みます。
 
 更にPWMは、Timerを使いますので、Timerモジュールも組み込みます。 PIC12F1822では、TMR2しか使えませんのでTMR2を組み込みます。

 PWMモジュールの設定をします。
 Timer Selectは、Timer2です。(これしか選べません)
 Duty Cycleは、50%のまま。
 PWM modeは、singleのまま。RA2がP1A(PWM出力)になります。
 pin polarityは、P1A active highのまま。アクティブの時に出力がHighになります。
 TMR2を組み込むとPWM parameterが自動的に設定されます。
 FOSC=16MHzの場合、PWM period=64us,PWM Resolution= 10bit,PWM Frequency=15.625KHzとなります。

 TMR2モジュールです。
 特に設定はしません。
 プログラムです。非常に簡単です。
----------------------------------------------------------------
#include "mcc_generated_files/mcc.h"

void main()
{
// initialize the device
SYSTEM_Initialize();

while (1)
{
EPWM_LoadDutyValue(ADC_GetConversion(channel_AN0));
}
}
---------------------------------------------------------------
 AN0のアナログ入力をADCで数値化(10bit 0~1023)して、その値に相当するデューティー比のPWMをP1Aに出力します。

 buildし、プログラムをPICに書き込み、実際の回路でテストしました。
 ボリュームを回すとLEDの明るさが変化します。OKです。

 実際のPWM波形を見てみます。
 Duty Cycle 50%の波形です。

 Duty Cycle 約20%

Duty Cycle 約80%

周波数も測定してみました。
 15.640KHzでした。設定値は、15.625KHzでしたので、誤差0.1%程度です。
 以前にPWMの勉強をしましたが、仕組みや計算がけっこう面倒でした。
 細かい設定をしなければ、MCCの設定だけで使えそうです。

PIC12F1840 MCC ADC テスト

2021-05-19 11:54:02 | MPLAB X MCC
 PIC12F1840を使って、MCCを利用したADCテストをやってみました。
 PICを変更したのは、PIC12F1822では、メモリが足りなくなりそうだからです。
 アナログ入力ポートはRA0(AN0)とし、RA1,RA2をI2C通信に利用します。
 AN0の電圧を10kΩのボリュームで調整して、電圧の値をAQM0802Aに表示します。

 プロジェクトを作成して、MCCを開きます。
 System Moduleの設定は、INTOSC,FOSC,16MHzとしました。
 I2Cの設定とプログラムは、前の記事と同じです。
  今回は、ADC関係の設定だけ紹介します。
 Enable ADCにチェックを入れ、ADCを有効にします。
 ADC Clockは、F1シリーズでは、1us~9usの範囲で設定しますので、変換クロック(Tad)は、FOSC/16 = 1.0usとしました。従って、Conversion Timeは11.5usとなります。
 変換結果の格納方式(Result Alignment)は、右詰め(right)
 正参照電圧(Positive Reference)は、電源電圧(VDD)としました。

 Pin ManagerとPin Moduleに自動的にADCが設定されます。
 RA0にアナログポートAN0が設定されました。
 設定は、これだけです。

 プログラムは次のとおりです。
 ADCに関係するのは、main()の中のprintf()関数の中の
ADC_GetConversion(0)
だけです。なんだか拍子抜けするくらい簡単です。
---------------------------------------------------------
/*
* PIC12F1840 MCC ADC test
* 2021.05.18
* JH7UBC Keiji Hata
*/

#include "mcc_generated_files/mcc.h"
#include "mcc_generated_files/examples/i2c_master_example.h"

#define I2CLCD_AQM0802A 0x3e

//-------- send character ------------------------
void LCD_dat(char chr)
{
I2C_Write1ByteRegister(I2CLCD_AQM0802A, 0x40, chr);
__delay_us(30); // 30us
}

//-------- send command -------------------------
void LCD_cmd(char cmd)
{
I2C_Write1ByteRegister(I2CLCD_AQM0802A, 0x00, cmd);
if(cmd & 0xFC) // bit6 = 1
__delay_us(30); // 30us
else
__delay_ms(2); // 2ms Clear or Home
}

//-------- clear LCD--------------------------
void LCD_clr(void){
LCD_cmd(0x01);
}

//--------- Home -----------------------------
void LCD_home(void){
LCD_cmd(0x02);
}

//--------- Cursor X,Y -----------------------
void LCD_cursor(unsigned char x,unsigned char y){
if (y == 0)
LCD_cmd(0x80 + x);
if (y == 1)
LCD_cmd(0xc0 + x);
}

//-------- display strings -------------------------
void LCD_str(char *str){
while(*str)
LCD_dat(*str++); //pointer increment
}

//-------- write 1 character to LCD ----------------
void putch(unsigned char ch){
LCD_dat(ch);
}

//-------- LCD initialize ---------------------------
void LCD_init(){
__delay_ms(40); //40ms wait
LCD_cmd(0x38); //8bit,2line
LCD_cmd(0x39); //IS=1 : extention mode set
LCD_cmd(0x14); //Internal OSC Frequency
LCD_cmd(0x70); //Contrast set
LCD_cmd(0x56); //Power/ICON/Contrast Control
LCD_cmd(0x6C); //Follower control
__delay_ms(200);//200ms wait
LCD_cmd(0x38); //IS=0 : extention mode cancel
LCD_cmd(0x0C); //Display ON
LCD_cmd(0x01); //Clear Display
__delay_ms(2); //wait more than 1.08ms
}

void main()
{
// initialize the device
SYSTEM_Initialize();
// Enable the Global Interrupts
INTERRUPT_GlobalInterruptEnable();
// Enable the Peripheral Interrupts
INTERRUPT_PeripheralInterruptEnable();

//I2C_Initialize();
LCD_init();
char msg[] = "ADC TEST";
LCD_str(msg);

while (1)
{
LCD_cursor(2,1);
printf("%4d",ADC_GetConversion(0));
__delay_ms(100);
}
}
---------------------------------------------------------
 ブレッドボードです。
 VRの位置により、0~3Vの電圧が、0~1023の値で2行目に表示されました。