上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
こんばんは!
携帯電話が故障してちょっぴり残念なゆってぃです><


今日は、以前に書いてすっかり忘れていた組み込みC言語をオブジェクト指向っぽく書くテクニックの続きです!

簡単におさらいをすると
構造体の中に関数ポインタを持たせることで、C++やJAVAのメソッドと同じような働きをさせることが出来るということでした。

言葉だけ聞くと簡単そうに聞こえるのですが、LEDを点滅させるだけの単純なプログラムでも、オブジェクト指向っぽく書こうとすると、意外と大変です(涙)

おまけに、過去の記事で書いたLED点滅プログラムのソースではプログラム領域が39hワード・データ領域が7hワードだったのに対し、今回のソースはプログラム領域が1D3hワード・データ領域が1Dhワードも使用しています。

すでにPIC16F84Aの貧弱なROM領域の50%弱を使ってしまっています。

LEDを点滅させるだけなのに…(T_T)

ですので、本来はこの程度のソフトであれば普通に書いた方がよいと思います。

では早速ソースコードを書いていきましょう。
なお、毎度のことですが、本ブログではインデントに全角スペースを使用しているため、コピペではコンパイルが通りませんのでご注意ください。

今回、僕が作成したヘッダファイルは2つあります。
1つは変数の型を再定義したtypedefine.h
もう1つは、LEDクラスを記述したled.hです。

//-----typedefine.h ここから-----//

#ifndef __TYPEDEFINE_H__
#define __TYPEDEFINE_H__

typedef unsigned char Bool;
typedef unsigned char Uint8;
typedef unsigned short Uint16;
typedef unsigned long Uint32;

#endif

//-----typedefine.h ここまで-----//

//-----led.h ここから-----//

#ifndef __LED_H__
#define __LED_H__

#include"typedefine.h"

#define FALSE (0)
#define TRUE  (1)

typedef struct TAG_LED_CTRL_COND{
 //メンバ変数
 Bool isInitialized;//初期化フラグ
 Uint8 OnTime;//LED点灯時間
 Uint8 OffTime;//LED消灯時間

 //メソッド
 Bool (*setOnTime)(struct TAG_LED_CTRL_COND *pLC, Uint8 time); //LEDの点灯時間をセットする
 Bool (*setOffTime)(struct TAG_LED_CTRL_COND *pLC, Uint8 time); //LEDの消灯時間をセットする
 Bool (*initLedPort)(struct TAG_LED_CTRL_COND *pLC);//LEDポートを初期化する
 Bool (*onLedBlink)(struct TAG_LED_CTRL_COND *pLC);//LEDを点灯させる
 Bool (*offLedBlink)(struct TAG_LED_CTRL_COND *pLC);//LEDを消灯させる
 Bool (*initLedTimer)(struct TAG_LED_CTRL_COND *pLC);//LED用点滅タイマーを初期化する
 Bool (*startLedTimer)(struct TAG_LED_CTRL_COND *pLC);//LED用点滅タイマーを起動する
 Bool (*stopLedTimer)(struct TAG_LED_CTRL_COND *pLC);//LED用点滅タイマーを停止する

}LED_CTRL_CONDITION;

//extern関数のプロトタイプ宣言
Bool startLedBlink(LED_CTRL_CONDITION *pLC);
LED_CTRL_CONDITION *getLC(void);

#endif

//-----led.h ここまで-----//

次に、メインルーチンと割り込みハンドラを含むmain.cを記述します。


//-----main.c ここから-----//

#include"pic.h"
#include"typedefine.h"
#include"led.h"

__CONFIG( FOSC_EXTRC & WDTE_OFF & PWRTE_ON & CP_ON);

static void initIntReg(void);

int main(void){

 LED_CTRL_CONDITION *pLC;

 initIntReg();
 
 if(startLedBlink(pLC) == TRUE){
  while(1);
 }else{
   TRISA = 0x00;
  PORTA |= 0x02;
  while(1);
 }

 return 0;

}

static void initIntReg(){
 
 GIE = 1;

}

void interrupt int_func(){

 LED_CTRL_CONDITION *pLC;



 if(T0IF){

  pLC = getLC();
  pLC->stopLedTimer(pLC);

  if(PORTA & 0x01){
   pLC->offLedBlink(pLC);
  }else{
   pLC->onLedBlink(pLC);
  }

  T0IF = 0;

  pLC->startLedTimer(pLC);

 }
  
}

//-----main.c ここまで-----//

最後に、本プログラムの要となるled.cです。

//-----led.c ここから-----//

#include"pic.h"
#include"typedefine.h"
#include"led.h"

//グローバル領域にインスタンスを生成
static LED_CTRL_CONDITION _instance_led;

//静的関数のプロトタイプ宣言
static LED_CTRL_CONDITION *initLedCond(void);

//LEDクラスの持つメソッドの実態
static Bool SET_ON_TIME(LED_CTRL_CONDITION *pLC, Uint8 time);
static Bool SET_OFF_TIME(LED_CTRL_CONDITION *pLC, Uint8 time);
static Bool INIT_LED_PORT(LED_CTRL_CONDITION *pLC);
static Bool ON_LED_BLINK(LED_CTRL_CONDITION *pLC);
static Bool OFF_LED_BLINK(LED_CTRL_CONDITION *pLC);
static Bool INIT_LED_TIMER(LED_CTRL_CONDITION *pLC);
static Bool START_LED_TIMER(LED_CTRL_CONDITION *pLC);
static Bool STOP_LED_TIMER(LED_CTRL_CONDITION *pLC);

//---------------------------

Bool startLedBlink(LED_CTRL_CONDITION *pLC){

 Bool err = FALSE;//どこかでエラーが発生したらTRUEになる。

 pLC = initLedCond();//LEDクラスのインスタンスを取得 

 if(pLC->setOnTime(pLC, 0x07) == FALSE){
  err = TRUE;
 }else if(pLC->setOffTime(pLC, 0x07) == FALSE){
  err = TRUE;
 }else if(pLC->initLedPort(pLC) == FALSE){
  err = TRUE;
 }else if(pLC->initLedTimer(pLC) == FALSE){
  err = TRUE;
 }else if(pLC->startLedTimer(pLC) == FALSE){
  err = TRUE;
 }

 if(err == TRUE){
  return FALSE;
 }else{
  return TRUE;
 }
}



static LED_CTRL_CONDITION *initLedCond(void){

 if(_instance_led.isInitialized == FALSE){
  //メンバ変数初期化
  _instance_led.isInitialized = TRUE;
  _instance_led.OnTime  = 0;
  _instance_led.OffTime = 0;

  //メソッド初期化
  _instance_led.setOnTime   = SET_ON_TIME;
  _instance_led.setOffTime = SET_OFF_TIME;
  _instance_led.initLedPort  = INIT_LED_PORT;
  _instance_led.onLedBlink = ON_LED_BLINK;
  _instance_led.offLedBlink = OFF_LED_BLINK;
  _instance_led.initLedTimer = INIT_LED_TIMER;
  _instance_led.startLedTimer = START_LED_TIMER;
  _instance_led.stopLedTimer = STOP_LED_TIMER;
 }
  
 return &_instance_led;

}

LED_CTRL_CONDITION *getLC(void){
 
 return &_instance_led;
 
}

static Bool SET_ON_TIME(LED_CTRL_CONDITION *pLC, Uint8 time){

 if(time > 0x07){
  return FALSE;
 }else{
  pLC->OnTime = time;
 }

 return TRUE;

}

static Bool SET_OFF_TIME(LED_CTRL_CONDITION *pLC, Uint8 time){

 if(time > 0x07){
  return FALSE;
 }else{
  pLC->OffTime = time;
 }

 return TRUE;

}

static Bool INIT_LED_PORT(LED_CTRL_CONDITION *pLC){

 PORTA &= 0xfe; //念のため出力はLOW
 TRISA &= 0xfe; //A0ポートを出力に設定

 return TRUE;

}

static Bool ON_LED_BLINK(LED_CTRL_CONDITION *pLC){
 
 PORTA |= 0x01;
 OPTION_REG |= pLC->OnTime;

 return TRUE;

}

static Bool OFF_LED_BLINK(LED_CTRL_CONDITION *pLC){

 PORTA &= 0xfe;
 OPTION_REG |= pLC->OffTime;

 return TRUE; 

}
static Bool INIT_LED_TIMER(LED_CTRL_CONDITION *pLC){

 T0IE = 0;
 T0CS = 0;
 PSA  = 0;
 if(pLC->OffTime <= 0x07){
     OPTION_REG |= pLC->OffTime;//offTimeに正しい値が入っていれば…
 }else{
  return FALSE;
 }
 TMR0 = 0x00;

 return TRUE; 

}

static Bool START_LED_TIMER(LED_CTRL_CONDITION *pLC){

 T0IE = 1;

 return TRUE;

}

static Bool STOP_LED_TIMER(LED_CTRL_CONDITION *pLC){

 T0IE = 0;
 TMR0 = 0x00;

 return TRUE;

}

//-----led.c ここまで-----//

はい。
読む気が失せますね…

僕自身、こんなにたいそうなコード量になるとは思ってもいませんでした(汗)
具体的な解説はしませんが(ぉぃ!)、要は関数ポインタで構造体の中にメソッドを入れているだけです。
あとは、エラー検出とかレジスタアクセスの隠蔽化とか、、、そこらへんを少しだけ真面目にやってみたら、こんなになってしまいました…(涙)
あ、ソースの解説は後日きちんと行いますからね(笑)

そうそう。構造体の中に関数ポインタを入れた場合の注意です。
関数ポインタという名前がついている以上、ひとつひとつがアドレス幅分の大きさを持ちますので、その分だけ構造体のサイズは大きくなるのでご注意くださいね。

さて、今日はここまでにしましょう!
最後までお読みいただいて、ありがとうございました!
関連記事
スポンサーサイト
コメント
コメントの投稿
トラックバック URL
トラックバック
ご訪問者様
プロフィール

ゆってぃ

Author:ゆってぃ
経歴7年の組み込み系・制御系エンジニアです。
("ど素人"という文言は取りました…笑)
ソフトウェア開発経験ゼロの状態から、なんとか実務がこなせるようになってきた現在に至るまでの経験を、備忘録代わりに綴っていきたいと思います。
入門者の方、大歓迎!
(上級者の方、ごめんなさい…)

あと、ブログには全然関係ないですが、Bumpy Headというバンドのギターをやっています。
ライブ情報なんかも書いたりすることがあるので、その時に「行ってもいいよ~」といった感じのコメントを戴けると、泣いて喜びます(泣)
ブログ読んでくださってる方なら、チケット代サービスしちゃいます!

最後に…滅多に流用することは無いでしょうが、このブログに書かれているソースは、特に指定の無い限りMITライセンスとします。ただし、一部それ以外のものもございますのでご注意下さい。
※ブログのリンク先にあるコードに関しては、リンク先のポリシーに従ってください。

最新記事
最新コメント
カテゴリ
RSSリンクの表示
メールフォーム

名前:
メール:
件名:
本文:

twitter
リンク
ブロとも申請フォーム
スポンサードリンク


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。