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.

software PWM

tumbleweed

Active Member
Never knew that // was a comment in basic, thought it was a C thing. In basics I've used it's normally '
Swordfish will accept either style as a comment.

Block comments are a bit different though. There is uses "(*" and "*)" for begin-end comment block.
 

MrDEB

Well-Known Member
I think I have hit a very simple loop that changes the led brightness or dimness.
In order to dim you must turn off the led thus the delays. In this simple loop, the delay is varied in accordance with the INDEX
I am using DEKAYMS(XXX) so I can see the rate of flash increase then decrease etc.
post #2 & 5 got me to rethink how to do this simple task which incorporates most all suggestions
Am using INDEX as a LONGWORD to length the transition time between bright and dim.
The flash rate increases then decreases which indicates it is maybe doing as desired. Will try using DELAYUS instead of DELAYMS.

Code:
{
*****************************************************************************
*  Name    : UNTITLED.BAS                                                   *
*  Author  : [select VIEW...EDITOR OPTIONS]                                 *
*  Notice  : Copyright (c) 2022 [select VIEW...EDITOR OPTIONS]              *
*          : All Rights Reserved                                            *
*  Date    : 5/21/2022                                                      *
*  Version : 1.0                                                            *
*  Notes   :  copy n pasted from
Report
rjenkinsgb                                                              *
*          :                                                                *
*****************************************************************************
}
Device = 18F43K22
Clock = 8

// int osc and IO pin libraries
Include "intosc.bas"
#option DIGITALIO_INIT = true       // automatically call setalldigital
Include "setdigitalio.bas"
Include "convert.bas"
//LEDS
DIM LED1 AS PORTA.0
DIM LED2 AS PORTB.0
DIM LED3 AS PORTC.0
DIM LED4 AS PORTD.0

DIM Time1 AS BYTE
DIM Time2 AS BYTE
DIM Time3 AS BYTE
DIM Time4 AS BYTE
DIM INDEX AS LONGWORD
dim counter as LONGWORD
dim Bright as longword        // a wider range of settings
dim Dimmer as longword

//LEDS ALL OFF AT START OF PROGRAM
led1 = 0
led2 = 0
led3 = 0
led4 = 0

Time1 = 25
Time2 = 50
Time3 = 75
Time4 = 100
//INCREMENT/ DECRIMINATE ON/OFF TIMES

INDEX = 1
//MAKE ALL OUTPUTS
trisa=0
'trisb=0
'trisc=0
'trisd=0

While TRUE

   // LED One control
   IF INDEX <=10000 THEN
   TIME1 = (TIME1 + INDEX)
   endif
       led1=1
       delayMs(Time1)             //INCREMENT THIS FOR BRIGHTER
       led1=0
       DELAYMS(TIME1)
         
     
     
     
     
      // LED One control
   IF INDEX >=10000 THEN
   TIME1 = (TIME1 - INDEX)
   endif
       led1=1
       delayMs(Time1)             // DECRIMENT FOR DIMMER
       led1=0
       DELAYMS(TIME1)
       
  INDEX = (INDEX +1)    //INCRIMENT INDEX EACH PASS THROUGH LOOP
      IF INDEX >= 10000 THEN
      INDEX = (INDEX - 1)

   End If
   
Wend
 

For The Popcorn

Active Member
Sigh
 

For The Popcorn

Active Member
Nevermind. Suggestions won't be taken anyway.
 

MrDEB

Well-Known Member
now this starts out really dim then goes bright really smooth but it won't go from full bright back to dim
Code:
BRIGHT_1 = 1
DIMMER_1 = 25000
BRIGHT_2 = 25000
DIMMER_2 = 1

INDEX = 1
//MAKE ALL OUTPUTS
trisa=0
'trisb=0
'trisc=0
'trisd=0

While TRUE
//this is a real smooth from dim to bright
repeat
  led1 = 1
  delayus(bright_1)  // 1
  led1 = 0                   // dim
  delayus (dimmer_1)  //25000
  bright_1 = (bright_1 +1)
  dimmer_1 = (dimmer_1 - 1)
 until
 bright_1 = 2500
 
//this won't go back to dim?? 
 repeat
  led1 = 1
  delayus(dimmer_2)  // 1
  led1 = 0                   // full bright
  delayus (bright_2)  //255
  bright_2 = (bright_2 -1)
  dimmer_2 = (dimmer_2 + 1)
 until
 dimmer_2 = 2500
  
 
wend
 

For The Popcorn

Active Member
Since you won't try suggestions that will work, and keep heading down paths that won't work, it's doubtful that anybody will attempt to decipher your code.
 

MrDEB

Well-Known Member
What I did was started from scratch to find out what ratio of LED ON TIME vers OFF TIME
try this and you will see what I am talking about
for a full dim
LED = 1 Delayus(1)
LED = 0 Delayus(25000)
this will dim the LED almost off

Now reverse the combination
LED=1 Delayus(25000)
led=0 Delayus(1)

While watching tv last night I was pondering my code and realized I need to reset the values of bright_1 and bright_2
bright _2 = bright_1 insert before second UNTIL LOOP
dimmer_2 = dimmer_1 insert AFTER THE SECOND until loop
after I finish this post will give it a go
Post 2 & 5 started my rethinking process about how to do a software only PWM simulation so thanks
 

MrDEB

Well-Known Member
THIS CODE WORKS PERFECT as desired

A really s m o o t h transition from very dim to very bright. Found a glitch AFTER I added a transition indicator led2
Just that small addition helped locate the issue of a jump from full bright back to full dim
Code:
{
*****************************************************************************
*  Name    : UNTITLED.BAS                                                   *
*  Author  : [select VIEW...EDITOR OPTIONS]                                 *
*  Notice  : Copyright (c) 2022 [select VIEW...EDITOR OPTIONS]              *
*          : All Rights Reserved                                            *
*  Date    : 5/21/2022                                                      *
*  Version : 1.0                                                            *
*  Notes   :  WORKS GREAT 5/23/22                                                             *
*          :                                                                *
*****************************************************************************
}
Device = 18F43K22
Clock = 8

// int osc and IO pin libraries
Include "intosc.bas"
#option DIGITALIO_INIT = true       // automatically call setalldigital
Include "setdigitalio.bas"
Include "convert.bas"
//LEDS
DIM LED1 AS PORTA.0
DIM LED2 AS PORTE.1
DIM LED3 AS PORTC.0
DIM LED4 AS PORTD.0


dim counter as LONGWORD
dim Bright_1 as longword        // a wider range of settings FOR A SMOOTHER TRANSITION
dim Dimmer_1 as longword
dim Bright_2 as longword        // a wider range of settings
dim Dimmer_2 as longword

//LEDS ALL OFF AT START OF PROGRAM
led1 = 0
led2 = 0
led3 = 0
led4 = 0


//INCREMENT/ DECRIMINATE ON/OFF TIMES
BRIGHT_1 = 0
DIMMER_1 = 0
BRIGHT_2 = 0
DIMMER_2 = 0

INDEX = 1
//MAKE ALL OUTPUTS
'trisa=0
'trisb=0
'trisc=0
'trisd=0
OUTPUT (LED1)
OUTPUT(LED2)
//     USING VALUE OF 5000 FOR A S M O O T H TRANSITION.

While TRUE
 bright_1 = 1              // bright_1 is ON  time variable
 dimmer_1 = 5000           //dimmer_1 is OFF time variable
repeat
  led1 = 1
  delayus(bright_1) 
  led1 = 0                   // dim
  delayus (dimmer_1) 
  bright_1 = (bright_1 +1)   // increase ON time BY 1
  dimmer_1 = (dimmer_1 - 1)  //decrease OFF time BY 1
 until
 bright_1 >= 5000            //HIGH BRIGHT
 
 
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
//reset values
  bright_2 = 5000
  dimmer_2 = 1
  LED2 = 1                    // LED2 COMES ON WHEN LED1 STARTS FROM HIGH BRIGHT TO FULL DIM
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

 
 repeat
  led1 = 1
  delayus(BRIGHT_2)           // LED is full brightness  FIRST PASS IN LOOP
  led1 = 0                   
  delayus(DIMMER_2)           // full dim          FIRST PASS IN LOOP
  bright_2 = (bright_2 - 1)
  dimmer_2 = (dimmer_2 + 1)
 until
 bright_2 = 1 
//reset valuesxxxxxxxxxxxxxx 
  bright_2 = 1
  dimmer_2 = 5000
  LED2 = 0                      // LED2 GOES OFF WHEN LED1 STARTS FROM FULL DIM  TO HIGH BRIGHT
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxx 
wend
















 {

//increase brghtness
   REPEAT
   // LED One control
   IF INDEX <=255 THEN
   BRIGHT = (INDEX + 1)
   endif
       led1=1
       delayMs(DIMMER)             //INCREMENT THIS FOR BRIGHTER
       led1=0
       DELAYMS(BRIGHT)
   BRIGHT = (BRIGHT + 1)
   UNTIL
   BRIGHT >= INDEX       
      
 // decrease brightness     
      
 REPEAT     
      // LED One control
   IF INDEX >= 1 THEN
   DIMMER = (INDEX)
   endif
       led1=1
       delayMs(BRIGHT)             // DECRIMENT FOR DIMMER
       led1=0
       DELAYMS(DIMMER)
    UNTIL
    DIMMER <= INDEX   
 
      IF INDEX <= 255 THEN     
      BRIGHT = (INDEX + 1)        // increase BRIGHT  until it hits 100000
      End If
       IF DIMMER >= 100000 THEN   //decrease  DIMMER  until it hits 0
      DIMMER = (INDEX - 1)
      End If
   ' if INDEX = 0 then index = (INDEX + 1) end if
    'if index = 1000000 then
    
Wend
 

For The Popcorn

Active Member
Awesome.

But the problem is, as you have discovered already in this thread, comes when you try to do this with more LEDs.
 

MrDEB

Well-Known Member
that's my next challenge BUT I do have a really good fading in & out snippet that works.
got to start small then go big.
 

MrDEB

Well-Known Member
lets add more LEDs easy
Code:
Sub Fade()
    
 Bright_1 = 1              // bright_1 is ON  time variable
 Dimmer_1 = 5000           //dimmer_1 is OFF time variable
Repeat
  PORTA = %11100111
  DelayUS(Bright_1) 
  PORTA = %00000000                   // dim
  DelayUS (Dimmer_1) 
  Bright_1 = (Bright_1 +1)   // increase ON time BY 1
  Dimmer_1 = (Dimmer_1 - 1)  //decrease OFF time BY 1
 Until
 Bright_1 >= 5000            //HIGH BRIGHT
 
 
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
//reset values
  Bright_2 = 5000
  Dimmer_2 = 1
 ' LED2 = 1                    // LED2 COMES ON WHEN LED1 STARTS FROM HIGH BRIGHT TO FULL DIM
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

 
 Repeat
  PORTA = %11100111
  DelayUS(Bright_2)           // LED is full brightness  FIRST PASS IN LOOP
  PORTA =%00000000                   
  DelayUS(Dimmer_2)           // full dim          FIRST PASS IN LOOP
  Bright_2 = (Bright_2 - 1)
  Dimmer_2 = (Dimmer_2 + 1)
 Until
 Bright_2 = 1 
//reset valuesxxxxxxxxxxxxxx 
  Bright_2 = 1
  Dimmer_2 = 5000
 ' LED2 = 0                      // LED2 GOES OFF WHEN LED1 STARTS FROM FULL DIM  TO HIGH BRIGHT
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 

MrDEB

Well-Known Member
The issue is current draw. I have 14 pairs of white LEDs in parallel with one 330 ohm resistor per pair which should be around 7ma per pair. Same for the 20 pairs of blue
7 x 14 = 98 rounded off to 100 ma.
the pic data sheet says 180ma max so the BLUE and WHITE can't be on at the same time
14 pairs of white and 20 pairs of blue = a total of 68 leds.
IF I decide to have more boards made then a different pattern for the resistor arrays and use 750 ohm resistors
a definite design flaw
One way around it is TOGGLE THE BLUE?
 

For The Popcorn

Active Member
Since MrDEB has been silent today, he may have figured out that a whole bunch of serial routines with delay statements aren't going to accomplish what he wants at least not very well.

One way to do what he wants is to base all actions on a loop counter, with at most exactly ONE delay statement. Ok, let's start with the basic program loop.

Code:
Dim Counter as Longword
Counter = 0

While 1 = 1

   // some code will go here

    Inc (Counter)
    If Counter > 4000000000 then
          Counter = 0
    End If

Wend

What happens in this program loop? The variable Counter counts from 0 to 4,000,000,000. This number can actually be 2^32, but rounding it off won't matter much. The IF statement may not be strictly necessary. The Counter value should automatically wrap back to zero.

Pretty neat, huh? Well, let's work on that. Let's add an LED, say at 50% brightness .


Code:
Dim Counter as Longword
Dim LED1On as Longword
Dim LED1Off as Longword

LED1On  = 0
LED1Off = 0
Counter = 0

While 1 = 1

   // some code will go here
   If Counter = LED1On then
        LED1 = 1
        LED1On = Counter + 20
        LED1Off = Counter + 10
   End If
   If Counter = LED1Off then
       LED1 = 0
   End If

    Inc (Counter)
    If Counter > 4000000000 then
          Counter = 0
    End If

Wend

Ok, so what happens here? Led1On starts at 0. When the Counter value equals 0, three things happen:
¤ LED1 is turned on
¤ LED1On is set to 20
¤ LED1Off is set to 10

When the Counter = 10, LED1 will be turned off.

When the Counter = 20, the sequence repeats.

LED1 is on half the time, off half the time, so the brightness is 50%. This is kind of crude; making it a subroutine (do not call this a sub route. That is gibberish.) would be cleaner.

So now let's add a second LED, operating at the same time the first does it's thing.


Code:
Dim Counter as Longword
Dim LED1On as Longword
Dim LED1Off as Longword
Dim LED2On as Longword
Dim LED2Off as Longword

LED1On  = 0
LED1Off = 0
LED2On = 0
LED2Off = 0
Counter = 0

While 1 = 1

   // some code will go here
   If Counter = LED1On then
        LED1 = 1
        LED1On = Counter + 20
        LED1Off = Counter + 10
   End If
   If Counter = LED1Off then
       LED1 = 0
   End If

   If Counter = LED2On then
       LED2 = 1
       LED2Off = 20
       LED2On = 500
   End If
  If Counter = LED2Off then
      LED2 = 0
   End If
       

    Inc (Counter)
    If Counter > 4000000000 then
          Counter = 0
    End If

Wend

So now, while LED1 is flashing rapidly on and off to be 50% bright, LED2 is flashing very briefly on and then off for a long period, resulting in a twinkling effect. Two LEDs operating independently in the same loop.

This definitely is not polished code, but will show anybody willing to take a few minutes to understand the code how to use this technique. This loop incrementing up to 4,000,000,000 is going to execute very quickly. The on/off Counter times need to be adjusted to suit the effect desired, and a short delay may need to added at the end of the loop. Also, at the end of the loop, initial values will need to be reset to zero.

The picture shows the process. On and off periods might be set to random numbers. But remember, all actions are based on Counter values. Exactly one delay statement might be added. MrDEB's fading routine can also be adapted to this technique.

loop counter.jpg
 

For The Popcorn

Active Member
I didn't check timing....I was a little off.

With a 20MHz clock, 1,000,000 cycles takes roughly 3.5 seconds. You can adjust the number of counter cycles to be the length of the pattern you want. Note: a slower clock will take longer to run – an 8MHz clock will take about 9 seconds, so each counter Increment is about 9 uSec.
 

Pommie

Well-Known Member
Most Helpful Member
Since MrDEB has been silent today, he may have figured out that a whole bunch of serial routines with delay statements aren't going to accomplish what he wants at least not very well.

One way to do what he wants is to base all actions on a loop counter, with at most exactly ONE delay statement. Ok, let's start with the basic program loop.

Code:
Dim Counter as Longword
Counter = 0

While 1 = 1

   // some code will go here

    Inc (Counter)
    If Counter > 4000000000 then
          Counter = 0
    End If

Wend

What happens in this program loop? The variable Counter counts from 0 to 4,000,000,000. This number can actually be 2^32, but rounding it off won't matter much. The IF statement may not be strictly necessary. The Counter value should automatically wrap back to zero.

Pretty neat, huh? Well, let's work on that. Let's add an LED, say at 50% brightness .


Code:
Dim Counter as Longword
Dim LED1On as Longword
Dim LED1Off as Longword

LED1On  = 0
LED1Off = 0
Counter = 0

While 1 = 1

   // some code will go here
   If Counter = LED1On then
        LED1 = 1
        LED1On = Counter + 20
        LED1Off = Counter + 10
   End If
   If Counter = LED1Off then
       LED1 = 0
   End If

    Inc (Counter)
    If Counter > 4000000000 then
          Counter = 0
    End If

Wend

Ok, so what happens here? Led1On starts at 0. When the Counter value equals 0, three things happen:
¤ LED1 is turned on
¤ LED1On is set to 20
¤ LED1Off is set to 10

When the Counter = 10, LED1 will be turned off.

When the Counter = 20, the sequence repeats.

LED1 is on half the time, off half the time, so the brightness is 50%. This is kind of crude; making it a subroutine (do not call this a sub route. That is gibberish.) would be cleaner.

So now let's add a second LED, operating at the same time the first does it's thing.


Code:
Dim Counter as Longword
Dim LED1On as Longword
Dim LED1Off as Longword
Dim LED2On as Longword
Dim LED2Off as Longword

LED1On  = 0
LED1Off = 0
LED2On = 0
LED2Off = 0
Counter = 0

While 1 = 1

   // some code will go here
   If Counter = LED1On then
        LED1 = 1
        LED1On = Counter + 20
        LED1Off = Counter + 10
   End If
   If Counter = LED1Off then
       LED1 = 0
   End If

   If Counter = LED2On then
       LED2 = 1
       LED2Off = 20
       LED2On = 500
   End If
  If Counter = LED2Off then
      LED2 = 0
   End If
      

    Inc (Counter)
    If Counter > 4000000000 then
          Counter = 0
    End If

Wend

So now, while LED1 is flashing rapidly on and off to be 50% bright, LED2 is flashing very briefly on and then off for a long period, resulting in a twinkling effect. Two LEDs operating independently in the same loop.

This definitely is not polished code, but will show anybody willing to take a few minutes to understand the code how to use this technique. This loop incrementing up to 4,000,000,000 is going to execute very quickly. The on/off Counter times need to be adjusted to suit the effect desired, and a short delay may need to added at the end of the loop. Also, at the end of the loop, initial values will need to be reset to zero.

The picture shows the process. On and off periods might be set to random numbers. But remember, all actions are based on Counter values. Exactly one delay statement might be added. MrDEB's fading routine can also be adapted to this technique.

View attachment 137243
You put a lot of effort into that explanation let's hope it's not wasted.

Mike.
 

For The Popcorn

Active Member
You put a lot of effort into that explanation let's hope it's not wasted.

Mike.

I'm quite sure it's an absolute waste of effort, but I'm a champion of lost causes.
 

MrDEB

Well-Known Member
an interesting method to dim an led.
I will give it a try and post the code.
As for yesterday, our internet was on/off all day.
 

For The Popcorn

Active Member
Yep. Hit another one clean out of the park! Right over his head!

Got to love baseball season.
 

MrDEB

Well-Known Member
hate to tell you this but it dos not dim. The ratio of on time vers off time stays the same post 108 works very well. Give it a try. Thanks
Code:
{
*****************************************************************************
*  Name    : UNTITLED.BAS                                                   *
*  Author  : [select VIEW...EDITOR OPTIONS]                                 *
*  Notice  : Copyright (c) 2022 [select VIEW...EDITOR OPTIONS]              *
*          : All Rights Reserved                                            *
*  Date    : 5/25/2022                                                      *
*  Version : 1.0                                                            *
*  Notes   :                                                                *
*          :                                                                *
*****************************************************************************
}


Device = 18F43K22
Clock = 8

// int osc and IO pin libraries
Include "intosc.bas"
#option DIGITALIO_INIT = true       // automatically call setalldigital
Include "setdigitalio.bas"

// hardware
Dim INDEX  As LongWord  //4294967295

Dim m As Byte
Dim w As Byte
Dim x As Byte
Dim y As Byte
Dim z As Byte
Dim Bright_1 As LongWord        // a wider range of settings FOR A SMOOTHER TRANSITION
Dim Dimmer_1 As LongWord
Dim Bright_2 As LongWord        // a wider range of settings
Dim Dimmer_2 As LongWord
Dim Counter As LongWord
Dim LED1On As LongWord
Dim LED1Off As LongWord
dim led1 as porta.0
main:
// init hdw
               // LED port - all outputs 2 LEDs per port in parallel 330 ohm resistor
TRISA = 0      // SET ALL PORTS AS OUTPUTS
TRISB = 0
TRISC = 0
TRISD = 0
TRISE = 0
   PORTE=%000         //TURN OFF ALL PORTS
   PORTD=%00000000
   PORTC=%00000000
   PORTA=%00000000
   PORTB=%00000000   


LED1On  = 0
LED1Off = 0
Counter = 0

While 1 = 1

   // some code will go here
   If Counter = LED1On Then         //first pass led1 = 0
        LED1 = 1                    // led1 is on
        LED1On = Counter + 20
        LED1Off = Counter + 10      //first pas led1 = 10
   End If
   If Counter = LED1Off Then
       LED1 = 0
   End If

    Inc (Counter)
    If Counter > 4000000000 Then  //   4000000000
          Counter = 0
    End If

Wend
 

Latest threads

Top