无名飞控的FLASH

在看无名的Flash之前先看一下如何操作Flash


STM32 FLASH操作步骤

1. FLASH解锁
在对 FLASH 进行写操作前必须先解锁,固件库函数实现很简单:

FLASH_Unlock();//解锁
2. 清除相关的标志位
FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);//清除标志位
3. 擦除函数

固件库提供三个 FLASH 擦除函数:

FLASH_Status FLASH_ErasePage(uint32_t Page_Address);
FLASH_Status FLASH_EraseAllPages(void); 
FLASH_Status FLASH_EraseOptionBytes(void);

这三个函数可以顾名思义了,非常简单。

4. 写操作函数

固件库提供了三个 FLASH 写函数:

FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data); 
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data); 
FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);

顾名思义分别为: FLASH_ProgramWord 为 32 位字写入函数, 其他分别为 16 位半字写入和 8位字节写入函数。这里需要说明, 32 位字节写入实际上是写入的两次 16 位数据,写完第一次后地址+2。 写入 8 位实际也是占用的两个地址了,跟写入 16 位基本上没啥区别。

5. 锁定函数
在对 FLASH 写操作完成之后,我们要锁定 FLASH,使用的库函数是:

void FLASH_Lock(void);
而飞控里面在Parameter_Init函数里面调用了ReadFlashThreeFloat

定义:

uint8_t ReadFlashThreeFloat(uint32_t ReadAddress,
                         float *WriteData1,
                         float *WriteData2,
                         float *WriteData3)
{
    uint8_t buf[12];
    uint16_t i=0;
    uint8_t flag=0x00;
    ReadAddress = (uint32_t)STARTADDR + ReadAddress;
    *WriteData1=*(float *)(ReadAddress);
    *WriteData2=*(float *)(ReadAddress+4);
    *WriteData3=*(float *)(ReadAddress+8);
    FLASH_LockBank1();
    
    for(i=0;i<12;i++)//单字节数据
    {
        *(buf+i)=*(__IO uint8_t*) ReadAddress++;
    }
    if((buf[0]==0xff&&buf[1]==0xff&&buf[2]==0xff&&buf[3]==0xff))
       flag=flag|0x01;
    if((buf[4]==0xff&&buf[5]==0xff&&buf[6]==0xff&&buf[7]==0xff))
       flag=flag|0x02;
    if((buf[8]==0xff&&buf[9]==0xff&&buf[10]==0xff&&buf[11]==0xff))
       flag=flag|0x04;
    return flag;
} 
一次读三个字节,并将值赋给输入参数

对于函数:

Parameter_Flag Parameter_Read_Flag;

bool Parameter_Init(void)
{
    bool success=true; 
   /************加速度计零偏与标度值*******/
    Parameter_Read_Flag.accel_off=ReadFlashThreeFloat(Accel_Offset_Address,
                         &Accel_Offset_Read.x,
                         &Accel_Offset_Read.y,
                         &Accel_Offset_Read.z);
     
    Parameter_Read_Flag.accel_scale=ReadFlashThreeFloat(Accel_Scale_Address,
                         &Accel_Scale_Read.x,
                         &Accel_Scale_Read.y,
                         &Accel_Scale_Read.z);
    /************磁力计零偏****************/
    Parameter_Read_Flag.mag=ReadFlashThreeFloat(Mag_Offset_Address,
                         &Mag_Offset_Read.x,
                         &Mag_Offset_Read.y,
                         &Mag_Offset_Read.z);
    // sanity check scale
    if(ABS(Accel_Scale_Read.x-1.0f)>0.2f 
         || ABS(Accel_Scale_Read.y-1.0f)>0.2f 
           || ABS(Accel_Scale_Read.z-1.0f)>0.2f) 
    {
        success = false;
    }
    // sanity check offsets (3.5 is roughly 3/10th of a G, 5.0 is roughly half a G)
    if(ABS(Accel_Offset_Read.x) > 3.5f 
         || ABS(Accel_Offset_Read.y) > 3.5f 
           || ABS(Accel_Offset_Read.z) > 3.5f) 
    {
        success = false;
    }
    
   
   if(success==true
      &&Parameter_Read_Flag.accel_off!=0x07
       &&Parameter_Read_Flag.accel_scale!=0x07)//Flash内数据正常,更新加速度校正值
   {
    B[0]=Accel_Offset_Read.x*One_G_TO_Accel;
    B[1]=Accel_Offset_Read.y*One_G_TO_Accel;
    B[2]=Accel_Offset_Read.z*One_G_TO_Accel;
    K[0]=Accel_Scale_Read.x;
    K[1]=Accel_Scale_Read.y;
    K[2]=Accel_Scale_Read.z;            
   }
   /**********磁力计中心偏执获取************/
   if(Parameter_Read_Flag.mag!=0x07)
   {
   Mag_Offset[0]=(int16_t)(Mag_Offset_Read.x);
   Mag_Offset[1]=(int16_t)(Mag_Offset_Read.y);
   Mag_Offset[2]=(int16_t)(Mag_Offset_Read.z); 
   }
   return success;
}
它首先定义了一个结构体,

Parameter_Flag Parameter_Read_Flag;
结构体内部:

typedef struct 
{
uint8_t accel_off;
uint8_t accel_scale;
uint8_t mag;
}Parameter_Flag;
首先应有三个结构体定义:

Mag_Unit Mag_Offset_Read={
  0,0,0,
};
Acce_Unit Accel_Offset_Read={
  0,0,0,
};
Acce_Unit Accel_Scale_Read={
  0,0,0,
};

其中:typedef struct
{
 float x;
 float y;
 float z;
}Acce_Unit;类外一个类似

整个函数的过程就是将读取的数据赋给Mag_Offset_Read,Accel_Scale_Read,Accel_Offset_Read结构体里面,并返回是否读取到数据的标志

得到的数组B[3],K[3],Mag_Offset[3],





开源飞控:支持气压计、超声波定高、户外GPS定点、定速巡航,部分视频链接如下: 无名飞控暴力测试 无名飞控江边定点(长时间) 无名飞控定高作死测试 无名飞控加速度计6面校准与融合简单讲解 无名飞控源码整体框架介绍初步 无名飞控解(上)锁与遥控器简单设置 无名科创自研飞控平台,经过武汉科技大学连续四届研究生师兄们参考国内外主流飞控(APM、Pixhawk、Autoquad、MWC、CC3D、无穷开、ANO、Light等)的算法与整体框架的进行深入学习基础上,经过软、硬件的精心设计,继承与发展,目前飞控整体功能相对完善,主要功能有:姿态自稳、超声波、气压计定高,户外GPS定点,GPS模式下定速巡航等功能,涵盖飞控学习主要核心算法: 1、四旋翼的传感器滤波(针对传感器不同使用情况:姿态解算、惯导、控制、传感器矫正等)分别采用窗口滑动滤波、不同截止频率的巴特沃斯数字低通滤波器);2、姿态解算(互补滤波、梯度下降法等);3、惯性导航(经典回路反馈法即APM三阶段互补滤波,单观测器的卡尔曼滤波,双观测量的卡尔曼滤波,观测传感器延时修正处理等); 4、控制算法(经典PID控制、前馈控制、自抗扰控制ADRC)等。 无名科创团队的发展: 多旋翼飞行器飞行控制系统(简称飞控)是我们团队历届主研项目,团队13年即开始第一代飞控的研究,从最开始的小四轴,到后来的多旋翼飞控,经历N个版本改进,经历无数次断桨、射桨、炸机,一步一步完善与改进,整合除了目前我们这款对外开源的飞控。团队历来贡献者均就职于无人机公司做算法相关工作。目前我们的飞控更加完善,更加稳定,更加适合学习,主要核心代码自写率达到百分之90以上,代码基本上是逐行注释,整个飞控框架清晰明了,模块化封装规范,方便大家学习与二次开发。由于作者目前仍然在校,主研项目仍为飞控,个人时间比较多,可和大家一同交流学习。我们的服务宗旨是:打造国内功能最多、性能最好、成本最低、可玩性最强的开源飞控学习平台。帮助大家以最小的代价、最大的获得感、最快的速度学习飞控相关算法,顺利完成进阶逆袭!!! 团队主要成员优快云开源技术博客汇总 ,充分展现我们开源共享、共同进步的创客精神,不废话了,直接上图: 部分技术博客截图: 无名科创开源飞控:独家首创10轴IMU组合:MPU6050(加速度计、陀螺仪)+IST8310(DJI同款磁力计)+SPL06-001(歌尔高精度气压计、媲美MS5611),MCU:STM32F103RCT6,这是一款强大的飞控,主频72Mhz,flash 256K,板载10 Axis传感器,3轴陀螺,3轴加速度,3轴磁罗盘,高精度气压计。适合新手学习无刷飞控,更适合玩家做多种拓展和二次开发,飞控预留多个串口,可外接各种附加设备,已实现超声波定高、气压计定高、GPS定点等功能,代码完全开源。 无名科创开源飞控学习平台: 1、飞控板与IMU分离式设计 2、采用3D打印的IMU气压防护罩 3、软件调试支持主流IAR、Keil两款编译器 4、支持多家上位机与地面站,方便调试
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值