JH7UBCブログ

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

PIC12F1822 MCC エレキー

2022-04-08 22:07:27 | MPLAB X MCC
 以前、Raspberry Pi Picoでエレキーを作ってみました。今回、そのアルゴリズムを使って、MPLAB X + XC8 + MCC環境で、PIC12F1822でエレキーを作ってみます。

 回路図です。電源は、乾電池2本で3Vとします。パドル(dot Keyとdash Key)は、RA3,RA4に接続します。(デジタル入力でPIC内でPULL UPしておきます)速度調整用の電圧入力は、アナログ入力ポートAN0(RA0)にVRから与えます。送信インジケータ用のLEDと送信機用の出力(2SC1815オープンコレクタ出力)は、RA1に接続します。SIDE TONE用のPWM出力(700Hz)は、RA5に出力し、スピーカーを直接接続しています。


 プロジェクトを作成し、MCCを立ち上げます。
 System Moduleは、INTOSC,FOSC,4MHz
 LVPのチェックを外し、全てのPinを使えるようにします。

 TMR1.TMR2,ECCP,ADCの各モジュールを導入します。
 Pin Moduleの設定をします。
 RA3,RA4は、入力にし、WPUにチェックを入れます。更にResiatersタグを開き、nWPUENをenabledに設定します。
 他のPinは、下のように設定し、RA3は今回は使用しません。


 Interrupt Moduleの設定です。Timer1で、Timer割込みをかけますので、TMR1のEnabledにチェックを入れます。

 TMR1 Moduleの設定です。Prescalerを1:1にし、Timer Periodを1msに設定します。Enable Timer Interruptにチェックが入っていますので、1msごとにTimer割込みがかかります。


 TMR2とECCP moduleは、PWMのための設定です。
 TMR2 Moduleで、Prescalerを1:16、Timer Periodを1.42msに設定するとPWM Frequencyは、702.25Hzになります。(これは、好みの周波数に設定してください。例800Hz)
  ECCP Moduleを見ると、PWM Duty Cycle 50%の時、CCPR Value=177になっています。この値は、プログラムの中で利用します。
 PWM(P1S)は、RA5に出力します。



 ADC Moduleの設定です。
 Result Alignmentをright(右揃え)に設定します。

 プログラムです。
 Raspberry Pi Picoの記事のプログラムをPICに移植しました。アルゴリズムは同じです。
 PWM信号を出したり、止めたりするには、EPWM_LoadDutyValue()関数を使い、EPWM_LoadDutyValue(177);で、Duty Cycle 50%のPWM信号が出て、
EPWM_LoadDutyValue(0);でPWM信号が止まります。
---------------------------------------------------------------------
/*
 * PIC16F1822 MCC Elekey
 * 2022.4.8
 * JH7UBC Keiji Hata 
*/

#include "mcc_generated_files/mcc.h"

//各Pinの定義
#define TX LATA1
#define dot_Key RA3 
#define dash_Key RA4

//各変数の設定
bool dot_flag = 0;
bool dash_flag = 0;
bool gate_flag = 0;
uint8_t mode = 0;
volatile uint16_t count = 0;
uint16_t dot_time = 100;
uint16_t dash_time = 300;
uint16_t space_time = 100;

//割込みサービスルーチン
void ISR()
{
     if (gate_flag == 1){//gsteが開いていれば、カウントアップ
         count++;
    }
     if (mode == 1 & dash_Key == 0)//dot送出中にdashキーが押されればdash_flagを立てる
         dash_flag = 1;
     if (mode == 2 & dot_Key ==0)//dash送信中にdotキーが押されればdash_flagを立てる
         dot_flag = 1;
}

//dotとspaceを送出する
void dot_out()
{
    count = 0;
    mode = 1;
    gate_flag =1;
    TX = 1;
    EPWM_LoadDutyValue(177);
    while(count <= dot_time);
    count = 0;
    TX = 0;
    EPWM_LoadDutyValue(0);
    while(count <= space_time);
    gate_flag = 0;
    mode = 0;
}

//dashとspaceを送出する
void dash_out()
{
    count = 0;
    mode = 2;
    gate_flag =1;
    TX = 1;
    EPWM_LoadDutyValue(177);
    while(count <= dash_time);
    count = 0;
    TX = 0;
    EPWM_LoadDutyValue(0);
    while(count <= space_time);
    gate_flag = 0;
    mode = 0;
}

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

     // Enable the Global Interrupts
     INTERRUPT_GlobalInterruptEnable();

     // Enable the Peripheral Interrupts
     INTERRUPT_PeripheralInterruptEnable();

     TMR1_SetInterruptHandler(ISR);//TMR1 Timer割込みハンドラー
     EPWM_LoadDutyValue(0);

     while (1)
    {
         dot_time = ADC_GetConversion(0) >> 2;//AN0
         if (dot_time < 40)
             dot_time = 40;
         if (dot_time > 200)
             dot_time = 200;
         dash_time = (dot_time << 1) + dot_time;//dash_time=dot_time * 3
         space_time = dot_time;
         if (dot_Key == 0 | dot_flag ==1)
         {
             dot_out();
             dot_flag = 0;
         }
         if (dash_Key == 0 | dash_flag ==1)
         {
             dash_out();
             dash_flag = 0;
         }
    }
}
---------------------------------------------------------------------
 ブレッドボードです。


 実際にモールス符号を打ってテストをしています。

 Raspberry Pi Pico でPinにスピーカーを直付けしたので、PICでも、PWM信号出力RA5を直接スピーカーに接続してみました。ちょっと心配したのですが、ちょうど良い音量で聞こえます。

 エレキーの打ち心地は、たいへんFBです。プログラムが簡単ですので、各局の好みに合わせて、カスタマイズすることも可能でしょう。

 PIC12F1822は、秋月電子で140円で入手できますので、非常に安価にエレキーを製作することができます。

PIC16F1705 MCC OP Ampテストその1

2022-04-06 17:19:14 | MPLAB X MCC
 PIC16F1705の特徴の一つは、オペアンプを内蔵していることです。

 このオペアンプは、いろいろな使い方ができると思います。

 今回は、PIC内のFVR(Fixed Voltage Reference)をオペアンプを介して外部に取り出してみます。

 オペアンプはボルテージフォロアで動作させて低インピーダンスで出力します。ボルテージフォロアの場合、入力電圧=出力電圧です。


 内部のオペアンプのダイアグラムです。非反転入力には、FVR Buffer2を選び、反転入力には、OP OUTを接続するように設定します。

 FVRは、1.024Vですが、SWを押すたびVRF Buffer Gainを変えて、2倍(2.48V)、4倍(4.96V)を出力するようにプログラミングします。

 プロジェクトを作成して、MCCを立ち上げます。
 オペアンプは、OPA1を使うことにして、OPA1モジュールを導入し、更にFVRモジュールも導入します。

 System Moduleは、Clock 8MHz_HFに、LVPはチェックを外しました。



 Pinモジュールの設定です。SWは、RC3に接続しますので、RC3をinputに設定し、WPUにチェックを入れて、ウィークプルアップします。この時、RegistersでnWPUENをenabledに設定します。


 OPA1モジュールで、入力チャンネルをFVR_Buffer2とします。


 FVRモジュールは、FVR_Buffer2 Gainの初期値として、1x=1.024Vとしておきます。

 プログラムです。
 FVR_Buffer Gainmの設定は、FVRCONレジスタのbi4,bi3で行い
bit4 bit3
1     1      x4
1      0     x2
0      1     x1
0      0     off
ですので、dataを左に2bitシフトして、0x80に加えた値をFVRCONに設定しています。(なお、bit8はFVRENで、1でFVR onです。)
-------------------------------------------------------------
/*
 * PIC16F1705 MCC OP Amp test 1
 * 2022.4.6
 * JH7UBC Keiji Hata
*/

#include "mcc_generated_files/mcc.h"
#define SW RC3
uint8_t n = 1;

void Vref_change(uint8_t data )
{
     FVRCON = 0x80 + (data<<2);
}


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

     while (1)
    {
         if (SW==0)
         {
             n++;
             if(n > 3)
                n=1;
             Vref_change(n);
             while(SW==0){   //SWが1になるまで待つ
                __delay_ms(10);
             }
         }
         __delay_ms(10);
    }
}
-------------------------------------------------------------

 電源を入れると初期のFVR=1.024Vが出力されます。
 実測値は1.04Vでした。


 SWボタンを一回押すとFVR_Buffer2 Gain=x2となり、2.048Vが出力されます。
 実測値は、2.07Vでした。


 更にもう一回SWを押すとFVR_Buffer2 Gain=x4となり、4.096Vになります。実測値は、4.11Vでした。

 更に、SWを押すと、Gain=x1となり、最初の状態に戻ります。

PIC16F1705 MCC ADC テスト

2022-04-04 18:20:10 | MPLAB X MCC
 MPLAB X + XC8 + MCC環境で、PIC16F1705のADCのテストをします。

 回路図です。AN0から入力した電圧をAD変換して、その数値(0~1023)をシリアル通信で出力して、TeraTermに表示します。
 電源は、USBシリアル変換モジュールFT234から供給します。AD変換のリファレンスは、VDDとします。
 

 プロジェクトを作成し、MCCを立ち上げます。

 System moduleの設定をします。Internal Clockは、16MHz_HFとしました。


 ADCモジュールとEUSARTモジュールを導入して、設定します。
 ADCモジュールは、Result Alignment=right(右詰め)だけ設定しました。


 EUSARTの設定は、9600bpsのままで、何も設定せず、そのままです。


 Pinモジュールです。EUSARTは、RC4=TX,RC5=RXがデフォルトで設定されています。ADCは、RA0=AN0に設定されています。PIC16F1705は、8チャンネルのアナログ入力(AN0~AN7)を持っています。今回は、AN0だけを使いました。他のアナログ入力を使う場合は、Pin Managerで該当部分をクリックして、設定します。


 Generateして、MCCを終了します。
 プログラムです。
 1秒ごとにAN0の電圧をAD変換して、数値をシリアル通信で送信します。
 printf()を使っていますので、プロジェクトのPropatiesで、C standardをC90にします。また、
#include <stdlib.h>
#include <stdio.h>
の設定が必要です。
-----------------------------------------------------------------
/*
 * PIC16F1705 MCC ADC test
 * 2022.4.4
 * JH7UBC Keiji Hata
*/

#include "mcc_generated_files/mcc.h"
#include <stdlib.h>
#include <stdio.h>

void putch(uint8_t ch)
{
     EUSART_Write(ch);
}

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

     while (1)
    {
         uint16_t data=ADC_GetConversion(0);
         printf("%4d\r\n",data);
         __delay_ms(1000);
    }
}
-----------------------------------------------------------------
 ブレッドボードです。


 TeraTermの画面です。VRを回していくとAD変換された値が徐々に大きくなっていきました。


PIC16F1705 MCC PWMテスト

2022-04-03 22:17:49 | MPLAB X MCC
 MPLAB X + XC8 + MCC環境で、PIC16F1705のPWMのテストをします。
 MCCを使わない場合、クロック、タイマー、デューティ設定などを計算によって求めなければなりません。(PIC16F1705PWMテスト参照)

 MCCを利用することにより、非常に簡単にPWM信号を発生させることができます。

 例として、500Hz,デューティ比50%のPWM信号をRA0に出力してみます。PIC16F1705はPWMを発生できるモジュールを4つ持っています。(CCP1(PWM1),CCP2(PWM2),PWM3,PWM4)今回は、PWM3を利用します。



 プロジェクトを作成し、MCCを立ち上げます。
 System moduleでクロックの設定をします。
 INTOSC,FOSC,8MHz_HFとして、クロックは8MHzとしました。


 PWM3モジュールとTMR2モジュールを導入します。
 Pin moduleで、PWM3をRA0に出力するよう設定します。


 PWMの周期を設定します。500Hzですから、PWM周期は2msです。
 これを設定するのは、TMR2モジュールです。Prescalerの比を調整して、Timer Periodを2msに設定します。



 PWM周期を設定するとPWMモジュールのPWM Parametersに表示されます。
 デューティ比(Duty Cycle)は、%で設定します。その時のPWMDC(PWM Duty Cycleレジスタ)の値が表示されます。この場合499です。



 これで、Generateし、MCCを終了します。
 生成されたmain.c です。
------------------------------------------------------------
#include "mcc_generated_files/mcc.h"

void main(void)
{
     // initialize the device
     SYSTEM_Initialize();
      while (1)
    {
    }
}
------------------------------------------------------------
 最小限のプログラムですが、PWM信号がRA0に出力されました。



 実際の周波数を測定してみました。498Hzでした。


 デューティ比を変えるには、
 PWM3_LoadDutyValue(uint16_t dutyValue) 関数を使います。
 この例では、50%でPWMDCの値が499ですから、デューティ比25%にするには、dutyValue=250とします。
 PWM3_LoadDutyValue(250); 
 をプログラムに書き込みます。
 その波形です。

 PWM信号を止めるには、dutyValue=0にするか、TMR2を止める
 TMR2_StopTimer(void)関数を使います。
 PWM信号をスタートさせるのは、
 TMR2_StartTimer(void)を使います。

PIC16F1705 MCC AQM0802A表示テスト

2022-04-02 12:12:28 | MPLAB X MCC
 MPLAB X + XC8 + MCCの環境で、PIC16F1705を使ったI2C LCD AQM0802Aの表示テストをします。回路図です。
 電源は、乾電池2本(3V)ととし、PIC16F1705のI2Cポートはデフォルトで、RC0=SCL,RC1=SDAとします。AQM0802Aは、秋月電子のモジュールを使用します。


 プロジェクトを作成し、MCCを立ち上げます。
 System Moduleの設定です。
 Clockは、INTOSC,FOSC,8MHz_HF,PLL Enableとして、32MHzで動作させています。


 MSSPモジュールを導入します。
 I2C,Masterモード,CLock=100000Hz(100KHz)としました。



 Pin Moduleです。I2Cポートは、デフォルトで、RC0=SCL,RC1=SDAとなります。
AQM0802A Moduleには、プルアップ抵抗が内蔵されているのですが、一応ウィークプルアップ(WPU)を有効にしておきます。



 Interruputは、デフォルトのままです。

 プログラムです。1行目に「JH7UBC」を表示し、2行目に数字を0からカウントアップします。
 printf関数を使うため、プロジェクトのPropertiesのXC8 Global OptionsのC standard をC90にします。
--------------------------------------------------------------------
/*
 * PIC16F1705 MCC AQM0802A test
 * 2022.4.2
 * 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(uint8_t chr)
{
     I2C_Write1ByteRegister(I2CLCD_AQM0802A, 0x40, chr);
     __delay_us(30); // 30us
}

//-------- send command -------------------------
void LCD_cmd(uint8_t 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(){
     LCD_cmd(0x01);
}

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

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

//-------- write 1 character to LCD ----------------
void putch(uint8_t 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(void)
{
     // initialize the device
     SYSTEM_Initialize();
     // Enable the Global Interrupts
     INTERRUPT_GlobalInterruptEnable();
     // Enable the Peripheral Interrupts
     INTERRUPT_PeripheralInterruptEnable();

     LCD_init();
     printf("JH7UBC");
     uint8_t count = 0;
     while (1)
    {
         LCD_cursor(2,1);
         printf("%3d",count);
         count++;
         __delay_ms(1000);
    }
}

--------------------------------------------------------------------
ブレッドボードです。

 他のPinでI2Cを使いたい場合、MCCのPin ManagerでSCL,SDAに指定するPinを設定します。
 例えば、RA0=SCL,RA1=SDAの場合は、下の図のように設定すればOKです。設定後、再びGenerateして、コンパイルしてPICにプログラムを書き込みます。
 プログラムはそのままで、PICとAQM0802Aの接続を変更するだけで、動作します。