首先我们先利用stm32cubemax创建工程代码(代码部分于先前博客一致)
生成代码并添加相对应的文件bsp、datou.c/h
main.c:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2023 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "datou.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* 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_DMA_Init();
MX_USART3_UART_Init();
/* USER CODE BEGIN 2 */
/*底盘电机初始化*/
StepperMotorControl_init(&moto1,0x01);
StepperMotorControl_init(&moto2,0x02);
StepperMotorControl_init(&moto3,0x03);
StepperMotorControl_init(&moto4,0x04);
HAL_Delay(100);
/*云台电机初始化*/
StepperMotorControl_init_location(&moto_9,0x09);//下云台是9
StepperMotorControl_init_location(&moto_8,0x08);
HAL_Delay(100);
set_angle_control_location(&moto_8,-900);//电机转-900度
HAL_Delay(2000);
set_speed(&moto1,1,200) ;//电机正转且速度为200
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
datou.h:
#ifndef __DATOU_H
#define __DATOU_H
#include "main.h"
typedef struct
{
uint8_t controlBytes[6];
uint8_t lastControlBytes[6];
} StepperMotorControl;
typedef struct
{
uint8_t controlBytes[9];
uint8_t lastControlBytes[9];
float now_angle;
} StepperMotorControl_location;
typedef enum
{
forward=0x12, //正
reverse=0x02 //反
}Command;
extern StepperMotorControl moto1;
extern StepperMotorControl moto2;
extern StepperMotorControl moto3;
extern StepperMotorControl moto4;
void StepperMotorControl_init(StepperMotorControl *control, uint8_t address);
void set_speed(StepperMotorControl *control, uint8_t direction, uint16_t speed);
void set_acceleration(StepperMotorControl *control, uint16_t acceleration);
extern StepperMotorControl_location moto_9;//下
extern StepperMotorControl_location moto_8;//上
void StepperMotorControl_init_location(StepperMotorControl_location *control, uint8_t address) ;
void set_angle_control_location(StepperMotorControl_location *control, float target_angle_num);
#endif
datou.c:
#include "datou.h"
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <usart.h>
StepperMotorControl moto1;//一号轮
StepperMotorControl moto2;//二号轮
StepperMotorControl moto3;//三号轮
StepperMotorControl moto4;//四号轮
/******************************************************
Function: void StepperMotorControl_init(StepperMotorControl *control, uint8_t address)
Description: 指定电机初始化函数(这个函数是用来指定电机的速度的)
Calls: NONE
Input: StepperMotorControl *control这个变量是结构体变量,这个结构体里面有2个成员
分别对应了当前发送的数据,上次发送的数据
address 是电机设定的地址
******************************************************/
void StepperMotorControl_init(StepperMotorControl *control, uint8_t address)
{
uint8_t defaultBytes[6] = {0x00, 0xF6, 0x10, 0x00, 0xaf, 0x6B};
memcpy(control->controlBytes, defaultBytes, 6);
memcpy(control->lastControlBytes, defaultBytes, 6);
control->controlBytes[0] = address;
}
static uint8_t hasChanged(StepperMotorControl *control)
{
for (uint8_t i = 0; i < 6; i++) {
if (control->controlBytes[i] != control->lastControlBytes[i])
{
return 1;
}
}
return 0;
}
static void updateLastControlBytes(StepperMotorControl *control)
{
for (uint8_t i = 0; i < 6; i++) {
control->lastControlBytes[i] = control->controlBytes[i];
}
}
static void sendCommand(StepperMotorControl *control)
{
if (hasChanged(control)) {
HAL_UART_Transmit(&huart3, control->controlBytes, 6, 100);
updateLastControlBytes(control);
}
}
/******************************************************
Function: void set_speed(StepperMotorControl *control, uint8_t direction, uint16_t speed)
Description: 设置电机的转速
Calls: static void sendCommand(StepperMotorControl *control)
Input: StepperMotorControl *control这个变量是结构体变量,这个结构体里面有2个成员
分别对应了当前发送的数据,上次发送的数据
direction 是电机的方向
speed 是电机的速度
******************************************************/
void set_speed(StepperMotorControl *control, uint8_t direction, uint16_t speed)
{
if (direction) {
control->controlBytes[2] = (0x10) | ((speed >> 8) & 0x0F); // 逆时针方向
} else {
control->controlBytes[2] = (0x00) | ((speed >> 8) & 0x0F); // 顺时针方向
}
control->controlBytes[3] = speed & 0xFF;
sendCommand(control);
}
/******************************************************
Function: void set_acceleration(StepperMotorControl *control, uint16_t acceleration)
Description: 设置电机的加转速
Calls: static void sendCommand(StepperMotorControl *control)
Input: StepperMotorControl *control这个变量是结构体变量,这个结构体里面有2个成员
分别对应了当前发送的数据,上次发送的数据
acceleration 是电机的加速度
******************************************************/
void set_acceleration(StepperMotorControl *control, uint16_t acceleration)
{
control->controlBytes[4] = acceleration;
sendCommand(control);
}
StepperMotorControl_location moto_9;//下
StepperMotorControl_location moto_8;//上
/******************************************************
Function: void StepperMotorControl_init_location(StepperMotorControl_location *control, uint8_t address)
Description: 指定电机初始化函数(这个函数是用来指定电机的位置的)
Calls: NONE
Input: StepperMotorControl_location *control这个变量是结构体变量,这个结构体里面有3个成员
分别对应了当前发送的数据,上次发送的数据,以及当前的位置值
address 是电机设定的地址
******************************************************/
void StepperMotorControl_init_location(StepperMotorControl_location *control, uint8_t address)
{
uint8_t defaultBytes[9] = {0x00, 0xFD, 0x12, 0x00, 0xaf,0x00,0x00,0x00,0x6B};
memcpy(control->controlBytes, defaultBytes, 9);
memcpy(control->lastControlBytes, defaultBytes, 9);
control->controlBytes[0] = address;
}
static uint8_t hasChanged_location(StepperMotorControl_location *control)
{
for (uint8_t i = 0; i < 9; i++) {
if (control->controlBytes[i] != control->lastControlBytes[i])
{
return 1;
}
}
return 0;
}
static void updateLastControlBytes_location(StepperMotorControl_location *control)
{
for (uint8_t i = 0; i < 9; i++) {
control->lastControlBytes[i] = control->controlBytes[i];
}
}
static void sendCommand_location(StepperMotorControl_location *control)
{
if (hasChanged_location(control)) {
HAL_UART_Transmit(&huart3, control->controlBytes, 9, 100);
updateLastControlBytes_location(control);
}
}
static void set_location(StepperMotorControl_location *control, Command com, int pulse_num)
{
control->controlBytes[2] =com;
control->controlBytes[6] = pulse_num>>8;/* 脉冲数中字节 */
control->controlBytes[7] = pulse_num-((pulse_num>>8)<<8); /* 脉冲数低字节 */
sendCommand_location(control);
}
/******************************************************
Function: void set_angle_control_location(StepperMotorControl_location *control, float target_angle_num)
Description: 控制指定电机的角度
Calls: static void set_location(StepperMotorControl_location *control, Command com, int pulse_num)
Input: StepperMotorControl_location *control这个变量是结构体变量,这个结构体里面有3个成员
分别对应了当前发送的数据,上次发送的数据,以及当前的位置值(由于需要通过用角度的差值来计算脉冲数,所以需要记录当前的位置)
target_angle_num 是目标角度
******************************************************/
#define a_circle_pulse 3200.0//这是一圈需要的脉冲数
void set_angle_control_location(StepperMotorControl_location *control, float target_angle_num)
{
double error_angle=target_angle_num-(control->now_angle);
int need_pulse=(int)(error_angle/360.0*a_circle_pulse);
if(error_angle!=0)
{
if(need_pulse<0)
{
set_location(control,reverse, -need_pulse);//注意此处的reverse可能需要改成forward,这个要根据你的物理结构而定
}
else
{
set_location(control,forward, need_pulse);//注意此处的forward可能需要改成reverse,这个要根据你的物理结构而定
}
control->now_angle=target_angle_num;
}
}
main.h包含头文件即可#ifndef __MAIN_H,#define __MAIN_H
编译无误后烤录到单片机stm32f103即可
完成上电自检后,接着按下图接线(参考博主张大头闭环伺服):
实物图如下:
并且调制好显示器中菜单的参数:比特率,串口,通讯地址,模式等
然后在串口调试助手xcom中输入对应的指令(十六进制)这里以串口3为例
完成串口通信既可实现电机转动如图:
这是没通信前的:
实现通信后:
背后转轴会发生指令要求中的转动: