STM32L1单片机的ADC必须开启HSI才能工作

之前玩过F1和F4的板子,这段时间,接个项目需要用低功耗,所以就整了STM32L151单片机,然后今天在写ADC的时候,发现了一个问题,就是STM32L151MCU必须要开启HSI才能工作,不然ADC转换的结果全是0,特别困惑,因为手册里面的框图这样描述了ADC1
在这里插入图片描述
可以看见,同大多数STM32单片机一样,是挂在APB2总线上的,所以我就正常的配置了外部的8M HSE作为PLL输入,PLL作为系统时钟,也开启了APB2上的ADC1外设时钟,一切都配置好后,启动ADC转换就发现数据全是0。

	/* ADC1 Periph clock enable */
    ADC_InitTypeDef     ADC_InitStructure;
    DMA_InitTypeDef     DMA_InitStructure;
    GPIO_InitTypeDef    GPIO_InitStructure;
    /* ADC1 DeInit */
    ADC_DeInit(ADC1);
    /* ADC1 Periph clock enable */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);  //这里开启了APB2上的ADC1时钟
	
    /* DMA1 clock enable */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);
	
    /* DMA1 Channel1 Config */
    DMA_DeInit(DMA1_Channel1);

在这里插入图片描述
特别困惑,之后去官方的固件库例程里面看了一下它的ADC初始化,发现有这样一段代码

	/* Enable the HSI oscillator */
    RCC_HSICmd(ENABLE);
    /* Check that HSI oscillator is ready */
    while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);

然后我在自己的程序加上了这段代码,再试果断好了,效果就是下面这个样子:

在这里插入图片描述
我是通道1接的GND,通道2接的3.3V电源,通道0是悬空的,所以从结果看起来,是正确的。然后就特别疑惑,所以就去找出参考手册去仔细阅读了一下,重要在两个地方发现了一些信息:

第一处是在5.2小节里面有这样的一句描述:
在这里插入图片描述

也就是说ADC的时钟只能来自于HSI。

同样的,第二处是在11.3.2小节里面也有类似的说明:

在这里插入图片描述

原文:
To avoid unnecessary consumption while not converting, the ADC digital interface has been designed to operate in a completely independent manner, at its maximum speed using an internal 16 MHz clock source (HSI), whatever the CPU operating frequency(which can range from a few sub-kHz up to 32 MHz).

翻译如下:
为了避免不必要的消耗而不进行转换,ADC数字接口被设计为以完全独立的方式运行,使用内部16 MHz时钟源(HSI)以其最大速度运行,而不管CPU的工作频率如何(范围从几个高达32 MHz的次kHz)。

所以综上所述,STM32L1系列的ADC时钟只能来自于HSI。顺便提下,STM32L0芯片的ADC时钟也只能来自于HSI。这和之前用过的F1有很大区别,虽然是同样的Cortex-M3内核,但是外设的安排却并不一样,这就是使用固件库带来的副作用,虽然方便开发,但是对于芯片还是很陌生,所以说遇到问题,还是需要多读芯片手册。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用HAL库实现STM32F103单片机定时器触发ADC转换的代码实现。 首先需要在CubeMX中配置好ADC和定时器的参数,然后在main.c文件中编写以下代码: ```c #include "stm32f1xx_hal.h" ADC_HandleTypeDef hadc1; TIM_HandleTypeDef htim2; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_ADC1_Init(void); static void MX_TIM2_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_ADC1_Init(); MX_TIM2_Init(); HAL_TIM_Base_Start(&htim2); //启动定时器 HAL_ADC_Start(&hadc1); //启动ADC uint32_t adc_value; //定义变量存储ADC转换结果 while (1) { HAL_ADC_PollForConversion(&hadc1, 100); //等待ADC转换完成 if (HAL_ADC_GetState(&hadc1) == HAL_ADC_STATE_EOC_REG) //判断ADC转换完成状态 { adc_value = HAL_ADC_GetValue(&hadc1); //获取ADC转换结果 //处理ADC转换结果 } } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } } static void MX_ADC1_Init(void) { ADC_ChannelConfTypeDef sConfig = {0}; hadc1.Instance = ADC1; hadc1.Init.ScanConvMode = DISABLE; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_CC2; //设置ADC触发源为定时器2的CC2输出 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1; if (HAL_ADC_Init(&hadc1) != HAL_OK) { Error_Handler(); } sConfig.Channel = ADC_CHANNEL_0; //设置采样通道为ADC1的通道0 sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } } static void MX_TIM2_Init(void) { TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; htim2.Instance = TIM2; htim2.Init.Prescaler = 35999; //设置定时器分频系数,定时器时钟频率为72MHz/(35999+1)=2kHz htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 999; //设置定时器计数周期为1000个时钟周期,即500ms产生一次触发信号 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { Error_Handler(); } } static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } ``` 在以上代码中,HAL_ADC_Init()函数用于初始化ADC,HAL_ADC_ConfigChannel()函数用于配置ADC的采样通道,HAL_TIM_Base_Init()函数用于初始化定时器,HAL_TIM_Base_Start()函数用于启动定时器,HAL_ADC_Start()函数用于启动ADC,HAL_ADC_PollForConversion()函数用于等待ADC转换完成,HAL_ADC_GetValue()函数用于获取ADC转换结果。 需要注意的是,在MX_ADC1_Init()函数中,使用了ADC_EXTERNALTRIGCONV_T2_CC2宏定义来设置ADC触发源为定时器2的CC2输出,这个宏定义在stm32f1xx_hal_adc.h头文件中定义。而在MX_TIM2_Init()函数中,使用了TIM_TRGO_UPDATE宏定义来设置定时器触发输出为更新事件触发。 以上就是使用HAL库实现STM32F103单片机定时器触发ADC转换的代码实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值