JH7UBCブログ

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

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行目に表示されました。



PIC12F1822 MCC I2C LCD AQM0802A 表示テスト

2021-05-18 08:52:14 | MPLAB X MCC
 PIC12F1822を使って、MPLAB X MCCでI2C設定をして、I2C LCD AQM0802Aに文字を表示するテストを行いました。

 まず、projectを作成してから、MCCで各種設定を行います。MCCを開いて、System Moduleの設定を行います。

INTOSC,FOSCとし、クロックは16MHzとしました。
Low Voltage programingのチェックははずし、RA3は、GPIOとしました。


 I2C通信を使うために、MSSPを導入します。
 Serial ProtocolをI2Cにセットします。
 Modeは、Masterにセット、クロックは100000Hz(100kHz)とし、Interrupt Drivenにチェックを入れます。(割込みを使うんですね)

 割込みを使うので、Interrupt Moduleの設定を行います。
 下のように、チェックを入れました。

 Pin Moduleには、ちゃんとRA1がSCL、RA2がSDAが設定されています。
 一応ウィークプルアップ(WPU)にチェックを入れ、RegistrersでnWPUEN enableにしておきます。


 Generateをクリックして、設定終了です。MCCを閉じて、プログラミングをします。各種設定ファイルとmain.cが生成されます。

 PIC12F1822とAQM0802Aモジュールの接続回路図です。電源は乾電池を使います。

 MCCを使ってAQM0802Aを表示した例は、Web上では例は少なく、どのようにプログラミングするのか頭を悩ませました。そんな中、KazHatブログというサイトの記事が参考になりました。(というか、コピーさせていただきました)

 AQM0802Aをコントロールするには、I2Cスレーブアドレス(AQM0802Aの場合、0x3e)に続いて、コントロールバイト(コマンドの場合0x00、データの場合00x40)を送り、次にコマンドまたはデータを送ります。

 このフォーマットを実現するためには、mcc_generated_files/examples/i2c_master_example.cの中のI2C_Write1ByteRegister(i2c_address_t address, uint8_t reg, uint8_t data)という関数を使います。

 試しに、i2c_address = 0x3e,reg = 0x40,data = 0x41としてAQM0802A
送信した場合のI2C信号を見てみました。I2Cアドレスは、bit0にwriteの0が加わって、0x7cとして送信されます。OKです。


 以前にMCCを使わないで組んだプログラムとKazHatさんのプログラムを合わせたような次のようなプログラムでテストしました。
 printf()関数を使っていますので、projectのpropertiesで、XC8 Global OptionsのC standerdをC90にしてコンパイルします。
-------------------------------------------------------
/*
* PIC12F1822 MCC I2C LCD AQM0802A
* 2021.05.17
* 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();

LCD_init();

char msg[] = "Hello!";
LCD_str(msg);

unsigned char count = 0;

while (1)
{
LCD_cursor(2,1);
printf("%3d",count);
count++;
__delay_ms(1000);
}
}
-------------------------------------------------------
ブレッドボードと文字が表示された様子です。

 一応、表示できましたが、PIC12F1822のプログラムメモリ2K Wordsのうち85%を使ってしまいました。データメモリは128byteのうち77%を使いました。
 ちなみに、同等のプログラムをMCCを使わないで組んだ場合は、プログラムメモリーの37%、データメモリの27%を使いました。

 つまり、MCCを使うと設定が簡略化させる分メモリーをたくさん使うということですね。メモリ容量の大きいPIC向きということでしょうか。

今日はトマトとハツカダイコン

2021-05-14 19:18:34 | 家庭菜園と花
 今日も朝から晴れ。最高気温は、26.8℃と夏日になりました。

 汗ばむ中、トマト苗の定植とハツカダイコンの種まきをしました。


 今年は、トマトの支柱を写真のように四角に組んでみました。(これまでは三角形)
 支柱の材料も手間も2倍かかりました。目的は、トマトが成長してきたときにより長く伸ばせるようにすることです。三角形より風の抵抗が増しまので、筋交いを入れてがっちりと仕上げました。

 トマトの苗は、横向きに植えてみました。

 これは、「奇跡のリンゴ」の木村さんの本に出ていた方法で、いつかやってみたいと思っていました。茎の部分からも根が出て、水分と養分の吸い上げが良くなるはず・・・・・

 ハツカダイコンは、いつものように害虫除けのため、ネットをかけました。
 無農薬栽培へのこだわりです。二,三日で発芽するでしょう。

 バジルとケールは小さめの連結ポットに種をまきました。発芽まで一週間くらいかかるかな。

 これから、毎日いろいろな種をまいていきます。