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的值。
3 程序實現
3.1 CUBEMX配置
1,時鐘配置,CUBEMX配置爲6分頻,最後時鐘頻率爲12MHz。ADC的採樣頻率不能高於14MHz。最短採樣週期爲(1.5+12.5)/14M=1uS
2,配置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 實驗結果
實驗結果如下,符合預期。