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);
	}
}

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐