Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] I wrote simple code buttons to rotary for PIC12F509, but it works only on simulation!

Status
Not open for further replies.

BAHKO

Newbie level 4
Joined
Sep 21, 2010
Messages
6
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,383
Hello! I tried to write my own code for 2 push buttons to rotary encoder (UP/DOWN Quadrature generator)
I have flashed it (ofcourse with changed ports) on PIC16F648 and it works perfect, it also works perfect in Proteus simulation with PIC12C509 (C509 was the closest i have to F509).

The problem comes when i program it on real PIC12F509 - the chip doing NOTHING but when i press reset it resets (i put 2 leds on outputs and they flicker on reset)!

GP0 = UP - button used with pull down
GP1 = DN - button used with pull down
GP2 = not connected/set to output
GP3 = RESET trough pullup 10k to Vcc and button to GND
GP4 = OUT B - output 2 - connected LED through 220 ohm to GND
GP5 = OUT A - output 1 - connected LED through 220 ohm to GND

The outputs just stay high and no reaction!
What i am doing wrong? I struggle with it for 3 days now and nothing work on real chip (i have few of them brand new)

MPLAB IDE 8.30 with High-Tech C compile it (for F509) with no errors.
The fuses are configured outside of the code - IntOSC, CP - OFF, RESET - ON, WDT - OFF

My Programmer is PicKit3 and also flash it perfectly!

It just does not work on real chip.
Please help me if anyone can.

Here is the
Code:
/*
PIC12F509 buttons to
rotary encoder truth table.
===========================
Count UP   OUTA  OUTB
===========================
<1.1> =     H  -  H
<1.2> =     L  -  H
<2.1> =     L  -  L
<2.2> =     H  -  L
===========================
Count DN   OUTA  OUTB
===========================
<1.1> =     H  -  H
<1.2> =     H  -  L
<2.1> =     L  -  L
<2.2> =     L  -  H
===========================
*/
#include <pic.h>

#if defined(_12F509)
  __CONFIG(0x31FA); 
#endif

//define buttons
#define UP GP0
#define DN GP1
unsigned int j;
// 8  = number of loop iterations for 1 ms at 4 MHz
#define loop4_ms 8

//functions 
void pause_ms(unsigned int given_ms);               // pause for given_ms milli seconds
//end functions
int REP;        //Repeat cycle 'n' times

unsigned char const STEPS_MAP[4] = {0b111000,0b011000,0b001000,0b100100};
int step=0;

//main code
void main(void) {    
#if defined(_12F509)
    TRIS = 0b001011;          // Set GP4,GP5 as outputs & GP3, GP0, GP1 as input (0 => Output, 1 => input)
#endif
    GPIO   = 0b001000;        // Set GPIO = 0 for all output but 1 for GP3/MCLR input
	OPTION = 0b11010000;    
do
     {
         if (UP)            //Check if switch  is closed
           {
             pause_ms(90);   //wait for 90ms  (switch debouncing)
             if (UP)         //Check if switch is still closed
                {
                 for(REP=0; REP<=1; REP++)        //Repeat steps until 'n'
   				{
   				 GPIO = (STEPS_MAP[step]);     //Load current state
 			   	 pause_ms(250);                  //Pulse time
    			 step++;                        //Count +
    			 if (step>3)step=0;

   				}
    			 REP;                //End REP

                }
           }

          else
             {
                 GPIO = (STEPS_MAP[step]);
             }
          if (DN)            //Check if switch  is closed
           {
             pause_ms(90);   //wait for 90ms  (switch debouncing)
             if (DN)         //Check if switch is still closed
                {
                  for(REP=0; REP<=1; REP++)
  				{
    			  GPIO = (STEPS_MAP[step]);     //Load current state
    			  pause_ms(250);                  //Pulse time
   				  step--;                        //Count -
   				  if (step<0)step=3;
    			}
      			  REP;                //End REP
                }
           }
          else
             {
                 GPIO = (STEPS_MAP[step]);
             }
              
     }

	while(1);
}
//end main code

	void pause_ms( unsigned int given_ms ) {  // pause for given_ms milli seconds
    
	unsigned long j, max_time = given_ms * loop4_ms;
    for(j=0; j < max_time; j++);          // Make waiting for about given_ms msec
};
And schematic:

F509_B_rot.jpg
 

Here is a code that you can use with a little modification according to your PIC.

Code:
// Value changes up or down as encoder is turned.
// encoder 2 outputs are PORTB.F1 and PORTB.F0
// logic; if newA == oldB, encoder turned clockwise
// if newA != oldB, encoder turned counterclockwise
// example; (AB) 00 01 11 10 00 01 11 10 00

char value;
char new_encoder;
char last_encoder;

   new_encoder = (PORTB & 0x03);      // keep only 2 bits
   if(new_encoder != last_encoder)      // if encoder has changed
   {
      if(new_encoder.F1 == last_encoder.F0) value++;
      else value--;

      last_encoder = new_encoder;   // save for next time
   }

There should be no blocking delays or if your PIC supports external interrupts on at least one pin then you can use that feature and put the whole code in the external interrupt ISR.
 

baileychic, than you for replay. It is not rotary encoder to UP and Down commands (logic states), it is the opposite UP and DOWN buttons to two way quadrature generator function (rotary encoder) in other words - replace encoder with buttons.
My programming skills are poor but that is not what i need and as i said it is for PIC12F509 - this exact code work on real PIC16F648 and in proteus sim for PIC12C509 but it compiles to PIC12F509 flawlessly and is dead on real pic12.... I also have build the whole thing out of CMOS logic and also works, but i wanted something compact and simple. I also want to learn where is my mistakes to improove myself
 

Show your actual hardware encode and provide its datasheet.
 

As said above, your code have a lot of blocking instructions that blinds the program for a while preventing from reading the actual encoder, for which we should just guess it have a resolution of houndred or thousands pulses per cycle (you did not mention anything about its specifications, nor rotation speed). On simulation everything works fine even when programming with inappropriate approaches. You should consider using I/O interrupt feature.

Another point to remark is that your encoder MAP do not handles abnormal execution, e.g whether a missing pulses happened or not, which is expected when the axis turns faster than your code can deal with; you could provide an output LED just to inform such an situation.
 

andre_teprom, thank you for your reply. I am not trying to READ Rotary Encoder but to emulate its function with buttons and replace it. LED1 and LED2 are there only to test and indicate outputs states, they won't be connected on finished board.

baileychic, The hardware is exact copy of the schematic i provided in the first post.

IMG_20191214_104625.jpg

The function, I'm trying to create is:
Code:
loop4_ms=8  -> represent 1mS delay, for 4MHz internal oscillator is 8 MCU cycles

STEPS_MAP should represent the corresponding output LEDs AB -> 11 01 00 10
first initialize on step0 (e.g. 11)

if button UP = 1 for more than 90mS and less than 250mS -> count UP two steps from current steps state from STEPS_MAP
e.g. -> step0 wait 90mS step1 wait for 250mS -> and stay on current step

when button UP is holded for more than 250mS -> do two more steps or just continue to count untill the button is pressed 
e.g. -> step0 -> wait 90mS step1 -> wait for 250mS -> step2 -> wait for 90mS -> step3 -> wait for 250mS -> step0 ... and so on (0,1,2,3,0,1, ...)

and when button is released stay on current step
when pressed again continue from current step 

if button DN = 1 for more than 90mS and less than 250mS -> count DN two steps from STEPS_MAP
e.g. -> step0 wait 90mS step1 wait for 250mS -> and stay on current step

when button DN is holded for more than 250mS -> do two more steps or just continue to count untill the button is pressed 
e.g. -> step3 -> wait 90mS step2 -> wait for 250mS -> step1 -> wait for 90mS -> step0 -> wait for 250mS -> step3 ... and so on (3,2,1,0,3,2, ...)

and when button is released stay on current step
when pressed again continue from current step

Everytime when any of 2 buttons is pressed always count from current step NOT from begining of STEPS_MAP

Here is the quadrature simulation of single push (showing UP press, for DN is the exact opposite way):
UP_func.jpg

Here is the quadrature simulation of holding UP and DN:
UP_DN_HOLD.jpg

You can clearly see the "TETRIS fugure" :laugh: is perfectly mirrored on the counting down sequence :cool: in the second image.

the STEPS_MAP table was in 8-bit hex values but i translate it to binary format so i can easily change the order of bits and see what i have.
If i could find sample for blinking led with delays and mapping the GPIO port as byte word for PIC12F509, i think i will be able to manage the code. I don't know how to write code for interrupts and how to enable internal hardware and use it and i thought that GPIO command can be exequted as PORTA on PIC16 ... and i stuck. PIC12F509 just doesn't want to work exept in simulation i can see it is alive when i reset it and that is all it does, and i have few of them, both do exately the same and they are brand new.

I atached the whole project to check it. It uses Proteus 7.10 and MPLAB IDE 8.30
I hope i provided the whole information about my problem!
 

Attachments

  • 12F509.zip
    1.4 MB · Views: 69

If someone can write this function in any language please!
I edited the code, but even this doesn't work on real chip:
Code:
/*
PIC12F509 buttons to
rotary encoder truth table.
===========================
Count UP   OUTA  OUTB
===========================
<1.1> =     H  -  H
<1.2> =     L  -  H
<2.1> =     L  -  L
<2.2> =     H  -  L
===========================
Count DN   OUTA  OUTB
===========================
<1.1> =     H  -  H
<1.2> =     H  -  L
<2.1> =     L  -  L
<2.2> =     L  -  H
===========================
*/
// CONFIG
#include <pic.h>
__CONFIG(0x0FEA);
//__OSCCAL(0x0C3A);
#define _XTAL_FREQ 4000000
#include <stdint.h>
#define UP GPIObits.GP5
#define DN GPIObits.GP4

/*#define loop4_ms 8  // 8 is number of loop iterations for 1 ms at 4 MHz

//**********functions****************

unsigned int j;

void pause_ms(unsigned int given_ms);               // pause_ms(n); function same as delay_ms(n); 

//**********mapping steps************

unsigned char const STEPS_MAP[4] = {0b11,0b10,0b00,0b01};
int step=0;
*/
//main code
void main(void) {    
    TRIS   = 0b110000;          // Set GP0,GP1,GP2 as outputs & GP3, GP5, GP4 as input (0 => Output, 1 => input)
    GPIO   = 0b000000;        // Set GPIO = 0 for all outputs
	OPTION = 0b11000000;      //Set functions for MCU pins - 0x30

GP0=1; //I LEAVE ONLY THIS AND EVEN THIS DOES NOT WORK!
/*	    
do
     {
         if (UP)            //Check if switch  is closed
           {
             pause_ms(90);   //wait for 90ms  (switch debouncing)
             if (UP)         //Check if switch is still closed
                {
   				 GPIO = (STEPS_MAP[step]);     //Load current state
 			   	 pause_ms(250);                  //Pulse time
    			 step++;                        //Count +
    			 if (step>3)step=0;				
				}
           }

          else
             {
                 GPIO = (STEPS_MAP[step]);
             }
          if (DN)            //Check if switch  is closed
           {
             pause_ms(90);   //wait for 90ms  (switch debouncing)
             if (DN)         //Check if switch is still closed
                {
  				  GPIO = (STEPS_MAP[step]);     //Load current state
    			  pause_ms(250);                  //Pulse time
   				  step--;                        //Count -
   				  if (step<0)step=3;
   				}
            }
          else
             {
                 GPIO = (STEPS_MAP[step]);
             }
     }
*/
	while(1);

//}
//end main code
/*
	void pause_ms( unsigned int given_ms ) {  // pause for given_ms milli seconds
    
	unsigned long j, max_time = given_ms * loop4_ms;
    for(j=0; j < max_time; j++);          // Make waiting for about given_ms msec
*/
};
 

Check the pull-up settings in the OPTION register. They may be fighting against the pull-down resistors in the actual product.

Brian.
 

Problem is solved in another forum, it was the CONFIG register settings.
Anyway thanks to all who tryed to help.

The thread may be closed now.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top