STM32筆記(21):ADC 顯示電壓值在 OLED(下)


[讀取電壓值設定步驟]

(1) 開啟 ADC1 時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

(2) 設定 ADC1 分頻因子
使用 RCC_ADCCLKConfig() 設置 ADC1 的分頻因子。分頻因子要確保 ADC1 的時鐘(ADCCLK)不要超過 14 Mhz。因此設置分頻因子位為 6,時鐘為 72 / 6 = 12MHz。
RCC_ADCCLKConfig(RCC_PCLK2_Div6);

(3) 將 ADC 恢復初始值
ADC_DeInit(ADC1);

(4) 使用 GPIOA 的總線時鐘並使用 GPIO_Init()函式設定 GPIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;  //模擬輸入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

(5) 設定 ADC1 的工作模式、資料對齊等,並初始化 ADC1
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;    // 用來設置 ADC 為獨立模式
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	// 設定資料靠右對齊
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  // 設定啟動規則轉換的外部事件為 None
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;	// 設定停用連續轉換模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE;		// 設定停用掃描模式
ADC_InitStructure.ADC_NbrOfChannel = 1;		// 設定規則序列開啟的通道:1 個
ADC_Init(ADC1, &ADC_InitStructure);		// 初始化

(6) 設定其在序列器中的相應等級為 1 及其採樣時間為 55.5,並啟動 ADC1
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
ADC_Cmd(ADC1, ENABLE);  //啟用 ADC1

(7) 執行複位校準,不準將導致結果不正確
		
ADC_ResetCalibration(ADC1);			//重置指定的 ADC 的校準暫存器
while (ADC_GetResetCalibrationStatus(ADC1) == SET);  //等待上一步操作完成
ADC_StartCalibration(ADC1);  			//開始指定ADC的校準狀態
while (ADC_GetCalibrationStatus(ADC1) == SET);  //等待上一步操作完成

(8) 進入主程式迴圈,執行以下轉換副程式
	
uint16_t ADCX_GetValue(void)
{
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);   //指定 ADC1 軟體轉換功能
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
	return ADC_GetConversionValue(ADC1);	//回傳最新的 ADC1 轉換結果。
}

[材料]

  • STM32F103C8T6 主板 x 1
  • OLED SSD1306 顯示器 x 1
  • 麵包板 x 1
  • STLINK V2 模擬下載器 x 1
  • 可變電阻 x 1
  • 連接線 x n 條

[接線與電路圖]

可變電阻的左右兩個接腳接在 GND 及 3.3V,另一腳接在 STM32F103x PA0,與 SSD1306 連接的方式如下:
STM32F103xSSD1306 OLED
3.3vVDD
GNDGND
B8SCK/SCL
B9SDA



[程式]

主程式一開始先對 ADC 進行初始化,進入迴圈循環後,透過 ADC 讀取數值,將 0~4096 的值轉換成 0~3.3V,主程式 main.c 如下:
#include "stm32f10x.h"
#include "delay.h"
#include "oled.h"
#include "bmp.h"
#include "adcx.h"

float ADValue;

int main (void)
{
	uint16_t vtg;
	delay_init();	   	//延時函數初始化	  	
	OLED_Init();		//初始化OLED  
	ADCX_Init();
	
	OLED_Clear(0);     	//清除螢幕
	
	OLED_ShowString(1, 2, "ADValue:",16);
	OLED_ShowString(1, 4, "Voltage:",16);

	while (1)
	{
		ADValue = ADCX_GetValue(0);
		OLED_ShowNum(70, 2, ADValue, 4, 16);		
		OLED_ShowNum(70, 4, ADValue / 4096 * 3.3, 1, 16);   //整數位
		OLED_ShowString(80, 4, ".",16); 

		vtg = (uint16_t)(ADValue / 4096 * 3.3 * 100) % 100;  //小數點後兩位
		if (vtg < 10) {
			OLED_ShowNum(88, 4, vtg, 2, 16);	
			OLED_ShowString(87, 4,"0",16); 		//個位數時前面補0	
		} else
		{
			OLED_ShowNum(88, 4, vtg, 2, 16);			
		}
		
		delay_ms(500);
	}
}

adcx.c 程式如下:
#include "stm32f10x.h" 

void ADCX_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	ADC_DeInit(ADC1);  //重設 ADC1
	
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	ADC_InitStructure.ADC_NbrOfChannel = 1;
	ADC_Init(ADC1, &ADC_InitStructure);
	
		
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while (ADC_GetCalibrationStatus(ADC1) == SET);
}

uint16_t ADCX_GetValue(u8 ch)
{
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_55Cycles5);

	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
	return ADC_GetConversionValue(ADC1);
}
adcx.h 程式如下:
#ifndef __ADCX_H
#define __ADCX_H
void ADCX_Init(void);
uint16_t ADCX_GetValue(u8 ch);

#endif


完整的程式請參考 Github:7. ADC Dispaly Voltage on OLED

[結果]

旋轉可變電阻,電壓隨著改變。

[參考資料]

Post a Comment

較新的 較舊