сряда, 21 март 2018 г.

DCC декодер за локомотив с Arduino Pro Mini

DCC декодер за локомотив с Arduino Pro Mini

Оригиналния проект е на този сайт
http://lamaquetade.infotronikblog.com/digitalizando-333-electrotren-con-locodec-dcc/

Аз промених малко кода за да може да управлява Н-мост с транзистори вместо моторния драйвър L293

Това е схемата на Н-моста който използвам аз
но той може да бъде изпълнен и по коя да е друга схема





Това е схемата на Ардуино със снемане на дсс сигнал и захранване




Ето и самия код който трябва да заредите в Ардуино

/* Декодер за локомотиви H0 с Arduino nano и Н-bridge  * Библиотека NmraDcc.h  * Стандартният адрес на локомотива е #define This_Decoder_Address  * Изходите PWM на Arduino Nano са 5 и 6  * Светлините са свързани към пинове 3 и 4 на Arduino Nano   * Основни CV: CV2 = Начално напрежение; CV3 = скорост на ускоряване; CV4 = степен на спиране; CV5 = максимално скоростно напрежение */ #include <NmraDcc.h> #define This_Decoder_Address 4 //Променете този номер, за да промените адреса на локомотива const int FunctionPin0 = 3;// pin 3 and 4 light const int FunctionPin1 = 7; const int FunctionPin2 = 8; const int FunctionPin3 = 9; const int FunctionPin4 = 10; const int DccAckPin = 15 ;//за индикация на промяна на CV const int PWM_MAX = 254; //const int left = 10; //Pin изход към left L293 //const int right = 11; //Pin изход към right L293 const int velPwm0 = 5; const int velPwm1 = 6; const int lucesDelanteras = 3; //pin изход към предни светлини const int lucesTraseras = 4; //pin изход към задни светлини int currentSpeed = 0; int rateSteps; int acSpeed; int locSpeed = 0; int rateSpeed = 0; int dirState = 0; //Променлива промяна на посоката int dirFlag1 = 0; int dirFlag2 = 0; int steps; //Pasos (14, 28, 128) стъпки //int maniobras = 0; //маневрени int Luces = 0; //Variable включване на светлините //-------------CV конфигуриране int CV2 = 60; //начално напрежение за скорост 1 int CV3 = 4; //Степен на ускоряване (CV3 * intervalAcc) int CV4 = 4; //Скорост на спиране (CV4 * intervalDec) int CV5 = 254; //Максимално напрежение //------------- int topSpeed = CV5; long previousDebug = 0; long previousAcc = 0; long previousDec = 0; long intervalDebug = (500); long intervalAcc = (25 * CV3); long intervalDec = (25 * CV4); struct CVPair { uint16_t CV; uint8_t Value; }; CVPair FactoryDefaultCVs [] = { // The CV Below defines the Short DCC Address {CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address}, {CV_ACCESSORY_DECODER_ADDRESS_MSB, 0}, // These two CVs define the Long DCC Address {CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, {CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, This_Decoder_Address}, // ONLY uncomment 1 CV_29_CONFIG line below as approprate // {CV_29_CONFIG, 0}, // Short Address 14 Speed Steps {CV_29_CONFIG, CV29_F0_LOCATION}, // Short Address 28/128 Speed Steps // {CV_29_CONFIG, CV29_EXT_ADDRESSING | CV29_F0_LOCATION}, // Long Address 28/128 Speed Steps }; NmraDcc Dcc ; DCC_MSG Packet ; uint8_t FactoryDefaultCVIndex = 0; // Uncomment this line below to force resetting the CVs back to Factory Defaults // FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair); void notifyCVResetFactoryDefault() { // Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset // to flag to the loop() function that a reset to Factory Defaults needs to be done FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs) / sizeof(CVPair); }; // Uncomment the #define below to print all Speed Packets #define NOTIFY_DCC_SPEED #ifdef NOTIFY_DCC_SPEED void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps ) { // Serial.print("notifyDccSpeed: Addr: "); // Serial.print(Addr, DEC); // Serial.print( (AddrType == DCC_ADDR_SHORT) ? "-S" : "-L" ); // Serial.print(" Speed: "); // Serial.print(Speed, DEC); // locSpeed = Speed; acSpeed = Speed; // Serial.print(" Steps: "); int SpeedStep = (SpeedSteps - 1); steps = SpeedStep; // Serial.print(SpeedStep, DEC); // Serial.print(" Dir: "); // Serial.println( (Dir == DCC_DIR_FWD) ? "Forward" : "Reverse" ); dirState = Dir; }; #endif // Uncomment the #define below to print all Function Packets #define NOTIFY_DCC_FUNC //#ifdef NOTIFY_DCC_FUNC void notifyDccFunc(uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) { // Serial.print("notifyDccFunc: Addr: "); //Serial.print(Addr, DEC); //Serial.print( (AddrType == DCC_ADDR_SHORT) ? 'S' : 'L' ); //Serial.print(" Function Group: "); //Serial.print(FuncGrp, DEC); switch ( FuncGrp ) { #ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE case FN_0: // Serial.print(" FN0: "); // Serial.println((FuncState & FN_BIT_00) ? "1 " : "0 "); break; #endif case FN_0_4: exec_function( 0, (FuncState & FN_BIT_00) >> 4 ); exec_function( 1, (FuncState & FN_BIT_01)); exec_function( 2, (FuncState & FN_BIT_02) >> 1); exec_function( 3, (FuncState & FN_BIT_03) >> 2 ); exec_function( 4, (FuncState & FN_BIT_04) >> 3 ); if (Dcc.getCV(CV_29_CONFIG) & CV29_F0_LOCATION) // Only process Function 0 in this packet if we're not in Speed Step 14 Mode { // Serial.print(" FN 0: "); // Serial.print((FuncState & FN_BIT_00) ? "1 " : "0 "); // delay (100); } break; case FN_5_8: exec_function( 5, (FuncState & FN_BIT_05)); exec_function( 6, (FuncState & FN_BIT_06) >> 1 ); exec_function( 7, (FuncState & FN_BIT_07) >> 2 ); exec_function( 8, (FuncState & FN_BIT_08) >> 3 ); break; case FN_9_12: exec_function( 9, (FuncState & FN_BIT_09)); exec_function( 10, (FuncState & FN_BIT_10) >> 1 ); exec_function( 11, (FuncState & FN_BIT_11) >> 2 ); exec_function( 12, (FuncState & FN_BIT_12) >> 3 ); break; } } void exec_function (int f_index, int FuncState) { switch (f_index) { case 0: if (FuncState == 1) { Luces = 1; } else { Luces = 0; } case 1: FuncState ? digitalWrite(FunctionPin1, 1) : digitalWrite(FunctionPin1, 0); break; case 2: FuncState ? digitalWrite(FunctionPin2, 1) : digitalWrite(FunctionPin2, 0); break; case 3: FuncState ? digitalWrite(FunctionPin3, 1) : digitalWrite(FunctionPin3, 0); break; case 4: FuncState ? digitalWrite(FunctionPin4, 1) : digitalWrite(FunctionPin4, 0); break; default: break; } } // This function is called by the NmraDcc library when a DCC ACK needs to be sent // Calling this function should cause an increased 60ma current drain on the power supply for 6ms to ACK a CV Read void notifyCVAck(void) { //Serial.println("notifyCVAck") ; digitalWrite( DccAckPin, HIGH ); delay( 8 ); digitalWrite( DccAckPin, LOW ); } void setup() { pinMode(velPwm0, OUTPUT);//pin 5 pinMode(velPwm1, OUTPUT);//pin 6 pinMode (lucesDelanteras, OUTPUT);//pin 3 pinMode (lucesTraseras, OUTPUT);//pin 4 pinMode (FunctionPin1, OUTPUT);//pin 7 digitalWrite(FunctionPin1, 0); pinMode (FunctionPin2, OUTPUT);//pin 8 digitalWrite(FunctionPin2, 0); pinMode (FunctionPin3, OUTPUT);//pin 9 digitalWrite(FunctionPin3, 0); pinMode (FunctionPin4, OUTPUT);//pin 10 digitalWrite(FunctionPin4, 0); Serial.begin(115200); Serial.println("NMRA Dcc Multifunction Decoder Demo 1"); // Configure the DCC CV Programing ACK pin for an output pinMode( DccAckPin, OUTPUT ); digitalWrite( DccAckPin, LOW ); // Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up // Първият параметър е номерът за прекъсване, вторият е pin, а третият е състоянието на вътрешния pullup резистор (1 означава разрешено ) Dcc.pin(0, 2, 0); // Call the main DCC Init function to enable the DCC Receiver //Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 ); //Първите два параметъра са производителят и версията на декодера С третия параметър можете да промените по подразбиране поведението на библиотеката: последният е адресът EEPROM, от който библиотеката съхранява своите стойности Dcc.init( MAN_ID_DIY, 10, FLAGS_MY_ADDRESS_ONLY, 0 ); // Uncomment to force CV Reset to Factory Defaults notifyCVResetFactoryDefault(); } void loop() { // You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation Dcc.process(); if ( FactoryDefaultCVIndex && Dcc.isSetCVReady()) { FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array Dcc.setCV( FactoryDefaultCVs[FactoryDefaultCVIndex].CV, FactoryDefaultCVs[FactoryDefaultCVIndex].Value); } if (dirState == 0) { if (dirFlag1 == 1) { int locSpeedup = locSpeed; for (int locSpeed = locSpeedup; locSpeed > CV2; locSpeed--) { digitalWrite (velPwm1, LOW); analogWrite (velPwm0, locSpeed); delay(intervalDec); } dirState0(); for (int locSpeed = CV2; locSpeed < locSpeedup; locSpeed++) { digitalWrite (velPwm1, LOW); analogWrite (velPwm0, locSpeed); delay(intervalAcc); } dirFlag1 = 0; } dirFlag2 = 1; dirState0(); } if (dirState == 1) { if (dirFlag2 == 1) { int locSpeedup = locSpeed; for (int locSpeed = locSpeedup; locSpeed > CV2; locSpeed--) { digitalWrite (velPwm0, LOW); analogWrite (velPwm1, locSpeed); delay(intervalDec); } dirState1(); for (int locSpeed = CV2; locSpeed < locSpeedup; locSpeed++) { digitalWrite (velPwm0, LOW); analogWrite (velPwm1, locSpeed); delay(intervalAcc); } dirFlag2 = 0; } dirFlag1 = 1; dirState1(); } if (currentSpeed <= 1) { locSpeed = 0; digitalWrite (velPwm0, LOW); digitalWrite (velPwm1, LOW); } else { rateSpeed = ((PWM_MAX - CV2) / steps); } if (currentSpeed != acSpeed ) { //ако currentSteps е различен от стъпките if (currentSpeed < acSpeed) { Acc(); } if (currentSpeed > acSpeed) { Dec(); } } //analogWrite (velPwm, locSpeed); Debugger(); } void Acc() { unsigned long currentAccMillis = millis(); if (currentAccMillis - previousAcc > intervalAcc ) { previousAcc = currentAccMillis; locSpeed = (CV2 + (currentSpeed * rateSpeed)); if (locSpeed >= CV5) { //ако скоростта на локомотива е по - голяма от CV5 locSpeed = CV5; } currentSpeed = (currentSpeed + 1); if (currentSpeed >= acSpeed) { currentSpeed = acSpeed; } } return; } void Dec() { unsigned long currentDecMillis = millis(); if (currentDecMillis - previousDec > intervalDec) { previousDec = currentDecMillis; locSpeed = (CV2 + (currentSpeed * rateSpeed)); currentSpeed = (currentSpeed - 1); if (currentSpeed <= acSpeed) { currentSpeed = acSpeed; } return; } } void dirState0() { digitalWrite (velPwm1, LOW); analogWrite (velPwm0, locSpeed); if (Luces == 1) { digitalWrite (lucesDelanteras, HIGH); digitalWrite (lucesTraseras, LOW); } else { digitalWrite (lucesDelanteras, LOW); digitalWrite (lucesTraseras, LOW); } return; } void dirState1() { digitalWrite (velPwm0, LOW); analogWrite (velPwm1, locSpeed); if (Luces == 1) { digitalWrite (lucesDelanteras, LOW); digitalWrite (lucesTraseras, HIGH); } else { digitalWrite (lucesDelanteras, LOW); digitalWrite (lucesTraseras, LOW); } return; } void Debugger() { unsigned long currentDebugMillis = millis(); if (currentDebugMillis - previousDebug > intervalDebug) { previousDebug = currentDebugMillis; Serial.print(" Adr N: "); Serial.print(This_Decoder_Address); Serial.print(" sped PWM : "); Serial.print(locSpeed); Serial.print(" step : "); Serial.print(steps, DEC); Serial.print(" Dir: "); //Serial.println( (dirState == DCC_DIR_FWD) ? "Forward" : "Reverse" ); Serial.println(dirState); } return; }