使用 STM32L ADC 单独读取不同的输入

发布于 2025-01-14 20:54:45 字数 2755 浏览 4 评论 0 原文

目标是通过轮询读取多个 ADC 通道。它不需要太快——其想法是读取所连接的不同电池的电压。我有一个 STM32L071 微控制器。与STM32F0模型相比,编程有点不同。我正在使用 platformio。

我在这里发现了非常有用的信息:

但是,不幸的是我不能读出多个通道。这些问题可能与 HAL_ADC_InitHAL_ADC_ConfigChannel 有关。

这是一个最小的代码示例:

#include <Arduino.h>
#include <STM32IntRef.h>

uint32_t a1=0, a2=0;

#define HAL_ADC_MODULE_ENABLED
ADC_HandleTypeDef hadc1;

void displaying(){
    Serial.println("values:");
    Serial.println("-------");
    Serial.print("ch1 - ");
    Serial.println(a1);
    Serial.print("ch2 - ");
    Serial.println(a2);
    Serial.println("");
}

void config_ext_channel_ADC(uint32_t channel, bool val) {
  hadc1.Instance = ADC1;
  hadc1.Init.SamplingTime = ADC_SAMPLETIME_79CYCLES_5;
  HAL_ADC_Init(&hadc1);
  
  ADC_ChannelConfTypeDef sConfig;
  sConfig.Channel = channel;
  if (val == true)  {
    sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  } else {
    sConfig.Rank = ADC_RANK_NONE;
  }
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
        Serial.println("Error ADC Config Channel");
        //Error_Handler();
  }
}

uint32_t r_single_ext_channel_ADC(uint32_t channel) {
  /* read the ADC and output result */
  uint32_t digital_result;
  config_ext_channel_ADC(channel, true);
  HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
  HAL_ADC_Start(&hadc1);
  HAL_ADC_PollForConversion(&hadc1, 1000);
  digital_result = HAL_ADC_GetValue(&hadc1);
  HAL_ADC_Stop(&hadc1);
  config_ext_channel_ADC(channel, false);
  return digital_result;
}

void readBat() {
  /* read voltages */
  a1 = r_single_ext_channel_ADC(1);
  a2 = r_single_ext_channel_ADC(PA2);
}

void setup() {
  // put your setup code here, to run once:
  // Serial monitor
  Serial.begin(9600);
  Serial.println(F("Starting now"));
  // initialize pins for ADC
  analogReadResolution(ADC_RESOLUTION);
  pinMode(PA1, INPUT);
  //pinMode(BATTERY_SENSE_PIN2, INPUT);
  pinMode(PA2, INPUT_ANALOG);
}

void loop() {
  // put your main code here, to run repeatedly:
  readBat();
  displaying();
  delay(2000);
}

输出为:

values:
-------
ch1 - 0
ch2 - 140

听起来很合理,但在引脚上施加一些电压不会改变值。

有人可以给我一些建议、想法吗?

The goal is to read multiple ADC channels by polling. It does not need to be fast - the idea is to read the voltages from different batteries that are attached. I have a STM32L071 microcontroller. The programming is a bit different compared to the STM32F0 model. I am using platformio.

I found already very helpful information here:

However, unfortunately I cannot read out multiple channels. The problems are probably related to HAL_ADC_Init and HAL_ADC_ConfigChannel.

Here is a minimal code example:

#include <Arduino.h>
#include <STM32IntRef.h>

uint32_t a1=0, a2=0;

#define HAL_ADC_MODULE_ENABLED
ADC_HandleTypeDef hadc1;

void displaying(){
    Serial.println("values:");
    Serial.println("-------");
    Serial.print("ch1 - ");
    Serial.println(a1);
    Serial.print("ch2 - ");
    Serial.println(a2);
    Serial.println("");
}

void config_ext_channel_ADC(uint32_t channel, bool val) {
  hadc1.Instance = ADC1;
  hadc1.Init.SamplingTime = ADC_SAMPLETIME_79CYCLES_5;
  HAL_ADC_Init(&hadc1);
  
  ADC_ChannelConfTypeDef sConfig;
  sConfig.Channel = channel;
  if (val == true)  {
    sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  } else {
    sConfig.Rank = ADC_RANK_NONE;
  }
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
        Serial.println("Error ADC Config Channel");
        //Error_Handler();
  }
}

uint32_t r_single_ext_channel_ADC(uint32_t channel) {
  /* read the ADC and output result */
  uint32_t digital_result;
  config_ext_channel_ADC(channel, true);
  HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
  HAL_ADC_Start(&hadc1);
  HAL_ADC_PollForConversion(&hadc1, 1000);
  digital_result = HAL_ADC_GetValue(&hadc1);
  HAL_ADC_Stop(&hadc1);
  config_ext_channel_ADC(channel, false);
  return digital_result;
}

void readBat() {
  /* read voltages */
  a1 = r_single_ext_channel_ADC(1);
  a2 = r_single_ext_channel_ADC(PA2);
}

void setup() {
  // put your setup code here, to run once:
  // Serial monitor
  Serial.begin(9600);
  Serial.println(F("Starting now"));
  // initialize pins for ADC
  analogReadResolution(ADC_RESOLUTION);
  pinMode(PA1, INPUT);
  //pinMode(BATTERY_SENSE_PIN2, INPUT);
  pinMode(PA2, INPUT_ANALOG);
}

void loop() {
  // put your main code here, to run repeatedly:
  readBat();
  displaying();
  delay(2000);
}

The output is:

values:
-------
ch1 - 0
ch2 - 140

Sounds reasonable, but applying some voltages at the pins does not change the values.

Could somebody please provide me some advice, ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

韬韬不绝 2025-01-21 20:54:45

分别读取不同 ADC 通道(此处为 2 个通道的 ADC2)的代码(由 CubeMX 生成):

注意:我们必须使用 ScanConvMode 加上 DiscontinuousConvMode 和 NO ContinouslyConvMode< /代码>。


/* ADC2 init function */
void MX_ADC2_Init(void)
{

  /* USER CODE BEGIN ADC2_Init 0 */

  /* USER CODE END ADC2_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC2_Init 1 */

  /* USER CODE END ADC2_Init 1 */
  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  */
  hadc2.Instance = ADC2;
  hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc2.Init.Resolution = ADC_RESOLUTION_12B;
  hadc2.Init.ScanConvMode = ENABLE;
  hadc2.Init.ContinuousConvMode = DISABLE;
  hadc2.Init.DiscontinuousConvMode = ENABLE;
  hadc2.Init.NbrOfDiscConversion = 1;
  hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc2.Init.NbrOfConversion = 2;
  hadc2.Init.DMAContinuousRequests = DISABLE;
  hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc2) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_8;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_9;
  sConfig.Rank = 2;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC2_Init 2 */

  /* USER CODE END ADC2_Init 2 */

}

现在,阅读:


void readChannel(){
    //read the next channel
    HAL_ADC_Start(&hadc2);
    uint8_t ret = HAL_ADC_PollForConversion(&hadc2, 1000 /*timeout*/);
    uint16_t value = HAL_ADC_GetValue(hadc);
    printf("HAL_ADC_PollForConversion status: %d, VALLLL: %d\n", ret, value);
}


int main(){
    while(1){
        //Automatically read the first channel (channel 8):
        readChannel();
        HAL_Delay(100);
        
        //Automatically read the second channel (channel 9):
        readChannel();
        HAL_Delay(100);
        
    }
}

Code to read different ADC channels (here ADC2 with 2 channels) separetly (Generated By CubeMX):

Note: We have to use ScanConvMode plus DiscontinuousConvMode and NO ContinuousConvMode.


/* ADC2 init function */
void MX_ADC2_Init(void)
{

  /* USER CODE BEGIN ADC2_Init 0 */

  /* USER CODE END ADC2_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC2_Init 1 */

  /* USER CODE END ADC2_Init 1 */
  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  */
  hadc2.Instance = ADC2;
  hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc2.Init.Resolution = ADC_RESOLUTION_12B;
  hadc2.Init.ScanConvMode = ENABLE;
  hadc2.Init.ContinuousConvMode = DISABLE;
  hadc2.Init.DiscontinuousConvMode = ENABLE;
  hadc2.Init.NbrOfDiscConversion = 1;
  hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc2.Init.NbrOfConversion = 2;
  hadc2.Init.DMAContinuousRequests = DISABLE;
  hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc2) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_8;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_9;
  sConfig.Rank = 2;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC2_Init 2 */

  /* USER CODE END ADC2_Init 2 */

}

Now, to read:


void readChannel(){
    //read the next channel
    HAL_ADC_Start(&hadc2);
    uint8_t ret = HAL_ADC_PollForConversion(&hadc2, 1000 /*timeout*/);
    uint16_t value = HAL_ADC_GetValue(hadc);
    printf("HAL_ADC_PollForConversion status: %d, VALLLL: %d\n", ret, value);
}


int main(){
    while(1){
        //Automatically read the first channel (channel 8):
        readChannel();
        HAL_Delay(100);
        
        //Automatically read the second channel (channel 9):
        readChannel();
        HAL_Delay(100);
        
    }
}
我还不会笑 2025-01-21 20:54:45

好吧,同时我发现了问题。软件很好;我采用了 Arduino 框架并使用了analogRead()。

我需要清除 PCB 上的所有助焊剂,这些助焊剂会导致引脚之间产生一些接触。
此外,如果想直接使用 HAL 寻址,则应设置 ClockDivider,使 ADC 采样频率低于 1 MHz。

Okay, in the meantime I found the problem. The software is fine; I took the Arduino framework and used analogRead().

I needed to clean all the solder flux from the PCB which caused some contacts between the pins.
Moreover, if one wants to use address the HAL directly, one should set the ClockDivider such that the ADC samples below 1 MHz.

等你爱我 2025-01-21 20:54:45

您是否错过了将 io 设置为模拟模式?它应该在某个地方是这样的(通常在你的 hal msp 文件中,adc_init func)。

GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

编辑=>你错过了 ch1

analogReadResolution(ADC_RESOLUTION);
pinMode(PA1, INPUT);
//pinMode(BATTERY_SENSE_PIN2, INPUT);
pinMode(PA2, INPUT_ANALOG);

它应该与 PA2 相同,输入是“数字模式”。

Did you miss to set the io to analog in mode? It should be something like this somewhere (usually in your hal msp file, adc_init func).

GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

edit => you missed it for ch1

analogReadResolution(ADC_RESOLUTION);
pinMode(PA1, INPUT);
//pinMode(BATTERY_SENSE_PIN2, INPUT);
pinMode(PA2, INPUT_ANALOG);

It should be the same as PA2, input is "digital mode".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文