Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

How to set time period of pulse in PWM

kumarr123

Junior Member level 1
Joined
Oct 18, 2023
Messages
19
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
155
Hi,
I am using PIC16f1526 micro-controller and PCA9685 IC to control servo motor. This below code I am using-

I am using mikroC pro for pic compiler to implement this code.

C-like:
#define Write_address 0x80  // I2C address for PCA9865 with no solder bridges
#define Read_address Write_address+1
#define PCA9685_software_reset 0x06
#define Reset   0x01        // Reset the device
#define MODE1   0x00        // 0x00 location for Mode1 register address
#define MODE2   0x01        // 0x01 location for Mode2 reigster address
#define LED0    0x06        // location for start of LED0 registers
#define ALL_CH_ON_L_reg   0xFA
#define ALL_CH_ON_H_reg   0xFB
#define ALL_CH_OFF_L_reg  0xFC
#define ALL_CH_OFF_H_reg  0xFD
#define HEARTBEAT LATC0_bit // green led on ETT board
sbit SCL_i2c at RC3_bit;
sbit SDA_i2c at RC4_bit;
sbit SCL_direction at TRISC3_bit;
sbit SDA_direction at TRISC4_bit;
////////////////////////////////////////////////////////////////////////////////
// Prototype functions - functions at end
void PCA9685_init();
void PCA9685_send(unsigned int value, unsigned char led);
void PCA9685AllLedOff();
unsigned char PCA9685_read_byte(unsigned char chip_register);
void PCA9685_write_byte(unsigned char chip_register, unsigned char value);
void PCA9685_write_word(unsigned char chip_register, unsigned int word_value);
void PCA9685_soft_reset();
////////////////////////////////////////////////////////////////////////////////
void main(){
    // block variables
    unsigned char              n = 0;   // LED flash
    unsigned int            loop = 0;   // loop counter
    unsigned int             pwm = 0;
    unsigned int                 x=0;
    
     OSCCON = 0x7a;    //0x7A     //122
     SCL_i2c = 0;
     SDA_i2c = 0;
     SCL_direction = 0;
     SDA_direction = 0;
 
    ADCON0 = 1;
  
    I2C1_Init(100000);
    PCA9685_init();

    PCA9685_send((int)4096 * 0.5 ,0); //     (int)4096 * 0.5
        
////////////////////////////////////////////////////////////////////////////////
// Functions
// Init the chip with pwm frequency and MODE2 settings
void PCA9685_init(){
     I2C1_start();             // Start
     I2C1_Wr(Write_address);   // Slave Write_address
     I2C1_Wr(MODE1);           // Mode 1 ADDRESS
     I2C1_Wr(0b00110001);      // Sleep and change default PWM frequency     00110001
     I2C1_stop();              // Stop
     delay_ms(1);              // Required 50 us delay
     I2C1_start();             // Start
     I2C1_Wr(Write_address);   // Slave Write_address
     I2C1_Wr(0xFE);            // PWM frequency PRE_SCALE ADDRESS to set pwm at 100Hz   fe
     I2C1_Wr(6);            // Osc_clk/(4096*update_rate)=25000000/(4096*100)=60=0x3C    //06
     I2C1_stop();              // Stop
     delay_ms(1);              // delay at least 500 us
     I2C1_start();             // Start
     I2C1_Wr(Write_address);   // Slave Write_address
     I2C1_Wr(MODE1);           // Mode 1 register ADDRESS
     I2C1_Wr(0b10100001);      // Set MODE1          //10100001
     I2C1_stop();              // Stop
     delay_ms(1);              // delay at least 500 us
     I2C1_start();             // Start
     I2C1_Wr(Write_address);   // Slave Address
     I2C1_Wr(MODE2);           // Mode2 register ADDRESS
     I2C1_Wr(0b00000100);      // Set MODE2 //00000100
     I2C1_stop();              //
}
// Send pulse length[0-4095] to selected LED/SERVO[0-15]
void PCA9685_send(unsigned int value, unsigned char led){
     unsigned char pulse_length;// temp variable for PWM
     I2C1_start();              // Start
     I2C1_Wr(Write_address);    // address of selected pca9685
     I2C1_Wr(LED0 + 4 * led);   // select slected LED ADDRESS
     I2C1_Wr(0x00);             // LED_ON_L    //00
     I2C1_Wr(0x00);             // LED_ON_H    // 00
     pulse_length = value;      // PWM value lo byte
     I2C1_Wr(pulse_length);     // LED_OFF_L
     pulse_length = value>>8;   // pwm 16 bit long, now shift upper 8 to lower 8
     I2C1_Wr(pulse_length);     // LED_OFF_H
     I2C1_stop();               // stop
}
void PCA9685AllLedOff(){
     I2C1_start();              // atart
     I2C1_Wr(Write_address);    // select pca9685
     I2C1_Wr(ALL_CH_OFF_L_reg); // All LEDs Off regiter
     I2C1_Wr(0b00000000);       // low byte
     I2C1_Wr(0b00010000);       // high byte, bit4 set so full_off see page 21
     I2C1_stop();               // Stop
}
// Read a byte and return it's value
unsigned char PCA9685_read_byte(unsigned char chip_register){
    unsigned char temp = 0x00;
    I2C1_Start();
    I2C1_Wr(Write_address);
    I2C1_Wr(chip_register);
    I2C1_Start();
    I2C1_Wr(Read_address);
    temp = I2C1_Rd(0);
    I2C1_Stop();
    return temp;
}
void PCA9685_write_byte(unsigned char chip_register, unsigned char value){
     I2C1_Start();
     I2C1_Wr(Write_address);
     I2C1_Wr(chip_register);
     I2C1_Wr(value);
     I2C1_Stop();
}
// Write 16bits to chip_register, increments automatically from lo to hi byte
void PCA9685_write_word(unsigned char chip_register, unsigned int word_value){
     unsigned char hb = 0x00;
     unsigned char lb = 0x00;
     lb = (word_value & 0x00FF);
     hb = ((word_value & 0xFF00) >> 0x08);
     PCA9685_write_byte(chip_register,lb);
     PCA9685_write_byte((chip_register+1),hb);
}
// Soft re-set
void PCA9685_soft_reset(){
    I2C1_Start();
    I2C1_Wr(0x00);
    I2C1_Wr(PCA9685_software_reset);
    I2C1_Stop();
}
This code is giving controlled duty cycle like 50%, 25%, etc. But I am not able to set the time period of Pulse 1ms. How to do this?
t1.png


Currently It's giving first one pulse, And now I am expecting second one pulse

Regards,
Kumar
 
Hi,

1ms equals to 1kHz.
1kHz x 4096 = 4.096MHz

25MHz / 4.096 MHz = 6.1
round down --> integer = 6
Subtract 1 --> prescaler = 6 (I guess you missed the "-1" as shown in the datasheet formula)

So setting the prescaler to 5 should result in 0.983 ms

For more detailed assitance we need to see your schematic (including all informations like power supply and part values) and your PCB layout.

Klaus
 
Last edited:
Hi,

1ms equals to 1kHz.
1kHz x 4096 = 4.096MHz

25MHz / 4.096 MHz = 6.1
round down --> integer = 6
Subtract 1 --> prescaler = 6 (I guess you missed the "-1" as shown in the datasheet formula)

So setting the prescaler to 5 should result in 0.983 ms

For more detailed assitance we need to see your schematic (including all informations like power supply and part values) and your PCB layout.

Klaus
Hi,
I am sending my all project configurations -
Schematic diagram I have drawn it on paint.
3d.png


project edit configuration-
eda_schematic.png


Regards,
Kumar
 
Hi,

your wiring shows ony 3 connections. But you need at least 4.
--> update your drawing

The header also shows an "OE" signal. You left it unconnected. Did you read the datsheet about it? If not: --> do so.

I see no pullup on SCL and SDA. Where are they? What value?

Do you have a scope?
Do you have a DVM?

Klaus
 
Hi,
No Klaus, I am getting pulse using three pins only, SCL, SDA, and GND. So, no need of 'OE' pin.
I have both scope and DVM.
SCL_i2c = 0;
SDA_i2c = 0;
SCL_direction = 0;
SDA_direction = 0;

I took these above line from the above post.

Regard,
Kumar
 
Hi,
If I want to connect the 'OE' pin of PCA9685 module to the pca16f1526 uC, Then which pin of uC, Should I use?
This is the pin diagram of uC-
pic16.png


For GND pin I forgot to mention in sketch but there is a GND pin I am using.

Regards,
Kumar
 
Hi,

Neither I nor the datasheet says you need to connect it to a microcontroller.
But if you want to do so, you are free to use any microcontroller output you like.

OE pin just must not be left floating.Pull up / pull down ... (or actively driven) is suffient for the IC to run reliably.

Klaus
 
Hi,
In PCA9685 module they are using I2C interface, so I don't think OE pin is mandatory to connect.

Regards,
Kumar
 
In PCA9685 module they are using I2C interface, so I don't think OE pin is mandatory to connect.
It's not required for I2C but need to be connected to GND to enable output driver. May be there's a pull-up or pull-down on your PCA9685 board, I don't have a spec.

Both SCL and SDA need pull ups. Mandatory.
There are two resistors on the PCB that look like I2C pull-ups. Just a guess, need to verify.
--- Updated ---

A closer look clarifies there are 10k pull-ups on SDA and SCL and 10k pull-down on /OE. Should work as is.
 
Last edited:
GPT-4 code example


#include <xc.h>
#include "your_i2c_library.h" // You need to include or write a library for I2C communication
// Define the PCA9685 address and registers
#define PCA9685_ADDRESS 0x40
#define MODE1 0x00
#define PRESCALE 0xFE
#define LED0_ON_L 0x06
#define LED0_ON_H 0x07
#define LED0_OFF_L 0x08
#define LED0_OFF_H 0x09
// Function prototypes
void PCA9685_Init(unsigned char freq);
void PCA9685_SetPWM(unsigned char num, unsigned short on, unsigned short off);
void main(void) {
// Initialize I2C communication
I2C_Init(); // This depends on the library or code you're using for I2C
// Initialize PCA9685 for 50Hz servo control
PCA9685_Init(50);
// ... Your code for setting up PIC16F1526 peripherals (if any)
// Control the servo motor
PCA9685_SetPWM(0, 0, 307); // Example to set channel 0 for a specific servo position
// ... Your main code loop
while(1) {
// Your loop code here
}
}
void PCA9685_Init(unsigned char freq) {
unsigned char prescale, oldmode, newmode;
double prescaleval;

// Set the prescale value for 50Hz
prescaleval = 25000000; // 25MHz
prescaleval /= 4096; // 12-bit
prescaleval /= freq;
prescaleval -= 1;
prescale = (unsigned char)prescaleval;

// Set up the PCA9685
I2C_Start();
I2C_Write(PCA9685_ADDRESS);
I2C_Write(MODE1);
I2C_Read(&oldmode);
newmode = (oldmode & 0x7F) | 0x10; // sleep
I2C_Write(MODE1);
I2C_Write(newmode); // go to sleep
I2C_Write(PRESCALE);
I2C_Write(prescale); // set the prescaler
I2C_Write(MODE1);
I2C_Write(oldmode);
__delay_ms(5);
I2C_Write(MODE1);
I2C_Write(oldmode | 0xA1); // This sets the MODE1 register to turn on auto increment.

I2C_Stop();
}
void PCA9685_SetPWM(unsigned char num, unsigned short on, unsigned short off) {
I2C_Start();
I2C_Write(PCA9685_ADDRESS);
I2C_Write(LED0_ON_L+4*num);
I2C_Write(on);
I2C_Write(on >> 8);
I2C_Write(off);
I2C_Write(off >> 8);
I2C_Stop();
}
 

LaTeX Commands Quick-Menu:

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top