匿名飞控源码解析(一) 您所在的位置:网站首页 匿名代码剧情解析 匿名飞控源码解析(一)

匿名飞控源码解析(一)

2024-07-17 12:30| 来源: 网络整理| 查看: 265

匿名飞控源码解析(一)—主程序

对于这个飞控的研究始于我本科时期的毕业设计,代码上的注释几乎都是由我当时书写,最近准备北航的研究生复试听闻老师们最爱问关于毕业设计的问题,故旧事重提,重新研究一下匿名飞控。

回想当时的研究,要是要我提出一个匿名飞控的特点即和其他飞控的不同之处就是没有采用硬件中断来做时分复用,而是采用简单的延时程序来做的时分复用,这使得其代码难度降低,不过感觉也有利有弊,长时间不使用定时器中断搞我的现在都有点忘了,不过这些硬件的调用就等到之后研究全权老师的rfly或者我的另一个平衡自行车项目的时候再复健吧。

从主程序入手1234567891011121314151617181920212223#include "include.h"#include "Ano_FcData.h"#ifdef USE_FULL_ASSERTvoid assert_failed(uint8_t* file, uint32_t line){ while (1) { //当系统出错后,会进入这个死循环 }}#endif//=======================================================================================//=======================================================================================int main(void){ flag.start_ok = All_Init(); //进行所有设备的初始化,并将初始化结果保存 Scheduler_Setup(); //调度器初始化,系统为裸奔,这里人工做了一个时分调度器 while(1) { Scheduler_Run(); //运行任务调度器,所有系统功能,除了中断服务函数,都在任务调度器内完成 }} main.c主程序分析预处理指令部分

第一条代码#include "include.h"主程序包含include.h头文件,接下来分部分分析该文件.

1234#ifndef _INCLUDE_H_#define _INCLUDE_H_;#endif

条件编译的经典格式,防止重复包含头文件。

接下来是头文件的包含,包括硬件驱动程序头文件(一般文件名以DRV开头),各类数据处理控制算法等程序头文件(一般以Ano开头)

1234567891011//#include "stm32f4xx.h"#include "Ano_FcData.h"#include "Ano_Scheduler.h"#include "BSP_Init.h"#include "Ano_DT.h"#include "Ano_Parameter.h"#include "Ano_USB.h"#include "Drv_time.h"#include "Drv_pwm_in.h"#include "Drv_usart.h"#include "Drv_Gps.h"

其中Ano_FcData.h为飞控数据处理的头文件,Ano_Scheduler.h为时分复用系统的头文件,’BSP_Init.h’为飞控初始化程序头文件,’Ano_DT.h’为飞控数据传输程序头文件,Ano_Parameter.h为控制参数配置头文件,Ano_USB.h为USB通信相关头文件。

Drv_time.h为时钟驱动头文件Drv_pwm_in.h为硬件PWM驱动头文件Drv_usart.h为USART通信驱动头文件Drv_Gps.h为GPS驱动头文件。

以上仅仅是让自己脑子有个大致的印象,以后深入到源码中还会细品各程序。不过在此我还想提醒一下自己包含这么多头文件有什么作用,引用一下上的目录:

共享宏定义和类型定义 共享函数原型 共享变量声明

接下来是第二条代码#include "Ano_FcData.h"在主程序中包含Ano_FcData.h但是讲道理这个在上一条中已经包含过虽然有条件编译并不会有什么问题,但是其实我认为是多此一举的。由于现在是在分析主程序就并不在本篇中对其他文件的细节进行解读了。

条件编译部分123456789#ifdef USE_FULL_ASSERTvoid assert_failed(uint8_t* file, uint32_t line){ while (1) { //当系统出错后,会进入这个死循环 }}#endif

由于这部分内容后面不会再涉及并且并不困难故在此处说一下,转到定义处代码

12345678910111213141516171819#define USE_FULL_ASSERT 1/* Exported macro ------------------------------------------------------------*/#ifdef USE_FULL_ASSERT/** * @brief The assert_param macro is used for function's parameters check. * @param expr: If expr is false, it calls assert_failed function * which reports the name of the source file and the source * line number of the call that failed. * If expr is true, it returns no value. * @retval None */ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))/* Exported functions ------------------------------------------------------- */ void assert_failed(uint8_t* file, uint32_t line);#else #define assert_param(expr) ((void)0)#endif /* USE_FULL_ASSERT */

宏USE_FULL_ASSERT被定义为常数1,这意味着一旦USE_FULL_ASSERT被定义就会进入到条件编译中,条件编译内容为一个带参数的宏。此处引用一下上对于带参数的宏的介绍:

格式为: #define 标识符(y1,y2,…,yn) 替换列表(x1,x2,…,xn)

注意:

宏的名字和左括号之间必须没有空格,例如一定是yz_K(_yzk)指的是下划线之间部分无空格 宏的参数可以在替换列表中根据需要任意引用 一定注意要多使用括号不然傻瓜替换会治好你的低血压

assert_param()此处被封装为一个函数,函数名直译为参数判断,@brief:函数用于函数参数检查,@param:如果参数expr为0调用assert_failed(),这个函数会报道导致失败的文件名和行数;如果expr为1则返回空。并且还会在主函数中定义assert_failed()为死循环。

而若USE_FULL_ASSERT未被定义则#define assert_param(expr) ((void)0)即返回空值。

综上,条件编译部分的经典条件编译语句我认为可以去掉而毫无影响,主体部分定义了一个死循环使得当系统出错时进入死循环仅此而已。

主函数部分123456789int main(void){ flag.start_ok = All_Init(); //进行所有设备的初始化,并将初始化结果保存 Scheduler_Setup(); //调度器初始化,系统为裸奔,这里人工做了一个时分调度器 while(1) { Scheduler_Run(); //运行任务调度器,所有系统功能,除了中断服务函数,都在任务调度器内完成 }}

主函数中各函数作用都在当年程序注释中注明,以下复制粘贴一下:

flag.start_ok = All_Init();进行所有设备的初始化,并将初始化结果保存 Scheduler_Setup();进调度器初始化,系统为裸奔,这里人工做了一个时分调度器 Scheduler_Run();运行任务调度器,所有系统功能,除了中断服务函数,都在任务调度器内完成

OK!主程序就看到这儿了,下次和兄弟们一起看Ano_FcData.h和Ano_FcData.c中的数据处理是如何进行的!



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有