STM32開發,使用CUBEMX實現ADC採樣並在串口中打印出來

1 概述

實驗的代碼已經上傳,無需積分。

1.1 資源概述

開發板:正點原子STM32F103 Nano開發板
CUBEMX版本:1.3.0
MDK版本:5.27
主控芯片型號:STM32F103RBT6
正點原子開發板

1.2 實現功能

1,適配正點原子STM32F103RB Nano開發板;
2,配置由CUBEMX生成;
3,採樣AD的數值,並在串口上打印出來。
4,ADC運行時,LED0燈閃爍,當輸出5次後,關閉ADC,同時LED0燈常亮。

2 硬件電路

3.3V通過電位器分壓,最後送到芯片的PB1腳。調整VR1的值,即可調整ADC的值。
ADC採樣電路圖

3 程序實現

3.1 CUBEMX配置

1,時鐘配置,CUBEMX配置爲6分頻,最後時鐘頻率爲12MHz。ADC的採樣頻率不能高於14MHz。最短採樣週期爲(1.5+12.5)/14M=1uS
CUBEMX配置
2,配置ADC,採樣獨立模式,數據右對齊,單次採樣,規則通道。
ADC配置

3.2 程序代碼

1,main()函數代碼如下,使用CUBEMX生成,刪除掉無用的註釋信息,並增加我們需要使用的代碼。

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
void LED0_ON(void);//函數在一開始進行申明,以;結束
void LED0_OFF(void);
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);

int main(void)
{
	uint16_t t=0;
	uint16_t ADC_B=0;
	float ADC_D=0;

  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  HAL_ADC_Start(&hadc1);//開啓ADC

  for (t=0;t<10;t++)
  {

	t++;
	HAL_ADC_PollForConversion(&hadc1,10);    //等待轉換完成,第二個參數表示超時時間,單位ms  
	if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))//Conversion data available on group regular
	{
		ADC_B = HAL_ADC_GetValue(&hadc1);
	}
	ADC_D= ADC_B*3.3/4096;
	HAL_Delay(500);	
	LED0_ON();  //調用函數,無void,如果帶void,則系統則會再次認爲是函數申明。
	HAL_Delay(500);	
	LED0_OFF();
	printf("STM32 ADC寄存器值爲%d\r\n",ADC_B);//串口輸出數據
	printf("STM32 ADC實際值值爲%1.3fV\r\n",ADC_D);
  }
	HAL_ADC_Stop(&hadc1);//關閉adc
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
  PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
int fputc(int ch,FILE *f)
{
    
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
	return ch;

}

void LED0_ON(void)//函數在結尾定義,沒有;
	{
	GPIOC->BSRR = LED0_Pin;//打開LED0
	}
void LED0_OFF(void)
	{
	 GPIOC->BSRR = (uint32_t)LED0_Pin << 16u;//關閉LED0
	}


void Error_Handler(void)
{

}

#ifdef  USE_FULL_ASSERT

void assert_failed(uint8_t *file, uint32_t line)
{ 

}
#endif /* USE_FULL_ASSERT */


2,ADC初始化函數如下。

void MX_ADC1_Init(void)
{
  ADC_ChannelConfTypeDef sConfig={0};//初始化函數聲明
 
  
  /** Common config 
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; //關閉掃描
  hadc1.Init.ContinuousConvMode = DISABLE;//連續轉換模式無效
  hadc1.Init.DiscontinuousConvMode = DISABLE;//無效連續轉換模式
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;//外部觸發爲軟件啓動
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;//數據右對齊
  hadc1.Init.NbrOfConversion = 1;//轉換次數

  
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel 
  */
  sConfig.Channel = ADC_CHANNEL_9;//配置採樣通道
  sConfig.Rank = ADC_REGULAR_RANK_1;//配置規則通道
  sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;//配置採樣週期
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

}

程序中對開燈關燈的函數進行了簡化,直接操作寄存器,沒有使用HAL 函數,相比原函數,少了有效性判定,更加簡潔,佔用的空間更少,在項目中,建議前期可以使用HAL函數實現,後續將HAL函數剝離,使用寄存器的方式,這樣做有幾個好處:
①,消除HAL函數中可能存在的BUG。
②,提高程序效率,降低Flash使用空間,特別是當程序空間在64K,128K等這種兩種芯片分段附近大小時,通過這種方式,有可能使芯片使用低一個檔次的,實現更低的成本。
當然如果項目僅僅是實驗性質的,並沒有大批量生產的需求或者市場窗口週期極短,就沒必要折騰了。HAL函數是最快最簡潔的方式。連ST官網的新一代芯片後續都不計劃提供標準庫函數版本了,只提供HAL函數版本的支持。
自定義函數採用先定義後使用的方式,另外對於無形參無返回值的函數void LED0_ON(void)在主程序中的使用方式爲 LED0_ON();不要畫蛇添足添加void,添加void表明這個還是函數聲明,而不是函數使用。
3,ADC函數說明
配置採樣通道 ADC_CHANNEL_9和配置規則通道ADC_REGULAR_RANK_1示意如下。
輸入通道和規則通道
掃描打開示意如下,本例子中只需要一個ADC,無需開啓掃描。
掃描打開
單次轉換模式和連續轉換模式,
單次轉換和連續轉換
ADC有非常多種使用方法,其它使用方式參數其對應的參考手冊。

4 實驗結果

實驗結果如下,符合預期。
實驗結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章