My project is a cable distance measurement system for adverse environments. The cable reel has an optical encoder which provides 100 pulses per revolution. I am using an Arduino Uno to count the number of pulses in both a clockwise and counterclockwise direction to determine the number of cable reel rotations. The number of rotations is then converted to the length of cable deployed. The amount of cable deployed is then displayed on a display using the Nootronics Video Experimenter and the TVOut library. This system works great when using non-optical encoders with fewer pulses per revolution. I have also constructed a stand alone circuit card with the ATMEGA328P chip and the LM1881 sync separator chip and it also works great. The problem I am having is for high resolution optical encoders that I have to interface to for some projects. Pulses are missed when the Arduino is off servicing the video stuff. One solution is to have 2 processors: one for the video overlay processing and the other for the pulse counting/direction processing. I am testing this approach now using the Arduino Uno for one processor (video overlay) and a stand alone ATMEGA 328P (pulse counting/direction) for the other processor.
I know that I am making this too difficult, but I am having problems trying to pass the number of pulses counted (unsigned integer) from the pulse counting/direction processor to the other processor using the serial interface. I can't use Interrupts on the video overlay processor since they cause interference with the TVOut library, so I am left with using the pollserial library. Pollserial does not have the capability of the standard interrupt driven serial interface (e.g. no parseInt() or readBytesUntil() functions). Using the test code implementation, I am able to send a single ASCII byte over the interface, but I haven't found a way to send multiple bytes of integer data.
Please provide help in possible approaches to sending two bytes of integer data to the overlay processor within the constraints of having to use the pollserial library for serial interface approaches. The test code for both processors compiles and executes satisfactorily and is included below.
ATMEGA328P Code:
#include <pollserial.h>
#include <digitalWriteFast.h>
#define encoderAPin 2 // the pin that Channel A is attached to
#define encoderBPin 4 // the pin that Channel B is attached to
pollserial pserial;
const char startOfNumberDelimiter = '<';
const char endOfNumberDelimiter = '>';
// Variable definition
volatile long encoderOutputCounter = 0.0; // counter for the number of encoder pulses
unsigned long time = 0;
void setup() {
pinMode(encoderAPin, INPUT);
pinMode(encoderBPin, INPUT);
attachInterrupt(0, readEncoder, CHANGE); // encoder pin on interrupt 0 - pin 2
pserial.begin(9600);
}
void loop() {
if((millis()-time)>1000) {
pserial.print(startOfNumberDelimiter);
pserial.print(encoderOutputCounter);
pserial.print(endOfNumberDelimiter);
pserial.println();
time = millis();
}
}
void readEncoder() {
/* Read the encoder outputs on the rising and falling edges of the encoder channel A.
If the encoder channel A and encoder channel B outputs are both high or both low, it is spinning
forward. If they are different, it's going backward.
*/
if (digitalReadFast(encoderAPin) == digitalReadFast(encoderBPin)) {
encoderOutputCounter++;
}
else {
encoderOutputCounter--;
}
}
Arduino Uno Code:
#include <pollserial.h>
#include <TVout.h>
#include <fontALL.h>
#include <digitalWriteFast.h>
#define W 136
#define H 96
pollserial pserial;
TVout tv;
unsigned char originx = 4;
unsigned char originy = 78;
const int displayBlankPin = 10; // the pin that the display blanking wwitch is attached to
const float minDrumDia = 22.0; // the initial drum diameter in inches
const float maxDrumDia = 25.0;
const float PulseCountPerRev = 200.0;
const char startOfNumberDelimiter = '<';
const char endOfNumberDelimiter = '>';
// Variable definition
volatile long encoderOutputCounter = 0.0; // counter for the number of encoder pulses
float drumDia=0.0;
float cableDist = 0.0; //amount of cable deployed
unsigned long time;
void setup() {
tv.begin(NTSC, W, H);
tv.select_font(font4x6);
initOverlay();
tv.fill(0);
pinMode (displayBlankPin, INPUT);
digitalWrite(displayBlankPin, HIGH); // tie other side of display blanking switch to ground
tv.set_hbi_hook(pserial.begin(9600));
}
// Initialize ATMega registers for video overlay capability.
// Must be called after tv.begin().
void initOverlay() {
TCCR1A = 0;
// Enable timer1. ICES1 (Bit 6) is set to 0 for falling edge detection on input capture pin.
TCCR1B = _BV(CS10);
// Enable input capture interrupt
TIMSK1 |= _BV(ICIE1);
// Enable external interrupt INT0 on pin 2 with falling edge.
EIMSK = _BV(INT0);
EICRA = _BV(ISC01);
}
// Required to reset the scan line when the vertical sync occurs
ISR(INT0_vect) {
display.scanLine = 0;
}
void processInput()
{
static long receivedNumber = 0;
static boolean negative = false;
byte c = pserial.read();
switch(c)
{
case endOfNumberDelimiter:
if(negative)
encoderOutputCounter = -receivedNumber;
else
encoderOutputCounter = receivedNumber;
case startOfNumberDelimiter:
receivedNumber = 0;
negative = false;
break;
case '0'...'9':
receivedNumber*=10;
receivedNumber+=c-'0';
break;
case'-':
negative=true;
break;
} //end of switch
} //end of processInput
void loop() {
if(pserial.available())
processInput();
// Drum diameter compensation loop; provides estimate of drum diameter as a function of cable deployed
if((encoderOutputCounter)>=0 && (encoderOutputCounter)<2400) { //1 row of cable deployed
drumDia=minDrumDia;
goto exitDiaComp;
}
if((encoderOutputCounter)>=2400 && (encoderOutputCounter)<4800) { //2 rows of cable deployed
drumDia=(minDrumDia + (minDrumDia+1.0))/2.0;
goto exitDiaComp;
}
if((encoderOutputCounter)>=4800 && (encoderOutputCounter)<7200) { //3 rows of cable deployed
drumDia=(minDrumDia + (minDrumDia+2.0))/2.0;
goto exitDiaComp;
}
if((encoderOutputCounter)>=7200 && (encoderOutputCounter)<9600) { //4 rows of cable deployed
drumDia=(minDrumDia + (minDrumDia+3.0))/2.0;
goto exitDiaComp;
}
if((encoderOutputCounter)>=9600 && (encoderOutputCounter)<12000) { //5 rows of cable deployed
drumDia=(minDrumDia + (minDrumDia+4.0))/2.0;
goto exitDiaComp;
}
if((encoderOutputCounter)>=12000) { //greater than 5 rows of cable deployed
drumDia=maxDrumDia;
goto exitDiaComp;
}
exitDiaComp:
cableDist = 3.14*(drumDia/12.00)*(encoderOutputCounter/PulseCountPerRev);
// amount of cable in feet that have been deployed
// save the current encoder state as the last encoder state
// for the next time through the loop
if(digitalRead(displayBlankPin)==HIGH) {
tv.println(originx,originy,encoderOutputCounter);
tv.print(originx, originy+6, cableDist,1);
tv.println(" FEET ");
}
else {
tv.fill(0);
}
}
I appreciate any assistance that you can provide.