赞
踩
#include "stm32f10x.h" uint16_t MyDMA_Size; void MyDMA_Init(uint32_t MemoryBaseAddr, uint32_t PeripheralBaseAddr, uint16_t Size) { // RCC使能时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); MyDMA_Size = Size; // 配置DMA DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_BufferSize=Size; // 缓冲区大小, 传输计数器的值 DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST; // 传输方向 DMA_InitStructure.DMA_M2M=DMA_M2M_Enable; // 软件触发或硬件触发 DMA_InitStructure.DMA_MemoryBaseAddr=MemoryBaseAddr; // 存储器基地址 DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord; // 存储器传输数据大小 DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable; // 配置存储器地址是否自增 DMA_InitStructure.DMA_Mode=DMA_Mode_Normal; // 配置是否自动重装 DMA_InitStructure.DMA_PeripheralBaseAddr=PeripheralBaseAddr; // 外设基地址 DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; // 外设传输数据大小 DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Enable; // 配置外设地址是否自增 DMA_InitStructure.DMA_Priority=DMA_Priority_Low; // 优先级 DMA_Init(DMA1_Channel1, &DMA_InitStructure); DMA_Cmd(DMA1_Channel1, DISABLE); // 先关闭 }
缓冲区大小, 即传输计数器的值, 可选的值为0~65535
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. */
该参数用来配置DMA运输方向, 是从站点A(Memory)到站点B(Periph)还是站点B到站点A, 位置是相对的
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 */
/** @defgroup DMA_data_transfer_direction
* @{
*/
#define DMA_DIR_PeripheralDST ((uint32_t)0x00000010)
#define DMA_DIR_PeripheralSRC ((uint32_t)0x00000000)
其实配置的是软件触发还是硬件触发
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 */
/** @defgroup DMA_memory_to_memory
* @{
*/
#define DMA_M2M_Enable ((uint32_t)0x00004000)
#define DMA_M2M_Disable ((uint32_t)0x00000000)
存储器基地址
传入(uint32_t)(地址)
存储器传输数据大小
uint32_t DMA_MemoryDataSize; /*!< Specifies the Memory data width.
This parameter can be a value of @ref DMA_memory_data_size */
/** @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)
配置存储器地址是否自增
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 */
/** @defgroup DMA_memory_incremented_mode
* @{
*/
#define DMA_MemoryInc_Enable ((uint32_t)0x00000080)
#define DMA_MemoryInc_Disable ((uint32_t)0x00000000)
实际上配置的是自动重装器
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 */
/** @defgroup DMA_circular_normal_mode
* @{
*/
#define DMA_Mode_Circular ((uint32_t)0x00000020)
#define DMA_Mode_Normal ((uint32_t)0x00000000)
外设基地址
传入(uint32_t)(地址)
外设传输数据大小
uint32_t DMA_PeripheralDataSize; /*!< Specifies the Peripheral data width.
This parameter can be a value of @ref DMA_peripheral_data_size */
/** @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)
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 */
/** @defgroup DMA_peripheral_incremented_mode
* @{
*/
#define DMA_PeripheralInc_Enable ((uint32_t)0x00000040)
#define DMA_PeripheralInc_Disable ((uint32_t)0x00000000)
配置外设地址是否自增
优先级
uint32_t DMA_Priority; /*!< Specifies the software priority for the DMAy Channelx.
This parameter can be a value of @ref DMA_priority_level */
/** @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)
#include "stm32f10x.h" uint16_t MyDMA_Size; void MyDMA_Init(uint32_t MemoryBaseAddr, uint32_t PeripheralBaseAddr, uint16_t Size) { // RCC使能时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); MyDMA_Size = Size; // 配置DMA DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_BufferSize=Size; // 缓冲区大小, 传输计数器的值 DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST; // 传输方向 DMA_InitStructure.DMA_M2M=DMA_M2M_Enable; // 软件触发或硬件触发 DMA_InitStructure.DMA_MemoryBaseAddr=MemoryBaseAddr; // 存储器基地址 DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord; // 存储器传输数据大小 DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable; // 配置存储器地址是否自增 DMA_InitStructure.DMA_Mode=DMA_Mode_Normal; // 配置是否自动重装 DMA_InitStructure.DMA_PeripheralBaseAddr=PeripheralBaseAddr; // 外设基地址 DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; // 外设传输数据大小 DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Enable; // 配置外设地址是否自增 DMA_InitStructure.DMA_Priority=DMA_Priority_Low; // 优先级 DMA_Init(DMA1_Channel1, &DMA_InitStructure); DMA_Cmd(DMA1_Channel1, DISABLE); // 先关闭 } /* 调用转运一次数据 */ void Data_Transfer(void) { 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); // 清除完成标志 }
#include "stm32f10x.h" #include "delay.h" #include "OLED.h" #include "MyDMA.h" uint16_t arrA[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint16_t arrB[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // DMA数据转运 将数据从数组A转运到数组B // 2023年3月26日13:38:02 int main(void) { OLED_Init(); MyDMA_Init((uint32_t)arrA, (uint32_t)arrB, 8); while(1) { // arrA OLED_ShowHexNum(1, 1, arrA[0], 2); OLED_ShowHexNum(1, 4, arrA[1], 2); OLED_ShowHexNum(1, 7, arrA[2], 2); OLED_ShowHexNum(1, 10,arrA[3], 2); Delay_ms(1000); OLED_ShowHexNum(2, 1, arrA[4], 2); OLED_ShowHexNum(2, 4, arrA[5], 2); OLED_ShowHexNum(2, 7, arrA[6], 2); OLED_ShowHexNum(2, 10,arrA[7], 2); Delay_ms(1000); // arrB[:4] Data_Transfer(); OLED_ShowHexNum(3, 1, arrB[0], 2); OLED_ShowHexNum(3, 4, arrB[1], 2); OLED_ShowHexNum(3, 7, arrB[2], 2); OLED_ShowHexNum(3, 10,arrB[3], 2); Delay_ms(1000); // arrB[:4] OLED_ShowHexNum(4, 1, arrB[4], 2); OLED_ShowHexNum(4, 4, arrB[5], 2); OLED_ShowHexNum(4, 7, arrB[6], 2); OLED_ShowHexNum(4, 10,arrB[7], 2); // CPU搬运 arrA[0] = arrB[5]; arrA[1] = arrB[7]; arrA[2] = arrB[3]; arrA[3] = arrB[4]; arrA[4] = arrB[2]; arrA[5] = arrB[0]; arrA[6] = arrB[1]; arrA[7] = arrB[6]; } }
#include "stm32f10x.h" uint16_t AD_Value[4]; /* 初始化ADC */ void AD_Init(void) { // RCC使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 12MHz // 配置GPIO口 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置规则通道 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_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 单次转换或者连续转换 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据对齐模式 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // ADC模式, 单独还是交叉 ADC_InitStructure.ADC_NbrOfChannel = 4; // 扫描的通道数 ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 扫描模式或者非扫描模式 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 触发控制 软件触发 ADC_Init(ADC1, &ADC_InitStructure); // 配置DMA DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; // ADC的数据寄存器 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 地址非自增, ADC可以理解为上菜的桌子只有一个 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value; // 保存的地址 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 这里要自增 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 转运方向 DMA_InitStructure.DMA_BufferSize = 4; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 自动重装 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 硬件触发 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; DMA_Init(DMA1_Channel1, &DMA_InitStructure); // 开启DMA DMA_Cmd(DMA1_Channel1, ENABLE); // 开启DMA搬运 ADC_DMACmd(ADC1, ENABLE); // 开启ADC功能 ADC_Cmd(ADC1, ENABLE); // ADC校准 ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1) == SET); // 已初始化为零 ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1) == SET); ADC_SoftwareStartConvCmd(ADC1, ENABLE); }
ADC用多次转换+扫描模式, 用ADC_DMACmd()使ADC在转换完成后自动请求DMA搬运数据
配置DMA的方法与之前类似
不要忘记RCC使能DMA时钟以及调用DMA_Cmd(), 开启DMA
最后用软件触发开启ADC
#include "stm32f10x.h" #include "delay.h" #include "OLED.h" #include "ADC.h" // DMA+ADC多通道 // 2023年3月26日15:28:49 int main(void) { OLED_Init(); AD_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, AD_Value[0], 4); OLED_ShowNum(2, 5, AD_Value[1], 4); OLED_ShowNum(3, 5, AD_Value[2], 4); OLED_ShowNum(4, 5, AD_Value[3], 4); Delay_ms(100); } }
【STM32入门教程-2023持续更新中】 https://www.bilibili.com/video/BV1th411z7sn/?p=24&share_source=copy_web&vd_source=ee06a25b3dfb2900ab707b01fdff6667
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。