STM32-DMA(软件出发、硬件触发)

这篇具有很好参考价值的文章主要介绍了STM32-DMA(软件出发、硬件触发)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

DMA  --为cpu减负

DMA简介

直接存储器存取(DMA)用来提供在外设存储器之间或者存储器和存储器之间的高速数据传输无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调DMA请求的优先权。

存储器和存储器之间的数据转运用软件触发

外设到存储器的数据转运,一般使用硬件触发。

STM32103C8T6 DMA资源:只有DMA1(7个通道)

存储器映像

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机

计算机系统的五大组成部分:运算器、控制器、存储器、输入设备、输出设备,

CPU:运算器和控制器

ROM就是只读存储器,是一种非易失性掉电不丢失的存储器

RAM就是随机存储器,是一种易失性、掉电丢失的存储器

程序存储器Flash,也就是主闪存

DMA主要特性

12个独立的可配置的通道(请求)DMA17个通道,DMA25个通道

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

● 在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推)

● 独立数据源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。

● 支持循环的缓冲器管理

● 每个通道都有3个事件标志(DMA半传输、DMA传输完成和DMA传输出错),这3个事件标志逻辑或成为一个单独的中断请求。

● 存储器和存储器间的传输

● 外设和存储器、存储器和外设之间的传输

● 闪存、SRAM、外设的SRAMAPB1APB2AHB外设均可作为访问的源和目标。

● 可编程的数据传输数目:最大为65535

DMA框图

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机

总线矩阵的左端,是主动单元,也就是拥有存储器的访问权。右边的这些,是被动单元,他们的存储器只能被左边的主动单元读写。主动单元 这里,内核有DCode和系统总线,可以访问右边的存储器。DCode总线是专门访问Flash的,系统总线是访问其他东西的。另外,由于DMA要转运数据,所以DMA也必须要有访问的主动权。那主动单元,除了内核CPU,剩下的就是DMA总线了。

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机

DMA1有一条总线,DMA也有一条总线,下面还有一条DMA总线,这是以太网外设自己私有的DMA,这个可以不用管。

DMA1:有7个通道;DMA2:有5个通道。各个通道可以分别设置他们转运数据的源地址和目的地址,这样它们就可以独立的工作

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机

DMA,即使总线矩阵的主动单元,可以读写各种寄存器,也是AHB总线上的被动单元。CPU通过这一条线路,就可以对DMA进行配置了。

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机

DMA请求:请求就是触发的意思,这条线路右边的触发源,是各个外设,所以DMA请求就是DMA的硬件触发源。(比如ADC转换完成、串口接收到数据,需要触发DMA转运数据的时候,就会通过这条线路,向DMA发出硬件触发信号,之后DMA就可以执行数据转运的工作了)

DMA基本结构

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机

数据转运的两大站点:

外设寄存器站点、存储器站点(Flash,SRAM)

在这里可以看出,DMA的数据转运,可以是从外设到存储器,也可以从存储器到外设。另外,还有一种转运方式,就是存储器到存储器。由于Flash是只读的,所以DMA不可以进行SRAM到Flash,或者Flash到Flash的转运操作

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机

然要进行数据转运,那肯定就要指定从哪里转到哪里,所以外设和存储器两个站点,就都有3个参数第一个参数:外设起始地址、存储器起始地址,这两个参数决定了数据是从哪里来,到哪里去。第二个数据参数:数据宽度,这个参数的作用是,指定一次转运要按多大的数据宽度来进行转运。它可以选择字节、半字、字。字节是8位,也就是一次转运一个uint8_t,这么大的数据;半字是16位,就是一次转运一个uint16_t这么大的数据;字是32位,就是一次转运一个uint32_t这么大的数据。(比如转运ADC的数据,ADC的结果是uint6_t这么大的数据,所以这个参数就要选择半字)。第三个参数:地址是否自增,这个参数的作用就是,指定一次转运完成后,下一次转运,是不是要把地址移动到下一个位置。比如ADC扫描模式,用DMA进行数据转运,外设地址是ADC_DR寄存器,寄存器这边,显然地址是不用自增的,如果自增,那下一次转运就跑到别的寄存器哪里了。存储器,地址就需要自增,每转运一个数据后,就往后挪个坑,要不然下次在转就把上次的覆盖掉了。)

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机

传输计数器

这个东西就是用来指定,我们总共需要转运多少次。他是一个自减计数器(比如你写一个5,那DMA就只能进行5次数据转运,转运过程中,每转运一次,计数器的数就会减1,当减到0之后,DMA就不会进行数据转运了。另外,它减到0之后,之前自增的地址,就会恢复到起始地址的位置,以方便之后DMA开始新一轮的转运

自动重装器

传输计数器减到0之后,是否要自动恢复到最初的值(比如最初传输计数器给5,如果不使用自动重装器,那转运5次后,DMA就结束了;如果使用,就恢复到初值5)。

触发源:

硬件触发、软件触发,具体选择那个,由M2M这个参数决定(M2M是存储器到存储器的意思),当给M2M位1时,DMA就会选择软件触发,这个软件触发并不是调用某一个函数一次,触发一次,他这个软件触发的执行逻辑是,以最快的速度,连续不断地触发DMA,争取早日把传输计数器清零,完成这一轮的转换(软件触发不能和自动重装器同时使用,如果同时使用,DMA就停不下来了)。软件触发一般适用于存储器到存储器的转运,因为存储器到存储器的转运,是软件启动、不需要时机,并且想尽快完成的任务,所以M2M位给1,就是软件触发。当M2M位给0,那就是使用硬件触发。硬件触发源可以选择ADC、串口、定时器等等。使用硬件触发的转运,一般都是与外设有关的转运,这些转运需要一定的时机(比如ADC转换完成、串口收到数据、定时时间到等),所以需要使用硬件触发,在硬件达到这些时机时,传个信号过来,来触发DMA进行转运。

开关控制(DMA_Cmd函数):

当给DMA使能后,DMA就准备就绪,可以进行转运了。DMA进行转运,有几个条件。第一:就是开关控制,DMA_Cmd必须使能;第二:传输计数器必须大于0;第三:必须有触发源信号,触发一次,转运一次,传输计数器自减一次,当传输计数器等于0,且没有自动重装时,这时无论是否触发,DMA都不会在进行转运了。此时就需要DMA_Cmd,给DISABLE,关闭DMA,在为传输计数器写入一个大于0的数,在DMA_Cmd,给ENABLE,开启DMA。(注意:写传输计数器时,必须要先关闭DMA,在进行,不能在DMA开启时,写传输计数器)。

DMA请求

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机

上面做这张图这是DMA1的请求映像,有7个通道。每个通道都有一个数据选择器,可以选择硬件触发或软件触发。

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机

EN控制位就相当于开关控制:EN=0时不工作,EN=1时工作。

当M2M位=1时,选择软件触发。

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机

通道1的硬件触发时ADC1、定时器2的通道3和定时器4的通道1,触发源应该怎么选择是对应的外设是否开启了DMA输出来决定的(比如使用ADC1,哪会有个库函数叫ADC_DMACmd,必须使用这个库函数开启ADC1的这一路输出,它才有效;如果现在定时器2的通道3,那也会有TIM_DMACmd函数,用来进行DMA输出控制)。总之触发源,具体使用那个,就把那个外设的DMA输出开启。之后,这7个触发源(DMA1有7个通道),进入到仲裁器,进行优先级判断,最终产生内部的DMA1请求(默认优先级是通道号越小,优先级越高)。

数据转运+DMA(软件触发)

将SRAM里的数组DataA转运到另一个数组DataB中

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机

地址自增:两个数组地址都要自增

方向:外设站点转运到寄存器站点

传输计数器:在这里,显然要转运7次,所以传输计数器给7,自动重装暂时不需要。

触发选择:软件触发,因为这是存储器到存储器的数据转运,不需要等待硬件时机的,尽快转运完成就行了。最后调用DMA_Cmd,给DMA使能。这里的转运是一种复制转运,转运完成后DataA的数据并不会消失。

代码例程

接线图

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.H"
#include  "dma.h"

uint8_t data[] = {0x01,0x02,0x03,0x04};  //源地址数组
uint8_t buff[] = {0,0,0,0};  //作为目的地址使用,存放转运后的结果


int main(void)
{
	MYDMA_Init((uint32_t)data,(uint32_t)buff,4);
	
	OLED_Init();
	OLED_ShowString(1,1,"data");
	OLED_ShowString(3,1,"buff");
	OLED_ShowHexNum(1,8,(uint32_t)data,8);
	OLED_ShowHexNum(3,8,(uint32_t)buff,8);
	
	OLED_ShowHexNum(2,1,data[0],2);
	OLED_ShowHexNum(2,4,data[1],2);
	OLED_ShowHexNum(2,7,data[2],2);
	OLED_ShowHexNum(2,10,data[3],2);
	
	OLED_ShowHexNum(4,1,buff[0],2);
	OLED_ShowHexNum(4,4,buff[1],2);
	OLED_ShowHexNum(4,7,buff[2],2);
	OLED_ShowHexNum(4,10,buff[3],2);
	
	
	while(1)
	{
		data[0]++;
		data[1]++;
		data[2]++;
		data[3]++;
		
	OLED_ShowHexNum(2,1,data[0],2);
	OLED_ShowHexNum(2,4,data[1],2);
	OLED_ShowHexNum(2,7,data[2],2);
	OLED_ShowHexNum(2,10,data[3],2);
	
	OLED_ShowHexNum(4,1,buff[0],2);
	OLED_ShowHexNum(4,4,buff[1],2);
	OLED_ShowHexNum(4,7,buff[2],2);
	OLED_ShowHexNum(4,10,buff[3],2);
		
	Delay_ms(1000);
		
	MYDMA_Transfer();
		
	OLED_ShowHexNum(2,1,data[0],2);
	OLED_ShowHexNum(2,4,data[1],2);
	OLED_ShowHexNum(2,7,data[2],2);
	OLED_ShowHexNum(2,10,data[3],2);
	
	OLED_ShowHexNum(4,1,buff[0],2);
	OLED_ShowHexNum(4,4,buff[1],2);
	OLED_ShowHexNum(4,7,buff[2],2);
	OLED_ShowHexNum(4,10,buff[3],2);
	Delay_ms(1000);
	}
}
#include "stm32f10x.h"                  // Device header
#include "DMA.h"

uint16_t MYDMA_size;

void MYDMA_Init(uint32_t AddrA,uint32_t AddrB,uint16_t size)
{
	MYDMA_size = size;
	//开启时钟  DMA是AHB总线的设备,所以要用AHB开启时钟的函数
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	
	//void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);
	//定义结构体
	DMA_InitTypeDef DMA_InitStruct = {0};
	
	//给结构体赋值
	DMA_InitStruct.DMA_BufferSize = size;
	DMA_InitStruct.DMA_DIR =  DMA_DIR_PeripheralSRC; //指定外设地址是源地址还是目的地址
	DMA_InitStruct.DMA_M2M = DMA_M2M_Enable;
	DMA_InitStruct.DMA_MemoryBaseAddr = AddrB;
	DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;  //自动重装
	DMA_InitStruct.DMA_PeripheralBaseAddr = AddrA; //外设站点的基地址
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  //传输字节
	DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Enable;  //地址自增
	DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
	
	//将参数写入寄存器
	//这个是存储器到存储器的转运,软件触发,通道可以任意选择
	DMA_Init(DMA1_Channel1,&DMA_InitStruct);   

	//使能DMA
	DMA_Cmd(DMA1_Channel1,DISABLE);

}

void MYDMA_Transfer(void)
{
	//传输计数器赋值,必须要先给DMA使能
	DMA_Cmd(DMA1_Channel1,DISABLE);
	
	//给传输计数器赋值
	DMA_SetCurrDataCounter(DMA1_Channel1,MYDMA_size);
	
	DMA_Cmd(DMA1_Channel1,ENABLE);
	
	while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
	
	DMA_ClearFlag(DMA1_FLAG_TC1);
}


#ifndef _DMA_H_
#define _DMA_H_

void MYDMA_Init(uint32_t AddrA,uint32_t AddrB,uint16_t size);
void MYDMA_Transfer(void);


#endif

ADC扫描模式+DMA(硬件触发)

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机

在这里有7个通道,触发一次,7个通道一次进行AD转换,然后转换结果都放到ADC_DR数据寄存器里。在每个单独的通道转换完成后,进行一个DMA数据转运,并且目的地址进行自增,所以在这里DMA的配置就是,外设地址,写入ADC_DR这个寄存器的地址。存储器的地址,可以在SRAM中定义一个数组,然后把这个数组的地址当作存储器的地址。之后数据宽度,因为ADC_DR和SRAM数组,我们要的都是uint16_t的数据,所以数据宽度都是16位的半字传输。地址自增:外设地址不要自增,存储器地址自增。传输方向,是外设站点到存储器站点。传输计数器,这里通道有7个,所以需要计数7次。计数器是否自动重装,这里可以ADC的配置,ADC如果是单次扫描,那DMA的传输计数器就不要配置自动重装,如果ADC是连续扫描模式,那DMA的传输计数器就需要自动重装。

代码例程

接线图

dma软件触发,STM32标准库开发,stm32,嵌入式硬件,单片机文章来源地址https://www.toymoban.com/news/detail-860655.html

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"

int main(void)
{
	/*模块初始化*/
	OLED_Init();				//OLED初始化
	AD_Init();					//AD初始化
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "AD0:");
	OLED_ShowString(2, 1, "AD1:");
	OLED_ShowString(3, 1, "AD2:");
	OLED_ShowString(4, 1, "AD3:");
	
	while (1)
	{
		OLED_ShowNum(1, 5, AD_Value[0], 4);		//显示转换结果第0个数据
		OLED_ShowNum(2, 5, AD_Value[1], 4);		//显示转换结果第1个数据
		OLED_ShowNum(3, 5, AD_Value[2], 4);		//显示转换结果第2个数据
		OLED_ShowNum(4, 5, AD_Value[3], 4);		//显示转换结果第3个数据
		
		Delay_ms(100);							//延时100ms,手动增加一些转换的间隔时间
	}
}
#include "stm32f10x.h"                  // Device header

uint16_t AD_Value[4];					//定义用于存放AD转换结果的全局数组

/**
  * 函    数:AD初始化
  * 参    数:无
  * 返 回 值:无
  */
void AD_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//开启ADC1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);		//开启DMA1的时钟
	
	/*设置ADC时钟*/
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA0、PA1、PA2和PA3引脚初始化为模拟输入
	
	/*规则组通道配置*/
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);	//规则组序列1的位置,配置为通道0
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);	//规则组序列2的位置,配置为通道1
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);	//规则组序列3的位置,配置为通道2
	ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);	//规则组序列4的位置,配置为通道3
	
	/*ADC初始化*/
	ADC_InitTypeDef ADC_InitStructure;											//定义结构体变量
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;							//模式,选择独立模式,即单独使用ADC1
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;						//数据对齐,选择右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;			//外部触发,使用软件触发,不需要外部触发
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;							//连续转换,使能,每转换一次规则组序列后立刻开始下一次转换
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;								//扫描模式,使能,扫描规则组的序列,扫描数量由ADC_NbrOfChannel确定
	ADC_InitStructure.ADC_NbrOfChannel = 4;										//通道数,为4,扫描规则组的前4个通道
	ADC_Init(ADC1, &ADC_InitStructure);											//将结构体变量交给ADC_Init,配置ADC1
	
	/*DMA初始化*/
	DMA_InitTypeDef DMA_InitStructure;											//定义结构体变量
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;				//外设基地址,给定形参AddrA
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;	//外设数据宽度,选择半字,对应16为的ADC数据寄存器
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;			//外设地址自增,选择失能,始终以ADC数据寄存器为源
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;					//存储器基地址,给定存放AD转换结果的全局数组AD_Value
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;			//存储器数据宽度,选择半字,与源数据宽度对应
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;						//存储器地址自增,选择使能,每次转运后,数组移到下一个位置
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;							//数据传输方向,选择由外设到存储器,ADC数据寄存器转到数组
	DMA_InitStructure.DMA_BufferSize = 4;										//转运的数据大小(转运次数),与ADC通道数一致
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;								//模式,选择循环模式,与ADC的连续转换一致
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;								//存储器到存储器,选择失能,数据由ADC外设触发转运到存储器
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;						//优先级,选择中等
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);								//将结构体变量交给DMA_Init,配置DMA1的通道1
	
	/*DMA和ADC使能*/
	DMA_Cmd(DMA1_Channel1, ENABLE);							//DMA1的通道1使能
	ADC_DMACmd(ADC1, ENABLE);								//ADC1触发DMA1的信号使能
	ADC_Cmd(ADC1, ENABLE);									//ADC1使能
	
	/*ADC校准*/
	ADC_ResetCalibration(ADC1);								//固定流程,内部有电路会自动执行校准
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while (ADC_GetCalibrationStatus(ADC1) == SET);
	
	/*ADC触发*/
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);	//软件触发ADC开始工作,由于ADC处于连续转换模式,故触发一次后ADC就可以一直连续不断地工作
}
#ifndef __AD_H
#define __AD_H

extern uint16_t AD_Value[4];

void AD_Init(void);

#endif

到了这里,关于STM32-DMA(软件出发、硬件触发)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32 硬件SPI+DMA实现快速刷TFT屏

    首先在TB上找一块SPI驱动的彩屏,下载商家提供的示例 例如我买的一款2.8寸SPI的TFT彩屏,商家提供的资料很齐全,模拟SPI和硬件SPI驱动的程序都有 打开硬件SPI驱动的工程,商家提供的代码是SPI2驱动,想换成其他的SPI可以到SPI.c文件中更改 打开main.c,测试一下简单颜色填充刷

    2024年04月15日
    浏览(47)
  • 【STM32】定时器1触发ADC多(规则)通道采样+DMA(CUBEMX配置)

    在用单片机做电源控制时不得不提ADC采集,离散系统是有固定的执行周期的,所以我们采样也是要固定时间去采样。然后就是我希望pwm波(定时器1产出)的频率与采样频率一致。 我下面演示的是G431CBU6,当然其他芯片也大差不差了。 说一下大致流程,TIM1触发ADC采样,然后

    2024年02月01日
    浏览(42)
  • STM32硬件IIC卡死问题和DMA发送数据异常问题

    问题1描述: 一直听说STM32的硬件IIC有问题,我平时做项目一直没有遇到过,这次做项目发现硬件IIC居然会自己卡死,现象就是IIC发不出数据,用逻辑分析仪捕捉不到任何电平,必须要重启单片机才能正常,接下来说一下我的硬件环境:STM32作为主机,IIC总线上挂载这AT24C02和一

    2024年02月03日
    浏览(27)
  • U8g2库的STM32硬件SPI(DMA)移植教程(HAL、OLED显示、四线SPI、DMA)

    本文教你把U8g2图形库移植到STM32上,基于STM32的硬件SPI、CubeMX U8g2库Github网址:https://github.com/olikraus/u8g2 U8g2库CSDN镜像网址:https://gitcode.net/mirrors/olikraus/u8g2?utm_source=csdn_github_accelerator 硬件准备:STM32C8T6(STM32系列芯片)、0.96寸OLED(128×64)、J-Link(或其他) 引脚连接: 出自此

    2024年02月09日
    浏览(41)
  • STM32 TIMER_TRGO触发+ADC采集 + DMA传输 + 中断均方根处理 实现三相电压显示

    STM32 TIMER_TRGO触发+ADC采集 + DMA传输 实现三相电压采集 首先,是实际采集的三相电压值,用excel处理了下: 采集个电压,为什么这么复杂。 开始我也是直接用ADC采集,然后delay,再采集,然后delay,再采集……最后数据处理…… 问题是如果我们用单片机裸跑,每次delay都会卡死

    2024年02月16日
    浏览(33)
  • 一个简单的HAL库STM32使用DMA+硬件IIC驱动0.96寸OLED的方法

    自己在刚入坑嵌入式的时候,加入学校科协的一道免试题是开发一个简易的示波器,当时萌新不会做,中间又在准备比赛没时间,最近帮女朋友做课设需要做一个简易的交流电压表,而且终于有空做一下自己感兴趣的项目了,就想到了之前想做有没得做的一个简易示波器。

    2024年02月19日
    浏览(37)
  • STM32开发(16)----CubeMX配置DMA

    本章介绍使用STM32CubeMX对DMA进行配置的方法,DMA的原理、概念和特点,配置各个步骤的功能,并通过串口DMA传输实验方式验证。 DMA(Direct Memory Access),即直接存储器访问。 DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为

    2024年02月15日
    浏览(39)
  • 【STM32F4系列】【HAL库】【自制库】WS2812(软件部分)(PWM+DMA)

    硬件介绍(PCB设计方案) 模拟时序发送 WS2812是一种异步串行通信,它每一位数据时间是ns级别的 默认是高电平状态 0码:220-380ns高电平+580-1600ns低电平 1码:580-1600ns高电平+220-380ns低电平 复位码:280us低电平 24Bit数据来代表GRB的亮度值 从高位到低位发送,分别按照G-R-B的顺序发送

    2024年02月15日
    浏览(74)
  • STM32CubeMX配置STM32G031多通道ADC + DMA采集(HAL库开发)

     时钟配置HSI主频配置64M  勾选打开8个通道的ADC  使能连续转换模式  添加DMA  DMA模式选择循环模式  使能DMA连续请求 采样时间配置160.5 转换次数为8  配置好8次转换的顺序  配置好串口,选择异步模式 配置好需要的开发环境并获取代码  修改main.c 串口重定向  串口重定向

    2024年02月08日
    浏览(47)
  • STM32CubeMx配置ADC(多通道采集+DMA读取数据)(HAL库开发)

    目录 1、函数配置过程(这是标准库配置过程): 2、STM32CubeMx配置过程  3、main函数源文件 采集5路ADC数据,并用串口printf()函数打印出来。 实验现象:  ADC转换的初始条件: 1、使能 2、触发源条件完成(这个需要自己配置)利用:HAL_ADC_Start_DMA()函数; ADC中HAL开发优势就是,

    2023年04月08日
    浏览(61)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包