提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
C语言(代码什么都都可以干)
写代码之前要考虑事件怎么操作
C语言要提前定义变量
{1.#include 2.mian() 3.变量 (int float char)
4判断(if switch) 5.循环(while for) 6.数组
7.函数 8.指针 9.结构体}
这就是C语言!
1.库函数,头文件(相当于程序的解)
2.main(看程序一定要从main函数开始看)
3.int pi =3.14 (pi是变量)(const) #define pi 3.14(pi是常量)
有符号(unsigned)和无符号(signed)
7.函数:传入参数 返回值
全局变量:括号外定义变量,没有赋初值,打印出来是0
局部变量:括号内定义变量,没有赋初值,打印出来是随机数
运行后会被释放
8.指针:C语言的灵魂
9.结构体:使用结构体,数据类型最为合理,节省内存,防止浪费。
结构体:“偷懒+变量”
关键字:
1.static
全局变量:对于全局变量也是存储在静态区,但是它的作用域仅为本文件。
局部变量:再次调用函数的时候,这个静态变量仍然保持上次时候的值。
静态函:只在当前文件下调用此函数,防止被其他的.c文件调用。
2.extern
extern关键字可以用来声明变量、函数作为外部变量或者函数供其它文件使用。
3.struct和union
struct和union都是由多个不同的数据类型成员组成, 但在任何同一时刻, union中只存放了一个被选中的成员, 而struct的所有成员都存在。在struct中,各成员都占有自己的内存空间,它们是同时存在的。一个struct变量的总长度等于所有成员长度之和。在Union中,所有成员不能同时占用它的内存空间,它们不能同时存在。Union变量的长度等于最长的成员的长度。
STM32被广泛应用在控制领域,本此选用STM32F407进行电机实验,此单片机是基于arm-cortem4为核心。
功能:执行 感知 计算 计时(定时器:外部晶振,按照一定周期震动,可以条件占空比)
控制器:
MCU(GPIO 定时器 PWM UARRT CAN) 板载外设(LED 通讯电路 驱动电路)
执行:I/O口 供电(母头)防止触碰引起火花
STM32功能很复杂,模式很多,所以引入寄存器。
STM32—电调(调速板)—电机
PID:P比例,I积分(求面积),D微分(求导)
纯P控制(无法消除误差) PI控制(求面积消除误差)
实际值和目标值,实际值需要用编码器来反馈。
输入捕获(I/O口的输入,定时器)
通信 数据传输(协议,数据,接受,发送)
遥控器—(无线)—接收机—串口(TX发送 RX接受)—单片机
协议可以通俗的理解为一个高低电平所经过的时间,比如规定经过2S为触发开关,经过3S为关闭开关。
串口 CAN IIC SPI
CAN((两根线 CAN_H CAN_L):稳定,挂在总线上的设备都有标识的ID。
CAN总线优势:
1.信号是差分信号,同一个信号通过两根线做差的方式作为最后的信号,干扰下相互抵消,抗干扰能力强。
2.总线形式,可以把所有的设备挂在总线上,设备的ID号不同可以挂无数个设备
作用给所有的电机发送命令,接受电机编码器所测量的数据
总结:
CAN总线发送数据,两个标识符(0x200,0x1FF),各自控制4个电机,
如0x200给四个电机发数据,用过数据域DATA【0】和DATA【1】这两个字节共同作用与一个电机,DATA【0】为一个字节高8为,DATA【1】为一个字节低8位
CAN总线接受数据,标识符0x20+电调ID(如ID为1,该标识符为0x201),反馈必须带上自己的ID号
CAN总线为什么用一个标识符就可以同时给4个电机发送指令,而调速板只能用一个对应ID的标识符反馈一个电机的参数呢?
这是因为发送的时候只用到2个字节对应一个电机,接受的时候用8个字节对应一个电机,接受的时候会接受多个参数,比如:角度,速度,转矩,温度等等,这都会占用相应的字节
陀螺仪通过IIC总线连接一块开发板,开发板通过CAN总线挂在主控板上,降低了主控板CPU的占用率。
DMA:通俗的讲,DMA的作用其实就相当于CPU的搬家公司,CPU只发送搬家命令给DMA,DMA计算发送数据,大大减少了CPU的任务负担。
步兵机器人
1.LED 提示(程序是否可以运行,主控板是否好坏)
2.按键 (模式切换,作为输入口,传感器信号的接受)
3.地盘(电机要和负载连接紧凑,调一块的时候关闭其他模块)
陀螺仪(角度传感器,角速度传感器,加速度传感器)
主要是完成不同开发板的适配工作
寄存器编程缺点 HAL缺点:
1.代码可读性太差 1.代码效率不是很高
2.二次开发难度大
3.每次写程序都要查阅手册
用户层
CMSIS层(提供除外设以的各种接口,hal库固件包在此层)
MCU层
固件包的文件夹
Documentation说明文档,如何使用固件包
Drives文(BSP CMSIS HAL_Drives
Middlewares中间件
Projects工程实例
Utilities通用文件
使用HAL库的两种方式
1.自己移植
2.CubeMX
板级支持包:对板上的资源功能给出实现,并且提供给用户程序的接口。以LED灯为例,用户应用程序不需要知道GPIO硬件的特点,只需要知道这个函数,就可以点亮LED灯了!
预定义
#ifndef _BSP_LED_H_
#define _BSP_LED_H_
#endif
预定义包含在.h文件中
作用:举个例子.h文件中引用了下面这个头文件,main函数中不仅引用了.h文件还引用了下面这个头文件,如果不使用预定义,系统就会报错。
#include "stm32f4xx.h"
RCC外设
系统时钟配置:时钟的原理是晶振震动的次数,即频率,而频率的倒数就是周期,这样就可以规定外设运行的时间。
复位:系统复位,电源复位,备份域复位
时钟:工作频率越高,功耗越高
HSI高速内部时钟 HSE高速外部时钟 PLL倍频时钟
Cube MX 配置时钟树
定时器
高级定时器—通用定时器—基本定时器
基本定时器(TM6 TM7):16位向上递增的(0到65535) 挂在APB1上
高级定时器:输入捕获 输出比较 PWM生成
SysTick定时器
属于Cortex-M内核中的一个外设。
计数宽度(24bit来存数据) 计数模式(向下递减) 计数周期(1/工作频率)
HAL_Delay()
SysTick定时器,可以调用一个中断服务函数
中断中不建议使用SysTick,因为中断优先级没有很好配置的话,就无法跳出死循环
PWM
高电平和低电平的比值,即占空比,调节占空比即调节电压的大小,进而调节电机的转速。
I/O口的输入捕获:就是为了读取PWM的频率,即占空比
中断
与按键的作用机理相似,区别在于按键的I/O口一直在监测电平的变换状态,中断只要写好中断程序等待触发即可,不用一直监视,减少了CPU资源占用。但是一般写按键,中断多了容易乱套。
其实所有能写成中断的都可以不写成中断
中断优先级:比如你在写作业的时候,电话响了同时有人敲门,你是先接电话还是先看门,这里就用到了中断优先级,分为可编程和不可编程。
复位:-3(最高)
中断优先级按照优先级分组(抢占优先级>子优先级>IRQ编号)
嵌套向量中断控制器(NVIC)
EXTI外设(扩展中断事件控制器):1.捕获外部输入事件 2.生成中断请求
事件->中断
通过EXTI线,捕获EXTI事件,并且去生成中断,再中断中,反转LDE的状态,并且清除EXTI中断标志
通信
I2C总线(两条总线线路,串行数据线(SDA)串行时钟线(SCL))
硬件IIC:可以设计一个芯片直接通信
软件IIC:可以控制IO口的高低规定信号协议
起始信号(SCL为高电平时,SDA有高电平向低电平跳变,开始传送数据)
停止信号(SCL为高电平时,SDA由低电平向到点评跳变,结束传送数据)
操作系统
Freertos
初写点亮程序
写程序第一步是初始化,你想点亮LED你就要把I/O口初始化,你想实现串口通信你就需要把串口初始化。
F12按键,转到定义处。
仿真器不仅可以下载程序还可以进行仿真
仿真:进入仿真加断点,如果发现某段程序中无法加断点,说明程序没有运行到这段程序中,
移植程序前,一定要把所要移植的程序看懂,带着目的去看。
上来一定看的是main函数
程序不是敲出来的,而是拼出来的
对与一些理论的东西,比如各种算法,PID,卡尔曼滤波,一上来不用先搞明白原理这些东西,先用起来,学会忽略一些东西。不能用通俗易懂的话描述出来的,说明你没有懂。
程序没用报错并不代表完全正确,只是说可能没有用到
机器人控制篇
比的不是会控制更多的传感器,写更多的程序,而是算法的逻辑
小数后面一定要加个f,否则会报错
遥控器
写程序调试不允通过串口调试助手来看,因为会占用一个串口,必须通过仿真看
串口:波特率,单元数据长度等+数据帧(相当于语言,这个语言很规范,精确到标点符号),tx连rt,这就是串口的全部内容
串口的数据形式:高低电平的形式
建议看看野火的DMA视频,讲的很详细。
1.IO口配置成AF(复用)功能
2.配置串口结构体(CAN总线里面有3个参数是设置时钟的,把3个数进行计算得到一个波特率)
1.程序逻辑的整体把握,多写多练
2.程序规范性很重要,变量用结构体,对C语言理解透彻了就会发现有很多程序不用那么繁琐
3.算法,编程到最后一定是数学。。。
4.只要传感器给我一个例程,就能把它编程自己的程序
英雄机器人
1.LED灯闪烁任务
2.检测任务(看门狗 STM32F407上的LED灯)
3.校准任务(得到3个参数引进消除误差,放到flash中)
4.底盘任务
(初始化各种外设,if或CAN总线,PID)
<1> 延时,给硬件初始化留时间
<2> 底盘初始化(可以通过指针得到遥控器值的地址,将这一类型结构体的地址引过来)
<3> while(1)
{
SET_MODE(模式)
模式变换(过度)
遥控器的值和鼠标键盘(斜坡函数)引进来
PID(速度计算) 目标值 实际值
CAN(函数)发给电机
}
模式 无力模式(调试) 正常遥控 小陀螺 子模式:在正常模式下插入子程序实现其他功能
5.云台任务
6.发射任务
7.MPU任务
反馈的值只要是连续的,就往PID方面想
读程序:
1.先去看程序的结构,所要实现的功能
从主函数开始main.c—底盘任务.c—底盘任务.h(结构体都摘出来)—初始化看变量找对应的函数赋初值—看死循环里面的函数—代码全部去掉—移植代码(结构体每用到一个成员填进去,每写一个函数进行仿真)
2.生成程序脑图
3.找和底盘有关的程序(底盘任务和底盘行为(模式))
不要排斥程序,太有乐趣了,对自己是一种升华
前台系统 后台系统
RTOS实时系统(实时内核)
硬实时:不允许超时
软实时:允许超时
多任务管理:模块化开发