vofa+上位机,无线调PID(附stm32F407标准库代码)

第一部分、初始化配置

步骤1、数据引擎选择JustFloat

步骤2、数据接口选择串口

步骤3、端口号选择下位机的端口

步骤4、波特率选择kiel中串口的波特率(需要一致,否则接收到的数据是乱码)

第二部分、获取下位机的波形

我读取的是MPU6050陀螺仪数据

第三部分、增加控件命令

步骤1、创建命令

我创建的命令(供参考)

步骤2、绑定命令

步骤3、设置菜单

第四部分、下位机(stm32F407)代码部分(以串口2为例)

USART2.c

#include "USART2.h"

float Serial_RxFlag_USART2;
uint16_t Serial_RxPacket_USART2[8];
uint16_t units,tens,hundreds,decimal_Firs,decimal_Sec;
int32_t P, P_integer, P_decimal, I, I_integer, I_decimal, D, D_integer, D_decimal;

void USART2_Init(int BaudRate)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    // 1. 启用串口时钟和GPIO时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOD, &GPIO_InitStruct);
    // 2. 配置串口引脚
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_USART2); // TX
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_USART2); // RX

    // 3. 初始化串口设置
    USART_InitTypeDef USART_InitStruct;
    USART_InitStruct.USART_BaudRate = BaudRate;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    USART_InitStruct.USART_Parity = USART_Parity_No;
    USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_Init(USART2, &USART_InitStruct);

    // 4. 配置串口中断
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); // 使能接收中断

    // 5. 使能串口
    USART_Cmd(USART2, ENABLE);
}

void Serial_SendByte_USART2(uint8_t Byte)        //串口发送一个字节
{
    USART_SendData(USART2, Byte);
    while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
}


void Serial_SendArray_USART2(uint8_t *Array, uint16_t Length)        //串口发送一个数组(在串口助手中一般使用HEX模式)
{
    uint16_t i;
    for (i = 0; i < Length; i ++)
    {
        Serial_SendByte_USART2(Array[i]);
    }
}

void USART_SendString_USART2(char *String)        //串口发送一个字符串(与发送数组类似)(在串口助手中使用一般使用文本模式)
{
    uint8_t i;
    for (i = 0; String[i] != '\0'; i ++)
    {
        Serial_SendByte_USART2(String[i]);
    }
}


uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
    uint32_t Result = 1;
    while (Y --)
    {
        Result *= X;
    }
    return Result;
}


void Serial_SendNumber_USART2(uint32_t Number, uint8_t Length)        //发送字符形式的数字
{
    uint8_t i;
    for (i = 0; i < Length; i ++)
    {
        Serial_SendByte_USART2(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');        //数字的类型与字符型的相差0x30("0")
    }
}


uint8_t Serial_GetRxFlag_USART2(void)        //接收标志位
{
    if (Serial_RxFlag_USART2 == 1)
    {
        Serial_RxFlag_USART2 = 0;
        return 1;
    }
    return 0;
}

typedef union
{
    float fdata;         // 浮点数
    unsigned long ldata; // 无符号长整型(通常是32位)
} FloatLongType;
void vofa_To_four(float x,unsigned char byte[])        /*vofa上位机,将参数X转化为四个8位数据*/
{
    FloatLongType fl;
    fl.fdata=x;
    byte[0] = (unsigned char)fl.ldata;
    byte[1] = (unsigned char)(fl.ldata >> 8);
    byte[2] = (unsigned char)(fl.ldata >> 16);
    byte[3] = (unsigned char)(fl.ldata >> 24);            
}

void Send_vofa(float x)
{
    u8 vofa[4] = {0};
    u8 tail[4] = {0x00, 0x00, 0x80, 0x7f};
    vofa_To_four(x, vofa);
    Serial_SendArray_USART2(vofa, 4);
    Serial_SendArray_USART2(tail, 4);
}

void USART2_IRQHandler(void)    //设置一个标志位
{
    static uint8_t flag_P, flag_I, flag_D;        //静态变量只在本函数中使用,初始化一次
    static uint8_t pRxPacket = 0;
    if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
    {
        uint16_t RxData = USART_ReceiveData(USART2);
        if(RxData == 80)            /*获取VOFA上位机P的值*/
        {
            flag_P = 1;
        }
        else if(flag_P == 1)
        {
            Serial_RxPacket_USART2[pRxPacket] = RxData;
            pRxPacket ++;
            if((Serial_RxPacket_USART2[6] == 64)||(Serial_RxPacket_USART2[5] == 64)||(Serial_RxPacket_USART2[4] == 64))
            {    
                if(pRxPacket == 7)
                {
                    hundreds = Serial_RxPacket_USART2[0] - '0';
                    tens = Serial_RxPacket_USART2[1] - '0';
                    units = Serial_RxPacket_USART2[2] - '0';
                    decimal_Firs = Serial_RxPacket_USART2[4] - '0';
                    decimal_Sec = Serial_RxPacket_USART2[5] - '0';

                    P_decimal = decimal_Firs * 10 + decimal_Sec;
                    P_integer = hundreds * 100 + tens * 10 + units;
                    P = P_integer + P_decimal / 100;
                    flag_P = 0;
                    pRxPacket=0;
                    Serial_RxPacket_USART2[6]='0';
                }
                else if(pRxPacket == 6)
                {
                    tens = Serial_RxPacket_USART2[0] - '0';
                    units = Serial_RxPacket_USART2[1] - '0';
                    
                    decimal_Firs = Serial_RxPacket_USART2[3] - '0';
                    decimal_Sec = Serial_RxPacket_USART2[4] - '0';
                    P_integer = tens * 10 + units;
                    P_decimal = decimal_Firs * 10 + decimal_Sec;
                    P = P_integer + P_decimal / 100;
                    flag_P = 0;
                    pRxPacket=0;
                    Serial_RxPacket_USART2[5]='0' ;
                }
                else if(pRxPacket == 5)
                {
                    units = Serial_RxPacket_USART2[0] - '0';
                    
                    decimal_Firs = Serial_RxPacket_USART2[2] - '0';
                    decimal_Sec = Serial_RxPacket_USART2[3] - '0';
                    P_integer = units;
                    P_decimal = decimal_Firs * 10 + decimal_Sec;
                    P = P_integer + P_decimal / 100;
                    flag_P = 0;
                    pRxPacket=0;
                    Serial_RxPacket_USART2[4]='0' ;
                }
            }
        }
                
                
        if(RxData == 73)            /*获取VOFA上位机I的值*/
        {
            flag_I = 1;
        }
        else if(flag_I == 1)
        {
            Serial_RxPacket_USART2[pRxPacket] = RxData;
            pRxPacket ++;
            if((Serial_RxPacket_USART2[6] == 64)||(Serial_RxPacket_USART2[5] == 64)||(Serial_RxPacket_USART2[4] == 64))
            {    
                if(pRxPacket == 7)
                {
                    hundreds = Serial_RxPacket_USART2[0] - '0';
                    tens = Serial_RxPacket_USART2[1] - '0';
                    units = Serial_RxPacket_USART2[2] - '0';
                    decimal_Firs = Serial_RxPacket_USART2[4] - '0';
                    decimal_Sec = Serial_RxPacket_USART2[5] - '0';

                    I_decimal = decimal_Firs * 10 + decimal_Sec;
                    I_integer = hundreds * 100 + tens * 10 + units;
                    I = I_integer + I_decimal / 100;
                    flag_I = 0;
                    pRxPacket=0;
                    Serial_RxPacket_USART2[6]='0';
                }
                else if(pRxPacket == 6)
                {
                    tens = Serial_RxPacket_USART2[0] - '0';
                    units = Serial_RxPacket_USART2[1] - '0';
                    
                    decimal_Firs = Serial_RxPacket_USART2[3] - '0';
                    decimal_Sec = Serial_RxPacket_USART2[4] - '0';
                    I_integer = tens * 10 + units;
                    I_decimal = decimal_Firs * 10 + decimal_Sec;
                    I = I_integer + I_decimal / 100;
                    flag_I = 0;
                    pRxPacket=0;
                    Serial_RxPacket_USART2[5]='0' ;
                }
                else if(pRxPacket == 5)
                {
                    units = Serial_RxPacket_USART2[0] - '0';
                    
                    decimal_Firs = Serial_RxPacket_USART2[2] - '0';
                    decimal_Sec = Serial_RxPacket_USART2[3] - '0';
                    I_integer = units;
                    I_decimal = decimal_Firs * 10 + decimal_Sec;
                    I = I_integer + I_decimal / 100;
                    flag_I = 0;
                    pRxPacket=0;
                    Serial_RxPacket_USART2[4]='0' ;
                }
            }
        }
                
        if(RxData == 68)            /*获取VOFA上位机D的值*/
        {
            flag_D = 1;
        }
        else if(flag_D == 1)
        {
            Serial_RxPacket_USART2[pRxPacket] = RxData;
            pRxPacket ++;
            if((Serial_RxPacket_USART2[6] == 64)||(Serial_RxPacket_USART2[5] == 64)||(Serial_RxPacket_USART2[4] == 64))
            {    
                if(pRxPacket == 7)
                {
                    hundreds = Serial_RxPacket_USART2[0] - '0';
                    tens = Serial_RxPacket_USART2[1] - '0';
                    units = Serial_RxPacket_USART2[2] - '0';
                    decimal_Firs = Serial_RxPacket_USART2[4] - '0';
                    decimal_Sec = Serial_RxPacket_USART2[5] - '0';

                    D_decimal = decimal_Firs * 10 + decimal_Sec;
                    D_integer = hundreds * 100 + tens * 10 + units;
                    D = D_integer + D_decimal / 100;
                    flag_D = 0;
                    pRxPacket=0;
                    Serial_RxPacket_USART2[6]='0';
                }
                else if(pRxPacket == 6)
                {
                    tens = Serial_RxPacket_USART2[0] - '0';
                    units = Serial_RxPacket_USART2[1] - '0';
                    
                    decimal_Firs = Serial_RxPacket_USART2[3] - '0';
                    decimal_Sec = Serial_RxPacket_USART2[4] - '0';
                    D_integer = tens * 10 + units;
                    D_decimal = decimal_Firs * 10 + decimal_Sec;
                    D = D_integer + D_decimal / 100;
                    flag_D = 0;
                    pRxPacket=0;
                    Serial_RxPacket_USART2[5]='0' ;
                }
                else if(pRxPacket == 5)
                {
                    units = Serial_RxPacket_USART2[0] - '0';
                    
                    decimal_Firs = Serial_RxPacket_USART2[2] - '0';
                    decimal_Sec = Serial_RxPacket_USART2[3] - '0';
                    D_integer = units;
                    D_decimal = decimal_Firs * 10 + decimal_Sec;
                    D = D_integer + D_decimal / 100;
                    flag_D = 0;
                    pRxPacket=0;
                    Serial_RxPacket_USART2[4]='0' ;
                }
            }
        }
        
                USART_ClearITPendingBit(USART2, USART_IT_RXNE);
    }
}

USART2.h

#ifndef _USART2_H_
#define _USART2_H_
 
#include "stm32f4xx.h"
#include "board.h"
#include "stdio.h"

void USART2_Init(int BaudRate);
void Serial_SendByte_USART2(uint8_t Byte);
void USART_SendString_USART2(char *String);
void send_pack_USART2(long int * sendbuf);
void Serial_SendNumber_USART2(uint32_t Number, uint8_t Length);
char USART2_ReceiveChar(void);
void Serial_SendArray_USART2(uint8_t *Array, uint16_t Length);
void vofa_To_four(float x,unsigned char byte[]);
void Send_vofa(float x);

#endif

main.c(测试代码)

#include "bsp_mpu6050.h"
#include <stdio.h>
#include "board.h"
#include "inv_mpu.h"
#include "OLED.h"
#include "USART2.h"
extern int32_t P, P_integer, P_decimal, I, I_integer, I_decimal, D, D_integer, D_decimal;        //vofa上位机调试的PID,P整数,P小数
float pitch = 0, roll = 0, yaw = 0;
int main(void)
{
    USART2_Init(115200);
    board_init();
    OLED_Init();
    //MPU6050初始化
    MPU6050_Init();
    //DMP初始化
    while( mpu_dmp_init() )
    {
        delay_ms(200);
    }
    while(1) 
    {
        OLED_Refresh();
        OLED_ShowString(36, 0, "P:    .", 16, 1);
        OLED_ShowNum(49, 0, P, 3, 16, 1, 1);
        OLED_ShowNum(86, 0, P_decimal, 2, 16, 1, 1);
        
        OLED_ShowString(36, 17, "I:    .", 16, 1);
        OLED_ShowNum(49, 17, I, 3, 16, 1, 1);
        OLED_ShowNum(86, 17, I_decimal, 2, 16, 1, 1);
        
        OLED_ShowString(36, 33, "D:    .", 16, 1);
        OLED_ShowNum(49, 33, D, 3, 16, 1, 1);
        OLED_ShowNum(86, 33, D_decimal, 2, 16, 1, 1);
        OLED_Refresh();
        if( mpu_dmp_get_data(&pitch,&roll,&yaw) == 0 )
        { 
            Send_vofa(roll);            //发送翻滚角为例
        }      
    }
}

程序运行成功图片

串口中断的代码还能更优化,这里就不过多阐述,USART.c文件有与上位机的通信协议,想要更深了解VOFA上位机,可以去找VOFA上位机的官方网站进行查看,感谢支持。

 

03-14
### VOF API介绍 VOF API 是一种用于与特定硬件设备交互的应用程序编程接口 (API),主要负责通过 USB 或其他通信协议实现主机软件与外设之间的数据交换。其核心功能是从指定类型的设备获取描述符并操作相应的端点管道。 #### 功能概述 该 API 提供了一种机制来访问设备的描述符信息,这些描述符通常定义了设备的功能特性以及支持的操作模式。具体来说,它允许开发者基于 `type` 和 `index` 参数索引来定位目标资源,并利用标记为 `ep` 的控制管道执行命令[^1]。 如果用成功,则会返回实际写入缓冲区 (`buf`) 中的数据长度;反之,在发生错误的情况下则返回负数作为状态码指示异常情况的发生。 #### 使用方法示例 下面是一个简单的 Python 实现例子展示如何使用此类 API: ```python import ctypes def vof_api_call(device_handle, type_value, index_value, ep_flag, buf): bytes_written = ctypes.c_int() result = device_handle.get_descriptor( descriptor_type=type_value, descriptor_index=index_value, endpoint_flag=ep_flag, buffer=buf, length=len(buf), actual_length=ctypes.byref(bytes_written) ) if result >= 0: print(f"Successfully wrote {bytes_written.value} bytes.") else: print("Operation failed with error code:", result) # Example usage of the function buffer_data = bytearray(64) # Allocate a buffer to hold data from/to the device. vof_api_call(my_device_instance, type_value=1, index_value=0, ep_flag='control', buf=buffer_data) ``` 上述代码片段展示了如何构建一个函数来进行标准的 VOF API 用过程。这里假设存在名为 `my_device_instance` 的对象实例代表已连接的目标硬件实体。 ### 注意事项 当处理 HTTP 请求时需要注意区分不同类型的请求方式及其适用场景。例如 GET 请求适合于检索资源而不改变服务器上的任何东西;而 POST 则常用来提交表单或者上传文件等动作[^2]。另外还需要考虑安全性方面的问题比如采用 HTTPS 加密传输可以有效防止中间人攻击保护敏感信息安全传递给远程服务端。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值