历史上的今天
今天是:2025年02月19日(星期三)
2020年02月19日 | stm32l151 ADC通过DMA通道定时采样电池电量
2020-02-19 来源:eefocus
最近在使用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) == RESET) {}; //如果ADC允许使用
ADC_SoftwareStartConv(ADC1); //开启ADC
while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)); //如果ADC转换结束
powervalue = (uint16_t)((After_Filter*3300*3)>>12);
}
至此,读取ADC电量步骤圆满完成!
史海拾趣
|
关键字:彩转黑摄像机 近年来,随着芯片技术的更新换代,彩转黑摄像机的整体性能有了很大的提高,“高感度,低照度”是各大厂家力推的产品特色,可以说是对弱光环境的一次集体的叫板。 对于安防监控来说,对图像品质 ...… 查看全部问答> |
|
在做2.4G射频识别时,发现有源射频识别系统的角度很难控制,尤其当标签距离识别设备小于10米时,角度基本上都是360。 在网上看到有些高人说,射频角度可以控制在15°...有谁有这方面的经验没有?如何有效控制有源射频的识别角度。 我的想法是这样 ...… 查看全部问答> |
|
向大家请教个问题:默认情况下,4G的内存,核心内存和用户态内存分别是2G,现在我写了一个驱动,需要更多的核心内存,因此想把核心内存调整的大些,应该如何做到呢? 另外,我还有个机器是8G内存,跑wxp64位系统,也想调整核心内存更 ...… 查看全部问答> |
|
将手机和PC机用USB相连: 当先将未开机的手机用USB线连到PC上,再打开手机时,从PC上向手机发送AT指令,手机能向PC返回OK;可是当先将手机开机,再将手机用USB线连接到PC机时,从PC上向手机发送AT指令,手机却不能向PC返回任何东西。不知以上是什么 ...… 查看全部问答> |
|
请问ioctl返回的地址是虚拟地址还是物理地址? 小弟在做dm6446上的resize,用ioctl返回的resize驱动中申请的buffer的地址是在用户空间是不能用的? 大家指教。 ioctl返回的地址问题?初学者,高人指点。… 查看全部问答> |
|
data verification failed at address 0x0 ? 本帖最后由 dontium 于 2015-1-23 12:45 编辑 仿真器连接正常,我用了光盘里的一个例子,编译好后下载.out程序时出现 data verification failed at address 0x0, please verify target memoty and memory map 以上错误,请问这是什么原因,我用的 ...… 查看全部问答> |




