PDA

View Full Version : PIC speed problems



The Master
- 4th October 2008, 21:31
Hi, This is about the lighting circuit ive been making with LEDs. Im using PWM to fade the LEDs. With this being DC im just flashing them really fast (no zero crossing or anything like with 240V AC). The problem i have is when i send serial data to it it has to spend a few milliseconds processing the data. Thats causing the lights to flash. I dont think i will ever get rid of it completely but i want to minimize it as much as possible.

Would someone be kind enough to tell me how long these things take please?
Copy 1 byte from RCREG into a variable
Copy 1 byte from a variable to another variable
If statements with 1 condition (EG "if aByte=255 then")
Passing a set value to a variable (EG "aWord=3000")
Bit masking (EG "temp & %11111100")
Bit shifting (EG "temp >> 2")
SELECT CASE. Does this take longer for matches further down the list?
Clearing serial buffer problems (cant remember which problem) RCSTA.4=0 / RCSTA.4=1

I know i asked about 1 or 2 of those before but i cant remember which and i cant find the thread. If i know how long it takes for each thing then i can spread them out more evenly and add more pauses in when no data is arriving to balance things out a little.

rmteo
- 4th October 2008, 23:11
Which PIC are you using? If it has hardware PWM, then use that and it will eliminate the blinking completely.

The Master
- 5th October 2008, 00:04
Its a PIC16F87. From what i can see it only has 2 PWM outputs. I need 4. Good idea though. I never thought of that. Maybe if there is another 18pin PIC with 4 PWM outputs then i can use it

skimask
- 5th October 2008, 00:19
Its a PIC16F87. From what i can see it only has 2 PWM outputs. I need 4. Good idea though. I never thought of that. Maybe if there is another 18pin PIC with 4 PWM outputs then i can use it
Or, you could look up Slow Speed software based PWM and get almost as many channels of PWM for messing with LEDs as your PIC can handle.
I've been able to do 20 RGB LEDs (3 colors each of course) at 152.5Hz (way fast enough to prevent flickering), serial data input/output (using the PIC's hardware modules), key pad scanning, reading an eeprom, housekeeping chores, etc. all using a software PWM scheme based off Timer 0. Works like a champ, no flickering, etc.etc. That's with an 18F at 40Mhz. Use a 16F at 20Mhz, and you'll still be able to get 76.2Hz (again, fast enough to prevent flicker) and still be able to drive a load of software based PWM outputs on an 18pin PIC.

The Master
- 5th October 2008, 01:35
Ok, ill have a look around for it. Im using a 20MHz oscillator already. The baud rate for the serial data is 115200. I would have thought that uses more processing power but i did have this working earlier. The problem seems to be with the code between the serial data arriving and the LEDs being turned on. Im still cutting as much out as possible but theres a limit to how small a program can be before it doesnt do everything you want. Ill probs strip my program back to basics when i test out that software PWM thing then build it up a few lines at a time.

skimask
- 5th October 2008, 02:01
You're using an 'F87, I used an 'F628A. 15 I/O pins available for me, 2 used for 20Mhz crystal, 2 used for Serial I/O, PGM/MCLR tied as needed, 3 buttons and 6 LEDs (2 RGB), and one spare pin. I was able to do serial at 19,200 without a problem using the hardware module (datasheet says it's 1.7% high, but it worked). Used Timer0 kicking an overflow interrupt at 19.531khz, software PWM for each LED at 76.2Hz, 8 bit resolution. Could get a higher refresh rate at the expense of resolution. Once in a great while, I'd get a slight bit of one-time flicker if I was trying to receive serial data too fast or send it too fast, but that's completely up to the software driving it.
I think that 'looping' PWM will end up kicking your butt in the long run, but that's just me.
Time to learn how to use interrupts to your advantage!

The Master
- 5th October 2008, 21:36
I found that PWM thing. Took a bit to get it working (installing MPASM etc) but i figured all that out. The problem i have is that for some reason the serial interrupt, PIR1.5, never equals 1. Im not sure whats wrong. At first i thought maybe the loop wasnt running but i added code to increase/decrease the PWM value and it worked fine. Its just that interrupt that doesnt seem to work. Im guessing its got something to do with the timer interrupt overriding it or something.

Edit: Im not using ON INTERRUPT. Aparently that doesnt work. Im only checking for PIR1.5

skimask
- 5th October 2008, 21:59
Edit: Im not using ON INTERRUPT. Aparently that doesnt work. Im only checking for PIR1.5

I'm using the ON INTERRUPT in that particular program I eluded to earlier. Works fine for me. It's definitely not optimal like the Instant Interrupt's, but it works and it would take too much rework to change it over.

If you're serial isn't working, get rid of the PWM for awhile and just turn things on/off to show that the serial port is in fact working (or not). Again, break it up...then put it back together...

The Master
- 5th October 2008, 23:20
The serial was working fine before and still does work with test programs. It only stops working when i add the PWM code. I tried adding the PWM code to an existing program that i know works. The PWM works fine but stops the serial from working. I also tried a brand new program starting with just the PWM and adding serial but with the same results.

I cant seem to send data while the PWM code is in either. Its like its overriding the settings for things like continuous receive etc and disabling serial.

Would it be worth trying to write code to use the timer similar to this PWM code but writing it in PBP instead of ASM? I dont understand ASM at all so when something goes wrong i have no idea how to fix it. Is there something like PIR1.5 but for the timer instead? Would that work or would it run too slow?

Edit: I have some code to turn a status LED on for about half a second whenever PIR1.5 equals 1 regardless of the data i get from RCREG. Always works without PWM but never works with it. I also had a blank project with only PWM and some simple serial receive code that copies RCREG directly to one of the PWM values but still no luck

skimask
- 6th October 2008, 01:02
Ok, just to be on the same page here...
When you say 'PWM' code, what do you mean exactly?
Something tells me that you're using the 'PWM' command and not the hardware, or even an interrupt based PWM method...

The Master
- 6th October 2008, 09:12
Im using a pbp project that i downloaded from the net. Its written by Darrel and you use it as an include file. I got it from here http://www.pbpgroup.com/modules/wfsection/article.php?articleid=12. Where i said "PWM code" i should have said "Multi_SPWM.pbp and the few lines you have to add to make it work"

On that page Darrel said "There's no way to combine Basic Language (A.K.A. ON INTERRUPT GOTO) type interrupts, with ASM interrupts". Does that include PIR1.5 then?

skimask
- 6th October 2008, 11:38
On that page Darrel said "There's no way to combine Basic Language (A.K.A. ON INTERRUPT GOTO) type interrupts, with ASM interrupts". Does that include PIR1.5 then?
Not necessarily true anymore. Look into the Instant Interrupts. You can combine them, but it's a bit of a pain.
http://darreltaylor.com/DT_INTS-14/intro.html

The Master
- 6th October 2008, 12:26
Ive had a read through a few pages on there and it seems that it shouldnt be a pain. I like the bit that says "It all "Just Happens".". Ill test it out when i get home from work.

Just out of interest, what actually happens in the ASM part? It sounds like there is a main loop running that checks each of the interrupt flags then allows the PBP bit to run. Its a little confusing because a pause command doesnt seem to affect it even though pause should stop code executing for a set amount of time. I have been told that to create a pause in ASM you need to have a loop that does nothing. Im guessing the interrupts are checked on each iteration of that loop too.

ASM is on my "to learn" list but i havnt found time to start yet

The Master
- 6th October 2008, 20:32
Ive been working on this for about 2 hours now and ive just got it working. Ive tested it by sending 512 bytes of data at 115200 baud and it all seems to work fine. At first the LEDs were flickering really bad but i just had to change the SPWM_FREQ. Im going to start tidying the code up a little and adding my code back in. Hopefully it wont slow it down at all.

Thanx for pointing that out and a big thanks to Darrel for writing it!

The Master
- 6th October 2008, 22:25
Ive added a little code in now and it seems to be causing problems. Heres what my code looks like



serialData:

'Get a byte of data
temp=RCREG

datapos=datapos+1

select case datapos
case 1
vred=temp
case 2
vgreen=temp
case 3
vblue=temp
case 4
vwhite=temp
datapos=0
end select

@ INT_RETURN


As you can see theres nothing special. It simply sets each byte to one of the 4 colors in turn. The problem is that if i set any color to half on (anything other than 0 and 255) i get really bad flashing on all the LEDs. Thats even just sending 1 byte of data at a time. Im gonna try messing with it to see if i can get it to work better. Do you have any ideas?

skimask
- 6th October 2008, 22:29
'cause your PWM freq isn't high enough in the first place. The freq of a 0% duty cycle wave is...0. The freq of a 100% duty cycle wave is...0.

The Master
- 6th October 2008, 22:47
Ive tried changing SPWM_FREQ to a bunch of different values. Anything below 60 causes the LEDs to continously flash. Anything above 50 causes bright flashes or dimming whenever data is received. I think its because there isnt enough processing power to accept serial data at that speed aswell as doing PWM at a frequency of 50+

Would it be best to try and find a PIC18F so i can use a higher oscillator? Other than that i can only think of lowering the baud rate and/or reducing the amount of data sent. I suppose that is an option but with each light using at least 4 bytes of data i wont be able to have many lights

skimask
- 6th October 2008, 22:55
Fact: There's plenty of processing power to do what you want to do...
Fact: There's not enough knowledge behind the keyboard to do it....YET!

Ok, as good as SSPWM is and as good as the Instant Interrupts are, I want you to take a look at the attached file. It's a program I wrote to handle a single RGB LED (actually a string of them) and serial data, no SSPWM, no Instant Interrupts, works great for me. The only reason I have it set up for 2400 baud right now is because of the distance between the controller and slave unit. On the bench, it worked just fine at 57.6Kbaud (or whatever that divisor comes out to)...but it wouldn't work reliably out in the field (again, because of the distance), and 2400 baud was plenty fast for me.
Take a look at the file. I'll clean it up a bit and re-upload it soon.

The Master
- 6th October 2008, 23:14
Well, thats good news (about having enough processing power). I will learn this properly now matter how long it takes.

Your program looks similar to the way i was doing things origionally. I had a loop that kept checking if serial data had arrived thought. You are using oninterrupt aswell. I think the difference is how i did the timing for the PWM. I didnt use pause at all, instead i used the speed of the loop. The faster the pic chip runs the faster the PWM should run. In theory that should have worked fine. The problem i had is that when serial data arrived it was delaying a few iterations of the loop and causing a flash.

I see that you are using the timer. That should do what i was trying to do in the first post of this thread. I wanted to add extra delays when the serial data wasnt arriving etc to balance things out. The timer should automatically do that.

Its a little late now so im gonna go to bed. A good nights sleep usually helps with things like this. Ill have another go tomorrow. Ill start again from scratch and try using the timer from within PBP which seems to be intcon.2. Im going to try coding the data receive code better too. Each light only needs to look out for about 4 bytes of data. It can ignore the rest. I also have an idea to test how much of an impact the serial data has on the program so ill give that a try too

skimask
- 6th October 2008, 23:18
I had a loop that kept checking if serial data had arrived thought.
A loop is a loop until you start to do stuff in that loop. That's when a loop becomes something else.


You are using oninterrupt aswell. I think the difference is how i did the timing for the PWM. I didnt use pause at all, instead i used the speed of the loop. The faster the pic chip runs the faster the PWM should run. In theory that should have worked fine. The problem i had is that when serial data arrived it was delaying a few iterations of the loop and causing a flash.
Yep, and I'm doing my PWM in a controlled manner. Basically, I'm doing nothing more than the hardware PWM already does except I'm doing it manually. Manually updating the count, manually doing the compare to either turn on or off the output.


I see that you are using the timer. That should do what i was trying to do in the first post of this thread. I wanted to add extra delays when the serial data wasnt arriving etc to balance things out. The timer should automatically do that.
Pull the data out of the serial port as fast as you can and process it later. It's not going anywhere and this type of thing isn't time critical (i.e. you won't have a nuclear meltdown if you don't update the RED LEDs right now!).
Just a quicky 'block' example of an idea for you...


'setup all the variables, pins, etc.etc.etc.etc.

'On Interrupt
'checks Tmr0 overflow and updates outputs based on duty cycle registers
'checks Serial RX register and saves value
'Returns from interrupt

'subroutines

'more setup

'main loop
'acts on serial data received to change desired duty cycle registers for individual LEDs
'for example, break the received byte into bits...
'b7-b4 = LED duty cycle to modify (b7=Red,b6=Green,b5=Blue,b4=White)
'b3-b2 = increase/decrease/max/min (b3=increase by x, b2=decrease by x)
'b1-b0 = increase-decrease amount (00=by 1, 01=by 5, 10=double or half depending on b3-b2, 11=max or min depending on b3-b2)

'goto main loop

'on interrupt fires as often as it needs to fire, every time Tmr0 overflows (19.5khz) and/or whenever a data byte is received at the serial port (i.e. 115,200 baud isn't too fast)

So, using this example, you send %11111011, it will:
1111 = bit 7 thru bit 4, all LEDs selected
10 = bit 3 thru bit 2, increase by x
11 = increase values to maximum

The Master
- 7th October 2008, 09:48
Aparently the PIC im using only has 368 bytes of ram. There isnt enough room to buffer 512 bytes of data.

I have been kinda trying to do that. I have a buffer in the form of an array (4 elements). When a byte is received it gets copied to a temp variable. Each one that arrives increases a counter. When the counter is between the lights address and the lights address plus 4 it copies the bytes into that buffer. Once the count reaches 512 then it moves the buffered bytes into the variables that control the PWM.

I suppose i could lose the temp variable meaning 1 less copy operation per byte. I actually added the buffer because its possible to send 1 byte at a time from the PC and i didnt want the PWM to update until all the data has been sent. It also syncs the lights better because the first one wont change until the last one is ready to change.

Because of the ram problem i need to process the first byte as soon as it comes in. One bit of that tells the light whether its using the line ID or the address so it knows which bytes to look for. Then im going to need an if statement to check if the byte is one of those that its looking out for. I can do everything else in the main loop if the datapos is 512.

I see why my origional code didnt work. The PWM part worked fine. I could fade the LEDs in and out etc. The problem was with serial. As soon as a byte arrived it stopped everything else processing to deal with the data. Simply accepting the byte and updating the PWM values even worked fine when sending 1024 bytes. The problems seem to start when if-thens and select cases are added. From what i know about this interrupt stuff i think i can still have all those ifs/selects but as long as they are in the main loop then the interrupt can break out half way through to update the outputs then carry on with the processing.

This all looks good but i thought thats what Darrel's code does. Darrel did mention that his code uses something like 70% of the processing power because of all the interrupts. Wouldnt i just get the same thing in PBP? From what ive heard ON INTERRUPT is even worse

The Master
- 7th October 2008, 12:06
Ive been reading the datasheet for this PIC again. Ive found the bits that talk about the timer and interrupts etc. It says "Timer0 module will increment every instruction cycle (without prescaler)." and "8-bit timer/counter". So it appears that it will count up by 1 on each instruction cycle and keep counting until it reaches 255. The next increment will cause an overflow (resetting it to 0). If INTCON.5 is enabled then this overflow causes an interrupt.

Now if i look at the OPTION_REG Register i see some stuff about this "prescaler". If i set that to 2:1 does that mean the timer increments once every 2 instruction cycles?

skimask
- 7th October 2008, 13:48
Aparently the PIC im using only has 368 bytes of ram. There isnt enough room to buffer 512 bytes of data.
Time to switch boats and go with an 18Fxxxx...


I see why my origional code didnt work. The PWM part worked fine. I could fade the LEDs in and out etc. The problem was with serial. As soon as a byte arrived it stopped everything else processing to deal with the data. Simply accepting the byte and updating the PWM values even worked fine when sending 1024 bytes. The problems seem to start when if-thens and select cases are added. From what i know about this interrupt stuff i think i can still have all those ifs/selects but as long as they are in the main loop then the interrupt can break out half way through to update the outputs then carry on with the processing.

This all looks good but i thought thats what Darrel's code does. Darrel did mention that his code uses something like 70% of the processing power because of all the interrupts. Wouldnt i just get the same thing in PBP? From what ive heard ON INTERRUPT is even worse
ON INTERRUPT is worse in most cases, yes. I've managed to get along with it ok, just have to keep track of what's going on. Yes, SSPWM can take a lot of processing power, depending on what you're doing.
Example...4 LED channels to update, Serial port reading, etc.etc.
Tmr0 overflows every 256 instruction cycles...When the interrupt hits, a couple cycles to get to the int-code, check the flag, 2 more, reset the flag, 2 more, update the pwm counter, a couple more cycles, update all of the LEDs, say 4 cycles each for 16 total, kick out of the interrupt code, 2 more cycles, comes out to roughly 30-ish cycles (probably more, but just an example)...
Add in a Serial port interrupt...couple of cycles to get to the int-code, check the flag, grab the data, store the data, exit the interrupt, roughly another 16-ish cycles.
Call it 100 cycles just to be overestimating everything by a load... That still leaves the PIC with another 156 cycles until the next overflow to process the incoming data 'packet', update anything it needs to update, etc.
At 115,200, a byte can possibly show up every 86.8us. Timer0 would overflow every 256us (assuming prescale of 1:1) when running the PIC at 4Mhz. Run the PIC at 20Mhz, and Timer0 would overflow every 51.2us (again, assume prescale of 1:1), leaving you with plenty of time to handle the serial, handle the 4 channels of lights, and so on and so on.
So I guess the moral of the story is, if you're running 4Mhz, time to bump that up a bit...


Now if i look at the OPTION_REG Register i see some stuff about this "prescaler". If i set that to 2:1 does that mean the timer increments once every 2 instruction cycles?
That's why it's called a prescaler :)

The Master
- 7th October 2008, 14:19
I was thinking about swapping to a 18F. They seem to be better for ram and oscillator speed although im already using 20Mhz and you say that is enough.

I understand your explanation about instruction cycles but you lost me a bit with the us explanation.

If i have all these cycles spare then does it matter whether i process the data in the main loop or the interrupt handler? What exactly is an "instruction cycle"? Is it the same as a word? (I mean word asin "Success : 100 words used", not the data type)

How do you know how long it takes to execute each instruction cycle? The datasheet says its 200us but that changes depending on the oscillator.

skimask
- 7th October 2008, 14:26
Instruction cycle = oscillator/4, i.e. 20Mhz oscillator = 5Mhz instruction cycle rate = 200ns per instruction cycle. Most things in a PIC are based off the instruction cycle, not the actual oscillator.
Yes, 20Mhz is more than plenty.
Spare instruction cycles - best to handle as much as you can in the main loop. Get in and out of the interrupt handler as fast as possible. While you are in the interrupt handler, you generally can't handle another interrupt (well, you can, but that's beyond the scope at the moment), therefore, you can't handle anything else until you get out of that interrupt routine.
Instruction cycle - a NOP takes one instruction cycle, it also takes one word of code space.
A GOTO takes 2 instruction cycles, but takes up only one word of code space. That info is in the 'Instruction Set' section of your PICs datasheet.
But to figure out how long it takes each 'block' to execute, you either have to count it out, or use one of a few different methods to calculate it (MPLAB, use one of the PICs timers, etc.etc.).

The Master
- 7th October 2008, 15:16
In making sense of that i just realised i forgot about microseconds. Nano seconds are 1000 times faster than i thought.

So when a datasheet says "200ns instruction cycle" thats calculated for the highest possible oscillator you can use with it. In this case 20MHz.

If the serial data comes in at about 86.8us then i work that out to be once every 434 cycles. Now it sounds more realistic.

So if i have a main loop that doesnt pause or anything then would it make sense to only have an interrupt for the PWM and repeatedly check PIR1.5 in the main loop? That way the interrupt might still be run when serial data arrives but it wont have to do anything and will be straight out of the interrupt handler. The main loop should then be able to pick it up on its next iteration and do all the processing within 434 cycles.

I guess i dont really have 434 cycles to play with because the PWM interrupt will use up a few cycles. Using your example it should run almost twice between each byte of serial data. If we say it uses 100 cycles to be on the safe side then i should have over 234 left to do the processing.

Does that make sense or have i got it all mixed up again? Its starting to look just like my original code except for the timer. When i first started this thread i was trying to do the timer's job manually and i think thats where it all went wrong

skimask
- 7th October 2008, 16:32
So if i have a main loop that doesnt pause or anything then would it make sense to only have an interrupt for the PWM and repeatedly check PIR1.5 in the main loop?
No...PIR1.5 (i.e. the serial port, either TX'ing a byte or RX'ing a byte) will trigger an interrupt if properly set up...that's the way interrupts work. If you can't get an interrupt to trigger, it might be because there's nothing there to trigger that interrupt and/or your serial port isn't working in the first place.

The Master
- 7th October 2008, 16:59
What i meant is that the interrupt would copy the byte from RCREG into a temp variable. Then the code in the main loop would need a way of knowing when a byte has been received to process it (possibly a bit variable). What im saying is why not just check PIR1.5 instead of having another variable to say serial data has arrived and why not use RCREG directly in the main program loop instead of having another byte variable. It would mean the serial interrupt completes much quicker because it doesnt do anything.

Should i be removing the byte from RCREG in the interrupt? If it doesnt matter as long as i do it before the next one arrives then doing it in the main program loop looks like a better way of doing it

skimask
- 7th October 2008, 17:17
What i meant is that the interrupt would copy the byte from RCREG into a temp variable. Then the code in the main loop would need a way of knowing when a byte has been received to process it (possibly a bit variable). What im saying is why not just check PIR1.5 instead of having another variable to say serial data has arrived and why not use RCREG directly in the main program loop instead of having another byte variable. It would mean the serial interrupt completes much quicker because it doesnt do anything.
Well, if you're receiving serial data in packets, the main loop should know when a full 'packet' has been placed into the 'buffer' and the main loop can clear the 'buffer' once it's done with it so the interrupt can start loading it again.


'4 byte buffer
Int: buf[3] = buf[2] : buf[2]=buf[1] : buf[1] = buf[0] : buf[0] = RCREG
RESUME

Everything in the receive 'buffer' got shifted up one, and the newest byte is in the lowest buffer position...
Now the main loop looks at all four bytes, decides it's a good packet, copies the packet and clears it so the interrupt can reload it.


Should i be removing the byte from RCREG in the interrupt? If it doesnt matter as long as i do it before the next one arrives then doing it in the main program loop looks like a better way of doing it
Problem with that is 'feature creep'... You never know what you're going to put into the main loop later on. You say you won't add that much...but who knows how many 'not that much's are going to creep in later on. If the interrupt handles it, it's handled, 'nuff said.

The Master
- 7th October 2008, 18:22
I see your point. I will be adding some extra stuff to the main loop but the other stuff will only get executed if the current bit doesnt.

It just seems like your way does a lot of unnecessary stuff. I can give it a go but it looks like a lot of processing that doesnt need to be done. Having said that, you know what your talking about and im new to this. Plus you say your code actually works and mine still doesnt

skimask
- 7th October 2008, 18:32
It just seems like your way does a lot of unnecessary stuff. I can give it a go but it looks like a lot of processing that doesnt need to be done. Having said that, you know what your talking about and im new to this. Plus you say your code actually works and mine still doesnt
It really doesn't do a lot of extra/unnecessary anything. All it does (or rather would do) is, the interrupt's would handle the PWM'ing on the LEDs for you (you update them in the main loop as required) and would handle putting any serial data received into a buffer (you pull the buffer in the main loop to update the LEDs brightness levels in the main loop as required).
Really very simple...That file that I attached earlier has a whole LOAD of code in it for handling various modes for this, that and the other thing (sleep mode, flashing, fading, color 'phasing', etc.etc.)...a LOT of stuff you wouldn't even come close to needing for your setup.

I modified that file I was talking about...4 channels (RGBW)...
Change it up a bit to fit your PIC and hardware and try it out. No serial support, but it'll show you how the main loop can work PWM'ing with interrupts on the LEDs.
The LEDs MUST be on portA for this exact code to work right. If you split up the LEDs between different ports, they may flash a bit funny...

The Master
- 7th October 2008, 19:01
Ok, thanx. Im home now and im having a little trouble getting the timer interrupt working so ill read that file and see if i can get it working

skimask
- 7th October 2008, 20:01
Ok, thanx. Im home now and im having a little trouble getting the timer interrupt working so ill read that file and see if i can get it working

You're still using a 16F87 right?
How about your hardware? How's that all hooked up? LEDs? Serial input? Anything else hooked up?
Get me that info...lemme cook on it for a bit...

The Master
- 7th October 2008, 22:05
Ive managed to sort it out. I almost came back with the info but i wanted to try and fix it myself. Ok, it took about 3 hours but i got there in the end.

Ive tried changing the pre-scaler too. i thought maybe a 2:1 ratio would free up a little extra processing time. Well, in theory it should because the PWM side of things is only using half the processing power. Unfortunately it didnt affect it in the way i wanted at all. All it did was make the lights flicker a bit because they were flashing too slow so i disabled the pre-scaler.

Now then, theres a sort of random problem. I currently have VB 6 in a loop sending 513 bytes of data. The PIC is processing the data and setting the PWM values. Well, its setting the same values over and over but its still processing and holding different colors in different PWM positions. Its actually working perfect

Now the random problem. If i have a scroll bar that sends the data in the onchange/onscroll then the LEDs flicker quite bad. I really dont understand how that could happen. The circuit is obv working and im sending 513 bytes of data so the baud rate isnt so high that its affecting it. The only thing i can think of is the gap between the last byte and the first byte of the next set of data is less than the gap between the bytes in 1 packet. That seems impossible though and if it did that then i wouldnt have thought you would notice.

Do you have any ideas? I just cant get my head around this one

Edit: Ive added some code to time the serial data going out of VB. Aparently it sends a full 513 bytes every 35-46 milliseconds and thats when it works fine

The Master
- 7th October 2008, 22:22
I have a theory! I just added some code to the loop (the working part) to change the value of the red LEDs and its started flickering a little. I belive the problem is in the way ive done the PWM.

The PWM counter starts at 255. Everytime TMR0 overflows it decrements that value then compares it with the value of each LED. If they match then it turns the LED on. When it gets to 0 it resets back to 255 and turns off any LEDs whos value is less than 255. I think that by changing the value sometimes the PWM counter "misses" the LEDs value so it never turns on until the PWM counter resets to 255 and comes around to the new value.

When testing DT's code i think he does it the oposite way. Turn the LEDs on and count up then turn them off when the value matches. When testing that code the LEDs seemed to flash brightly rather than turn off for half a second.

Im gonna try and fix that problem but again i wouldnt have thought missing 1 PWM cycle would affect the LEDs that bad

The Master
- 7th October 2008, 22:30
Wow, that was quick. I fixed that little problem and all the flickering seems to have gone away! Ive just been moving those scrollbars as fast as possible and they wont flicker at all now.

Although i have learned quite a lot from this thread and finally been able to link a lot of that stuff in the datasheet (the registers) to something usefull, i get the feeling that i could have solved this in the origional code simply by replacing "=" with "=>" 4 times.

Oh well, its not a problem... just a learning oportunity ;)

skimask
- 8th October 2008, 00:30
Although i have learned quite a lot from this thread and finally been able to link a lot of that stuff in the datasheet (the registers) to something usefull, i get the feeling that i could have solved this in the origional code simply by replacing "=" with "=>" 4 times.
I smell what you're cooking...and if you'll notice, in my code, I go the other direction than you do (i.e. opposite logic) and use a "<" which is practically the opposite of "=>" :)
Funny how it's sometimes the same...but different...

Show some code...Let the rest of us smell what you cooked (or burned :D )

The Master
- 8th October 2008, 09:18
Yep, your way looks like the way DT's code did it. You turn everything on then count up and turn each LED off as the counter reaches the PWM value. In my code i turn them all off then count down and turn them on when the counter reaches the PWM value.

I think i probably did it that way because my previous PWM circuits controlled AC lights through a triac. The way you and DT did it would still work and probably be better for AC lights but it needs those other components similar to triacs (cant remember the name) and they are more expensive.

Ive uploaded the file so you can take a look. I know theres lots of bits that seem pointless at the moment. Ive got to addin all the other stuff that i had before.

BTW, that still gets serial data in the main loop. I may still need to buffer it in an interrupt once i have all that extra code back in but for now it works and it doesnt need to buffer all the data that arrives.

Edit: I commented out the bit that resets the serial flag. When i was having trouble i thought maybe that changing PIR1.5 was causing another interrupt or something but it turns out that it works without it. Reading RCREG seems to clear it anyway so is that really needed?

Edit2: Ive uploaded a newer version of the code. I used your buffer idea for sending serial data. Not sure if it works because i dont have the PIC here to test it. All i know is that it compiles properly. I still need to figure out how to set the stored address. That will be a tough one

T.Jackson
- 11th October 2008, 17:25
Your code looks good. You have an appreciation for logic, clarity and organization. I see a good programmer.

Trent Jackson

The Master
- 11th October 2008, 19:35
Thanx, I started with Visual Basic. VB is used for much larger programs than PBP so its more important to write tidy code but i guess its a good habit to keep with any language