STM32H723 ADC+DMA寄存器配置

分享基于STM32H723的ADC+DMA的配置方法

        1、ADC寄存器配置,这里以ADC3为例,使用四个通道,分别是4、8、9以及内部温度传感器17通道;

//先初始化IO口
RCC->AHB4ENR |= 1 << 24;                                                                  //使能ADC3时钟 
RCC->AHB4ENR |= 1 << 5;                                                                    //使能PORT F时钟
GPIO_Set(GPIOF,PIN6,GPIO_MODE_AIN,0,0,GPIO_PUPD_NONE);

//PF6,模拟输入,不带上下拉   
GPIO_Set(GPIOF,PIN4,GPIO_MODE_AIN,0,0,GPIO_PUPD_NONE);                                 //PF4,模拟输入,不带上下拉  
 GPIO_Set(GPIOF,PIN5,GPIO_MODE_AIN,0,0,GPIO_PUPD_NONE);                                  //PF5,模拟输入,不带上下拉 

//DMA配置这里我用了自己仿以前ST标准库的封装方式

DMA_InitStruct.u32DMA_NumberData = 4;                                        //数量
DMA_InitStruct.u32DMA_Memory1BaseAddr  = (uint32_t)ADCValueBuffer;

//DMA存储器地址
DMA_InitStruct.u32DMA_PeripheralBaseAddr = (uint32_t)&ADC3->DR;

//外设地址
DMA_InitStruct.u8DMA_Channel  = 115;
DMA_InitStruct.u8DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStruct.u8DMA_DoubleBufferMode = DMA_DoubleBuffer_Disable;

DMA_InitStruct.u8DMA_MemoryBurstTransfer = DMA_MemoryBurst_Single;
DMA_InitStruct.u8DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStruct.u8DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.u8DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.u8DMA_PeripheralBurstTransfer = DMA_PeripheralBurst_Single;
DMA_InitStruct.u8DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStruct.u8DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.u8DMA_Priority  = DMA_Priority_VeryHigh;
DMA_Driver_Init(DMA1_Stream2,&DMA_InitStruct);

RCC->AHB4RSTR |= 1 << 24 ; //ADC3复位

RCC->AHB4RSTR &= ~(1 << 24); //复位结束    
RCC->D3CCIPR  &= ~(3 << 16); //ADCSEL[1:0]清零
RCC->D3CCIPR  |= 2 << 16;

//ADCSEL[1:0]=2,per_ck作为ADC时钟源,默认选择hsi_ker_ck作为per_ck,频率:64Mhz
ADC3_COMMON->CCR |= 2 << 18;

//PRESC[3:0]=2,输入时钟4分频,即adc_ker_ck=per_ck/4=64/4=16Mhz(不能超过36Mhz)
ADC3_COMMON->CCR |= 1 << 23;                                                            

//VSENSEEN = 1,开启内部温度传感器
ADC3->CR = 0;                                                                          

//CR寄存器清零,DEEPPWD清零,从深度睡眠唤醒.

ADC3->CR |= 1 << 28;                                                                      

//ADVREGEN=1,使能ADC稳压器

/*需要在这里实现延时,我这里延时了50ms等待稳压器启动完成*/

ADC3->CFGR &= ~(1 << 13);                                                                    

//CONT=0,单次转换模式,使用单次转换是为了ADC每转换完一次,都由软件再次触发采样
ADC3->CFGR |= 1 << 12;                                                                        

//OVRMOD=1,复写模式(DR寄存器可被复写)    
ADC3->CFGR &= ~(3 << 10);                                                                    

//EXTEN[1:0]=0,软件触发
ADC3->CFGR &= ~(3 << 3);                                                                    

//RES[1:0]位清零
ADC3->CFGR |= 0 << 3;                                                                        

//RES[1:0]=0,12位分辨率(0,12位;1,10位;2,8位.3,6位)
ADC3->CFGR |= 3 << 0;                   

//DMA循环模式

ADC3->CFGR &= ~(1 << 15);                                                                  

 //数据右对齐.
ADC3->CFGR2 &= ~((uint32_t)15 << 5);                                                        

//OVSS[3:0]=0,不左移,数据右对齐.
ADC3->CFGR2 &= ~((uint32_t)0x7 << 2);                                                        

//OSR[2:0]=0,不使用过采样

ADC3->CR &= ~((uint32_t)1 << 30);                                                            

//ADCALDIF=0,校准单端转换通道
ADC3->CR |= (uint32_t)1 << 31;                                                                //开启校准

while(ADC3->CR&((uint32_t)1 << 31))                                                            //等待校准完成

{

        /*在这里实现等待校准完成,做个计时,超时即退出并返回错误*/

}

ADC3->SQR1 &= ~(0XF << 0);                                                                

//L[3:0]清零
ADC3->SQR1 |= (ADC3_CHANNEL_NUM - 1) << 0;                                                            //L[3:0]=3,4个转换在规则序列中 也就是转换规则序列1、2、3、4四个序列

ADC3->SQR1 &= ~(0x1F << (6 * 1));    
ADC3->SQR1 |= 4 << (6 * 1);   

//设置序列1的通道号为4 
ADC3->SQR1 &= ~(0x1F << (6 * 2));    
ADC3->SQR1 |= 17 << (6 * 2);

//设置序列2的通道号为17
ADC3->SQR1 &= ~(0x1F << (6 * 3));    
ADC3->SQR1 |= 8<< (6 * 3);     

//设置序列3的通道号为8
ADC3->SQR1 &= ~(0x1F << (6 * 4));    
ADC3->SQR1 |= HARDWARE_VERSION_ADC_CHANNEL << (6 * 4);  

//设置序列4的通道号为9

//设置通道8的采样时间
ADC3->SMPR1 &= ~(7 << (3 * 8));                                                            

//通道8采样时间清空      
ADC3->SMPR1 |= 7 << (3 * 8);                                                             

//通道8 640.5个周期,提高采样时间可以提高精确度        
    
//设置通道9的采样时间
ADC3->SMPR1 &= ~(7 << (3 * 9));                                                            

//通道9采样时间清空      
ADC3->SMPR1 |= 7 << (3 * 9);                                                             

//通道9 640.5个周期,提高采样时间可以提高精确度    
    
//设置通道4的采样时间
ADC3->SMPR1 &= ~(7 << (3 * 4));                                                            

//通道4采样时间清空      
ADC3->SMPR1 |= 7 << (3 * 4);                                                             

//通道4 640.5个周期,提高采样时

//设置通道17的采样时间
ADC3->SMPR2 &= ~(7 << (3 * 7));                                                            

//通道17采样时间清空      
ADC3->SMPR2 |= 7 << (3 * 7);                                                             

//通道17 640.5个周期,提高采样时间可以提高精确度    

DMA1_Stream2->CR |= 1 << 0;      /* 开启DMA传输 */
                    
ADC3->CR |= 1 << 0;            /* 启动ADC */

return 1;

        以上便是ADC+DMA的寄存器配置,此时基本的配置已经完成,接下来便是触发采样,需要注意的是DMA配置的是正常模式,ADC配置的是单次转换模式,此时是ADC采样完一个通道的数据,则会搬运一次数据至设置的RAM地址中,ADC设定了需转换四个规则序列,则DMA需要搬运四次,搬运完后,需要再次触发ADC采样,则需要再次触发采样。而如果需要ADC一直循环采样及DMA一直搬运的话,则可以将ADC配置为连续转换模式,DMA配置为循环模式,此时DMA设置的缓存地址才会与ADC预设的转换规则序列相对应上。如果ADC为连续转换,而DMA为正常模式,则会出现AD数值循环在DMA设置的缓存地址中滚动存储的情况;

        下面是触发ADC采样的寄存器实现

/*******************************************************************************
** 函数名称:Get_ADC3_Value_From_DMA
** 函数作用:从DMA接收ADC数据
** 输入参数:pBuffer------------接收缓存
**           u8Length-----------接收几个通道
** 输出参数:0------------------失败
**                   1------------------成功
** 使用样例:无
** 函数备注:无
*******************************************************************************/
uint8_t Get_ADC3_Value_From_DMA(uint16_t *pBuffer,uint8_t u8Length)

{

        static uint8_t u8TimeCounter = 0;

        ADC3->CR &= ~(1 << 0);         /* 先关闭ADC */

        ADC3->SQR1 &= ~(0XF << 0);                                                                //L[3:0]清零
        ADC3->SQR1 |= (u8Length - 1) << 0;                                                 

        //L[3:0] = u8Length - 1,u8Length - 1个转换在规则序列中 也就是转换规则序列前       u8Length - 1个

        DMA1_Stream2->CR &= ~(1 << 0);   /* 关闭DMA传输 */

        u8TimeCounter = 0;

        while (DMA1_Stream2->CR & 0X1)  /* 确保DMA可以被设置 */

        {

                /*在这里实现计时*/

        }

        DMA1->LIFCR |= 0x3D << 16;
        DMA1_Stream2->NDTR = u8Length;                  /* 要传输的数据项数目 */
        DMA1_Stream2->CR |= 1 << 0;                     /* 开启DMA传输 */
    
        ADC3->CR |= 1 << 0;                             /* 重新启动ADC */
        ADC3->CR |= 1 << 2;                             /* 启动规则转换通道 */

        while(1)
        {
                if(DMA1_Stream2->NDTR == 0)
                {
                    SCB_InvalidateDCache_by_Addr((uint32_t *)g_u16ADCValueBuffer,                          sizeof(g_u16ADCValueBuffer));

                        /*在这里实现数据拷贝*/

                        memcpy(pBuffer,g_u16ADCValueBuffer,(u8Length * 2));
                    return 1;
        } 
        else
        {
            if(++u8TimeCounter > 100)
            {
                u8TimeCounter = 0;
                return 0;
            }
        }
    }

}

        以上便是ADC+DMA的寄存器配置及获取数据的实现。此时DMA的BUFFER中,0则是规则序列1的采样值,1则是规则序列2中的通道的采样值,一次类推。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
嗨!对于STM32F1系列微控制器,你可以使用ADC(模数转换器)和DMA(直接内存访问)来实现ADC采样。以下是一些步骤和示例代码来帮助你开始: 1. 配置ADC参数: - 选择采样通道:通过设置ADC_SQR3、ADC_SQR2和ADC_SQR1寄存器来选择要采样的通道。 - 设置采样时间:通过设置ADC_SMPR2和ADC_SMPR1寄存器配置采样时间。 2. 配置DMA参数: - 设置外设地址:将ADC数据寄存器地址(ADC_DR)设置为DMA外设地址。 - 设置内存地址:将一个内存数组的地址设置为DMA内存地址。 - 设置数据传输方向:将DMA_CCR寄存器的DIR位设置为从外设到内存。 3. 配置中断(可选): - 如果你想在每次转换完成后获得中断通知,可以启用ADC的转换完成中断,并在中断处理函数中处理数据。 4. 启动ADCDMA: - 启用ADC:通过设置ADC_CR2寄存器的ADON位启用ADC。 - 启用DMA请求:通过设置ADC_CR2寄存器DMA位启用DMA请求。 - 启动DMA传输:通过设置DMA_CCR寄存器的EN位启动DMA传输。 以下是一个简单的示例代码片段,演示了如何配置ADCDMA进行连续采样: ```c #include "stm32f1xx_hal.h" ADC_HandleTypeDef hadc; DMA_HandleTypeDef hdma_adc; uint16_t adc_values[100]; // 存储采样结果的数组 void ADC_DMA_Init(void) { // 初始化ADCDMA hadc.Instance = ADC1; hadc.Init.ScanConvMode = ADC_SCAN_ENABLE; hadc.Init.ContinuousConvMode = ENABLE; hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc.Init.NbrOfConversion = 1; HAL_ADC_Init(&hadc); hdma_adc.Instance = DMA1_Channel1; hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE; hdma_adc.Init.MemInc = DMA_MINC_ENABLE; hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma_adc.Init.Mode = DMA_CIRCULAR; hdma_adc.Init.Priority = DMA_PRIORITY_HIGH; HAL_DMA_Init(&hdma_adc); __HAL_LINKDMA(&hadc, DMA_Handle, hdma_adc); // 配置ADC通道和采样时间 ADC_ChannelConfTypeDef sConfig = {0}; sConfig.Channel = ADC_CHANNEL_0; // 假设采样通道为ADC1的通道0 sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_13CYCLES_5; HAL_ADC_ConfigChannel(&hadc, &sConfig); } void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { // 采样完成中断处理函数 // 在这里处理采样结果 } int main(void) { // 初始化硬件和库 HAL_Init(); SystemClock_Config(); // 配置ADCDMA ADC_DMA_Init(); // 启动ADCDMA HAL_ADC_Start_DMA(&hadc, (uint32_t*)adc_values, sizeof(adc_values) / sizeof(uint16_t)); while (1) { // 主循环代码 // 在这里可以进行其他任务 } } ``` 这只是一个简单的示例,你可以根据你的需求进行自定义。希望对你有所帮助!如果有任何问题,请随时问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

醉心客丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值