Rotary Encoder To Set Count on Four Seven Segment Digits

Go To Last Post
36 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

Google led to this  https://www.avrfreaks.net/sites/default/files/Encoder.c

 

I have used this code as listed on this thread. Compiled it and uploaded it on Atmega32@ 16MHz.

I want to make a coil winding , decremental counter starting from the number set on the four digits of seven segment display. (this is the first step to the final requirement.)
The display can be set to the desired number, but to set a number in thousands the spins on the encoder are plenty!

Encoder is connected to PD2 and PD0. Switch not used
Seven Segment are connected to PB0.......PB6. DP not used.
PC4...PC7 select the ones,tens,hundreds and thousands digit.

 

Can the button on the encoder be used to select a digit with every press to set the number on that digit?

Will be greatfull for inputs toward this endeavor.

 

This is the code

//Code for Atmega32 @ 16 MHz
/Code taken from url https://www.avrfreaks.net/sites/default/files/Encoder.c

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <math.h>
#include <util/delay.h>

#define CHECKBIT(x,y) (x & (y)) /* Check bit y in byte x*/
#define SETBIT(x,y) (x |= (y)) /* Set bit y in byte x*/
#define CLEARBIT(x,y) (x &= (~y)) /* Clear bit y in byte x*/

//lookup table ascii char to 7 segment common anode type with pullup resistors
//static const uint8_t PROGMEM sevsegascii_table[] = {
//  0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0xbf // 0 1 2 3 4 5 6 7 8 9 -
//};

//lookup table ascii char to 7 segment common anode type without pullup resistors
static const uint8_t PROGMEM sevsegascii_table[] = {
  0x3F, 0x6, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x7, 0x7F, 0x6F, 0x40 // 0 1 2 3 4 5 6 7 8 9 -
};
void displayNumber(int number);
void printNumber(int number);
volatile int num;
volatile int ones;
volatile int tens;
volatile int hundreds;
volatile int thousands;

int main(void)
{
  DDRB = 0xff;  // sets port b as output
  PORTB = 0x00; // sets all bis on port B low
  DDRD = 0x00;   //input port
  PORTD = 0xFF;  //enable pull up resistor
  DDRC = 0xff;
  PORTC = 0x10;
  
  TCCR0 |= (1<< CS02);  //256 PRESCALER
  TCCR0 |= (1<< WGM01); //CTC MODE
  OCR0 = 130;  //8ms. setting how fast to refresh the display

  MCUCR = 0x01;     //int0 interrupt on level change
  //MCUCR |= (1<<ISC00); // int0 interrupt on level change

  GICR = 0x40;// enable int0 interrupt. This uses 2 bytes less 
              //as compard to next commented statement
  //GICR  |= 1<<INT0;     //enable the int0 interrupt.
  TIMSK |= (1<<OCIE0);  //enable the timer0 compare interrupt
  sei();          //enable global interrupts

  num = 10; //initializing the "counter"

  while(1)
  {
      printNumber(num);
  }
  return 0;
}
void printNumber(int number)
{
  int temp = 0;
  //splitting the number into separate numbers
  //to display on the 4 digit 7-segment display
  thousands = floor(number / 1000);
  temp = number % 1000;
  hundreds = floor(temp/100);
  temp = number % 100;
  tens = floor(temp/10);
  ones = temp % 10;
}
//displaying the number on the 7 segment display
void displayNumber(int number)
{
  if (number<0) {
    number*=-1;
  } 
  PORTB = pgm_read_byte(&sevsegascii_table[number]);
}

ISR(TIMER0_COMP_vect)
{

  //selecting which digit to display
  //timing controlled by Timer0
  switch(PORTC)
  {
    case 0x80:
      displayNumber(hundreds);
      PORTC = 0x40;
      break;
    case 0x40:
      displayNumber(tens);
      PORTC = 0x20;
      break;
    case 0x20:
      displayNumber(ones);
      PORTC = 0x10;
      break;
    case 0x10:
      displayNumber(thousands);
      PORTC = 0x80;
      break;
    default:
      break;

  }
}

ISR(INT0_vect)
{

/* this works for MCUCR=0x01 i.e. interrupt on level change */

  // A raising edge
  if ((PIND & (1<<PD2))) {
    if ((PIND & (1<<PD0))) num++; // B rising edge
    else num--;           // B falling edge
  }
  // A raising edge   
  else {
    if ((PIND & (1<<PD0))) num--; // B rising edge
    else num++;           // B falling edge
  }
  
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Rather than slap random bits of code together, think about how you can build subsystems that provide a useful abstraction. Eg: code that makes your display easy to use - give it a number and the function does what is required to display it. You might want to add a digit flashing function to aid your user interface - the flashing digit is the one that the encoder will change. 

 

Similarly for your encoder. Why are you using external interrupts? You could easily poll it in your timer isr as well as debounce the pushbutton input and time the button press.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
Rather than slap random bits of code together, think about how you can build subsystems that provide a useful abstraction. Eg: code that makes your display easy to use - give it a number and the function does what is required to display it. You might want to add a digit flashing function to aid your user interface - the flashing digit is the one that the encoder will change.

 

Thanks Kartman. I will start with display and blinking the digit with a switch button, and the n method.interface the encoder.

You are right i will not use the level change int0, use enc A and B on the analog input pins.

I will do this and share the results.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

On first sight this code looks like it's "all over the place".

 

Apart from the modularity that Kartman suggests the general principle of software engineering is to spend more time up front in a design phase planning out how the solution is going to work. Don't just rush to a keyboard and start typing C into an editor then after a while step back to contemplate - well how is this bit over here going to know what that bit over there is doing. At this stage it's too later. If you had a clear design in the first place you would already have worked such things through.

 

Of course there's no harm, while planning, to prototype some parts of it to get a clearer picture of how you are going to implement a part of it. In fact, if done correctly such prototype code may be almost totally reusable in the final solution.

 

One thing I would have contemplated in the design phase for example would have been whether it were better to have separate ones, tens, hundreds, thousands variables or simply digits[3]..digits[0] ? The latter more easily lends itself to "indexing" so if you are going to have to do something repeatedly (like printing each digit in turn) you just keep a 0..3 counter of which one is next rather than having to use switch/case to map some index to thr right ones/tens?hundreds/... variable.

 

Also, for example, if your digits are displayed from left to right as digits[0], digits[1], digits[2], digits[3] (so [0] is 1000's, [1] is 100's, [2] is 10's and [3] is 1's) then your breaking the digits routine then becomes something like:

splitDigits(uint16_t num) {
    uint8_t i;
    for (i = 0; i < 4; i++) {
        digits[3 - i] = num % 10;
        num /= 10;
    }
}

or even:

splitDigits(uint16_t num) {
    uint8_t i;
    ldiv_t result;
    
    for (i = 0; i < 4; i++) {
        result  = ldiv(num, 10);
        digits[3 - i] = result.rem;
        num = result.quot;
    }
}

These are just ideas. But they are the kind of ideas you should have up front in the design phase. Maybe even writing small test programs to test such ideas out. When you decide on the best approach then you put that into the final implementation.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There are some basic system design tools that are missing here:

 

1. ANY numeeric 7 segment display needs to work from a number, and convert that to the pattern of segments that are on or off, then send that pattern to the display digit.

 

2. Multiple digit 7 segment display simply repeat what a single digit display does, once for each digit. So, if you have 4 digits you want to display, you need 4 numbers to start with.

 

3. For a multi-digit 7 segment display to behave like a single multi-digit number, you simply want the numbers to behave as if you were counting. Thus, make one of these numbers represent units, one digit represent 10s, one represent 100s, and one represent 1000s. Then, when the units digit reaches 9, the next increment returns it to zero and increments the 10s digit. Likewise for each of the other digits.

 

4. Now you have an abstract number counting display.

 

5. The incremental encoder is independent of all this. It simply provides count "commands" to the decimal number counter.

 

6. So, YOU need to figure out how to handle the quadrature output signal from the encoder. What drives the encoder? Do you get one step per machine revolution or are there many steps per revolution? If there are many, you simply need to "count down" the encoder signal until you get one per revolution (coil turn).

 

6. I am wondering if an incremental encoder is even a good choice? Why not a photo-interruptor that makes one pulse per revolution. It might be mechanically simpler and program simpler.

 

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

Last Edited: Mon. Jan 20, 2020 - 05:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Start at CPU reset with all four LED digit digit displays off.  Set an uint8_t variable to 5.  Test the encoder.  With each activation, increase or decrease the 1000s digit only.  Roll over to zero when advancing past nine, and roll-under to nine when turning the encoder below zero.  When you reach the desired 1000s value, press the button that is currently unused.  Repeat three more times lighting up the 100s, 10s, and 1s  7-segment with value. 

  Now the MCU is ready with a valid count to do its main activity with that count.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Appreciate your dwelling on my issue, Kartman, clawson, ka7ehk ans Simonetta. Will try your suggestions. 
I have used the encoder just as a input device to set the count on the 4Digit SevenSeg Display.

A need has arisen to have a transformer 220/12-012 V to power a small zero cross detect, triac controlled device.

I thought of rigging a counter to count turns with my electric drill. This was to be done by a magnet and a reed switch. I have all the hardware that I have described. I will surely share my progress on this thread.

Cheers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
This is my code to start with all four digits with 0.
How do i make each digit selectable with a switch to set its value 0 to 9?
//Atmega8 @16MHZ
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay_basic.h>

#define SEVEN_SEGMENT_PORT PORTD
#define SEVEN_SEGMENT_DDR  DDRD

volatile uint8_t digits[3];

void sevenSegment(uint8_t n)
{
  /*
    This function writes a digits given by n to the display
    the decimal point is not used

    Note:

    n must be less than 9
  */
  if (n < 10)
  {
    switch (n)
    {
      case 0:
        //.gfedcba
        SEVEN_SEGMENT_PORT = 0b10111111;
        break;

      case 1:
        //.gfedcba
        SEVEN_SEGMENT_PORT = 0b10000110;
        break;

      case 2:
        //.gfedcba
        SEVEN_SEGMENT_PORT = 0b11011011;
        break;

      case 3:
        //.gfedcba
        SEVEN_SEGMENT_PORT = 0b11001111;
        break;

      case 4:
        //.gfedcba
        SEVEN_SEGMENT_PORT = 0b11100110;
        break;

      case 5:
        //.gfedcba
        SEVEN_SEGMENT_PORT = 0b11101101;
        break;

      case 6:
        //.gfedcba
        SEVEN_SEGMENT_PORT = 0b11111101;
        break;

      case 7:
        //.gfedcba
        SEVEN_SEGMENT_PORT = 0b10000111;
        break;

      case 8:
        //.gfedcba
        SEVEN_SEGMENT_PORT = 0b11111111;
        break;

      case 9:
        //.gfedcba
        SEVEN_SEGMENT_PORT = 0b11101111;
        break;
    }

  }

}

void Wait()
{
  uint8_t i;
  for (i = 0; i < 5; i++)
  {
    _delay_loop_2(0);
  }
}

void Print(uint16_t num)
{
  /*
    This function separates a given integer into  digits
    and writes them to the four SSDs.

  */
  uint8_t i = 0;
  uint8_t j;

  if (num > 9999) return; // display all zeroes for number that is >9999

  while (num)
  {
    digits[i] = num % 10;
    i++;

    num = num / 10;
  }
  for (j = i; j < 4; j++) digits[j] = 0;  // show 0 on SSD that is 0
}

int main(void)
{
  uint16_t i;

  // Prescaler = FCPU/256
  TCCR0 |= (1 << CS02);

  //Enable Overflow Interrupt Enable
  TIMSK |= (1 << TOIE0);

  //Initialize Counter

  TCNT0 = 0;

  //Port B[3,2,1,0] as out put
  DDRB |= ((1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0));

  PORTB = 0b00000000;

  //Port D
  SEVEN_SEGMENT_DDR = 0XFF;

  //Turn off all segments
  SEVEN_SEGMENT_PORT = 0X00;

  //Enable Global Interrupts
  sei();

  while (1)
  {
    Print(0);
    Wait();
  }

}

ISR(TIMER0_OVF_vect)
{
  /*

    This interrupt service routine (ISR)
    Updates the SSDs

  */
  static uint8_t i = 0;

  if (i == 3)
  {
    //If on 1st SSD go to 4th SSD
        i = 0;
  }
  else
  {
    //Goto Next SSD
    i++;
  }

  //Activate the SSD display according to i
  PORTB &= (0b00000000);
  PORTB |= (1 << i);

  //Write the digit[i] in the ith SSD.
  sevenSegment(digits[i]);

}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
volatile uint8_t digits[3];

 

I think you want 4 rather than 3.

 

A lookup table is much less typing than the switch() statement:


const uint8_t sevenSeg[] = {0b10111111,0b10000110,0b11011011,0b11001111,
                            0b11100110,0b11101101,0b11111101,0b10000111,
                            0b11111111,0b11101111
                            };

// then the lookup becomes:
SEVEN_SEGMENT_PORT = sevenSeg[num];

What is this gem doing?

 

PORTB &= (0b00000000);

surely you could be a bit more obvious with this?

Last Edited: Sat. Feb 1, 2020 - 09:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
A lookup table

Hey - is it 2003 already ?!

 

http://www.8052mcu.com/forum/read/55866

 

cheeky

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:

PORTB &= (0b00000000);

 

It should have been this

PORTB &= (0b11110000);

I will need some time to implement the look up table lead from you, will appreciate if you have any post for referral.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ka7ehk wrote:

5. The incremental encoder is independent of all this. It simply provides count "commands" to the decimal number counter.

6. So, YOU need to figure out how to handle the quadrature output signal from the encoder. What drives the encoder? Do you get one step per machine revolution or are there many steps per revolution? If there are many, you simply need to "count down" the encoder signal until you get one per revolution (coil turn).

 

6. I am wondering if an incremental encoder is even a good choice? Why not a photo-interruptor that makes one pulse per revolution. It might be mechanically simpler and program simpler.

 

One benefit of a quad style encoder, is you can easily decrement the number when you have gone too far.

You could use 2 slotted interruptors, or find one with 2 receivers, to get one pulse per rev plus Up/Down

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

karanbir wrote:
I will need some time to implement the look up table lead from you, will appreciate if you have any post for referral.

 

How about the one from 2003: http://www.8052mcu.com/forum/rea... ?

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I didn't look at your code at all, but will tell you what I did a long time ago.

 

I used an acceleration factor...as you spin the dial it counts faster & faster & faster, and as you slow down the dialing it counts slower & slower & slower.  If you reverse direction, it goes to the slowest speed (and starts picking up speed again in the reverse direction).

So, say you want to set it to 5000, but you are only at 250...as you quickly spin the dial ,it quickly picks up counting speed & you get near there very fast.  As you get close to 5000, of course, you turn it slower & the rate falls as well.  If you overshoot, & have to reverse slightly, it goes very slow so you can get to the exact value.  When the rates are all programmed nice, it works great!  The dial acts like it has some "smarts" so it is able to home in on your desired setting very rapidly.  I've used the same scheme on up/down settings buttons.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sat. Feb 1, 2020 - 11:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's a great tip!

 

laugh

 

That's the kind of thing that distinguishes a great user interface ("UI") from a mediocre one.

 

Nowadays, this is called "UX" - for "User eXperience"

 

In the old days, we might have called it "Ergonomics" or "Human Factors"

 

avrcandies wrote:
what I did a long time ago

The sad thing is that all this has been done and well-known for a long time - and yet people are still reinventing the basic wheel from scratch.

 

frown

 

That was my point with the 2003 references.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sounds like "mouse acceleration" with improvements which certainly predates 2003. smiley

Letting the smoke out since 1978

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The encoder is being used as a device to set the count from which to count down. Yes a photo interrupter or a hall effect sensor will be used to count the revs.

The code in my first comment works, but to set counts in thousands the encoder needs plenty spins. I was looking for advice to be able to set the digit wise count by using the switch on the encoder. I have not been able to do this.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Who-me wrote:

ka7ehk wrote:

 

5. The incremental encoder is independent of all this. It simply provides count "commands" to the decimal number counter.

6. So, YOU need to figure out how to handle the quadrature output signal from the encoder. What drives the encoder? Do you get one step per machine revolution or are there many steps per revolution? If there are many, you simply need to "count down" the encoder signal until you get one per revolution (coil turn).

 

6. I am wondering if an incremental encoder is even a good choice? Why not a photo-interruptor that makes one pulse per revolution. It might be mechanically simpler and program simpler.

 

One benefit of a quad style encoder, is you can easily decrement the number when you have gone too far.

You could use 2 slotted interruptors, or find one with 2 receivers, to get one pulse per rev plus Up/Down

The encoder is being used as a device to set the count on the seven segment digits. My code in the start of this works great but it takes plenty of spins at the encoder to set the number that is in thousands as it increments every 9th count.

I was looking at being able to set the count digitwise by using the switch on the encoder. ( For 9999 i will need max of 36 advances on the encoder)

For the counter of the revolutions i will use a hall effect sensor.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

karanbir wrote:
the switch on the encoder.

What switch?

 

You mean it's one of those you can turn, and it also has s switch which makes when you press it in?

 

I have not been able to do this.

So what have you tried?

 

What was the problem(s) ?

 

Where are you stuck?

 

As has already been said, the way to approach such things is always to break it down into the separate, independent subsystems.

 

So forget, for a moment, about the rotary encoded; just think about how you could select 1 item from 4 using any push-button ... ?

 

Presumably, you want something that will "cycle" through the 4 items; eg,

 

  1. start with item 1 selected
  2. push button to select item 2
  3. push button to select item 3
  4. push button to select item 4
  5. push button to repeat from (1) ...

 

EDIT

 

From a UX perspective (see above), it may be better to just have 1 button per digit ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Mon. Feb 3, 2020 - 03:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My code in the start of this works great but it takes plenty of spins at the encoder to set the number that is in thousands as it increments every 9th count.

As already mentioned, as you spin the wheel count faster and faster.  When you stop or reverse, set the count rate (counts per click) back to 1.

You can massage this to be fancier (such as modifying the count rate based on the knob acceleration/deceleration), but this does pretty well.

You'll be able to dial in the desired value very quickly & easily.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

I think OP is trying to model a thumbwheel interface:

 

 

I guess that might be the familiar/traditional interface in her/his context (a coil winder) - so, in that sense, it would seem "easier" to the target audience ... ?

 

at least initially ...

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Mon. Feb 3, 2020 - 05:21 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

 

I think OP is trying to model a thumbwheel interface:

 

 

I guess that might be the familiar/traditional interface in her/his context (a coil winder) - so, in that sense, it would seem "easier" to the target audience ... ?

 

at least initially ...

 

No this is not my intention. I intend to carry on with the rotary encoder.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I said trying to model that - not actually going to use one!

 

You seem to be trying to copy the way that one would have to adjust each digit separately on one of those.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

karanbir wrote:
...The encoder is being used as a device to set the count on the seven segment digits. My code in the start of this works great but it takes plenty of spins at the encoder to set the number that is in thousands as it increments every 9th count.

I was looking at being able to set the count digitwise by using the switch on the encoder. ( For 9999 i will need max of 36 advances on the encoder)

For the counter of the revolutions i will use a hall effect sensor.

...

karanbir wrote:
Can the button on the encoder be used to select a digit with every press to set the number on that digit?

 

If your encoder has a push-button, yes that should be readily possible.

eg flash the digit you are setting, with a simple timeout from last click, to change back into run mode from set mode.

 

You may like to use the encoder to select the digit, rather than just step with button, as then you can quickly move left and right on digits.

eg push-in == encoder selects digit one of 4, and button release increment/decrement that digit, for some time window.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Who-me wrote:
You may like to use the encoder to select the digit, rather than just step with button, as then you can quickly move left and right on digits.

eg push-in == encoder selects digit one of 4, and button release increment/decrement that digit, for some time window.

 

We are now into the 3rd decade of the 21st Century - do we really want to be going back to these arcane UX nightmares where one button could do any of 26 different things depending on what incantation of short & long clicks you had used in the last fortnight ...

 

surprise

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

Who-me wrote:
You may like to use the encoder to select the digit, rather than just step with button, as then you can quickly move left and right on digits.

eg push-in == encoder selects digit one of 4, and button release increment/decrement that digit, for some time window.

 

We are now into the 3rd decade of the 21st Century - do we really want to be going back to these arcane UX nightmares where one button could do any of 26 different things depending on what incantation of short & long clicks you had used in the last fortnight ...

 

surprise

If you count carefully, the button actually merely does one of two things (not 26) !   

The OP can decide on the finer points of the button use, I merely gave one example that avoided one-way-traffic effects, which was certainly annoying on the classic clock-set UIs

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

do we really want to be going back to these arcane UX nightmares

I wanna go play some Tempest, just so I can enter my initials as the high score! 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ha! flash backs to a miss spent youth! They cheated by having a flywheel! 

 

Time to fire up Mame!

 

(Mame - multi-arcade machine emulator). Open source project that seeks to emulate just about everything - especially arcade games and various computers from the past. Want to learn about emulation - start there.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Simonetta wrote:

Start at CPU reset with all four LED digit digit displays off.  Set an uint8_t variable to 5.  Test the encoder.  With each activation, increase or decrease the 1000s digit only.  Roll over to zero when advancing past nine, and roll-under to nine when turning the encoder below zero.  When you reach the desired 1000s value, press the button that is currently unused.  Repeat three more times lighting up the 100s, 10s, and 1s  7-segment with value. 

  Now the MCU is ready with a valid count to do its main activity with that count.


This is ideal, but how do I do it. And I need to do it on a Atmega8. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Start at CPU reset with all four LED digit digit displays off.  Set an uint8_t variable to 5.  Test the encoder.  With each activation, increase or decrease the 1000s digit only.  Roll over to zero when advancing past nine, and roll-under to nine when turning the encoder below zero.  When you reach the desired 1000s value, press the button that is currently unused.  Repeat three more times lighting up the 100s, 10s, and 1s  7-segment with value. 

  Now the MCU is ready with a valid count to do its main activity with that count.

I have started my sketch afresh. I am able to set a value on on digit . It rolls over from 9 to 0 but in the reverse from 0 it does not go to 9 


//For Atmega 328 @16 MHz
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdio.h>

#define CLK PC0
#define DATA PC1
#define BUTTON PC2
static uint8_t prevNextCode = 0;
static uint16_t store = 0;

static int8_t rot_enc_table[] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0};
volatile uint8_t digit[4];
volatile uint8_t segmentsfa[] = {0b11111100, 0b00011000, 0b01101100, 0b00111100, 0b10011000, 0b10110100, 0b11110100, 0b00011100, 0b11111100, 0b10111100};
volatile uint8_t segmentsg[] = {0b00000000, 0b00000000, 0b00100000, 0b00100000, 0b00100000, 0b00100000, 0b00100000, 0b00000000, 0b00100000, 0b00100000};
volatile int k, j, i, h  ;
volatile int temp;

int main(void)
{

  DDRC &= ~((1 << DDD2) | (1 << DDD1) | (1 << DDD0)); //Set PC0 and PC1 and PC2 as input
  PINC |= ((1 << PINC2) | (1 << PINC1) | (1 << PINC0));  // Input pullups enabled


  PORTD = 0x00; /*  Writing all bits on port D to 0 */
  DDRD = 0xFF;  /*    Port D set as ouput */
  DDRD &= ~(1 << DDD0); //  Setting PDO as input
  PIND = (1 << PIND0);  // Enabled input pullup.
  PORTB = 0x00;
  DDRB = 0xFF ; /* define port direction for PB0 to PB5 as  output */

  int val;

  while (1)
  {
    int val = 0;

    PINB |= 1 << PB0;
    PORTB = segmentsg[temp];
    PORTD = segmentsfa[temp];

    if (val = read_rotary())  {
      temp += val;
      if (temp == 10) {
        temp  = 0;
      }
    }
  }
}


// A valid CW or CCW move returns 1, invalid returns 0

int read_rotary()  {
  prevNextCode <<= 2;
  if (PINC & (1 << DATA)) prevNextCode |= 0x02; //digitalRead the DATA pin
  if (PINC & (1 << CLK)) prevNextCode |= 0x01; //digitalRead the CLK pin
  prevNextCode &= 0x0f;

  //if valid store as 16 bit data
  if (rot_enc_table[prevNextCode])  {
    store <<= 4;
    store |= prevNextCode;
    if ((store & 0xff) == 0x2b) return -1;
    if ((store & 0xff) == 0x17) return 1;
  }
  return 0;
}

In the next step the number temp will be saved to another variable k to be used during final display.

i am unable to figure out code for the button on PC2. Looking forward to guidance on this.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
      if (temp == 10) {
        temp  = 0;

don't you mean >=10  ???!!!?   make things error-proof

 

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sun. Feb 16, 2020 - 08:45 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

karanbir wrote:
It rolls over from 9 to 0 but in the reverse from 0 it does not go to 9 

because you haven't provided any code that would do a rollover from 0 to 9 !

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

      if (temp == 10) {
        temp  = 0;

don't you mean >=10  ???!!!?   make things error-proof

 

Not quite. The OP needs to catch 9-> 10, to be fixed to 0, and they also need to catch 0-1 -> -1 to fixed to 9

Because this mixes binary numbers and decimal wrap, I don't think a single test can do that, but 2 tests are needed.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks a plenty to who-me, awneil, avrcandies for piointing out glaring mistake in the code. You folks are masters at your game!

I have modified the while loop as below, now it is like the thumbwheel interface.

 

while (1)
  {
    PORTB = segmentsg[temp];
    PORTD = segmentsfa[temp];
    PINB = (1 << PB0);

    if (val = read_rotary())  {
      temp += val;
      if (temp >= 10) {
        temp  = 0;
      }
    }
    if (temp <= -1) {
      temp = 9;
    }
  }
}

 

Last Edited: Mon. Feb 17, 2020 - 04:36 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

karanbir wrote:
piointing out glaring mistake in the code.

This was the kind of mistake that you would easily find by simply stepping through the code manually using paper and pencil.

 

Or stepping the code in a debugger.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Or stepping the code in a debugger.

Which debugger can be used with Arduino IDE for such a purpose?