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上位机的官方网站进行查看,感谢支持。

 

  • 21
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
关于vofa上位机PID的问题,我可以为您提供一些基本的指导。首先,您需要了解PID控制器的基本概念和参数节方法。PID控制器由比例(P)、积分(I)和微分(D)三个部分组成,用于节系统的输出以使其接近期望值。 在vofa上位机中,您可以按照以下步骤进行PID试: 1. 设置初始参数:将P、I和D参数的初始值设置为0,并将输出限制设置为适当的范围。 2. 整比例参数:增加P参数的值,观察系统响应。如果响应过冲或不稳定,减小P值;如果响应过于缓慢,增加P值。逐渐整P值,直到系统响应接近期望值。 3. 整积分参数:增加I参数的值,观察系统响应。如果存在稳态误差(系统无法完全达到期望值),增加I值;如果系统响应过冲或不稳定,减小I值。逐渐整I值,直到稳态误差最小。 4. 整微分参数:增加D参数的值,观察系统响应。微分作用可以提高系统的稳定性和抗干扰能力。如果系统响应过冲或不稳定,减小D值;如果响应过于缓慢,增加D值。逐渐整D值,直到系统响应最佳。 5. 迭代整:根据实际情况,反复进行参数整和观察,直到系统达到期望的响应效果。 请注意,PID参数的整需要根据具体的系统和控制需求进行,因此上述步骤仅提供了一个基本的指导。在试过程中,您可能需要进行多次试验和整,以找到最优的PID参数组合。 希望这些信息对您有所帮助!如果您还有其他问题,请随时提问。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值