stm32f103控制总线舵机(hal库版本)
·
usart1用于控制多个总线舵机
usart2用于和电脑进行调试
已上传githubGitHub - damowuhe/stm32f103_hal_busServo: stm32f103控制总线舵机(hal库)
demo.c
#include "demo.h"
#include "stdio.h"
#include "user_uart.h"
#define ID 0 // 舵机的ID号
//使用串口1作为舵机控制的端口
// <接线说明>
// STM32F103 PA9(Tx) <----> 总线伺服舵机转接板 Rx
// STM32F103 PA10(Rx) <----> 总线伺服舵机转接板 Tx
// STM32F103 GND <----> 总线伺服舵机转接板 GND
// STM32F103 V5 <----> 总线伺服舵机转接板 5V
// 使用串口2作为日志输出的端口
// <接线说明>
// STM32F103 PA2(Tx) <----> USB转TTL Rx
// STM32F103 PA3(Rx) <----> USB转TTL Tx
// STM32F103 GND <----> USB转TTL GND
// STM32F103 V5 <----> USB转TTL 5V (可选)
// 这些参数并非所有例程都会用到,根据具体接口的要求来设置
uint8_t statusCode;
float angle;
float nextAngle = 0; // 舵机的目标角度
uint16_t power = 1000; // 舵机执行功率 单位mV 默认为0
uint16_t speed = 200; // 舵机的转速 单位 °/s
uint16_t interval = 0; // 舵机旋转的周期
uint8_t wait = 0; // 0:不等待 1:等待舵机旋转到特定的位置
uint16_t t_acc; // 加速时间
uint16_t t_dec; // 减速时间
float angle_read; // 读取的角度
uint8_t is_cw = 0; // 舵机的旋转方向
uint16_t nTime = 3000; // 延时时间
uint16_t nCircle = 1; // 舵机旋转的圈数
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/********************************************************
* 测试通信检测指令,测试舵机是否在线
********************************************************/
void demo_ping()
{
printf("\r\n");
// Ping一下舵机
printf("[INFO]ping servo %d \r\n", ID);
statusCode = FSUS_Ping(&FSUS_usart1, ID);
printf("[INFO]status code %d \r\n", statusCode);
// 根据状态码做不同的处理
if (statusCode == FSUS_STATUS_SUCCESS)
{
printf("[INFO]ping success, servo %d echo \r\n", ID);
}
else
{
printf("[ERROR]ping fail, servo %d not online \r\n", ID);
}
// 等待1000ms
HAL_Delay(1000);
}
/********************************************************
* 设置单个舵机的角度
* 简易角度控制 + 当前角度查询
* 带加减速的角度控制(指定周期) + 当前角度查询
* 带加减速的角度控制(指定转速) + 当前角度查询
* 串口2每隔一段时间打印一下舵机角度信息。
********************************************************/
void demo_setAngle_SingleServo()
{
printf("GOTO: 135.0f\r\n");
// 简易角度控制 + 当前角度查询
angle = 135.0;
interval = 2000;
FSUS_SetServoAngle(&FSUS_usart1, ID, angle, interval, power, wait);
FSUS_QueryServoAngle(&FSUS_usart1, ID, &angle_read);
printf("Cur Angle: %.1f\r\n", angle_read);
// 等待2s
HAL_Delay(2000);
// 带加减速的角度控制(指定周期) + 当前角度查询
printf("GOTO+Interval: 0.0f\r\n");
angle = 0.0f;
interval = 1000;
t_acc = 100;
t_dec = 150;
FSUS_SetServoAngleByInterval(&FSUS_usart1, ID, angle, interval, t_acc, t_dec, power, wait);
FSUS_QueryServoAngle(&FSUS_usart1, ID, &angle_read);
printf("Cur Angle: %.1f\r\n", angle_read);
// 等待2s
HAL_Delay(2000);
// 带加减速的角度控制(指定转速) + 当前角度查询
printf("GOTO+speed: -135.0f\r\n");
angle = -135.0f;
speed = 200.0f;
t_acc = 100;
t_dec = 150;
FSUS_SetServoAngleByVelocity(&FSUS_usart1, ID, angle, speed, t_acc, t_dec, power, wait);
FSUS_QueryServoAngle(&FSUS_usart1, ID, &angle_read);
printf("Cur Angle: %.1f\r\n", angle_read);
}
/********************************************************
* 设置多个舵机的角度
* 演示如何使用简易角度控制指令来控制多个舵机。
********************************************************/
void demo_setAngle_MultiServo()
{
// 简易角度控制指令,控制0和1号舵机
angle = 135.0;
FSUS_SetServoAngle(&FSUS_usart1, 0, angle, interval, power, wait);
angle = 45.0;
FSUS_SetServoAngle(&FSUS_usart1, 1, angle, interval, power, wait);
// 等待动作完成
HAL_Delay(interval);
// 等待2s
HAL_Delay(2000);
// 简易角度控制指令,控制0和1号舵机
angle = -135.0;
FSUS_SetServoAngle(&FSUS_usart1, 0, angle, interval, power, wait);
angle = -45.0;
FSUS_SetServoAngle(&FSUS_usart1, 1, angle, interval, power, wait);
// 等待动作完成
HAL_Delay(interval);
// 等待2s
HAL_Delay(2000);
}
/********************************************************
* 例程演示了多圈角度控制以及查询实时多圈角度的API使用方法
* 简易多圈角度控制+ 当前多圈角度查询
* 带加减速的多圈角度控制(指定周期)+ 当前多圈角度查询
* 带加减速的多圈角度控制(指定转速)+ 当前多圈角度查询
********************************************************/
void demo_setAngle_MultiCircle()
{
printf("MTurn GOTO: 720.0f\r\n");
// 简易多圈角度控制 + 当前多圈角度查询
angle = 720.0f;
interval = 2000;
FSUS_SetServoAngleMTurn(&FSUS_usart1, ID, angle, interval, power, wait);
FSUS_QueryServoAngleMTurn(&FSUS_usart1, ID, &angle_read);
printf("Cur Angle: %.1f\r\n", angle_read);
// 等待2s
HAL_Delay(2000);
printf("MTurn GOTO: 0.0f\r\n");
angle = 0.0;
FSUS_SetServoAngleMTurn(&FSUS_usart1, ID, angle, interval, power, wait);
FSUS_QueryServoAngleMTurn(&FSUS_usart1, ID, &angle_read);
printf("Cur Angle: %.1f\r\n", angle_read);
// 等待2s
HAL_Delay(2000);
// 带加减速的多圈角度控制(指定周期) + 当前多圈角度查询
printf("MTurn+Interval GOTO: -180.0f\r\n");
angle = 180.0f;
interval = 1000;
t_acc = 100;
t_dec = 200;
FSUS_SetServoAngleMTurnByInterval(&FSUS_usart1, ID, angle, interval, t_acc, t_dec, power, wait);
FSUS_QueryServoAngleMTurn(&FSUS_usart1, ID, &angle_read);
printf("Cur Angle: %.1f\r\n", angle_read);
// 等待2s
HAL_Delay(2000);
// 带加减速的多圈角度控制(指定转速) + 当前多圈角度查询
printf("MTurn+speed GOTO: -180.0f\r\n");
angle = -180.0f;
speed = 100.0f;
t_acc = 100;
t_dec = 200;
FSUS_SetServoAngleByVelocity(&FSUS_usart1, ID, angle, speed, t_acc, t_dec, power, wait);
FSUS_QueryServoAngleMTurn(&FSUS_usart1, ID, &angle_read);
printf("Cur Angle: %.1f\r\n", angle_read);
// 等待2s
HAL_Delay(2000);
}
/********************************************************
* 设置舵机为阻尼模式,同时请求舵机的角度。在旋转舵机的情况下,每隔一段时间就更新一下舵机的角度。
* 串口2每隔一段时间打印一下舵机角度信息。
********************************************************/
void demo_DampingModeAndQueryAngle()
{
// 启用阻尼模式,给一次指令即可,重复发送会应用最新的指令。
FSUS_DampingMode(&FSUS_usart1, ID, power);
// 读取一下舵机的角度
statusCode = FSUS_QueryServoAngle(&FSUS_usart1, ID, &angle);
if (statusCode == FSUS_STATUS_SUCCESS)
{
// 成功的读取到了舵机的角度
printf("[INFO] servo id= %d ; angle = %f\r\n", ID, angle);
}
else
{
// 没有正确的读取到舵机的角度
printf("\r\n[INFO] read servo %d angle, status code: %d \r\n", ID, statusCode);
printf("[ERROR]failed to read servo angle\r\n");
}
// 等待500ms
HAL_Delay(500);
}
/********************************************************
* 测试舵机360度定速持续旋转
********************************************************/
void demo_WheelKeepMove()
{
// 舵机轮式模式定速控制 顺时针旋转3s
is_cw = 1;
FSUS_WheelKeepMove(&FSUS_usart1, ID, is_cw, speed);
HAL_Delay(3000);
// 舵机刹车 停顿2s
FSUS_WheelStop(&FSUS_usart1, ID);
HAL_Delay(1000);
// 舵机轮式模式定速控制 逆时针旋转3s
is_cw = 0;
FSUS_WheelKeepMove(&FSUS_usart1, ID, is_cw, speed);
HAL_Delay(3000);
// 舵机刹车 停顿2s
FSUS_WheelStop(&FSUS_usart1, ID);
HAL_Delay(1000);
}
/********************************************************
* 测试舵机定时旋转,顺时针旋转3s,然后逆时针旋转3s。
********************************************************/
void demo_WheelMoveTime()
{
// 舵机轮式模式定速控制 顺时针旋转3s
is_cw = 1;
FSUS_WheelMoveTime(&FSUS_usart1, ID, is_cw, speed, nTime);
// FSUS_WheelMoveTime是非阻塞的,因为有时候需要控制多个舵机同时旋转
// 所以在后面要手动加延迟
HAL_Delay(nTime);
// 停顿1s
HAL_Delay(1000);
// 舵机轮式模式定速控制 逆时针旋转3s
is_cw = 0;
FSUS_WheelMoveTime(&FSUS_usart1, ID, is_cw, speed, nTime);
HAL_Delay(nTime);
// 停顿1s
HAL_Delay(1000);
}
/********************************************************
* 测试舵机定圈旋转,顺时针旋转一圈,然后逆时针旋转一圈。
********************************************************/
void demo_WheelMoveCircle()
{
// 舵机轮转模式定速控制 顺时针旋转1圈
is_cw = 1;
FSUS_WheelMoveNCircle(&FSUS_usart1, ID, is_cw, speed, nCircle);
// FSUS_WheelMoveNCircle是非阻塞的,因为有时候需要控制多个舵机同时旋转
// 停顿3s
HAL_Delay(3000);
// 舵机轮转模式定速控制 逆时针旋转1圈
is_cw = 0;
FSUS_WheelMoveNCircle(&FSUS_usart1, ID, is_cw, speed, nCircle);
// 注意: FSUS_WheelMoveNCircle是非阻塞的,因为有时候需要控制多个舵机同时旋转
// 停顿3s
HAL_Delay(3000);
}
/********************************************************
* 读取舵机的实时状态,并且给出了判断工作状态异常的示例
* 电压
* 电流
* 功率
* 温度
* 工作状态标志位
// 舵机工作状态标志位
// BIT[0] - 执行指令置1,执行完成后清零。
// BIT[1] - 执行指令错误置1,在下次正确执行后清零。
// BIT[2] - 堵转错误置1,解除堵转后清零。
// BIT[3] - 电压过高置1,电压恢复正常后清零。
// BIT[4] - 电压过低置1,电压恢复正常后清零。
// BIT[5] - 电流错误置1,电流恢复正常后清零。
// BIT[6] - 功率错误置1,功率恢复正常后清零。
// BIT[7] - 温度错误置1,温度恢复正常后清零。
********************************************************/
void demo_QueryServoStatus()
{
// 读取用户自定义数据
// 数据表里面的数据字节长度一般为1个字节/2个字节/4个字节
// 查阅通信协议可知,舵机角度上限的数据类型是有符号短整型(UShort, 对应STM32里面的int16_t),长度为2个字节
// 所以这里设置value的数据类型为int16_t
int16_t value;
uint8_t dataSize;
// 传参数的时候, 要将value的指针强行转换为uint8_t
// 读取电压
statusCode = FSUS_ReadData(&FSUS_usart1, ID, FSUS_PARAM_VOLTAGE, (uint8_t *)&value, &dataSize);
printf("read ID: %d\r\n", ID);
if (statusCode == FSUS_STATUS_SUCCESS)
{
printf("read sucess, voltage: %d mV\r\n", value);
}
else
{
printf("fail\r\n");
}
// 读取电流
statusCode = FSUS_ReadData(&FSUS_usart1, ID, FSUS_PARAM_CURRENT, (uint8_t *)&value, &dataSize);
if (statusCode == FSUS_STATUS_SUCCESS)
{
printf("read sucess, current: %d mA\r\n", value);
}
else
{
printf("fail\r\n");
}
// 读取功率
statusCode = FSUS_ReadData(&FSUS_usart1, ID, FSUS_PARAM_POWER, (uint8_t *)&value, &dataSize);
if (statusCode == FSUS_STATUS_SUCCESS)
{
printf("read sucess, power: %d mW\r\n", value);
}
else
{
printf("fail\r\n");
}
// 读取温度
statusCode = FSUS_ReadData(&FSUS_usart1, ID, FSUS_PARAM_TEMPRATURE, (uint8_t *)&value, &dataSize);
if (statusCode == FSUS_STATUS_SUCCESS)
{
double temperature, temp;
temp = (double)value;
temperature = 1 / (log(temp / (4096.0f - temp)) / 3435.0f + 1 / (273.15 + 25)) - 273.15;
printf("read sucess, temperature: %f\r\n", temperature);
}
else
{
printf("fail\r\n");
}
// 读取工作状态
statusCode = FSUS_ReadData(&FSUS_usart1, ID, FSUS_PARAM_SERVO_STATUS, (uint8_t *)&value, &dataSize);
if (statusCode == FSUS_STATUS_SUCCESS)
{
// 舵机工作状态
// BIT[0] - 执行指令置1,执行完成后清零。
// BIT[1] - 执行指令错误置1,在下次正确执行后清零。
// BIT[2] - 堵转错误置1,解除堵转后清零。
// BIT[3] - 电压过高置1,电压恢复正常后清零。
// BIT[4] - 电压过低置1,电压恢复正常后清零。
// BIT[5] - 电流错误置1,电流恢复正常后清零。
// BIT[6] - 功率错误置1,功率恢复正常后清零。
// BIT[7] - 温度错误置1,温度恢复正常后清零。
if ((value >> 3) & 0x01)
printf("read sucess, voltage too high\r\n");
if ((value >> 4) & 0x01)
printf("read sucess, voltage too low\r\n");
}
else
{
printf("fail\r\n");
}
printf("================================= \r\n");
HAL_Delay(2000);
}
usart部分代码
#include "user_uart.h"
uint8_t usart1SendBuf[USART_SEND_BUF_SIZE + 1];
uint8_t usart1RecvBuf[USART_RECV_BUF_SIZE + 1];
RingBufferTypeDef usart1SendRingBuf;
RingBufferTypeDef usart1RecvRingBuf;
Usart_DataTypeDef FSUS_usart1;
uint8_t rc1;
void User_Uart_Init(UART_HandleTypeDef *huartx)
{
// 创建缓冲组
RingBuffer_Init(&usart1SendRingBuf, USART_SEND_BUF_SIZE, usart1SendBuf);
RingBuffer_Init(&usart1RecvRingBuf, USART_RECV_BUF_SIZE, usart1RecvBuf);
// 初始化自定义用户串口结构体
FSUS_usart1.recvBuf = &usart1RecvRingBuf;
FSUS_usart1.sendBuf = &usart1SendRingBuf;
FSUS_usart1.huartX = huartx;
// 开启接收中断
HAL_UART_Receive_IT(FSUS_usart1.huartX, (uint8_t *)&rc1, 1);
}
// 发送数据
void Usart_SendAll(Usart_DataTypeDef *usart)
{
uint8_t value;
while (RingBuffer_GetByteUsed(usart->sendBuf))
{
value = RingBuffer_Pop(usart->sendBuf);
HAL_UART_Transmit(usart->huartX, &value, 1, 1);
}
}
//中断接收
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
uint8_t ucTemp;
if (huart->Instance == FSUS_usart1.huartX->Instance)
{
ucTemp = rc1;
RingBuffer_Push(FSUS_usart1.recvBuf, ucTemp);// 接收到数据放入缓冲区,不在中断具体处理数据
HAL_UART_Receive_IT(FSUS_usart1.huartX, (uint8_t *)&rc1, 1);
}
}
更多推荐



所有评论(0)