2
votes

System is basic but I have terrible problem and I can not solve it pls help me. When my system works PIC keep running but clear the registers 4-5 times in a day.

How system should work:

-I have a PIC, pneumatic cylinder and 3 sensor(works with 24V DC). -Main sensor take the signal from another system. -When a signal came from main sensor, if the cyclinder is backward, cylinder should go to forward until forward sensor see it and if the cylinder is forward, cyclinder should come to backward until backward sensor see it.

Program:

#include <16F628A.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or 
B5(PIC18) used for I/O

#use delay(crystal=4000000)

#use fast_io(a)
#use fast_io(b)

#define goForward   PIN_A0
#define comeBackward   PIN_A1
#define main_sensor   PIN_B0
#define positionSensorForward   PIN_B5
#define positionSensorBackward   PIN_B4

int1 pistonPositionedForward=0, pistonPositionedBackward=1;
int1 positionForwardReg=0, positionBackwardReg=0;
int1 pistonForwarding=0, pistonBackwarding=0;

#priority rb,ext

#int_RB NOCLEAR
void B_change()
{

  positionForwardReg=input(positionSensorForward);
  positionBackwardReg=input(positionSensorBackward);

if(positionForwardReg&&pistonForwarding) //if forwarding and forward sensor see
{   
  disable_interrupts(INT_RB);

  output_low(goForward);
  pistonPositionedForward=1;
  pistonPositionedBackward=0;

  write_eeprom(0,1);
  write_eeprom(1,0);

  pistonForwarding=0;
  pistonBackwarding=0;

  clear_interrupt(int_ext);
  enable_interrupts(INT_EXT);
}

else if(positionBackwardReg&&pistonBackwarding) //if backwarding and backward sensor see
{  
  disable_interrupts(INT_RB);

  output_low(comeBackward);
  pistonPositionedForward=0;
  pistonPositionedBackward=1;

  write_eeprom(0,0);
  write_eeprom(1,1);

  pistonForwarding=0;
  pistonBackwarding=0;

  clear_interrupt(int_ext);
  enable_interrupts(INT_EXT);
}

clear_interrupt(int_rb);

}

#int_ext NOCLEAR
void ext_interrupt()
{

  disable_interrupts(INT_EXT);

  positionForwardReg=input(positionSensorForward);
  positionBackwardReg=input(positionSensorBackward);

  if(positionForwardReg^positionBackwardReg)  //if one of position sensor is see then position according to sensor, else position according to memory
  {
     pistonPositionedForward=positionForwardReg;
     pistonPositionedBackward=positionBackwardReg;
  }

  if(pistonPositionedForward)
  {
     pistonBackwarding=1;
     pistonForwarding=0;
     output_high(comeBackward);

     clear_interrupt(int_rb);
     enable_interrupts(INT_RB);
  }
  else if(pistonPositionedBackward)
  {
     pistonForwarding=1;
     pistonBackwarding=0;
     output_high(goForward);

     clear_interrupt(int_rb);
     enable_interrupts(INT_RB);
  }
  clear_interrupt(int_ext);
}

void main()
{
   //to remember last position after power off
   pistonPositionedForward=read_eeprom(0); 
   pistonPositionedBackward==read_eeprom(1);

   set_tris_a(0x00);
   set_tris_b(0xFF);

   output_a(0x00);
   delay_ms(1000);

   ext_int_edge(L_TO_H);

   clear_interrupt(int_ext);
   enable_interrupts(INT_EXT);

   enable_interrupts(GLOBAL);

   while(TRUE)
   {

   }

}

And my circuit: CIRCUIT

*j2,j3 connected selonoid valve

*J4,J5,J6 connected 3 sensors 1. pin +24VDC,2. pin GND, 3.pin sensor data

***B1 and B2 connections changed. Now B1 connected to B5,B2 connected to B4

And These are I tried:

-I have 3 PIC all of them do same thing

-I changed 24V power supply

-I cancelled 7805 and 7812 and I connected seperate 5V power supply istead of 7805.

I am debugging via LEDs. Sometimes system stop running just waiting at one of positions. Take main sensor signal but doesnot anything, And pistonPositionedForward and pistonPositionedBackward register values are 0. I cant find problem how can it clear these registers?

1

1 Answers

2
votes

You have unconnected pins on RB that are configured as inputs, with no internal pull ups set. Electrical noise may well trigger unwanted interrupts on PORTB, that has been known to happen.

The use of interrupts is making the overall logic a bit hard to follow for such a simple device. Have you tried rewriting the program NOT using interrupts (except maybe for EXT)? It should not take long and I think it may greatly improve the reliability - and maintainability, without impacting performance of the physical system.

I suggest you first configure the unused PORTA and PORTB pins as outputs, and see if the problem goes away. If that fails, a rewrite not using interrupts should take no more than an hour. This would probably make sense since that is probably way shorter than the time you have already spent chasing the issue.

Reading the description, I came up with this solution.

#include <16F628A.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B5(PIC18) used for I/O

#use delay(crystal=4000000)

#use fast_io(a)
#use fast_io(b)

#define FWD_MOVE        PIN_A0
#define BACK_MOVE       PIN_A1
#define PORTA_RESET     (0x00)    // outputs=LO, unused pins as outputs
#define PORTA_TRISTATE  (0x00)

#define EXT_SENSOR      PIN_B0
#define FWD_REST        PIN_B5
#define BACK_REST       PIN_B4
#define PORTB_RESET     (0xCE)   // can't use pull ups because of HW logic...
#define PORTB_TRISTATE  (0x31)

#define EEPROM_STATUS_ADDR  (0x0000)
#define EEPROM_STATUS_FWD   (0x01)
#define EEPROM_STATUS_BACK  (0x00)

int1 extLast;
int1 extCur;

void main()
{
   // setup
   output_a(PORTA_RESET):
   output_b(PORTB_RESET):

   // setting to last known state...  

   // safety check.
   output_low(FWD_MOVE);
   output_low(BACK_MOVE);

   // This will activate the outputs to make sure we have good
   // positioning.
   switch(eeprom_read(EEPROM_STATUS_ADDR))
   {
   default:  // EEPROM error...  I'll let you decide what to do here.
             // either move forward or back.
             // this implementation goes back by default.

       eeprom_write(EEPROM_STATUS_ADDR, EEPROM_STATUS_BACK);
       disable_interrupts(GLOBAL);

       // falling through...

   case EEPROM_STATUS_BACK:
       output_high(BACK_MOVE);
       break;
   case EEPROM_STATUS_FWD:
       output_high(FWD_MOVE);
       break;
   }

   // activate outputs... watch your fingers!
   set_tris_a(PORTA_TRISTATE);
   set_tris_b(PORTB_TRISTATE);

   extLast = input(EXT_SENSOR);
   for (;;)
   {
       // read external sensor, take action.
       extCur = input(EXT_SENSOR);
       if (extCur && !extlast)
       {
           // safety check.
           output_low(FWD_MOVE);
           output_low(BACK_MOVE);

           // control logic
           switch(eeprom_read(EEPROM_STATUS_ADDR))
           {
           default:  // should never happen.

               // falling through...

           case EEPROM_STATUS_BACK:
               output_high(FWD_MOVE);
               eeprom_write(EEPROM_STATUS_ADDR, EEPROM_STATUS_FWD);
               disable_interrupts(GLOBAL);
               break;

           case EEPROM_STATUS_FWD:
               output_high(BACK_MOVE);
               eeprom_write(EEPROM_STATUS_ADDR, EEPROM_STATUS_BACK);
               disable_interrupts(GLOBAL);
               break;
           }
       }
       extLast = extCur;

       // mechanical interface:
       // read the limit guards and stop movement when done.
       if (input(FWD_REST))
       {
           output_low(FWD_MOVE);
       }
       if (input(BACK_REST))
       {
           output_low(BACK_MOVE);
       }
   }
}

Of course, I could not check the above code on-site :).

After reviewing the schematics, I must also advise to add 1N4001 diodes in parallel of the 2 output MOSFETS to give them better protection against reverse voltage spikes. MOSFET built-in diodes are not very sturdy. 1N4148 or 1N914 would work there as well.

The 16F628 has very limited stack space. It looks like you are experiencing stack overflow during the call to write_eeprom. Calling write_eeprom from an interrupt may not be such a good idea after all.

There was a bug in older CCS compilers, related to the use of write_eeprom. It seems write_eeprom is enabling interrupts during the call. I've added calls to disable interrupts after the writes. I don't know if that bug was fixed, since I never use CCS.

[EDIT] after checking your HW. I realized you cannot use internal pull-ups because the HW logic is positive-going. The pull-ups in the PIC are meant to work with NPN transistors in the open collector configuration (emitter to ground). I changed the code accordingly.

The way you write to EEPROM is not good. eeprom writes take time, and the second write is usually taken care of in the eeprom interrupt. The CCS bug that enables the global interrupt and unmask the EEIE in eeprom_write does not help. Unhandled interrupts do generate a reset.