stm32笔记[8]-基础知识整理
摘要
STM32基础知识整理,包括LED流水灯,TIM定时器,中断,串口,以及一些关于ARM架构和STM32的嵌入式开发的前置知识.
第一章:「课后思考题」及「选择填空题测试」整理
课后思考题
- 算原码,反码,补码的方法.
原码、反码、补码是计算机中常用的三种二进制数表示方法,它们的主要区别在于对负数的表示方式不同。
原码:
原码是二进制数的最基本表示方法,也是最直观的一种表示方法。在原码中,最高位表示符号位,0表示正数,1表示负数,其余位表示数值大小。例如,+7的原码为00000111,-7的原码为10000111。
反码:
反码是在原码的基础上,将负数的符号位不变,其余各位取反得到的一种表示方法。例如,+7的反码为00000111,-7的反码为11111000。
补码:
补码是在反码的基础上,将负数的符号位不变,其余各位取反后再加1得到的一种表示方法。例如,+7的补码为00000111,-7的补码为11111001。
举例说明:
假设有一个8位二进制数,其中第一位为符号位,后面7位为数值位。
- 要表示+3,其原码为00000011,反码为00000011,补码为00000011。
- 要表示-3,其原码为10000011,反码为11111100,补码为11111101。
在计算机中,通常使用补码来表示负数,因为补码具有唯一性,可以方便地进行加减运算。
- 转换10进制,16进制,2进制的方法.
转换10进制、16进制、2进制的方法如下:
转换10进制:
将一个数转换为10进制,只需将其各位数字乘以对应的权值,再将结果相加即可。例如,将二进制数1011转换为10进制,计算方法为:1×2³+0×2²+1×2¹+1×2⁰=8+0+2+1=11。
转换16进制:
将一个数转换为16进制,需要将其转换为4位2进制数,然后再将每4位2进制数转换为对应的16进制数。例如,将10进制数27转换为16进制,计算方法为:27÷16=1余11,1÷16=0余1,因此27的16进制表示为1B。
转换2进制:
将一个数转换为2进制,需要不断地将其除以2,直到商为0为止,然后将每次的余数倒序排列即可。例如,将10进制数23转换为2进制,计算方法为:23÷2=11余1,11÷2=5余1,5÷2=2余1,2÷2=1余0,1÷2=0余1,因此23的2进制表示为10111。 - 简述微控制器定义.
微控制器是一种集成了微处理器、存储器、输入/输出接口和定时器等功能单元的单芯片微型计算机系统。它通常被用于控制和监测各种电子设备和系统,如家电、汽车、医疗设备、工业自动化等。
微控制器的核心是微处理器,它包含了中央处理器(CPU)、寄存器、指令集、时钟和总线等基本组成部分。微控制器还集成了存储器,包括闪存、EEPROM、RAM等,用于存储程序代码和数据。此外,微控制器还包含了输入/输出接口,用于与外部设备进行通信,以及定时器和计数器等功能单元,用于实现各种计时和计数操作。
微控制器的优点是体积小、功耗低、成本低、易于集成和使用等。它可以帮助开发人员快速构建各种控制和监测系统,提高系统的可靠性和性能。微控制器在电子行业中得到了广泛应用,是现代电子技术中不可或缺的一部分。 - 嵌入式系统与一般微型计算机系统结构上的区别.
嵌入式系统和一般微型计算机系统在结构上有以下几个区别:
功能和用途:嵌入式系统是为特定的应用程序而设计的,通常用于控制和监控系统。一般微型计算机系统则是为通用计算任务而设计的,例如文档处理、图形处理和游戏等。
硬件:嵌入式系统通常使用定制的硬件,以满足特定的应用需求。一般微型计算机系统则使用通用的硬件,例如CPU、内存、硬盘和显示器等。
软件:嵌入式系统的软件通常是定制的,以满足特定的应用需求。一般微型计算机系统则使用通用的操作系统和应用软件。
大小和功耗:嵌入式系统通常比一般微型计算机系统更小、更轻便,功耗也更低。
可靠性:嵌入式系统通常需要更高的可靠性和稳定性,因为它们通常用于控制和监控系统。一般微型计算机系统则通常不需要如此高的可靠性。
总之,嵌入式系统和一般微型计算机系统在结构上有很多区别,这些区别主要是由于它们的功能、用途、硬件、软件、大小、功耗和可靠性等方面的不同。 - 简述冯诺伊曼和哈佛架构区别.
冯诺伊曼结构和哈佛结构是两种计算机体系结构,它们的主要区别在于它们如何处理数据和指令。
冯诺伊曼结构是一种计算机体系结构,它将数据和指令存储在同一块存储器中,并使用同一组总线来传输数据和指令。这意味着计算机必须在执行指令之前将指令从存储器中读取到CPU中。这种结构的优点是简单和灵活,但缺点是速度较慢,因为CPU必须等待指令从存储器中读取。
哈佛结构是一种计算机体系结构,它将数据和指令存储在不同的存储器中,并使用不同的总线来传输数据和指令。这意味着计算机可以同时读取指令和数据,从而提高了速度。这种结构的优点是速度快,但缺点是复杂和不灵活。
总的来说,冯诺伊曼结构适用于需要灵活性和简单性的应用程序,而哈佛结构适用于需要速度和效率的应用程序,如数字信号处理和嵌入式系统。 - 简述ARM架构流水线技术特点.
ARM架构是一种精简指令集(RISC)架构,其流水线技术特点如下:
简单流水线结构:ARM架构采用了简单的五级流水线结构,包括取指、译码、执行、访存和写回五个阶段。这种结构可以提高指令执行的效率,同时也使得流水线的控制逻辑更加简单。
分支预测:ARM架构采用了静态分支预测和动态分支预测相结合的方式,可以有效地减少分支带来的流水线停顿,提高指令执行效率。
数据旁路:ARM架构采用了数据旁路技术,可以在指令执行过程中直接从寄存器中读取数据,避免了数据冒险带来的流水线停顿。
指令重排:ARM架构采用了指令重排技术,可以将多个指令的执行顺序重新排列,以便更好地利用流水线的各个阶段,提高指令执行效率。
多发射:ARM架构的一些高端处理器还支持多发射技术,可以同时执行多条指令,进一步提高指令执行效率。
总之,ARM架构的流水线技术采用了多种优化措施,可以提高指令执行效率,同时也使得处理器的设计更加简单和灵活。 - Cortex-M3内核有几种工作模式?
Cortex-M3内核有三种工作模式,分别是:
Thread Mode(线程模式):这是Cortex-M3的默认工作模式,用于执行大多数应用程序代码。在这种模式下,处理器可以访问所有的寄存器和系统资源。
Handler Mode(处理器模式):当中断或异常发生时,处理器会从Thread Mode切换到Handler Mode。在这种模式下,处理器只能访问一部分寄存器和系统资源,以确保中断或异常处理程序的正确执行。
Privileged Mode(特权模式):这是最高优先级的工作模式,用于执行特权指令和访问特权资源。在这种模式下,处理器可以访问所有的寄存器和系统资源,并且可以执行特权指令,如修改控制寄存器和访问保护存储器。 - 异常和中断的不同?ARM架构可以管理的异常和中断有哪些?
异常和中断是计算机系统中的两个重要概念,它们都是指计算机在执行程序时遇到的一些意外情况,但它们的触发方式和处理方式有所不同。
异常是指程序在执行过程中遇到的一些非法或不正常的情况,例如除零、访问非法内存、指令错误等,这些情况会导致程序无法正常执行。当发生异常时,处理器会立即停止当前的指令执行,并跳转到异常处理程序中进行处理。
中断是指外部设备向处理器发出的一种请求,请求处理器暂停当前的任务,转而去处理设备发来的请求。例如,键盘输入、鼠标移动等都可以触发中断。当发生中断时,处理器会暂停当前的任务,保存当前的上下文信息,并跳转到中断处理程序中进行处理。
在ARM架构中,异常和中断都是由协处理器来处理的。ARM架构可以管理的异常和中断包括:
复位异常(Reset Exception):当处理器上电或复位时触发,用于初始化处理器和系统。
数据中止异常(Data Abort Exception):当处理器试图访问非法内存或发生数据传输错误时触发。
指令中止异常(Prefetch Abort Exception):当处理器试图执行非法指令或发生指令预取错误时触发。
中断请求(IRQ):由外部设备发出的中断请求,用于处理设备输入输出等操作。
快速中断请求(FIQ):与IRQ类似,但是具有更高的优先级和更快的响应时间,用于处理一些紧急的任务。
未定义指令异常(Undefined Instruction Exception):当处理器遇到未定义的指令时触发。
系统调用异常(Supervisor Call Exception):当处理器执行系统调用指令时触发,用于进入特权模式执行系统级任务。
总之,异常和中断都是计算机系统中非常重要的概念,它们可以帮助处理器处理各种意外情况和外部请求,保证系统的稳定和可靠性。 - 简述ARM架构中断的特点.
在ARM架构中,中断是一种处理器响应外部事件的机制。以下是ARM架构中断的一些特点:
异步性:中断是异步事件,即它们不是由处理器控制的。当外部事件发生时,处理器会停止正在执行的指令,并跳转到中断服务程序(ISR)中去执行。
可屏蔽性:ARM架构中的中断可以被屏蔽或禁用。这意味着处理器可以选择在某些情况下忽略中断请求,以避免中断服务程序的执行。这种可屏蔽性使得处理器可以更好地控制中断的优先级和处理顺序。
中断向量表:ARM架构中的中断向量表是一个特殊的数据结构,其中包含了所有可能的中断类型及其对应的中断服务程序的地址。当中断发生时,处理器会根据中断类型从中断向量表中查找对应的中断服务程序的地址,并跳转到该地址执行。
嵌套中断:ARM架构支持嵌套中断,即当一个中断正在处理时,另一个中断请求可以被接受并处理。这种机制使得处理器可以更好地处理多个中断请求,并保证高优先级的中断能够及时得到处理。
中断优先级:ARM架构中的中断可以分为不同的优先级,高优先级的中断会优先得到处理。处理器可以通过设置中断优先级来控制中断的处理顺序,以确保高优先级的中断能够及时得到处理。
总之,ARM架构中断具有异步性、可屏蔽性、中断向量表、嵌套中断和中断优先级等特点,这些特点使得处理器可以更好地响应外部事件,并保证高优先级的中断能够及时得到处理。 - 简述Cortex-M3位带操作的基本原理和应用.
Cortex-M3是一种32位微控制器,它支持位带操作,这是一种高效的编程技术,可以大大简化代码并提高执行速度。
位带操作的基本原理是将单个位映射到单独的内存地址,这样就可以像访问普通变量一样访问单个位。例如,如果我们有一个32位的寄存器,我们可以使用位带操作来访问其中的某个位,而不必使用掩码和移位操作。
应用方面,位带操作可以用于许多任务,例如:
原子操作:位带操作可以用于原子操作,这是一种在多线程环境下保护共享资源的技术。通过使用位带操作,可以确保对共享资源的访问是原子的,从而避免竞态条件。
GPIO控制:位带操作可以用于控制GPIO引脚。例如,如果我们需要将一个引脚设置为高电平,我们可以使用位带操作来将该引脚的位设置为1。
位字段操作:位带操作可以用于位字段操作,这是一种将多个位组合成单个值的技术。通过使用位带操作,可以轻松地访问和设置位字段,而不必使用掩码和移位操作。
总之,Cortex-M3的位带操作提供了一种高效的编程技术,可以简化代码并提高执行速度。它可以用于许多任务,例如原子操作、GPIO控制和位字段操作。 - Cortex-M3的堆栈有哪些特点?
Cortex-M3是一种基于ARM架构的微控制器,其堆栈有以下特点:
堆栈是向下增长的:Cortex-M3的堆栈是向下增长的,也就是说,堆栈指针的值会随着每次函数调用而减小,而不是增加。
堆栈大小可配置:Cortex-M3的堆栈大小可以通过软件进行配置,以适应不同的应用需求。在编写应用程序时,需要根据实际情况来确定堆栈的大小。
堆栈空间可以被多个任务共享:Cortex-M3的堆栈空间可以被多个任务共享,这意味着多个任务可以使用同一个堆栈空间,从而减少了内存的使用。
堆栈指针可以被保存和恢复:Cortex-M3的堆栈指针可以被保存和恢复,这意味着在函数调用过程中,堆栈指针的值可以被保存到内存中,以便在函数返回时恢复堆栈指针的值。
堆栈溢出检测:Cortex-M3的硬件支持堆栈溢出检测,当堆栈溢出时,会触发异常,从而保护系统免受堆栈溢出带来的风险。 - 简述Cortex-M3处理器的特点.
Cortex-M3处理器是一种基于ARM架构的微控制器处理器,具有以下特点:
高性能:Cortex-M3处理器采用了Harvard结构,具有高效的指令和数据访问,可以实现高达1.25 DMIPS/MHz的性能。
低功耗:Cortex-M3处理器采用了先进的节能技术,包括可变时钟频率、睡眠模式和动态电压调节等,可以实现低功耗运行。
可靠性:Cortex-M3处理器采用了硬件保护机制,包括存储器保护、系统保护和调试保护等,可以提高系统的可靠性和安全性。
易于开发:Cortex-M3处理器支持多种编程语言和开发工具,包括C语言、汇编语言和Keil等,可以方便地进行软件开发和调试。
多种接口:Cortex-M3处理器支持多种接口标准,包括USB、CAN、SPI、I2C和UART等,可以方便地与其他设备进行通信。
总之,Cortex-M3处理器具有高性能、低功耗、可靠性和易于开发等特点,适用于各种嵌入式系统和物联网设备。 - STM32F103VET6的存储器结构有什么特点?
STM32F103VET6是一款基于ARM Cortex-M3内核的微控制器,其存储器结构具有以下特点:
Flash存储器:STM32F103VET6具有512KB的Flash存储器,可用于存储程序代码和数据。Flash存储器可以通过编程器进行编程,支持擦除和编程操作。
SRAM存储器:STM32F103VET6具有64KB的SRAM存储器,可用于存储变量和临时数据。SRAM存储器的读写速度比Flash存储器快,但是在断电时数据会丢失。
EEPROM存储器:STM32F103VET6还具有2KB的EEPROM存储器,可用于存储非易失性数据,例如配置信息和校准数据。EEPROM存储器可以通过编程器进行编程,支持擦除和编程操作。
Bootloader存储器:STM32F103VET6还具有一个用于存储Bootloader程序的区域,该程序可以用于更新Flash存储器中的应用程序代码。Bootloader存储器通常具有更高的可靠性和安全性,以确保应用程序的可靠性和安全性。
总之,STM32F103VET6的存储器结构具有多种类型的存储器,可用于存储不同类型的数据和程序代码,并且具有高可靠性和安全性。 - STM32F103VET6的时钟结构对于系统的功耗控制有什么作用?
STM32F103VET6是一种基于ARM Cortex-M3内核的微控制器,其时钟结构对于系统的功耗控制有着重要的作用。
首先,STM32F103VET6的时钟结构包括内部RC振荡器、内部低速晶体振荡器、内部高速晶体振荡器和外部晶体振荡器等多种时钟源,可以根据实际需求选择合适的时钟源,从而实现功耗的优化。
其次,STM32F103VET6的时钟结构还包括多个时钟域,如AHB、APB1、APB2等,这些时钟域可以独立地进行时钟门控,从而实现对不同外设的功耗控制。例如,当某个外设不需要工作时,可以关闭其所在的时钟域,从而降低功耗。
此外,STM32F103VET6还提供了多种低功耗模式,如停止模式、待机模式、休眠模式等,可以根据实际需求选择合适的低功耗模式,从而进一步降低系统功耗。
综上所述,STM32F103VET6的时钟结构对于系统的功耗控制有着重要的作用,可以通过选择合适的时钟源、时钟门控和低功耗模式等方式,实现对系统功耗的优化。 - STM32固件库和CMSIS的关系?
STM32固件库和CMSIS(Cortex Microcontroller Software Interface Standard)是紧密相关的概念,它们都是用于支持STM32微控制器的软件库。
CMSIS是一种通用的软件接口标准,旨在简化嵌入式软件开发。它定义了一组通用的API,用于访问处理器核心和外设,以及一些通用的数据类型和宏定义。STM32微控制器使用Cortex-M内核,因此它们遵循CMSIS标准。
STM32固件库是STMicroelectronics提供的一组软件库,用于支持STM32微控制器。它包含了许多驱动程序和函数,用于访问STM32微控制器的各种外设和功能。STM32固件库是基于CMSIS标准构建的,因此它们使用CMSIS定义的API和数据类型。
因此,STM32固件库和CMSIS是紧密相关的,STM32固件库是基于CMSIS标准构建的。使用STM32固件库可以方便地访问STM32微控制器的各种外设和功能,而CMSIS则提供了通用的API和数据类型,使得嵌入式软件开发更加简单和标准化。 - STM32的中断向量表是什么?作用是什么?
STM32是一款嵌入式微控制器,它的中断向量表是一个特殊的数据结构,用于存储中断处理程序的地址。中断向量表是一个固定的内存区域,通常位于芯片的起始地址处。
当一个中断事件发生时,STM32会自动跳转到相应的中断处理程序。这个跳转是通过中断向量表中存储的中断处理程序地址实现的。因此,中断向量表的作用是将中断事件与相应的中断处理程序关联起来。
在STM32中,中断向量表包含了所有可能的中断事件的处理程序地址。这些中断事件包括外部中断、定时器中断、串口中断等等。当一个中断事件发生时,STM32会自动跳转到相应的中断处理程序,执行相应的中断服务程序。中断向量表的设计使得中断处理程序的调用变得非常高效和快速。
总之,STM32的中断向量表是一个非常重要的数据结构,它的作用是将中断事件与相应的中断处理程序关联起来,从而实现高效的中断处理。 - STM32F103VET6的GPIO有什么功能和特点?
STM32F103VET6是一款基于ARM Cortex-M3内核的微控制器,它具有多种GPIO功能和特点,如下所述:
GPIO引脚数量:STM32F103VET6具有112个GPIO引脚,其中包括82个可用于通用输入/输出(GPIO)的引脚。
GPIO模式:每个GPIO引脚都可以配置为输入、输出、复用或模拟模式。
GPIO速度:STM32F103VET6的GPIO引脚支持高速和低速操作,可以根据需要进行配置。
GPIO电平:GPIO引脚可以配置为推挽输出或开漏输出,以及具有内部上拉或下拉电阻。
GPIO中断:STM32F103VET6的GPIO引脚支持外部中断和事件中断,可以通过配置来实现。
GPIO电源:STM32F103VET6的GPIO引脚可以在不同的电源模式下运行,包括正常模式、低功耗模式和停机模式。
GPIO保护:STM32F103VET6的GPIO引脚具有过电压保护和静电放电保护功能,可以保护芯片免受损坏。
总之,STM32F103VET6的GPIO具有丰富的功能和特点,可以满足各种应用的需求。 - 如何确定STM32外设某个寄存器的物理地址?
确定STM32外设某个寄存器的物理地址需要查阅STM32芯片的数据手册。在数据手册中,有一个外设寄存器映射表,列出了每个外设的寄存器地址和偏移量。通过查找这个表,可以找到所需寄存器的物理地址。
通常,寄存器地址由两部分组成:基地址和偏移量。基地址是外设的起始地址,而偏移量则是寄存器相对于基地址的偏移量。因此,要确定某个寄存器的物理地址,需要将基地址和偏移量相加。
例如,假设要确定USART1的数据寄存器(USART_DR)的物理地址,可以按照以下步骤进行:
- 打开STM32芯片的数据手册,找到USART1的外设寄存器映射表。
- 在映射表中找到USART_DR寄存器,并记录它的偏移量。假设偏移量为0x04。
- 找到USART1的基地址。假设USART1的基地址为0x40011000。
- 将基地址和偏移量相加,得到USART_DR的物理地址:0x40011000 + 0x04 = 0x40011004。
因此,USART_DR的物理地址为0x40011004。
- STM32的中断和事件的区别?
在STM32中,中断和事件是两种不同的机制,它们的作用和触发方式也不同。
中断是一种硬件机制,当某个外设需要处理器的响应时,会向处理器发出一个中断请求信号,处理器会立即停止当前的任务,转而去处理中断请求。在处理完中断请求后,处理器会恢复之前的任务继续执行。
事件是一种软件机制,它是由程序员在代码中定义的,用于处理某个特定的事件。当事件发生时,程序会调用相应的事件处理函数来处理这个事件。与中断不同的是,事件处理函数是在主程序中被调用的,而不是在中断服务程序中执行的。
因此,中断和事件的区别在于它们的触发方式和处理方式不同。中断是由硬件触发的,处理器会立即停止当前任务去处理中断请求;而事件是由软件触发的,程序会在主程序中调用相应的事件处理函数来处理事件。 - STM32的中断优先级如何设定?
在STM32中,中断优先级的设定是通过NVIC(Nested Vectored Interrupt Controller)寄存器来实现的。以下是中断优先级的设定步骤:
- 确定中断号:首先需要确定要设置的中断号,这个中断号对应着某个外设或内核中断。
- 确定中断优先级组:STM32中的中断优先级分为两组,分别是抢占式优先级和响应式优先级。抢占式优先级用于处理同一时刻多个中断同时发生的情况,响应式优先级用于处理同一时刻同一中断多次发生的情况。需要根据实际情况选择中断优先级组。
- 确定抢占式优先级和响应式优先级:抢占式优先级的范围是015,数值越小,优先级越高。响应式优先级的范围也是015,数值越小,优先级越高。需要根据实际情况确定中断的抢占式优先级和响应式优先级。
- 设置中断优先级:将中断号、中断优先级组、抢占式优先级和响应式优先级写入NVIC寄存器中,即可完成中断优先级的设置。
以下是一个示例代码,用于设置中断号为TIM2的中断优先级:
NVIC_SetPriority(TIM2_IRQn, 2, 0);
其中,TIM2_IRQn是中断号,2是抢占式优先级,0是响应式优先级。
21. STM32F103VET6的定时器有哪些?
STM32F103VET6是一款基于ARM Cortex-M3内核的微控制器,它具有多个定时器。以下是该芯片的定时器列表:
- TIM1:高级定时器,具有16位或32位计数器,可用于PWM输出、编码器接口、输入捕获和输出比较等应用。
- TIM2:通用定时器,具有16位计数器,可用于PWM输出、编码器接口、输入捕获和输出比较等应用。
- TIM3:通用定时器,具有16位计数器,可用于PWM输出、编码器接口、输入捕获和输出比较等应用。
- TIM4:通用定时器,具有16位计数器,可用于PWM输出、编码器接口、输入捕获和输出比较等应用。
- TIM5:高级定时器,具有32位计数器,可用于PWM输出、编码器接口、输入捕获和输出比较等应用。
- TIM6:基本定时器,具有16位计数器,可用于生成定时中断。
- TIM7:基本定时器,具有16位计数器,可用于生成定时中断。
- TIM8:高级定时器,具有16位或32位计数器,可用于PWM输出、编码器接口、输入捕获和输出比较等应用。
- TIM9:通用定时器,具有16位计数器,可用于PWM输出、编码器接口、输入捕获和输出比较等应用。
- TIM10:通用定时器,具有16位计数器,可用于PWM输出、编码器接口、输入捕获和输出比较等应用。
- TIM11:通用定时器,具有16位计数器,可用于PWM输出、编码器接口、输入捕获和输出比较等应用。
- TIM12:通用定时器,具有16位计数器,可用于PWM输出、编码器接口、输入捕获和输出比较等应用。
- TIM13:通用定时器,具有16位计数器,可用于PWM输出、编码器接口、输入捕获和输出比较等应用。
- TIM14:通用定时器,具有16位计数器,可用于PWM输出、编码器接口、输入捕获和输出比较等应用。
这些定时器可以用于各种应用,例如控制LED灯的闪烁频率、测量输入信号的脉冲宽度、控制电机的速度等。
- STM32定时器定时时间如何设定?定时范围是什么?
STM32定时器的定时时间可以通过设置定时器的预分频器和计数器来实现。预分频器用于将输入时钟分频,计数器用于计数分频后的时钟周期数,从而实现定时功能。
定时范围取决于所使用的定时器的位数和预分频器的设置。例如,对于16位定时器,如果使用最大预分频器分频后的时钟频率为72MHz,则最大定时时间为65535个时钟周期,即1.8秒。如果使用更小的预分频器,则可以实现更长的定时时间。
在STM32中,定时器的设置可以通过寄存器来完成,具体的设置方法可以参考相关的数据手册和参考手册。同时,也可以使用STM32的HAL库或者CubeMX工具来进行定时器的配置和使用。 - STM32F103VET6的USART有哪些特点?
STM32F103VET6是一款基于ARM Cortex-M3内核的微控制器,它的USART模块具有以下特点:
- 支持多种通信模式:USART模块可以支持异步串行通信、同步串行通信和单线半双工通信等多种通信模式,可以满足不同应用场景的需求。
- 支持多种数据格式:USART模块可以支持8位、9位和10位数据格式,可以满足不同数据传输的需求。
- 支持多种波特率:USART模块可以支持多种波特率,包括标准波特率和自定义波特率,可以满足不同数据传输速率的需求。
- 支持硬件流控制:USART模块可以支持硬件流控制,包括RTS/CTS流控制和DTR/DSR流控制,可以提高数据传输的可靠性。
- 支持中断和DMA传输:USART模块可以支持中断和DMA传输,可以提高数据传输的效率和可靠性。
- 支持多个USART通道:STM32F103VET6的USART模块可以支持多个USART通道,可以满足多个串口通信的需求。
- 简述STM32F103VET6的ADC模块的特点.
STM32F103VET6是一款基于ARM Cortex-M3内核的微控制器,其ADC模块具有以下特点:
- 12位精度:ADC模块可以进行12位精度的模数转换,可以提供高精度的模拟信号采集。
- 多通道采集:ADC模块可以同时采集多个通道的模拟信号,最多可以采集16个通道。
- 快速采样:ADC模块可以进行高速采样,最高采样速率可以达到1Msps。
- 外部触发:ADC模块可以通过外部触发进行采样,可以实现更加精确的采样控制。
- DMA支持:ADC模块支持DMA传输,可以实现高效的数据传输。
- 温度传感器和内部参考电压:ADC模块内置有温度传感器和内部参考电压源,可以方便地进行温度测量和电压测量。
- 低功耗:ADC模块可以在低功耗模式下工作,可以实现更加节能的应用设计。
总之,STM32F103VET6的ADC模块具有高精度、多通道、快速采样、外部触发、DMA支持、温度传感器和内部参考电压等特点,可以满足各种应用场景的需求。
- STM32的ADC的注入通道和规则通道有什么本质区别?
STM32的ADC(模数转换器)有两种不同的转换模式:注入模式和规则模式。注入模式和规则模式之间的主要区别在于它们转换通道的方式和优先级。
注入通道是一种特殊的通道,它允许在规则通道转换期间插入一些额外的转换。注入通道的优先级高于规则通道,因此在注入通道上进行的转换将在规则通道上进行的转换之前完成。
规则通道是ADC的标准转换通道,它允许选择一组ADC输入通道进行转换。规则通道的转换顺序是由程序员定义的,并且在转换期间不会被中断或插入其他转换。
注入通道和规则通道之间的另一个区别是它们的采样时间。注入通道的采样时间比规则通道的采样时间长,因为注入通道需要更多的时间来充电和放电。这意味着在注入通道上进行的转换需要更长的时间来完成。
总之,注入通道和规则通道的本质区别在于它们转换通道的方式和优先级。注入通道允许在规则通道转换期间插入额外的转换,并具有更长的采样时间。规则通道是ADC的标准转换通道,由程序员定义转换顺序,并且在转换期间不会被中断或插入其他转换。 - 简述STM32F103VET6的DMA模块的特点?
STM32F103VET6是一款基于ARM Cortex-M3内核的微控制器,它的DMA模块具有以下特点:
- 多通道:STM32F103VET6的DMA模块支持多达7个DMA通道,可以同时处理多个数据流,提高了数据传输的效率。
- 高速传输:DMA模块支持高速传输,最高可以达到36MB/s的传输速度,可以满足高速数据传输的需求。
- 灵活配置:DMA模块的配置非常灵活,可以根据不同的应用场景进行配置,支持多种传输模式和传输方向,可以满足不同的数据传输需求。
- 低功耗:DMA模块采用了先进的低功耗技术,可以在数据传输过程中降低功耗,延长系统的使用寿命。
- 中断支持:DMA模块支持中断,可以在数据传输完成时触发中断,方便用户进行数据处理和控制。
总之,STM32F103VET6的DMA模块具有高速传输、灵活配置、低功耗和中断支持等特点,可以满足不同应用场景下的数据传输需求。
- DMA技术和中断技术有什么本质区别?
DMA技术和中断技术都是计算机系统中常见的I/O(输入/输出)技术,但它们的本质区别在于它们处理I/O操作的方式和机制。
DMA(直接内存访问)技术是一种通过专用硬件控制器直接访问内存的技术,它允许外设(如硬盘、网卡等)直接读写内存,而不需要CPU的干预。DMA技术可以提高I/O操作的效率,减少CPU的负担,因为CPU不需要在I/O操作期间持续参与数据传输过程。DMA技术通常用于大量数据传输,如音频、视频和图像等。
中断技术是一种基于CPU的响应机制,它允许外设向CPU发出中断请求,以便CPU能够在必要时停止当前任务并处理中断请求。中断技术可以使计算机系统更加灵活,因为它可以在I/O操作期间处理其他任务。中断技术通常用于处理低速I/O设备,如键盘、鼠标和串口等。
因此,DMA技术和中断技术在处理I/O操作的方式和机制上存在本质区别。DMA技术通过专用硬件控制器直接访问内存,而中断技术是基于CPU的响应机制,允许外设向CPU发出中断请求。 - 简述STM32F103VET6的FSMC模块的特点.
STM32F103VET6是一款基于ARM Cortex-M3内核的微控制器,它具有FSMC(Flexible Static Memory Controller)模块,该模块具有以下特点:
- 支持多种外部存储器:FSMC模块支持多种外部存储器,包括SRAM、NOR Flash、NAND Flash、PSRAM等,可以满足不同应用场景的需求。
- 高速数据传输:FSMC模块支持高速数据传输,最高可达100MHz,可以满足高速数据读写的需求。
- 多种访问模式:FSMC模块支持多种访问模式,包括异步访问、同步访问、Burst访问等,可以根据不同的存储器类型和应用场景选择合适的访问模式。
- 多种数据总线宽度:FSMC模块支持多种数据总线宽度,包括8位、16位、32位,可以根据不同的存储器类型和应用场景选择合适的数据总线宽度。
- 多种时序配置:FSMC模块支持多种时序配置,可以根据不同的存储器类型和应用场景进行灵活配置。
- 多种中断和DMA支持:FSMC模块支持多种中断和DMA支持,可以提高数据传输的效率和可靠性。
综上所述,STM32F103VET6的FSMC模块具有灵活性高、数据传输速度快、支持多种存储器类型和访问模式等特点,可以满足不同应用场景的需求。
- 简述如何使用STM32F103ZET6扩展片外RAM.
要使用STM32F103ZET6扩展片外RAM,需要完成以下步骤:
- 选择合适的片外RAM芯片。片外RAM的选择应该考虑到芯片的容量、速度、接口等因素。常用的片外RAM芯片有SRAM和SDRAM两种类型。
- 连接片外RAM芯片。将片外RAM芯片连接到STM32F103ZET6的外部总线上,通常使用地址线、数据线、控制线等进行连接。需要注意的是,STM32F103ZET6的外部总线支持多种接口类型,如FSMC、FSMC_NOR、FSMC_NAND、FSMC_PCCARD等,需要根据所选的片外RAM芯片类型选择合适的接口类型。
- 配置STM32F103ZET6的外部总线。在使用片外RAM之前,需要对STM32F103ZET6的外部总线进行配置。具体的配置包括时序参数、读写模式、数据宽度等。可以使用STM32CubeMX软件进行配置,也可以手动编写配置代码。
- 在代码中使用片外RAM。在代码中使用片外RAM时,需要先初始化外部总线,然后使用指针访问片外RAM的地址空间。需要注意的是,片外RAM的地址空间和内部RAM的地址空间是分开的,需要使用不同的指针进行访问。
总之,使用STM32F103ZET6扩展片外RAM需要进行硬件连接、外部总线配置和代码编写等多个步骤,需要仔细考虑和实施。
头歌平台测试
- 指令LDR R0,[R1,#4]的寻址方式为什么?
基址变址寻址. - 某系统需要永久存放高速度写的数据,最合适的存储器是什么?
FRAM. - 下面哪一种工作模式不属于ARM异常模式?
系统模式. - 中断向量是指什么?
中断处理程序入口地址. - 某系统需要大量的高速缓存,最合适的存储器是什么?
DRAM. - 某系统需要永久存放大量不再修改的数据,最合适的存储器是什么?
Flash. - 以下有关ARM处理器工作状态的描述中,不正确的是?
切换工作状态时必须保存现场. - 指令ADD R0,R1,R2的寻址方式是什么?
寄存器寻址. - 嵌入式系统有别于其他系统的最大特点是什么?
嵌入专用. - 下列有关Flash存储器的描述,不正确的是什么?
Flash存储器的写操作与SDRAM存储器的写操作基本相同. - 下面哪一种单元不属于I/O接口电路?
LED,薄膜键盘. - 下列关于DMA描述不正确的是什么?
数据的输入和输出需要经过CPU再由DMA控制器访问内存. - 下面关于冯·诺伊曼架构描述正确的是什么?
程序存储空间与数据存储空间合并. - 与十进制数254等值的二进制数是什么?
- 在 IRQ,预取中止,FIQ,异常中,未定义指令 异常中,优先级最高的是什么?
FIQ.
解析:异常中断的优先级:复位 > 数据异常中止 > FIQ > IRQ > 预取指令异常中止 > SWI > 未定义指令(包括缺协处理器). - 下面关于哈佛架构描述正确的是什么?
程序存储空间与数据存储空间分离. - 基于查询的实时编程结构的实时性取决于什么?
所有其它任务执行时间之和. - 硬实时系统要求什么?
任务响应实时. - 前后台系统的实时性取决于什么?
所有其它任务执行时间之和. - 基于中断的实时编程结构的实时性取决于什么?
中断响应时间. - 嵌入式系统最常用的数据传送方式是什么?
中断. - 下面哪一种工作模式不属于ARM特权模式?
用户模式. - 以下哪个处理器属于嵌入式处理器?
S3C44B0x. - 下面哪一类嵌入式处理器最适合用于工业控制?
嵌入式微处理器. - 下面关于DMA描述不正确的是什么?
数据的输入和输出需要经过CPU,再由DMA控制器访问内存. - 下面关于GPIO的描述正确的是什么?
GPIO可以用于模拟Flash的接口,对Flash存储器进行读写操作.
解析:GPIO,称为通用型输入输出或总线扩展器,GPIO可以用于模拟Flash的接口,对Flash存储器进行读写操作,可以用来模拟总线跟外部设备通信。 - 某系统需要小量的高速缓存,最合适的存储器是什么?
SRAM. - 嵌入式系统的基本定义.
嵌入式系统的一般定义:以应用为中心,以计算机技术为基础,软件硬件可裁剪,功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。 - 总线的定义.
总线是一种在多于两个模块(设备或子系统)间传送信息的公共通路. - 总线的功能.
总线的功能是实现各模块(设备或子系统)之间能实现信息共享和交换. - ARM系列微处理支持的数据类型.
ARM系列微处理支持的数据类型有:字节,字和半字等三种类型. - ARM系列微处理支持的字数据存储格式.
ARM系列微处理支持的字数据存储格式有:大端格式和小端格式. - I/O接口编址方式.
I/O接口编址方式有两种,分别是:统一编址和独立编址. - 下面哪一种工作模式不属于ARM异常模式?
系统模式. - I/O接口面向软件设计人员的寄存器.
I/O接口面向软件设计人员有三类寄存器,分别是:数据寄存器,状态寄存器和命令寄存器. - RAM存储器分类.
对于RAM存储器主要有两种,分别是:DRAM和SRAM. - RS-232C的帧格式.
RS-232C的帧格式由四部分组成,包括:起始位,数据位,奇偶校验位和停止位. - 变量的指针的含义是什么?
变量的地址. - C语言中的int类型数据在内存中占多少位?
不一定是8位.
解析:在C语言中,int类型数据的大小(占用的内存位数)是由编译器和操作系统决定的,因为不同的编译器和操作系统可能有不同的实现方式。通常情况下,int类型数据在内存中占用4个字节(32位),但在一些嵌入式系统中,int类型数据可能只占用2个字节(16位)或更少。可以使用sizeof运算符来确定int类型数据在特定系统中的大小,例如:
#include <stdio.h>
int main() {
printf("Size of int: %d bytes\n", sizeof(int));
return 0;
}
这个程序将输出int类型数据在当前系统中的大小(以字节为单位)。
40. 在DMA传送期间,CPU能使用总线吗?
不能.
解析:在DMA(Direct Memory Access,直接内存访问)传送期间,CPU(中央处理器)不能使用总线。这是因为DMA控制器接管了总线的控制权,直接与内存进行数据传输,而不需要CPU的干预。这样可以提高数据传输的效率,减少CPU的负担,从而提高系统的整体性能。在DMA传送期间,CPU可以继续执行其他任务,或者处于空闲状态等待DMA传输完成。
第二章:实验代码及引脚配置
使用TIM及定时器中断
- STM32CubeMX配置:
时钟:System-Clock:80MHz,
Timers:TIM2->Prescaler=7999,->Counter Preriod=5000,->auto_reload=Enable,
允许TIM2 global interrupt; - 核心代码
main.c
//配置TIM2定时器
static void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 7999;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 5000;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
}
//初始化TIM2定时器
MX_TIM2_Init();
//启动TIM2定时器
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
//中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
HAL_GPIO_TogglePin(LED_1_GPIO_Port, LED_1_Pin);
}
}
按键中断
- STM32CubeMX配置:
配置Pinout的PE11为GPIO_EXTI11,
System Core的NVIC:允许EXTI line[15:10] interrupts. - 核心代码
main.c
//初始化IO口
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_11|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
/*Configure GPIO pin : PE3 */
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/*Configure GPIO pin : PA3 */
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : PE11 */
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/*Configure GPIO pins : PD11 PD14 PD15 */
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/*Configure GPIO pin : PB6 */
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
}
//初始化IO口
MX_GPIO_Init();
//中断回调
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
// 判断是否是按键引脚的中断
if (GPIO_Pin == GPIO_PIN_11) {
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_11)==0){
// 切换是否闪烁两个LED灯
led_state = !led_state;
}
}
}
各种形式的流水灯
假设使用PA0-PA7的IO口作为LED灯引脚.
公共代码:
//初始化LED的GPIO接口
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7; // LED灯在PA0~PA7
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
- 依次点亮(延时)
BSRR代表的是Bit Set/Reset Register,即位设置/复位寄存器。在STM32中,BSRR的高16位用于设置GPIO口的输出状态为高电平,低16位用于设置GPIO口的输出状态为低电平。因此,使用BSRR寄存器的BS位(Bit Set)可以将GPIO口的输出状态设置为高电平,而BR位(Bit Reset)可以将GPIO口的输出状态设置为低电平。
BRR代表的是Bit Reset Register,即位复位寄存器。在STM32中,BRR的每一位都用于将对应的GPIO口输出状态设置为低电平。因此,使用BRR寄存器可以将GPIO口的输出状态设置为低电平。
核心代码:
main.c
//延时方式依次点亮
while(1){
for (int i = 0; i < 8; i++) {
GPIOA->BRR = (1 << i); // 设置对应IO口为低电平,点亮第i个(PAi)LED灯
HAL_Delay(100); // 延时100ms
GPIOA->BSRR = (1 << (i+8)); // 设置对应IO口为高电平,熄灭第i个(PAi)LED灯
}
}
- 依次翻转LED灯状态(定时器)
在STM32系列微控制器中,每个GPIO端口都有一个ODR寄存器,ODR寄存器的功能是控制GPIO引脚的输出电平状态。ODR寄存器的每一位对应一个GPIO引脚,当某一位被置1时,对应的GPIO引脚输出高电平;当某一位被置0时,对应的GPIO引脚输出低电平。
核心代码:
main.c
//全局变量
uint8_t pin_number=0;
//定时器中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
// 获取引脚号
uint32_t pin = 1 << (pin_number & 0x0F);
// 翻转GPIO电平
GPIOA->ODR ^= pin;
pin_number++;
}
}
- 隔一个点亮(按键查询触发流水灯)
核心代码:
main.c
//全局变量
uint8_t is_enable_led=0;//是否开启流水灯,按键触发变量改变
//延时方式依次点亮
while(1){
if(is_enable_led==1){//查询流水灯开关
//偶数灯
for (int i = 0; i < 8; i+=2) {
GPIOA->BRR = (1 << i); // 设置对应IO口为低电平,点亮第i个(PAi)LED灯
HAL_Delay(100); // 延时100ms
GPIOA->BSRR = (1 << (i+8)); // 设置对应IO口为高电平,熄灭第i个(PAi)LED灯
}
//奇数灯
for (int i = 1; i < 8; i+=2) {
GPIOA->BRR = (1 << i); // 设置对应IO口为低电平,点亮第i个(PAi)LED灯
HAL_Delay(100); // 延时100ms
GPIOA->BSRR = (1 << (i+8)); // 设置对应IO口为高电平,熄灭第i个(PAi)LED灯
}
}
}
- 变速流水灯
核心代码:
main.c
//全局变量
uint32_t count=0;
//翻转电平函数
void LED_Toggle(uint16_t GPIO_Pin)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_Pin); // 翻转GPIO电平
}
//普通的HAL方式操控GPIO口
LED_Toggle(GPIO_PIN_0); // 点亮第1个LED
HAL_Delay(1000 / (count + 1)); // 根据流水灯速度延时
LED_Toggle(GPIO_PIN_0); // 关闭第1个LED
count++;
LED_Toggle(GPIO_PIN_1); // 点亮第2个LED
HAL_Delay(1000 / (count + 1)); // 根据流水灯速度延时
LED_Toggle(GPIO_PIN_1); // 关闭第2个LED
count++;
LED_Toggle(GPIO_PIN_2); // 点亮第3个LED
HAL_Delay(1000 / (count + 1)); // 根据流水灯速度延时
LED_Toggle(GPIO_PIN_2); // 关闭第3个LED
count++;
LED_Toggle(GPIO_PIN_3); // 点亮第4个LED
HAL_Delay(1000 / (count + 1)); // 根据流水灯速度延时
LED_Toggle(GPIO_PIN_3); // 关闭第4个LED
count++;
LED_Toggle(GPIO_PIN_4); // 点亮第5个LED
HAL_Delay(1000 / (count + 1)); // 根据流水灯速度延时
LED_Toggle(GPIO_PIN_4); // 关闭第5个LED
count++;
LED_Toggle(GPIO_PIN_5); // 点亮第6个LED
HAL_Delay(1000 / (count + 1)); // 根据流水灯速度延时
LED_Toggle(GPIO_PIN_5); // 关闭第6个LED
count++;
LED_Toggle(GPIO_PIN_6); // 点亮第7个LED
HAL_Delay(1000 / (count + 1)); // 根据流水灯速度延时
LED_Toggle(GPIO_PIN_6); // 关闭第7个LED
count++;
LED_Toggle(GPIO_PIN_7); // 点亮第8个LED
HAL_Delay(1000 / (count + 1)); // 根据流水灯速度延时
LED_Toggle(GPIO_PIN_7); // 关闭第8个LED
count++;
//重置变量
count=0;
ADC转换
- STM32CubeMX配置:
Analog:ADC1->IN7->Single-ended,
Pinout:配置PA2位ADC1_IN7, - 核心代码:
//初始化ADC
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_MultiModeTypeDef multimode = {0};
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_7;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
//Cortex-M4 ADC校准
if (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK)
{
Error_Handler();
}
//读取ADC的值
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
uint16_t adc_value = HAL_ADC_GetValue(&hadc1);
char buffer[32];
sprintf(buffer, "ADC value: %d\r\n", adc_value);
lpuart1_printf(buffer);
串口多字节收发
- STM32CubeMX配置:
配置IO口为LPUART,允许LPUART1全局中断. - 核心代码
主要方法:主要使用HAL库,在处理接收中断时读取寄存器UART_FLAG_RXNE
的值,在处理空闲中断时读取空闲中断寄存器UART_FLAG_IDLE
的值。
main.c
//串口配置
static void MX_LPUART1_UART_Init(void)
{
/* USER CODE BEGIN LPUART1_Init 0 */
/* USER CODE END LPUART1_Init 0 */
/* USER CODE BEGIN LPUART1_Init 1 */
/* USER CODE END LPUART1_Init 1 */
hlpuart1.Instance = LPUART1;
hlpuart1.Init.BaudRate = 115200;
hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;
hlpuart1.Init.StopBits = UART_STOPBITS_1;
hlpuart1.Init.Parity = UART_PARITY_NONE;
hlpuart1.Init.Mode = UART_MODE_TX_RX;
hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&hlpuart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN LPUART1_Init 2 */
//添加空闲中断
HAL_NVIC_EnableIRQ(LPUART1_IRQn);
HAL_NVIC_SetPriority(LPUART1_IRQn,3,3);
__HAL_UART_ENABLE_IT(&hlpuart1,UART_IT_RXNE);//接收中断
__HAL_UART_ENABLE_IT(&hlpuart1,UART_IT_IDLE);//空闲中断
/* USER CODE END LPUART1_Init 2 */
}
//串口打印函数
void lpuart1_printf(char * input){
char b2[32];
snprintf(b2, sizeof(b2), "log:%s\n", input);
HAL_UART_Transmit(&hlpuart1, (uint8_t *)b2, strlen(b2), strlen(b2) * 10);
}
stm32l4xx_it.c
//串口中断回调函数
void LPUART1_IRQHandler(void)
{
/* USER CODE BEGIN LPUART1_IRQn 0 */
//自动调用HAL_UART_RxCpltCallback()
uint8_t rec; // 暂存接收到的数据
//接收中断
if (__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_RXNE) != RESET) {
HAL_UART_Receive(&hlpuart1, &rec, 1, 1000);
if (matter_frame_buffer_pos < 256) { // 确保不会溢出
matter_frame_buffer[matter_frame_buffer_pos++] = rec; // 存储数据并更新长度
}
//清除中断接收标志
__HAL_UART_CLEAR_FLAG(&hlpuart1,UART_FLAG_RXNE);
}
//空闲中断
if (__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_IDLE) != RESET){
//接收完成一帧数据
LPUART_IdleCallback(matter_frame_buffer,matter_frame_buffer_pos);
//清除中断接收标志
__HAL_UART_CLEAR_FLAG(&hlpuart1,UART_FLAG_IDLE);
}
/* USER CODE END LPUART1_IRQn 0 */
HAL_UART_IRQHandler(&hlpuart1);
/* USER CODE BEGIN LPUART1_IRQn 1 */
/* USER CODE END LPUART1_IRQn 1 */
}
/* USER CODE BEGIN 1 */
//空闲中断回调函数
void LPUART_IdleCallback(uint8_t *pData,uint16_t len){
//空闲中断回调
while(__HAL_UART_GET_FLAG(&hlpuart1,UART_FLAG_TC)!=SET);
//调试:转发数据
HAL_UART_Transmit(&hlpuart1,"Idle_Rec:",9,1000);
HAL_UART_Transmit(&hlpuart1,matter_frame_buffer,len,1000);
HAL_UART_Transmit(&hlpuart1,"\n",2,1000);
}
第三章:重点知识
STM32的中断系统简明介绍
STM32F103系列是STMicroelectronics公司推出的一款基于Cortex-M3内核的32位微控制器。中断是STM32F103系列的一个重要特性,它可以让MCU在执行主程序的同时,响应外部事件,从而提高系统的实时性和可靠性。本文将对STM32F103系列的中断系统进行简要介绍,并与Cortex-M3内核的中断系统进行对比。
一、STM32F103系列的中断系统
- 中断向量表
STM32F103系列的中断向量表是一个固定的地址表,其中包含了所有中断服务程序的入口地址。当一个中断事件发生时,MCU会自动跳转到对应的中断服务程序入口地址执行中断处理程序。中断向量表的地址可以通过修改NVIC_VectTab的值来改变。
- 中断优先级
STM32F103系列的中断系统支持16级中断优先级,其中0级为最高优先级,15级为最低优先级。当多个中断事件同时发生时,MCU会根据中断优先级来决定哪个中断先被处理。中断优先级可以通过NVIC_SetPriority函数来设置。
- 中断控制器
STM32F103系列的中断控制器是一个硬件模块,它负责管理所有中断事件的优先级和状态。中断控制器可以通过NVIC_EnableIRQ和NVIC_DisableIRQ函数来使能或禁止某个中断事件。同时,中断控制器还可以通过NVIC_SetPendingIRQ函数来模拟中断事件的发生,从而触发中断处理程序的执行。
- 中断服务程序
STM32F103系列的中断服务程序是一段特殊的代码,它负责处理中断事件。中断服务程序需要遵循一定的规范,包括保存现场、清除中断标志、执行中断处理程序、恢复现场等。中断服务程序可以通过在中断向量表中设置相应的入口地址来注册。
二、Cortex-M3内核的中断系统
Cortex-M3内核是一种高性能、低功耗的32位RISC内核,它的中断系统与STM32F103系列的中断系统有些许不同。
- 中断向量表
Cortex-M3内核的中断向量表是一个可配置的地址表,其中包含了所有中断服务程序的入口地址。与STM32F103系列不同的是,Cortex-M3内核的中断向量表可以放在任意地址,而不是固定的地址。中断向量表的地址可以通过修改VTOR寄存器的值来改变。
- 中断优先级
Cortex-M3内核的中断系统支持256级中断优先级,其中0级为最高优先级,255级为最低优先级。当多个中断事件同时发生时,MCU会根据中断优先级来决定哪个中断先被处理。中断优先级可以通过NVIC_SetPriority函数来设置。
- 中断控制器
Cortex-M3内核的中断控制器也是一个硬件模块,它负责管理所有中断事件的优先级和状态。中断控制器可以通过NVIC_EnableIRQ和NVIC_DisableIRQ函数来使能或禁止某个中断事件。同时,中断控制器还可以通过NVIC_SetPendingIRQ函数来模拟中断事件的发生,从而触发中断处理程序的执行。
- 中断服务程序
Cortex-M3内核的中断服务程序也需要遵循一定的规范,包括保存现场、清除中断标志、执行中断处理程序、恢复现场等。与STM32F103系列不同的是,Cortex-M3内核的中断服务程序需要手动压栈和出栈,而不是由硬件自动完成。
三、总结
STM32F103系列的中断系统与Cortex-M3内核的中断系统有些许不同,但它们的基本原理和功能都是相似的。中断是一种重要的系统特性,它可以让MCU在执行主程序的同时,响应外部事件,从而提高系统的实时性和可靠性。在实际应用中,我们需要根据具体的需求来选择合适的中断系统,并合理设置中断优先级,以确保系统的稳定性和可靠性。
STM32的volatile关键字
在STM32中,volatile关键字用于告诉编译器该变量可能会在程序的执行过程中被意外地改变,因此编译器不应该对该变量进行优化,以确保程序的正确性。
具体来说,当一个变量被声明为volatile时,编译器会在生成代码时,每次都从内存中读取该变量的值,而不是使用寄存器中的缓存值。这样可以确保在多线程或中断处理程序中,对该变量的读写操作都是正确的,避免了由于编译器优化而引起的问题。
在STM32中,由于常常需要在中断处理程序中访问硬件寄存器,而硬件寄存器的值可能会在程序执行过程中被改变,因此使用volatile关键字是非常重要的。
参考资料
- (简化版引用文献格式)
- 陈桂友.《基于ARM的微机原理与接口技术》.
- Cotex-M3架构参考手册
- STM32F103VET6参考手册
- 野火STM32开发板配套教程(HAL库)
- 正点原子STM32开发板配套教程(HAL库)
- 正点原子STM32开发板配套例程(HAL库)