Category : プログラミング
こんばんは!


ひっっっっっさしぶりの更新です。
久しぶりすぎて、僕自身、なんか他の人が書いたブログに不正アクセスしちゃってる気分です(汗)

やぁ、転職して1年が経ち、もうすっかりベテラン面しているゆってぃでございます。
民生品メーカーから自動車系メーカーへの転職だったので、本当に最初はやっていけるか不安でしたが、いはやは、何とかなるものですね。

久々に書こうと思ったのは、本日の業務中、組み込みシステムの基本的な部分にも関わらず、意外と気がつきにくいミスを発見したからです。

え?いやいや、僕が埋め込んだミスじゃないですよ!
やや、本当ですって!(涙)
まぁ、気がつくのに午前いっぱい取られてしまいましたけど><

皆様ご存知の通り、マイコンのプログラムをする上で、ポインタのキャストには細心の注意を払う必要があります。
例えば、こんなことはしてはいけません。


int main(void)
{
char array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int i;
long *p;

for(i=0;i< 7;i++)
{
p = (long*)&array[i];
printf("*p = %04x\n",*p);
}

return 0;

}


おわかりいただけただろうか?

何がいけないかというと、long型のポインタ変数に対し、char型の配列の任意のアドレスを与えているところがNGです。
(厳密に言うと、その値を参照しているprintf文がNGで、ここでマイコンがハングします)

というのも、一般的な32bitマイコンは、変数に対して4バイト境界を跨ぐ様なアクセスをした場合、アドレスエラーが発生するからです。
要するに、4バイトの変数なら、メモリ(RAM/ROM)に配置できるアドレスも4つおきになるんです。
例えば
0x0010_0000番地
0x0010_0004番地
0x0010_0008番地
・・・
みたいにね。
この例では、0x0010_0000~0x0010_0003までがひとつの纏まりで、0x0010_0003と0x0010_0004の間にバイト境界があります。

にも関わらず、上のサンプルコードでは、どこかのタイミングで
0x0010_0001番地
に、無理やり4バイトアクセスする感じになります。
つまり、
0x0010_0001
0x0010_0002
0x0010_0003
=== 越えられない壁 ===
0x0010_0004
の4つのアドレスに、一度にアクセスすることになります。
でも、途中に越えられない壁(バイト境界)があるので、エラーが発生する訳ですね。
どうです?結構落とし穴でしょ(笑)

でもこれ、パソコンで作成したアプリとかだと、エラーになりません。
マイコンなら確実にエラーになるかというと、そうとも限りません。
例えば、ARMのCortex系マイコンでは例外にはなりませんが、SH系マイコンでは例外が発生します。
だからこそ落とし穴なのです!

詳しい話は、wikiペディア先生のページにも書かれています。
バスエラー

因みに、long型やshort型に対して、char型のポインタをキャストする分には問題がありません。
なぜなら、char型はバイト境界を意識せずに、どんな変数にもアクセスできるからです。
なんせ1バイト型ですから、アクセス時にバイト境界も跨ぐもへったくれもございません。

その逆・・・long型やshort型などのポインタに対し、自分より小さな型を持つ変数のアドレスを与えることは
よほどの理由が無い限りオススメ出来ません

でも、マイコンとポインタは切っても切れない関係なので、こういったことに注意しつつ、テクニックを身につけて行きましょうね^^

最後までお読みいただいて、ありがとうございました!
スポンサーサイト
新年あけましておめでとうございます!
明日から仕事ということで、大変憂鬱な気分になっているゆってぃでございます。

むひーーーーーーー!
もっと休みたいよーーーーーーーーーーーー!



さて・・・
今日は、C言語を使用したオブジェクト指向プログラミング技法について書きたいと思います。

みなさまご存知の通り、C言語はオブジェクト指向プログラミング言語(OOPL)ではありません。
ですので、JAVAやC++の様にバリバリのオブジェクト指向プログラミングをする事は困難です。
しかしながら、開発するシステムが大規模になると、オブジェクト指向型の設計の方がメリットがあることは、なんとなくイメージが出来ると思います。

オブジェクト指向にすると何が良いか?
設計がし易くなったり(UMLが適応しやすくなります)
ソフトの見通しが良くなったり(同上)
拡張性が向上したり・・・
メリットは沢山あります。

もちろん、デメリットもあります
コードが冗長になる
 →メモリ使用量(ROM/RAM)が増える、リアルタイム性も落ちる・・・
関数ポインタなどを多用する
 →慣れるまでが大変
などですね。

話を戻します。
先述の通り、C言語で出来るオブジェクト指向(っぽい)プログラミング方法を伝授いたします。
特に、組み込みシステム向けということで書きたいと思います。
ただし、継承とかオーバーロードとかオーバーライドはありません。
ググってみると、Cでもこれらを実現している歴戦の猛者はいらっしゃるのですが、ゆってぃでは使いこなすことが出来ないので、ここでは議論をしません。
もはやこの時点でオブジェクト指向ではない雰囲気むんむんですが
あくまでオブジェクト指向風味ってことで
有権者の方々にはひとつよろしくお願い申し上げたい所存でございます。

(1)クラスの定義は、構造体で実現する
C言語にはクラスという概念はありませんが、構造体は存在します。
んなことは知っているよ!
で、ですよね!すみません…(涙)

ただ、構造体で定義した変数は全てpublicメンバとなってしまい、カプセル化が実現できていません。
また、メソッドを持つことも出来ません。
そこで、以下の様に構造体を作成します。

 publicメンバ…構造体内で定義
 privateメンバ…構造体内に、void型のポインタとして定義(変数構造体は、ソースファイルで定義)
 publicメソッド…関数ポインタで定義
 privateメソッド…static関数として、ソースファイルで定義

実際に例を見てみましょう。
ここでは、LEDを制御するためのLED制御クラス(そのままやないかい!)を例に取ります。

-------------------------------------------------
(Led.h)

// LED制御クラス
typedef struct st_Led{

//メソッド
void (*on)(struct st_Led *pL);
void (*off)(struct st_Led *pL);
en_PortState (*getState)(struct st_Led *pL);

//メンバ変数
void *mem;

}Led;

extern Led* initLed(en_LED_NUM n);
extern Led* getLed(en_LED_NUM n);

-------------------------------------------------
(Led.c)

typedef struct st_LedMem
{
Dout *LedPort;
en_LedState state;
} LedMem;

-------------------------------------------------

こんな風にしておくと、privateなメンバ変数は、Led.c内からしか参照不能になります。
なお、今回は言及しませんが、Doutクラスは自身のメンバ変数にレジスタのアドレスなどをもつドライバとしてのクラスです。
IOレジスタへのアクセスなどは、Doutクラスのメソッドを呼び出すことで実現します。
(こうしておけば、仮にマイコンが変わってもLedクラスはコピペで持ってくるだけで移植できます)

(2)クラスのインスタンスは、staticなグローバル変数として実現
組み込み屋さんは、malloc(C++ならnew)とかそれに付随するヒープ系の呪文を嫌がります。
というか、メモリマップ作る段階でヒープ領域なんか確保しない時もあります。
だって、RAMとか内蔵メモリの128kBとか64kBとか32kBだけで頑張る時も多いから
それっぽちのMP(RAM)じゃヒープ系は使えないんです!
(いや、全然使えるんですけど、メモリ確保失敗とか不安なんですよね)

じゃ、どうするか。
基本的に、メモリは静的に確保する訳です。
無闇にグローバル変数を増やすことはダメって習ったかもしれませんが、きちんと役割のあるオブジェクトとしての存在であれば大丈夫です。そもそも、static宣言してますしね(笑)

-------------------------------------------------

(Utility.h)

/*
* インスタンス生成マクロ
*/
#define INSTANCE_CREATE(ClassName, InstanceName) \
static ClassName InstanceName; \
static ClassName##Mem InstanceName##Mem
-------------------------------------------------
(Led.c)

/*
* ToDo
* クラスのインスタンス化
*/
INSTANCE_CREATE(Led, RedLed);
INSTANCE_CREATE(Led, BlueLed);

-------------------------------------------------

こうしておけば、RedLedとBlueLedおよびそのメンバ変数であるRedLedMemとBlueLedMemのインスタンスが生成されます。

(3)インスタンスの初期化は初期化テーブルで実現
上記まででインスタンスは生成されましたが、メンバ変数のインスタンスを、クラスそのもののインスタンスに紐付ける必要があります。
これは、初期化テーブルと初期化関数を用いて実現します。



-------------------------------------------------


(Led.c)

typedef struct st_LedInstanceTable
{
en_LED_NUM ledNum;
Led *LedInstance;
LedMem *LedMemInstance;
} LedInstanceTable;

static LedInstanceTable ledInstanceTable[] = {
{LED_1, &RedLed, &RedLedMem},
{LED_2, &BlueLed, &BlueLedMem},

{0xff, (Led*) 0, (void*) 0}, //番人
};

/*
* インスタンスの初期化とハンドル取得
*/
Led *initLed(en_LED_NUM n)
{

LedInstanceTable *lt;

//指定されたインスタンスをテーブルから検索
for (lt = ledInstanceTable; lt->LedInstance != (Led*) 0; lt++)
{
if (n == lt->ledNum)
{
break;
}
}

//メンバ変数インスタンスの紐付け
*(LedMem**)&lt->LedInstance->mem = lt->LedMemInstance;

//メンバ変数の初期化
((LedMem*) (lt->LedInstance->mem))->LedPort = initDout(n);
((LedMem*) (lt->LedInstance->mem))->state = LED_OFF;

//メソッドの初期化
lt->LedInstance->on = on;
lt->LedInstance->off = off;
lt->LedInstance->getState = getState;

//インスタンスの初期処理
lt->LedInstance->off(lt->LedInstance);

//インスタンスのアドレスを返す
return lt->LedInstance;

}

/*
* インスタンスのハンドル取得(初期化済みが前提)
*/
Led *getLed(en_LED_NUM n)
{

LedInstanceTable *lt;

for (lt = ledInstanceTable; lt->LedInstance != (Led*) 0; lt++)
{
if (n == lt->ledNum)
{
break;
}
}

return lt->LedInstance;

}

/*
* LEDをオンする
*/
static void on(Led *pLed)
{

((LedMem*) (pLed->mem))->LedPort->write(((LedMem*) (pLed->mem))->LedPort, PORT_HI);
((LedMem*) (pLed->mem))->state = LED_ON;
}

/*
* LEDをオフする
*/
static void off(Led *pLed)
{

((LedMem*) (pLed->mem))->LedPort->write(((LedMem*) (pLed->mem))->LedPort, PORT_LO);
((LedMem*) (pLed->mem))->state = LED_OFF;

}

/*
* LEDの状態を取得する
*/
static en_PortState getState(Led *pLed)
{
return ((LedMem*) (pLed->mem))->state;
}


-------------------------------------------------

(4)インスタンスへのアクセスはアドレス経由で行う
インスタンスはstaticな領域に確保してしまったので、別のオブジェクトから参照できません。
そこで、アドレス取得関数を使用し、他のオブジェクトからはアドレス経由でアクセスします。

-------------------------------------------------

(main.c)

int main(int argc, char** argv) {

Led *l;

initCpu();

l = initLed(LED_1);
l->on(l);

//以下略

}

-------------------------------------------------

以上が大まかな流れです。

こうすれば、例えば黄色のLEDが追加になった場合は、Led.c内で

INSTANCE_CREATE(Led, YellowLed);

とし、初期化テーブルに

static LedInstanceTable ledInstanceTable[] = {
{LED_1, &RedLed, &RedLedMem},
{LED_2, &BlueLed, &BlueLedMem},
{LED_3, &YellowLed, &YellowLedMem},

{0xff, (Led*) 0, (void*) 0},
};


と書いたりすればOKです。
(もちろん、別途レジスタの設定は必要ですが、それはブート時やドライバ層のクラスで行います)

いかがでしたでしょうか??
慣れるまでは大変ですが、このプログラミング法を用いれば、プログラムの設計がやりやすくなります。
CPU性能やリソースが豊富で、かつ、プログラムの規模がある程度大きくなりそうなときは、この様なプログラムを行うと、後々ラクになったりするかもしれません^^

なお、周波数が遅いマイコンではオススメしません。
最適化をどの程度かけるかにもよりますが、このプログラミング技法ではオーバーヘッドが大きくなるため、周波数が遅いと処理時間にクリティカルに影響してきます。
メモリ使用量も大きくなるため、実際に使用する場合は、事前検討を念入りに行う必要がある旨をご留意下さい。


因みに、今回ご紹介したコードは、オブジェクト指向のような雰囲気を出していますが、設計自体は構造化プログラミングです。
つまり、クライアント(main.c)がLedクラスを通じて、Doutクラスを制御するという階層構造ですね。
なぜかというと、冒頭に述べたように、この書き方ではカプセル化は実現できているものの、多態性が実現できていないからです。

実は、この書き方にもう少し工夫を施すと、よりオブジェクト指向の恩恵を預かることが出来るコードになります。
具体的には、変更や拡張に強いコードになります。
例えば、今回は出力ポートをハイにするとLEDがオンされるというソフトを書いていますが、別の回路では、出力ポートをローにした時、LEDがオンという仕様(負論理)になるかもしれません。
あるいは、オン時にいきなり点灯するのではなく、ぼわぁっとゆっくり点灯する仕様になるかもしれません。

ソフトの拡張で大切なことは2つあります。
1つ目は、クライアントが使用するLedクラスのメソッド(関数)を変更せずに、これらの仕様変更に対応すること
2つ目は、ソフト変更を行っても、変更箇所以外には影響しないこと
です。

現実装では、Ledクラスのもつonメソッドは、Doutクラスのもつwriteメソッドに処理を委譲しています。
ここを変更して、wirteメソッドの代わりに、それぞれの仕様に応じた関数を入れてあげればよい訳ですね。
そうすれば、クライアントからは同じようにonメソッドを呼ぶだけで良いし、Ledクラスもonメソッドの委譲先を変えるだけで済みます。新たに委譲先の関数を書く必要がありますが、委譲先として記述した関数は他の関数と独立しているので、互いに影響することが無いようにすれば問題ありません。
この様に、同じonメソッドでも動作を変えることが出来るのがオブジェクト指向であり、この特徴を多態性と呼びます。

具体的なアプローチとしては、デザインパターンの中のストラテジパターンという設計のテンプレートを用います。
ただし、ストラテジパターンはインターフェース(あるいは抽象クラス)を用いて実現することが多いので、C言語では少し工夫が必要です。
次回は、このパターンを用いて、今回のコードを改良したいと思います。

今回はずいぶん長くなってしまいましたが、最後までお読みいいただいて、ありがとうございました!

今年もよろしくお願いいたしますm(_ _)m
こんにちは!
今日は車の1年点検で、近所のホンダさんへ来ているゆってぃです。
点検には3時間程度かかるということなので、今はお店の中からブログを更新しています^ ^

ついに10万PVを達成させていただきました><
皆様、本っっっ当にありがとうございます!!
これからも多くの方にご覧いただけるよう、頑張って書き続けていきたいと思います!

さて、仕事で新規の組み込みソフトウェアを開発することになりました。
新規ですので、最初にしっかりとした設計を行わないと、あとあと苦労することになってしまいます…。
ですので、自分への復習の意味もこめて、組み込みソフトウェアにおけるオブジェクト指向の考え方について、ここで記載したいと思います。

なお、ここで記載する内容は独学+ゆってぃの思い込みによる部分が大きいので、一般的に正しいのかどうか定かではありません。。。
ご参考程度でお願いいたします。m(_ _)m

個人的に、組み込みとオブジェクト指向は、比較的相性がよいと思っています。
なぜなら、組み込みではソフトウェアを利用して、最終的にモーターやLED、センサーといったデバイスを動かすことが多いので、そのデバイスをそのままクラスとして定義することができるからです。

例えば、LEDをPWMで制御する場合を考えましょう。
現実世界にLEDというオブジェクトが存在するので、プログラム中にもLEDクラスが現れます。
なお、僕は「LEDクラス」というクラスは作成せず、これを2つのクラスに分割するようにしています。
具体的には、「LED情報クラス」と「PWM制御クラス」に分割します。

なぜ、LEDクラスをわざわざ2種類のクラスに分割するのでしょうか?
これは組み込みに限定した話ではないですが、ソフトを開発するときには「移植性」という部分を考慮しなければなりません。
特に組み込みにおいては、プロジェクト終了後に、モーターやセンサーといったデバイスが変更になったり、マイコンそのものが変更になる場合があります。
マイコンが変更になった場合、特にベンダーやコアの変更を伴う全く新規のマイコンへの移植となった場合、ハードウェア制御部分が大きく変更になります。
言うまでも無く、レジスタの種類やアドレスは、全く異なるものになるでしょう。

組み込みソフトウェアの開発時には
ハードウェア制御部分(レジスタ制御部分)と制御情報の管理部分を分離
しておけば、そういった変更があってもハードウェア制御部分のみの修正だけで移植が済みます。

んなこと当たり前だろ!オブジェクト指向うんぬん関係なしにやってるわ!
ですよね・・・。すみませんでした・・・。


さて、気を取り直して先ほどのLEDの例に戻りましょう。
先述の通り、レジスタの操作や輝度調整を行うLEDクラスというクラスを作成しても良いのですが、ここではLED情報クラスPWM制御クラスというように、2つのクラスに分けて考えます。

(1)LED情報クラス・・・現在のRGBの輝度情報を持つ。また、上位クラスからLEDを操作するためのメソッドを持つ。
(2)PWM制御クラス・・・レジスタ操作関連のメソッドを持つ。

LED情報クラスは、さらに上位のアプリケーション層(あるいは割り込みハンドラなど)からメッセージを受け取り、それに応じてPWM制御クラスへメッセージを渡します
本クラスのメソッドでは、レジスタ操作は行いません。

PWM制御クラスでは、PWM関連のレジスタの初期化や、オン/オフ。および、周期・DUTY比などのレジスタ操作を行うメソッドを有しています。その代わり、現在の輝度など、LEDの制御情報に関するパラメータ(メンバ)は持ちません。
せいぜい、RGBそれぞれのLEDに対して波形を出力中か否かのフラグを持っている程度です。

こうすることで、移植の時はPWM制御クラスのみ書き換えれば良いことになります。

まぁ、当たり前っちゃ当たり前のことなのですけど、復習の意味も含めて書かせていただきました。

次回は、FM3マイコンを用いて具体的なコードを記述しながら、より詳細な内容をお話したいと思います。

最後までお読みいただいて、ありがとうございました!(感謝)

こんばんは!
念願のビデオカメラをゲットしたゆってぃです!

いやぁ、これであらゆるイベント事をガシガシ記録できますね!
これで結婚式の二次会で使うムービーもバッチリです。
結婚の予定は全くありませんが、、、(涙)


さて、今日はMFCプログラミングで、自分のアプリから別のアプリを呼び出す方法です。
これが出来ると、他人の作ったアプリを使って色々なことが出来るようになりますので
なんだか一気にレベルアップした気になります(笑)

MFCで別プロセスを起動させる手段は、大きく分けて3つあります。
system関数
ShellExecute関数
CreateProcess関数
です。

なお、system関数は標準Cライブラリの関数ですので、Windows以外のプラットフォームでも呼び出せます。
(ただし、実行可能かどうかは処理系によります)
非常にシンプルで使いやすいので、linux環境などで使用したことがある人も多いのではないでしょうか?

僕はよくShellExecute関数を使うので、今日はこの使用方法を説明します。
機能が拡張されたShellExecuteEx関数というのもありますが、今回はShellExecuteに焦点を当てて説明します。
あと、環境はWindows XP SP3(今時…)、Windows Visual Studio 2010 professional です。

さて、MSDNを見ると、インターフェースは


HINSTANCE ShellExecute(
HWND hwnd, // 親ウィンドウのハンドル
LPCTSTR lpVerb, // 操作
LPCTSTR lpFile, // 操作対象のファイル
LPCTSTR lpParameters, // 操作のパラメータ
LPCTSTR lpDirectory, // 既定のディレクトリ
INT nShowCmd // 表示状態
);


となっております。
それでは、それぞれの引数について書いていきます。

まず、hWndですが、ここには親ウィンドウハンドルを入れます。
ウィンドウハンドルを取得したい場合は、MFCなら(CWNDクラスの拡張クラスからであれば)GetSafeHwndで取得可能です。
ネイティブなWin32APIでゴリゴリ書くときはCreateWindow実行時に取得できますが、MFCではウィンドウはすでに存在しているものですからね(笑)
あ、自分自身が親ダイアログの場合はNULLで大丈夫です。

次のlpVerbは、これから実行するプロセスにどんな操作を行うかを、文字列として渡します。
今回は実行可能ファイルなので、_T("open")としましょう。

次のlpFileは、実行するファイル名を入れます。
なお、ここには実行ファイルのパスを文字列として入れますが、
lpDirectoryNULLを入れた場合は、絶対パスを。
特定のパスを入れた場合は、そこからの相対パスを文字列として入れます。

次のlpParametersは、実行ファイルに引数として渡す文字列です。
例えば、起動するプロセスがコンソールアプリケーションであった場合などは、コマンドライン引数を入れます。
これも文字列です。

次のlpDirectoryは前述の通りですね。
例えば、作成中のメインアプリと、そこから呼び出すサブプロセス(xxx.exeなど)が必ず同じディレクトリにあることが前提なら、ここに現在のディレクトリのパスを取得して入れれば便利です。

最後のnShowCmdには、アプリケーションの表示方法を指示するフラグを指定します。
詳細はMSDNをご参照ください。

関数が成功すると、32 より大きい値が返りますので、戻り値は必ず確認しましょう。

ちなみに、ShellExecute関数を実行すると、その終了を待たずに次へ進んでしまいます。
終了を待ちたい場合は、CreateProcess()を使用してプロセスのハンドルを取得し、WaitForSingleObject()と組み合わせて終了を待ちましょう。

さて!今日はここまでです!
(それにしても、最近、どんどん組み込みから遠ざかっていますね><)

以上、最後までお読みいただいて、ありがとうございました(感謝)
こんばんは!
帰宅したら、にゃんこ達がラグの上に盛大にお醤油をこぼしていて、ちょっとショッキングなゆってぃです。
洗って落ちるとかいう生ぬるいレベルの範囲ではなかったので、泣く泣く処分を決めました。

でもね、これは

テーブルの上に醤油を置いておいた僕がいけないんです。

ちゃんとフタは閉めてたのですが、にゃんこは何が起こすかわからないので…(涙)

まだ買って数ヶ月しか経ってないのになぁ(T_T)



さて、今日は昨日のVISAの続きです。
というほど書く内容もないのですが、大まかな使い方はわかりました。

基本的には
<接続> → <通信> → <接続終了>
という流れのようです。

それでは、さっそくひとつひとつ見ていきましょう。

<接続>
viOpenDefaultRM()関数でVISAシステムを起動し、viOpen()関数で接続を確立します。
この時、viOpen()の引数として、測定器を特定するためのアドレス情報などを渡します。
その後、viSetAttribute()関数で接続の属性を決めます。タイムアウトなどもここで設定します。


<通信>
接続が完了したら、viPrintf()関数で、測定器にコマンド(クエリ)を投げます。
文字列は通常のprintf()フォーマットで記述します。
これらのコマンドはSCPI(スキッピー)と呼ばれるコマンドセットに定義されており、測定器の機種に関係なく送ることが出来るコモン部分のコマンドと、機器別のコマンドに分かれています。
機種別のコマンドは、各測定機器のヘルプをご参照ください。

なお、SCPIに関する概要はwikipediaに書かれていますので、合わせてご参照ください。
SCPIとは(英語)
IEEE488(SCPIのみに関する説明ではないですが、日本語)

また、投げるコマンドの最後に"?"を付けた場合は、機器が該当するデータを応答として返します。
(※全てのコマンドに応答するわけではありません。?が付けられるコマンドを知るには、接続機種のヘルプをご覧下さい。)
例えば、ある測定値の最大値を知りたい場合などに用います。
なお、この応答を受け取る際には、viScanf()関数を使用します。
このフォーマットも、scanf()関数と同じですので、簡単に使用することが出来ます。

つまり、viScanf()を使用する前には、必ずviPrintf(io, "xxx?")のように、問い合わせを行う必要があります。
もし、応答がこない場合(正しい問い合わせコマンドが投げられていない場合)は、viSetAttribute()関数で指定した時間だけ待ち、その後はエラーとして先に進みます。

<接続終了>
通信が終わったら、viClose()関数を用いて、接続を解放することを忘れずに!

以上が、VISAライブラリを用いた測定器のリモートコントロール方法です。
実際に組んでいただければわかりますが、驚くほど簡単に、PCから測定器を操作することが出来ます。
ログ取りも簡単に出来るし、開発段階でも大いに役立ってくれそうです^^

最後までお読みいただいて、ありがとうございました!(感謝)
ご訪問者様
プロフィール

ゆってぃ

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

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

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

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

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

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