PIC16F1455はわずか14ピンでUSB2.0通信を実現する8ビットマイコンで、48Mhzで動作可能な為、非常に扱っていて楽しい。
USB駆動に割り込みもいらんし、こりゃええです。

何とかHID通信が出来る様になったので、これから色々と楽しいものが作れそう。
簡易オシロスコープみたいなものも出来た。
本当に簡易なんで、そのうちちゃんと作りたい。

PIC16F1455はマイクロチップ製PICマイコンの内、拡張ミッドレンジアーキテクチャ製品群にあたる。

 pic
よく使っている製品番号PIC12F1822とアーキテクチャはほぼ同じ。
なので、大部分のコードは流用できる。
今回CDIをPIC12F1822からPIC16F1455へ移植するのは存外簡単。
なので日本語版のPIC12F1822のマニュアルは結構助かる。
 
さて、、、1455に移植するにあたって、変更した点は2点だけ。

1.USB対応
2.8MHz->16MHz化

USB対応は主たる目的だったけど、16MHz化は今回初めて。
もともと8MHzが上限のPIC12F863からスタートしているので8MHzで作っていただけで、今回はUSB処理とかもあり、少し余裕を持たせる為、ちょっと早くしてみる。
周波数をあげるとリスクも高まるんだけど、USB対応の溜めに48MHz上限となった1455なら16MHzは余裕ちゃうかな〜という算段。

その他の変更も色々と検討していて、点火時期のタイミングをあらかじめ全てPIC内部に持つ様なCDI一作目の実装も再現してみた。
コンパイルすると、残り2バイトという、えらく余裕のないものになったので、これはやめ。
ide
 
結局基本的な実装はほとんど変わらず。

本題。
PIC16F1455が持つ内部タイマーは8ビットのTimer0,2 と 16ビットのTimer1。
このうちTimer1はエンジンの回転数を計算するのにどうしても必要。
16ビットのタイマーが二つあれば良いのだけれども、ないので8ビットタイマーでなんとか考えないといけない。

移植に当たってTimer2の計算方法を思い出すのに時間が掛かったので、自分の為に解説。

SDRのピックアップ信号は、ピストン上死点よりも70度前に来る。
このピックアップ信号を起点として、ある一定の時間後にプラグに点火するのが基本的な仕組み。
例えば上死点から20度前、つまりB.T.D.C.20度に点火させようとすると、ピックアップ信号から50度進んだところで点火させる。
この50度分の時間をTimer2で実現する。

Timer2は8ビットタイマーだけれども、実質14ビットタイマーであり、2ビットのプリスケーラーと2ビットのポストスケーラーによって最長16ビット分のカウントを実現する。
timer2
 
プリスケーラーは1:1、1:4、1:16、ポストスケーラーは1:1〜1:16となる。
例えばTimer2のカウントアップ値xは以下の通り。
x = prescaler * PR2 * postscaler = {1:1/1:4/1:16} * {1..255} * {1:1...1:16}

仮にx = 9,300だったとすると、上記3つの値を組み合わせてこの9,300の近似値を作る必要がある。 
その計算をVisualStudio2010Expressで記述してみたのが以下。
説明よりもコードが一番。


[コードを表示する]
#include "stdafx.h"
#include 
using namespace std;

// 1,000rpm時の1度のカウント=666.67(16Mhz Fosc/4)
#define COUNT_OF_1DEG	667 //*10
// ピックアップ信号は70度前に来る
#define PICKUP_DEG		70
// 割り込み処理等の時間がかかるので事前に差っ引く分
#define COUNT_OF_TUNE	1400

int _tmain(int argc, _TCHAR* argv[])
{
	int	in_deg;
	int	in_rpm;

	unsigned short pre_degree;
	unsigned short pre_count;
	unsigned short prescaler;
	unsigned short postscaler;
	unsigned short pr2;
	unsigned short result;
	unsigned short xx;
	while(1){
		cout << "input degree>";
		cin >> in_deg;
		cout << "input rpm(x100)>";
		cin >> in_rpm;

		// 70度前のピックアップ信号からの時間を作成
		pre_degree = PICKUP_DEG - in_deg;
		pre_count = ((pre_degree * COUNT_OF_1DEG * 10) / in_rpm) ;
		cout << "pre_count:" << pre_count << "\n";

		// PIC Timer2 の値を作成
		// Timer2はカウント値 Prescaler * PR2 * Postscaler でTimeup 
		// PR2:        {0 ... 255}
		// Prescaler:  {1:1/1:4/1:16}
		// Postscaler: {1:1 ... 1:16}
	
		// prescalerを算出
		xx = pre_count/256;
		if     ((xx/ 1) < 16) prescaler = 1;
		else if((xx/ 4) < 16) prescaler = 4;
		else if((xx/16) < 16) prescaler = 16;
		else {cout << "error";goto error_exit;}

		// postscalerを算出
		postscaler = pre_count/256/prescaler + 1;

		// pr2の算出
		pr2 = pre_count / prescaler / postscaler;
		result = prescaler * pr2 * postscaler - COUNT_OF_TUNE;
		printf( "pre:%d post:%d pr2:%d total:%d result:%d \n"
			, prescaler, postscaler, pr2, prescaler * pr2 * postscaler, result );
	}
error_exit:
	cin >> xx;
	return 0;
}