Combine three variables into one - Page 1
Forum section: electronics / general

author: AcHmed99
author_rank: Contributor
timestamp: June 22, 2016, 11:18:59 am
content: I'm using a PIC16F1717 for reading a pushbutton menu and writing results to the display for a variable output SMPS. The SMPS output is controlled by the 8b DAC on the PIC. I have 4 pushbuttons one for select, one for UP, another for Down and one to Shift the cursor to the value the user wants to adjust. An example selection may be 4.82V. I store 4 in ones,8 in hundreds and 2 in tens. Each ones = 50 steps on the DAC, each hundreds=5 steps on the DAC,the tens are incrementing/decrementing 20mV increments which is the resolution one step.For the 4.82V example I need a way to convert that to four hundred and eighty two (482) then divide that result by two which gives 241 DAC steps, check that its within range less then 256 but greater then 40 steps (output range 5.10V-0.8V). Is there a way to do that without using addtion? Or is there a way to track the DAC directly from the user input?Here is a snip of the function used to track user input on a down pushbutton push.The UP button function is identical only values are incremented.Code:/***************************DWN_Button******************************************Function for decoding down push button push. If we are this far a valid push isassumed and appropriate action (decrement) value at the saved cursor postionones,tens or hundreds via switch case.*******************************************************************************/void DWN_Button(){switch (curs_pos){//We are at postion 11 or tenths.case 11:if(tens == 0){ //last postion was zero so wraptens = 8; //aroundi = (tens)+ 48; //Change value to ASCII for displayWriteVal(); //go write valuereturn;}else{--tens; //20mV resoulotion so dec twice--tens;i = (tens)+ 48; //Change value to ASCII for displayWriteVal(); //go write valuereturn;}break;//We are at hundreths cursor postion 10. Same procedure from tens is followedcase 10:if(hundreds == 0){hundreds = 9;i = (hundreds)+ 48;WriteVal();return;}else{ --hundreds;i = (hundreds)+ 48;WriteVal();return;}break;//We are at ones cursor postion 8. Same procedure from tens is followedcase 8:if(ones == 0){ones = 5;i = (ones)+ 48;WriteVal();return;}else{ --ones;i = (ones)+ 48;WriteVal();return;}break;//We should never get this far but its here just in case.Error invalid cursor//postion DON'T FORGET TO WRITE ERROR HANDLER.default:Lcd_Cmd(_LCD_CLEAR); // Clear displayLcd_Out(1,2,message1); //error message invalid inputbreak;}}//***********************End DWN_Button***************************************

author: dannyf
author_rank: Super Contributor
timestamp: June 22, 2016, 11:35:13 am
content: "Is there a way to do that without using addtion? "You certainly can make it through subtractions, divisiionss, log transformation or something even more complex.But why is addition so offensive here that you have to avoid it?

author: JPortici
author_rank: Super Contributor
timestamp: June 22, 2016, 12:18:40 pm
content: Quotea closed loop where you read the input voltage and change the dac output when the input doesn't match the set point (user input) with all the fun involvedbut to answer the first question, since you don't have a dsp on board it will be much much.. much much faster to keep track of the three digits and reconstruct the binary value than the other way around. you can hand optimize the functions as you will have to do(X + 10 * Y + 100 * Z ) / 2X, Y go from 0 to 9 -> 4 bit -> the 8x8 bit multiplication routine will always have 4 times when you don't need to do nothing, second bit is always zero.Z goes from 0 to 5 -> 3 bit -> 5 cycles of wasted timeat the end you'll have a number from 0 to 511 (0 to 255 + carry), so RRC and you have your 0-255 number.this of course has to be done only once, if you change a digit at a time you just have to adjust the "digit" by adding/subtracting 1,5,10,50,100,whatever

author: Mechatrommer
author_rank: Super Contributor
timestamp: June 22, 2016, 12:39:19 pm
content: why you:1) need to process 47K down button a second?2) care to ask to optimize 99.2% free resources?3) want to find simpler than ADD instruction?4) dont combine UP and DOWN button in one single switch branch to further optimize your 99.2% free resources?5) put tenth decimal in hundreds and hundreth in tens?this is way too much confusing...

author: dannyf
author_rank: Super Contributor
timestamp: June 22, 2016, 01:09:00 pm
content: You are essentially asking if there are more efficient ways without using the most efficient way. I think the answer there is obvious.As to the button processing, yeah, it does look quite inefficient.

author: rstofer
author_rank: Super Contributor
timestamp: June 22, 2016, 02:29:04 pm
content: There is a different way to code the switch processing when you notice how much code is invariant within the if..else.. statement:Code:if(ones == 0){ones = 5;i = (ones)+ 48;WriteVal();return;}else{--ones;i = (ones)+ 48;WriteVal();return;}This could be written as:Code:if(ones == 0){ones = 5;}else{--ones;}i = (ones)+ 48;WriteVal();return;Maybe this form makes it more clear what is being done as a result of the switch press.

author: Buriedcode
author_rank: Super Contributor
timestamp: June 22, 2016, 02:37:51 pm
content: Unless these switch statements are being run inside a control loop, I don't see what the big deal is. The idea of manually adding/subtracting values from variables (like adding 50 to the DAC output if the 'ones' is pushed) is already pretty efficient if that device doesn't have hardware multiply. And if you're just incrementing/decrementing the DAC value based on user inputs, there is no control loop anyway. I assume you're not updating the DAC with the new value until the user presses the enter button? That allows the user to change all the digits and update all at once rather than clumsily jumping up and down the scale as one hits buttons.The up and down buttons essentially do the same thing for each digit, the only variables there are the upper limit (roll over, 9, or 5) and what value to add/subtract from the DAC. As the 'ones', 'hundreds' and 'tens' are global variables theres no need to pass these to a function, and keeping track of what digit is selected is just on char. Perhaps a smaller function that returns the DAC step value for inputs 0-2 (each digit) and the upper limit value (9, or 5) that's called for up or down.

author: rstofer
author_rank: Super Contributor
timestamp: June 22, 2016, 03:03:17 pm
content: The conditional operator is a matter of style and many won't use it but...Code:if(ones == 0){ones = 5;}else{--ones;}could be coded as:Code:ones = (ones == 0) ? 5 : ones - 1;Using such a statement might make your code shorter and easier to read. But it's a matter of style and a lot of folks would prefer the if {} else {} structure.

author: Buriedcode
author_rank: Super Contributor
timestamp: June 22, 2016, 03:17:19 pm
content: also whilst the compiler probably produce less instructions, you can always decrement and check for underflow,Code:if (--ones == 0xFF) ones = 5;

author: Buriedcode
author_rank: Super Contributor
timestamp: June 22, 2016, 08:46:27 pm
content: I know there have been many projects using a micro as the controller, but for LED's the current limit loop should be fast to prevent voltage overshoot. I'm probably in the minority but for a 'testing' power supply that may be used for almost anything (as in, not hardwired to power a particular circuit) I wouldn't use a micro for it.But with that said, if your micro is just handling the user input, the display and outputting a value to the DAC, it'll have more than enough room, and execution time for many extra features should you wish to add them. And it's enough for *some* maths (16x-16 bit multiplication, or division) that will of course be done just in software but it'll still take less than a millisecond at 4MHz.I can see why you were a bit unhappy with the various switch-case statements. They can start to look clumbsy and out of hand, and sometimes is just nicer to merge things into what appears to be a more efficient loop. But depends on the restrictions you impose, with little int he way of memory/execution time restrictions, there is still 'readability'. I often go back to old projects I've done for PIC's and AVR's and have to spend far too long re-familiarizing myself with the algorithm - not because its bad, but because it was highly optimised and not obvious what its actually doing. Sure its nice to seem clever to yourself, but it becomes a real pain if you, or someone else has to modify it.

author: rstofer
author_rank: Super Contributor
timestamp: June 22, 2016, 08:49:43 pm
content: Eventually, you will want the entire keyboard operation to be interrupt driven. You will want to get it out of the control loop and over to one side.Some kind of tiny RTOS is probably the way to go. The keyboard interrupts do as little as possible but once <ENTER> is detected, a message is posted to the control loop to change the settings. Since there is every possibility that there will be incorrect key presses, you need a way to deal with them. You have already updated the display but not the output (before <ENTER>) so you need to roll the display back after some timeout or cancel key.The UI is often the hardest part.

author: altaic
author_rank: Unknown
timestamp: June 22, 2016, 09:21:23 pm
content: Quote from: rstofer on June 22, 2016, 08:49:43 pmThis. Polling and UI should never go together.

author: Buriedcode
author_rank: Super Contributor
timestamp: June 23, 2016, 12:15:53 am
content: Quote from: AcHmed99 on June 22, 2016, 10:46:27 pmWonderful isn't it? As always I didn't really look into those devices when they came out and only last year appreciated the versatility. Sure the opamps have pretty bad offset, and the internal voltage references aren't great but there are *many* projects that don't require those. I've sadly become a bit of a fanboy of the 16F17xx series :/ often with just one on a bit of stripboard and a few passives doing wonderful things

author: dannyf
author_rank: Super Contributor
timestamp: June 23, 2016, 11:13:06 am
content: Rather than calculating the value from three "variables", you could simply add to or subtract from it 100/10/1 based on the keys pressed, with boundary checks obviously.

author: rstofer
author_rank: Super Contributor
timestamp: June 25, 2016, 04:05:51 am
content: Premature optimization is always a mistake. Among other things, the wrong things get optimized.Quote