4Motus DIY Überbike Part3

Zusammenbau Teil 3

So nach zwei kleinen “Zwangspausen” (=kaputter Controller/einige malträtierte Gliedmassen und ein gebrochener Daumen) kommt mal wieder ein Update – wahrscheinlich das Zweitletzte 😉

Um das Gesamtbild des Bikes ein wenig zu verbessern, habe ich mich dazu entschieden, die Feder, die Pedalen sowie den Lenker udn den Vorbau ebenfalls zu Pulvern.

20141025_143611

20141025_143638

Ein 23mm grosses Loch mit dem Schälbohrer zu bohren ist, gar nicht mal so einfach. Es hat schlussendlich aber doch geklappt. Später wird darin ein Neutrik Speakon als Ladeport hausen.20140915_200608

Keine Ahnung wie viele Meter Kabel in der Box verstaut werden, auf jeden Fall sind es einige.20141015_220434

Ready zur Testfahrt. Auf der Seite hängt ein Greentime Controller, den ich zum Test angehängt habe. Das Bike funktionierte mehr oder weniger gut, man merkt jedoch, dass die interne Regelung nicht wirklich gut ist. Das Motorgeräusch ist sehr deutlich hörbar und der Motor stottert ganz leicht bei hohen und sehr tiefen Geschwindigkeiten. Dummerweise drehte der Motor bei gleichem Phasen- und Hallsensor-Anschluss  rückwärts und nicht vorwärts wie beim Sabvoton Controller. Das habe ich auch gleich zu spüren bekommen, als sich die Pedale in meinem Knie vergraben hat. Naja, die Freude über die Funktion war natürlich grösser als der Schmerz und so konnte ich eine kurze Testfahrt machen. Es geht schon gut ab, aber ist noch sehr gut handlebar.20141031_191229

Der Gasgriff-Controller: Das Bike kann nun mit einem RFID Tag ensperrt werden. Es gibt 3 Modi: Nach dem Einschalten kann das Bike nur mit den Pedalen gefahren werden. Der Gasgriff ist nutzlos. Modus 2: Mit einem RFID Tag kann das Bike in den strassenlegalen Modus geschaltet werden. Die Leistung wird dabei auf ca. 1kW und die Geschwindigkeit auf 45km/h beschränkt. Modus 3: Das Bike ist komplett entsperrt.

Ebenso ist es möglich die Rekuperation stufenlos einzustellen. Wenn man die Bremse zieht, stellt der Controller auf Rekuperation um. Der Gasgriff fungiert dann als Bremsgriff. Eine Sicherheitsfunktion muss jedoch noch implementiert werden: Wenn beim Bremsen der Gasgriff voll auf ist und die Bremse wieder losgelassen wird, muss der Gasgriff zuerst in die Nullstellung gebracht werden, bevor er wieder als Gasgriff fungieren kann. So wird vermieden, dass versehentlich vollgas gegeben werden kann, wenn die Bremse gelöst wird. Ev. kann auf dieses Feature verzichtet werden, wenn die Stromrampe im Controller genügend lange ist.

Nachtrag: Es reicht, die Drehmomentrampe im Controller auf 1800ms zu stellen. Die Rampe fühlt sich so an, als würde sie exponentionell ansteigen und dann in die Sättigung gehen. Die Leistung kann auch so bei niedrigen Drehzahlen sehr gut dosiert werden.

/*
4motus überbike throttle and brake controller
Created by chuleo



 */

#include <SPI.h>
#define	uchar	unsigned char
#define	uint	unsigned int

//data array maxium length
#define MAX_LEN 16

/////////////////////////////////////////////////////////////////////
//set the pin
/////////////////////////////////////////////////////////////////////
const int chipSelectPin = 10;
const int NRSTPD = 5;


int sensorPin = A0;    // select the input pin for the potentiometer
int ledPin = 13;      // select the pin for the LED
int outPin = 5;
int brakeOut = 6;
int brakeIn = 2;
int speedLim = 7;
int sensorValue = 0;  // variable to store the value coming from the sensor
int brakeVal;

//MF522 command bits
#define PCD_IDLE              0x00               //NO action; cancel current commands
#define PCD_AUTHENT           0x0E               //verify password key
#define PCD_RECEIVE           0x08               //receive data
#define PCD_TRANSMIT          0x04               //send data
#define PCD_TRANSCEIVE        0x0C               //send and receive data
#define PCD_RESETPHASE        0x0F               //reset
#define PCD_CALCCRC           0x03               //CRC check and caculation

//Mifare_One card command bits
#define PICC_REQIDL           0x26               //Search the cards that not into sleep mode in the antenna area 
#define PICC_REQALL           0x52               //Search all the cards in the antenna area
#define PICC_ANTICOLL         0x93               //prevent conflict
#define PICC_SElECTTAG        0x93               //select card
#define PICC_AUTHENT1A        0x60               //verify A password key
#define PICC_AUTHENT1B        0x61               //verify B password key
#define PICC_READ             0x30               //read 
#define PICC_WRITE            0xA0               //write
#define PICC_DECREMENT        0xC0               //deduct value
#define PICC_INCREMENT        0xC1               //charge up value
#define PICC_RESTORE          0xC2               //Restore data into buffer
#define PICC_TRANSFER         0xB0               //Save data into buffer
#define PICC_HALT             0x50               //sleep mode


//THe mistake code that return when communicate with MF522
#define MI_OK                 0
#define MI_NOTAGERR           1
#define MI_ERR                2


//------------------MFRC522 register ---------------
//Page 0:Command and Status
#define     Reserved00            0x00    
#define     CommandReg            0x01    
#define     CommIEnReg            0x02    
#define     DivlEnReg             0x03    
#define     CommIrqReg            0x04    
#define     DivIrqReg             0x05
#define     ErrorReg              0x06    
#define     Status1Reg            0x07    
#define     Status2Reg            0x08    
#define     FIFODataReg           0x09
#define     FIFOLevelReg          0x0A
#define     WaterLevelReg         0x0B
#define     ControlReg            0x0C
#define     BitFramingReg         0x0D
#define     CollReg               0x0E
#define     Reserved01            0x0F
//Page 1:Command     
#define     Reserved10            0x10
#define     ModeReg               0x11
#define     TxModeReg             0x12
#define     RxModeReg             0x13
#define     TxControlReg          0x14
#define     TxAutoReg             0x15
#define     TxSelReg              0x16
#define     RxSelReg              0x17
#define     RxThresholdReg        0x18
#define     DemodReg              0x19
#define     Reserved11            0x1A
#define     Reserved12            0x1B
#define     MifareReg             0x1C
#define     Reserved13            0x1D
#define     Reserved14            0x1E
#define     SerialSpeedReg        0x1F
//Page 2:CFG    
#define     Reserved20            0x20  
#define     CRCResultRegM         0x21
#define     CRCResultRegL         0x22
#define     Reserved21            0x23
#define     ModWidthReg           0x24
#define     Reserved22            0x25
#define     RFCfgReg              0x26
#define     GsNReg                0x27
#define     CWGsPReg	          0x28
#define     ModGsPReg             0x29
#define     TModeReg              0x2A
#define     TPrescalerReg         0x2B
#define     TReloadRegH           0x2C
#define     TReloadRegL           0x2D
#define     TCounterValueRegH     0x2E
#define     TCounterValueRegL     0x2F
//Page 3:TestRegister     
#define     Reserved30            0x30
#define     TestSel1Reg           0x31
#define     TestSel2Reg           0x32
#define     TestPinEnReg          0x33
#define     TestPinValueReg       0x34
#define     TestBusReg            0x35
#define     AutoTestReg           0x36
#define     VersionReg            0x37
#define     AnalogTestReg         0x38
#define     TestDAC1Reg           0x39  
#define     TestDAC2Reg           0x3A   
#define     TestADCReg            0x3B   
#define     Reserved31            0x3C   
#define     Reserved32            0x3D   
#define     Reserved33            0x3E   
#define     Reserved34			  0x3F
//-----------------------------------------------

//4 bytes Serial number of card, the 5 bytes is verfiy bytes
uchar serNum[5];
static int unlocked = 2;
static int maxpower = 100;

int throttle_pin = 0;
int throttle_val;


//buffer A password, 16 buffer, the passowrd of every buffer is 6 byte 
 uchar sectorKeyA[16][16] = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                             {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                             //{0x19, 0x84, 0x07, 0x15, 0x76, 0x14},
                             {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                            };
 uchar sectorNewKeyA[16][16] = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                                {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xff,0x07,0x80,0x69, 0x19,0x84,0x07,0x15,0x76,0x14},
                                 //you can set another ket , such as  " 0x19, 0x84, 0x07, 0x15, 0x76, 0x14 "
                                 //{0x19, 0x84, 0x07, 0x15, 0x76, 0x14, 0xff,0x07,0x80,0x69, 0x19,0x84,0x07,0x15,0x76,0x14},
                                 // but when loop, please set the  sectorKeyA, the same key, so that RFID module can read the card
                                {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xff,0x07,0x80,0x69, 0x19,0x33,0x07,0x15,0x34,0x14},
                               };


void setup() {

  
  pinMode(chipSelectPin,OUTPUT);             // Set digital pin 10 as OUTPUT to connect it to the RFID /ENABLE pin 
  pinMode(ledPin, OUTPUT);
  pinMode(outPin, OUTPUT);
  pinMode(brakeOut, OUTPUT);
  pinMode(brakeIn, INPUT);
  pinMode(speedLim, OUTPUT);
  
  digitalWrite(chipSelectPin, LOW);        // Activate the RFID reader
  digitalWrite(NRSTPD, HIGH);
  digitalWrite(speedLim, HIGH);       //Speedlimit is deactivated by default
  
  //brakeVal=digitalRead(brakeIn);
  
  Serial.begin(9600);                       // RFID reader SOUT pin connected to Serial RX pin at 9600bps 
  SPI.begin(); 
  setPwmFrequency(5, 1);                //set pwm frequency to 62khz (output needs less filtering with a high pwm freq.)
  MFRC522_Init();  
}

void loop() {         
        uchar i,tmp;
	uchar status;
        uchar str[MAX_LEN];
        uchar RC_size;
        uchar blockAddr;	//Select operation buck address  0 - 63
        String mynum = "";
        int breaking;

        sensorValue=analogRead(sensorPin)/4; //throttle input. if unlocked = 0 then max throttle out= maxpower
        breaking=map(sensorValue,0,256,48,208);  //breaking begins at approx. 1.5V -> needs an offset. 
                                                  //if breaking is 5V it will stop breaking (detects hardware fault)
        
        if(unlocked==0){                        //if unlocked=1 then max speed = throttle
          if((sensorValue)<=maxpower){
          analogWrite(outPin,sensorValue);
          analogWrite(brakeOut,breaking);    
          }
          else{
          analogWrite(outPin,maxpower);
          analogWrite(brakeOut,breaking);  //max braking power should be the same at any time
          }
        }
        else if(unlocked==1){
          analogWrite(outPin,sensorValue);
          analogWrite(brakeOut,breaking);
          //Serial.println(sensorValue);
        }
        else if(unlocked==2){                                    //default state, bike soesnt move
                  analogWrite(outPin,10);
          analogWrite(brakeOut,10);
        }
        
      if(unlocked==2){                      //default on startup, reads rfid constantly, slows analog read from throttle down
                
		//Search card, return card types
		status = MFRC522_Request(PICC_REQIDL, str);	
		if (status == MI_OK){
		}

		//Prevent conflict, return the 4 bytes Serial number of the card
		status = MFRC522_Anticoll(str);
		memcpy(serNum, str, 5);
		if (status == MI_OK)
		{

                        Serial.println("The card's number is  : ");
			Serial.print(serNum[0]);
                        Serial.print(" , ");
			Serial.print(serNum[1]);
                        Serial.print(" , ");
			Serial.print(serNum[2]);
                        Serial.print(" , ");
			Serial.print(serNum[3]);
                        Serial.print(" , ");
			Serial.print(serNum[4]);
                        Serial.println(" ");
                        
                        // Should really check all pairs, but for now we'll just use the first
                     
                        if(serNum[0] == 111 && serNum[1] == 111 && serNum[2]==111  && serNum[3]==111) {
                          unlocked=1;
                        }
                        else if(serNum[0] == 111 && serNum[1] == 111 && serNum[2]==111 && serNum[3]==111){
                          unlocked=0;                                                                          //that means bike runs with speed limit
                          digitalWrite(speedLim,LOW);
                        }
                        else{ 
                    }
                       // delay(1000);
		}
                //Serial.println(" ");
		MFRC522_Halt();			//command the card into sleep mode
        }
        else {}
                
}

void setPwmFrequency(int pin, int divisor) {
  byte mode;
  if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 64: mode = 0x03; break;
      case 256: mode = 0x04; break;
      case 1024: mode = 0x05; break;
      default: return;
    }
    if(pin == 5 || pin == 6) {
      TCCR0B = TCCR0B & 0b11111000 | mode;
    } else {
      TCCR1B = TCCR1B & 0b11111000 | mode;
    }
  } else if(pin == 3 || pin == 11) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 32: mode = 0x03; break;
      case 64: mode = 0x04; break;
      case 128: mode = 0x05; break;
      case 256: mode = 0x06; break;
      case 1024: mode = 0x7; break;
      default: return;
    }
    TCCR2B = TCCR2B & 0b11111000 | mode;
  }
}
/*
 * Function:Write_MFRC5200
 * Description:write a byte data into one register of MR RC522
 * Input parameter:addr--register address;val--the value that need to write in
 * Return:Null
 */
void Write_MFRC522(uchar addr, uchar val)
{
	digitalWrite(chipSelectPin, LOW);

	//address format:0XXXXXX0
	SPI.transfer((addr<<1)&0x7E);	
	SPI.transfer(val);
	
	digitalWrite(chipSelectPin, HIGH);
}


/*
 * Function:Read_MFRC522
 * Description:read a byte data into one register of MR RC522
 * Input parameter:addr--register address
 * Return:return the read value
 */
uchar Read_MFRC522(uchar addr)
{
	uchar val;

	digitalWrite(chipSelectPin, LOW);

	//address format:1XXXXXX0
	SPI.transfer(((addr<<1)&0x7E) | 0x80);	
	val =SPI.transfer(0x00);
	
	digitalWrite(chipSelectPin, HIGH);
	
	return val;	
}

/*
 * Function:SetBitMask
 * Description:set RC522 register bit
 * Input parameter:reg--register address;mask--value
 * Return:null
 */
void SetBitMask(uchar reg, uchar mask)  
{
    uchar tmp;
    tmp = Read_MFRC522(reg);
    Write_MFRC522(reg, tmp | mask);  // set bit mask
}


/*
 * Function:ClearBitMask
 * Description:clear RC522 register bit
 * Input parameter:reg--register address;mask--value
 * Return:null
 */
void ClearBitMask(uchar reg, uchar mask)  
{
    uchar tmp;
    tmp = Read_MFRC522(reg);
    Write_MFRC522(reg, tmp & (~mask));  // clear bit mask
} 


/*
 * Function:AntennaOn
 * Description:Turn on antenna, every time turn on or shut down antenna need at least 1ms delay
 * Input parameter:null
 * Return:null
 */
void AntennaOn(void)
{
	uchar temp;

	temp = Read_MFRC522(TxControlReg);
	if (!(temp & 0x03))
	{
		SetBitMask(TxControlReg, 0x03);
	}
}


/*
 * Function:AntennaOff
 * Description:Turn off antenna, every time turn on or shut down antenna need at least 1ms delay
 * Input parameter:null
 * Return:null
 */
void AntennaOff(void)
{
	ClearBitMask(TxControlReg, 0x03);
}


/*
 * Function:ResetMFRC522
 * Description: reset RC522
 * Input parameter:null
 * Return:null
 */
void MFRC522_Reset(void)
{
    Write_MFRC522(CommandReg, PCD_RESETPHASE);
}


/*
 * Function:InitMFRC522
 * Description:initilize RC522
 * Input parameter:null
 * Return:null
 */
void MFRC522_Init(void)
{
	digitalWrite(NRSTPD,HIGH);

	MFRC522_Reset();
	 	
	//Timer: TPrescaler*TreloadVal/6.78MHz = 24ms
    Write_MFRC522(TModeReg, 0x8D);		//Tauto=1; f(Timer) = 6.78MHz/TPreScaler
    Write_MFRC522(TPrescalerReg, 0x3E);	//TModeReg[3..0] + TPrescalerReg
    Write_MFRC522(TReloadRegL, 30);           
    Write_MFRC522(TReloadRegH, 0);
	
	Write_MFRC522(TxAutoReg, 0x40);		//100%ASK
	Write_MFRC522(ModeReg, 0x3D);		//CRC initilizate value 0x6363	???

	//ClearBitMask(Status2Reg, 0x08);		//MFCrypto1On=0
	//Write_MFRC522(RxSelReg, 0x86);		//RxWait = RxSelReg[5..0]
	//Write_MFRC522(RFCfgReg, 0x7F);   		//RxGain = 48dB

	AntennaOn();		//turn on antenna
}


/*
 * Function:MFRC522_Request
 * Description:Searching card, read card type
 * Input parameter:reqMode--search methods,
 *			 TagType--return card types
 *			 	0x4400 = Mifare_UltraLight
 *				0x0400 = Mifare_One(S50)
 *				0x0200 = Mifare_One(S70)
 *				0x0800 = Mifare_Pro(X)
 *				0x4403 = Mifare_DESFire
 * return:return MI_OK if successed
 */
uchar MFRC522_Request(uchar reqMode, uchar *TagType)
{
	uchar status;  
	uint backBits;			//the data bits that received

	Write_MFRC522(BitFramingReg, 0x07);		//TxLastBists = BitFramingReg[2..0]	???
	
	TagType[0] = reqMode;
	status = MFRC522_ToCard(PCD_TRANSCEIVE, TagType, 1, TagType, &backBits);

	if ((status != MI_OK) || (backBits != 0x10))
	{    
		status = MI_ERR;
	}
   
	return status;
}


/*
 * Function:MFRC522_ToCard
 * Description:communicate between RC522 and ISO14443
 * Input parameter:command--MF522 command bits
 *			 sendData--send data to card via rc522
 *			 sendLen--send data length		 
 *			 backData--the return data from card
 *			 backLen--the length of return data
 * return:return MI_OK if successed
 */
uchar MFRC522_ToCard(uchar command, uchar *sendData, uchar sendLen, uchar *backData, uint *backLen)
{
    uchar status = MI_ERR;
    uchar irqEn = 0x00;
    uchar waitIRq = 0x00;
    uchar lastBits;
    uchar n;
    uint i;

    switch (command)
    {
        case PCD_AUTHENT:		//verify card password
		{
			irqEn = 0x12;
			waitIRq = 0x10;
			break;
		}
		case PCD_TRANSCEIVE:	//send data in the FIFO
		{
			irqEn = 0x77;
			waitIRq = 0x30;
			break;
		}
		default:
			break;
    }
   
    Write_MFRC522(CommIEnReg, irqEn|0x80);	//Allow interruption
    ClearBitMask(CommIrqReg, 0x80);			//Clear all the interrupt bits
    SetBitMask(FIFOLevelReg, 0x80);			//FlushBuffer=1, FIFO initilizate
    
	Write_MFRC522(CommandReg, PCD_IDLE);	//NO action;cancel current command	???

	//write data into FIFO
    for (i=0; i<sendLen; i++)
    {   
		Write_MFRC522(FIFODataReg, sendData[i]);    
	}

	//procceed it
	Write_MFRC522(CommandReg, command);
    if (command == PCD_TRANSCEIVE)
    {    
		SetBitMask(BitFramingReg, 0x80);		//StartSend=1,transmission of data starts  
	}   
    
	//waite receive data is finished
	i = 2000;	//i should adjust according the clock, the maxium the waiting time should be 25 ms???
    do 
    {
		//CommIrqReg[7..0]
		//Set1 TxIRq RxIRq IdleIRq HiAlerIRq LoAlertIRq ErrIRq TimerIRq
        n = Read_MFRC522(CommIrqReg);
        i--;
    }
    while ((i!=0) && !(n&0x01) && !(n&waitIRq));

    ClearBitMask(BitFramingReg, 0x80);			//StartSend=0
	
    if (i != 0)
    {    
        if(!(Read_MFRC522(ErrorReg) & 0x1B))	//BufferOvfl Collerr CRCErr ProtecolErr
        {
            status = MI_OK;
            if (n & irqEn & 0x01)
            {   
				status = MI_NOTAGERR;			//??   
			}

            if (command == PCD_TRANSCEIVE)
            {
               	n = Read_MFRC522(FIFOLevelReg);
              	lastBits = Read_MFRC522(ControlReg) & 0x07;
                if (lastBits)
                {   
					*backLen = (n-1)*8 + lastBits;   
				}
                else
                {   
					*backLen = n*8;   
				}

                if (n == 0)
                {   
					n = 1;    
				}
                if (n > MAX_LEN)
                {   
					n = MAX_LEN;   
				}
				
				//read the data from FIFO
                for (i=0; i<n; i++)
                {   
					backData[i] = Read_MFRC522(FIFODataReg);    
				}
            }
        }
        else
        {   
			status = MI_ERR;  
		}
        
    }
	
    //SetBitMask(ControlReg,0x80);           //timer stops
    //Write_MFRC522(CommandReg, PCD_IDLE); 

    return status;
}


/*
 * Function:MFRC522_Anticoll
 * Description:Prevent conflict, read the card serial number 
 * Input parameter:serNum--return the 4 bytes card serial number, the 5th byte is recheck byte
 * return:return MI_OK if successed
 */
uchar MFRC522_Anticoll(uchar *serNum)
{
    uchar status;
    uchar i;
	uchar serNumCheck=0;
    uint unLen;
    

    //ClearBitMask(Status2Reg, 0x08);		//TempSensclear
    //ClearBitMask(CollReg,0x80);			//ValuesAfterColl
	Write_MFRC522(BitFramingReg, 0x00);		//TxLastBists = BitFramingReg[2..0]
 
    serNum[0] = PICC_ANTICOLL;
    serNum[1] = 0x20;
    status = MFRC522_ToCard(PCD_TRANSCEIVE, serNum, 2, serNum, &unLen);

    if (status == MI_OK)
	{
		//Verify card serial number
		for (i=0; i<4; i++)
		{   
		 	serNumCheck ^= serNum[i];
		}
		if (serNumCheck != serNum[i])
		{   
			status = MI_ERR;    
		}
    }

    //SetBitMask(CollReg, 0x80);		//ValuesAfterColl=1

    return status;
} 


/*
 * Function:CalulateCRC
 * Description:Use MF522 to caculate CRC
 * Input parameter:pIndata--the CRC data need to be read,len--data length,pOutData-- the caculated result of CRC
 * return:Null
 */
void CalulateCRC(uchar *pIndata, uchar len, uchar *pOutData)
{
    uchar i, n;

    ClearBitMask(DivIrqReg, 0x04);			//CRCIrq = 0
    SetBitMask(FIFOLevelReg, 0x80);			//Clear FIFO pointer
    //Write_MFRC522(CommandReg, PCD_IDLE);

	//Write data into FIFO	
    for (i=0; i<len; i++)
    {   
		Write_MFRC522(FIFODataReg, *(pIndata+i));   
	}
    Write_MFRC522(CommandReg, PCD_CALCCRC);

	//waite CRC caculation to finish
    i = 0xFF;
    do 
    {
        n = Read_MFRC522(DivIrqReg);
        i--;
    }
    while ((i!=0) && !(n&0x04));			//CRCIrq = 1

	//read CRC caculation result
    pOutData[0] = Read_MFRC522(CRCResultRegL);
    pOutData[1] = Read_MFRC522(CRCResultRegM);
}


/*
 * Function:MFRC522_SelectTag
 * Description:Select card, read card storage volume
 * Input parameter:serNum--Send card serial number
 * return:return the card storage volume
 */
uchar MFRC522_SelectTag(uchar *serNum)
{
    uchar i;
	uchar status;
	uchar size;
    uint recvBits;
    uchar buffer[9]; 

	//ClearBitMask(Status2Reg, 0x08);			//MFCrypto1On=0

    buffer[0] = PICC_SElECTTAG;
    buffer[1] = 0x70;
    for (i=0; i<5; i++)
    {
    	buffer[i+2] = *(serNum+i);
    }
	CalulateCRC(buffer, 7, &buffer[7]);		//??
    status = MFRC522_ToCard(PCD_TRANSCEIVE, buffer, 9, buffer, &recvBits);
    
    if ((status == MI_OK) && (recvBits == 0x18))
    {   
		size = buffer[0]; 
	}
    else
    {   
		size = 0;    
	}

    return size;
}


/*
 * Function:MFRC522_Auth
 * Description:verify card password
 * Input parameters:authMode--password verify mode
                 0x60 = verify A passowrd key 
                 0x61 = verify B passowrd key 
             BlockAddr--Block address
             Sectorkey--Block password
             serNum--Card serial number ,4 bytes
 * return:return MI_OK if successed
 */
uchar MFRC522_Auth(uchar authMode, uchar BlockAddr, uchar *Sectorkey, uchar *serNum)
{
    uchar status;
    uint recvBits;
    uchar i;
	uchar buff[12]; 

	//Verify command + block address + buffer password + card SN
    buff[0] = authMode;
    buff[1] = BlockAddr;
    for (i=0; i<6; i++)
    {    
		buff[i+2] = *(Sectorkey+i);   
	}
    for (i=0; i<4; i++)
    {    
		buff[i+8] = *(serNum+i);   
	}
    status = MFRC522_ToCard(PCD_AUTHENT, buff, 12, buff, &recvBits);

    if ((status != MI_OK) || (!(Read_MFRC522(Status2Reg) & 0x08)))
    {   
		status = MI_ERR;   
	}
    
    return status;
}


/*
 * Function:MFRC522_Read
 * Description:Read data 
 * Input parameters:blockAddr--block address;recvData--the block data which are read
 * return:return MI_OK if successed
 */
uchar MFRC522_Read(uchar blockAddr, uchar *recvData)
{
    uchar status;
    uint unLen;

    recvData[0] = PICC_READ;
    recvData[1] = blockAddr;
    CalulateCRC(recvData,2, &recvData[2]);
    status = MFRC522_ToCard(PCD_TRANSCEIVE, recvData, 4, recvData, &unLen);

    if ((status != MI_OK) || (unLen != 0x90))
    {
        status = MI_ERR;
    }
    
    return status;
}


/*
 * Function:MFRC522_Write
 * Description:write block data
 * Input parameters:blockAddr--block address;writeData--Write 16 bytes data into block
 * return:return MI_OK if successed
 */
uchar MFRC522_Write(uchar blockAddr, uchar *writeData)
{
    uchar status;
    uint recvBits;
    uchar i;
	uchar buff[18]; 
    
    buff[0] = PICC_WRITE;
    buff[1] = blockAddr;
    CalulateCRC(buff, 2, &buff[2]);
    status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 4, buff, &recvBits);

    if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A))
    {   
		status = MI_ERR;   
	}
        
    if (status == MI_OK)
    {
        for (i=0; i<16; i++)		//Write 16 bytes data into FIFO
        {    
        	buff[i] = *(writeData+i);   
        }
        CalulateCRC(buff, 16, &buff[16]);
        status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 18, buff, &recvBits);
        
		if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A))
        {   
			status = MI_ERR;   
		}
    }
    
    return status;
}


/*
 * Function:MFRC522_Halt
 * Description:Command the cards into sleep mode
 * Input parameters:null
 * return:null
 */
void MFRC522_Halt(void)
{
	uchar status;
    uint unLen;
    uchar buff[4]; 

    buff[0] = PICC_HALT;
    buff[1] = 0;
    CalulateCRC(buff, 2, &buff[2]);
 
    status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 4, buff,&unLen);
}

 

20141106_182902

Natürlich wäre ein Drehmomentsensor viel eleganter… leider sind diese auch viel teurer (ab 200.-) In meinem Fall unterstützt das Bike auch, wenn man “pseudopedaliert”. Bei einigen Baumarkt Pedelecs ist dies ebenfalls so. Da ich nur einen Gang habe, macht es auch keinen Sinn die Tretunterstützung über die Kadenz anzupassen. Die Leistungsregelung erfolgt adaptiv über den Gasgriff.

Sabvoton Einstellungen

Wie bei allen China Controllern ist die Dokumentation schon ziemlich dürftig und teilweise fehlerhaft. Deshalb beschreibe ich hier ganz kurz das erbärmliche Chinglish Labview Interface und das wiring diagram des Controllers. Ebenso ist das Bluetooth Interface wirklich unbrauchbar: Die Android App stürzt dauernd ab und die Kommunikation funktioniert, wenn überhaupt, nur sporadisch. Ich werde aber nur die wichtigsten Funktionen erläutern. Das Diagramm zeigt eigentlich die 96V Variante des Controllers. Die linke Seite  muss man nicht beachten.

  1. Blaues Hallsensor Kabel (Funktion unbekannt)
  2. Beide Throttle reagieren auf ein analoges 0-5V Signal. Wobei der nutzbare Bereich eingestellt werden kann. I.d.R. liest der Controller eine eher zu hohe Spannung ein. Fällt die Spannung auf 0V oder steigt sie auf 5V so schaltet der Motor ab und der Controller gibt einen Fehler aus.
  3. Die Signale Cruise, Reverse und Boost werden aktiviert wenn man sie auf 0V zieht
  4. Das High brake Signal muss min 5V sein um aktiv zu sein. Anscheinend kann es auch auf die positive Batteriespannung gezogen werden ohne den Controller zu beschädigen.
  5. Das Electric lock ist eigentlich die Speisung des Controllers (Orange oder Rot)
  6. Ein pinkes Kabel wird entweder das Low brake oder das Speed Limit Signal sein

electric_schemata

Die Basic Funktionen sind eigentlich selbsterklärend: Lack Volt ist die Spannung bei der der Controller den Dienst quittiert. Idealerweise wird der Phasenstrom auf ca. 2.5x Batteriestrom gesetzt.

sab1

Die Temperaturfunktionen muss ich wohl nicht erläutern. Wenn die variable Rekuperation benutzt wird, müssen General brake disabled und Electric brake enabled sein. Flux weakening ist nützlich um eine höhere Geschwindigkeit auf Kosten der Reichweite zu erzielen. Wenn Slide recharge enabled ist, rekuperiert der Controller sobald der Gasgriff losgelassen wird. Der Grenzwert bei dem der Slide recharge noch funktioniert kann mit dem Slide recharge speed eingestellt werden.

Wichtig: Der Controller scheint den Electric brake ph current falsch einzulesen: Wenn man mit bis zu 50A Phasenstrom rekuperieren will, muss der Wert auf 500 gesetzt werden! (Zumindest in der ewig aktuellen Softwareversion). Electric brake wird eingeschaltet wenn das High brake Signal auf 5V+ gezogen wird. Mit dem Variable Regen wird der Phasenstrom eingestellt.Sab2

Der Throttle min vol darf nicht zu tief eingestellt werden, ansonsten dreht sich der Motor, wenn der Gasgriff nicht betätigt wird. 1.3-1.4V sind üblich (auch wenn der Gasgriff nur 0.8V ausgibt!)

Die Accelerate time ist die Zeit, die es dauert, bis der Phasenstrom von 0-max geht. Um Wheelies beim Anfahren zu vermeiden, sollte der Wert am Anfang auf 2000ms (Maximalwert) und die Decelerate time auf 50ms gesetzt werden.

sab3

Falls man ein Kabel hat, um die Geschwindigkeit zu begrenzen, kann man unter Motor limit speed set den Wert einstellen. (Der Wert gilt, wenn das Signal -auch nur temporär- auf 0V gezogen wird).

Low/Middle speed set sind für den Fall, dass ein 3 Speed Switch installiert wurde.

Sab4

Was ich am Anfang übersehen habe war der Parameter store Schalter. Wenn man die Einstellungen auch speichern will, so muss man nach jeder neuen Eingabe zuerst OK neben dem Wert drücken und anschliessend im Debug Register, den Parameter store Schalter umlegen und dann OK drücken. sab5