備忘録
SDR:もろもろと、島田優選手のタコメータの改善
の続き

島田優さんに取り付けているタコメーターは、自作のステッピングモーター式。
パルス感知をIGコイル1次側のマイナス電圧で行う3XV感知式。
これをCDIから直接信号を取る形にした。

単純にPICマイコンの線を繋いだだけでやってみたところ、タコメータの針が暴れるとのこと。
その動画がこちら。



確かに高回転で針が振れている気がする。
SS Killersまで時間がないので、とりあえずこんなのを作ってみた。
c1
浮け側(タコ側)で単純に電圧を半分にしただけ。

ノイズはパルス回路を使った机上では発生せず、実機上で発生。
iPhone 001

つまりCDIの高電圧がノイズ発生元なんだろうと想定。
なるべく受け側にこの分電回路を入れて、ノイズを拾っても半分以下にして感知しない様にした。

PICの出力側は5Vなので、半分で2.5V。
受け側はPIC12F1822でInputCaptureを使っていて、シュミットトリガ回路が使われる。
なので2.0Vあれば良い感じ。
ノイズが2.0Vに届かなければ良いので、半分にすれば丁度ええのとちゃう?的な発想。

結果はこちらで紹介したSS Killers2015 R3の結果の通り。
ちゃんと動いています。
SS Killers 2015R3 NSR250とタメで走るSDR200(1/2)


さて、この結果を受けてボウズさんから預かっているRS125用タコメータの話。
このタコメータは、12Vのオンオフ信号で動作することが分かってる。
つまり多くのトランジスタ点火方式の車体でも動作することになりますね。

RS125のCDIは12Vのオンオフ信号を出していてそれで動作させている訳なので、自作CDIからも12Vオンオフを出力すればよい訳です。

先ほどとは違って、なるべく出力側、つまりCDI側に寄せて作るのがエエのですが、、、
iPhone 002

タコメータ側につけました。
回路はこんな感じ。

c2

前回作ったものをやり直してます。
まぁつまりもう少しちゃんと作った。
iPhone 065

ちょっとしたノイズでも2SC1805トランジスタでで増幅されてしまうので、ツェナーを装着。
こんくらいやっといても良いだろう。

一応波形をとってみたけど、上手い具合に出来てると思う。
IMAG001
 
12000回転まで実験したけど問題なし。
これでアカンかったらどうすっぺかなと。

ボウズさんとりあえずこれで試してみて。 


あと、CDIは少々変更が必要。
RC0ポートに電線一本。
メインソースコードを以下の物に取替え。
パルスをオンオフしているだけ。



[コードを表示する]
/* ----------------------------------------------------------------------------
  USB CDI system for YAMAHA SDR200
  Copyright (C) 2015 Rilassaru (http://rilassaru.blog.jp/)
  ----------------------------------------------------------------------------
  RCDI is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  For details, see sections 7, 8, and 9
  of the Apache License, version 2.0 which apply to this file.  If you have
  purchased a commercial license for this software from this software,
  your commerical license superceeds the information in this header.
 
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
  DEALINGS IN THE SOFTWARE.
---------------------------------------------------------------------------- */

//------------------------------------------------------------------
// PIN layout
//------------------------------------------------------------------
/*         PIC16F1455
           |VDD  VSS|
SCR GATE<< |RA5   D+| <> USB+(RA0)
PULSE IN>> |RA4   D-| <> USB-(RA1)
RESET   >> |RA3 Vusb| <> Vusb(RA2)
YPVS+   << |RC5  RC0| >> PULSE OUT
YPCS-   << |RC4  RC1| >> LED
YPVS POT>> |RC3  RC2| << SW1
*/

#include "usb.h"
#include "HardwareProfile.h"
#include "userinterface.h"
#include "constant.h"

#define _XTAL_FREQ 16000000

#define mPULSE_OUT		LATC0
#define mLED			LATC1
#define mSW1			RC2
#define mYPVSA		LATC4
#define mYPVSB		LATC5
#define mRESET		RA3
#define mPULSE_IN		RA4
#define mGATE			LATA5

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#ifdef __DEBUG
#pragma config PWRTE = OFF       // Power-up Timer Enable (PWRT enabled)
#else
#pragma config PWRTE = ON       // Power-up Timer Enable (PWRT enabled)
#endif
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF       // Internal/External Switchover Mode (Internal/External Switchover Mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)

// CONFIG2
#pragma config USBLSCLK = 48MHz // USB Low SPeed Clock Selection bit (System clock expects 48 MHz, FS/LS USB CLKENs divide-by is set to 8.)
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config CPUDIV = CLKDIV3 // CPU System Clock Selection Bit (CPU system clock divided by 3)
#pragma config PLLMULT = 3x     // PLL Multipler Selection Bit (3x Output Frequency Selected)
#pragma config PLLEN = ENABLED  // PLL Enable Bit (3x or 4x PLL Enabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
// -------------------------------------------------------
// Motor state
typedef enum{
	MT_OPEN,
	MT_CLOSE,
	MT_STOP,
	MT_BRAKE
}MOTOR_STATE;

// YPVS state
typedef enum{
	YPVS_ACTIVE = 0,	// Engine started
	YPVS_INIT_OPEN1,	// Open at first
	YPVS_INIT_CLOSE,	// Close after open
	YPVS_INIT_OPEN2	// Reopen after close
}YPVS_STATE;

/** -----------------------------------------------------------------
CDI definition
------------------------------------------------------------------ */
#define MIN_RPM			10
#define MAX_RPM			150
#define SCR_GATE_ON_TIME	300		// SCR open time(us)
#define SCR_GATE_ON		1
#define SCR_GATE_OFF		0

/** -----------------------------------------------------------------
YPVS definition
------------------------------------------------------------------ */
#define NR_DATA_NUM 5	// Data size of NoiseReduction
#define NR_TRIGGER 8	// Range to determine the electrical noise (Decide for actual measurement) 

#define YPVS_INIT_OPEN_VALUE	123	// 0x7B
#define YPVS_INIT_CLOSE_VALUE	55	// 

#define MT_BRAKE()	{mYPVSA=1;mYPVSB=1;}
#define MT_OPEN()	{mYPVSA=1;mYPVSB=0;}
#define MT_CLOSE()	{mYPVSA=0;mYPVSB=1;}
#define MT_STOP()	{mYPVSA=0;mYPVSB=0;}

#define ENGINE_STOP_SC		8000	// Count to determine engine stop
#define ENGINE_START_SC	4000	// Count to determine engine start

//------------------------------------------------------------------
//proto type
//------------------------------------------------------------------
void main(void);
void initialize_system(void);
void interrupt ISRCode();
uint8_t ypvs_leveled_analog_data(uint8_t pot);
void ypvs_motor_head(uint16_t rpm, uint8_t pot);


/** -----------------------------------------------------------------
 global variable
------------------------------------------------------------------ */
uint16_t	gRPM = 0;
uint8_t	gEngineStop = TRUE;
uint8_t 	gSW1 = 0;

/** -----------------------------------------------------------------
 main loop
 
------------------------------------------------------------------ */
void main(void) {
	int ii;
	initialize_system();
	// Initialieze pot data
	for(ii = 0; ii < NR_DATA_NUM; ii++) {
		GO = 1;
		while(GO);
		ypvs_leveled_analog_data(ADRESH);
		CLRWDT();
	}
	// Initialize interrupt setting
	IOCAP4	= 1;
	TMR1IE	= 1;		// Timer1 intterupt on
	TMR2IE	= 1;		// Timer2 intterupt on
	TMR1ON	= 1;		// Timer1 start
	IOCIE	= 1;		// IOC on
	PEIE		= 1;
	GIE		= 1;

	ypvs_motor_head(gRPM, ypvs_leveled_analog_data(ADRESH));
	while (1) {
		usb_device_tasks();
		hid_user_interface();

		GO = 1;
		while(GO);
		ypvs_motor_head(gRPM, ypvs_leveled_analog_data(ADRESH));
		
		mLED = mSW1;
		status.g.sw1 =  mSW1;
		gSW1 = mSW1;
		ClrWdt();
	}
}


/** -----------------------------------------------------------------
void interrupt ISRCode()

------------------------------------------------------------------ */
void interrupt ISRCode() {
	uint16_t ccpr1;
	
	// Interrupt from Input capture
	if(IOCAF) {
		if( mPULSE_IN )
		{ // This ioc has rising edge.

			ccpr1 = ((TMR1H << 8)|TMR1L) + 1;

			TMR1H = 0;
			TMR1L = 0;
			// RPM
			gRPM  = (uint16_t)(600000UL/ccpr1) + 1;
			if((MAX_RPM >= gRPM) && (gRPM >= MIN_RPM)) {
				PR2   = (gIGtbl[gSW1][gRPM] & 0x00FF);
				T2CON = (gIGtbl[gSW1][gRPM] >> 8);
				mGATE = SCR_GATE_OFF;
				mPULSE_OUT = 1;
			} else {
				TMR2ON = 0;
			}
		}
		IOCAF = 0;
	}

	// Timer1: Timeout means engine stop
	if(TMR1IF) {
		gEngineStop = TRUE;
		gRPM = 0;
		// Reset intterupt
		TMR1IF = 0;
	}

	// Timer2: SCR gate open
	if(TMR2IF) {
		// Stop Timer2
		TMR2ON = 0;

		if(!gEngineStop) {
			// IGNITE PLUG
			mGATE = SCR_GATE_ON;
			__delay_us(SCR_GATE_ON_TIME);
			mGATE = SCR_GATE_OFF;
		}
		gEngineStop = FALSE;
		mPULSE_OUT = 0;

		// Reset intterupt
		TMR2IF = 0;

	}


	// For usb report
	status.g.timer1	= gIGtbl[gSW1][gRPM];
	status.g.rpm		= gRPM;
	status.g.e_stop	= gEngineStop;
}

/** -----------------------------------------------------------------
  unsigned int ypvs_leveled_analog_dat(uint8_t pot)
  
------------------------------------------------------------------ */
uint8_t ypvs_leveled_analog_data(uint8_t pot)
{
	static uint8_t pots[NR_DATA_NUM] = {0};
	uint16_t ave;
	int ii;
	
	ave = pots[NR_DATA_NUM-1];
	for(ii = (NR_DATA_NUM-1); ii > 0; ii--) {
		pots[ii] = pots[ii-1];
		ave += pots[ii];
	}
		
	ave /= NR_DATA_NUM;
	pots[0] = pot;

	if((pot > ave+NR_TRIGGER) || (ave-NR_TRIGGER > pot)) {
		return ave;
	}
	return pot;
}

/** -----------------------------------------------------------------
  void ypvs_motor_head()

------------------------------------------------------------------ */
void ypvs_motor_head(uint16_t rpm, uint8_t pot)
{
	static uint16_t engine_mode_change_count = 0;
	static uint8_t ypvs_mode = YPVS_INIT_OPEN1;
	static uint8_t motor_state = MT_BRAKE;
	uint8_t target = 0;
	uint8_t pot_buf = 2;	// 

	if(MIN_RPM > rpm) {rpm = MIN_RPM;}
	if(rpm > MAX_RPM)	{rpm = MAX_RPM;}


	// Engine schmitt trigger
	if((FALSE == gEngineStop) && (ypvs_mode != YPVS_ACTIVE)){
		if(engine_mode_change_count++ > ENGINE_START_SC) {
			ypvs_mode = YPVS_ACTIVE;
			engine_mode_change_count = 0;
		}
	}
	if((TRUE == gEngineStop) && (ypvs_mode == YPVS_ACTIVE)){
		if(engine_mode_change_count++ > ENGINE_STOP_SC) {
			ypvs_mode = YPVS_INIT_OPEN1;
			engine_mode_change_count = 0;
		}
	}

	// YPVS state machine
	switch(ypvs_mode) {
		case YPVS_ACTIVE: {
			target = gPVtbl[gSW1][rpm];
			break;
		}	
	
		case YPVS_INIT_OPEN1: {
			target =YPVS_INIT_OPEN_VALUE;
			if(target - pot_buf <= pot) {
				ypvs_mode = YPVS_INIT_CLOSE;
			}
			break;
		}	
	
		case YPVS_INIT_CLOSE: {
			target = YPVS_INIT_CLOSE_VALUE;
			if(target + pot_buf >= pot) {
				ypvs_mode = YPVS_INIT_OPEN2;
			}
			break;
		}	
		
		case YPVS_INIT_OPEN2: {
			target = YPVS_INIT_OPEN_VALUE;
			break;
		}
	}


	// Motor state
	if(target > (pot + pot_buf)) {
		if( MT_CLOSE == motor_state ) {
			// Blank of 100us need when reverse the motor.
			MT_STOP();
			__delay_us(120);
		}	
		motor_state = MT_OPEN;

	} else if(target < (pot - pot_buf)) {
		if( MT_OPEN == motor_state ){
			MT_STOP();
			__delay_us(120);
		}	
		motor_state = MT_CLOSE;
	} else {
		motor_state = MT_BRAKE;
	}

	// Drive motor
	switch(motor_state) {
		case MT_OPEN:		{MT_OPEN();	break;}
		case MT_CLOSE:	{MT_CLOSE();	break;}
		case MT_BRAKE:	{MT_BRAKE();	break;}
		case MT_STOP:		{MT_STOP();	break;}
		default:			{MT_BRAKE();	break;}
	}
	status.g.pv_pot = pot;
	status.g.pv_target = target;
	status.g.pv_mode = ypvs_mode;
}

/** -----------------------------------------------------------------
------------------------------------------------------------------ */
void initialize_system(void) {
	OSCCON = 0xFC; //3x PLL enabled from 16MHz HFINTOSC (1111 1100)
	ACTCON = 0x90; //Enable active clock tuning from USB
	while (OSCSTATbits.PLLRDY == 0); //Wait for PLL ready/locked
	WDTCONbits.WDTPS = 0b01100; //~2 second timeout

	UserInit();
	usb_device_init();
	
	WPUA		= 0b00000000;
	TRISA	= 0b00010000;	// RA4 is input/RA5 is output
	ANSELA	= 0b00000000;	// Disable all RAx analog input
	PORTA	= 0b00000000;	// Reset PORTA

	TRISC	= 0b00001100;	// RC2,3 are input/0,1,4,5 are output
	ANSELC	= 0b00001000;	// RC3(AN7) as Analog input
	PORTC	= 0b00000000;	// Reset PORTC

	ADCON2	= 0x0;		//  No auto-conversion trigger selected
	ADCON1	= 0b00100000;	// Clock:Fosc/32, VREF+ is VDD
	ADCON0	= 0b00011101;	// AN7 selected
	
	mLED = 0;

	// Timer1 setteing
	T1CONbits.TMR1CS =0;		// 00 = Timer1 clock source is instruction clock (FOSC/4)
	T1CONbits.T1CKPS =0b10;	// Timer1 Input Clock Prescale Select bits 1:4 Prescale value
	T1CONbits.T1OSCEN=0;		// Dedicated Timer1 oscillator circuit disabled
	T1CONbits.nT1SYNC=1;		// 1 = Do not synchronize external clock input
	T1CONbits.TMR1ON =0;		// Timer1 On bit

	// Timer2 setting
	T2CON	= 0;
	PR2		= 0;
	TMR2IF	= 0;

	// Interrupt on change setting
	IOCAP	= 0;
	IOCAN	= 0;
	IOCAF	= 0;


}

/** EOF main.c ***************************************************************/