Shop OBEX P1 Docs P2 Docs Learn Events
Noticable flickering on multiple 7 segment displays because of PULSIN? — Parallax Forums

Noticable flickering on multiple 7 segment displays because of PULSIN?

eagletalontimeagletalontim Posts: 1,399
edited 2008-07-09 16:55 in General Discussion
Here is what i am attempting....

I am wanting to have a set of 7 segment displays to show my current RPM on my car. I am using an RPM function that i found on here and now I am trying to get it to show the RPM on the displays. Everything works except there is a VERY noticeable flicker on the displays. Can anyone help me on how to remove this flicker?

RPM_signal      PIN     RC.0
TRIS_disp       VAR     TRIS_B
rpm              VAR     WORD
pWidth0           VAR     WORD
pWidth1           VAR     WORD
dividendMSW       VAR     WORD
dividendLSW       VAR     WORD
overflow          VAR     BIT
doneBit           VAR     BIT
display         VAR     RB
digit        VAR    WORD
digit1        VAR    WORD
b1              VAR     WORD
PROGRAM Start

PUT_DIGIT       SUB     2
getrpm        FUNC    3, 0

Start:
  TRIS_disp = %00000000

Main:
    rpm = getrpm
    display = PUT_DIGIT rpm
    GOTO Main

PUT_DIGIT:
  b1 = __WPARAM12
  LOW RA.1
  digit1 = b1 / 10
  digit = __REMAINDER
  READ SegMap + digit, display
  pause 5
  HIGH RA.1
  LOW RA.2
  digit1 = digit1 / 10
  digit = __REMAINDER
  READ SegMap + digit, display
  pause 5
  HIGH RA.2
  LOW RA.3
  digit1 = digit1 / 10
  digit = __REMAINDER
  READ SegMap + digit, display
  pause 5
  HIGH RA.3
  RETURN

getrpm:
    PULSIN RPM_signal, 0, pWidth0
    PULSIN RPM_signal, 1, pWidth1
    pWidth0 = pWidth0 + pWidth1
    dividendMSW = $005B
    dividendLSW = $8D80
    rpm = 1
    overflow = 0  
    DO
      doneBit = rpm.15
      rpm = rpm << 1
      IF overflow = 1 THEN
        rpm.0 = 1
        dividendMSW = dividendMSW - pWidth0
      ELSE
        IF dividendMSW >= pWidth0 THEN
          rpm.0 = 1
          dividendMSW = dividendMSW - pWidth0
        ENDIF
      ENDIF
      overflow = dividendMSW.15
      dividendMSW = dividendMSW << 1
      dividendMSW.0 = dividendLSW.15
      dividendLSW = dividendLSW << 1
    LOOP UNTIL doneBit = 1
    rpm = rpm << 1
    rpm.0 = overflow
    IF dividendMSW >= pWidth0 THEN
      rpm.0 = 1
    ENDIF
    RETURN rpm
    ENDFUNC

«1

Comments

  • JonnyMacJonnyMac Posts: 9,392
    edited 2008-07-06 23:11
    The problem is the delay caused by two PULSIN functions, especially at low RPM. I would suggest using an interrupt to multiplex the display and measure your pulses -- it will take some work, but will be the only way to you to fully control the display and prevent flickering.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2008-07-07 00:06
    ok, I am confused on what you mean by using an interrupt....what exactly is that? I tried using the count command to measure the RPM since there is no delay with that, but it is completely inaccurate.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2008-07-07 00:43
    I did some research on interrupts and was not able to get it working. It actually does not show anything on the displays now [noparse]:([/noparse]

    DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
    FREQ            4_000_000
    ID              "M-SEG"
    
    RPM_signal      PIN     RC.0
    TRIS_disp       VAR     TRIS_B
    rpm              VAR     WORD
    pWidth0           VAR     WORD
    pWidth1           VAR     WORD
    dividendMSW       VAR     WORD
    dividendLSW       VAR     WORD
    overflow          VAR     BIT
    doneBit           VAR     BIT
    display         VAR     RB
    digit        VAR    WORD
    digit1        VAR    WORD
    b1              VAR     WORD
    
    INTERRUPT
    
    ISR_Start:
      b1 = rpm
      LOW RA.1
      digit1 = b1 / 10
      digit = __REMAINDER
      READ SegMap + digit, display
      pause 5
      HIGH RA.1
      LOW RA.2
      digit1 = digit1 / 10
      digit = __REMAINDER
      READ SegMap + digit, display
      pause 5
      HIGH RA.2
      LOW RA.3
      digit1 = digit1 / 10
      digit = __REMAINDER
      READ SegMap + digit, display
      pause 5
      HIGH RA.3
    
    ISR_Exit:
      RETURNINT
    
    PROGRAM Start
    
    Start:
      TRIS_disp = %00000000
    
    Main:
        PULSIN RPM_signal, 0, pWidth0
        PULSIN RPM_signal, 1, pWidth1
        pWidth0 = pWidth0 + pWidth1
        pWidth0 = pWidth0 * 2
        dividendMSW = $005B
        dividendLSW = $8D80
        rpm = 1
        overflow = 0  
        DO
          doneBit = rpm.15
          rpm = rpm << 1
          IF overflow = 1 THEN
            rpm.0 = 1
            dividendMSW = dividendMSW - pWidth0
          ELSE
            IF dividendMSW >= pWidth0 THEN
              rpm.0 = 1
              dividendMSW = dividendMSW - pWidth0
            ENDIF
          ENDIF
          overflow = dividendMSW.15
          dividendMSW = dividendMSW << 1
          dividendMSW.0 = dividendLSW.15
          dividendLSW = dividendLSW << 1
        LOOP UNTIL doneBit = 1
        rpm = rpm << 1
        rpm.0 = overflow
        IF dividendMSW >= pWidth0 THEN
          rpm.0 = 1
        ENDIF
        'display = PUT_DIGIT rpm
        GOTO Main
    
    SegMap:
    
    
  • ClintClint Posts: 95
    edited 2008-07-07 02:01
    I think you are missing something·like this to specify the rate.
      OPTION = $88                                  'interrupt, no prescaler
    
  • eagletalontimeagletalontim Posts: 1,399
    edited 2008-07-07 04:07
    ok, I am totally lost now. I got the interrupt written in and now the numbers are showing on 1 random display at a time! What is going on?

    RPM_signal      PIN     RC.0
    TRIS_disp       VAR     TRIS_B
    rpm              VAR     WORD
    currentrpm    VAR    WORD
    pWidth0           VAR     WORD
    pWidth1           VAR     WORD
    dividendMSW       VAR     WORD
    dividendLSW       VAR     WORD
    overflow          VAR     BIT
    doneBit           VAR     BIT
    display         VAR     RB
    digit        VAR    WORD
    digit1        VAR    WORD
    b1              VAR     WORD
    
    INTERRUPT 100
    
    ISR_Start:
        PULSIN RPM_signal, 0, pWidth0
        PULSIN RPM_signal, 1, pWidth1
        pWidth0 = pWidth0 + pWidth1
        pWidth0 = pWidth0 * 2
        dividendMSW = $005B
        dividendLSW = $8D80
        rpm = 1
        overflow = 0  
        DO
          doneBit = rpm.15
          rpm = rpm << 1
          IF overflow = 1 THEN
            rpm.0 = 1
            dividendMSW = dividendMSW - pWidth0
          ELSE
            IF dividendMSW >= pWidth0 THEN
              rpm.0 = 1
              dividendMSW = dividendMSW - pWidth0
            ENDIF
          ENDIF
          overflow = dividendMSW.15
          dividendMSW = dividendMSW << 1
          dividendMSW.0 = dividendLSW.15
          dividendLSW = dividendLSW << 1
        LOOP UNTIL doneBit = 1
        rpm = rpm << 1
        rpm.0 = overflow
        IF dividendMSW >= pWidth0 THEN
          rpm.0 = 1
        ENDIF
      currentrpm = rpm
    
    ISR_Exit:
      RETURNINT
    
    PROGRAM Start
    
    Start:
      TRIS_disp = %00000000
    
    Main:
      b1 = currentrpm
      LOW RA.1
      digit1 = b1 / 10
      digit = __REMAINDER
      READ SegMap + digit, display
      pause 5
      HIGH RA.1
      LOW RA.2
      digit1 = digit1 / 10
      digit = __REMAINDER
      READ SegMap + digit, display
      pause 5
      HIGH RA.2
      LOW RA.3
      digit1 = digit1 / 10
      digit = __REMAINDER
      READ SegMap + digit, display
      pause 5
      HIGH RA.3
      GOTO Main
    
    
  • JonnyMacJonnyMac Posts: 9,392
    edited 2008-07-07 13:37
    Don't use PULSIN inside the ISR, and don't do all your big math in there either. Interrupts aren't a magic pill, they take some serious work to implement if you want them to work properly. What you're going to have to do to get this to work well is simulate PULSIN inside the interrupt. It's not something you're going to be able to bang out in a few minutes.
  • BeanBean Posts: 8,129
    edited 2008-07-07 13:59
    You could solve the problem by not updating the RPM value every time through the main loop.

    Using the original program you posted (without interrupts) this code will update the RPM value about once a second:

    Main:
    · rpm = getrpm
    · FOR cnt = 1 TO 60
    ··· PUT_DIGIT rpm
    · NEXT
    · display = 0 ' Blank display while getting new RPM value
    · GOTO Main

    You will still get a flicker, but it will only be once a second. You could change the "60" value in the FOR line to adjust the update/flicker rate.

    P.S. You should NOT be assigning PUT_DIGIT to the variable display as you are in the line "display = PUT_DIGIT rpm". Just use "PUT_DIGIT rpm".

    Bean.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    "A government big enough to give you everything you want, is big enough to take away everything you·have."·· Thomas Jefferson

    "It is our choices, Harry, that show what we truly are, far more than our abilities."·Dumbledore from Harry Potter

    www.iElectronicDesigns.com

    ·
  • eagletalontimeagletalontim Posts: 1,399
    edited 2008-07-08 02:40
    Is there any other way i can do this and completely remove the flicker? I don't want to be driving at night and have a cop pull me over because I have lights flickering inside my car [noparse]:([/noparse] Is there a different command or a prebuilt function to use to get RPM from a vehicle without using the pulsin command? I know there has to be a way with the COUNT command, but I have no idea how to do the math for that.
  • Sens-a-DatSens-a-Dat Posts: 44
    edited 2008-07-08 03:58
    Using COUNT should be simple, but then again maybe I am missing something in what you need to do for the displays.

    The example in the help file for COUNT provides a good understanding of how to use the command.

    COUNT RPM_signal, 1000, revolutions

    I am using 'revolutions' in the statement as a variable.

    The 1000 in the COUNT command represents 1 second (1000 milliseconds) of timing to give you the revolutions in one second. This is something I am sure you know, but I wanted to state it none-the-less. This value can be changed to 500 (milliseconds), thus the revolutions measured is for one-half second. Or use a count value of 250 for one-fourth second. A multiplier would then be needed to get the desired value for true rpm. For example, RPM = REVOLUTIONS * 60

    I hope this provides some help. Or maybe I am way off of what you are after in using the COUNT command.

    Gary

    [noparse][[/noparse]post edited for clarity for conversion to revolutions per minute]

    Post Edited (Sens-a-Dat) : 7/8/2008 1:22:18 PM GMT
  • JonnyMacJonnyMac Posts: 9,392
    edited 2008-07-08 04:41
    To get rid of the flicker you're either going to have to 1) use the ISR to multiplex your displays and measure your incoming pulses (this will take some work) or... 2) you will have to use an external display driver (like a MAX7219). What you're doing is a bit on the sophisticated side, so it will take some work to get working as cleanly as you like. Have fun, when it is finally working you'll have learned a whole lot.

    [noparse][[/noparse]Edit] I've attached a program that shows you how to simulate PULSIN with custom functions that use the ISR timing. Put your display multiplexing code in the ISR -- everything else goes OUTSIDE (you want the ISR to run as swiftly as possible).

    Post Edited (JonnyMac) : 7/8/2008 5:16:31 AM GMT
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2008-07-08 12:06
    There are multiple ways you can try to accomplish your goal. You can add some extra hardware to capture the pulse information for you. Or you can add some dedicated display driver chips. Of course, the SX itself can handle both tasks quite well if you time your operations right.

    JonnyMac is right. It will definitely take some time to learn how to do this no matter what approach you use. However, it is a worthwhile goal.

    Bean's suggestion is easier to implement but you have stated that even occasional flicker is unacceptable.

    Sens-a-Dat might be on to an alternative concept, though I expect that the COUNT command will take too much time to complete (although fixed) thus creating noticeable flicker as well.

    I will offer you another alternative concept but will not actually solve the particulars for you in this post. Consider running just the display update routine for a moment. It sounds like you will then have a nice, flicker-free display running if you do this. That should work but you need to read data and perform some calculations. If only you did not have to "interrupt" this routine to obtain and process new input data you would have a sweet RPM display for your car that you built yourself. Well, maybe you can still achieve that goal!

    I noticed that in your original display update code you have three sections where you pause for 5ms. What is the SX doing during that time? It is doing nothing useful except counting down the time!

    If you can figure out a way check your input pin state and perform some calculations based on that state in less than the 5ms wait period you can do both without disrupting your display. Do you think you can do that?

    The big drawback to what I have just proposed is in the lack of timing accuracy. As written you will not have a very accurate sense of how much time it takes to execute the primary loop each time. It is possible the difference will be small enough to disregard.

    If the timing errors from this approach are too significant you will have two corrective options. One way to correct for this is to write the code for the loop so that each possible path variation takes the exact same amount of time to complete. This is not trivial but for your tasks should not be extremely difficult. The other way to correct for time invariance is to use interrupts. (There is that interrupt option again!) However, if you can accomplish the above then calling a display update routine once every 5ms while cycling between the three digits of the display will not seem too difficult.

    Really, there are many options. You will learn a lot by trying out more than one. The reality is that trying to have the two time dependent tasks you want to have working together is going to require some careful thought and planning. It can most certainly be done but it is going to require a bit of effort.

    Let us know how you choose to proceed.

    - Sparks
  • BeanBean Posts: 8,129
    edited 2008-07-08 12:53
    Just to throw another option out there. You could connect the RPM signal to the RTCC pin and use that to get a count of the RPM signal.

    Basically you would setup RTCC to count from external input using "OPTION = %1111_1000"
    Then clear the counter by using "RTCC = 0"
    Then update the display for 1 second (you might have to adjust the PAUSE value to get this as close as possible).
    Then do "rpm = RTCC" and "rpm = rpm * 60"

    That is how I would do it...

    Bean.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    "A government big enough to give you everything you want, is big enough to take away everything you·have."·· Thomas Jefferson

    "It is our choices, Harry, that show what we truly are, far more than our abilities."·Dumbledore from Harry Potter

    www.iElectronicDesigns.com

    ·
  • pjvpjv Posts: 1,903
    edited 2008-07-08 13:03
    Hi All;

    Then of course there is the assembler approach using multi tasking scheduler approach. No external hardware required, all the multiplexing speed you want -ie no observable flicker- and as precise as you need.

    However, it is adifferent approach, and much more work..... and tons of fun learning.

    Cheers,

    Peter (pjv)
  • JonnyMacJonnyMac Posts: 9,392
    edited 2008-07-08 16:47
    Peter,

    I'd love to see more examples of your scheduler approach. While it intuitively makes sense to me, I have yet to wrap me head around it enough to be able to use that technique in my own programs.
  • JonnyMacJonnyMac Posts: 9,392
    edited 2008-07-08 22:42
    Tim,

    I've attached a program that does what you want; it uses your math and my original suggestion to use the interrupt for timing and display multiplexing. I've added some traps for low (< 91) and high (> 9999) rpm values. I have this running on a PDB, you may need to adapt for your needs.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2008-07-09 01:44
    wow, that is some complex stuff! I have tested it out and tried to get some kind of output to the displays and nothing yet [noparse]:([/noparse] Thanks for helping!
  • pjvpjv Posts: 1,903
    edited 2008-07-09 03:50
    Hi Jon;

    As a result of the theft of my laptop with all my SX assembler projects on it, I've been forced to rewite my current project because my backup was several months out of date. Lesson learned.

    So I'm rewriting it in SX/B, and I'm having a blast! Normally I would not have entertained such an approach as gnerally I have a serious need for muti-tasking, and that is something SX/B is terrible at. That said, this particular project manages to get by pretty well with a single thread, soI thought to have a go. As I'm learnng SX/B, I'm finding my efficiency in recreating the code to be very high compared to the assembler approach.... somewhere in the 2 to 4 to one range.... realizing of course I'm re-using the algorithms and structure developed previously.

    What I would love to see, is a modified SX/B that can be truly multi-tasking....getting rid of those ugly PAUSEUS and delay statements that cause indeterminism and timing interactions between code segments. And as I learn SX/B I'm seeing the sheer convenience, power and elegance of it...I'm truly marveled by it's simplicity.

    A job well done Bean!

    So, after I expect to finish my rewrite over the next several months, I suggest a few of us meet at some convenient place and time to see if it's possible to make the modifications to SX/B for achieving that end. I'd be happy to fly to Parallax if they would be willing to offer their facility.

    Anybody game??

    Cheers,

    Peter (pjv)

    Post Edited (pjv) : 7/9/2008 3:56:11 AM GMT
  • JonnyMacJonnyMac Posts: 9,392
    edited 2008-07-09 05:06
    Welcome to the big leagues -- interrupts are fun, but not for the faint-of-heart; and the serious news is that SX/B makes them easy now (in the past you had to do a lot of math on your own).

    I can assure you that the program works. It uses four, common-cathode 7-segment displays. The segment mapping is laid out in the digit tables section. If you get the connections right and the program properly downloaded you should see something on the displays.
    eagletalontim said...
    wow, that is some complex stuff! I have tested it out and tried to get some kind of output to the displays and nothing yet [noparse]:([/noparse] Thanks for helping!
  • eagletalontimeagletalontim Posts: 1,399
    edited 2008-07-09 05:13
    I am using 3 common cathode displays for testing purposes for now, and my test board is laid out the same way your program is written. RB's are the anodes, RA's are the cathodes. Not sure why I could not get anything to show. I don't have a 50Mhz crystal so I simply set the frequency to 4mhz and set the OSC4MHZ in the Device. I figured it would at least give me something on one of the pins, but there is no output at all. There was an error at first on one of the subs that said Invalid Number of Parameters, so I had to change VAL_TO_ARRAY SUB 2, 4 to be able to program it to the chip.
  • JonnyMacJonnyMac Posts: 9,392
    edited 2008-07-09 05:24
    When you go changing things willy-nilly (i.e., without a clue) they are bound not to work. That program won't run at 4 MHz, you can't get the ISR to run every 10 uS (what you need to simulate PULSIN in the interrupt) at that frequency. The RTCC wants to generate another interrupt while you're still in the interrupt. The program will run properly with a 20 MHz resonator so you could use that if you have them; I tend to favor 50 MHz on projects like this.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2008-07-09 05:26
    lol...i know, I should not be changing things that already work, but that is basically how I learn tongue.gif I just learned something new [noparse]:)[/noparse] I do have 1 resonator that i can find. it has 500R written on it. I have no idea what that computes to.
  • JonnyMacJonnyMac Posts: 9,392
    edited 2008-07-09 05:26
    Sorry, I was using the beta 2.0 compiler; change the line that uses VAL_TO_ARRAY to this:

    VAL_TO_ARRAY rpm, @digits(0)

    ... the 2.0 compiler doesn't need the zero index. I've reloaded the 1.51.03 compiler and it works fine with this change.

    Since you're serious about SX development get yourself a hand full of resonators from Parallax, and an SX-Key (not the Blitz).

    Post Edited (JonnyMac) : 7/9/2008 5:39:54 AM GMT
  • eagletalontimeagletalontim Posts: 1,399
    edited 2008-07-09 15:13
    I do have the SX-Key [noparse]:)[/noparse] I tried what you said above and re uploaded the program, but I am still not able to get anything to show on the displays much less get anything to output any of the pins on the chip [noparse]:([/noparse] I tried a new chip as well and it did not work. I put my version back on and everything worked as it did before. Not sure what is going on with it [noparse]:([/noparse]
  • JonnyMacJonnyMac Posts: 9,392
    edited 2008-07-09 15:57
    There is clearly a connections problem -- I have it easy on my end because I'm using the PDB, so it's just connecting wires from the SX to the displays. Do you have a schematic of your circuit?
  • eagletalontimeagletalontim Posts: 1,399
    edited 2008-07-09 16:00
    No schematic. [noparse]:([/noparse] When I program the chip, I use the same programming board and put a 1k resistor from RB.1 to an LED, then the LED is connected to RA.1. I know I have the LED in the correct way [noparse]:)[/noparse]
  • JonnyMacJonnyMac Posts: 9,392
    edited 2008-07-09 16:02
    When you say LED, do you mean a 7-segment display?
  • eagletalontimeagletalontim Posts: 1,399
    edited 2008-07-09 16:03
    no, I just have an LED in the board to see if there is any output on the pins. If there is an output, I move it to my other board. It is one of those project boards from RadioShack.
  • JonnyMacJonnyMac Posts: 9,392
    edited 2008-07-09 16:20
    Well, there we go... willy-nilly. Sorry, perhaps I'm just not smart enough to help you take advantage of a perfectly-working program. Before I bow out, let me suggest that you'll save yourself (and those you seek help from) a LOT of time by just putting a programming header on your target circuit. Attempting to test on a circuit that doesn't match the end target is, in my opinion, a big waste of time; but that's just me.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2008-07-09 16:49
    I did not mean to make you upset. I am still learning on the chip and I try new things all the time with it. I had figured that the LED would atleast pulse as it did with my program. I would love to get your program working on my board so I can experiment from there. Would you happen to have a schematic of your board so I can match it with mine?
  • JonnyMacJonnyMac Posts: 9,392
    edited 2008-07-09 16:55
    I'm not upset, but probably won't be contributing to this thread beyond this final post -- I've done what I can for you. Look up the PDB for circuity; it's actually quite straightforward: the segments port (RB) is connected (through current limiters) to the anodes of 7-segment displays; the cathodes port (RA) connects right to the cathodes of each display module -- there's no magic in this.

    Since you're building a custom circuit and asking for help, you should draw your schematic -- that will help forum members help you. If you don't have it, download ExpressPCB and use their schematic editor; it takes about 5 minutes to learn and produces nice, clean output.

    [noparse][[/noparse]Edit] I just downloaded your program, and after filling in the information you didn't provide, find that it runs on my hardware. The only difference is that your ones digit is offset by one in my display as you're using RA.1. My program uses four digits with RA.0 controlling the ones. Still, unless you've changed my code, you should see my program running on your hardware. I do sincerely hope you're able to sort it all out.

    Post Edited (JonnyMac) : 7/9/2008 5:08:04 PM GMT
Sign In or Register to comment.