×
单片机 > 单片机程序设计 > 详情

stm32l151 ADC通过DMA通道定时采样电池电量

发布时间:2020-08-26 发布时间:
|

  最近在使用stm32l151开发一个项目,我的项目需求是ADC采集电池电量,通过DMA通道传送出来。然而我并不是得到了电池电量数据后就立马连续输出,而是通过tim4定时器每1s访问一次采样得到的电池数据,并显示出来。本来网上关于stm32通过adc通道采集电池电量的代码很多,但要找到和我的需求一样的,还真没有。于是在借鉴其他人代码的基础上,根据我的特殊需求,写了一份这样功能的代码。


  因为我的需求涉及到了tim4定时器,adc和dma,所以在最终配置的时候也分为几个部分:

  1.首先是定时器tim4。

   a)初始化


void vTim4_Init(void)

{

 TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

 

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);


/* Time base configuration */

TIM_TimeBaseStructure.TIM_Period = TIMER4_PERIOD_TIMING;

TIM_TimeBaseStructure.TIM_Prescaler = u32Tim4PrescalerValue;


TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;


TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

/* TIM IT enable */

TIM_ITConfig(TIM4, TIM_IT_Update |TIM_IT_Trigger, ENABLE); 


  /* TIM14 disable */

TIM_Cmd(TIM4, DISABLE);

}


   b)NVIC中断设置


/* Enable the TIMER4 Interrupt */

NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 10;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

NVIC_Init(&NVIC_InitStructure);

}


   c)Tim4中断函数书写,我这里是通过给任务一个信号量longtimerTaskSemaphoreHandler,唤醒获取电量的任务来获取电量数据并显示。


void vTimer4_Interrupt(void)

{

BaseType_t xHigherPriorityTaskWoken;

if(TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)

{

xSemaphoreGiveFromISR(longtimerTaskSemaphoreHandler,&xHigherPriorityTaskWoken);

if(xHigherPriorityTaskWoken == pdTRUE)

portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

TIM_ClearITPendingBit(TIM4, TIM_IT_Update);

}

}


  2.其次是adc。

   a)adc的GPIO口初始化


void ADC_GPIO_INIT()

{

GPIO_InitTypeDef GPIO_InitStructure;


RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);  //打开对应GPIO的时钟

GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_1;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

GPIO_Init(GPIOA, &GPIO_InitStructure);

}


   b)adc通道的初始化设置


void ADC_INIT()

{

ADC_InitTypeDef ADC_InitStructure;


RCC_HSICmd(ENABLE);                    //开启HSI时钟,非常重要,stm32l151的时钟由HSI提供

while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);      //使能ADC1时钟

ADC_InitStructure.ADC_ScanConvMode             = DISABLE;        //关闭扫描模式,因为多ADC通道同时使用时才打开

ADC_InitStructure.ADC_ContinuousConvMode       = ENABLE;        //连续转换模式,因为我需要连续取十次数据

ADC_InitStructure.ADC_ExternalTrigConvEdge     = ADC_ExternalTrigConvEdge_None;        //不适用外部触发转换

ADC_InitStructure.ADC_DataAlign                = ADC_DataAlign_Right;                 //采集数据右对齐

ADC_InitStructure.ADC_Resolution               = ADC_Resolution_12b;       //分辨率是12位

ADC_InitStructure.ADC_NbrOfConversion          = 1;                  //要转换的通道数目1

ADC_Init(ADC1, &ADC_InitStructure);


ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_48Cycles);     //设置adc1的通道0的转换周期为48个采样周期

ADC_DMACmd(ADC1, ENABLE);                                                 //启动DMA搬运ADC数值

ADC_Cmd(ADC1, ENABLE);                                                    //打开ADC

while(ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) == RESET);    //等待ADC1转换完成,必须返回值是SET  

ADC_SoftwareStartConv(ADC1);                            //打开软件触发

}


  3.dma的设置。

   a)dma初始化设置


void DMA_CONFIG()

{

DMA_InitTypeDef DMA_InitStructure;


RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);                       //开启DMA时钟

DMA_DeInit(DMA1_Channel1);                                             //DMA复位

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC1->DR));             //ADC地址

DMA_InitStructure.DMA_MemoryBaseAddr     = (uint32_t)&ADC_ConvertedValue;     //存储地址

DMA_InitStructure.DMA_DIR                        = DMA_DIR_PeripheralSRC;     //DMA传输方向为设备到内存

DMA_InitStructure.DMA_BufferSize               = 10;                   //存储大小,所以前面的ADC我设置的是连续转换

DMA_InitStructure.DMA_PeripheralInc          = DMA_PeripheralInc_Disable;                //外存地址固定                 

DMA_InitStructure.DMA_MemoryInc            = DMA_MemoryInc_Enable;                 //内存地址递增,这样从ADC转换过来的数据才能依次传到目标地址上,否则的话就是固定写在一个地址上,并且前面的数据把后面的覆盖了                                                                             

DMA_InitStructure.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_HalfWord;     //每次发送是半字,即16位

DMA_InitStructure.DMA_MemoryDataSize    = DMA_MemoryDataSize_HalfWord;           //每次存储数据单位为半字,即16位

DMA_InitStructure.DMA_Mode              = DMA_Mode_Circular;                     //循环AD

DMA_InitStructure.DMA_Priority                  = DMA_Priority_High;      //DMA优先级高

DMA_InitStructure.DMA_M2M                      = DMA_M2M_Disable;         //DMA禁止内存到内存

DMA_Init(DMA1_Channel1, &DMA_InitStructure);                              //DMA初始化

DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);                           //使能DMA发送完中断

DMA_ClearITPendingBit(DMA1_IT_TC1);                                       //清除中断位

DMA_Cmd(DMA1_Channel1, ENABLE);                                           //启动DMA通道1

}


   b)dma的中断设置


void DMA_CONFIG()

{

NVIC_InitTypeDef NVIC_InitStructure;

NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 13;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

}


   c)dma中断函数书写。


void DMA1_Channel1_IRQHandler(void)

{  

u32 i;

u32 After_Buff=0;

 

    if (DMA_GetITStatus(DMA_IT_TC) != RESET)

    {

      DMA_ClearITPendingBit(DMA1_IT_TC1);        //清除DMA中断标志位            

ADC_DMACmd(ADC1, DISABLE);                //停止DMA搬运ADC数值

ADC_Cmd(ADC1,DISABLE);                    //停止ADC转换,我是通过Tim4定时器产生的中断来开关DMA和ADC。

for(i = 0;i < buff_size;i++)

{

After_Buff = After_Buff+ADC_ConvertedValue[i];

After_Filter=After_Buff/10;   //强制转换后电量显示正常

After_Buff=0;

    }

   

}



    最后回到mian()函数部分了,通过Tim4定时触发读取电池电量的任务,读取并显示。


void AdcTransfer(void)

{

u32 powervalue;

ADC_DMACmd(ADC1, ENABLE);                 //开启DMA搬运数据

ADC_Cmd(ADC1, ENABLE);                    //开启ADC转换 

while(ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) == R


关键字:stm32l151  ADC  DMA通道  定时采样  电池电量

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
单片机的抗干扰措施有哪些