Compare commits
27 Commits
ESP8266-IC
...
GBSMA601
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5efcaaeb6b | ||
|
|
d1e4a2b83d | ||
|
|
3e7ac4967c | ||
|
|
29e90c7c9c | ||
|
|
a8d3a32d07 | ||
|
|
644fe9abff | ||
|
|
771d2ae722 | ||
|
|
8184159c87 | ||
|
|
6d23aa0993 | ||
|
|
b0ac4a4f6f | ||
|
|
3bbdad9f8f | ||
|
|
c18ed5b703 | ||
|
|
37bb3f8e66 | ||
|
|
70b5530bb4 | ||
|
|
8574dda01c | ||
|
|
90e40f8f91 | ||
|
|
6ed5a97e30 | ||
|
|
e0ceeafcb9 | ||
|
|
8ca2e03264 | ||
|
|
e6a9f9a825 | ||
|
|
06999ee778 | ||
|
|
0277afd827 | ||
|
|
209256ff44 | ||
|
|
84fb903af2 | ||
|
|
fd5246040f | ||
|
|
e9e9684c08 | ||
|
|
1a51b94ad3 |
109
NmraDcc.cpp
109
NmraDcc.cpp
@@ -25,8 +25,6 @@
|
|||||||
// 2017-01-19 added STM32F1 support by Franz-Peter
|
// 2017-01-19 added STM32F1 support by Franz-Peter
|
||||||
// 2017-11-29 Ken West (kgw4449@gmail.com):
|
// 2017-11-29 Ken West (kgw4449@gmail.com):
|
||||||
// Minor fixes to pass NMRA Baseline Conformance Tests.
|
// Minor fixes to pass NMRA Baseline Conformance Tests.
|
||||||
// 2018-12-17 added ESP32 support by Trusty (thierry@lapajaparis.net)
|
|
||||||
// 2019-02-17 added ESP32 specific changes by Hans Tanner
|
|
||||||
//
|
//
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
@@ -176,22 +174,9 @@
|
|||||||
#define MODE_TP3 pinMode( D7,OUTPUT ) ; // GPIO 13
|
#define MODE_TP3 pinMode( D7,OUTPUT ) ; // GPIO 13
|
||||||
#define SET_TP3 GPOS = (1 << D7);
|
#define SET_TP3 GPOS = (1 << D7);
|
||||||
#define CLR_TP3 GPOC = (1 << D7);
|
#define CLR_TP3 GPOC = (1 << D7);
|
||||||
#define MODE_TP4 pinMode( D8,OUTPUT ) ; // GPIO 15
|
#define MODE_TP4 pinMode( D7,OUTPUT ); // GPIO 15
|
||||||
#define SET_TP4 GPOC = (1 << D8);
|
#define SET_TP4 GPOC = (1 << D8);
|
||||||
#define CLR_TP4 GPOC = (1 << D8);
|
#define CLR_TP4 GPOC = (1 << D8);
|
||||||
#elif defined(ESP32)
|
|
||||||
#define MODE_TP1 pinMode( 33,OUTPUT ) ; // GPIO 33
|
|
||||||
#define SET_TP1 GPOS = (1 << 33);
|
|
||||||
#define CLR_TP1 GPOC = (1 << 33);
|
|
||||||
#define MODE_TP2 pinMode( 25,OUTPUT ) ; // GPIO 25
|
|
||||||
#define SET_TP2 GPOS = (1 << 25);
|
|
||||||
#define CLR_TP2 GPOC = (1 << 25);
|
|
||||||
#define MODE_TP3 pinMode( 26,OUTPUT ) ; // GPIO 26
|
|
||||||
#define SET_TP3 GPOS = (1 << 26);
|
|
||||||
#define CLR_TP3 GPOC = (1 << 26);
|
|
||||||
#define MODE_TP4 pinMode( 27,OUTPUT ) ; // GPIO 27
|
|
||||||
#define SET_TP4 GPOC = (1 << 27);
|
|
||||||
#define CLR_TP4 GPOC = (1 << 27);
|
|
||||||
|
|
||||||
|
|
||||||
//#elif defined(__AVR_ATmega128__) ||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
|
//#elif defined(__AVR_ATmega128__) ||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
|
||||||
@@ -245,12 +230,8 @@ struct countOf_t countOf;
|
|||||||
|
|
||||||
#if defined ( __STM32F1__ )
|
#if defined ( __STM32F1__ )
|
||||||
static ExtIntTriggerMode ISREdge;
|
static ExtIntTriggerMode ISREdge;
|
||||||
#elif defined ( ESP32 )
|
|
||||||
static byte ISREdge; // Holder of the Next Edge we're looking for: RISING or FALLING
|
|
||||||
static byte ISRWatch; // Interrupt Handler Edge Filter
|
|
||||||
#else
|
#else
|
||||||
static byte ISREdge; // Holder of the Next Edge we're looking for: RISING or FALLING
|
static byte ISREdge; // RISING or FALLING
|
||||||
static byte ISRWatch; // Interrupt Handler Edge Filter
|
|
||||||
#endif
|
#endif
|
||||||
static word bitMax, bitMin;
|
static word bitMax, bitMin;
|
||||||
|
|
||||||
@@ -306,43 +287,12 @@ DCC_PROCESSOR_STATE ;
|
|||||||
|
|
||||||
DCC_PROCESSOR_STATE DccProcState ;
|
DCC_PROCESSOR_STATE DccProcState ;
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
|
|
||||||
|
|
||||||
void IRAM_ATTR ExternalInterruptHandler(void)
|
|
||||||
#elif defined(ESP8266)
|
|
||||||
void ICACHE_RAM_ATTR ExternalInterruptHandler(void)
|
|
||||||
#else
|
|
||||||
void ExternalInterruptHandler(void)
|
void ExternalInterruptHandler(void)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
#ifdef ESP32
|
|
||||||
// switch (ISRWatch)
|
|
||||||
// {
|
|
||||||
// case RISING: if (digitalRead(DccProcState.ExtIntPinNum)) break;
|
|
||||||
// case FALLING: if (digitalRead(DccProcState.ExtIntPinNum)) return; break;
|
|
||||||
// }
|
|
||||||
// First compare the edge we're looking for to the pin state
|
|
||||||
switch (ISRWatch)
|
|
||||||
{
|
|
||||||
case CHANGE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RISING:
|
|
||||||
if (digitalRead(DccProcState.ExtIntPinNum) != HIGH)
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FALLING:
|
|
||||||
if (digitalRead(DccProcState.ExtIntPinNum) != LOW)
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// Bit evaluation without Timer 0 ------------------------------
|
// Bit evaluation without Timer 0 ------------------------------
|
||||||
uint8_t DccBitVal;
|
uint8_t DccBitVal;
|
||||||
static int8_t bit1, bit2 ;
|
static int8_t bit1, bit2 ;
|
||||||
static word lastMicros = 0;
|
static word lastMicros;
|
||||||
static byte halfBit, DCC_IrqRunning;
|
static byte halfBit, DCC_IrqRunning;
|
||||||
unsigned int actMicros, bitMicros;
|
unsigned int actMicros, bitMicros;
|
||||||
if ( DCC_IrqRunning ) {
|
if ( DCC_IrqRunning ) {
|
||||||
@@ -386,15 +336,10 @@ void ExternalInterruptHandler(void)
|
|||||||
DccRx.State = WAIT_START_BIT ;
|
DccRx.State = WAIT_START_BIT ;
|
||||||
// While waiting for the start bit, detect halfbit lengths. We will detect the correct
|
// While waiting for the start bit, detect halfbit lengths. We will detect the correct
|
||||||
// sync and detect whether we see a false (e.g. motorola) protocol
|
// sync and detect whether we see a false (e.g. motorola) protocol
|
||||||
|
|
||||||
#if defined ( __STM32F1__ )
|
#if defined ( __STM32F1__ )
|
||||||
detachInterrupt( DccProcState.ExtIntNum );
|
detachInterrupt( DccProcState.ExtIntNum );
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESP32
|
|
||||||
ISRWatch = CHANGE;
|
|
||||||
#else
|
|
||||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, CHANGE);
|
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, CHANGE);
|
||||||
#endif
|
|
||||||
halfBit = 0;
|
halfBit = 0;
|
||||||
bitMax = MAX_ONEBITHALF;
|
bitMax = MAX_ONEBITHALF;
|
||||||
bitMin = MIN_ONEBITHALF;
|
bitMin = MIN_ONEBITHALF;
|
||||||
@@ -438,15 +383,10 @@ void ExternalInterruptHandler(void)
|
|||||||
bitMin = MIN_ONEBITFULL;
|
bitMin = MIN_ONEBITFULL;
|
||||||
DccRx.BitCount = 0;
|
DccRx.BitCount = 0;
|
||||||
SET_TP4;
|
SET_TP4;
|
||||||
|
|
||||||
#if defined ( __STM32F1__ )
|
#if defined ( __STM32F1__ )
|
||||||
detachInterrupt( DccProcState.ExtIntNum );
|
detachInterrupt( DccProcState.ExtIntNum );
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESP32
|
|
||||||
ISRWatch = ISREdge;
|
|
||||||
#else
|
|
||||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
||||||
#endif
|
|
||||||
SET_TP3;
|
SET_TP3;
|
||||||
CLR_TP4;
|
CLR_TP4;
|
||||||
}
|
}
|
||||||
@@ -482,15 +422,10 @@ void ExternalInterruptHandler(void)
|
|||||||
DccRx.TempByte = 0 ;
|
DccRx.TempByte = 0 ;
|
||||||
}
|
}
|
||||||
SET_TP4;
|
SET_TP4;
|
||||||
|
|
||||||
#if defined ( __STM32F1__ )
|
#if defined ( __STM32F1__ )
|
||||||
detachInterrupt( DccProcState.ExtIntNum );
|
detachInterrupt( DccProcState.ExtIntNum );
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESP32
|
|
||||||
ISRWatch = ISREdge;
|
|
||||||
#else
|
|
||||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
||||||
#endif
|
|
||||||
CLR_TP1;
|
CLR_TP1;
|
||||||
CLR_TP4;
|
CLR_TP4;
|
||||||
break;
|
break;
|
||||||
@@ -519,16 +454,10 @@ void ExternalInterruptHandler(void)
|
|||||||
|
|
||||||
CLR_TP1;
|
CLR_TP1;
|
||||||
SET_TP4;
|
SET_TP4;
|
||||||
|
|
||||||
#if defined ( __STM32F1__ )
|
#if defined ( __STM32F1__ )
|
||||||
detachInterrupt( DccProcState.ExtIntNum );
|
detachInterrupt( DccProcState.ExtIntNum );
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESP32
|
|
||||||
ISRWatch = ISREdge;
|
|
||||||
#else
|
|
||||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
||||||
#endif
|
|
||||||
|
|
||||||
CLR_TP4;
|
CLR_TP4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -566,14 +495,8 @@ void ExternalInterruptHandler(void)
|
|||||||
DccRx.State = WAIT_PREAMBLE ;
|
DccRx.State = WAIT_PREAMBLE ;
|
||||||
bitMax = MAX_PRAEAMBEL;
|
bitMax = MAX_PRAEAMBEL;
|
||||||
bitMin = MIN_ONEBITFULL;
|
bitMin = MIN_ONEBITFULL;
|
||||||
#ifdef ESP32
|
|
||||||
portENTER_CRITICAL_ISR(&mux);
|
|
||||||
#endif
|
|
||||||
DccRx.PacketCopy = DccRx.PacketBuf ;
|
DccRx.PacketCopy = DccRx.PacketBuf ;
|
||||||
DccRx.DataReady = 1 ;
|
DccRx.DataReady = 1 ;
|
||||||
#ifdef ESP32
|
|
||||||
portEXIT_CRITICAL_ISR(&mux);
|
|
||||||
#endif
|
|
||||||
SET_TP3;
|
SET_TP3;
|
||||||
}
|
}
|
||||||
else // Get next Byte
|
else // Get next Byte
|
||||||
@@ -613,9 +536,6 @@ void writeEEPROM( unsigned int CV, uint8_t Value ) {
|
|||||||
#if defined(ESP8266)
|
#if defined(ESP8266)
|
||||||
EEPROM.commit();
|
EEPROM.commit();
|
||||||
#endif
|
#endif
|
||||||
#if defined(ESP32)
|
|
||||||
EEPROM.commit();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readyEEPROM() {
|
bool readyEEPROM() {
|
||||||
@@ -1379,9 +1299,6 @@ void NmraDcc::init( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, ui
|
|||||||
#if defined(ESP8266)
|
#if defined(ESP8266)
|
||||||
EEPROM.begin(MAXCV);
|
EEPROM.begin(MAXCV);
|
||||||
#endif
|
#endif
|
||||||
#if defined(ESP32)
|
|
||||||
EEPROM.begin(MAXCV);
|
|
||||||
#endif
|
|
||||||
// Clear all the static member variables
|
// Clear all the static member variables
|
||||||
memset( &DccRx, 0, sizeof( DccRx) );
|
memset( &DccRx, 0, sizeof( DccRx) );
|
||||||
|
|
||||||
@@ -1389,23 +1306,16 @@ void NmraDcc::init( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, ui
|
|||||||
MODE_TP2;
|
MODE_TP2;
|
||||||
MODE_TP3;
|
MODE_TP3;
|
||||||
MODE_TP4;
|
MODE_TP4;
|
||||||
|
ISREdge = RISING;
|
||||||
bitMax = MAX_ONEBITFULL;
|
bitMax = MAX_ONEBITFULL;
|
||||||
bitMin = MIN_ONEBITFULL;
|
bitMin = MIN_ONEBITFULL;
|
||||||
|
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, RISING);
|
||||||
|
|
||||||
DccProcState.Flags = Flags ;
|
DccProcState.Flags = Flags ;
|
||||||
DccProcState.OpsModeAddressBaseCV = OpsModeAddressBaseCV ;
|
DccProcState.OpsModeAddressBaseCV = OpsModeAddressBaseCV ;
|
||||||
DccProcState.myDccAddress = -1;
|
DccProcState.myDccAddress = -1;
|
||||||
DccProcState.inAccDecDCCAddrNextReceivedMode = 0;
|
DccProcState.inAccDecDCCAddrNextReceivedMode = 0;
|
||||||
|
|
||||||
ISREdge = RISING;
|
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
ISRWatch = ISREdge;
|
|
||||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, CHANGE);
|
|
||||||
#else
|
|
||||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, RISING);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Set the Bits that control Multifunction or Accessory behaviour
|
// Set the Bits that control Multifunction or Accessory behaviour
|
||||||
// and if the Accessory decoder optionally handles Output Addressing
|
// and if the Accessory decoder optionally handles Output Addressing
|
||||||
// we need to peal off the top two bits
|
// we need to peal off the top two bits
|
||||||
@@ -1509,19 +1419,10 @@ uint8_t NmraDcc::process()
|
|||||||
{
|
{
|
||||||
// We need to do this check with interrupts disabled
|
// We need to do this check with interrupts disabled
|
||||||
//SET_TP4;
|
//SET_TP4;
|
||||||
#ifdef ESP32
|
|
||||||
portENTER_CRITICAL(&mux);
|
|
||||||
#else
|
|
||||||
noInterrupts();
|
noInterrupts();
|
||||||
#endif
|
|
||||||
Msg = DccRx.PacketCopy ;
|
Msg = DccRx.PacketCopy ;
|
||||||
DccRx.DataReady = 0 ;
|
DccRx.DataReady = 0 ;
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
portEXIT_CRITICAL(&mux);
|
|
||||||
#else
|
|
||||||
interrupts();
|
interrupts();
|
||||||
#endif
|
|
||||||
#ifdef DCC_DBGVAR
|
#ifdef DCC_DBGVAR
|
||||||
countOf.Tel++;
|
countOf.Tel++;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
11
NmraDcc.h
11
NmraDcc.h
@@ -32,7 +32,7 @@
|
|||||||
// Uncomment the following Line to Enable Service Mode CV Programming
|
// Uncomment the following Line to Enable Service Mode CV Programming
|
||||||
#define NMRA_DCC_PROCESS_SERVICEMODE
|
#define NMRA_DCC_PROCESS_SERVICEMODE
|
||||||
|
|
||||||
// Uncomment the following line to Enable MultiFunction Decoder Operations
|
// Uncomment the following line to Enable MutliFunction Decoder Operations
|
||||||
#define NMRA_DCC_PROCESS_MULTIFUNCTION
|
#define NMRA_DCC_PROCESS_MULTIFUNCTION
|
||||||
|
|
||||||
// Uncomment the following line to Enable 14 Speed Step Support
|
// Uncomment the following line to Enable 14 Speed Step Support
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
#ifndef NMRADCC_IS_IN
|
#ifndef NMRADCC_IS_IN
|
||||||
#define NMRADCC_IS_IN
|
#define NMRADCC_IS_IN
|
||||||
|
|
||||||
#define NMRADCC_VERSION 201 // Version 2.0.1
|
#define NMRADCC_VERSION 200 // Version 2.0.0
|
||||||
|
|
||||||
#define MAX_DCC_MESSAGE_LEN 6 // including XOR-Byte
|
#define MAX_DCC_MESSAGE_LEN 6 // including XOR-Byte
|
||||||
|
|
||||||
@@ -96,10 +96,7 @@ typedef struct
|
|||||||
#define CV_MANUFACTURER_ID 8
|
#define CV_MANUFACTURER_ID 8
|
||||||
#define CV_29_CONFIG 29
|
#define CV_29_CONFIG 29
|
||||||
|
|
||||||
#if defined(ESP32)
|
#if defined(ESP8266)
|
||||||
#include <esp_log.h>
|
|
||||||
#define MAXCV SPI_FLASH_SEC_SIZE
|
|
||||||
#elif defined(ESP8266)
|
|
||||||
#include <spi_flash.h>
|
#include <spi_flash.h>
|
||||||
#define MAXCV SPI_FLASH_SEC_SIZE
|
#define MAXCV SPI_FLASH_SEC_SIZE
|
||||||
#elif defined( __STM32F1__)
|
#elif defined( __STM32F1__)
|
||||||
@@ -654,7 +651,7 @@ extern uint8_t notifyIsSetCVReady(void) __attribute__ ((weak));
|
|||||||
* notifyCVChange() Called when a CV value is changed.
|
* notifyCVChange() Called when a CV value is changed.
|
||||||
* This is called whenever a CV's value is changed.
|
* This is called whenever a CV's value is changed.
|
||||||
* notifyDccCVChange() Called only when a CV value is changed by a Dcc packet or a internal lib function.
|
* notifyDccCVChange() Called only when a CV value is changed by a Dcc packet or a internal lib function.
|
||||||
* it is NOT called if the CV is changed by means of the setCV() method.
|
* it is NOT called if the CV is chaged by means of the setCV() method.
|
||||||
* Note: It is not called if notifyCVWrite() is defined
|
* Note: It is not called if notifyCVWrite() is defined
|
||||||
* or if the value in the EEPROM is the same as the value
|
* or if the value in the EEPROM is the same as the value
|
||||||
* in the write command.
|
* in the write command.
|
||||||
|
|||||||
@@ -1,314 +0,0 @@
|
|||||||
// NMRA Dcc Multifunction Motor Decoder Demo
|
|
||||||
//
|
|
||||||
// Author: Alex Shepherd 2019-03-30
|
|
||||||
//
|
|
||||||
// This example requires these Arduino Libraries:
|
|
||||||
//
|
|
||||||
// 1) The NmraDcc Library from: http://mrrwa.org/download/
|
|
||||||
//
|
|
||||||
// These libraries can be found and installed via the Arduino IDE Library Manager
|
|
||||||
//
|
|
||||||
// This is a simple demo of how to drive and motor speed and direction using PWM and a motor H-Bridge
|
|
||||||
// It uses vStart and vHigh CV values to customise the PWM values to the motor response
|
|
||||||
// It also uses the Headling Function to drive 2 LEDs for Directional Headlights
|
|
||||||
// Apart from that there's nothing fancy like Lighting Effects or a function matrix or Speed Tables - its just the basics...
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <NmraDcc.h>
|
|
||||||
// Uncomment any of the lines below to enable debug messages for different parts of the code
|
|
||||||
//#define DEBUG_FUNCTIONS
|
|
||||||
//#define DEBUG_SPEED
|
|
||||||
//#define DEBUG_PWM
|
|
||||||
//#define DEBUG_DCC_ACK
|
|
||||||
//#define DEBUG_DCC_MSG
|
|
||||||
|
|
||||||
#if defined(DEBUG_FUNCTIONS) or defined(DEBUG_SPEED) or defined(DEBUG_PWM) or defined(DEBUG_DCC_ACK) or defined(DEBUG_DCC_MSG)
|
|
||||||
#define DEBUG_PRINT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// This is the default DCC Address
|
|
||||||
#define DEFAULT_DECODER_ADDRESS 3
|
|
||||||
|
|
||||||
// This section defines the Arduino UNO Pins to use
|
|
||||||
#ifdef __AVR_ATmega328P__
|
|
||||||
|
|
||||||
#define DCC_PIN 2
|
|
||||||
|
|
||||||
#define LED_PIN_FWD 5
|
|
||||||
#define LED_PIN_REV 6
|
|
||||||
#define MOTOR_DIR_PIN 12
|
|
||||||
#define MOTOR_PWM_PIN 3
|
|
||||||
|
|
||||||
// This section defines the Arduino ATTiny85 Pins to use
|
|
||||||
#elif ARDUINO_AVR_ATTINYX5
|
|
||||||
|
|
||||||
#define DCC_PIN 2
|
|
||||||
|
|
||||||
#define LED_PIN_FWD 0
|
|
||||||
#define LED_PIN_REV 1
|
|
||||||
#define MOTOR_DIR_PIN 3
|
|
||||||
#define MOTOR_PWM_PIN 4
|
|
||||||
|
|
||||||
#else
|
|
||||||
#error "Unsupported CPU, you need to add another configuration section for your CPU"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Some global state variables
|
|
||||||
uint8_t newLedState = 0;
|
|
||||||
uint8_t lastLedState = 0;
|
|
||||||
|
|
||||||
uint8_t newDirection = 0;
|
|
||||||
uint8_t lastDirection = 0;
|
|
||||||
|
|
||||||
uint8_t newSpeed = 0;
|
|
||||||
uint8_t lastSpeed = 0;
|
|
||||||
uint8_t numSpeedSteps = SPEED_STEP_128;
|
|
||||||
|
|
||||||
uint8_t vStart;
|
|
||||||
uint8_t vHigh;
|
|
||||||
|
|
||||||
// Structure for CV Values Table
|
|
||||||
struct CVPair
|
|
||||||
{
|
|
||||||
uint16_t CV;
|
|
||||||
uint8_t Value;
|
|
||||||
};
|
|
||||||
|
|
||||||
// CV Addresses we will be using
|
|
||||||
#define CV_VSTART 2
|
|
||||||
#define CV_VHIGH 5
|
|
||||||
|
|
||||||
// Default CV Values Table
|
|
||||||
CVPair FactoryDefaultCVs [] =
|
|
||||||
{
|
|
||||||
// The CV Below defines the Short DCC Address
|
|
||||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, DEFAULT_DECODER_ADDRESS},
|
|
||||||
|
|
||||||
// Three Step Speed Table
|
|
||||||
{CV_VSTART, 120},
|
|
||||||
{CV_VHIGH, 255},
|
|
||||||
|
|
||||||
// These two CVs define the Long DCC Address
|
|
||||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
|
||||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, DEFAULT_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 ;
|
|
||||||
|
|
||||||
uint8_t FactoryDefaultCVIndex = 0;
|
|
||||||
|
|
||||||
// This call-back function is called when a CV Value changes so we can update CVs we're using
|
|
||||||
void notifyCVChange( uint16_t CV, uint8_t Value)
|
|
||||||
{
|
|
||||||
switch(CV)
|
|
||||||
{
|
|
||||||
case CV_VSTART:
|
|
||||||
vStart = Value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CV_VHIGH:
|
|
||||||
vHigh = Value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
// This call-back function is called whenever we receive a DCC Speed packet for our address
|
|
||||||
void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps )
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_SPEED
|
|
||||||
Serial.print("notifyDccSpeed: Addr: ");
|
|
||||||
Serial.print(Addr,DEC);
|
|
||||||
Serial.print( (AddrType == DCC_ADDR_SHORT) ? "-S" : "-L" );
|
|
||||||
Serial.print(" Speed: ");
|
|
||||||
Serial.print(Speed,DEC);
|
|
||||||
Serial.print(" Steps: ");
|
|
||||||
Serial.print(SpeedSteps,DEC);
|
|
||||||
Serial.print(" Dir: ");
|
|
||||||
Serial.println( (Dir == DCC_DIR_FWD) ? "Forward" : "Reverse" );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
newDirection = Dir;
|
|
||||||
newSpeed = Speed;
|
|
||||||
numSpeedSteps = SpeedSteps;
|
|
||||||
};
|
|
||||||
|
|
||||||
// This call-back function is called whenever we receive a DCC Function packet for our address
|
|
||||||
void notifyDccFunc(uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_FUNCTIONS
|
|
||||||
Serial.print("notifyDccFunc: Addr: ");
|
|
||||||
Serial.print(Addr,DEC);
|
|
||||||
Serial.print( (AddrType == DCC_ADDR_SHORT) ? 'S' : 'L' );
|
|
||||||
Serial.print(" Function Group: ");
|
|
||||||
Serial.print(FuncGrp,DEC);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(FuncGrp == FN_0_4)
|
|
||||||
{
|
|
||||||
newLedState = (FuncState & FN_BIT_00) ? 1 : 0;
|
|
||||||
#ifdef DEBUG_FUNCTIONS
|
|
||||||
Serial.print(" FN 0: ");
|
|
||||||
Serial.print(newLedState);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_FUNCTIONS
|
|
||||||
Serial.println();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// This call-back function is called whenever we receive a DCC Packet
|
|
||||||
#ifdef DEBUG_DCC_MSG
|
|
||||||
void notifyDccMsg( DCC_MSG * Msg)
|
|
||||||
{
|
|
||||||
Serial.print("notifyDccMsg: ") ;
|
|
||||||
for(uint8_t i = 0; i < Msg->Size; i++)
|
|
||||||
{
|
|
||||||
Serial.print(Msg->Data[i], HEX);
|
|
||||||
Serial.write(' ');
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// This call-back 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
|
|
||||||
// So we will just turn the motor on for 8ms and then turn it off again.
|
|
||||||
|
|
||||||
void notifyCVAck(void)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_DCC_ACK
|
|
||||||
Serial.println("notifyCVAck") ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
digitalWrite(MOTOR_DIR_PIN, HIGH);
|
|
||||||
digitalWrite(MOTOR_PWM_PIN, HIGH);
|
|
||||||
|
|
||||||
delay( 8 );
|
|
||||||
|
|
||||||
digitalWrite(MOTOR_DIR_PIN, LOW);
|
|
||||||
digitalWrite(MOTOR_PWM_PIN, LOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_PRINT
|
|
||||||
Serial.begin(115200);
|
|
||||||
Serial.println("NMRA Dcc Multifunction Motor Decoder Demo");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Setup the Pins for the Fwd/Rev LED for Function 0 Headlight
|
|
||||||
pinMode(LED_PIN_FWD, OUTPUT);
|
|
||||||
pinMode(LED_PIN_REV, OUTPUT);
|
|
||||||
|
|
||||||
// Setup the Pins for the Motor H-Bridge Driver
|
|
||||||
pinMode(MOTOR_DIR_PIN, OUTPUT);
|
|
||||||
pinMode(MOTOR_PWM_PIN, OUTPUT);
|
|
||||||
|
|
||||||
|
|
||||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
|
||||||
Dcc.pin(DCC_PIN, 0);
|
|
||||||
|
|
||||||
Dcc.init( MAN_ID_DIY, 10, FLAGS_MY_ADDRESS_ONLY | FLAGS_AUTO_FACTORY_DEFAULT, 0 );
|
|
||||||
|
|
||||||
// Uncomment to force CV Reset to Factory Defaults
|
|
||||||
// notifyCVResetFactoryDefault();
|
|
||||||
|
|
||||||
// Read the current CV values for vStart and vHigh
|
|
||||||
vStart = Dcc.getCV(CV_VSTART);
|
|
||||||
vHigh = Dcc.getCV(CV_VHIGH);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
|
|
||||||
Dcc.process();
|
|
||||||
|
|
||||||
// Handle Speed changes
|
|
||||||
if(lastSpeed != newSpeed)
|
|
||||||
{
|
|
||||||
lastSpeed = newSpeed;
|
|
||||||
|
|
||||||
// Stop if speed = 0 or 1
|
|
||||||
|
|
||||||
if(newSpeed <= 1)
|
|
||||||
digitalWrite(MOTOR_PWM_PIN, LOW);
|
|
||||||
|
|
||||||
// Calculate PWM value in the range 1..255
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint8_t vScaleFactor;
|
|
||||||
|
|
||||||
if((vHigh > 1) && (vHigh > vStart))
|
|
||||||
vScaleFactor = vHigh - vStart;
|
|
||||||
else
|
|
||||||
vScaleFactor = 255 - vStart;
|
|
||||||
|
|
||||||
uint8_t modSpeed = newSpeed - 1;
|
|
||||||
uint8_t modSteps = numSpeedSteps - 1;
|
|
||||||
|
|
||||||
uint8_t newPwm = (uint8_t) vStart + modSpeed * vScaleFactor / modSteps;
|
|
||||||
|
|
||||||
#ifdef DEBUG_PWM
|
|
||||||
Serial.print("New Speed: vStart: ");
|
|
||||||
Serial.print(vStart);
|
|
||||||
Serial.print(" vHigh: ");
|
|
||||||
Serial.print(vHigh);
|
|
||||||
Serial.print(" modSpeed: ");
|
|
||||||
Serial.print(modSpeed);
|
|
||||||
Serial.print(" vScaleFactor: ");
|
|
||||||
Serial.print(vScaleFactor);
|
|
||||||
Serial.print(" modSteps: ");
|
|
||||||
Serial.print(modSteps);
|
|
||||||
Serial.print(" newPwm: ");
|
|
||||||
Serial.println(newPwm);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
analogWrite(MOTOR_PWM_PIN, newPwm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle Direction and Headlight changes
|
|
||||||
if((lastDirection != newDirection) || (lastLedState != newLedState))
|
|
||||||
{
|
|
||||||
lastDirection = newDirection;
|
|
||||||
lastLedState = newLedState;
|
|
||||||
|
|
||||||
digitalWrite(MOTOR_DIR_PIN, newDirection);
|
|
||||||
|
|
||||||
if(newLedState)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_FUNCTIONS
|
|
||||||
Serial.println("LED On");
|
|
||||||
#endif
|
|
||||||
digitalWrite(LED_PIN_FWD, newDirection ? LOW : HIGH);
|
|
||||||
digitalWrite(LED_PIN_REV, newDirection ? HIGH : LOW);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_FUNCTIONS
|
|
||||||
Serial.println("LED Off");
|
|
||||||
#endif
|
|
||||||
digitalWrite(LED_PIN_FWD, LOW);
|
|
||||||
digitalWrite(LED_PIN_REV, LOW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle resetting CVs back to Factory Defaults
|
|
||||||
if( FactoryDefaultCVIndex && Dcc.isSetCVReady())
|
|
||||||
{
|
|
||||||
FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array
|
|
||||||
Dcc.setCV( FactoryDefaultCVs[FactoryDefaultCVIndex].CV, FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
name=NmraDcc
|
name=NmraDcc
|
||||||
version=2.0.1
|
version=2.0.0
|
||||||
author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Müller, Sven (littleyoda), Hans Tanner
|
author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Müller, Sven (littleyoda)
|
||||||
maintainer=Alex Shepherd <kiwi64ajs@gmail.com>
|
maintainer=Alex Shepherd <kiwi64ajs@gmail.com>
|
||||||
sentence=Enables NMRA DCC Communication
|
sentence=Enables NMRA DCC Communication
|
||||||
paragraph=This library allows you to interface to a NMRA DCC track signal and receive DCC commands. The library has been tested on AVR ATTiny84/85 & ATMega88/168/328/32u4, ESP8266 and Teensy 3.x using the INT0/1 Hardware Interrupt and micros() ONLY and no longer uses Timer0 Compare Match B, which makes it much more portable to other platforms.
|
paragraph=This library allows you to interface to a NMRA DCC track signal and receive DCC commands. The library has been tested on AVR ATTiny84/85 & ATMega88/168/328/32u4, ESP8266 and Teensy 3.x using the INT0/1 Hardware Interrupt and micros() ONLY and no longer uses Timer0 Compare Match B, which makes it much more portable to other platforms.
|
||||||
|
|||||||
Reference in New Issue
Block a user