STM32 PCA9685 HAL庫 舵機擴展板
概述
最近在學習機械臂控制,由于單片機的IO口有限,如果機械臂的舵機都使用單片機控制,過于占用資源,從網上購買了PCA9685這款舵機擴展板,通過I2C與單片機通信,實作對舵機的控制,節省了單片機的IO口,對于PCA9685的使用網上的資料很少,賣家給的資料也全部都是英文版的,目前還沒有完全搞清楚,都是如果僅僅用于控制舵機啥的,不需要太關心PCA9685,以后有時間再好好研究研究,
I2C通信
STM32的I2C通信有兩種方式,一種是硬體I2C,還有一種是模擬I2C,這兩種的區別大概就是硬體I2C直接使用庫函式進行操作,模擬I2C根據I2C的作業時序,自己寫相應的函式,操作單片機,包括起始信號,停止信號,應答信號等,跟串口相同的地方是I2C同樣有中斷和DMA,但是在這里僅僅使用阻塞方式就行,I2C的具體原理已經有很多的資料可以參考了,HAL庫的I2C使用硬體I2C更加方便,因為HAL庫已經提供了比較完整的庫函式,不需要自己寫函式操作單片機,更加便捷,
主要HAL庫I2C 阻塞方式下的庫函式:
/*I2C寫資料的函式*/
HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
/*
I2C_HandleTypeDef *hi2c :也就是你所設定的那個實體,比如I2C1 &hi2c1
uint16_t DevAddress : 你要寫入資料的地址,比如0xA0
uint8_t *pData :存放你要寫的資料
uint16_t Size :資料的大小
uint32_t Timeout :最大的傳輸時間
例如
HAL_I2C_Master_Transmit(&hi2c1,0xA1,(uint8_t*)TxData,2,1000)
*/
/*I2C讀資料的函式*/
HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
/*
I2C_HandleTypeDef *hi2c :也就是你所設定的那個實體,比如I2C1 &hi2c1
uint16_t DevAddress : 你要讀入資料的地址,比如0xA0
uint8_t *pData :存放你要讀的資料
uint16_t Size :資料的大小
uint32_t Timeout :最大的傳輸時間
*/
還有許多的其他庫函式,但是這里用不到,就暫時不加啦!
/*PCA9685.c*/
#include "stm32_pca9685.h"
#include "math.h"
#include "i2c.h"
uint8_t pca_read(uint8_t startAddress) {
//Send address to start reading from.
uint8_t tx[1];
uint8_t buffer[1];
tx[0]=startAddress;
HAL_I2C_Master_Transmit(&hi2c1,pca_adrr, tx,1,10000);
HAL_I2C_Master_Receive(&hi2c1,pca_adrr,buffer,1,10000);
return buffer[0];
}
void pca_write(uint8_t startAddress, uint8_t buffer) {
//Send address to start reading from.
uint8_t tx[2];
tx[0]=startAddress;
tx[1]=buffer;
HAL_I2C_Master_Transmit(&hi2c1,pca_adrr, tx,2,10000);
}
void pca_setfreq(float freq)//設定PWM頻率
{
uint8_t prescale,oldmode,newmode;
double prescaleval;
freq *= 0.92;
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); // go to sleep
pca_write(pca_pre, prescale); // set the prescaler
pca_write(pca_mode1, oldmode);
HAL_Delay(2);
pca_write(pca_mode1, oldmode | 0xa1);
}
void pca_setpwm(uint8_t num, uint32_t on, uint32_t 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:舵機PWM輸出引腳0~15,on:PWM上升計數值0~4096,off:PWM下降計數值0~4096
一個PWM周期分成4096份,由0開始+1計數,計到on時跳變為高電平,繼續計數到off時
跳變為低電平,直到計滿4096重新開始,所以當on不等于0時可作延時,當on等于0時,
off/4096的值就是PWM的占空比,*/
/*
函式作用:初始化舵機驅動板
引數:1.PWM頻率
2.初始化舵機角度
*/
void PCA_Servo_Init(float hz,uint8_t angle)
{
uint32_t off=0;
// IIC_Init();
pca_write(pca_mode1,0x0);
pca_setfreq(hz);//設定PWM頻率
off=(uint32_t)(145+angle*2.4);
pca_setpwm(0,0,off);pca_setpwm(1,0,off);pca_setpwm(2,0,off);pca_setpwm(3,0,off);
pca_setpwm(4,0,off);pca_setpwm(5,0,off);pca_setpwm(6,0,off);pca_setpwm(7,0,off);
pca_setpwm(8,0,off);pca_setpwm(9,0,off);pca_setpwm(10,0,off);pca_setpwm(11,0,off);
pca_setpwm(12,0,off);pca_setpwm(13,0,off);pca_setpwm(14,0,off);pca_setpwm(15,0,off);
HAL_Delay(500);
}
/*
函式作用:控制舵機轉動;
引數:1.輸出埠,可選0~15;
2.起始角度,可選0~180;
3.結束角度,可選0~180;
4.模式選擇,0 表示函式內無延時,呼叫時需要在函式后另外加延時函式,且不可調速,第五個引數可填任意值;
1 表示函式內有延時,呼叫時不需要在函式后另外加延時函式,且不可調速,第五個引數可填任意值;
2 表示速度可調,第五個引數表示速度值;
5.速度,可填大于 0 的任意值,填 1 時速度最快,數值越大,速度越小;
注意事項:模式 0和1 的速度比模式 2 的最大速度大;
*/
void PCA_Servo(uint8_t num,uint8_t end_angle)
{
uint32_t off=0;
off=(uint32_t)(158+end_angle*2.2);
pca_setpwm(num,0,off);
}
/*PCA9685.h*/
#ifndef __STM32PCA9685_H
#define __STM32PCA9685_H
//#include "stm32f10x.h"
#include "stm32f4xx_hal.h"
#define pca_adrr 0x80
#define pca_mode1 0x0
#define pca_pre 0xFE
#define LED0_ON_L 0x6
#define LED0_ON_H 0x7
#define LED0_OFF_L 0x8
#define LED0_OFF_H 0x9
#define jdMIN 115 // minimum
#define jdMAX 590 // maximum
#define jd000 130 //0度對應4096的脈寬計數值
#define jd180 520 //180度對應4096的脈寬計算值
void pca_write(uint8_t adrr,uint8_t data);
uint8_t pca_read(uint8_t adrr);
void PCA_Servo_Init(float hz,uint8_t angle);
void pca_setfreq(float freq);
void pca_setpwm(uint8_t num, uint32_t on, uint32_t off);
void PCA_Servo(uint8_t num,uint8_t end_angle);
#endif
具體的代碼解釋還沒來得及做,感謝那些原作者的分享,站在巨人的肩膀上能使我們看得更遠,
原文點這里哦!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/291722.html
標籤:其他
上一篇:[長文干貨]MicroPython移植到野火STM32F429開發板
下一篇:crm系統讓企業更具競爭力
