单片机学习之路一些常见的疑问也是我的个人学习总结

1,821 阅读21分钟

​本文已参与「新人创作礼」活动,一起开启掘金创作之路。  

STM32的八种输入输出模式?

输入模式

上拉输入:通过内部的上拉电阻将一个不确定的信号通过一个电阻拉到高电平。

下拉输入:把电压拉到GND。与上拉原理相似。

浮空输入:引脚内部什么都不接,处于浮空模式下,电平状态是不确定的。外部信号输入什么,IO口就是什么状态。

模拟输入:接收到的是连续的模拟信号,一般用于AD转换。

输出模式:

推挽输出:可以输出高低电平,连接数字器件。在stm32中推挽电路由两个MOS管组成:输出高电平时P-MOS管导通,引脚联通VDD(3.3v)。输出低电平时N-MOS导通,引脚联通GND。该方式既提高电路的负载能力,又提高开关速度。

开漏输出:无法直接输出高电平,要在外部连接上拉电阻才行,输出的电压由上拉电阻连接的电源决定。适合做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。开漏输出还有一个特性:线与。即很多开漏模式引脚连接在一起,只有当所有引脚都输出1时,才能够被上拉电阻拉到高电平。若有一个引脚为低电平,则所有引脚相当于接地。

复用推挽输出:简单来说就是给内部外设使用的推挽输出模式,

复用开漏输出:简单来说就是给内部外设使用的开漏输出模式

在STM32中,根据不同的使用场景,选用不同的IO模式:

GPIO_Mode_AIN: 模拟输入,一般用作模数转换

GPIO_Mode_IN_FLOATING: 浮空输入,常用在key识别上

GPIO_Mode_IPD: 下拉输入--- IO内部下拉电阻输入

GPIO_Mode_IPU:上拉输入--- IO内部上拉电阻输入

GPIO_Mode_Out_OD: 开漏输出---可以外接上拉电阻输出较高的电平,也能够通过读取IO的电平变化实现C51的IO双向功能。

GPIO_Mode_Out_PP: 推挽输出---IO输出0-接GND,IO输出1 -接VCC,读输入值是未知的。

GPIO_Mode_AF_OD:复用开漏输出---片内外设功能(TX1,MOSI,MISO.SCK.SS)。

GPIO_Mode_AF_PP: 复用推挽输出---片内外设功能(I2C的SCL,SDA)。

STM32启动文件(.s)主要实现什么功能?

1、初始化堆栈指针 SP;2、初始化程序计数器指针 PC;3、设置堆、栈的大小;4、设置异常向量表的入口地址;5、配置外部 SRAM作为数据存储器(这个由用户配置,一般的开发板可没有外部 SRAM);6、设置 C库的分支入口__main(最终用来调用 main函数);7、在 3.5版的启动文件还调用了在 system_stm32f10x.c文件中的SystemIni()函数配置系统时钟。

stm32有哪些定时器(stm32f103rct6)?

stm32有8个16位定时器分成3个组;

基本定时器(TIM6,TIM7)的主要功能:

只有最基本的定时功能,。基本定时器TIM6和TIM7各包含一个16位自动装载计数器,由各自的可编程预分频器驱动

通用定时器(TIM2~TIM5)的主要功能:

除了基本的定时器的功能外,还具有测量输入信号的脉冲长度( 输入捕获) 或者产生输出波形( 输出比较和PWM)

高级定时器(TIM1,TIM8)的主要功能:

高级定时器不但具有基本,通用定时器的所有的功能,还具有控制交直流电动机所有的功能,你比如它可以输出6路互补带死区的信号,刹车功能等等

STM32F1芯片有哪些程序下载方法?

一共三大类:通过JTAG ULINK SWD 等 这是一类 都是通过外部调试下载工具;ISP是一类不同型号有 USART USB 等;IAP  是一类,用户自己定义可通过USART/USB/SD/SPI/I2C…… 用你可能用的任何接口 写入程序。

STM32F103系列小容量、中等容量、大容量有什么区别?

​编辑

什么是CMSIS?

ARM® Cortex™ 微控制器软件接口标准 (CMSIS) 是 Cortex-M 处理器系列的与供应商无关的硬件抽象层。CMSIS 可实现与处理器和外设之间的一致且简单的软件接口,从而简化软件的重用,缩短微控制器开发人员新手的学习过程,并缩短新设备的上市时间。优势是速度块,免费、占用资源少、仿真方便、使用简单、组件丰富。

JTAG调试接口和SWD调试接口在硬件上有什么区别?

JTAG需要的接线:强制:TDI、TMS、TCLK、TDO;看实际情况添加:VCC、GND、TRST、RESET;即一般的系统设计会选择这样子的8线制;
SWD需要的接线:强制:SWDIO、SWCLK看实际情况添加:VCC、GND、RESET;

STM32F1芯片有哪三种启动模式?

  1. BOOT1=x BOOT0=0 从用户闪存启动,这是正常的工作模式。
    2、BOOT1=0 BOOT0=1 从系统存储器启动,这种模式启动的程序功能由厂家设置。ISP
    3、BOOT1=1 BOOT0=1 从内置SRAM启动,这种模式可以用于调试。

STM32和ARM二者之间是什么关系?

arm是架构内核,stm32是搭载arm架构内核的单片机

//(包含与被包含的关系)

STM32F1芯片是高电平复位还是低电平复位?请画出复位电路?

低电平复位

​编辑

什么是JTAG接口?

JTAG是一种国际标准测试协议(IEEE 1149.1兼容),主要用于芯片内部测试。现在多数的高级器件都支持JTAG协议,如DSP、FPGA器件等。标准的JTAG接口是4线:TMS、TCK、TDI、TDO,分别为模式选择、时钟、数据输入和数据输出线。

STM32芯片数据手册主要包含哪些内容?

包含各个功能模块的内部结构、所有可能的功能描述、各种工作模式的使用和寄存器配置等详细信息。技术参考手册不包含有关产品技术特征的说明,这些内容在数据手册中。数据手册中的内容包括:产品的基本配置(如内置Flash和RAM的容量、外设模块的种类和数量等),管脚的数量和分配,电气特性,封装信息,和定购代码等。简单说就是:芯片引脚数量及定义、电气特性、封装规格

STM32寄存器操作和库函数操作区别?

操作寄存器,你必须明白每个数据位的物理意义,直观而且明确;库函数总是隔着一层毛玻璃看窗外。结合学习。寄存器让你理解原理,做到心中有数。库函数用来开发,当然前提是你理解先。没有理解你不可能会用库函数,个人觉得库函数够用了,现在单片机有那么多,就算寄存器全弄明白了,换个CPU你还得重新学。隔一段时间忘了还是得重新查表。从原理来说学习寄存器是最好的,开发实战库函数比较好。

单片机上电后没有运转,首先要检查什么?

首先应该确认电源电压是否正常。用电压表测量接地引脚跟电源引脚之间的电压,看是否是电源电压,例如常用的5V。接下来就是检查复位引脚电压是否正常。分别测量按下复位按钮和放开复位按钮的电压值,看是否正确。然后再检查晶振是否起振了,一般用示波器来看晶振引脚的波形,注意应该使用示波器探头的“X10”档。另一个办法是测量复位状态下的IO口电平,按住复位键不放,然后测量IO口(没接外部上拉的P0口除外)的电压,看是否是高电平,如果不是高电平,则多半是因为晶振没有起振。另外还要注意的地方是,如果使用片内ROM,一定要将EA引脚拉高,否则会出现程序乱跑的情况。有时用仿真器可以,而烧入片子不行,往往是因为EA引脚没拉高的缘故(当然,晶振没起振也是原因只一)。经过上面几点的检查,一般即可排除故障了。如果系统不稳定的话,有时是因为电源滤波不好导致的。在单片机的电源引脚跟地引脚之间接上一个0.1uF的电容会有所改善。如果电源没有滤波电容的话,则需要再接一个更大滤波电容,例如220uF的。遇到系统不稳定时,就可以并上电容试试(越靠近芯片越好)。

单片机总线有哪些?

数据总线、控制总线、地址总线。P0口为I/O口,即可以是数据线,也可以是地址线,倘若都要使用时,要用锁存器将二者分开,做地址线时,充当地址线的低8位,高8位由P2口充当。

键盘与控制器(或者是单片机)连接时时如何工作的?

通过控制器(或者是单片机)对键盘扫描,即:通过键盘与控制器相连导线上的电平值来判断按下的键盘,从而判断相应的键盘值,通过中断,调用相应的中断服务子程序。一般是通过键盘的行扫描和列扫描判断键盘。

通信的三种解调方式?

调频、调相、调幅。

常用的信道复用技术?

频分多路复用(FDM),时分多路复用(TDM),频分多址 (FDMA),时分多址(TDMA),码分多址(CDMA)。

单片机对系统的滤波方式?

单片机对系统只能实现数字滤波,即通过一种数字算法对系统进行滤波。常用的有中值滤波,平滑滤波,程序滤波等

单片机的CPU主要由什么组成?

运算器、控制器

ARR、CNTR、CCR、PSCR寄存器的作用?

ARR //自动重装载值;CNTR//计数器寄存器的值;CCR//俘获比较寄存器的值;PSCR//预分频寄存;

ARR自动重装载寄存器(auto reload register) 。 CCR1捕获/比较寄存器(capture/compare register),显然有CCR2了。PSC预分频器(pre-scaler )。CNT计数器(count)

控制端口的寄存器以及作用?

IDR只读,ODR控制端口输出状态,DDR控制方向

定时器的定时模式和计数模式有什么区别?

定时模式是用cpu的运行时钟进行计数,计数模式是用外部引脚上的脉冲计数。

请简述中断响应过程

中断请求、中断判优、中断响应、中断处理和中断返回

什么是键盘抖动?如何消除?

按键按下时或按键弹起时,接触片会抖动,导致按键通断很多次,解决方法就是按键按下过后检测按键是否弹起,弹起过后再读取该值。

  if(KEY0 == 0){

delay(10); //按键去抖动

        If (KEY0 == 0) {

                  while(KEY0 == 0);

                  key = KEY0_PRESS;   }   }

单片机定时器的定时模式和计数模式有什么区别

定时器是以内部时钟作为基准来工作的,计数器是以外部脉冲输入来计数的。

什么是半双工通信?什么是全双工通信

半双工:在某一时刻只允许某一端进行传送或者接收数据;

全双工:拥有两条线路,允许双方同时进行发送与接收数据。

软件定时和硬件定时的原理有什么异同?

软件定时:是由指令让CPU进行跑空定时,优点是占用硬件资源少编程简单,CPU利用率低,长时间软件定时会产生误差。

硬件定时:采用内置定时器计算时间优点是不占用cpu,响应速度快,但是占用硬件资源

采用SWD接口调试程序需要用几根线,写出对应的单片机引脚编号和名称

三线,CLK(PA14), SWIO(PA13),GND.为了好调试可以留一根VCC

推挽输出模式和开漏输出模式有什么区别?

推挽输出:可以输出高,低电平,连接数字器件。 
输出 0 时,N-MOS 导通,P-MOS 高阻,输出0。 
输出 1 时,N-MOS 高阻,P-MOS 导通,输出1(不需要外部上拉电路)。

开漏输出:输出端相当于三极管的集电极. 要得到高电平状态需要上拉电阻才行. 适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内). 
输出 0 时,N-MOS 导通,P-MOS 不被激活,输出0。 
输出 1 时,N-MOS 高阻, P-MOS 不被激活,输出1(需要外部上拉电路);可以读IO输入电平变化,此模式可以把端口作为双向IO使用。

C语言typedef表示什么含义?

类型定义,它就和define相对应define是把一个自己起的名字的常量定义为代替它的另一个常量来用typedef是把一个自己起的名字的类型用已经有的类型代替使用,如:typedef int Type1;之后如果有Type1 i ;系统则理解为int i;

类似#define两个指令的区别是前者是通过编译器编译,后者是预编译处理直接在未进行编译的过程中就替换#define的代码

C语言->符号表示什么含义?

类似于结构体引用p指针指向s结构体p->a可以等同于s.a

图中标出IO口工作于推挽输出时的输出路径。什么元件导通输出高电平,什么元件导通输出低电平(参考上个题得推挽输出)

​编辑

​编辑

#idndef 和#define在自定义文件库中时什么作用?

头文件中使用#ifndef和#define和#endif格式条件编译,作用时避免头文件内容重复应用定义,第一次应用判断是否定义头文件名,第二次判断已经定义就不会执行#define。

C语言extern表示什么含义?

变量的声明(修饰),extern不是定义变量而是寻找已定义的变量

C语言static表示什么含义?

在多个.c工程中:a.c中定义了static属性的变量str在b.c文件中不可引用这个变量str
static int a;
int b;
void func(void)
{
static int c;
int d;
}在这里,a与b都是全局变量,二者的区别是,b可以被别的文件使用,a只能在本文件中使用,这是static对全局变量的作用。
c和d的区别是,d是一个自动变量,func函数执行完后,d会自动被释放。但c却不会被释放,下一次调用func函数时,c的值会保留上次的值继续使用。

STM32有哪些时钟源

在STM32中,有五个时钟源,为HSI、HSE、LSI、LSE、PLL。
①HSI是高速内部时钟,RC振荡器,频率为8MHz。
②HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz16MHz。
③LSI是低速内部时钟,RC振荡器,频率为40kHz。
④LSE是低速外部时钟,接频率为32.768kHz的石英晶体。
⑤PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2
16倍,但是其输出频率最大不得超过72MHz。

什么是AHB、APB。

AHB高性能总线。主要用于系统高性能、高时钟速率模块间通信,。

APB主要用于低带宽的周边外设之间的连接,它的总线架构不像  AHB支持多个主模块,在APB里面唯一的主模块就是APB 桥。再往下,APB2负责AD,I/O,高级TIM,串口1;APB1负责DA,USB,SPI,I2C,CAN,串口2345,普通TIM。

什么是SYSCLK

系统时钟SYSCLK:HSI、PLLCLK、HSE,具体的由时钟配置寄存器RCC_CFGR的SW位配置

什么是PLL

PLL锁相环。许多电子设备要正常工作,通常需要外部的输入信号与内部的振荡信号同步,利用锁相环路就可以实现这个目的。锁相环路是一种反馈控制电路,简称锁相环(PLL)。一种输出一定频率信号的振荡电路,也称为相位同步环(回路)。该回路利用使外部施加的基准信号与 PLL 回路内的振荡器输出的相位差恒定的反馈控制来产生振荡信号。在网络领域中, PLL 用于从接收的信号中分离出时钟信号。可以将晶振输出频宰Fosc倍增几倍,以满足高速运算需要。在不连接PLL时,cpu时钟和晶振时钟相同即CCLK = Fosc。当使能PLL并连接。则CCLK = Fosc * MM为倍频数。

BRR,BSRR寄存器的作用。

BRR和BSRR寄存器可以方便地快速地实现对端口某些特定位的操作,而不影响其它位的状态

IDR,ODR寄存器的作用。

IDR是查看引脚电平状态用的寄存器,ODR是引脚电平输出的寄存器

CRL,CRH寄存器的作用。

CRH用于控制GPIOX(X表示A---G)的高8位(Pin15---Pin8)
CRL用于控制GPIOX(X表示A---G)的低8位(Pin7----Pin0)

STM32位操作的基本原理。

把一个bit分为32位,每位都分配一个地址,这样就有32个地址,直接通过地址访问

操作IO口输出高低电平有哪些方法?

通过操作ODR,BRR,BSRR寄存器改变IO的输出状态,也就是改变I/O配置的方式。

结构体和共用体有什么区别

一、结构体struct
各成员各自拥有自己的内存,各自使用互不干涉,同时存在的,遵循内存对齐原则。一个struct变量的总长度等于所有成员的长度之和。
二、联合体union
各成员共用一块内存空间,并且同时只有一个成员可以得到这块内存的使用权(对该内存的读写),各变量共用一个内存首地址。

什么是I2C总线的起始信号?

在时钟线SCL保持高电平期间,数据线SDA上的电平被拉低(即负跳变),定义为I2C总线总线的启动信号

什么是I2C总线的停止信号?

在时钟线SCL保持高电平期间,数据线SDA被释放,使得SDA返回高电平(即正跳变),称为I2C总线的停止信号

堆和栈的区别是?

1、存储内容不同:栈:在函数调用时,栈中存放的是函数中(最底下是函数调用后的下一条指令)的各个参数(局部变量)。堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员分配。

2、管理方式上不同:栈:由系统自动分配并释放空间。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间,当对应的生存周期结束后栈空间被自动释放。堆:需要程序员指定大小手动申请和手动释放,在C语言中使用malloc函数申请,使用free函数释放。

3、空间大小不同:栈:获取空间较小。在Windows下一般大小是1M或2M,当剩余栈空间不足时,分配失败overflow。堆:获得空间根据系统的有效虚拟内存有关,比较灵活、大。

4、能否产生碎片不同:栈:不会产生碎片,空间连续。堆:采用的是链表的存储方式,会产生碎片。

5、生长方向不同:栈: 向低地址扩展的数据结构,是一块连续的内存区域。堆: 向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表空闲内存地址来存储的,自然不连续,而链表的遍历方向是由低地址向高地址。

6、分配方式不同:栈:有2种分配方式:静态分配和动态分配,静态由编译器完成,例如局部变量;动态由malloc函数实现,由编译器进行释放。堆: 都是动态分配的,没有静态分配的堆。

7、分配效率不同:栈:由系统自动分配,速度较快。但程序员无法控制。堆:由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。

Volatile与Register的区别是?

a.volatile
volatile是易变的,不稳定的意思,volatile是关键字,是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其他线程等,遇到这个关键字声明的变量,编译器对访问该变量的代码不在进行优化,从而可以提供对特殊地址的稳定访问。那么什么是编译器优化呢?

为了提高运行效率,攻城师们费尽心机地把代码优化,优化程序运行时存取速度。一般,分为硬件优化和软件优化。硬件优化,流水线工作,详细可以参考《计算机组成原理》。软件优化,一部分是程序猿们做的代码优化(前提你得有优化的思路和能力),还有一部分就是我们的编译器优化了。

现代的编译器经过那么多年的发展,已经比较成熟,它会把多余的变量忽略掉,让代码的运行效率更高。默认情况下,编译器都会对代码进行优化,会把一些变量在寄存器里存取,而不是在内存里存取,如此一来,CPU在自己家里拿东西当然比从内存那里拿东西要快得多。举个小栗子:
int i = 5;
int a = i;
……
int b = i;

编译器发现两次从i读数据的代码之间,并没有对i进行过操作,它会自动把上次读的数据放在b中,而不是重新从i里面读取。

而volatile关键字告诉编译器该变量是随时可能发生变化的,每次使用它的时候必须从内存中取出它的值,因而编译器生成的汇编代码会从原内存地址中读取数据使用,而不是从寄存器或者缓存中读取,从而保证了对特殊地址的稳定访问。

简言之,状态要经常变化的,为了防止我们编译优化而导致的存取的数据不同步的问题,这时我们就需要用到volatile。那具体到什么场景下需要用到volatile关键字呢?

1、并行设备的硬件寄存器(如:状态寄存器);

2、一个中断服务子程序中会访问到的非自动变量();

3、多线程应用中被几个任务共享的变量;

上面提到了非自动变量,这里进一步对几种变量做一番解释:

自动变量:是在函数内部定义和使用的变量,它是局部变量。

非自动变量:有两种,一种是全局变量,一种是静态变量。

全局变量:在函数外面定义的变量,只能定义一次,不能有重复的定义,不然就会发生错误,而其他的文件要想使用这个变量,需要extern来声明这个变量(也可省略,因为默认就是extern),这个声明叫做引用声明。

若不想被其他文件访问,则用static关键字声明为静态变量。静态变量与自动变量的本质区别是,静态变量并不像自动变量那样使用堆栈机制来使用内存。

而是为静态变量分配固定的内存,在程序运行的整个过程中,它都会被保持,而不会被销毁。这就是说静态变量的持续性是程序运行的整个周期。这有利于我们共享一些数据。

如果静态变量在函数内部定义,则它的作用域就是在这个函数内部,仅在这个函数内部使用它才有效,但是它不同于自动变量,自动变量离开函数后就会被销毁,而静态变量不会被销毁。他在函数的整个运行周期内都会存在。

b. register
这个关键字请求编译器尽可能的将变量存在CPU内部寄存器中,而不是通过内存寻址访问,以提高效率。注意是尽可能,不是绝对。你想想,一个CPU 的寄存器也就那么几个或几十个,你要是定义了很多很多register 变量,它累死也可能不能全部把这些变量放入寄存器吧。

ARM里的大端格式和小端格式分别是什么意思?

当前的存储器,多以byte为访问的最小单元,当一个逻辑上的地址必须分割为物理上的若干单元时就存在了先放谁后放谁的问题, 于是端(endian)的问题应运而生了, 对于不同的存储方法, 就有大端(big-endian)和小端(little- endian)两个描述。

字节排序按分为大端和小端,概念如下

大端(big endian): 低地址存放高有效字节

小端(little endian): 低字节存放低有效字节

现在主流的CPU, intel系列的是采用的little endian的格式存放数据,而motorola系列的CPU采用的是big endian,ARM则同时支持 big和little。举个例子:
int a = 0x12345678;
a是四字节的int类型变量,需要占四个字节空间,假设变量a的首地址是0x2000,那么数据存储在地址中的格式如下:​编辑