@LarryD
Ok, Posting in the code below, yes function is being called inside the loop. I thought I was using the code tags? Am I not using them correctly?
Have not made the changes will wait for you to revert once you have gone through it to get a better understanding. ISR is written for the ATmega 4809 Arduino nano Again, thank you,
/* Disclaimer!!!!!!!
GAP RECORDINGS Pulltruder - Firmware V1.0
If you find this project useful remember to
give credit to the designers please.
This is NOT intended to be used outside the scope
of it's intended design, you consent to using this
code and it's entirety AT YOUR OWN RISK!
There are various sources that code snippets were used from.
Some of this coding is mine but some of it comes from
other libraries and other youtubers such as but
not limited to:
Electronoobs https://www.youtube.com/@ELECTRONOOBS,
JRT3D, https://www.youtube.com/@JRT3D/videos
Thank you to Mike McCauly and Patrick Wasp
for the AccelStepper Library.
Website: http://www.airspayce.com/mikem/arduino/AccelStepper/
Github: https://github.com/waspinator/AccelStepper
Finally, thank you to red_car on the Arduino Forum for help
with the final, but all important safty coding for this project.
https://forum.arduino.cc/u/red_car/summary
Other coding and sources are linked in futher down!
FINALLY, THIS PROJECT AND IT'S CODING WERE DEVELOPED AROUND
THE ARDUINO NANO EVERY, IF YOU WANT TO USE A PLAIN NANO
YOU WILL NEED TO REFER TO ELECTRONOOBS PROGRAMING AND ADAPT
FROM THERE. I AM BY NO MEANS A KNOWLAGABLE PROGRAMMER!!!!!
*/
/* UI Setup: NOTES!!
In these lines below you can set the temperature (Line 41) that you want
the heating block to heat to. And then at (Line 42) you can set the speed
that the motor must turn/run at. This is a (HIGHLY NON) scientific approach
to getting the right speed for the correct extrusion width. The next (lines 44 /45)
are for the fan hysteries, YOU MUST USE FLOATING POINT NUMERICS PLEASE!
Failing to do this will lead to fans not running. Also ALLOW AT LEAST 2.00
degrees centigrade between on and off so that your fans do not cycle or chatter.
*/
//UI SETUP !!!!!!NB!!!!!! PLEASE SET UP THE NEXT FEW LINES ACCORDING TO YOUR NEEDS!! Thank you.
float set_temperature = 200; // Default temperature setpoint. Find what works and preset this here.
int pullingSpeed = 2000; // Set speed for my motor running at 62.5kHz PWM with
/////////////////////////////////// 1/16th steps this works out to 300mm or 30cm / minute.
float setFanON = 50.00; // Here you set the FAN ON temp.
float setFanOFF = 35.00; // Here you can set theFAN OFF temp.
/*
The Proccessor or PWM speed sketch is from @HiboTronix
It can be found here: https://hibotronix.co.uk/electronics/arduino-nano-every-atmega4809-pwm-code
NB!!!This sketch DIRECTLY INFLUENCES STEPPER SPEED! If your stepper is set to microstepping be
forewarned that you will experiance LOWER speeds than when running @ full steps! The advantage of
microstepping here is a more "LINEAR" pulling or extruding of the filament. The step pin is driven
@ PWM frequency which means that at 970Hz you might only see a max of around 1000 stepps / second.
*/
/* Defining PWM Frequency */
#define PWM_NORMAL 0 // 16MHz CPU = 970Hz PWM, 20MHz CPU = 1221Hz PWM
#define PWM_MEDIUM 1 // 16MHz CPU = 31250Hz PWM, 20MHz CPU = 39063Hz PWM
#define PWM_FAST 2 // 16MHz CPU = 62500Hz PWM, 20MHz CPU = 78125Hz PWM
/* Configuring LCD Type and Address */
#include <Wire.h> // You will need to include this library.
#include <LiquidCrystal_I2C.h> // And this one.
LiquidCrystal_I2C lcd(0x27, 20, 4); // Sometimes the adress is not 0x27. Change to 0x3f if it dosn't work.
/*
Thermistors NEED a library if you are using the 100k glass bead type from a 3D printer the below library "should" work.
Original sketch from Andrei @ electronoobs.com
Thermistor library also from him. PID config ALSO from Andrei
*/
#include <thermistor.h> // Download it here: https://electronoobs.com/eng_arduino_thermistor.php
thermistor therm1(A0, 0); // Connect thermistor on (pin) A0, (Thermistor) 0 represents TEMP_SENSOR_0 ( configuration.h for more)
/* Configuring I/O for Fans, Heater Buttons and more */
int PWM_Fan = 6; // Pin for PWM signal to the fan MOSFET driver
int PWM_pin = 3; // Pin for PWM signal to the heater MOSFET driver In all fairness this device will need a heatsink
int LED = 13; // Pin for visual status of motor engaged or running
int heaterPWM = 255; // Setting up Max PWM for Heater cartridge, this setting can also be used to limit current draw from the PSU (Setting 0 -255)
//Variables
float temperature_read = 0.0;
float PID_error = 0.0;
float previous_error = 0.0;
float elapsedTime, Time, timePrev;
int TEMP_CHECK_INTERVAL = 2000;
float PID_value = 0.0;
float last_set_temperature = 0.0;
float newTemp;
float newPID;
float currTemp;
float currPID;
float overTemptime = 1000L * 60L;
//Smoothing Temp Readings
const int numReadings = 10;
int readings[numReadings];
int readIndex = 0;
float avgTemp;
int thisReading;
// Min and Max motor speed (PWM Frequency dependant)
const int max_speed = 12000; // Max Posible speed @ specified PWM frequency.
const int min_speed = 0; // Minimum speed = off.
// Stepper Driver pin allocation.
const int EN = 2; // Enable disable pin to Stepper driver.
const int STEP = 5; // Stepping pin to Stepper driver.
const int DIR = 4; // Direction pin to Stepper driver.
// Button States for heater and stepper de/activation and run out detection.
const int but1 = 7; // Stepper Run / Stop button.
const int but2 = 10; // Heating on / off button.
const int Micro1 = 11; // Filament runout sensor. (still to implement Hardware)
bool but1_state = true;
bool activate_stepper = false;
bool but2_state = true;
bool activate_Heating = false;
bool heating_active = true;
bool reached_target_temp = false;
int currMicro1state = HIGH;
int prevMicro1state = HIGH;
/*
AccelStepper is maintained and written by AirSpayce.com
@https://www.airspayce.com/mikem/arduino/AccelStepper/
Make sure to read all Calls and functions. This is NOT my software.
*/
#include <AccelStepper.h>
// Define a stepper and the pins it will use
AccelStepper stepper1(1, STEP, DIR); // (Type of driver: with 2 pins, STEP, DIR).
//PID Constants
//////////////////////////////////////////////////////////
int kp = 95.0; int ki = 30.0; int kd = 5.0;
//////////////////////////////////////////////////////////
int PID_p = 0; int PID_i = 0; int PID_d = 0;
float last_kp = 0;
float last_ki = 0;
float last_kd = 0;
int PID_values_fixed = 0;
void setup() {
// set_PWM(PWM_NORMAL); // Uncomment for Normal PWM frequency.
// set_PWM(PWM_MEDIUM); // Uncomment for Medium PWM frequency.
set_PWM(PWM_FAST); // Uncomment for Fast PWM frequency.
Serial.begin (115200);
pinMode(EN, OUTPUT); // Setting the EN pinmode to output.
digitalWrite(EN, HIGH); // Writing the EN pin to Disable the stepper driver output.
stepper1.setMaxSpeed(max_speed); // Setting the "max Speed" Parameter for the Stepper library.
pinMode(but1, INPUT_PULLUP); // Setting the pin mode for button1.
pinMode(but2, INPUT_PULLUP); // Setting the pin mode for button2.
pinMode (Micro1, INPUT_PULLUP); // Setting the pin mode for MicroSwitch 1 (filament runout sensor).
pinMode(LED, OUTPUT); // Setting the pin mode for the LED.
digitalWrite(LED, LOW); // Setting the initial status of the LED to off.
pinMode(PWM_pin, OUTPUT); // Setting the pin mode for the heater pin.
analogWrite(PWM_pin, 0); // Setting the heater pin to off.
pinMode (PWM_Fan, OUTPUT); // Setting the pin mode for the fan pin.
TCB0.INTCTRL |= TCB_CAPT_bm; // Enabling Timer B0's Interrupt.
attachInterrupt(digitalPinToInterrupt(but1), stepRun, FALLING); //Attaching interrupt to motor Run/Stop button.
attachInterrupt(digitalPinToInterrupt(but2), butt_Heating, FALLING); // Attaching itnterrupt to Heating On/Off Button.
lcd.init(); // Initialising LCD communication.
lcd.backlight(); // Switching on the backlight.
lcd.clear(); // Clearing whatever might be on the LCD.
// Setting up and printing stationary text, this saves on processing time
// and program memory as this does not have to be written over and over.
lcd.setCursor(0, 0); // Setting the cursor pozition, row 0.
lcd.print("TA: "); // Printing text.
lcd.setCursor (10, 0); // Setting the cursor pozition, row 0.
lcd.print ("TS: "); // Printing text.
lcd. setCursor (0, 1); // Setting the cursor pozition, row 1.
lcd.print ("Speed: "); // Printing text.
lcd.setCursor(12, 1); // Setting the cursor pozition, row 1.
lcd.print("PID: "); // Printing text.
lcd.setCursor (0, 2); // Setting the cursor pozition, row 2.
lcd.print ("Motor:"); // Printing text.
lcd.setCursor (12, 2); // Setting the cursor pozition, row 2.
lcd.print ("Fan: "); // Printing text.
lcd.setCursor (0, 3); // Setting the cursor pozition, row 3.
lcd.print ("Heating: "); // Printing text.
/*Clearing/ zeroing posible readings*/
readings[thisReading] = 0;
}
void loop() {
runOut(); // Filament runout function.
butt_Heating(); // Button ON/OFF for heating.
stepRun(); // Stepper run function.
fan_Control();
heating_routine(); //
PID_Heating(); // Temperature function.
lcdPrint(); // LCD Printing function.
// serialPrint();
safetyAbort ();
}
// Checking the filament sensor.
void runOut() { // GAP code
currMicro1state = digitalRead(Micro1); // Setting the place holder to read a value from an Input.
if (currMicro1state == LOW && prevMicro1state == HIGH) { // If this is the state then do the following:
lcd.setCursor(12, 3); // Setting the Cursor position.
lcd.print (" Extrude"); // Write this to the screen for this function.
}
else if (currMicro1state == HIGH && prevMicro1state == LOW) { // Otherwise, if this is the state then do the following:
lcd.setCursor(12, 3); // Setting the Cursor position.
lcd.print ("!RUNOUT!"); // Write this to the screen for this function.
activate_Heating = !activate_Heating; // Turn off the hot end heating element.
activate_Heating = false; // Keep Heating element turned off inside this function once turned off.
} prevMicro1state = currMicro1state; // The previous Micro switch state is now the current state.
}
void butt_Heating() { // Chat GPT-3 Assisted code
heating_active = true;
if (!digitalRead(but2) && but2_state) { // Are we reading the digital input as triggered?
but2_state = false; // If not.
activate_Heating = !activate_Heating; // The active heating function will remain disabled.
}
else if (digitalRead(but2) && !but2_state) { // If we are reading the digital input as triggered,
but2_state = true; // Then the state will be LOW.
}
if (activate_Heating) { // If the active heating function is called,
// check if the temperature has reached the target temperature
if (!reached_target_temp) {
// code to check temperature and wait until it reaches target temperature
reached_target_temp = true; //when temperature reaches target
}
(analogWrite(PWM_pin, PID_value)); // continue with heating code
} else {
// heating is not active, set reached_target_temp = false
reached_target_temp = false;
analogWrite(PWM_pin, 0); // The PWM pin for the heater is off!
}
}
// Run or Stop the Stepper motor.
void stepRun() {
if (!digitalRead(but1) && but1_state) { // Are we reading the digital input?
but1_state = false; // If not.
activate_stepper = !activate_stepper; // The active Stepper function will remain disabled.
}
else if (digitalRead(but1) && !but1_state) { // If the active Stepping function is called,
but1_state = true; // The step pin for the Stepper will be pullsed with the Pulling Value.
}
if (activate_stepper) { // If the stepper function is active.
digitalWrite(LED, HIGH); // Enable the LED for visual confirmation of the command.
digitalWrite(EN, LOW); // Enable the Stepper dirver module.
stepper1.setSpeed(pullingSpeed); // Set Stepper 1's speed to the pulling value.
//stepper1.runSpeed(); // The speed (PWM) pulse value is handeled inside the ISR.
}
else // Otherwise,
{
digitalWrite(EN, HIGH); // Disable the Stepper dirver module.
digitalWrite(LED, LOW); // Disable the LED for visual confirmation of the command.
stepper1.setSpeed(0); // Set Stepper 1's speed to the stop value.
stepper1.runSpeed(); // is set to 0.
}
}
// Fan Control.
void fan_Control() {
if (avgTemp > setFanON) {
analogWrite(PWM_Fan, 255);
} else if (avgTemp < setFanOFF) {
analogWrite(PWM_Fan, 0);
}
}
// Function to check if heating is taking place or not and to see if temp is reached or not before calling the PID_Heating Function
void heating_routine() {
unsigned long start_time = millis(); // store the start time
while (!reached_target_temp) {
PID_Heating(); // check temperature and update PID values
if (temperature_read >= set_temperature) { // check if temperature has reached target
reached_target_temp = true;
break;
}
if (millis() - start_time >= TEMP_CHECK_INTERVAL) { // check if TEMP_CHECK_INTERVAL has passed
break;
}
}
}
// Calculating PID values and temp readings. Added fan control.
void PID_Heating() {
// First we read the real value of temperature
temperature_read = therm1.analog2temp(); // read temperature
//Next we calculate the error between the setpoint and the real value
PID_error = set_temperature - temperature_read + 4; //GAP (+6 I found this setting the error point to high +2 was to low)
//Calculate the P value
PID_p = 0.01 * kp * PID_error;
//Calculate the I value in a range on +-4
PID_i = 0.01 * PID_i + (ki * PID_error);
//For derivative we need real time to calculate speed change rate
timePrev = Time; // The previous time is stored before the actual time read
Time = millis(); // Actual time read
elapsedTime = (Time - timePrev) / 1000;
//Now we can calculate the D calue
PID_d = 0.01 * kd * ((PID_error - previous_error) / elapsedTime);
//Final total PID value is the sum of P + I + D
PID_value = PID_p + PID_i + PID_d;
//We define PWM range between 0 and 255
PID_value = min(heaterPWM, max(0, PID_value));
previous_error = PID_error; // Remember to store the previous error for next loop.
// read from the sensor:
readings[readIndex] = temperature_read;
// advance to the next position in the array:
readIndex = (readIndex + 1) % numReadings;
int total = 0;
for (thisReading = 0; thisReading < numReadings; thisReading++) {
total += readings[thisReading];
}
avgTemp = total / numReadings;
}
// Printing info to LCD.
void lcdPrint() {
currTemp = temperature_read; // Setting place holder to read from temp function
if (newTemp != currTemp ) { // If the new temp is not = to the current temp do the following:
// lcd.setCursor(0, 0); // Printed in setup
// lcd.print("TA: "); // Printed in setup
lcd.setCursor(4, 0);
lcd.print (" ");
lcd.setCursor(4, 0); // Setting Cursor Position
lcd.print(avgTemp , 0); // Writing new Temp Characters.
// lcd.setCursor (10, 0); // Printed in setup
// lcd.print ("TS: "); // Printed in setup
lcd.setCursor(14, 0); // Setting Cursor Position
lcd.print(set_temperature, 0); // Writing new SET Temp Characters.
} newTemp = currTemp; // Setting new temp to the current temp
lcd.setCursor (7, 1); // Setting Cursor Position
lcd.print(pullingSpeed); // Writing set motor Speed.
currPID = PID_value; // Setting PID place holder to read actual PID Value.
if (newPID != currPID) { // If the new PID value is not = to the current PID value, do the following:
// lcd.setCursor(12, 1); // Printed in setup.
// lcd.print("PID: "); // Printed in setup.
lcd.setCursor(17, 1); // Setting Cursor Position.
lcd.print (" "); // Used to clear provius PID Characters.
lcd.setCursor(17, 1); // Resetting Cursor to write new Characters.
lcd.print(currPID, 0); // Writing new PID Characters.
} newPID = currPID; // New PID value is now the current PID value.
if (digitalRead(LED) == HIGH) { // If the LED is ON.
// lcd.setCursor (0, 2); // Printed in setup.
// lcd.print ("Motor:"); // Printed in setup.
lcd.setCursor (7, 2); // Setting Cursor Position.
lcd.print ("Run "); // Writing text for that set function.
} else { // Otherwise if the function is:
// lcd.setCursor (0, 2); // Printed in setup
// lcd.print ("Motor: "); // Printed in setup
lcd.setCursor (7, 2); // Setting Cursor Position.
lcd.print ("Stop"); // Writing text for that set function.
}
if (avgTemp > setFanON ) { // If the average temperature is higher than this value.
// lcd.setCursor (12, 2); // Printed in setup.
// lcd.print ("Fan: "); // Printed in setup.
lcd.setCursor (17, 2); // Setting Cursor Position.
lcd.print ("On "); // Writing text for that set function.
}
if (avgTemp < setFanOFF) { // If the average temperature is lower than this value.
// lcd.setCursor (12, 2); //Printed in setup.
// lcd.print ("Fan: "); //Printed in setup.
lcd.setCursor (17, 2); // Setting Cursor Position.
lcd.print ("Off"); // Writing text for that set function.
}
if (activate_Heating) { // If the heating function is active.
// lcd.setCursor (0, 3); // Printed in setup.
// lcd.print ("Heating: "); // Printed in setup.
lcd.setCursor (9, 3); // Setting Cursor Position.
lcd.print ("On "); // Writing text for that set function.
} else { // Otherwise if the function is:
// lcd.setCursor (0, 3); // Printed in setup.
// lcd.print ("Heating: "); // Printed in setup.
lcd.setCursor (9, 3); // Setting Cursor Position.
lcd.print ("Off"); // Writing text for that set function.
}
}
void serialPrint() {
Serial.println (avgTemp, 0);
Serial.println (set_temperature, 0);
Serial.println (currPID, 0);
}
void safetyAbort () {
unsigned long overTemptimer = millis(); // Start over temp timer
if ((activate_Heating) && avgTemp >= set_temperature) {
}
if (millis() - overTemptimer >= overTemptime) {
activate_Heating = !activate_Heating; // Turn off the hot end heating element.
activate_Heating = false; // Keep Heating element turned off inside this function once turned off.
lcd.clear ();
lcd.setCursor (0, 2);
lcd.print ("!!HEATING ERROR!!");
lcd.setCursor (0, 3);
lcd.print ("POWER CYCLE");
}
}
//PWM function to set Frequency of PWM output pins.
void set_PWM(int option) {
cli(); // Disable Interrupts
switch (option) {
case PWM_MEDIUM:
TCB0_CTRLA = (TCB_CLKSEL_CLKDIV2_gc) | (TCB_ENABLE_bm);
TCB1_CTRLA = (TCB_CLKSEL_CLKDIV2_gc) | (TCB_ENABLE_bm);
TCB2_CTRLA = (TCB_CLKSEL_CLKDIV2_gc) | (TCB_ENABLE_bm);
break;
case PWM_FAST:
TCB0_CTRLA = (TCB_CLKSEL_CLKDIV1_gc) | (TCB_ENABLE_bm);
TCB1_CTRLA = (TCB_CLKSEL_CLKDIV1_gc) | (TCB_ENABLE_bm);
TCB2_CTRLA = (TCB_CLKSEL_CLKDIV1_gc) | (TCB_ENABLE_bm);
break;
case PWM_NORMAL:
default:
TCB0_CTRLA = (TCB_CLKSEL_CLKTCA_gc) | (TCB_ENABLE_bm);
TCB1_CTRLA = (TCB_CLKSEL_CLKTCA_gc) | (TCB_ENABLE_bm);
TCB2_CTRLA = (TCB_CLKSEL_CLKTCA_gc) | (TCB_ENABLE_bm);
}
sei(); // Enable Interrupts
}
// ISR for buttons.
ISR(TCB0_INT_vect) {
TCB0.INTFLAGS = TCB_CAPT_bm; //Clear the interrupt flag
stepper1.runSpeed(); // Set Stepper 1's speed (PWM) to the pulling value.
}
/*End of Program */