自己在刷B站的时候,看见很多大佬自己手工做的四组机器人,要知道,没有一个男人可以拒绝这些可以动的机器的时候,都是没有抵抗力的,我自己也不例外,如何自己也在犹豫,要不要自己也做一个,说实话自己做的时候也没有底气,因为自己也觉得很困难,有点不相信自己,但是还是鼓起勇气做了一个,慢慢的自己也学到了一些东西,而且对电路也有了认识,我自己也觉得是一个还不错的项目,而且还没有想象的那么难,比较简单,但是做起来还是蜿蜒曲折,做的时候走了不少的弯路,所以在这分享给各位,如果对各位有帮助,那也挺不错的,如果有大佬看出有什么不足,还请大佬指出来,比较自己也是一个小白,学习的过程在于交流。
需要的材料
需要的耗材其实也不是很多,在淘宝上也比较便宜,
首先就是机器人的灵魂,主控板:stm32f103c8t6
这个随便那个店铺都可以,现在stm32也是白菜价,买几个也无所谓,我推荐还是买没有焊的,比较比较便宜嘛,自己拿回来焊一下,可以给自己省几块钱
然后就是蓝牙模块,主要是用于控制机器人的运动,这个买一个CH-05或者CH-06啊什么的都可以,毕竟蓝牙不需要自己写代码,插上就能用。
然后就是舵机的控制板,因为涉及到的舵机比较多,所以舵机不能直接连接到stm32上,不然浪费stm32的资源不说,供电也容易把板子烧了。
可以看见这样一个板子可以驱动16路舵机哈,而且只需要连接四根线,还是比较强大的这个板子。
然后就是机器人的身体了,这个身体是3D打印出来的,在网上买的也比较贵,就光买一个支架差不多都要四五十米,我也会把3D打印的图纸放在最下面,如果有条件的可以自己打印,实在不行也可以自己去买一个。
最后就是舵机了,因为需要的舵机有点多,需要八个,这个看各位自己了,但是我建议用SG90,虽然这个只能转180度,但是别的舵机塞不进去这个身体里面,反正我是没有塞进去,所以我才建议SG90。
串口通信
然后我们开始着手串口通信,其实用蓝牙连接串口很简单,都不需要自己些代码,用HAL库直接生成,然后直接调用就行了。
先来看HAL库把。
然后可以看见,就这三步串口就可以说已经生成好了,然后我波特率用的是9600,要和自己设置蓝牙的波特率一致不然单片机接收不到数据。然后进入工程直接调用就好了,但要记住,把外部时钟打开,还要开到72兆话不多说上个图。
然后就可以开始写代码了,代码也很简单,直接调用就好了,但是要把蓝牙设置为从机模式,我之前也遇到了,明明直接用就可以了,但是单片机就是没有反应,最后绕了很久才知道,要把蓝牙设置为从机模式,这个软件等一会我也放到云盘里面。
先给大家看看怎么设置从机模式。
可以看见啊,只需要打开串口,然后点两下,就设置完成了,还是比较简单的。
然后就是代码,可以看见啊,就自己定义了一个变量,然后接一下线就可以了,就直接可以用了。
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t RX;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
printf("AT+ROLE=S");
// HAL_UART_Transmit(&huart1,"11111\r\n",7,HAL_MAX_DELAY);
while ( 1 )
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_UART_Receive(&huart1,&RX,1,HAL_MAX_DELAY);//接收函数
if(RX == '1')
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}
else if(RX == '2')
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
}
}
PAC9685
然后串口写完了,就是轮到了PAC9685,这个模块需要一个驱动代码,这个也是我找的一个大佬的代码,写的非常好,也很详细,如果有兴趣可以去看看:(54条消息) 使用CodeMX配置stm32单片机实现对PCA9685的控制_田小呱的博客-CSDN博客,然后这个PAC9685需要用I2C驱动,这里把步骤给大家看一下。
其实根本不用设置,这个些都是默认设置,把I2C打开就好了。然后就是PAC9685:
这个是.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_MG9XX_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_MG9XX(uint8_t num,uint8_t end_angle)
{
uint32_t off=0;
off=(uint32_t)(158+end_angle*2.2);
pca_setpwm(num,0,off);
}
这个是.h文件
#ifndef __STM32PCA9685_H
#define __STM32PCA9685_H
//#include "stm32f10x.h"
#include "stm32f1xx_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_MG9XX_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_MG9XX(uint8_t num,uint8_t end_angle);
#endif
这个把I2C打开了直接用就好了然后看一下调用把
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t RX;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
PCA_MG9XX_Init(65,90);//初始化舵机驱动
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
printf("AT+ROLE=S");
// HAL_UART_Transmit(&huart1,"11111\r\n",7,HAL_MAX_DELAY);
while ( 1 )
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_UART_Receive(&huart1,&RX,1,HAL_MAX_DELAY);//接收函数
if(RX == '1')
{
PCA_MG9XX(2,50); //通道0 从0度转到180度
PCA_MG9XX(1,100); //通道2 从0度转到180度
HAL_Delay(200);
PCA_MG9XX(9,70); //通道0 从0度转到180度
PCA_MG9XX(0,40); //通道0 从180度转到0度
PCA_MG9XX(2,120); //通道0 从0度转到180度
PCA_MG9XX(1,30); //通道2 从0度转到180度
PCA_MG9XX(3,170); //通道0 从0度转到180度
HAL_Delay(200);
PCA_MG9XX(0,100); //通道0 从180度转到0度
PCA_MG9XX(2,120); //通道0 从0度转到180度
PCA_MG9XX(1,30); //通道2 从0度转到180度
PCA_MG9XX(3,110); //通道0 从0度转到180度
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}
else if(RX == '2')
{
PCA_MG9XX(0,140); //通道0 从180度转到0度
PCA_MG9XX(1,10); //通道0 从180度转到0度
PCA_MG9XX(2,50); //通道2 从180度转到0度
PCA_MG9XX(3,160); //通道0 从0度转到180度
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
// HAL_UART_Transmit(&huart1,"led two\r\n",6,HAL_MAX_DELAY);
}
}
然后就好了,然后把接线图和程序都放到一起,程序写的很散,如果有大佬发现问题,希望直接指出来,如果有不懂的,也可以直接问我,我们互相学习,互相进步,创作不易,如果有人看到这里,希望点给赞,我会很开心的
链接:https://pan.baidu.com/s/12EmAttUPv-b8qysu2D9wiQ?pwd=1234
提取码:1234