Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Noob Q - Analog Outputs

Status
Not open for further replies.

Revolvr

Member
Noob Q - Analog Outputs

I have some circuits to build that will fade on and off various lights based on sensor inputs. I can do this with timers, op-amps, logic IC's etc. but it may be time to graduate to PICs.

Couple simple questions.

From what I've read so far, PICs do not support D-to-A conversion or any analog output. Since I need to fade several sets of lights on or off over time, I presume the solution is PWM control?

Do I have to write the code to do the PWM or are there simple native commands and HW support that allow me to, for example, specify the frequency and duty cycle? Or is programming PWM outputs a long and complex process?

Are there only certain chips I can use? Only certain outputs?

Can I have more than one PWM output per chip?

Are there only certain high level languages (C, Basic) that support PWM control?

TIA

-- Dan
 
You use PWM to dim lights, you don't need analogue outputs - it would be a really poor way of doing it. Many PIC's have PWM in hardware, but only one or two channels (some higher end devices have more) - but if required you can do it in software.
 
OK I think I'm getting it. So if I use a mid range PIC w/o PWM HW support, and I wanted to write a program that output levels of 0-100% on 4 channels, I could create some subroutine that translates that percent into PWM on/off cycles.

I haven't built a PWM controller since 1993 and that was in Ada. :)

So I'm a little rusty. I can think of a few techniques from counters to reading data arrays. Are there publically available libraries of common subroutines such as this? I suppose something like this is fairly common?

Cheers,

- Dan
 
Yes, but most pics do have PWM, or at the very least timer interupts, so software PWM can comprise of very little actual cpu time.
 
Here's a simple interrupt "software" driver example for 8-channels (PORTB) with 100 levels.
  1. the code runs in exactly the same number of cycles for any value of any of the PWM registers, thus guarantees zero jitter.
  2. it operates on a shadow register to guarantee update with zero skew for any output.
Your main program would simply set values in the PWMLED0 through PWMLED7 variables with a value from 0 to 99 (decimal) and the interrupt code drives the LED channels in the background.

Good luck. Have fun. Regards, Mike

Code:
 ;
 ;  within the interrupt service routine after saving context
 ;
 ;
         incf    PWMCTR,f        ; increment master PWM counter
         movf    PWMCTR,W        ; 
         xorlw   d'100'          ; cycled through all 100 values?
         bnz     test            ; no, branch, else
         clrf    SHADOW          ; turn on all LEDs in shadow GPR
         clrf    PWMCTR          ; and reset master PWM counter
 ;
 ;  test each LED PWM setting each interrupt against the PWMCTR
 ;  value and turn off the shadow LEDx bit when PWMLEDx = PWMCTR
 ;
         movf    PWMCTR,W        ; get current PWM count [00..99]
         xorwf   PWMLED0,W       ; same as LED 0 PWM value?
         skpnz                   ; no, skip, else
         bsf     SHADOW,0        ; turn off LED 0 bit in shadow GPR
 ;
         movf    PWMCTR,W        ; get current PWM count [00..99]
         xorwf   PWMLED1,W       ; same as LED 1 PWM value?
         skpnz                   ; no, skip, else
         bsf     SHADOW,1        ; turn off LED 1 bit in shadow GPR
 ;
         movf    PWMCTR,W        ; get current PWM count [00..99]
         xorwf   PWMLED2,W       ; same as LED 2 PWM value?
         skpnz                   ; no, skip, else
         bsf     SHADOW,2        ; turn off LED 2 bit in shadow GPR
 ;
         movf    PWMCTR,W        ; get current PWM count [00..99]
         xorwf   PWMLED3,W       ; same as LED 3 PWM value?
         skpnz                   ; no, skip, else
         bsf     SHADOW,3        ; turn off LED 3 bit in shadow GPR
 ;
         movf    PWMCTR,W        ; get current PWM count [00..99]
         xorwf   PWMLED4,W       ; same as LED 4 PWM value?
         skpnz                   ; no, skip, else
         bsf     SHADOW,4        ; turn off LED 4 bit in shadow GPR
 ;
         movf    PWMCTR,W        ; get current PWM count [00..99]
         xorwf   PWMLED5,W       ; same as LED 5 PWM value?
         skpnz                   ; no, skip, else
         bsf     SHADOW,5        ; turn off LED 5 bit in shadow GPR
 ;
         movf    PWMCTR,W        ; get current PWM count [00..99]
         xorwf   PWMLED6,W       ; same as LED 6 PWM value?
         skpnz                   ; no, skip, else
         bsf     SHADOW,6        ; turn off LED 6 bit in shadow GPR
 ;
         movf    PWMCTR,W        ; get current PWM count [00..99]
         xorwf   PWMLED7,W       ; same as LED 7 PWM value?
         skpnz                   ; no, skip, else
         bsf     SHADOW,7        ; turn off LED 7 bit in shadow GPR
 ;
 ;  finally, update PORTB from the SHADOW GPR
 ;
         movf    SHADOW,W        ; get SHADOW LED bits
         movwf   PORTB           ; update PORTB
 ;
 ;  clear the interrupt flag, restore context, and return from interrupt
 ;
 
If your using a basic compiler like Proton+, its as easy as;

PHP:
Device = 16F876A

XTAL = 4

Dim Brightness as Byte

Declare CCP1_PIN = PORTC.2
TRISC.2 = 0

Main:
	 
	 For Brightness = 0 to 255
	 	 HPWM 1, Brightness, 32767
	 	 Delayms 10
	 Next	  	 			 	

	 Goto Main

The breakdown;

PORTC.2 will vary with a duty cycle from 0 to 255 (0 - 100%) at the frequency of 32767Hz.

Should your PIC not have a hardware PWM, then you can use the software equivilant.
 
Thanks everyone for the help and code snippets. This is a great forum.

Since I need 4 or more outputs I'll probably try a SW PWM routine first - rather than multiple chips. Since these are lights the frequency can be low, say 200 Hz or higher.

What I might do is write code for all of the control logic, then create a 1-0 alternating signal and measure it's frequency with a scope to see how fast the code is running. That should tell me what frequency the SW PWM could run at and what delays might be needed.

Cheers,

-- Dan
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top