PDA

View Full Version : PIC's ports individual bits manipulation - how to?



flotulopex
- 25th February 2007, 16:49
Hello,

In one of my projects, I have to adress the first (LSB) four bits of my PIC's PORTA.

This is done within a FOR...NEXT loop so the bits are adressed as a variable ("Digit").

I would like to use the other four bits for other purpose (Button, any Input...) but I can't make this the way I did it up to now.

How is it possible to handle ONLY those four bits wihtout modifying the other (MSB) four bits?

I've attached my code if you like to see how I've done it. Any comments/critics are very welcome.

sayzer
- 25th February 2007, 18:12
Hi flotulopex,

Check this http://www.picbasic.co.uk/forum/showthread.php?t=3753

May give you some ideas.


------------------

flotulopex
- 25th February 2007, 19:54
Thank you sayzer,

I found this thread already. I tried Melanie's way but it doesn't work.

First, it looks as "Digit" won't increment from 0 to 3.

Second, I have put a "spy" before entering the loop. I put PORTA.6 = 1.

Since I use PIC Simulator, I can see the port status and as soon as the program has started, PORTA.6 goes back to 0 (!?).

Am I doing something wrong?

In my code's FOR...NEXT loop, I have put:
for Digit = 0 to 3
value_d = value dig digit
lookup value_d, [$7E,$0C,$B6,$9E,$CC,$DA,$FA,$0E,$FE,$DE], Segments
PORTA.0(Digit) = ~DCD Digit
PORTB = Segments
next

skimask
- 25th February 2007, 20:07
for Digit = 0 to 3
value_d = value dig digit
lookup value_d, [$7E,$0C,$B6,$9E,$CC,$DA,$FA,$0E,$FE,$DE], Segments
PORTA.0(Digit) = ~DCD Digit
PORTB = Segments
next

I'm not so sure that ~DCD Digit will work. I could be wrong. Maybe: ~ (DCD Digit) ?
And I don't see an initial 'ENABLE' in the program itself...not sure if that's needed either or if interrupts are 'ENABLE'd by default.
Ha...just found the answer to that last 'not sure'. Page 183 of the PBP manual states that interrupts are NOT enabled by default...so, you have to turn them on.

mister_e
- 25th February 2007, 20:14
PORTA.0(Digit) = ~DCD Digit
as you write to a BIT, it have to be 0 or 1 ONLY.

Use a LCD or a serial comm to see the results of ~DCD digit... it return 254, 253, 251, 247.

i bet PORTA.0[Digit]=1 is what you're looking for.

SteveB
- 25th February 2007, 20:16
How about something simple, like:



PORTA.0 = Digit.0
PORTA.1 = Digit.1
PORTA.2 = Digit.2
PORTA.3 = Digit.3


HTH,
SteveB

flotulopex
- 25th February 2007, 20:37
I just made this piece of code as test.

MYPORT var PORTA
Loop var BYTE
PORTA.0 = MYport.0
PORTA.1 = MYport.1
PORTA.2 = MYport.2
PORTA.3 = MYport.3

PORTA.6 = 1 'Test to check port's state change in simulator...

Start:
for LOOP = 0 to 3
myport.0[Loop] = 1 'High
myport.0[loop] = 0 'Low
next
goto start
END
It works except the PORTA.6 will change it's status from 1 to 0 when the firt loop will be executed.

skimask
- 25th February 2007, 20:43
I think you've got the variable declarations backwards.
Try myport.0 = porta.0, etc. instead of the way you have it.

mister_e
- 25th February 2007, 20:43
this won't work indeed... and you make it too complicated for what it need to be.



Start:
for LOOP = 0 to 3
PORTA.0[Loop] = 1 'High
PAUSE 500
PORTA.0[loop] = 0 'Low
next
goto start
END

MyPORT.0=PORTA.0 will work only once, If you want to alias a variable bit to a PORT bit... it's an all different story..

flotulopex
- 25th February 2007, 20:53
I've attached two pictures about what I can see.

The first picture "Before Loop Start" shows that my PORTA.0 to 3 are set to "1". This is because I need them to be at this state before the main loop starts (driving CA Leds).

I did the same for PORTA.6 (=1) just for testing purpose. PORTA.6 will be used for something else in my program if I can handle the actual problem.

When I start the execution of the program, PORTA.6 goes to "0" witch is unwanted here.

Mister_E you're right, using DCD will modify all ports.... Was not a good idea on my side. Thank you for making me aware.

mister_e
- 25th February 2007, 21:03
I should have see it first... You must set the TRIS register, unless those pin are set as input.


MYPORT var PORTB
Loop var BYTE
TRISB=0
PORTB.6 = 1 'Test to check port's state change in simulator...

Start:
for LOOP = 0 to 3
myport.0[Loop] = 1 'High
PAUSE 500
myport.0[loop] = 0 'Low
next
goto start
END

skimask
- 25th February 2007, 21:04
I've attached two pictures about what I can see.

The first picture "Before Loop Start" shows that my PORTA.0 to 3 are set to "1". This is because I need them to be at this state before the main loop starts (driving CA Leds).

I did the same for PORTA.6 (=1) just for testing purpose. PORTA.6 will be used for something else in my program if I can handle the actual problem.

When I start the execution of the program, PORTA.6 goes to "0" witch is unwanted here.

Mister_E you're right, using DCD will modify all ports.... Was not a good idea on my side. Thank you for making me aware.

Looks like it might be a bug in the simulator. PortA.6 on the F88 is also OSC2/CLKO. I may have missed something, ya never know. Try it on the real thing and see what happens.

mister_e
- 25th February 2007, 21:09
Never mind.. misread the original code...

flotulopex
- 25th February 2007, 21:10
You may be right!

I just noticed that, using an additional microcontroler view in the simulator, the port doesn't change.

So I'm going to make it in "real".

Another thing; I have declared PORTA.6 as an Input (TRISA = %11110000). When I change this to an Output (TRISA = %10110000), the port will keep it's status as it should be.

Unfortunalety, I will need it as an Input.

I'll go back to my breadboard....

skimask
- 25th February 2007, 21:12
You may be right!

I just noticed that, using an additional microcontroler view in the simulator, the port doesn't change.

So I'm going to make it in "real".

Another thing; I have declared PORTA.6 as an Input (TRISA = %11110000). When I change this to an Output (TRISA = %10110000), the port will keep it's status as it should be.

Unfortunalety, I will need it as an Input.

I'll go back to my breadboard....

Actually, I believe I heard both mister_e and DT both say that they don't trust simulators one bit.
However, I trust the Microchip simulator almost implicitly. Why don't you try running your code on that and keeping an eye on the port values?

flotulopex
- 25th February 2007, 21:25
Well, the simulator I use is wrong. I checked with my logic probe, and this one says true.

Skimask, I have tried to use the MELABS simulator if this is the one you're talking about.

But, compared to the one I use, it was such a hassle to make it work that I abandonned this one.

Is it the one you use?

Dave
- 25th February 2007, 21:37
flotulopex,
INPUTDATA = PORTA >> 4 'LOWER 4 BITS OF INPUTDATA ARE NOW UPPER 4 BITS OR PORTA (INPUT PINS)
PORTA = PORTA & %11110000 'STRIP LOWER 4 BITS OF PORTA
PORTA = PORTA | (DIGIT & %00001111) 'REPLACE LOWER 4 BITS WITH NEW DIGIT DATA

Now your upper 4 bits are stored in variable INPUTDATA. The lower 4 bits of PORTA have just been updated with the lower 4 bits of variable DIGIT.

If I'm incorrect about your original question? I can't think of any easier method.

Dave Purola,
N8NTA

mister_e
- 25th February 2007, 21:43
Flotulopex,
as far as i'm aware of MELABS don't do any Simulator... but i could be wrong.

Skimask talked about the built-in MPLAB simulator (Debugger>Select Tool>>MPLAB Sim) one.

To use it, you need to add some 'Watch' (View>Watch) and then you enjoy seeing them changing.

flotulopex
- 25th February 2007, 21:44
Thanks Dave, this is another way to solve my problem.

Indexing the port may be faster in the loop's execution (I need speed).

flotulopex
- 25th February 2007, 21:47
Right then Mister_e, that's the one I had a hard time to make work...

Maybe I should insist a little more.

The simulator I use is that easy... but maybe not fully reliable so it may be worth to spend more time on the MELABS Sim programmer.

skimask
- 25th February 2007, 21:54
Right then Mister_e, that's the one I had a hard time to make work...

Maybe I should insist a little more.

The simulator I use is that easy... but maybe not fully reliable so it may be worth to spend more time on the MELABS Sim programmer.

I don't know if the MPLABs simulator is 'hard to use', at least I don't think so anyways. There is a bit of an initial learning curve to figure out which windows to use, which keystrokes and which functions key are really handy, etc.
All I do it pull up MPSIM, load the .asm file that PBP gave me, and run it, or single step it or whatever. Yes, you need to have some input values, and maybe a stimulus file, but I don't use any of that and just set my program up to 'fake' those values.
All I can say is that MPSIM has always treated me right...and I especially like the 'stopwatch' function.

mister_e
- 25th February 2007, 22:04
Well it's actually pretty simple once you know how.

Start a new project using the usual method, then Select MPLAB Sim and compile your code.

Go to View> Watch, right to Add Symbol chose the variable you want to monitor and add them in the list.

If you want to monitor a PORT ouput, you go on the Add SFR side.

Once done, press f9 and enjoy the show.

If you have some PAUSE, PAUSEUS in your code... comment them.

You can use and create your Code in MPLAB and use the animate mode... it works. You just need to install properly the MPLAB plug-in. Easier to figure out than the .ASM file.

Today i notice that Microchip have added the VSM plug-in. I need to laugh and waste some time... i'll try it...

flotulopex
- 25th February 2007, 22:22
Well it's actually pretty simple once you know how.
Ça, c'est la phrase qui tue :-)

I wish this could be as simple as it looks like... to your (expert) eyes.

Going to sleep now but tomorrow, MELABS will have to be nice with me!

Bonne nuit.

mister_e
- 25th February 2007, 22:51
MELABS or MPLAB?

Bonne nuit :D

mister_e
- 26th February 2007, 00:17
Update to the VSM... painful and useless as you can't create your OWN neither modify the provided sample...

Idiot and useless...

SteveB
- 26th February 2007, 02:40
I might have misread the original intent, but you did ask:


How is it possible to handle ONLY those four bits wihtout modifying the other (MSB) four bits?

"Under the hood" PBP will either write to the port as a Byte, or set/clear individual bits. This means you have 2 basic approaches:
1) Dave's approach, which deals with the port as a byte. This uses some bit manipulation to preserve the status of the MSBs.
2) And what I was trying to get at, but was not very clear, and that is to set each bit individually.

Just so I've got it straight, as your FOR...NEXT loop counts from 0 to 3 you would like to see a pattern on PORTAs LSB like: 0001, 0010, 0100, 1000. Is this correct?

If this is the case, then this should work:


Digit VAR Byte
DCD_temp VAR Byte

FOR Digit = 0 TO 3
DCD_temp = DCD Digit
PORTA.0 = DCD_temp.0
PORTA.1 = DCD_temp.1
PORTA.2 = DCD_temp.2
PORTA.3 = DCD_temp.3
NEXT Digit

SteveB

nish
- 26th February 2007, 05:54
hi all
i m new to pic16f877a.i need a help regarding timers in pic 16f877a.
in the timer1,T1CON register what is the purpose of using T1OSCEN bit and the T1SYNC bit.if we are using T1SYNC bit,with what signal it will get synchronised and the purpose of synchronization.expecting the reply.

thanx n advance

nish

flotulopex
- 26th February 2007, 07:12
I was already sleeping when I wrote this big mistake.

Thanks SteveB; indexing the ports, like "PORTA.0[Var]", works well. But you're right, it is about to adress the four LSBs.

paul borgmeier
- 26th February 2007, 08:08
If the upper four bytes are guaranteed to always be inputs then you do not need to worry about how “they” are affected by your modifications of the lower four output bytes. Your

PORTA = ~DCD digit
should work fine (all reads are of the actual values of the pins irrespective of any previous written values; all writes are read-modify-write operations).

If the upper four bits could be outputs then you do need to worry and you can use one of the suggested fixes. If speed is an issue as you suggest (but I do not see why it would be, especially with a pause in the main loop), then you could 1) switch to real interrupts (see Darrel's methods) and 2) unroll your for-next loop. A possible version is shown below for the latter.


' PORTA = XXXX1111

value_d = value dig 3 'Select the 3 Digit Value
lookup value_d, [$7E,$0C,$B6,$9E,$CC,$DA,$FA,$0E,$FE,$DE], Segments
PORTA = PORTA - 8 ' PORTA = XXXX0111
PORTB = Segments
pause Scan

MAIN:
value_d = value dig 0 'Select the 0 Digit Value
lookup value_d, [$7E,$0C,$B6,$9E,$CC,$DA,$FA,$0E,$FE,$DE], Segments
PORTA = PORTA +7 ' PORTA = XXXX1110
PORTB = Segments
pause Scan

value_d = value dig 1 'Select the 1 Digit Value
lookup value_d, [$7E,$0C,$B6,$9E,$CC,$DA,$FA,$0E,$FE,$DE], Segments
PORTA = PORTA - 1 ' PORTA = XXXX1101
PORTB = Segments
pause Scan

value_d = value dig 2 'Select the 2 Digit Value
lookup value_d, [$7E,$0C,$B6,$9E,$CC,$DA,$FA,$0E,$FE,$DE], Segments
PORTA = PORTA - 2 ' PORTA = XXXX1011
PORTB = Segments
pause Scan

value_d = value dig 3 'Select the 3 Digit Value
lookup value_d, [$7E,$0C,$B6,$9E,$CC,$DA,$FA,$0E,$FE,$DE], Segments
PORTA = PORTA - 4 ' PORTA = XXXX0111
PORTB = Segments
pause Scan

Goto MAIN


and for clarity – any change to a single pin in PBP actually is writing to the entire port. (i.e, if you do this PORTA.0=1 then the microprocessor does this PORTA = uuuuuuu1 where the u is the value of the port pin at the time of the execution of the command)

flotulopex
- 26th February 2007, 09:05
Thanks a lot, Paul.

First, the "need for speed" is due to the display refresh rate. The higher the speed is, the less time each digit is going to be light on and so, it will dimm naturally.

If I want to make the display brighter, I slow down the loop with the "Scan" pause making the digit to be powered longer.

I could do it another way with a slower clock rate: dimm the LEDs with transistors (this is what I actually did).

Another way would also be to modulate the voltage for each digit's pin at the µc. But I'm not so far yet ;)

PORTA = ~DCD Digit will set 1 bit to a state and all others to the other state; this is an unwanted effect in my case.

I didn't think about your solution; it's always amazing to see how many different ways there are to solve a problem. I will try it anyway since I want to know witch is more memory space effective.

SteveB
- 26th February 2007, 14:58
and for clarity – any change to a single pin in PBP actually is writing to the entire port. (i.e, if you do this PORTA.0=1 then the microprocessor does this PORTA = uuuuuuu1 where the u is the value of the port pin at the time of the execution of the command)

Paul, looking at the ASM, bitwise manipulation of the port is handled by BSF/BCF commands. For example.

PORTA.3 = 1 results in: BSF PORTA, 003h
PORTA.2 = 0 results in: BCF PORTA, 002h
and
PORTA.1 = DCD_temp.1 results in:

btfsc _DCD_temp, 001h
bsf PORTA, 001h
btfss _DCD_temp, 001h
bcf PORTA, 001h

Are you saying that even these bitwise commands, when actually implemented by the PIC, will write to the whole port?

Steve

paul borgmeier
- 26th February 2007, 15:47
Are you saying that even these bitwise commands, when actually implemented by the PIC, will write to the whole port?

Yes - the entire port is updated via port R-M-W when using bcf or bsf.

paul borgmeier
- 26th February 2007, 16:13
First, the "need for speed" is due to the display refresh rate. The higher the speed is, the less time each digit is going to be light on and so, it will dimm naturally.
Have you demonstrated this? Your loop has each digit on for about ¼ the time. Frequency should be irrelevant because with higher frequceny, it will be lit less but will be lit more often. Would not you need to turn the digit off before the pause (or between pauses) to affect the dimness? I will have to think about it more.



PORTA = ~DCD Digit will set 1 bit to a state and all others to the other state; this is an unwanted effect in my case.
I thought you wanted
MAIN:
PORTA = XXXX1110
PORTA = XXXX1101
PORTA = XXXX1011
PORTA = XXXX0111
GOTO MAIN

where the upper nibble were inputs? If they are inputs, they will not be affected by your PORTA=~DCD command because, well, they are inputs.


I didn't think about your solution; it's always amazing to see how many different ways there are to solve a problem. I will try it anyway since I want to know witch is more memory space effective.
Earlier you mentioned speed is an issue, now you mention code space – the unrolled version will not be very code efficient but it should by slightly faster than the looped depending on How PBP converts them to ASM. If one were to write it in ASM, I know the unrolled method would be faster (at least I know I could write an ASM version faster than a looped. Also the PORTA add commands could be done in two instructions versus more as with the >>, & and | approach). However, I still do not know if your upper nibble of PORTA will always be inputs?

Dave
- 26th February 2007, 17:49
flotulopex,The statement: "If I want to make the display brighter, I slow down the loop with the "Scan" pause making the digit to be powered longer." makes no sense if the drive circuitry is designed correctly and the software is truly multiplexing the digit drivers at 100%/number of displays. The only thing that lowering the display frequency will do is at the lower end of about 50 to 40 hz the viewer will start to see the telltale multiplexing action. If at 60 hz. or more the display brightness should not change as far as your eye is concerned. If your display gets brighter as you increase the frequency then your circuitry is not shutting off the digits fast enough. If it gets dimmer as you increase the frequency then your circuitry is not turning on fast enough. This is assuming you have the dutycycle set at 100%/number of displays with no delays. I have designed an automotive gage set using a 16f88 that runs a 4 digit + decimal point multiplexed display that has a 16 step dimming function thru an A/D channel tied to the dashboard dimmer. I chose 63 hz as the lowest frequency to eliminate the STROBING effect during driving.

Dave Purola,
N8NTA

flotulopex
- 27th February 2007, 10:44
Paul,

The four higher bits of PORTA are Inputs and when I checked out the levels on my PIC with my logic probe (set to TTL), using ~DCD would make the ports change status. BUT I have to try with another my PIC since one of my digits doesn't light-up normally making me think about a "little" problem... Should get a new one tomorrow.

About dimming, modifying the scan (refresh) rate of the digits is effectively not a good solution. It's working but, as said in another post, the strobe effect is also accentuated. I have modified my circuit and added transistors in each Common Anode connection. Those four transistors are then levelled by one additional transistor witch is LDR driven. At least, it works fine.

Dave,

My approach is maybe not a good one and any example/critic/suggestion is welcome. It's my first project involving a LED display, I didn't even know what multiplexing was before, so got still to learn more... My english is poor, what is a "gage set"?

Dave
- 27th February 2007, 12:11
flotulopex, It is a set of digital gages used for automobiles. About 3 years ago I gutted a trio of small SUN aftermarket gages in chrome cans and built digital inerds for each. 1 displays water temperature, 1 oil pressure, and 1 battery voltage/current. I beleive the MELABS web site has an intorduction to display multiplexing that you should see and i beleive also some code that you can use as a basis for your program if this helps.

Dave Purola,
N8NTA

paul borgmeier
- 27th February 2007, 15:30
The four higher bits of PORTA are Inputs and when I checked out the levels on my PIC with my logic probe (set to TTL), using ~DCD would make the ports change status.

When using digital inputs, you need to make sure the external connection are either high or low. It sounds like what you are testing are floating (unconnected) inputs, which is a big no-no (not the testing of, but leaving inputs unconnected). Tie your inputs either high or low and repeat - you will see that they are not affected by your DCD command.

flotulopex
- 27th February 2007, 16:32
This could be the trick.

Let me check over and I'll come back.

flotulopex
- 27th February 2007, 22:34
Yes Paul, you're absolutely right.

The DCD command doesn't affect the input ports. Personally, I would appreciate to see this kind of information in the PBP manual. Maybe it will be there in the next edition?

As you mentionned, it is not a good idea to measure ports whithout pull-ups or pull-downs; what I did now.

So, DCD works fine and faster than indexing the ports.

Thank you very much.