智能车基础知识

一些报错

  • Warning[Pe223]: function “Speed_Control” declared implicitly

    出现原因1
    该函数没有在本文件包含的头文件中定义,而只在其他c文件的头文件中有定义,也就是间接地有定义。这样是不规范的。

    解决办法1
    把出现问题的函数所在头文件包含进来。且如果包含进来还未解决,可能是头文件包含的先后顺序有关。

    出现原因2
    头文件和C文件中的函数声明不完全相同,可能出现函数名有细微差别,比如字母大小写不一致等情况。

    解决办法2
    回去仔细看一下出现问题的函数是否在声明和调用时使用了完全一致的函数名称和变量

  • Error[Pe028]: expression must have a constant value

    报错内容:float Output=angle_duty;

    报错原因:Output和angle_duty都是变量不能在定义时赋值,可以先定义在函数中赋值。

    1
    2
    3
    4
    5
    6
    意思是.表达式必须是常量

    推论---------------
    1.数组在声明时初始化必须是常量!
    2.unsigned char const Tab[]。Tab是变量
    3.const unsigned char const Tab[]。Tab也是是变量!尽管程序整个过程它都不能被改变.
  • Error[Pe028]: expression must have a constant value

常见原件

电阻和电容

贴片电容(不分+,-),钽电容(分+,-)

固态电解电容(用于主板)

img

电阻、电容的标号

电容:1μF = 1,000nF = 1,000,000pF

【103】,即10 x 10^3皮法 = 10纳法;

计算方法:前两位数字代表有效数字,第三位代表10的n次幂(也可以理解为在有效数字后面有几个0),单位是皮法。

前3位数字是容量代码,字母是额定电压代码(耐压值)

字母C表示额定电压为16V(C型耐压16V),字母A表示额定电压为10V(A型耐压10V)

107C是 100UF 16V,107A是100UF 10F

电阻:1MΩ=1,000KΩ=1,000,000Ω

  1. 数字索位标称法(一般矩形片状电阻采用这种标称法)

数字索位标称法就是在电阻体上用三位数字来标明其阻值。它的第一位和第二位为有效数字,第三位表示在有效数字后面所加“0”的个数。这一位不会出现字母。

例如:【472】表示“4700Ω”;【151】表示“150Ω”。 如果是小数。则用“R”表示“小数点”。并占用一位有效数字,其余两位是有效数字。例如:【2R4】表示“2.4Ω”;【R15】表示“0.15Ω”。

  1. 色环标称法(一般圆柱形固定电阻采用这种标称法)
      色环电阻大多采用三环、四环(有时五环、六环)标明其阻值,原理都一样。

    在这里插入图片描述

颜色表示:
从左到右,前三列为有效数字,第四列为倍数,第五列为误差,第六列为温度系数。

例如:【蓝灰橙银】表示“68kΩ”,误差±10%

二极管LED

有正有负,有线的一边为负极

蜂鸣器

调车使用,有问题可以响

排母、排针

焊接工具

焊箱

松香

焊芯片,自动分开防止短路

细丝

吸锡器

排针孔堵了

IAR安装和使用

Ctrl+Shift+F 快捷键唤出查找功能->查找之后再go to defination

Ctrl+T 格式化

C语言基础知识

内存和地址

内存是以字节为单位的存储空间

有底到顶:机械码、代码->静态变量->全局变量->堆区(指针)->栈区(main函数中的)

数据类型

1
2
3
4
5
6
7
typedef	char			int8; // 8 bits
typedef short int int16; // 16bits
typedef long int int32; //32 bits
typedef unsigned char uint8; //8 bits
typedef unsigned short int uint8;// 16 bits
typedef unsigned long int uint8;// 32 bits
typedef unsigned long long uint8;// 64 bits

外部变量和外部函数

文件之间调用

关键字extern:

当extern不与“C”在一起修饰变量和函数时,如在头文件中:extern int g_Int : 它的作用就是声明函数或全局变量的作用范围的关键字,其声明的函数和变量可以在本模块或者其他模块中使用。!!!它是一个声明不是一个定义。

栗子:B模块(编译单元)要是引用模块(编译单元)A中定义的全局变量或函数时,它只要包含A模块的头文件即可,在编译阶段,模块B虽然找不到该函数或变量,但它不会报错,它会在连接时从模块A生成的目标代码中找到此函数。

1
2
3
4
5
6
7
8
//include.cpp
#include"include.h"
int a=10;
int b=5;
int sum(int a,int b)
{
return a+b;
}
1
2
3
4
5
6
7
8
9
//include.h
#ifndef _INCLUDE_H_ //防止嵌套,造成资源浪费
#define _INCLUDE_H_

extern int a;
extern int b;
int sum(int a,int b);

#endif
1
2
3
4
5
6
//主函数异步编译多个不同代码,使用关键词
#if 0
#elif 1
#elif 0
#endif
//想编译的写1,不想编译的写0
1
2
3
4
5
6
7
8
9
//main.cpp
#include<iostream>
#include"include.h"
using namespace std;
int main()
{
cout<<a<<"+"<<b<<"="<<sum(a,b)<<endl;
return 0;
}

中断原理及应用

中断服务程序

中断服务程序,处理器处理“急件”,可理解为是一种服务,是通过执行事先编好的某个特定的程序来完成的,这种处理“急件”的程序被称为——中断服务程序。

与每类I/O设备相关的进程都有一个靠近内存底部的地址,称作中断向量它包括中断服务程序的入口地址
当中央处理器正在处理内部数据时,外界发生了紧急情况,要求CPU暂停当前的工作转去处理这个紧急事件。处理完毕后,再回到原来被中断的地址,继续原来的工作,这样的过程称为中断。实现这一功能的部件称为中断系统申请CPU中断的请求源称为中断源,单片机的中断系统一般允许多个中断源,当多个中断源同时向CPU请求中断时,就存在一个中断优先权的问题。通常根据中断源的优先级别,优先处理最紧急事件的中断请求源,即最先响应级别最高的中断请求。

1、中断标识码(中断类型号):由硬件(通常是中断控制器)产生,以标识不同的中断源。

2、中断向量:早期的微机系统中将由硬件产生的中断标识码(中断源的识别标志,可用来形成相应的中断服务程序的入口地址或存放中断服务程序的首地址)称为中断向量在某些计算机中,中断向量的位置存放一条跳转到中断服务程序入口地址的跳转指令

3、中断向量地址:存储中断向量的存储单元地址。

4、中断:在计算机执行程序的过程中,当出现异常情况或者特殊请求时,计算机停止现行的程序的运行,转而对这些异常处理或者特殊请求的处理,处理结束后再返回到现行程序的中断处,继续执行原程序。

存放:存放中断服务程序的入口地址,来存放中断向量(共256个),称这一片内存区为中断向量表。

**跳转:**跳转到中断服务程序的入口地址,在AVR或ARM微处理器中,中断向量的大小也是4个字节,但其中存放的不是中断程服务程序的入口地址,而是可执行的代码。当响应中断时,硬件自动执行相应中断向量处的跳转代码,然后跳转到具体的中断服务程序的入口地址。

综上所述:中断向量的地址一定是 中断服务程序的入口地址的地址,但中断向量不一定就是中断服务程序的入口地址。

单片机中重要中断

PID定时中断:

对于时间进行精准的控制,定时进入中断服务程序完成某个任务

1
2
3
4
5
6
7
8
9
main()
{
1.关总中断
2.中断初始化(中断开启):
PID中断初始化(4个PID定时器用哪个:一般只使用一个,定时的时间:10ms进入一次)
3.开启中断
4.使能(使其能工作)
5.
}

串口接收中断:

由单片机通过蓝牙串口接收到信息时,做出对应的反应(调车使用)

中断一多就有中断优先级问题……

https://www.bilibili.com/video/BV1fJ411K7bk?spm_id_from=333.999.0.0

怎样烧录程序

硬件准备:1.主板 2.核心板 3.下载器

软件准备:IAR

img

不要插反

img img img

GPIO通用输入输出接口

概念:通用型之输入输出的简称,其接脚可以供使用者由程控自由使用,PIN脚依现实考量可作为通用输入GPI或通用输出GPO或通用输入输出GPIO。对于输入,一定可以通过读取某个寄存器来确定引脚电位的高低;对于输出,一定可以通过写入某个寄存器来让这个引脚输出高电位或者低电位;对于其他特殊功能,则有另外的寄存器来控制它

输入模式:通过读取某个寄存器来确定引脚电位的高低
输出模式:写入某个寄存器来让这个引脚输出高电位或低电位

通用串行异步数据总线:
异步通信:通信中两个字符(8位)之间的时间间隔是不固定的,而在一个字符内各位的时间间隔是固定的。
波特率:每秒钟传送的二进制位

PC–>USB原则
单片机–>TTL原则(USB转TTL模块转Kea板)

img

主要:引脚(即排针)

1
2
3
4
GPIO初始化	gpio_init(port,dir,state)
port/ptxn端口号,dir引脚方向(0=输入,1=输出),state引脚初始状态(0=低电平,1=高电平)
设置引脚状态 gpio_set(ptxn,state)
获取引脚状态 gpio_get(ptxn)

UART串口(输入输出信息)

概念:串行接口(Serial Interface)是指数据一位一位地顺序传送

​ 有线串口:usb转ttl的模块;

​ 蓝牙串口更适用于调试;

img

硬件:1.USB to TTL模块 2.KEA板 3.下载器

!!注意:硬件连接时,下载器拔掉3.3V跳线帽

img
1
2
3
4
5
UART初始化 uart_init(uartn,band_rate)
UARTn通道(实际是两个引脚),band_rate波特率(数据传输的速度:9600 11400……)
UART串口打印 uartPrintf(UARTn uartn,char *pcFmt....)
虚拟示波器 uart_sendware(UARTn uartn,void *wareaddr,uint32 waresize)
串口接收中断 uart_rx_irq_en

AD采集(电磁组)

概念:模拟信号(Analog signal) -> 数字信号(Digital signal)

1
2
3
4
5
6
7
初始化 ADC_Init(ch,bit)
ch采集通道,bit采集位数
单次采集 adc_once(adcn_ch)
adcn_ch ADC通道
均值滤波 adc_ave(adcn_ch,N)
adcn_ch ADC通道,N均值滤波次数(范围:0~255)
其他滤波算法:中位值平均滤波算法、卡尔曼滤波算法……

PIT定时中断

软件上执行时间一致,但在硬件上(电容、电阻跑久了温度会升高,时间发生变化会导致周期变化)时间不一致

概念:定时器实际上是计数器,它通过累计已知时间间隔的个数来计算时间。被累积的时间间隔若是系统时钟,计数器就变成了定时器。(周期性地做某一件事……)

1
2
3
4
初始化 PIT_Init(uSChannel_No,freq)
uSChannel_No PIT通道端口号01,freq定时器频率
中断服务函数 PIT0_ISR(uSChannel_No)
中断使能 pit_irq_en(uSChannel_No)

关于中断

内核 约等于 操作系统

单片机上的程序,始终获得CPU的控制权

用户程序并发处理的时候,是轮番处理的且交换很快

所以单片机要明确知道IO什么时候做这些输入输出和这些中断,要自己亲自过问

摄像头的获取,摄像头输入:首先摄像头分传感器和集成本地缓存,传感器会把光的信号转换为数字信号,数值放在缓存里。若是写成请求一次程序,完全收集好一次数据交给CPU处理会非常难慢。先初始摄像头给摄像头配置寄存器写好时然后告诉摄像头以什么频率和分辨率、彩色还是干风暴的画面,按行采集完一次告诉CPU一次,使用的是外部中断,CPU给传感器一个地址,就是DMA传送方式(DMA直接内存访问:在传的过程中不需要CPU一条一条把缓存里的东西取到内存里,而是传感器的缓存是直接向内存传数据,CPU只要直接告诉缓存往哪存数据缓存往哪存数据)

FTM多功能定时器

PWM波驱使电机转动和舵机打角

编码器测速(轮胎转的速度)

img

占空比(高电平的时间占总时间的比例)

img

FTM模块的核心是一个16位计数器。
主要功能:PWM输出、输入捕捉、正交解码

PWM输出:

PWM的周期=(MOD-CNTIN)

1
2
3
4
5
6
FTM模块初始化 FTM_PWM_init(ftm,ch,freq,duty)
ftm PWM模块,ch通道,freq频率,duty占空比(0-1000 可以调节FTM_PRECISON这个系数)
设置占空比 FTM_PWM_Duty
计数模块初始化 ftm_count_init
获取计数值 ftm_count_get
清空计数值 ftm_count_clean

img

初始化以及其他一些功能函数写在.c文件,服务函数统一写在Isr.c

!注意:串口打印和虚拟示波器不能同时使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#if 1
//GPIO
void main()
{
DisableInterrupts;
gpio_init(GPI0,1,0);
gpio_init(GPI1,0,0);
if(gpio_get(PIG1)==0)gpio_set(GPI1,1);
EnableInterrupts;
}
#elif 0
//串口
void main()
{
DisableInterrupts;
uart_init(UARTR0,9600);
int pulse[2];
pulse[0]=0;
pulse[1]=100;
uartPrintf(UARTR0,"ok\n");
EnableInterrupts;
while(1)
{
//串口打印时需注释掉虚拟示波器
//uart_sendware(UARTR0,&pulse,sizeof(pulse));
}
}
#elif 0
//串口接收中断
void main()
{
DisableInterrupts;
uart_init(UARTR0,9600);
gpio_init(PIG0,1,0);
gpio_init(PIG1,1,0);
gpio_init(PIG2,1,0);
gpio_init(PIG3,1,0);
uart_rx_irq_en(UARTR0);//rx接收,tx发放->isr.c
EnableInterrupts;
}
#elif 0
//AD采集
void main()
{
DisableInterrupts;
uart_init(UARTR0,9600);
int val;
ADC_Init(ADC_CHANNEL_AD6,ADC_12BIT);
EnableInterrupts;
while(1)
{
val=adc_once(ADC_CHANNEL_AD6);
//val=adc_ave(ADC_CHANNEL_AD6);//均值滤波
uart_sendware(UARTR0,&val,sizeof(val));
}
}
#elif 0
//PIT定时中断
void main()
{
DisableInterrupts;
PIT_Init(PIT_CHANNEL0,1);
uart_init(UARTR0,9600);
PIT_IRQ_EN(PIT_CHANNEL0);
EnableInterrupts;
}
#elif 0
//FTM
void main()
{
DisableInterrupts;
PIT_Init(PIT_CHANNEL0,1);
uart_init(UARTR0,9600);
FTM_PWM_init(CFTM0,FTM_CH1,50,10);
ftm_count_init(CFTM1);
PIT_IRQ_EN(PIT_CNANNEL0);
EnableInterrupts;
}
#endif

#if 0
//FTM
void PIT0_ISR(void)
{
//清除中断标志位
PIT->CHANNEL[0].TFLG = PIT_TFLG_TIF_MASK;
uartPrintf(UARTR0,"%d\n",ftm_count_get(CFTM1));
ftm_count_clean(CFTM1);
}
#elif 1
//PIT定时中断
void PIT0_isr(void)
{
//清除中断标志位
PIT->CHANNEL[0].TFLG = PIT_TFLG_TIF_MASK;
uartPrintf(UARTR0,"%d\n",1);
}