?? ? ? ?STM32F103C8T6的ADC配置。PB0對應的是ADC1的通道8。在標準庫中,需要初始化ADC,設置通道,時鐘,轉換模式等。需要配置GPIOB的第0腳為模擬輸入模式,然后配置ADC1的通道8,設置轉換周期和觸發方式。
????????接下來是I2C屏幕的驅動,通常使用SSD1306 OLED屏,I2C地址一般為0x7a或0X7b。需要編寫I2C的初始化函數,包括GPIO配置(PB8和PB9作為SCL和SDA),設置I2C的時鐘和模式,以及實現數據的發送函數。同時,需要整合SSD1306的驅動代碼,包括初始化命令、清屏、寫字符串等函數(這里我們為了省事,直接使用江協科技)。
????????用戶提到使用標準庫,所以需要避免使用HAL的函數,轉而使用如stm32f10x_gpio.h、stm32f10x_adc.h、stm32f10x_i2c.h等頭文件中的函數。比如,ADC的初始化需要配置ADC_InitTypeDef結構體,啟動校準,然后進行轉換。I2C部分需要手動處理起始、地址發送、數據發送和停止條件。
????????另外,ADC的轉換結果需要通過計算得到電壓值,這里使用3.3V參考電壓,12位分辨率,所以電壓=adc_value * 3.3 / 4095。顯示部分需要將數值轉換為字符串,并格式化輸出到OLED上。
????????需要注意的問題包括:I2C的時序是否正確,是否添加了上拉電阻;ADC的采樣時間是否足夠,是否需要多次采樣取平均以減少噪聲;標準庫中的函數調用是否正確,例如I2C的等待標志位是否處理妥當,避免死循環。
????????最后,代碼結構應包括初始化函數(GPIO、ADC、I2C)、OLED驅動函數、主循環中的ADC讀取和顯示更新。可能還需要實現簡單的延時函數,因為標準庫中沒有HAL_Delay,可以使用SysTick或簡單的循環延時。
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "stdlib.h"int adc_value;
float voltage;
u8 buff[30];
/*** 坐標軸定義:* 左上角為(0, 0)點* 橫向向右為X軸,取值范圍:0~127* 縱向向下為Y軸,取值范圍:0~63* * 0 X軸 127 * .------------------------------->* 0 |* |* |* |* Y軸 |* |* |* |* 63 |* v* */// 初始化水泵ADC
void ADC_Init_Config(void)
{ADC_InitTypeDef ADC;GPIO_InitTypeDef GPIO;// 使能ADC1和GPIOB時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOB, ENABLE);// 配置PB0為模擬輸入模式GPIO.GPIO_Pin = GPIO_Pin_0;GPIO.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOB, &GPIO);// 配置ADC1ADC.ADC_Mode = ADC_Mode_Independent;ADC.ADC_ScanConvMode = DISABLE;ADC.ADC_ContinuousConvMode = DISABLE;ADC.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;ADC.ADC_DataAlign = ADC_DataAlign_Right;ADC.ADC_NbrOfChannel = 1;ADC_Init(ADC1, &ADC);// 配置ADC1的通道8(PB0),采樣時間為1.5周期ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_1Cycles5);// 使能ADC1ADC_Cmd(ADC1, ENABLE);// 初始化ADC校準值ADC_ResetCalibration(ADC1);while (ADC_GetResetCalibrationStatus(ADC1));ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1));
}int main(void)
{ADC_Init_Config();/*OLED初始化*/OLED_Init();/*在(0, 0)位置顯示字符'A',字體大小為8*16點陣*/OLED_ShowChar(0, 0, 'A', OLED_8X16);/*在(16, 0)位置顯示字符串"Hello World!",字體大小為8*16點陣*/OLED_ShowString(16, 0, "Hello World!", OLED_8X16);/*在(0, 18)位置顯示字符'A',字體大小為6*8點陣*/OLED_ShowChar(0, 18, 'A', OLED_6X8);/*在(16, 18)位置顯示字符串"Hello World!",字體大小為6*8點陣*/OLED_ShowString(16, 18, "Hello World!", OLED_6X8);/*在(0, 28)位置顯示數字12345,長度為5,字體大小為6*8點陣*/OLED_ShowNum(0, 28, 12345, 5, OLED_6X8);/*在(40, 28)位置顯示有符號數字-66,長度為2,字體大小為6*8點陣*/OLED_ShowSignedNum(40, 28, -66, 2, OLED_6X8);/*在(70, 28)位置顯示十六進制數字0xA5A5,長度為4,字體大小為6*8點陣*/OLED_ShowHexNum(70, 28, 0xA5A5, 4, OLED_6X8);/*在(0, 38)位置顯示二進制數字0xA5,長度為8,字體大小為6*8點陣*/OLED_ShowBinNum(0, 38, 0xA5, 8, OLED_6X8);/*在(60, 38)位置顯示浮點數字123.45,整數部分長度為3,小數部分長度為2,字體大小為6*8點陣*/OLED_ShowFloatNum(60, 38, 123.45, 3, 2, OLED_6X8);/*在(0, 48)位置顯示漢字串"你好,世界。",字體大小為固定的16*16點陣*/OLED_ShowChinese(0, 48, "你好,世界。");/*在(96, 48)位置顯示圖像,寬16像素,高16像素,圖像數據為Diode數組*/OLED_ShowImage(96, 48, 16, 16, Diode);/*在(96, 18)位置打印格式化字符串,字體大小為6*8點陣,格式化字符串為"[%02d]"*/OLED_Printf(96, 18, OLED_6X8, "[%02d]", 6);/*調用OLED_Update函數,將OLED顯存數組的內容更新到OLED硬件進行顯示*/OLED_Update();/*延時3000ms,觀察現象*/Delay_ms(3000);/*清空OLED顯存數組*/OLED_Clear();while (1){// 啟動ADC轉換ADC_SoftwareStartConvCmd(ADC1, ENABLE);// 等待轉換完成while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));// 獲取ADC轉換結果adc_value = ADC_GetConversionValue(ADC1);// 計算電壓值// STM32F103C8T6的ADC分辨率是12位,參考電壓為3.3Vvoltage = (adc_value * 3.3) / 4096;sprintf((char*)buff,"%fV ",voltage);OLED_ShowString(16, 18, buff, OLED_6X8);OLED_Update();}
}
優化建議:
? ? ? ? 1.添加ADC軟件平均濾波:
uint16_t ADC_ReadAvg(uint8_t times) {uint32_t sum = 0;for(uint8_t i=0; i<times; i++) {ADC_SoftwareStartConvCmd(ADC1, ENABLE);while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));sum += ADC_GetConversionValue(ADC1);}return sum/times;
}
????????2.顯示刷新使用局部刷新代替全屏刷新提升性能