Good Morning all
I wounder if Anyone is available to look of a program and advise please
I have come into a project Three quarters though My predecessor had started the project then left but left Leaving me with loads of issues machine base and program base
The machine is controlled by a Nano basic but the program has two issues firstly the project spec stated length of paper from 250mm to 4m the but the program is operating 250mm to 2m as stated line 244
Also a very strange fault if the machine runs out of paper the start button needs to be pressed 3 times before normal operation
If Anyone has any ideas or can see any other possible issues will be gratefully appreciated
Unfortunately my background is Machine automation with plc controllers with ladder and scl and sql and robotics And very new to Arduino
//BLUEBOARD NO RUNON TIMER (B7)
// NOTES : STANDARD MACHINE CODE WITH JOG SWITCH RUN ON TIMER AND CUT SPEED CONTROL ON FAULT POT.(V4)
// The ardunio libraries have a timer limitation, in that we need the processor timer0/1 for PWM's and it uses the timer0/1 for delay/sleep functions
// The functions will still work, but just at the wrong speed/time.
// To tackle this there are defines that equate to real time periods
//
// Set Terminal to 115200
// A #define is used by the compiler, where ever the defined name appears in the code the value assigned is inserted
// Meaning you can define it in one place and only need to change it once. Reducing errors
// We use them here to set pin numbers. Pin numbers relate to the port pin of the processor (Not physical chip pin numbers)
#define LOAD_SPEED 160 // Speed used when loadSwitch is pressed. Max 255
#define PIN_AIN1 5 //
#define PIN_AIN2 6 //
#define PIN_FAULT_OUT 7 //
#define PIN_BIN1 9 //
#define PIN_BIN2 10 //
#define PIN_OC_POT A6 // Analog input, On board Pot
#define PIN_SPD_POT A5 // Analog input, On board Pot
#define FEED_BASE 125 // max 255
#define FEED_RATE 15 // step change per task interval (50mS) - max 255, DO NOT make larger than FEED_BASE
#define MAX_FEED_SPEED 255 // max 255, lower val = lower speed
#define CUT_BASE 180 // max 255
#define CUT_RATE 10 // step change per task interval (50mS) - max 255, DO NOT make larger than CUT_BASE
#define CUT_BRAKE 1 // 1 = BRAKE, 0 = NO BRAKE
#define MAX_CUT_SPEED 249 // max 255, lower val = lower speed
#define SLOW_CUT_SPEED 180 // max 255, lower val = lower speed
#define REV_CUT_SPEED 180 // max 255, lower val = lower speed
#define RUN_ON_TIME 0 //time in 50mS increments
// The DRV IC is connected via SPI and uses the following pins :
#define DRV_SPI_CS_PIN 8 // SPI CS Line
#define DRV_SPI_MOSI 11 // SPI Master out slave in
#define DRV_SPI_MISO 12 // SPI Master in slave out
#define DRV_SPI_CLK 13 // SPI Clock
#define DRV_RST 4 // Reset control input to DRV
#define DRV_SLEEP 3 // Sleep control input to DRV
#define DRV_FAULT 2 // Fault output from DRV
#define FAULT_PERIOD 10 // number of 50mS periods
#define MAX_FAULTS 10 // maximum faults allowed in above time before lockout
// The following is a list of register numbers in the DRV8704 IC
// Refer to the data sheet : http://www.ti.com/lit/ds/symlink/drv8704.pdf
// For details of what each register will do
#define DRV_REG_CTRL 0x00 //
#define DRV_REG_TORQUE 0x01 //
#define DRV_REG_OFF 0x02 //
#define DRV_REG_BLANK 0x03 //
#define DRV_REG_DECAY 0x04 //
#define DRV_REG_RESERVED 0x05 //
#define DRV_REG_DRIVE 0x06 //
#define DRV_REG_STATUS 0x07 //
// Read messages have the top bit set. Write messages do not
#define DRV_READ_MASK 0x80 //
#define DRV_WRITE_MASK 0x00 //
// This is an array, we use this to store a copy of the DRV registers
uint16_t DrvRegisterCache[8];
typedef enum SYS_STATE_T
{
SYS_STATE0 = 0,
SYS_STATE1,
SYS_STATE2,
SYS_STATE3,
SYS_STATE4
} SYS_STATE_T;
SYS_STATE_T CurrentState = SYS_STATE0;
// Store the Previous no of MS
unsigned long PrevMS = 0;
// Interval, as timer0 has been addjust for the PWM, the millis() does not provide MS timing,
// these interval values help convert the new time base to a known one
const long OneSecond_Interval = 64100;
const long HundredMS_Interval = 6410;
const long TenMS_Interval = 641;
// Select the sheduler tick interval
const long TickInterval = TenMS_Interval;
// These varibles will store the ADC value from each pot 0 to 1023
uint16_t OcPotVal;
uint16_t SpdPotVal;
char demandClear;
bool minLengthReached = true;
bool Active = false;
bool stopping = false; //Variable used to determine whether motors have just run, and need to stop.
int lengthNeeded = 0; //Variable used to track if a length is needed
int iteration = 0; //Used to keep track of how many times the loop iterates, used for timing between motor stopping.
int potIteration = 0; //used to keep track of loop iterations for mode 2.
int potLength = 0;
int lastState = 0;
int Iteration2 = 0;
int noPaper = 0;
// -----------------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------
// Set up the interface to the DRV
// ---------------------------------------------------------------
void DRV_Init ( void )
{
pinMode(DRV_FAULT, INPUT);
pinMode(DRV_SLEEP, OUTPUT);
pinMode(DRV_RST, OUTPUT);
pinMode(DRV_SPI_CS_PIN, OUTPUT);
pinMode(DRV_SPI_MOSI, OUTPUT);
pinMode(DRV_SPI_MISO, INPUT);
pinMode(DRV_SPI_CLK, OUTPUT);
// Take the chip out of reset and wake it up..
digitalWrite(DRV_SLEEP, HIGH);
digitalWrite(DRV_RST, LOW);
SPI.begin();
}
// ---------------------------------------------------------------
// Write to the DRV
// ---------------------------------------------------------------
void DRV_Write ( byte reg, uint16_t newValue )
{
uint8_t tempOut;
SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
// take the SS pin high to select the chip:
digitalWrite(DRV_SPI_CS_PIN, HIGH);
// We dont want the top four bits, DRV registers are 12bit
newValue = newValue & 0x0FFF;
// Send the DRV the address and value via SPI:
tempOut = ( (reg << 4) | DRV_WRITE_MASK );
tempOut = tempOut | (uint8_t)(( newValue >> 8 ) & 0x000F);
SPI.transfer( tempOut );
tempOut = (uint8_t)( newValue & 0x00FF);
SPI.transfer( newValue );
// take the SS pin low to de-select the chip:
digitalWrite(DRV_SPI_CS_PIN, LOW);
SPI.endTransaction();
}
// ---------------------------------------------------------------
// Read from the DRV
// ---------------------------------------------------------------
uint16_t DRV_Read ( byte reg )
{
uint16_t result = 0;
SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
// take the SS pin high to select the chip:
digitalWrite(DRV_SPI_CS_PIN, HIGH);
// To Read you must send the register value shifted up
// With bit7 set
result = SPI.transfer( (reg << 4) | DRV_READ_MASK );
result = result << 8;
result |= SPI.transfer(0x00);
result &= ~0x8000;
// take the SS pin low to de-select the chip:
digitalWrite(DRV_SPI_CS_PIN, LOW);
SPI.endTransaction();
return ( result );
}
// ---------------------------------------------------------------
// PWM_Init - Set up the PWM output
// ---------------------------------------------------------------
void PWM_Init ( void )
{
// PWM Setup, the configures the chips timer directly
// WARNING : this will interfer with the ardunio sleep/delay library so can not be used at the same time..
OCR0A = 0x00;
OCR0B = 0x00;
TCCR0A = 0b10100011;
TCCR0B = 0b00000001;
OCR1AH = 0x00;
OCR1BH = 0x00;
OCR1AL = 0x00;
OCR1BL = 0x00;
TCCR1A = 0b10100001;
TCCR1B = 0b00001001;
}
// ---------------------------------------------------------------
// setup - Called by the Ardunio library first
// ---------------------------------------------------------------
void setup()
{
// put your setup code here, to run once:
// open the serial port at 115200 bps
// Use the terminal to help debug your code..
//Serial.begin(115200);
// Set up the DRV interface/pins
DRV_Init();
pinMode(PIN_FAULT_OUT, OUTPUT);
pinMode(PIN_AIN1, OUTPUT);
pinMode(PIN_AIN2, OUTPUT);
pinMode(PIN_BIN1, OUTPUT);
pinMode(PIN_BIN2, OUTPUT);
pinMode(7, INPUT_PULLUP);
//pinMode(A2, INPUT_PULLUP);
//pinMode(A3, INPUT_PULLUP);
//pinMode(A4, INPUT_PULLUP);
digitalWrite(PIN_BIN1, LOW);
digitalWrite(PIN_BIN2, LOW);
digitalWrite(PIN_FAULT_OUT, LOW);
PWM_Init();
}
// ---------------------------------------------------------------
// InputLoop - Process the inputs and action the pwm output
// to the DRV
// ---------------------------------------------------------------
void InputLoop ()
{
static int stepsPer = 22; //This is how many steps of the potentiometer equals 50ms of motor running time. Use this to adjust length of paper.
//For example, 5 steps will mean if pot value reads 20, motors will run for 20/5 * 50ms = 200ms. Increasing this value will mean less length for the same pot reading, and vice versa for decreasing.
static int minLength = 15; //This is how many 50ms motor will run regardless of pot reading. Used mostly when pot is a low value (e.g. 20) and thus motors run for 100 ms, which is not long enough.
int footPedal = analogRead(A1);
int loadSwitch = analogRead(A0);
int potVal = analogRead(A3);
//decide which mode based on potentiometer's built-in switch.
int mode;
if (analogRead(A4) < 20) {
mode = 1;
}
else {
mode = 2;
}
int paperEye = analogRead(A2);
static int speed = 0;
//calculate pot input into length
potVal = potVal / stepsPer;
potVal = potVal + 10;
//MODE 1
if (mode == 1) {
//if loadSwitch is pressed and the motors are not in the process of stopping, run motors at speed defined in LOAD_SPEED
if (loadSwitch < 650 && !stopping) {
OCR1AL = LOAD_SPEED;
OCR1BL = 0x00;
OCR0A = LOAD_SPEED;
OCR0B = 0x00;
}
//if footPedal is high (>4v), run both motors forward at full speed, with acceleration ramp
else if (footPedal < 650 || !minLengthReached) {
if (Iteration2 < minLength) {
minLengthReached = false;
Iteration2 ++;
}
else {
minLengthReached = true;
}
//make sure there is enough room to ramp up
if (speed < (MAX_FEED_SPEED - FEED_RATE))
{
speed += FEED_RATE;
}
else
{
speed = MAX_FEED_SPEED;
}
//needs to stop when pedal is released.
stopping = true;
//set motors to speed as changed when ramping up (the above if statement)
OCR1AL = speed;
OCR1BL = 0x00;
OCR0A = speed;
OCR0B = 0x00;
}
//if motors need to stop, and speed is greater than stopped speed (FEED_BASE)(this is not strictly necessary, just sanity check), stop motors with delay between motors.
else if (stopping) {
//brake motor 1
OCR1AL = 0xFF;
OCR1BL = 0xFF;
//delay
if (iteration < 5 + 1) { //Change this number to change the delay betweens stopping. Each iteration takes 50ms, so a value of 6 means that 6*50ms = 300ms.
iteration ++;
}
else {
//reset iteration counter
iteration = 0;
//brake motor 2
OCR0A = 0xFF;
OCR0B = 0xFF;
//set speed to off
speed = FEED_BASE;
//stopping is complete, no longer needs to stop
stopping = false;
minLengthReached = true;
Iteration2 = 0;
}
}
//else feed is off
else
{
OCR1AL = 0x00;
OCR1BL = 0x00;
OCR0A = 0x00;
OCR0B = 0x00;
speed = FEED_BASE;
minLengthReached = true;
Iteration2 = 0;
Active = false;
}
}
//MODE 2
if (mode == 2) {
//if loadSwitch is pressed and the motors are not in the process of stopping, run motors at speed defined in LOAD_SPEED
if (loadSwitch < 650 && !stopping && lengthNeeded == 0) {
OCR1AL = LOAD_SPEED;
OCR1BL = 0x00;
OCR0A = LOAD_SPEED;
OCR0B = 0x00;
}
//if footpedal is high (>4v), do logic to switch Active true or false.
else if (footPedal < 650) {
if (lastState == 0) {
if (Active) {
Active = false;
lengthNeeded = 1;
stopping = true;
}
else {
Active = true;
}
lastState = 1;
}
}
//if a length is needed, run motors for time based on potentiometer input
else if (lengthNeeded == 1 && Active) {
noPaper ++;
if (potIteration < potVal + 1) {
if (speed < (MAX_FEED_SPEED - FEED_RATE))
{
speed += FEED_RATE;
}
else
{
speed = MAX_FEED_SPEED;
}
//needs to stop when pedal is released.
//stopping = true;
//set motors to speed as changed when ramping up (the above if statement)
OCR1AL = speed;
OCR1BL = 0x00;
OCR0A = speed;
OCR0B = 0x00;
potIteration ++;
}
else {
lengthNeeded = 0;
stopping = true;
potIteration = 0;
}
//change the less than thumber for potIteration to change the time it stops (number of 50ms so 20 = one second. However, if the potVal is less than this number, this function pretty much becomes irrelevant.
if (potIteration > 20 && paperEye > 100 ) {
lengthNeeded = 0;
stopping = true;
potIteration = 0;
Active = false;
}
}
//if motors need to stop, stop motors with delay between motors.
else if (stopping) {
//brake motor 1
OCR1AL = 0xFF;
OCR1BL = 0xFF;
//delay
if (iteration < 3 + 1) { //Change this number to change the delay betweens stopping. Each iteration takes 50ms, so a value of 6 means that 6*50ms = 300ms.
iteration ++;
}
else {
//reset iteration counter
iteration = 0;
//brake motor 2
OCR0A = 0xFF;
OCR0B = 0xFF;
//set speed to off
speed = FEED_BASE;
//stopping is complete, no longer needs to stop
stopping = false;
//lengthNeeded = 0;
//lastState = 0;
}
}
//if lengthNeeded equals 0 and paper eye detects empty space, and is Active, call lengthNeeded 1
else if (lengthNeeded == 0 && paperEye > 100 && Active) {
lengthNeeded = 1;
}
//else feed is off
else
{
OCR1AL = 0x00;
OCR1BL = 0x00;
OCR0A = 0x00;
OCR0B = 0x00;
speed = FEED_BASE;
lastState = 0;
}
}
if (paperEye < 100) {
noPaper = 0;
}
//change the less than thumber for potIteration to change the time it stops (number of 50ms so 20 = one second.
if (noPaper > 20 && paperEye > 100) {
lengthNeeded = 0;
stopping = true;
potIteration = 0;
Active = false;
noPaper = 0;
}
}
// ---------------------------------------------------------------
// PrintHex - Takes the supplied "num" and prints the value in
// readable hex over the serial port
// ---------------------------------------------------------------
void PrintHex ( uint16_t num )
{
char tmp[16];
char format[128];
sprintf(format, "0x%%.%dX", 4);
sprintf(tmp, format, num);
//Serial.print(tmp);
}
// ---------------------------------------------------------------
// ReadAllDrvRegisters - Read all of the DRV registers in to RAM
// ---------------------------------------------------------------
void ReadAllDrvRegisters ( void )
{
// Read all of the DRV registers in to memory
DrvRegisterCache[DRV_REG_CTRL] = DRV_Read(DRV_REG_CTRL);
DrvRegisterCache[DRV_REG_TORQUE] = DRV_Read(DRV_REG_TORQUE);
DrvRegisterCache[DRV_REG_OFF] = DRV_Read(DRV_REG_OFF);
DrvRegisterCache[DRV_REG_BLANK] = DRV_Read(DRV_REG_BLANK);
DrvRegisterCache[DRV_REG_DECAY] = DRV_Read(DRV_REG_DECAY);
DrvRegisterCache[DRV_REG_DRIVE] = DRV_Read(DRV_REG_DRIVE);
DrvRegisterCache[DRV_REG_STATUS] = DRV_Read(DRV_REG_STATUS);
}
// -----------------------------------------------------------------
// PrintAllDrvRegisters - This function will print out the cached
// registers to the terminal
// -----------------------------------------------------------------
void PrintAllDrvRegisters ( void )
{
// Serial.print("DRV Register 0 (CTRL) : ");
PrintHex(DrvRegisterCache[DRV_REG_CTRL]);
// Serial.print("\r\n");
// Serial.print("DRV Register 1 (DRV_REG_TORQUE) :");
PrintHex(DrvRegisterCache[DRV_REG_TORQUE]);
// Serial.print("\r\n");
// Serial.print("DRV Register 2 (DRV_REG_OFF) :");
PrintHex(DrvRegisterCache[DRV_REG_OFF]);
// Serial.print("\r\n");
// Serial.print("DRV Register 3 (DRV_REG_BLANK) :");
PrintHex(DrvRegisterCache[DRV_REG_BLANK]);
// Serial.print("\r\n");
// Serial.print("DRV Register 4 (DRV_REG_DECAY) :");
PrintHex(DrvRegisterCache[DRV_REG_DECAY]);
// Serial.print("\r\n");
// Serial.print("DRV Register 6 (DRV_REG_DRIVE) :");
PrintHex(DrvRegisterCache[DRV_REG_DRIVE]);
// Serial.print("\r\n");
// Serial.print("DRV Register 7 (DRV_REG_STATUS) :");
PrintHex(DrvRegisterCache[DRV_REG_STATUS]);
// Serial.print("\r\n");
}
// ---------------------------------------------------------------
// ScheduleTicked - Using the Millisecond count provided by Arduio
// provide time base for scheduled code
// ---------------------------------------------------------------
bool ScheduleTicked ( void )
{
unsigned long currentMS = millis();
bool ticked = false;
int difference;
// We will constantly compare the current MsCounter with the previous to see if we have reached the interval
// This is far better than using delay()
// Also note due to the PWM freq requirements timer0 has been modified meaning the millis() provided value is not in ms
// OneSecondInterval is calculated at the current pwm freq to give you one second timing..
if ((currentMS - PrevMS) >= TickInterval)
{
PrevMS = currentMS;
ticked = true;
}
else if (PrevMS > currentMS)
{
// The currentMS has rolled over
difference = (0xFFFFFFFF - PrevMS) + currentMS;
if ( difference >= TickInterval)
{
PrevMS = currentMS;
ticked = true;
}
}
return ( ticked );
}
bool toggle = false;
bool enableNextTime = true;
// ---------------------------------------------------------------
// loop is the Ardunio Main loop
// it will contastanly call this function..
// Process you inputs, make decisions then leave to repeat..
// ---------------------------------------------------------------
void loop()
{
bool ticked = ScheduleTicked();
static char fltCount = 0;
static char fltTimer = 0;
static char faultPending = 0;
if (ticked)
{
ticked = false;
// You can now schedule your code against a known time base (the interval)
// NOTE : If the interval is too short the code execute might take longer to run than the TickInterval period
//toggle = !toggle;
//digitalWrite(PIN_FAULT_OUT, toggle);
// State machine example ..
// Your product may do different things at different times
// Sometimes it helps to break this down in to states
switch ( CurrentState )
{
case SYS_STATE0 :
// Read all of the DRV Registers
ReadAllDrvRegisters();
//next state
CurrentState = SYS_STATE1;
break;
case SYS_STATE1 :
// Print out registers so we can check them
PrintAllDrvRegisters();
//next state
CurrentState = SYS_STATE2;
break;
case SYS_STATE2 :
// Capture input demands and set PWM outputs
InputLoop();
//next state
CurrentState = SYS_STATE3;
break;
case SYS_STATE3 :
// Read the input pots
OcPotVal = analogRead(PIN_OC_POT);
SpdPotVal = analogRead(PIN_SPD_POT);
//print out ADC values
//Serial.print("OC Pot : ");
//Serial.print(OcPotVal);
//Serial.print(" - SPD Pot : ");
//Serial.print(SpdPotVal);
// Serial.print("\r\n");
// next state
CurrentState = SYS_STATE4;
break;
case SYS_STATE4 :
// Write to the DRV chip
if ( enableNextTime )
{
//Serial.println("Enable Motor (DRV)");
// BIT0 set to enable the motor
DRV_Write( DRV_REG_CTRL, 0x0201 );
DRV_Write( DRV_REG_BLANK, 0x00FF );
//DRV_Write( DRV_REG_DRIVE, 0x0FAE );
DRV_Write( DRV_REG_DRIVE, 0x0FAD ); //OCP trip set to 89A (500mV @ Rds of 5.6mR)
}
else
{
//Serial.println("Disable Motor (DRV)");
// BIT0 cleared to disable the motor
DRV_Write( DRV_REG_CTRL, 0x0300 );
}
//enableNextTime = !enableNextTime;
//if there was a fault to clear from last time and we haven't faulted too many times then clear the fault to allow retry
if ((faultPending) && (demandClear))
{
DRV_Write( DRV_REG_STATUS, 0x0000);
faultPending = 0;
}
//if all demands have been removed then clear the fault counter
if (demandClear)
{
fltCount = 0;
}
//if the fault line is active (low) then flag up a fault for next time round
if (digitalRead(DRV_FAULT) == 0)
{
fltTimer = 0;
fltCount++;
//prevent overflow of counter
if (fltCount >= MAX_FAULTS)
{
fltCount = MAX_FAULTS;
}
faultPending = 1;
}
/*
//clear fault counter after timeout
if(fltTimer++ > FAULT_PERIOD)
{
fltCount = 0;
fltTimer = 0;
}
//check for driver fault and clear
if(digitalRead(DRV_FAULT) == 0)
{
fltTimer = 0;
fltCount++;
//if we havent exceeded max faults then retry
if(fltCount < MAX_FAULTS)
{
DRV_Write( DRV_REG_STATUS, 0x0000);
}
//else prevent overflow of counter
else
{
fltCount = MAX_FAULTS;
}
}
*/
// Back to the begining!
CurrentState = SYS_STATE0;
break;
}
}
else
{
// some code you might want to run all the time as fast as possible
// if so put it here ..
// NOTE : again if the code here takes a long time to execute it can delay the scheduled code..
}
}
type or paste code here