STM32

STM32是STMicroelectronics(意法半导体)推出的一系列基于ARM Cortex-M内核的32位微控制器(MCU)产品。这些微控制器提供了广泛的产品系列,覆盖了多种不同的性能和功能需求,适用于各种应用领域,包括工业控制、汽车电子、消费类电子、医疗设备等。

STM32系列微控制器以其高性能、低功耗、丰富的外设接口和灵活的开发工具而闻名。它们通常具有丰富的存储器、多种通信接口(如UART、SPI、I2C、CAN等)、模拟数字转换器(ADC)、定时器、PWM输出等功能,以满足不同应用场景下的需求。

STM32微控制器通常使用标准的ARM Cortex-M内核,包括Cortex-M0、M0+、M3、M4和M7等,这些内核具有不同的性能和功耗特性,可根据具体应用的需求进行选择。此外,STM32系列还提供了多种封装和引脚配置,以满足不同尺寸和集成度的要求。

STMicroelectronics为STM32系列提供了丰富的开发工具和支持资源,包括基于ARM开发环境的集成开发环境(IDE)、调试器、评估板和参考设计等。这些工具和资源有助于开发人员快速开发和部署他们的应用,并提供了全面的技术支持和文档资料,帮助用户充分发挥STM32微控制器的性能和功能优势。

DMA的基本介绍

什么是DMA (DMA的基本定义)

DMA,全称Direct Memory Access,即直接存储器访问。

DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。

我们知道CPU有转移数据、计算、控制程序转移等很多功能,系统运作的核心就是CPU,CPU无时不刻的在处理着大量的事务,但有些事情却没有那么重要,比方说数据的复制和存储数据,如果我们把这部分的CPU资源拿出来,让CPU去处理其他的复杂计算事务,是不是能够更好的利用CPU的资源呢?

因此:转移数据(尤其是转移大量数据)是可以不需要CPU参与。比如希望外设A的数据拷贝到外设B,只要给两种外设提供一条数据通路,直接让数据由A拷贝到B 不经过CPU的处理。

“详解STM32中的DMA原理"

DMA就是基于以上设想设计的,它的作用就是解决大量数据转移过度消耗CPU资源的问题。有了DMA使CPU更专注于更加实用的操作–计算、控制等。

DMA定义

DMA用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU的干预,通过DMA数据可以快速地移动。这就节省了CPU的资源来做其他操作。

DMA传输方式

DMA的作用就是实现数据的直接传输,而去掉了传统数据传输需要CPU寄存器参与的环节,主要涉及四种情况的数据传输,但本质上是一样的,都是从内存的某一区域传输到内存的另一区域(外设的数据寄存器本质上就是内存的一个存储单元)。四种情况的数据传输如下:

  • 外设到内存
  • 内存到外设
  • 内存到内存
  • 外设到外设

DMA传输参数

我们知道,数据传输,首先需要的是1 数据的源地址 2 数据传输位置的目标地址 ,3 传递数据多少的数据传输量 ,4 进行多少次传输的传输模式 DMA所需要的核心参数,便是这四个。

“详解STM32中的DMA原理"

当用户将参数设置好,主要涉及源地址、目标地址、传输数据量这三个,DMA控制器就会启动数据传输,当剩余传输数据量为0时 达到传输终点,结束DMA传输 ,当然,DMA 还有循环传输模式 当到达传输终点时会重新启动DMA传输。

也就是说只要剩余传输数据量不是0,而且DMA是启动状态,那么就会发生数据传输。  

DMA的主要特征

每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过软件来配置。

  • 在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推);
  • 独立数据源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐;
  • 支持循环的缓冲器管理;
  • 每个通道都有3个事件标志(DMA半传输、DMA传输完成和DMA传输出错),这3个事件标志逻辑或成为一个单独的中断请求;
  • 存储器和存储器间的传输、外设和存储器、存储器和外设之间的传输;
  • 闪存、SRAM、外设的SRAM、APB1、APB2和AHB外设均可作为访问的源和目标;
  • 可编程的数据传输数目:最大为65535。

STM32少个DMA资源?

对于大容量的STM32芯片有2个DMA控制器 两个DMA控制器,DMA1有7个通道,DMA2有5个通道。

每个通道都可以配置一些外设的地址。

①DMA1 controller

从外设(TIMx[x=1、2、3、4]、ADC1、SPI1、SPI/I2S2、I2Cx[x=1、2]和USARTx[x=1、2、3])产生的7个DMA请求,通过逻辑或输入到DMA1控制器 其中每个通道都对应着具体的外设:

“详解STM32中的DMA原理"

“详解STM32中的DMA原理"

② DMA2 controller

从外设(TIMx[5、6、7、8]、ADC3、SPI/I2S3、UART4、DAC通道1、2和SDIO)产生的5个请求,经逻辑或输入到DMA2控制器,其中每个通道都对应着具体的外设:

“详解STM32中的DMA原理"

“详解STM32中的DMA原理"

这些在下方系统框图中也可以清晰地看到。

DMA工作系统框图

“详解STM32中的DMA原理"

上方的框图,我们可以看到STM32内核,存储器,外设及DMA的连接,这些硬件最终通过各种各样的线连接到总线矩阵中,硬件结构之间的数据转移都经过总线矩阵的协调,使各个外设和谐的使用总线来传输数据。

我们对他来进行一点一点的分析:

下面看有与没有DMA的情况下,ADC采集的数据是怎样存放到SRAM中的?

没有DMA

1.如果没有DMA,CPU传输数据还要以内核作为中转站,比如要将ADC采集的数据转移到到SRAM中,这个过程是这样的:

内核通过DCode经过总线矩阵协调,从获取AHB存储的外设ADC采集的数据,

然后内核再通过DCode经过总线矩阵协调把数据存放到内存SRAM中。

“详解STM32中的DMA原理"

有DMA传输

有DMA的话:

1)DMA传输时外设对DMA控制器发出请求。

2)DMA控制器收到请求,触发DMA工作。

3)DMA控制器从AHB外设获取ADC采集的数据,存储到DMA通道中

4)DMA控制器的DMA总线与总线矩阵协调,使用AHB把外设ADC采集的数据经由DMA通道存放到SRAM中,这个数据的传输过程中,完全不需要内核的参与,也就是不需要CPU的参与。

“详解STM32中的DMA原理"

我们把上面的步骤专业一点介绍:

在发生一个事件后,外设向DMA控制器发送一个请求信号。DMA控制器根据通道的优先权处理请求。当DMA控制器开始访问发出请求的外设时,DMA控制器立即发送给它一个应答信号。当从DMA控制器得到应答信号时,外设立即释放它的请求。一旦外设释放了这个请求,DMA控制器同时撤销应答信号。DMA传输结束,如果有更多的请求时,外设可以启动下一个周期。

总之,每次DMA传送由3个操作组成:

  • 从外设数据寄存器或者从当前外设/存储器地址寄存器指示的存储器地址取数据,第一次传输时的开始地址是DMA_CPARx或DMA_CMARx寄存器指定的外设基地址或存储器单元;
  • 存数据到外设数据寄存器或者当前外设/存储器地址寄存器指示的存储器地址,第一次传输时的开始地址是DMA_CPARx或DMA_CMARx寄存器指定的外设基地址或存储器单元;
  • 执行一次DMA_CNDTRx寄存器的递减操作,该寄存器包含未完成的操作数目。

DMA传输方式

方法1:DMA_Mode_Normal,正常模式,

当一次DMA数据传输完后,停止DMA传送 ,也就是只传输一次 

方法2:DMA_Mode_Circular ,循环传输模式

当传输结束时,硬件自动会将传输数据量寄存器进行重装,进行下一轮的数据传输。也就是多次传输模式

仲裁器

“详解STM32中的DMA原理"

仲裁器的作用是确定各个DMA传输的优先级。

仲裁器根据通道请求的优先级来启动外设/存储器的访问。

优先权管理分2个阶段:

软件:每个通道的优先权可以在DMA_CCRx寄存器中设置,有4个等级:

  • 最高优先级
  • 高优先级
  • 中等优先级
  • 低优先级;

硬件:如果2个请求有相同的软件优先级,则较低编号的通道比较高编号的通道有较高的优先权。比如:如果软件优先级相同,通道2优先于通道4。

注意:在大容量产品和互联型产品中,DMA1控制器拥有高于DMA2控制器的优先级。

DMA数据流(仅存在于STM32F4 /M4 内核上)

在设置了DMA的通道之后,还要选择通道对应外设的数据流。

8 个 DMA 控制器数据流都能够提供源和目标之间的单向传输链路。每个数据流配置后都可以执行:

● 常规类型事务:存储器到外设、外设到存储器或存储器到存储器的传输。

● 双缓冲区类型事务:使用存储器的两个存储器指针的双缓冲区传输(当 DMA 正在进行自/至缓冲区的读/写操作时,应用程序可以进行至/自其它缓冲区的写/读操作)。要传输的数据量(多达 65535)可以编程,并与连接到外设 AHB 端口的外设(请求 DMA 传输)的源宽度相关。每个事务完成后,包含要传输的数据项总量的寄存器都会递减。

DMA_SxCR 寄存器控制数据流到底使用哪一个通道,每个数据流有 8 个通道可供选择,每次只能选择其中一个通道进行 DMA 传输。接下来,我们看看 DMA2 的各数据流通道映射表,如表 28.1.1 所示:

“详解STM32中的DMA原理"

DMA 传输通道

每个通道都可以在有固定地址的外设寄存器和存储器地址之间执行DMA传输。DMA传输的数据 量是可编程的,大达到65535。包含要传输的数据项数量的寄存器,在每次传输后递减。

可编程的数据量:

外设和存储器的传输数据量可以通过DMA_CCRx寄存器中的PSIZE和MSIZE位编程。

指针递增模式

根据 DMA_SxCR 寄存器中 PINC 和 MINC 位的状态,外设和存储器指针在每次传输后可以自动向后递增或保持常量。当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值。

通过单个寄存器访问外设源或目标数据时,禁止递增模式十分有用。

如果使能了递增模式,则根据在 DMA_SxCR 寄存器 PSIZE 或 MSIZE 位中编程的数据宽度,下一次传输的地址将是前一次传输的地址递增 1个数据宽度、2个数据宽度或 4个数据宽度。

存储器到存储器模式

DMA通道的操作可以在没有外设请求的情况下进行,这种操作就是存储器到存储器模式。

当设置了DMA_CCRx寄存器中的MEM2MEM位之后,在软件设置了DMA_CCRx寄存器中的EN位启动DMA通道时,DMA传输将马上开始。当DMA_CNDTRx寄存器变为0时,DMA传输结束。存储器到存储器模式不能与循环模式同时使用。

这里要注意仅 DMA2 的外设接口可以访问存储器,所以仅 DMA2 控制器支持存储器到存储器的传输,DMA1 不支持。

存储器到存储器模式不能与循环模式同时使用。

DMA中断

每个DMA通道都可以在DMA传输过半、传输完成和传输错误时产生中断。为应用的灵活性考虑,通过设置寄存器的不同位来打开这些中断。

“详解STM32中的DMA原理"

使没开启,我们也可以通过查询这些位来获得当前 DMA 传输的状态。这里我们常用的是 TCIFx位,即数据流 x 的 DMA 传输完成与否标志。

可编程的数据传输宽度、对齐方式和数据大小端。

当PSIZE和MSIZE不相同时,DMA模块按照下图进行数据对齐。

注意:在大容量产品中, DMA2 通道 4 和 DMA2 通道 5 的中断被映射在同一个中断向量上。在互联型产品 中, DMA2 通道 4 和 DMA2 通道 5 的中断分别有独立的中断向量。所有其他的 DMA 通道都有自己的中断向量。

DMA的内存占用

在STM32控制器中,芯片采用Cortex-MX架构,总线结构有了很大的优化,DMA占用另外的地址总线,并不会与CPU的系统总线发生冲突。也就是说,DMA的使用不会影响CPU的运行速度。

但是要注意:

DMA控制器和Cortex-M3核共享系统数据总线执行直接存储器数据传输。当CPU和DMA同时访问相同的目标(RAM或外设)时,DMA请求可能会停止 CPU访问系统总线达若干个周期,总线仲裁器执行循环调度,以保证CPU至少可以得到一半的系统总线(存储器或外设)带宽。

DMA配置部分

此部分我们分为DMA寄存器和DMA库函数分别介绍:

DMA寄存器

DMA配置参数包括:通道地址、优先级、数据传输方向、存储器/外设数据宽度、存储器/外设地址是否增量、循环模式、数据传输量。

DMA中断状态寄存器(DMA_ISR)

“详解STM32中的DMA原理"

我们如果开启了 DMA_ISR 中这些中断,在达到条件后就会跳到中断服务函数里面去,即使 没开启,我们也可以通过查询这些位来获得当前 DMA 传输的状态。这里我们常用的是 TCIFx, 即通道 DMA 传输完成与否的标志。

注意此寄存器为只读寄存器,所以在这些位被置位之后,只 能通过其他的操作来清除。

DMA中断标志清除寄存器(DMA_IFCR)

“详解STM32中的DMA原理"

DMA_IFCR 的各位就是用来清除 DMA_ISR 的对应位的,通过写 0 清除。在 DMA_ISR 被置位后, 我们必须通过向该位寄存器对应的位写入 0 来清除。

DMA通道x配置寄存器(DMA_CCRx)

“详解STM32中的DMA原理"

该寄存器控制着 DMA 的很多相关 信息,包括数据宽度、外设及存储器的宽度、通道优先级、增量模式、传输方向、中断允许、 使能等都是通过该寄存器来设置的。所以 DMA_CCRx 是 DMA 传输的核心控制寄存器。

DMA通道x传输数量寄存器(DMA_CNDTRx)(x = 1…7)

“详解STM32中的DMA原理"

这个寄存器控制 DMA 通道 x 的每次 传输所要传输的数据量。其设置范围为 0~65535。并且该寄存器的值会随着传输的进行而减少, 当该寄存器的值为 0 的时候就代表此次数据传输已经全部发送完成了。所以可以通过这个寄存 器的值来知道当前DMA 传输的进度。

DMA通道x外设地址寄存器(DMA_CPARx)(x = 1…7)

“详解STM32中的DMA原理"

该寄存器用来存储 STM32 外设的地 址,比如我们使用串口 1,那么该寄存器必须写入 0x40013804(其实就是&USART1_DR)。如果使 用其他外设,就修改成相应外设的地址就行了。

DMA通道x配置寄存器(DMA_CMARx)

“详解STM32中的DMA原理"

该寄存器和 DMA_CPARx 差不多, 但是是用来放存储器的地址的。比如我们使用 SendBuf[5200]数组来做存储器,那么我们在 DMA_CMARx 中写入&SendBuff 就可以了。

DMA寄存器配置流程

通道配置过程 下面是配置DMA通道x的过程(x代表通道号):

1、在DMA_CPARx寄存器中设置外设寄存器的地址。发生外设数据传输请求时,这个地址将 是数据传输的源或目标。

2、在DMA_CMARx寄存器中设置数据存储器的地址。发生外设数据传输请求时,传输的数 据将从这个地址读出或写入这个地址。

3、在DMA_CNDTRx寄存器中设置要传输的数据量。在每个数据传输后,这个数值递减。

4、在DMA_CCRx寄存器的PL[1:0]位中设置通道的优先级。

5、在DMA_CCRx寄存器中设置数据传输的方向、循环模式、外设和存储器的增量模式、外 设和存储器的数据宽度、传输一半产生中断或传输完成产生中断。

6、设置DMA_CCRx寄存器的ENABLE位,启动该通道。

一旦启动了DMA通道,它既可响应连到该通道上的外设的DMA请求。当传输一半的数据后,半传输标志(HTIF)被置1,当设置了允许半传输中断位(HTIE)时,将产生 一个中断请求。在数据传输结束后,传输完成标志(TCIF)被置1,当设置了允许传输完成中断位 (TCIE)时,将产生一个中断请求。

DMA库函数

1.DMA初始化函数

DMA_DeInit(DMAX_ChannelX);

功能:将DMAyChannelx寄存器的初始化为其默认值

注释:RCC_ResetCmd中对DMA无定义,因此采用的直接操纵DMA寄存器的方式

void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx,  DMA_InitTypeDef* DMA_InitStruct)

功能:设置要开启的通道,还有一些参数,包括外设基地址,存储器基地址,传输的数据量,增量模式,数据宽度等。

具体看下方结构体代码介绍:

typedef struct {  
 uint32_t DMA_PeripheralBaseAddr;   
 /*设置DMA源地址*/
 uint32_t DMA_MemoryBaseAddr;       
 /*设置DMA目的地址*/
 uint32_t DMA_DIR; 
 /* 设置数据传输方向,决定是从外设读取数据到内存还送从内存读取数 据发送到外设,也就是外设是源地还是目的地
 */                       
 uint32_t DMA_BufferSize;      
 /*设置传输大小*/    
 uint32_t DMA_PeripheralInc;       
 /*设置ReceiveBuff地址是否自增*/      
 uint32_t DMA_MemoryInc; 
 /*设置传输数据时候内存地址是否递,需要开启*/       
 uint32_t DMA_PeripheralDataSize;   
 /*外设的数据长度是为字节传输(8bits),半 字传输(16bits) 还是字传输(32bits) */    
 uint32_t DMA_MemoryDataSize;    
   /*设置内存的数据长度*/
 uint32_t DMA_Mode;      
 /*设置DMA的模式,正常模式/循环模式  是否循环发送*/        
 uint32_t DMA_Priority; 
  /*设置 DMA 通道的优先级,有低,中,高,超高四种模式*/        
 uint32_t DMA_M2M;    
  /*设置是否是存储器到存储器模式传输,*/       }
 DMA_InitTypeDef; 

2.DMA使能函数

void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState  NewState);

功能:使能或者失能DMA外设

例如:DMA_Cmd(DMA1_Channel1 , ENABLE);

3.DMA中断使能函数

void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT,  FunctionalState NewState);
//DMA_IT_TC:传输完成 DMA_IT_HT:传输一半 DMA_IT_TE:传输错误

功能:配置指定的DMAy通道x的中断

例如:DMA_ITConfig(DMA1_Channel1 , DMA_IT_TC , ENABLE);

4.设置CNDTRx和读CNDTRx函数 (通道传输数据量)

void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t  DataNumber);
uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);

作用:前者设置DMA通道的传输数据量(DMA处于关闭状态);后者获取当前DMA通道传输剩余数据量(DMA处于开启状态)。

DMA库函数配置过程:

  • 使能DMA时钟:RCC_AHBPeriphClockCmd();
  • 初始化DMA通道:DMA_Init();
    • //设置通道;传输地址;传输方向;传输数据的数目;传输数据宽度;传输模式;优先级;是否开启存储器到存储器。
  • 使能外设DMA
    • 以串口为例:使能串口DMA发送,串口DMA使能函数。调用函数:USART_DMACmd();
  • 使能DMA通道传输;函数:DMA_Cmd();
  • 查询DMA传输状态。函数:DMA_GetFlagStatus();
  • 获取当前剩余数据量大小 函数: DMA_GetCurrDataCounter(DMA1_Channel4);

UART DMA传输

DMA就是一个搬运工,可以将数据从一个位置搬运到另一个位置。

以UART为例,如果要接收数据,会触发UART中断,然后CPU介入,在中断中通过CPU将UART输入寄存器的值读出来,存放到内存中;

而DMA方式,产生UART中断后,DMA直接参与,把UART输入寄存器的值搬运到内存中,CPU只需要在去检查内存的值就好了,这样提高了CPU的效率。

DMA代码配置

①DMA初始化配置

void dma_init()
{

DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);


/*DMA配置*/


DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;//串口数据寄存器地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SendBuff; //内存地址(要传输的变量的指针)
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //方向(从内存到外设)
DMA_InitStructure.DMA_BufferSize = 500; //传输内容的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址不增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址自增
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_Byte ; //外设数据单位
DMA_InitStructure.DMA_MemoryDataSize =
DMA_MemoryDataSize_Byte ; //内存数据单位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ; //DMA模式:一次传输,循环
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium ; //优先级:高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止内存到内存的传输

DMA_Init(DMA1_Channel4, &DMA_InitStructure); //配置DMA1的4通道
DMA_Cmd(DMA1_Channel4,ENABLE);
DMA_SetCurrDataCounter(DMA_CH4,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小
DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);//配置DMA发送完成后产生中断

}

DMA中断

void DMA1_Channel4_IRQHandler(void)
{
  if(DMA_GetFlagStatus(DMA1_FLAG_TC4)==SET)
  {

    DMA_ClearFlag(DMA1_FLAG_TC4);
  }
}

main函数

#define SEND_BUF_SIZE 500  //发送数据长度,最好等于sizeof(TEXT_TO_SEND)+2的整数倍.

u8 SendBuff[SEND_BUF_SIZE];  //发送数据缓冲区
const u8 TEXT_TO_SEND[]={"STM32F1 DMA 串口实验"};
 uint16_t i;
int main(void)
{     
  uart_init(115200);     //串口初始化为115200

  for(i=0;i<500;i++)
  {
  SendBuff[i] =0xaf;
  }  
  USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);  //使能串口dma传输 

  while(1);
}

————————————————
版权声明:本文为CSDN博主「Z小旋」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
https://blog.csdn.net/as480133937/article/details/104927922
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 1583

1、序言

很早前就想实现这个红外遥控自学习的这个实验,用于来自己控制房子里如空调等红外遥控设备的自动化,NEC的标准到具体的产品上可能就被厂家定义为不一样了,所以自学习就应该是接收到什么就发送什么,不用管内容是什么!

2、硬件实现原理

“STM32之红外遥控信号自学习实现"

由上述原理图可知,当IE为高电平时发送红外光,为低电平时不发送红外光。

在NEC协议中,信息传输是基于38K载波,也就是说红外线是以载波的方式传递。

发送波形如下图所示:

“STM32之红外遥控信号自学习实现"

NEC协议规定:

发送协议数据“0” = 发送载波560us + 不发送载波560us

发送协议数据“1” = 发送载波560us+ 不发送载波1680us

发送引导码 = 发送载波9000us + 不发送载波4500us

在红外接收端,如果接收到红外38K载波,则IR输出为低电平,如果不是载波包括固定低电平和固定高电平则输出高电平。在IR端接收的信号如下所示:

“STM32之红外遥控信号自学习实现"

“STM32之红外遥控信号自学习实现"

3、软件实现自学习

设计原理:

“STM32之红外遥控信号自学习实现"

1、 根据接收波形记录电平和电平持续时间,以便于发送。

2、电平记录采用定时器捕获功能,从下降沿接收引导信号开始,每触发一次改变触发方式,从而使每个电平变化都能捕获到。

源码实现如下:

定时器捕获初始化设置(CubeMax软件自动配置生成):

void MX_TIM4_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_IC_InitTypeDef sConfigIC = {0};


htim4.Instance = TIM4;
htim4.Init.Prescaler = 71;
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
htim4.Init.Period = 10000;
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_IC_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim4, &sConfigIC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}


}

定时器捕获中断回调处理:

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
    {
if(TIM4->CCER & (TIM_CCER_CC4P))   //下降沿触发
        {
            TIM4->CCER &= ~(TIM_CCER_CC4P); //切换
            gu8BitVal = 1;
        }
else                               //上升沿触发
        {
            TIM4->CCER |= TIM_CCER_CC4P;    //切换
            gu8BitVal = 0;
        }




if(gsInfrared.State == NONE_STATE)
        {
            gsInfrared.State = RECV_STATE;
        }
else if(gsInfrared.State == RECV_STATE)
        {
            NowTimCnt = HAL_TIM_ReadCapturedValue(&htim4, TIM_CHANNEL_4);
            gsInfrared.KeepTime[gsInfrared.SampleCount] = Round(NowTimCnt);
            gsInfrared.BitValue[gsInfrared.SampleCount ++] = gu8BitVal;
        }


        TIM4->CNT = 0;
    }
}

3、设置的定时器溢出时间为10ms,如果10毫秒内不再接收电平变化则默认接收结束,设置结束标志。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim4)
    {
if(gsInfrared.State == RECV_STATE)
        {
            gsInfrared.State = END_STATE;
        }
    }
}

至此,实现了红外遥控的学习功能,获得的记录数据为记录长度和电平信号数组与电平信号维持的时间数组。

“”

“”

4、发送实现

设置定时器输出38KPWM信号,在记录电平为0是输出记录时间的38K载波信号,如果为1则不输出载波,实现如下:

PWM生成设置(CubeMax自动配置生成):

void MX_TIM5_Init(void)
{
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};


  htim5.Instance = TIM5;
  htim5.Init.Prescaler = 0;
  htim5.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim5.Init.Period = 1896;
  htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_PWM_Init(&htim5) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_TIM_MspPostInit(&htim5);


}

发送实现,注意点就是记录为0时发载波,记录为1时不发载波:

void InfraredSend(void)
{
uint16_t Count = 0;

while(Count < gsInfrared.SampleCount &&  gsInfrared.State == END_STATE)
    {
if(gsInfrared.BitValue[Count] == 0)
        {
            TIM5->CCR2 = 948;
            delay_us(gsInfrared.KeepTime[Count]);
            TIM5->CCR2 = 0;
        }
else
        {
            TIM5->CCR2 = 0;
            delay_us(gsInfrared.KeepTime[Count]);
            TIM5->CCR2 = 0;
        }


        Count ++;
    }


    delay_us(20000);
}

往PWM比较寄存器设置948即为设置38KPWM波,也可在初始化时固定948,在此函数内启停定时器即可;

至此,自学习功能的全部思路已实现,通过对各个不同类型的红外遥控进行功能测试,均成功。

PS:查看很多资料发现很多红外解码未判断低电平时间,个人感觉不是很好,应该是不仅高电平时间得符合,低电平时间也应该符合。

自己写了一个小函数验证了一下,这个函数只是验证,未经仔细推敲,还可优化,仅供参考这一思想。

误差设计:±200us(拍脑袋值)

void InFraredDataDeal(void)
{
uint32_t DataBuff = 0;
uint16_t Count = 0;


if(gsInfrared.State == END_STATE)
    {
        gsInfraredData.State = 0;


do
        {
switch(gsInfraredData.State)
            {
case 0:   //引导码识别
            {


if(gsInfrared.KeepTime[0] >= 8800 && gsInfrared.KeepTime[0] <= 9200 && gsInfrared.BitValue[0] == 0)
                {
if(gsInfrared.KeepTime[1] >= 4300 && gsInfrared.KeepTime[1] <= 4700 && gsInfrared.BitValue[1] == 1)
                    {
if(gsInfrared.KeepTime[2] >= 360 && gsInfrared.KeepTime[2] <= 760 && gsInfrared.BitValue[2] == 0)
                        {
                            Count = 3;
                            gsInfraredData.State = 1;
                        }
                    }
else if(gsInfrared.KeepTime[1] >= 2300 && gsInfrared.KeepTime[1] <= 2700 && gsInfrared.BitValue[1] == 1)
                    {
if(gsInfrared.KeepTime[2] >= 360 && gsInfrared.KeepTime[2] <= 760 && gsInfrared.BitValue[2] == 0)
                        {
                            gsInfraredData.ReDataCount ++;
                            gsInfraredData.State = 3;
                        }
                    }
else
                    {
                        gsInfraredData.State = 3;
                    }


                }
else
                {
                    gsInfraredData.State = 3;
                }




            }
break;




case 1:   //数据解析
            {


if(gsInfrared.KeepTime[Count + 1] >= 360 && gsInfrared.KeepTime[Count + 1] <= 760 && gsInfrared.BitValue[Count + 1] == 0)
                {


if(gsInfrared.BitValue[Count] == 1)
                    {
if(gsInfrared.KeepTime[Count] >= 1480 && gsInfrared.KeepTime[Count] <= 1880)
                        {
                            DataBuff <<= 1;
                            DataBuff |= 1;
                        }
else if(gsInfrared.KeepTime[Count] >= 360 && gsInfrared.KeepTime[Count] <= 760 && gsInfrared.BitValue[Count] == 1)
                        {
                            DataBuff <<= 1;
                            DataBuff |= 0;
                        }
else
                        {
                            gsInfraredData.State = 3;
                        }
                    }
                }


if(Count < gsInfrared.SampleCount)
                {
                    Count += 2;
                }
else
                {
                    gsInfraredData.State = 2;
                }


            }
break;


case 2:   //成功解析
            {
                gsInfraredData.Data = DataBuff;
                gsInfraredData.State = 3;


            }
break;


default:
            {
                gsInfraredData.State = 3;   //解析结束


            }
break;
            }


        }
while(gsInfraredData.State != 3);


        gsInfrared.State = NONE_STATE;
        gsInfrared.SampleCount = 0;
    }


}

解析的话一般高位在前,所以左移,经测试帧格式为:引导码+用户码+用户码反码+命令码+命令码反码,能成功解析数据!解析的话根据具体协议,具体分析。

来源:博客园(博主:树荫下的阳光)
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 410

可能很多人都不习惯使用Keil、IAR自带的编辑器,可能代码补全、错误提示、高亮等编辑功能相对来说支持的不是很好。

虽然Keil MDK 从 V5.25版本开始对编辑功能改善了很多,但是很多人还是青睐于第三方的编辑器。

使用第三方的编辑器,如果需要编译和下载,就需要借助通过额外的方式实现,比如本文即将描述的通过命令行编译和下载的方式,可以让我们在使用第三方编辑器编辑的时候,进行代码编译和下载。

下面我们来描述以下内容:

  • 常用代码编辑器

  • Keil 命令行编译下载

  • IAR 命令行编译下载

  • 编译下载使用方法

1、常用的代码编辑器

下面介绍几款常用的代码编辑器:

1.VS Code

VS Code 是绝大部分软件工程师都在使用的一款软件编辑器工具,VS Code 全称 Visual Studio Code,是微软开发的一套免费、轻量级、功能强大的源代码编辑器工具。

网址:
https://code.visualstudio.com

“STM32通过命令行编译和下载

2.Source Insight

Source Insight是一款功能强大的代码编辑器、浏览器和分析器,可在你代码编辑时快速理解代码。同时,Source Insight具有针对C/C++、 C#、 Java、Objective-C等语言的动态分析功能。

网址:

https://www.sourceinsight.com

“STM32通过命令行编译和下载

3.Vim

Vim是从 vi 发展出来的一个文本编辑器,它是一个高度可配置的文本编辑器工具,旨在使创建和更改任何类型的代码(和文本)非常高效。在大多数UNIX、Linux系统和Apple OS X中,都集成了Vi。

网址:

http://www.vim.org

“STM32通过命令行编译和下载

4.Sublime Text

Sublime Text 也是一款优秀的、轻量级的跨平台的编辑器。它是一个跨平台的编辑器,支持windows、linux和Mac操作系统。

网址:

https://www.sublimetext.com

“STM32通过命令行编译和下载

2、Keil 命令行编译下载

编译:

UV4 〚command〛 〚projectfile〛 〚options〛
UV4.exe -r Blinky.uvproj -o Build_Output.txt

UV4.exe : 前面需要补全路径
-r Blinky.uvproj :Keil 工程名
-o Build_Output.txt:输出文档

下载:

UV4.exe -f Programming.UVPROJ -o Prg_Output.txt\

参考资料:
http://www.keil.com/support/man/docs/uv4/uv4_commandline.htm

3、IAR 命令行编译下载

编译:

IarBuild.exe test.ewp -build Debug -log all

IarBuild.exe :前面需要补全路径
test.ewp :工程名,注意是.ewp结尾的。
-build Debug :表示build
-log all :打印所有,可以设置 -log info

下载:

在Setting 文件夹下面有一个.cspy的bat文件,在后面加上参数 "--download_only",前提是在IAR下面都配置好了,并且成功下载过一次的工程。

--download_only

4、使用方法

我们可以在工程所在的路径下面编写bat文件,通过直接运行bat就可以编译和下载了,第三方编辑器通常都可以配置编译选项和调试选项,也可以配置在Tool里面进行编译下载,我比较喜欢使用powershell进行编译和下载。

可能每个人习惯不同,对工具的使用也不同,这种方法,如果感兴趣你可以试试。

参考来源:
https://www.cnblogs.com/memorypro/p/9562919.html

编排 | strongerHuang
微信公众号 | 嵌入式专栏
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 893

本应用笔记中包含的一些指南用于检验下表列出的所选STM32微控制器(MCU)中嵌入的RNG外设生成的数字的随机性。

详阅请点击下载《使用NIST统计测试集验证STM32微控制器随机数生成》

来源:ST
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 21

开发低功耗产品,我们会比较关注整个系统的功耗问题。那么,LPTIM低功耗定时器你有关注吗?

1、写在前面

在早些年,可能较少听见LPTIM这个名词。随着低功耗产品需求越来越严格,MCU厂商就推出了针对低功耗应用的LPTIM定时器。

定时器是我们常见的一种外设,之所以这么常见,原因在于定时器的用途非常广泛。

在STM32所有MCU中都配有定时器,那么你有关注、对比过各系列,各型号MCU中定时器的差异吗?

2、哪些STM32配有LPTIM定时器

在STM32中,相对较新的MCU部分型号配有LPTIM定时器。

比如:STM32F7、H7高性能MCU,STM32L0、 L4低功耗MCU,以及新推出的G0、G4系列中都配有这种LPTIM定时器。

具体哪些MCU配有LPTIM,大家可以下载对应的数据手册查看。

本文围绕STM32G0讲述其中的LPTIM定时器。

3、LPTIM功能

LPTIM:Low-power timer,即低功耗定时器。

LPTIM 是一个 16 位定时器,得益于其定时器的低功耗。

由于 LPTIM 的时钟源具有多样性,因此 LPTIM 能够在所有电源模式(待机模式除外)下保持运行状态。

即使没有内部时钟源, LPTIM 也能运行,鉴于这一点,可将其用作“脉冲计数器”,这种脉冲计数器在某些应用中十分有用。

此外, LPTIM 还能将系统从低功耗模式唤醒,因此非常适合实现“超时功能”,而且功耗极低。

LPTIM 引入了一个灵活的时钟方案,该方案能够提供所需的功能和性能,同时还能最大程度地降低功耗。

我仔细对比了一下STM32各系列的LPTIM低功耗定时器,发现很多功能基本一样。

1)框图

STM32G0低功耗定时器框图:

“STM32低功耗定时器(LPTIM)有哪些独特功能?"

STM32L0低功耗定时器框图:

“STM32低功耗定时器(LPTIM)有哪些独特功能?"

对比框图,可以发现这个LPTIM片上外设有相似之处。

当然,有些细节是不一样的,像在STM32H7中有多个LPTIM,这几个LPTIM之间是有一定差异的。

2)LPTIM 主要特性

  • 16 位递增计数器

  • 3 位预分频器,可采用 8 种分频系数(1、 2、 4、 8、 16、 32、 64 和 128)

  • 可选时钟

– 内部时钟源:LSE、 LSI、 HSI 或 APB 时钟

– LPTIM 输入的外部时钟源(在没有 LP 振荡器运行的情况下工作,可在使用脉冲计数器应用场景中使用)

  • 16 位 ARR 自动重载寄存器

  • 16 位比较寄存器

  • 连续/单触发模式

  • 可选软件/硬件输入触发

  • 可编程数字防抖动干扰滤波器

  • 可配置输出:脉冲和 PWM

  • 可配置 I/O 极性

  • 编码器模式

拿这些特性和其它基本定时器相对较,你会发现,这些特性中很多都是LPTIM独有的。

3)LPTIM RCC

LPTIM的RCC和其他定时器相比较,其RCC功能更加丰富。

通过上面框图可以发现,LPTIM 可通过多个时钟源提供时钟。

它可以由内部时钟信号提供时钟,内部时钟信号可通过复位和时钟控制器 (RCC) 在 APB、 LSI、 LSE 或 HSI 时钟源中进行选择。

4)干扰滤波器

这个功能也是LPTIM所特有的一个功能。

LPTIM 输入由数字滤波器保护,避免任何毛刺和噪声干扰在 LPTIM 内部传播,从而防止产生意外计数或触发。

滤波示意图:

“STM32低功耗定时器(LPTIM)有哪些独特功能?"

这个原理比较简单,如果不能理解请查看参考手册详解。

LPTIM定时器的功能比较多,可能初学者一看到那么多内容就吓到了。其实,把内容拆开来看并不难。

本文旨在让更多朋友知道这些功能,想要深入掌握其中知识,需结合手册和实践编程。

来源:strongerHuang
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 774
  • 扩展后的STM32Cube 生态系统可支持 STM32WB 无线 MCU
  • 新的 STM32CubeWB 固件,升级的编程器和射频测试工具
  • 改进的无线功耗估算器准确计算电池续航时间

服务多重电子应用领域的全球半导体领导者意法半导体(STMicroelectronics,简称ST;纽约证券交易所代码:STM) 发布了新的STM32WB无线微控制器(MCU)开发工具和软件,为智能建筑、智能工业和智能基础设施的开发者降低设计经济、节能的无线设备的难度。

“意法半导体市场领先的

意法半导体的高集成度 STM32WB 单片集成一个 2.4GHz射频收发器和Arm® Cortex®-M4 和Cortex-M0+ 双核微控制器,从而消除了诸多射频电路设计挑战,因为射频电路设计会增加项目的开发时间,而且会给项目开发带来很多不确定性。而用STM32WB开发硬件设计只需要少量的外部组件,例如,选择天线。STM32WB MCU 配备许多外设,包括 12 位模数转换器 (ADC)、数字接口和无晶振 USB 2.0 全速接口,具体根据所选型号而定。芯片支持的协议包括 Bluetooth® LE 5.2、Zigbee®、OpenThread 和专有协议,包括这些协议组合的并发模式。

STM32家族是市场领先的Arm Cortex-M微控制器,作为该产品家族的成员,STM32WB 基于经过市场检验的、受到广泛支持的开发工具和软件资源丰富的STM32Cube 生态系统。

意法半导体 STM32 无线市场总监 Hakim Jaafar 表示:“STM32Cube 生态系统已经被广泛使用,并得到第三方开发者资源的广泛支持,这有助于加快项目开发。我们新推出的经过强化的无线产品扩展了 STM32 系列处理新需求和用例的能力,进一步增强了稳健的STM32 解决方案的市场领先地位。”

技术详情:生态系统新特性助力无线设计

STM32WB 生态系统加强了对无线设计的支持力度,提供了所有必要的嵌入式软件模块和工具,让用户可以轻松地开发应用。在STM32CubeWB MCU软件包里面有很多代码示例,并提供一整套外设驱动程序(HAL 和 LL)和所有的必要的射频协议栈,包括用于蓝牙 5.2、Zigbee 3.0、OpenThread v1.1 和专有协议的 802.15.4 MAC,以及多个实现这些协议栈并发模式(静态和/或动态)的例程。STM32CubeMX and STM32CubeIDE等软件工具的GUI界面直接支持射频协议栈,方便访问和配置这些协议栈。用户可以轻松地选择和配置Profiles和Clusters,以支持主流的标准,并受益于现成的代码示例。

STM32CubeMX 配置器为功耗估算工具增加了额外的控制功能,有助于计算射频子系统对整体功耗预算的影响。用户可以设置各种场景来准确评估电池续航时间。

此外还有更多新功能,例如,STM32Cube 编程器的强化功能可以优化对STM32WB 双核架构的编程功能,利用Cortex-M0+ 处理器与Cortex-M4 主内核一起控制射频子系统,确保实时应用性能。

借助 STM32CubeMonitor-RF评估工具,生态系统将开发过程拓展到在客户环境中高效安装射频并测试性能。STM32CubeMonitor-RF 支持Bluetooth® LE和通用 802.15.4 射频技术,可执行收发测试和射频性能测量,并协助编写测试脚本、测试协议和命令序列。最新版本为 802.15.4 协议引入了侦测器功能,降低网状网络产品的开发难度。

STM32CubeWB 无线生态系统中的所有工具和射频协议栈都取得了相关认证并免费提供,以及随附蓝牙 5.2 和 802.15.4 认证项目的详细说明文档,使客户能够快速且经济地获得适用的射频产品许可证书。

STM32WB 无线微控制器生态系统还包含一套 STM32WB 无线微控制器评估板,帮助用户加快无线产品的开发速度。

含有Nucleo-64开发板和USB适配器、NUCLEO-WB55RG 开发板和 NUCLEO-WB15CC Nucleo-64 开发板的P- NUCLEO-WB55开发套件,以及 STM32WB5MM-DK探索套件 ,为用户提供立即开发应用的各种功能,适合各种无线应用。

使用同一系列芯片,各种应用设计都可以共用同一个基础设计,充分利用产品开发和认证投资。

STM32WB 产品的灵活性很高,从高端到成本敏感的不同类型产品均可使用,应用前景广阔。

详情访问www.st.com/stm32wb.

关于意法半导体

意法半导体拥有46,000名半导体技术的创造者和创新者,掌握半导体供应链和先进的制造设备。作为一家独立的半导体设备制造商,意法半导体与十万余客户、数千名合作伙伴一起研发产品和解决方案,共同构建生态系统,帮助他们更好地应对各种挑战和新机遇,满足世界对可持续发展的更高需求。意法半导体的技术让人们的出行更智能,电力和能源管理更高效,物联网和5G技术应用更广泛。详情请浏览意法半导体公司网站:www.st.com

围观 20

页面

订阅 RSS - STM32