Menu

Display voltage in XX.XX but with a caveat

Help
Chris S
2021-09-27
2021-11-19
  • Chris S

    Chris S - 2021-09-27

    and not "XXXX". So I have data coming in, I am scaling it and I want to display it on an GLCD. 10V shows up at 1000, 9.90V shows up as 990V, etc etc. I want it to show up as "10.00V" or "1.024A", etc etc. Normally I know I could convert it to a string, and pad it. But here is the caveat: Im running low on memory. The program barks at me if I try to convert things to a string. Currently I have used up 90-95% of my PICs program and Ive tried to slim things down as much as I can, but the scaling takes up a ton of program space. Now I would be OK with it showing up as is; BUT when the voltage being read back is less than 1000 (or 4 digits) the last digit still stays on screen. A current work around is to basically clear the screen when I turn the encoders. Its lazy but it works.

    Ive tried a few things, but most of them have lead to dead ends. So I figured Id ask here. See lines 220 to 226 (The GLCD print commands)

    I see the following options:

    1) De-solder the PIC and upgrade to the same family but with more memory (I think theres one with 2k program memory).
    2) Downgrade to a smaller I2C GLCD .
    3) Use a nextion GLCD-but this is slightly pricey. The one advantage this has is that I can also implement an NTC temperature sensor to control the heatsink fan since I will have more room for code. I can also do a lot more with the screen and not have to worry about the PIC being bogged down by sending data to the screen all the time.
    4) Make/design a small board to interface to the GLCD I want and just off load the commands to it, and send the commands via UART. I know where I want things, I could just program this PIC to display data. This is more of a coding exercise though.

    Non relevant info: The project is an adjustable bench power supply. Ive written my own encoder function based on one I found for arduino. The two encoders adjust the voltage and current limits. Voltage and current is read back to a screen. I havent packed it up yet, but it does work pretty nicely. Next post will have the mostly done schematics.

    Thanks for the help-Currently at work so any code changes will have to be done tonight.

     

    Last edit: Chris S 2021-09-27
    • Chris Roper

      Chris Roper - 2021-09-27

      Your code would be more relevant to you query than the schematic is but, from what you have described, if you are managing to display xxxxV can you not use fixed point and send 2 chr's, point, 2chr's, 'V' ?

       
      • Chris S

        Chris S - 2021-09-27

        You mean convert to string? yes but string ops put my code overboard and it wont compile since I ran out of space

         
  • Chris S

    Chris S - 2021-09-27

    Schematic.

    If anyone wants to build this, dont populate the LM334. It remains to be seen if I need that.

     
    • Anobium

      Anobium - 2021-09-27
      1. Add the ADC OPTIMISER code. This will save 100 words. I am assuming you only need ADC 0 and 1... else edit. See below.

      2. Remove the Version Control variables.

      3. Change the SPI commands in the library to NOT included the software SPI when you are using the hardware SPI....

      Would yield... 85.96%

      Compiler Version: 0.98.07 2021-08-24 (Windows 64 bit) : Build 1020 Program Memory: 3521/4096 words (85.96%) RAM: 152/512 bytes (29.69%) OSC: INTOSC, 16Mhz (Internal oscillator) Chip: 16F1773

      Evan

      ''' GCB Optimisation file
      
      'Optmise PWM.h
          #define USE_HPWMCCP1 FALSE
          #define USE_HPWMCCP2 FALSE
          #define USE_HPWMCCP3 FALSE
          #define USE_HPWMCCP4 FALSE
          #define USE_HPWMCCP5 FALSE
      
          #define USE_HPWM1 FALSE
          #define USE_HPWM2 FALSE
          #define USE_HPWM3 FALSE
          #define USE_HPWM4 FALSE
          #define USE_HPWM5 FALSE
          #define USE_HPWM6 FALSE
          #define USE_HPWM7 FALSE
          #define USE_HPWM8 FALSE
      
          #define USE_HPWM_TIMER2 FALSE
          #define USE_HPWM_TIMER4 FALSE
          #define USE_HPWM_TIMER6 FALSE
      
      'Optimise A-d.h
        'Standard family chips
          #define USE_AD0 TRUE
          #define USE_AD1 TRUE
          #define USE_AD2 FALSE
          #define USE_AD2 FALSE
          #define USE_AD3 FALSE
          #define USE_AD4 FALSE
          #define USE_AD5 FALSE
          #define USE_AD6 FALSE
          #define USE_AD7 FALSE
          #define USE_AD8 FALSE
          #define USE_AD9 FALSE
          #define USE_AD10 FALSE
          #define USE_AD11 FALSE
          #define USE_AD12 FALSE
          #define USE_AD13 FALSE
          #define USE_AD14 FALSE
          #define USE_AD15 FALSE
          #define USE_AD16 FALSE
          #define USE_AD17 FALSE
          #define USE_AD18 FALSE
          #define USE_AD19 FALSE
          #define USE_AD20 FALSE
          #define USE_AD21 FALSE
          #define USE_AD22 FALSE
          #define USE_AD23 FALSE
          #define USE_AD24 FALSE
          #define USE_AD25 FALSE
          #define USE_AD26 FALSE
          #define USE_AD27 FALSE
          #define USE_AD28 FALSE
          #define USE_AD29 FALSE
          #define USE_AD30 FALSE
          #define USE_AD31 FALSE
          #define USE_AD32 FALSE
          #define USE_AD33 FALSE
          #define USE_AD34 FALSE
      
          'Family of chips based on 16f1688x with ADCON3 register
          #define USE_ADA0 FALSE
          #define USE_ADA1 FALSE
          #define USE_ADA2 FALSE
          #define USE_ADA3 FALSE
          #define USE_ADA4 FALSE
          #define USE_ADA5 FALSE
          #define USE_ADA6 FALSE
          #define USE_ADA7 FALSE
          #define USE_ADB0 FALSE
          #define USE_ADB1 FALSE
          #define USE_ADB2 FALSE
          #define USE_ADB3 FALSE
          #define USE_ADB4 FALSE
          #define USE_ADB5 FALSE
          #define USE_ADB6 FALSE
          #define USE_ADB7 FALSE
          #define USE_ADC0 FALSE
          #define USE_ADC1 FALSE
          #define USE_ADC2 FALSE
          #define USE_ADC3 FALSE
          #define USE_ADC4 FALSE
          #define USE_ADC5 FALSE
          #define USE_ADC6 FALSE
          #define USE_ADC7 FALSE
          #define USE_ADD0 FALSE
          #define USE_ADD1 FALSE
          #define USE_ADD2 FALSE
          #define USE_ADD3 FALSE
          #define USE_ADD4 FALSE
          #define USE_ADD5 FALSE
          #define USE_ADD6 FALSE
          #define USE_ADD7 FALSE
          #define USE_ADE0 FALSE
          #define USE_ADE1 FALSE
          #define USE_ADE2 FALSE
      
       
      • Chris S

        Chris S - 2021-09-27

        Gave this a shot, and I still only have room for one Str conversion, 96.53%. I can convert it to a string, but any manipulation (like left padding), and I run out of memory.

        ex:

        VoltageString=StrInteger(VoltageOutput_Scaled)
        GLCDPrintWithSize(0, 10,leftpad(VoltageString,4,"0"),2,TFT_RED )

        I have a sinking feeling my options are running out.

        Edit: as of 9/27, 7:13PM EST. They have the larger device in production (F1778) which has 28k program space. Might as well go over board right?

        Tried Recompiling the program with the chip options
        PIC16F1776 or PIC16F1778

        and I get an error
        "BenchtopPSU20210927AWithGLCD.gcb (185): Error: Variable ADPREF was not explicitly declared"

        Using version:
        0.98.07 2021-05-27 (Windows 64 bit)

        Interesting. Nothing else has changed.

        Edit #2 @7:26PM.
        Added in the lines
        ADPREF,ADCON1,1
        ADPREF,ADCON1,0
        On line 2624 and 2625 respectively and this fixes it. Compiles with 50% Program space used

        1778 Chip compiles as well if I make the same mods :). I think we have the obvious solution, even though its a slight PITA to de-solder an SOIC....that is if I can find the chip :(

         

        Last edit: Chris S 2021-09-27
  • Anobium

    Anobium - 2021-09-28

    Try this... This removed the WithSize method but I guessing without the actual program. 92%....

    And, I would like to see the ASM.

    GLCDfntDefaultSize = 2
    dim VoltageString as string * 4
    VoltageString=StrInteger(VoltageOutput_Scaled)
    GLCDPrint(0, 10,leftpad(VoltageString,4,"0"),TFT_RED )
    GLCDfntDefaultSize = 1
    
     
    • Chris S

      Chris S - 2021-11-18

      Sorry for the later response. I had to wait to engineer another project to justify shipping costs on a few PICs. But Now ive upgraded to a 16F1778. This code works perfectly and I have more than enough ram + program memory to do other things with it as well. So I thank you and everyone else for your input.

      But now I am on to the next set of problems: The ADC responds too quick and the values change quickly under load even though they stay the same on my meter. When no load is present its fine and reads a perfect 1000mV (10.00V). Under load, it varies from 9700 to 9800. Im guessing its picking up the noise from loading down the rail.

      I had this problem once before, and I forgot how I solved it.

       

      Last edit: Chris S 2021-11-18
      • Anobium

        Anobium - 2021-11-18

        Good to hear the chip sorted.

        The ADC - an ADC Delay to be added?

         
        • Chris S

          Chris S - 2021-11-18

          I think I need a delay, or something else but I suspect a few things:

          1) Noise on the 5V rail when loaded (its not the rail being loaded though). I am using a solid voltage reference though. I dont suspect its this but I'll check the 5V rail when the main rail is being loaded anyway.
          2) Noise from the output being picked up by the ADC. In this case it would be the 120Hz waveform from the filter caps making it through the pass transistor. I suspect its picking up the peaks and valleys. I'll have to confirm values with my oscilloscope.
          3) Quantum mechanics. If I look away it will probably work but observing the circuit collapses its function and the outcome changes 🤣

          What Ive implemented so far: Run timer 1 at one second intervals and read the ADC then. Using this method, it still happens. The only slight issue this causes is that I dont see the change on the screen if Im changing the voltage.

          For #2 maybe an averaging function would work?

          Other possibilities: Maybe heat killed my op-amp again from being near the PIC being desoldered?

           
          • mkstevo

            mkstevo - 2021-11-18

            Add a small capacitor across the ADC input? Depending on your resistive divider 10nF to 100nF or so? You could solder/connect the capacitor directly across the lower portion of the resistive divider.

            Of course averaging consecutive ADC readings would work just as well.

            Not forgetting where and how the negative return is connected on the circuit you are measuring the voltage of.

             
            • Chris S

              Chris S - 2021-11-19

              I think I have a clue as to whats going on. Makes no sense but here we are. My voltage reference gets dragged down when a load is placed on the main circuit. Heres the kicker: That voltage reference isnt tied to anything else BUT the PIC micro 😕 😕 😕

              I mean, the PIC ADC shouldnt take up much current from the voltage reference. Maybe I'll reduce the resistor value and see if that fixes it. So it doesnt seem to be software. But Im tired.

              So, I did de-solder and resolder this reference. Maybe I ruined it?

               
  • Anobium

    Anobium - 2021-09-28

    Regarding the ADPREF error. PICINFO shows that ADPREF does not exist. Which is correct per the MPASM INC file, which shows:

    ;----- ADCON1 Bits -----------------------------------------------------
    ADNREF           EQU  H'0002'
    ADFM             EQU  H'0007'
    

    However, this does not match the datasheet

    491h ADCON1 ADFM ADCS<2:0>  ADNREF ADPREF<1:0> 0000 -000 0000 -000
    

    The INC file should be:

    ;----- ADCON1 Bits -----------------------------------------------------
    ADPREF0          EQU  H'0000'
    ADPREF1          EQU  H'0001'
    ADNREF           EQU  H'0002'
    ADCS0            EQU  H'0004'
    ADCS1            EQU  H'0005'
    ADCS2            EQU  H'0006'
    ADFM             EQU  H'0007'
    

    The errata does not show this error. We should report.

    We can sort in the DAT file generation, but, can you do me a favor - examine all these parts... do they all have the same issue?

    PIC16(L)F1773 
    PIC16(L)F1776 
    PIC16(L)F1777 
    PIC16(L)F1778 
    PIC16(L)F1779
    others ?
    

    We can adapt the generation (so, this is resolved in the future) but I need to know which chips are impacted.

    So, I need some analysis to correct for everyone else.

     
    • Chris S

      Chris S - 2021-09-28

      You know whats strange? Notepad++ can usually open files with no problem. It opens the .dat files but for some reason, doesnt show the ADC registers. They show up properly if I open it up in GCCB.

      PIC16LF1779-No Ref
      PIC16LF1778- No Ref. Shows it but I think I modified it.
      PIC16LF1777-No Ref
      PIC16LF1776-No Ref
      PIC16LF1773-No Ref

      PIC16F1779-No ADPREF
      PIC16F1778-No Pref (but I know I modified this one last night)
      PIC16F1777-No ADPREF
      PIC16F1776-Has ADPREF. I possibly modified this one.
      PIC16F1773-Has ADPREF

      I have one more thing to try before work. I'll open up MBLabX and start a project there with the 1779

       

      Last edit: Chris S 2021-09-28
      • Anobium

        Anobium - 2021-09-28

        I will add to the generation process a fix to resolve the issue in Great Cow BASIC.

        Re MPLAB-X if you are using 5.xx then the compiler does not use the INC files. The way to test... is to select MPASM as the compiler in Great Cow BASIC. And, MPASM cannot parse ADPREF


        Also, more importantly. Where you set ADPREF = 10 this is wrong. Very wrong.

        This is the correct change

        ADPREF1,ADCON1,1
        ADPREF0,ADCON1,0
        

        ADPREF is two bits of register ADCON1 therefore you cannot set to 10. If you use the change you used you will simply incorrectly set bits in ADCON1. To be clear ADPREF does not exist as a register or byte. And, should not be created as such. ADPREF0 and ADPREF1 are bits. To set these bits use a ADCON1 mask, an alias, or directly set as follows;

        ADPREF1 = 1
        ADPREF0= 0
        
         
  • stan cartwright

    stan cartwright - 2021-09-29

    @Chris S "10V shows up at 1000, 9.90V shows up as 990V, etc etc. I want it to show up as "10.00V"
    divide number ie 990 by 100 and print
    then print "."
    then divide 990 by 10 and print
    should get 9.99

    edit think it need mod

     

    Last edit: stan cartwright 2021-09-29
  • William Roth

    William Roth - 2021-09-30

    Looking at the code:

    //ADC Setup
    ADPREF=10 ;ext vref
    ADCON1.1=1
    ADCON1.0=0
    ADON=1  ;Turn the ADC on
    ADCON1=0b11100010
    

    This can be reduced to :

    //ADC Setup
    ADON=1  ;Turn the ADC on
    ADCON1=0b11100010
    

    There is no need to set the ADCON1.1 and ADCON1.0 bits twice
    There is also no need to Set "ADON = 1" If you are using READAD or READAD10 as GCB manages this.


    To save more memory .... Consider that ALL I/0 pins default to inputs on Power up. Therefore, there is no absolute need too explicitly set an I/0 as an input as this is the default POR State. Only the outputs really need to be set with DIR. This can save a few words of memory . You could save even more memory by setting the TRIS Registers directly like this:

    TRISA = 0b11011011      ' "1" is Input  "0" is output
    TRISB = 0b11010000
    TRISC = 0b11100111
    

    Then comment out all of the DIR statements

    But alas ... if you are scrambling for even more memory, it might be prudent to get the right sized chip for the application, one that gives you some wiggle room.

    William

    Edited to correct TRIS bits

     

    Last edit: William Roth 2021-09-30
  • William Roth

    William Roth - 2021-09-30

    I made a few more changes/corrections to the original code. Now at 88.45% All of the changes will be remarked with

    ' ***** WMR
    

    The compiler now reports:

    3623/4096 words (88.45%) RAM: 222/512 bytes (43.36%)

    Review the code to see the changes.

    @Anobium

    Not too sure that the compiler is reporting the correct Program Memory usage.
    (4096 - 3623) = 473 Words Free

    However looking at the hex ( Using PK2+ Hex View) I see only 424 Words Free

    William

     

    Last edit: William Roth 2021-09-30
  • Anobium

    Anobium - 2021-09-30

    @williamroth I just loaded into PIC-AS the HEX looks like 471 words. Look ok here using PIC-AS as a reference.

     
  • William Roth

    William Roth - 2021-09-30

    It looks ok but due to how memory "pages" are managed in 16F Chips ...all 471 words may not be available.

     

    Last edit: William Roth 2021-09-30

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.