2009年04月29日

PIC12F675でエレキー

PIC12F675でエレキー

PIC12F675でエレキー

今回は、Microchip社の8Pinマイコン・PIC12F675でエレキー(アマチュア無線用)を作ってみました。
エレキープロジェクト第8ステージとなりました。

PIC12F675は、秋月電子さんでは130円で販売されているA/Dコンバータ内臓のマイコンです。
小型安価のため、いろいろと利用価値があります。
 http://akizukidenshi.com/catalog/g/gI-02113/

Webサイトを検索したところ
 PICマイコン、C言語、フリーのCコンパイラ
で作られたエレキーのサンプルソースコードがなかったため、今回の試作・公開となりました。
参考にしていただければ幸いです。

Cコンパイラはフリーの SDCC(Small Device C Compiler)
アセンブラ・リンカもフリーの gputils(GNU PIC Utilities)を使用しました。

上記ソフトウエアのインストール方法と簡単な使用方法は、次のサイトにわかりやすい説明がありますのでご参照ください。
SDCCの使い方(http://xenopusq.hp.infoseek.co.jp/pic/sdcc.html)
SDCCとgputilsのインストール


マイコン動作は、以前の記事「エレキープロジェクト・UML設計図」に基づいています。

ポート配置と配線はこちらです。
(今回の配線はブレッドボードを使用してみました。)
LED出力     → GP5(負論理)
Buzzer出力   → GP4(Trバッファ付き)
Dot入力     → GP1(内部プルアップ抵抗)
Dash入力    → GP2(内部プルアップ抵抗)
速度調整     → AN0(VR入力)
回路図は下記の通りです。

PIC12F675でエレキー

ソフトウエア機能としては下記を使用しています。
A/D変換
タイマ(0)割り込み
ポートの入出力/内臓プルアップ機能

PIC12F675のデータシート(英文)はこちら
 http://ww1.microchip.com/downloads/en/devicedoc/41190c.pdf

PIC12F629でもエレキー作ってみました。 下記記事をご参照ください。
 http://micom.hamazo.tv/e1848478.html

動作の様子はこちら


コンパイル時のパラメータは下記のようにしました。(pic12f675_elekey.c はソースファイル名)
> sdcc -V -c -mpic14 -p12f675 pic12f675_elekey.c
> gplink -I"c:\program files\SDCC\lib\pic" -w -r -o pic12f675_elekey pic12f675_elekey.o libsdcc.lib pic12f675.lib

ソースコードはこちらです。
 (上記のSDCCの環境でコンパイル(HEX作成)可能です。)

//--------------------------------------------------------------------
//
//      Simple Elekey Program
//
//      DESCRIPTION:
//          Hardware:   Microchip PIC 12F675
//          C-Compoler: SDCC(Small Device C Compiler)
//          Editer:     M.Utsunomiya
//          Date:       2009/4/29
//
//--------------------------------------------------------------------

//----I/O DESCRIPTION ------------------------------------------------
//  実機レイアウト・配線
//  LED出力     → GP5(負論理)
//  Buzzer出力  → GP4(Trバッファ)
//  Dot入力     → GP1(内部プルアップ抵抗)
//  Dash入力    → GP2(内部プルアップ抵抗)
//  速度調整    → AN0(VR入力)
//--------------------------------------------------------------------

#include <sdcc-lib.h>
#include <pic12f675.h>

//----------------------------------------------------------------------------
//  Define Code Parameter
//----------------------------------------------------------------------------
#define PARA_ALL_OFF    0x00
#define PARA_DOT_ON     0x01
#define PARA_DOT_OFF    0x02
#define PARA_DASH_ON    0x03
#define PARA_DASH_OFF   0x04

#define LIMIT_VALUE     0x03            // チャタリングフィルタ用

#define MAX_SPEED       5
#define MIN_SPEED       15


//----------------------------------------------------------------------------
//  Define User Memory
//----------------------------------------------------------------------------
unsigned int    ParaTime;
unsigned int    ADCData;
unsigned char   Timer100ms;

unsigned char   ParaCode;
unsigned char   CntDotOn;
unsigned char   CntDashOn;

//--------------------------------------------------------------------
//       Configuration Bits (pic12f675.h 内で定義)
//--------------------------------------------------------------------
//  _CPD_ON / _CPD_OFF                      : Data Code Protection
//  _CP_ON / _CP_OFF                        : Code Protection
//  _BODEN_ON / _BODEN_OFF                  : Brown-out(低電圧) Detect Enable
//  _MCLRE_ON / _MCLRE_OFF                  : GP3/MCLR pin function select
//  _PWRTE_OFF / _PWRTE_ON                  : Power-up Timer Enable
//  _WDT_ON / _WDT_OFF                      : WatchDogタイマ設定
//  _LP_OSC / _XT_OSC / _HS_OSC / _EC_OSC   : 200kHz以下外部/4MHz以下外部/4MHz以上外部/内部RC
//  _INTRC_OSC_NOCLKOUT / _INTRC_OSC_CLKOUT : INTOSC oscillator: CLKOUT function
//  _EXTRC_OSC_NOCLKOUT / _EXTRC_OSC_CLKOUT : EC: I/O function
//--------------------------------------------------------------------

int at 0x2007 __config = _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT;

void Delay(volatile long dly)
{
    while(dly-- > 0x00) {;}
}


//----------------------------------------------------------------------------
// 初期化
//----------------------------------------------------------------------------
void Init() {
    CMCON = 0x07;           // コンパレータ未使用
    ANSEL = 0x11;           // 8Tosc,AN0
    ADCON0 = 0x01;          // Left justified, Vref=Vdd,AN0,A/D_ON
    TRISIO = 0x0F;          // GP0~3:Input ,GP4~5:Output
    WPU = 0x06;             // GP1~2:キー入力端子はプルアップ抵抗
    GPIO = 0x00;

    //OPTION_REG = 0x81;    // プリスケーラ: TMR0/4  0.256*4msec
    OPTION_REG = 0x03;      // プルアップ許可、プリスケーラ:TMR0/16(0.256*16msec)
    TMR0 = 0x00;
    T0IE = 1;               // TMR0割り込み許可
}

//----------------------------------------------------------------------------
// ボリューム電圧値
//----------------------------------------------------------------------------
unsigned char volume() {
    unsigned char tmp;

    if (GO_DONE == 0) {         // 変換済み?
        tmp = ADRESH;           // 上位8bit (前回の変換結果!)

        GO_DONE = 1;            // A/D変換開始
        //while ( GO_DONE ){;}  // 変換待ち
        return tmp;
    }
    else
        return 0x00;
}

//----------------------------------------------------------------------------
//  LEDを点灯する処理
//----------------------------------------------------------------------------
void LED_ON() {
    GPIO &= ~0x20;
}

//----------------------------------------------------------------------------
//  LEDを消灯する処理
//----------------------------------------------------------------------------
void LED_OFF() {
    GPIO |= 0x20;
}

//----------------------------------------------------------------------------
//  Buzzer On する処理
//----------------------------------------------------------------------------
void BUZZER_ON() {
    GPIO |= 0x10;
}

//----------------------------------------------------------------------------
//  Buzzer Off する処理
//----------------------------------------------------------------------------
void BUZZER_OFF() {
    GPIO &= ~0x10;
}

//----------------------------------------------------------------------------
//  Dotポートチェック
//----------------------------------------------------------------------------
char ChkDotPort() {
    if ((GPIO & 0x02) == 0) return 1;
    return 0;
}

//----------------------------------------------------------------------------
//  Dashポートチェック
//----------------------------------------------------------------------------
char ChkDashPort() {
    if ((GPIO & 0x04) == 0) return 1;
    return 0;
}

//----------------------------------------------------------------------------
//  Set Output port
//----------------------------------------------------------------------------
void SetOutput()
{
    if ((ParaCode == PARA_DASH_ON) || (ParaCode == PARA_DOT_ON)) {
        LED_ON();
        BUZZER_ON();
    }
    else {
        LED_OFF();
        BUZZER_OFF();
    }
}

//----------------------------------------------------------------------------
//  Check Input port
//----------------------------------------------------------------------------
void ChkInputPort()
{
    // for Dot
    if (ParaCode != PARA_DOT_ON) {
        if (CntDotOn < LIMIT_VALUE) {
            if (ChkDotPort())           //  Dotポートチェック
                CntDotOn ++;
            else
                CntDotOn = 0;
        }
    }
   
    // for Dash
    if (ParaCode != PARA_DASH_ON) {
        if (CntDashOn < LIMIT_VALUE) {
            if (ChkDashPort())          //  Dashポートチェック
                CntDashOn ++;
            else
                CntDashOn = 0;
        }
    }
}

//----------------------------------------------------------------------------
//  Set Parameter Dash
//----------------------------------------------------------------------------
char SetParaDash()
{
    if (CntDashOn >= LIMIT_VALUE) {
        CntDashOn = 0;
        ParaCode = PARA_DASH_ON;
        ParaTime = (ADCData * 3);
        return 1;
    }
    return 0;
}

//----------------------------------------------------------------------------
//  Set Parameter Dot
//----------------------------------------------------------------------------
char SetParaDot()
{
    if (CntDotOn >= LIMIT_VALUE) {
        CntDotOn = 0;
        ParaCode = PARA_DOT_ON;
        ParaTime = ADCData;
        return 1;
    }
    return 0;
}


//----------------------------------------------------------------------------
//  キー処理メイン関数
//----------------------------------------------------------------------------
void key_sequence(void)
{
    unsigned char tmp;
   
    Timer100ms ++;
    if (Timer100ms > 25) {
        Timer100ms = 0x00;

        tmp = volume();
        if (tmp > 0x00) {
            tmp >>= 0x02;
            ADCData = tmp;
            ADCData += MAX_SPEED;
        }
    }

    if (ParaTime != 0) {
        ParaTime --;
        if (ParaTime == 0) {
            if (ParaCode == PARA_DOT_ON) {
                ParaCode = PARA_DOT_OFF;
                ParaTime = ADCData;
            }
            else if (ParaCode == PARA_DASH_ON) {
                ParaCode = PARA_DASH_OFF;
                ParaTime = ADCData;
            }
            else if (ParaCode == PARA_DOT_OFF) {
                if (!SetParaDash())
                    ParaCode = PARA_ALL_OFF;
            }
            else if (ParaCode == PARA_DASH_OFF) {
                if (!SetParaDot())
                    ParaCode = PARA_ALL_OFF;
            }
            else {
                ParaCode = PARA_ALL_OFF;
            }
            SetOutput();
        }
    }

    ChkInputPort();
    if (ParaCode == PARA_ALL_OFF) {
        if (!SetParaDot())
            SetParaDash();
    }
    SetOutput();
}


//----------------------------------------------------------------------------
// 割り込み(タイマ割り込みのみ使用)
//----------------------------------------------------------------------------
static void Inntrpt(void) interrupt 0
{
    if (T0IF) {                 // TMR0割り込み?
        T0IF = 0;               // 割り込みフラグクリア
       
        key_sequence();         // キー処理メイン関数
    }
}


//----------------------------------------------------------------------------
//  Main関数
//----------------------------------------------------------------------------
main()
{
    Init();                     // システムレジスタ初期化

    // ユーザメモリの初期化
    CntDashOn = 0;
    CntDotOn = 0;
    ADCData = MAX_SPEED;
    ParaTime = 0;
    ParaCode = PARA_ALL_OFF;
    LED_OFF();
    BUZZER_OFF();

    GIE = 1;                    // 全割り込み許可
   
    while (1) {
        ;
    }
}


不明点やご質問はお気軽に、コメント欄、またはお問合せフォームにてご連絡ください。








スクイズ機能で不用意にキーがメモリされてしまい、速度を上げると余計な符号が出る不具合があります。



同じカテゴリー(マイコン開発)の記事
Fusion PCBでエレキー
Fusion PCBでエレキー(2020-04-01 19:00)


この記事へのコメント
お忙しい中、突然のメール失礼します。
[PIC12F675でエレキー] について困っています。

SDCC でコンパイルできません。Win7 or XP 互換モードで行いましたがエラーが出ます。

error 20; Undefined ifentifier 'CMCON'
ANSEL
ADCOND

GPIO

よろしくお願いします。
なおエレキーが動きましたら、貴殿のページにリンク張らせてもらっても、宜しいでしょうか?
Posted by JR6AUA at 2011年06月02日 12:17
GA JR6AUA OM

調べたところ、現在のSDCC・PICライブラリのライセンスが変更になって、ヘッダファイルのインストール先が以前と異なるようです。

エラーをなくすためには、

 C:\Program Files\SDCC\non-free\include\
  内のフォルダとファイルをまとめて
    ↓
 C:\Program Files\SDCC\include\ へコピー

 C:\Program Files\SDCC\non-free\lib\
  内のフォルダとファイルをまとめて
    ↓
 C:\Program Files\SDCC\lib\ へコピー


かつ、

 at と記述している箇所を __at にする。

 interrupt  と記述している箇所を __interrupt にする。

以上でHEXファイルが生成されると思います。
Posted by 宇都宮 at 2011年06月02日 14:21
JR6AUA OM

リンクの件は全く問題ありません。
なるべく多くリンクを張って頂ければ幸いです。

では。
Posted by 宇都宮宇都宮 at 2011年06月02日 17:24
早速の、ご回答ありがとうございます。

やってみました結果 .hex までは行きませんでしたが .asm が作れましたので書込みはできました。

これでやってみます。ありがとうございました。
Posted by JR6AUA at 2011年06月02日 20:21
この .asm ファイルでは動作しませんでした。
色々やってみて、program files (x86) にしてなかったり・・・

結局 .hex ファイルの作成に成功しました。
やっと動作しました。ありがとうございます。

感謝いたします。
Posted by JR6AUA at 2011年06月02日 23:34
無事に動作したようで安心しました。
Posted by 宇都宮 at 2011年06月03日 09:57
SDCCの環境でコンパイル(HEX作成)可能です。とありますが、SDCC4.1.0X64をインストールしようと起動するとWindowsによって浜っ子保護されます。これは無視していいものでしょうか?
又、他の使用可能な環境があればお教えください。

横浜市 中川
Posted by JA5ZZ/1 at 2021年04月07日 15:10
> SDCC4.1.0X64をインストールしようと起動するとWindowsによって浜っ子保護されます。これは無視していいものでしょうか?

すみません。最近SDCCは使っていないのでコメントできません。


>他の使用可能な環境があればお教えください。

現在であれば、MicrochipのMPLAB X IDE + Cコンパイラ で良いかと思います。

ヘッダファイルの入替と
レジスタ名でエラーになるかと思いますので、若干の変更が必要になると思います。
Posted by 宇都宮宇都宮 at 2021年04月07日 15:33
上の画像に書かれている文字を入力して下さい
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。

削除
PIC12F675でエレキー
    コメント(8)