00. 目录
文章目录
- 00. 目录
- 01. DMA简介
- 02. DMA相关API
- 2.1 DMA_Init
- 2.2 DMA_InitTypeDef
- 2.3 DMA_Cmd
- 2.4 DMA_SetCurrDataCounter
- 2.5 DMA_GetFlagStatus
- 2.6 DMA_ClearFlag
- 03. DMA数据单通道接线图
- 04. DMA数据单通道示例
- 05. DMA数据多通道接线图
- 06. DMA数据多通道示例一
- 07. DMA数据多通道示例二
- 08. 程序下载
- 09. 附录
01. DMA简介
小容量产品是指闪存存储器容量在16K至32K字节之间的STM32F101xx、STM32F102xx和STM32F103xx微控制器。
中容量产品是指闪存存储器容量在64K至128K字节之间的STM32F101xx、STM32F102xx和STM32F103xx微控制器。
大容量产品是指闪存存储器容量在256K至512K字节之间的STM32F101xx和STM32F103xx微控制器。
互联型产品是指STM32F105xx和STM32F107xx微控制器。
直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。
两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。
02. DMA相关API
2.1 DMA_Init
/**
* @brief Initializes the DMAy Channelx according to the specified
* parameters in the DMA_InitStruct.
* @param DMAy_Channelx: where y can be 1 or 2 to select the DMA and
* x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the DMA Channel.
* @param DMA_InitStruct: pointer to a DMA_InitTypeDef structure that
* contains the configuration information for the specified DMA Channel.
* @retval None
*/
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct)
功能:
根据 DMA_InitStruct 中指定的参数初始化 DMA 的通道 x 寄存器
参数:
DMA Channelx:x 可以是 1,2…,或者 7 来选择 DMA 通道 x
DMA_InitStruct:指向结构 DMA_InitTypeDef 的指针,包含了 DMA 通道 x 的配置信息
返回值:
无
2.2 DMA_InitTypeDef
/**
* @brief DMA Init structure definition
*/
typedef struct
{
uint32_t DMA_PeripheralBaseAddr; /*!< Specifies the peripheral base address for DMAy Channelx. */
uint32_t DMA_MemoryBaseAddr; /*!< Specifies the memory base address for DMAy Channelx. */
uint32_t DMA_DIR; /*!< Specifies if the peripheral is the source or destination.
This parameter can be a value of @ref DMA_data_transfer_direction */
uint32_t DMA_BufferSize; /*!< Specifies the buffer size, in data unit, of the specified Channel.
The data unit is equal to the configuration set in DMA_PeripheralDataSize
or DMA_MemoryDataSize members depending in the transfer direction. */
uint32_t DMA_PeripheralInc; /*!< Specifies whether the Peripheral address register is incremented or not.
This parameter can be a value of @ref DMA_peripheral_incremented_mode */
uint32_t DMA_MemoryInc; /*!< Specifies whether the memory address register is incremented or not.
This parameter can be a value of @ref DMA_memory_incremented_mode */
uint32_t DMA_PeripheralDataSize; /*!< Specifies the Peripheral data width.
This parameter can be a value of @ref DMA_peripheral_data_size */
uint32_t DMA_MemoryDataSize; /*!< Specifies the Memory data width.
This parameter can be a value of @ref DMA_memory_data_size */
uint32_t DMA_Mode; /*!< Specifies the operation mode of the DMAy Channelx.
This parameter can be a value of @ref DMA_circular_normal_mode.
@note: The circular buffer mode cannot be used if the memory-to-memory
data transfer is configured on the selected Channel */
uint32_t DMA_Priority; /*!< Specifies the software priority for the DMAy Channelx.
This parameter can be a value of @ref DMA_priority_level */
uint32_t DMA_M2M; /*!< Specifies if the DMAy Channelx will be used in memory-to-memory transfer.
This parameter can be a value of @ref DMA_memory_to_memory */
}DMA_InitTypeDef;
DMA_PeripheralBaseAddr
该参数用以定义 DMA 外设基地址
DMA_MemoryBaseAddr
该参数用以定义 DMA 内存基地址
DMA_DIR
/** @defgroup DMA_data_transfer_direction
* @{
*/
#define DMA_DIR_PeripheralDST ((uint32_t)0x00000010)
#define DMA_DIR_PeripheralSRC ((uint32_t)0x00000000)
DMA_PeripheralInc
/** @defgroup DMA_peripheral_incremented_mode
* @{
*/
#define DMA_PeripheralInc_Enable ((uint32_t)0x00000040)
#define DMA_PeripheralInc_Disable ((uint32_t)0x00000000)
DMA_MemoryInc
/** @defgroup DMA_memory_incremented_mode
* @{
*/
#define DMA_MemoryInc_Enable ((uint32_t)0x00000080)
#define DMA_MemoryInc_Disable ((uint32_t)0x00000000)
DMA_PeripheralDataSize
/** @defgroup DMA_peripheral_data_size
* @{
*/
#define DMA_PeripheralDataSize_Byte ((uint32_t)0x00000000)
#define DMA_PeripheralDataSize_HalfWord ((uint32_t)0x00000100)
#define DMA_PeripheralDataSize_Word ((uint32_t)0x00000200)
DMA_MemoryDataSize
/** @defgroup DMA_memory_data_size
* @{
*/
#define DMA_MemoryDataSize_Byte ((uint32_t)0x00000000)
#define DMA_MemoryDataSize_HalfWord ((uint32_t)0x00000400)
#define DMA_MemoryDataSize_Word ((uint32_t)0x00000800)
DMA_Mode
/** @defgroup DMA_circular_normal_mode
* @{
*/
#define DMA_Mode_Circular ((uint32_t)0x00000020)
#define DMA_Mode_Normal ((uint32_t)0x00000000)
DMA_Priority
/** @defgroup DMA_priority_level
* @{
*/
#define DMA_Priority_VeryHigh ((uint32_t)0x00003000)
#define DMA_Priority_High ((uint32_t)0x00002000)
#define DMA_Priority_Medium ((uint32_t)0x00001000)
#define DMA_Priority_Low ((uint32_t)0x00000000)
DMA_M2M
/** @defgroup DMA_memory_to_memory
* @{
*/
#define DMA_M2M_Enable ((uint32_t)0x00004000)
#define DMA_M2M_Disable ((uint32_t)0x00000000)
2.3 DMA_Cmd
/**
* @brief Enables or disables the specified DMAy Channelx.
* @param DMAy_Channelx: where y can be 1 or 2 to select the DMA and
* x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the DMA Channel.
* @param NewState: new state of the DMAy Channelx.
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState)
功能:
使能或者失能指定的通道 x
参数:
DMA Channelx:x 可以是 1,2…,或者 7 来选择 DMA 通道 x
NewState:DMA 通道 x 的新状态 这个参数可以取:ENABLE 或者 DISABLE
返回值:
无
2.4 DMA_SetCurrDataCounter
/**
* @brief Sets the number of data units in the current DMAy Channelx transfer.
* @param DMAy_Channelx: where y can be 1 or 2 to select the DMA and
* x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the DMA Channel.
* @param DataNumber: The number of data units in the current DMAy Channelx
* transfer.
* @note This function can only be used when the DMAy_Channelx is disabled.
* @retval None.
*/
void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber)
功能:
设置DMA转换数据个数
参数:
DMA Channelx:x 可以是 1,2…,或者 7 来选择 DMA 通道 x
DataNumber:数据个数
返回值:
无
2.5 DMA_GetFlagStatus
/**
* @brief Checks whether the specified DMAy Channelx flag is set or not.
* @param DMAy_FLAG: specifies the flag to check.
* This parameter can be one of the following values:
* @arg DMA1_FLAG_GL1: DMA1 Channel1 global flag.
* @arg DMA1_FLAG_TC1: DMA1 Channel1 transfer complete flag.
* @arg DMA1_FLAG_HT1: DMA1 Channel1 half transfer flag.
* @arg DMA1_FLAG_TE1: DMA1 Channel1 transfer error flag.
* @arg DMA1_FLAG_GL2: DMA1 Channel2 global flag.
* @arg DMA1_FLAG_TC2: DMA1 Channel2 transfer complete flag.
* @arg DMA1_FLAG_HT2: DMA1 Channel2 half transfer flag.
* @arg DMA1_FLAG_TE2: DMA1 Channel2 transfer error flag.
* @arg DMA1_FLAG_GL3: DMA1 Channel3 global flag.
* @arg DMA1_FLAG_TC3: DMA1 Channel3 transfer complete flag.
* @arg DMA1_FLAG_HT3: DMA1 Channel3 half transfer flag.
* @arg DMA1_FLAG_TE3: DMA1 Channel3 transfer error flag.
* @arg DMA1_FLAG_GL4: DMA1 Channel4 global flag.
* @arg DMA1_FLAG_TC4: DMA1 Channel4 transfer complete flag.
* @arg DMA1_FLAG_HT4: DMA1 Channel4 half transfer flag.
* @arg DMA1_FLAG_TE4: DMA1 Channel4 transfer error flag.
* @arg DMA1_FLAG_GL5: DMA1 Channel5 global flag.
* @arg DMA1_FLAG_TC5: DMA1 Channel5 transfer complete flag.
* @arg DMA1_FLAG_HT5: DMA1 Channel5 half transfer flag.
* @arg DMA1_FLAG_TE5: DMA1 Channel5 transfer error flag.
* @arg DMA1_FLAG_GL6: DMA1 Channel6 global flag.
* @arg DMA1_FLAG_TC6: DMA1 Channel6 transfer complete flag.
* @arg DMA1_FLAG_HT6: DMA1 Channel6 half transfer flag.
* @arg DMA1_FLAG_TE6: DMA1 Channel6 transfer error flag.
* @arg DMA1_FLAG_GL7: DMA1 Channel7 global flag.
* @arg DMA1_FLAG_TC7: DMA1 Channel7 transfer complete flag.
* @arg DMA1_FLAG_HT7: DMA1 Channel7 half transfer flag.
* @arg DMA1_FLAG_TE7: DMA1 Channel7 transfer error flag.
* @arg DMA2_FLAG_GL1: DMA2 Channel1 global flag.
* @arg DMA2_FLAG_TC1: DMA2 Channel1 transfer complete flag.
* @arg DMA2_FLAG_HT1: DMA2 Channel1 half transfer flag.
* @arg DMA2_FLAG_TE1: DMA2 Channel1 transfer error flag.
* @arg DMA2_FLAG_GL2: DMA2 Channel2 global flag.
* @arg DMA2_FLAG_TC2: DMA2 Channel2 transfer complete flag.
* @arg DMA2_FLAG_HT2: DMA2 Channel2 half transfer flag.
* @arg DMA2_FLAG_TE2: DMA2 Channel2 transfer error flag.
* @arg DMA2_FLAG_GL3: DMA2 Channel3 global flag.
* @arg DMA2_FLAG_TC3: DMA2 Channel3 transfer complete flag.
* @arg DMA2_FLAG_HT3: DMA2 Channel3 half transfer flag.
* @arg DMA2_FLAG_TE3: DMA2 Channel3 transfer error flag.
* @arg DMA2_FLAG_GL4: DMA2 Channel4 global flag.
* @arg DMA2_FLAG_TC4: DMA2 Channel4 transfer complete flag.
* @arg DMA2_FLAG_HT4: DMA2 Channel4 half transfer flag.
* @arg DMA2_FLAG_TE4: DMA2 Channel4 transfer error flag.
* @arg DMA2_FLAG_GL5: DMA2 Channel5 global flag.
* @arg DMA2_FLAG_TC5: DMA2 Channel5 transfer complete flag.
* @arg DMA2_FLAG_HT5: DMA2 Channel5 half transfer flag.
* @arg DMA2_FLAG_TE5: DMA2 Channel5 transfer error flag.
* @retval The new state of DMAy_FLAG (SET or RESET).
*/
FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG)
功能:
检查指定的 DMA 通道 x 标志位设置与否
参数:
DMA_FLAG:待检查的 DMA 标志位
返回值:
DMA_FLAG 的新状态(SET 或者 RESET)
2.6 DMA_ClearFlag
/**
* @brief Clears the DMAy Channelx's pending flags.
* @param DMAy_FLAG: specifies the flag to clear.
* This parameter can be any combination (for the same DMA) of the following values:
* @arg DMA1_FLAG_GL1: DMA1 Channel1 global flag.
* @arg DMA1_FLAG_TC1: DMA1 Channel1 transfer complete flag.
* @arg DMA1_FLAG_HT1: DMA1 Channel1 half transfer flag.
* @arg DMA1_FLAG_TE1: DMA1 Channel1 transfer error flag.
* @arg DMA1_FLAG_GL2: DMA1 Channel2 global flag.
* @arg DMA1_FLAG_TC2: DMA1 Channel2 transfer complete flag.
* @arg DMA1_FLAG_HT2: DMA1 Channel2 half transfer flag.
* @arg DMA1_FLAG_TE2: DMA1 Channel2 transfer error flag.
* @arg DMA1_FLAG_GL3: DMA1 Channel3 global flag.
* @arg DMA1_FLAG_TC3: DMA1 Channel3 transfer complete flag.
* @arg DMA1_FLAG_HT3: DMA1 Channel3 half transfer flag.
* @arg DMA1_FLAG_TE3: DMA1 Channel3 transfer error flag.
* @arg DMA1_FLAG_GL4: DMA1 Channel4 global flag.
* @arg DMA1_FLAG_TC4: DMA1 Channel4 transfer complete flag.
* @arg DMA1_FLAG_HT4: DMA1 Channel4 half transfer flag.
* @arg DMA1_FLAG_TE4: DMA1 Channel4 transfer error flag.
* @arg DMA1_FLAG_GL5: DMA1 Channel5 global flag.
* @arg DMA1_FLAG_TC5: DMA1 Channel5 transfer complete flag.
* @arg DMA1_FLAG_HT5: DMA1 Channel5 half transfer flag.
* @arg DMA1_FLAG_TE5: DMA1 Channel5 transfer error flag.
* @arg DMA1_FLAG_GL6: DMA1 Channel6 global flag.
* @arg DMA1_FLAG_TC6: DMA1 Channel6 transfer complete flag.
* @arg DMA1_FLAG_HT6: DMA1 Channel6 half transfer flag.
* @arg DMA1_FLAG_TE6: DMA1 Channel6 transfer error flag.
* @arg DMA1_FLAG_GL7: DMA1 Channel7 global flag.
* @arg DMA1_FLAG_TC7: DMA1 Channel7 transfer complete flag.
* @arg DMA1_FLAG_HT7: DMA1 Channel7 half transfer flag.
* @arg DMA1_FLAG_TE7: DMA1 Channel7 transfer error flag.
* @arg DMA2_FLAG_GL1: DMA2 Channel1 global flag.
* @arg DMA2_FLAG_TC1: DMA2 Channel1 transfer complete flag.
* @arg DMA2_FLAG_HT1: DMA2 Channel1 half transfer flag.
* @arg DMA2_FLAG_TE1: DMA2 Channel1 transfer error flag.
* @arg DMA2_FLAG_GL2: DMA2 Channel2 global flag.
* @arg DMA2_FLAG_TC2: DMA2 Channel2 transfer complete flag.
* @arg DMA2_FLAG_HT2: DMA2 Channel2 half transfer flag.
* @arg DMA2_FLAG_TE2: DMA2 Channel2 transfer error flag.
* @arg DMA2_FLAG_GL3: DMA2 Channel3 global flag.
* @arg DMA2_FLAG_TC3: DMA2 Channel3 transfer complete flag.
* @arg DMA2_FLAG_HT3: DMA2 Channel3 half transfer flag.
* @arg DMA2_FLAG_TE3: DMA2 Channel3 transfer error flag.
* @arg DMA2_FLAG_GL4: DMA2 Channel4 global flag.
* @arg DMA2_FLAG_TC4: DMA2 Channel4 transfer complete flag.
* @arg DMA2_FLAG_HT4: DMA2 Channel4 half transfer flag.
* @arg DMA2_FLAG_TE4: DMA2 Channel4 transfer error flag.
* @arg DMA2_FLAG_GL5: DMA2 Channel5 global flag.
* @arg DMA2_FLAG_TC5: DMA2 Channel5 transfer complete flag.
* @arg DMA2_FLAG_HT5: DMA2 Channel5 half transfer flag.
* @arg DMA2_FLAG_TE5: DMA2 Channel5 transfer error flag.
* @retval None
*/
void DMA_ClearFlag(uint32_t DMAy_FLAG)
功能:
清除 DMA 通道 x 待处理标志位
参数:
DMA_FLAG:待清除的 DMA 标志位,使用操作符“|”可以同时选中多个DMA 标志位
返回值:
无
03. DMA数据单通道接线图
04. DMA数据单通道示例
dma.h
#ifndef __DMA_H__
#define __DMA_H__
#include "stm32f10x.h" // Device header
void dma_init(uint32_t src, uint32_t dest, uint32_t size);
void dma_trasfer(uint32_t size);
#endif
dma.c
#include "dma.h"
void dma_init(uint32_t src, uint32_t dest, uint32_t size)
{
DMA_InitTypeDef DMA_InitStruct;
//开启时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_InitStruct.DMA_MemoryBaseAddr = dest;
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 = src;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
DMA_InitStruct.DMA_Priority = DMA_Priority_Low;
DMA_InitStruct.DMA_BufferSize = size;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_M2M = DMA_M2M_Enable;
DMA_Init(DMA1_Channel1, &DMA_InitStruct);
DMA_Cmd(DMA1_Channel1, DISABLE);
}
void dma_trasfer(uint32_t size)
{
DMA_Cmd(DMA1_Channel1, DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel1, size);
DMA_Cmd(DMA1_Channel1, ENABLE);
while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
DMA_ClearFlag(DMA1_FLAG_TC1);
}
测试程序1 main.c
#include "stm32f10x.h"
#include "delay.h"
#include "oled.h"
#include "dma.h"
const uint8_t src[] = {0x1, 0x2, 0x3, 0x4};
uint8_t dest[] = {0, 0, 0, 0};
int main(void)
{
//初始化
OLED_Init();
dma_init((uint32_t)src, (uint32_t)dest, 4);
OLED_ShowHexNum(1, 1, src[0], 2);
OLED_ShowHexNum(1, 4, src[1], 2);
OLED_ShowHexNum(1, 7, src[2], 2);
OLED_ShowHexNum(1, 10, src[3], 2);
OLED_ShowHexNum(2, 1, dest[0], 2);
OLED_ShowHexNum(2, 4, dest[1], 2);
OLED_ShowHexNum(2, 7, dest[2], 2);
OLED_ShowHexNum(2, 10, dest[3], 2);
dma_trasfer(4);
OLED_ShowHexNum(3, 1, src[0], 2);
OLED_ShowHexNum(3, 4, src[1], 2);
OLED_ShowHexNum(3, 7, src[2], 2);
OLED_ShowHexNum(3, 10, src[3], 2);
OLED_ShowHexNum(4, 1, dest[0], 2);
OLED_ShowHexNum(4, 4, dest[1], 2);
OLED_ShowHexNum(4, 7, dest[2], 2);
OLED_ShowHexNum(4, 10, dest[3], 2);
while(1)
{
}
return 0;
}
测试程序2 main.c
#include "stm32f10x.h"
#include "delay.h"
#include "oled.h"
#include "dma.h"
uint8_t src[] = {0x1, 0x2, 0x3, 0x4};
uint8_t dest[] = {0, 0, 0, 0};
int main(void)
{
//初始化
OLED_Init();
dma_init((uint32_t)src, (uint32_t)dest, 4);
OLED_ShowString(1, 1, "DataA");
OLED_ShowString(3, 1, "DataB");
OLED_ShowHexNum(1, 8, (uint32_t)src, 8);
OLED_ShowHexNum(3, 8, (uint32_t)dest, 8);
while(1)
{
src[0] ++;
src[1] ++;
src[2] ++;
src[3] ++;
OLED_ShowHexNum(2, 1, src[0], 2);
OLED_ShowHexNum(2, 4, src[1], 2);
OLED_ShowHexNum(2, 7, src[2], 2);
OLED_ShowHexNum(2, 10, src[3], 2);
OLED_ShowHexNum(4, 1, dest[0], 2);
OLED_ShowHexNum(4, 4, dest[1], 2);
OLED_ShowHexNum(4, 7, dest[2], 2);
OLED_ShowHexNum(4, 10, dest[3], 2);
delay_ms(1000);
dma_trasfer(4);
OLED_ShowHexNum(2, 1, src[0], 2);
OLED_ShowHexNum(2, 4, src[1], 2);
OLED_ShowHexNum(2, 7, src[2], 2);
OLED_ShowHexNum(2, 10, src[3], 2);
OLED_ShowHexNum(4, 1, dest[0], 2);
OLED_ShowHexNum(4, 4, dest[1], 2);
OLED_ShowHexNum(4, 7, dest[2], 2);
OLED_ShowHexNum(4, 10, dest[3], 2);
delay_ms(1000);
}
return 0;
}
05. DMA数据多通道接线图
06. DMA数据多通道示例一
单次转换 扫描模式
adc.h
#ifndef __ADC_H__
#define __ADC_H__
#include "stm32f10x.h" // Device header
extern uint16_t adc_value[4];
void adc_init(void);
void adc_getvalue(void);
#endif /*__ADC_H__*/
adc.c
#include "adc.h"
uint16_t adc_value[4] = {0};
void adc_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStruct;
DMA_InitTypeDef DMA_InitStruct;
//开启ADC时钟 PA0 --> ADC1_0
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
//开启GPIOA的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//开启时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
//设置为6分频 72M / 6 = 12M
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//GPIO配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 4个ADC通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);
//ADC配置
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; //单次转换
ADC_InitStruct.ADC_ScanConvMode = ENABLE; //扫描模式
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
ADC_InitStruct.ADC_NbrOfChannel = 4; //4个通道
ADC_Init(ADC1, &ADC_InitStruct);
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)adc_value;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_Priority = DMA_Priority_Low;
DMA_InitStruct.DMA_BufferSize = 4;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStruct);
DMA_Cmd(DMA1_Channel1, DISABLE);
ADC_DMACmd(ADC1, ENABLE);
//使能ADC
ADC_Cmd(ADC1, ENABLE);
//校准ADC
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
void adc_getvalue(void)
{
DMA_Cmd(DMA1_Channel1, DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel1, 4);
DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
DMA_ClearFlag(DMA1_FLAG_TC1);
}
main.c
#include "stm32f10x.h"
#include "delay.h"
#include "oled.h"
#include "adc.h"
int main(void)
{
//初始化
OLED_Init();
adc_init();
//显示字符串
OLED_ShowString(1, 1, "AD0: ");
OLED_ShowString(2, 1, "AD1: ");
OLED_ShowString(3, 1, "AD2: ");
OLED_ShowString(4, 1, "AD3: ");
while(1)
{
adc_getvalue();
OLED_ShowNum(1, 5, adc_value[0], 4);
OLED_ShowNum(2, 5, adc_value[1], 4);
OLED_ShowNum(3, 5, adc_value[2], 4);
OLED_ShowNum(4, 5, adc_value[3], 4);
delay_ms(100);
}
}
07. DMA数据多通道示例二
连续扫描,循环转换
adc.h
#ifndef __ADC_H__
#define __ADC_H__
#include "stm32f10x.h" // Device header
extern uint16_t adc_value[4];
void adc_init(void);
#endif /*__ADC_H__*/
adc.c
#include "adc.h"
uint16_t adc_value[4] = {0};
void adc_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStruct;
DMA_InitTypeDef DMA_InitStruct;
//开启ADC时钟 PA0 --> ADC1_0
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
//开启GPIOA的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//开启时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
//设置为6分频 72M / 6 = 12M
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//GPIO配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 4个ADC通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);
//ADC配置
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; //连续模式
ADC_InitStruct.ADC_ScanConvMode = ENABLE; //扫描模式
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
ADC_InitStruct.ADC_NbrOfChannel = 4; //4个通道
ADC_Init(ADC1, &ADC_InitStruct);
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)adc_value;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; //DMA循环模式
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_Priority = DMA_Priority_Low;
DMA_InitStruct.DMA_BufferSize = 4;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStruct);
DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
//使能ADC
ADC_Cmd(ADC1, ENABLE);
//校准ADC
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
//ADC触发
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
main.c
#include "stm32f10x.h"
#include "delay.h"
#include "oled.h"
#include "adc.h"
int main(void)
{
//初始化
OLED_Init();
adc_init();
//显示字符串
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, adc_value[0], 4);
OLED_ShowNum(2, 5, adc_value[1], 4);
OLED_ShowNum(3, 5, adc_value[2], 4);
OLED_ShowNum(4, 5, adc_value[3], 4);
delay_ms(100);
}
}
08. 程序下载
19-DMA单通道.rar
20-DMA-ADC多通道1.rar
21-DMA-ADC多通道2.rar
09. 附录
参考: 【STM32】江科大STM32学习笔记汇总