STM32F103 controls PCA9685 to generate 16 PWM waves to control SG90 steering gear

Keywords: stm32

STM32 controls PCA9685 to generate 16 PWM waves to control SG90 steering gear

If you can click this article, it shows that you already know how powerful PCA9685 is. NXP originally made this chip to provide led use. In its official documents, you can see that all PWM outputs are written with LED, but PWM waveform can not only control a simple LED, but one aspect of PWM application is motor speed regulation, And some steering gear control angles are realized by adjusting the duty cycle of PWM wave. Therefore, this blog will introduce how to use this chip.

Bloggers use the following module, which is easy to buy on Taobao.

This chip is controlled by IIC bus. If you want to get started quickly, you can refer to another article of blogger, general software simulation IIC, just change the pin you want to use.

Stop gossiping and code

Chip use can refer to This article , I'm just talking about how to use it

#ifndef _PCA9685_H
#define _PCA9685_H

#include "sys.h"
#include "delay.h"
#include "iic.h"

// Here is the IIC address of your PWM module. The default is 0x80. You need to modify it to the address you use
#define pca_adrr 0x80
// Chip operating mode
#define pca_mode1 0x00
// Set chip frequency division
#define pca_pre 0xFE
// Channel address
#define LED0_ON_L 0x06
#define LED0_ON_H 0x07
#define LED0_OFF_L 0x08
#define LED0_OFF_H 0x09
 
 
//#define jdMIN  115 // minimum
//#define jdMAX  590 // maximum
//#Define jd000 130 / / 0 degrees corresponds to the pulse width count value of 4096
//#Define jd180 520 / / 180 degrees corresponds to the calculated pulse width of 4096

void pca_write(u8 adrr,u8 data);
u8 pca_read(u8 adrr);
void PCA9685_Init(float hz,u8 angle);
void pca_setfreq(float freq);
void pca_setpwm(u8 num, u32 on, u32 off);
void PCA_Set(u8 num,u8 start_angle,u8 end_angle,u8 mode,u8 speed);

#endif

The following is the specific implementation code

#include "pca9685.h"
#include "iic.h"
#include "delay.h"
#include "math.h"

// Write data, adrrd address and data to PCA
void pca_write(u8 adrr,u8 data)
{ 
	IIC_Start();
	
	IIC_Write_One_Byte(pca_adrr);
	IIC_Wait_Ack();
	
	IIC_Write_One_Byte(adrr);
	IIC_Wait_Ack();
	
	IIC_Write_One_Byte(data);
	IIC_Wait_Ack();
	
	IIC_Stop();
}

//Read data from PCA
u8 pca_read(u8 adrr)
{
	u8 data;
	IIC_Start();
	
	IIC_Write_One_Byte(pca_adrr);
	IIC_Wait_Ack();
	
	IIC_Write_One_Byte(adrr);
	IIC_Wait_Ack();
	
	IIC_Start();
	
	IIC_Write_One_Byte(pca_adrr|0x01);
	IIC_Wait_Ack();
	
	data=IIC_Read_One_Byte(0);
	IIC_Stop();
	
	return data;
}

//Set PWM frequency
void pca_setfreq(float freq)
{
		u8 prescale,oldmode,newmode;
		double prescaleval;
    	// If you can't understand the calculation here, you can go to the article mentioned earlier 
		freq *= 0.915; 
		prescaleval = 25000000;
		prescaleval /= 4096;
		prescaleval /= freq;
		prescaleval -= 1;
		prescale =floor(prescaleval + 0.5f);

		oldmode = pca_read(pca_mode1);
	
		newmode = (oldmode&0x7F) | 0x10; // sleep
	
		pca_write(pca_mode1, newmode); // You must enter sleep mode before setting the clock
	
		pca_write(pca_pre, prescale); // Set frequency division
	
		pca_write(pca_mode1, oldmode); // Write original mode
		delay_ms(2);
	
		pca_write(pca_mode1, oldmode | 0xa1); 
}
// Set the PWM of the channel
void pca_setpwm(u8 num, u32 on, u32 off)
{
		pca_write(LED0_ON_L+4*num,on);
		pca_write(LED0_ON_H+4*num,on>>8);
		pca_write(LED0_OFF_L+4*num,off);
		pca_write(LED0_OFF_H+4*num,off>>8);
}
/**
 *@num:Steering gear PWM output pin 0 ~ 15
 *@on:PWM Rising count value 0 ~ 4096
 *@off:PWM Descent count value 0 ~ 4096
 *A PWM cycle is divided into 4096 parts, counting from 0 to + 1, jumping to high level when counting on, and jumping to low level when counting off until 4096 is full. Therefore, when on is not equal to 0, it can be delayed. When on is equal to 0, the value of off/4096 is the duty cycle of PWM.
**/

/*
	The function initializes the steering gear drive board
	Parameter: 1.PWM frequency
		  2.Initialize steering gear angle
*/
void PCA9685_Init(float hz,u8 angle)
{
	u32 off=0;
    u8 i=0;
	IIC_Init();
	pca_write(pca_mode1,0x0);
	pca_setfreq(hz);//Set PWM frequency
	off=(u32)(102+angle*2.2);
    // Initializes that all channels are fixed to the specified angle angle
	for(i=0;i<=15;i++)
    {
        pca_setpwm(i,0,off);
    }
	
	delay_ms(500);
}

/*
	Function: control the steering gear rotation;
	Parameters: 1. Output port, optional 0 ~ 15;
		  2.Starting angle, optional: 0 ~ 180;
		  3.End angle, optional 0 ~ 180;
		  4.Mode selection, 0 means there is no delay in the function. When calling, a delay function needs to be added after the function, and speed regulation is not allowed. The fifth parameter can be filled with any value;
					  1 Indicates that there is a delay in the function. When calling, there is no need to add another delay function after the function, and the speed can not be adjusted. The fifth parameter can be filled with any value;
					  2 Indicates that the speed is adjustable, and the fifth parameter indicates the speed value;
		  5.Speed: any value greater than 0 can be filled in. When 1 is filled in, the speed is the fastest. The larger the value, the smaller the speed;
	Note: the speed of modes 0 and 1 is higher than the maximum speed of mode 2;
*/
// Generally, you can select 0 for mode, and start at this time_ Angle can also write 0 and speed, only end_angle is the angle you want to output.
void PCA_Set(u8 num,u8 start_angle,u8 end_angle,u8 mode,u8 speed)
{
	u8 i;
	u32 off=0;
	switch(mode)
	{
		case 0:
		{
			off=(u32)(102+end_angle*2.2);
			pca_setpwm(num,0,off);
		}break;

		case 1:
		{
			off=(u32)(158+end_angle*2.2);
			pca_setpwm(num,0,off);
			if(end_angle>start_angle)
            {
                delay_ms((u16)((end_angle-start_angle)*2.7));  // To use mode 1 or 2, you can adjust the multiple of 2.7 here to what you need
            }
			else
            {
                delay_ms((u16)((start_angle-end_angle)*2.7));
            }
		}break;
		case 2:
		{
			if(end_angle>start_angle)
			{
				for(i=start_angle;i<=end_angle;i++)
				{
					off=(u32)(158+i*2.2);
					pca_setpwm(num,0,off);
					delay_ms(2);
					delay_us(speed*250);
				}
			}
			else if(start_angle>end_angle)
			{
				for(i=start_angle;i>=end_angle;i--)
				{
					off=(u32)(158+i*2.2);
					pca_setpwm(num,0,off);
					delay_ms(2);
					delay_us(speed*250);
				}
			}
		}break;
	}
}

The delay, sys and iic used in the code can be Another article Download at the end of the page. There are no links here.

The test shows that the output angle of the steering gear is relatively stable.

Let's briefly talk about the steering gear SG90, which is a 90g steering gear. It is controlled by PWM wave with a period of 50Hz, that is, 20ms. In 0.5ms high level, the steering gear outputs 0 degrees, 1ms outputs 45 degrees, 1.5ms outputs 90 degrees, 2ms outputs 135 degrees, and 2.5ms outputs 180 degrees. In the code, it passes off=(u32)(158+i*2.2); To convert it into the value to be written to the chip channel register. You can adjust the accuracy by adjusting this calculation formula. However, through the personal test of the blogger, the output accuracy is enough to meet the general use.

If you think it's useful, you might as well like it. Welcome to click here Visit the blogger's personal website to exchange and learn together

Posted by duelist on Tue, 30 Nov 2021 11:22:49 -0800