PIC16/18 Controller with 14 or more PWM outputs

Gaurav Gupta_1568212829

Joined Sep 11, 2019
22
I have requirement of 14 PWM output for a project. Can anyone guide me whether I should find a controller with 14 PWM output or I should be using PWM pin extender ICs.

Thanks

jpanhalt

Joined Jan 18, 2008
11,088
This should take you to a parametric search and show those PIC's wtih 14 or more PWM channels: https://www.microchip.com/ParamChartSearch/Chart.aspx?branchID=30048

Oops, link doesn't work to go to the parsed page. It just goes to the main selection page. You can do the search there. Here are some 16F that meet that criterion:

EDIT:

Those numbers seem to be based on counting re-assignable pins, not actual, independent PWM drivers. Yes, it seemed too simple, so I checked:

Last edited:

John P

Joined Oct 14, 2008
1,910
It's important to know what frequency these PWM outputs need to run at, and how many different states (duty cycles) each needs to have. If the frequency is low, then it may be possible to synthesize them in software.

Ian0

Joined Aug 7, 2020
3,285

jpanhalt

Joined Jan 18, 2008
11,088
Software can do a lot. I have links to controlling 18 different servos independently with a PIC. I interpreted the TS as wanting hardware PWM, which depends on TMR2, 4, 6, etc. That's what got me to thinking the MIcrochip parametric search engine might not be accurate in that regard.

John P

Joined Oct 14, 2008
1,910
The request was for PWM, and hobby servos take a particularly restricted kind of PWM signal that's very slow by usual standards, and varies only from (quick calculation) 5% to 10% duty cycle. If hobby servos are what's involved, the posting should have said so.

Gaurav Gupta_1568212829

Joined Sep 11, 2019
22
This should take you to a parametric search and show those PIC's wtih 14 or more PWM channels: https://www.microchip.com/ParamChartSearch/Chart.aspx?branchID=30048

Oops, link doesn't work to go to the parsed page. It just goes to the main selection page. You can do the search there. Here are some 16F that meet that criterion:

View attachment 221266

EDIT:

Those numbers seem to be based on counting re-assignable pins, not actual, independent PWM drivers. Yes, it seemed too simple, so I checked:

View attachment 221269
Thank you. @jpanhalt Yes, I looked into it but I require 14 independent PWM to control led panels.

Last edited:

Gaurav Gupta_1568212829

Joined Sep 11, 2019
22
It's important to know what frequency these PWM outputs need to run at, and how many different states (duty cycles) each needs to have. If the frequency is low, then it may be possible to synthesize them in software.
Thank you @John P The least I require is 1KHz frequency with two different states(full and 1/3). I have to include a switch button and RF module for wireless connectivity so I guess software generated PWM might keep the controller busy.

Gaurav Gupta_1568212829

Joined Sep 11, 2019
22
Thank you @Ian0 I will look into it.

John P

Joined Oct 14, 2008
1,910
All right, some useful information. I think this is an easy task that just about any processor can do if it has the port pins available, without using very much processing power at all. You'd need to have a loop running in main() that gets visited at least 3000 times per second, but that's easy enough. Alternatively, most of the code could run in an interrupt. Assuming you're working on an 8-bit processor, and the LEDs are connected to 2 8-bit ports, called PortA and PortB, then I'd do this (untested code, not guaranteed to work):

Code:
unsigned char leds0to7;
unsigned char leds8to13;                                // These are global variables, accessible from anywhere
bit tick;                                                            // Globally accessible flag

void interrupt(void)                                        // 3KHz repeat rate
{
tick = 1;
PortA = leds0to7;
PortB = leds8to13;
}

main()
{
unsigned char phase, i, mask;

unsigned int led_state[14];         // This array needs to contain 0 for a light that has a 33% duty cycle, and nonzero for a light
// that is at full brightness.

// Do whatever you need to set up the interrupt with a 3KHz repeat rate, and set PortA and PortB to outputs

while (1)
{
if (tick)
{
tick = 0;                                                   // If flag is set, clear it
phase++;
if (phase >= 3)
{
phase = 0;
leds0to7 = 0xFF;                                   // All LEDs on in phase 0
leds8to13 = 0x3F;                                // Only 6 bits in 2nd byte
}
else if (phase == 1)                               // Some LEDs will turn off on phase 1, and nothing changes in phase 2
{
for (i = 0; i < 8; i++)
{
if (led_state[i] == 0)
leds0to7 &= ~mask;                     // Maybe set a single bit to zero, if led_state was 0
if ((i < 6) && (led_state[i + 8] == 0))
leds8to13 &= ~mask;                  // Apply test to 2nd byte only when i has value 0-5
}
} // End phase == 1
} // End tick == 1
}  // End while(1)
}

Gaurav Gupta_1568212829

Joined Sep 11, 2019
22
All right, some useful information. I think this is an easy task that just about any processor can do if it has the port pins available, without using very much processing power at all. You'd need to have a loop running in main() that gets visited at least 3000 times per second, but that's easy enough. Alternatively, most of the code could run in an interrupt. Assuming you're working on an 8-bit processor, and the LEDs are connected to 2 8-bit ports, called PortA and PortB, then I'd do this (untested code, not guaranteed to work):

Code:
unsigned char leds0to7;
unsigned char leds8to13;                                // These are global variables, accessible from anywhere
bit tick;                                                            // Globally accessible flag

void interrupt(void)                                        // 3KHz repeat rate
{
tick = 1;
PortA = leds0to7;
PortB = leds8to13;
}

main()
{
unsigned char phase, i, mask;

unsigned int led_state[14];         // This array needs to contain 0 for a light that has a 33% duty cycle, and nonzero for a light
// that is at full brightness.

// Do whatever you need to set up the interrupt with a 3KHz repeat rate, and set PortA and PortB to outputs

while (1)
{
if (tick)
{
tick = 0;                                                   // If flag is set, clear it
phase++;
if (phase >= 3)
{
phase = 0;
leds0to7 = 0xFF;                                   // All LEDs on in phase 0
leds8to13 = 0x3F;                                // Only 6 bits in 2nd byte
}
else if (phase == 1)                               // Some LEDs will turn off on phase 1, and nothing changes in phase 2
{
for (i = 0; i < 8; i++)
{
if (led_state[i] == 0)
leds0to7 &= ~mask;                     // Maybe set a single bit to zero, if led_state was 0
if ((i < 6) && (led_state[i + 8] == 0))
leds8to13 &= ~mask;                  // Apply test to 2nd byte only when i has value 0-5
}