Minimal sketch:
/********************************************************************************
* PrinterCaptureInterrupt.ino
* ------------------
* Monitor a parallel port printer output and capture each character. Output the
* character on the USB serial port so it can be captured in a terminal program.
*
* By............: Rich Mellor - simple based on version by Paul Jewell 29th January 2015
* Date..........: 5th December 2023
* Version.......: 0.1a
* Modification : Change Interrupt Routine so Arduino respond "faster" to Printer
* Writing Busy Signal directly from interrupt routine
* Ecirbaf 12 Jan 2017
* Test on a PC with a "generic Printer Text only" printer
* Printing a test page OK
* Even if using somme accent characters
* Depend How your Terminal Software is handling that.
*-------------------------------------------------------------------------------
* Wiring Layout
* -------------
*
* Parallel Port Output Arduino Input
* -------------------- -------------
* Name Dir. Pin Name Pin
* ---- ---- --- ---- ---
* nSTROBE > 1................INT0 2 (as interupt)
* DATA BYTE > 2-9.......................3-10
* nACK < 10.........................11
* BUSY < 11.........................12
* OutofPaper < 12................GND
* Selected < 13.................5v
* GND <> 18-25................GND
*-------------------------------------------------------------------------------
********************************************************************************/
#include "Arduino.h"
#include "pins_arduino.h"
//define the pins
//25 pin printer port
#define PRN_SelectIn 2 // DB25 Pin 13 SelectIn OUTPUT
#define PRN_PERROR 3 // DB25 Pin 12 Paper Out OUTPUT
#define PRN_STROBE 4 // DB25 Pin 1 Strobe INPUT
#define PRN_AutoFeed 5 // DB25 Pin 14 Autofeed INPUT
#define PRN_NFault 6 // DB25 Pin 15 Error OUTPUT
#define PRN_INT 7 // DB25 Pin 16 Reset INPUT
#define PRN_SELECT 8 // DB25 Pin 17 Select INPUT
#define PRN_ACK 9 // DB25 Pin 10 Ack OUTPUT
#define PRN_BUSY 10 // DB25 Pin 11 BUSY OUTPUT
#define PRN_D0 A0 // DB25 Pin 2 DATA_0 INPUT
#define PRN_D1 A1 // DB25 Pin 3 DATA_1 INPUT
#define PRN_D2 A2 // DB25 Pin 4 DATA_2 INPUT
#define PRN_D3 A3 // DB25 Pin 5 DATA_3 INPUT
#define PRN_D4 A4 // DB25 Pin 6 DATA_4 INPUT
#define PRN_D5 A5 // DB25 Pin 7 DATA_5 INPUT
#define PRN_D6 A6 // DB25 Pin 8 DATA_6 INPUT
#define PRN_D7 A7 // DB25 Pin 9 DATA_7 INPUT
byte myChar;
bool strobeState = true;
enum States {
READY,
BUSY,
ACK
} State;
ISR(PCINT0_vect) {
// state = !state;
// handle pin change interrupt for D0 to D7 here
} // end of PCINT0_vect
ISR(PCINT1_vect) {
// state = !state;
// handle pin change interrupt for A0 to A5 here
} // end of PCINT1_vect
ISR(PCINT2_vect) {
if (digitalRead(PRN_STROBE) == HIGH) {
// Set the Busy Signal true - to stop the centronics sending more data
digitalWrite(PRN_BUSY, true);
digitalWrite(LED_BUILTIN, LOW);
// Read all of the data pins quickly
ProcessChar();
State = ACK;
}
// handle pin change interrupt for PCINT16 to PCINT23 here
} // end of PCINT2_vect
void setup() {
// Configure pins
pinMode(PRN_STROBE, INPUT_PULLUP);
pinMode(PRN_D0, INPUT_PULLUP);
pinMode(PRN_D1, INPUT_PULLUP);
pinMode(PRN_D2, INPUT_PULLUP);
pinMode(PRN_D3, INPUT_PULLUP);
pinMode(PRN_D4, INPUT_PULLUP);
pinMode(PRN_D5, INPUT_PULLUP);
pinMode(PRN_D6, INPUT_PULLUP);
pinMode(PRN_D7, INPUT_PULLUP);
pinMode(PRN_AutoFeed, INPUT_PULLUP);
pinMode(PRN_SelectIn, INPUT_PULLUP);
pinMode(PRN_INT, INPUT_PULLUP);
//setup the outputs
pinMode(PRN_SELECT, OUTPUT);
pinMode(PRN_PERROR, OUTPUT);
pinMode(PRN_BUSY, OUTPUT); // High indicates Busy
pinMode(PRN_ACK, OUTPUT); // LOW indicates an acknowledge
pinMode(PRN_NFault, OUTPUT);
strobeState = true;
Serial.begin(300);
while (!Serial) {
;
}
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
// based on https://forum.arduino.cc/t/interrupt-on-pin-4-pcint20/651245
// pin change interrupt to note state change of the PRN_STROBE pin
PCMSK2 |= bit(PCINT20); // Mask PCInt20 on the Interrupt (bit 4) PCMSK2 covers PCINT16 to PCINT23
PCIFR |= bit(PCIF2); // Clear any outstanding interrupts (PCIF2 is any change interrupt on PCINT16 to PCINT23)
PCICR |= bit(PCIE2); // Enable pin change interrupts Control Register for PCINT16 to PCINT23
State = READY;
delay(100);
Serial.println("Initialised");
}
void loop() {
switch (State) {
case READY:
digitalWrite(PRN_BUSY, LOW);
digitalWrite(PRN_ACK, HIGH);
digitalWrite(LED_BUILTIN, HIGH);
break;
// case BUSY: // nStrobe signal received by interrupt handler
// digitalWrite(Busy, HIGH);
// digitalWrite(led, LOW);
// ProcessChar();
// State = ACK;
// break;
// ** All this case is made during Interrupt (Avoid some missed characters with "fast" printer) **
case ACK:
digitalWrite(PRN_ACK, LOW);
delay(1); //milliseconds. Specification minimum = 5 us ** Reduced to 1 is ok **
State = READY;
break;
}
}
void ProcessChar() {
//byte Char = ((PINE & B00001100 ) << 4) | (PINC & B00111111);
byte Char;
Char = digitalRead(PRN_D0) +
(digitalRead(PRN_D1) << 1) +
(digitalRead(PRN_D2) << 2) +
(digitalRead(PRN_D3) << 3) +
(digitalRead(PRN_D4) << 4) +
(digitalRead(PRN_D5) << 5) +
(digitalRead(PRN_D6) << 6) +
(digitalRead(PRN_D7) << 7);
Serial.println(Char);
}
I am sending a string of bytes 130 to 132
Output appears as:
130
130
131
131
255
255
The main issue is that I need to test with
if (digitalRead(PRN_STROBE) == HIGH) {
It should be
if (digitalRead(PRN_STROBE) == LOW) {
However, if I use that, ProcessChar is never triggered! I guess the ISR is being triggered on the ACK signal changing from LOW to HIGH and HIGH to LOW as expected, but by the time it is triggered, it is simply too late to read the pin.