利用STM32开发板制作简易电压表

开发板电压表制作教程

1、需要材料

  • STM32芯片的开发板
  • SPI通讯协议的0.96寸OLED显示屏
  • 导线若干

2、配置开发板硬件

(1)初始化ADC模块

  • 可以去看我之前的帖子,这里就不过多赘述该步骤了

ADC模块的简单应用

(2)配置SPI通讯模块

I(粘贴)

  • OLED显示屏的厂商一般会提供显示屏的驱动,我们需要将代码复制粘贴到自己的项目中

II(移植)

如果是硬件SPI驱动的可以忽略该步骤

  • 由于厂商提供给我的驱动是软件模拟的,所以需要根据开发板的实际情况改动宏定义
    img
  • 这里我们选择PA1作为SCL端,PC2作为SDA端,PC3作为RES端,PA4作为DC端,PA5作为CS
    img
  • 根据原理图进行接线

PA1
img

PC2, PC3
img

PA4
img

PA5
img

  • 根据找到的管脚进行接线
    img
  • 在驱动代码中宏定义的部分重构
#define OLED_SCLK_Clr() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET)//CLK
#define OLED_SCLK_Set() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET)

#define OLED_SDIN_Clr() HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET)//DIN
#define OLED_SDIN_Set() HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET)


#define OLED_RST_Clr() HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_RESET)//RES
#define OLED_RST_Set() HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_SET)

#define OLED_DC_Clr() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET)//DC
#define OLED_DC_Set() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)


#define OLED_CS_Clr()  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET)//CS
#define OLED_CS_Set()  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET)

#define OLED_CMD  0	//写命令
#define OLED_DATA 1	//写数据

3、写入代码

(1)定义变量

  • 在主函数外侧定义全局变量
/* USER CODE BEGIN 0 */
uint32_t ADC_Value;//ADC模块的采样值
uint32_t Voltage;//计算后的电压值
/* USER CODE END 0 */

(2)初始化硬件

  • 在主循环外则写入以下内容
  /* USER CODE BEGIN 2 */
  OLED_Init();//OLED厂商提供的库函数,用于完成OLED的初始化
  //启用ADC模块
  HAL_Delay(10);//等待ADC模块稳定
  HAL_ADC_Start(&hadc1);
  HAL_ADC_PollForConversion(&hadc1, 100);
  OLED_ShowString(0, 4, "Simple Voltmeter", 1);//显示字符串,表明该程序为"简易电压表"
  HAL_Delay(999);//显示1秒
  OLED_Clear();//OLED厂商的库函数,用于清屏

(3)计算并显示结果

I计算浮点数

  • 由于库函数中不支持直接显示浮点数,所以我们需要手写一个显示浮点数的函数
  • 具体过程为:将采样值乘1000,分别计算出整数位和小数点后三位,用小数点隔开后依次显示
  • adc.h中声明该函数
/* USER CODE BEGIN Prototypes */
uint32_t ADC_Analyse(uint32_t value);//用于计算去掉小数点后电压的函数
/* USER CODE END Prototypes */
  • adc.c中定义该函数
/* USER CODE BEGIN 1 */
//用于计算去掉小数点后电压的函数,需要参数value,返回去掉小数点的电压值
uint32_t ADC_Analyse(uint32_t value){
	uint32_t Voltage;
	value *= 3150;//最大采样电压
	Voltage = value / 4096;
	return Voltage;
}

计算方法为:
img

  • 在主循环内写入以下内容
  while (1)
  {
        //启动ADC模块,不然采样值会保持以一次的结果
	    HAL_Delay(10);
	    HAL_ADC_Start(&hadc1);
	    ADC_Value = HAL_ADC_GetValue(&hadc1);//获取采样值
	    Voltage = ADC_Analyse(ADC_Value);//计算去掉小数点后的电压值
        //依次输出电压值的各位数
	    OLED_ShowNum(4, 4, (Voltage / 1000), 1, 3);
	    OLED_ShowChar(12, 4, '.');//用小数点隔开整数和小数位
	    Voltage = Voltage - (Voltage / 1000) * 1000;
	    OLED_ShowNum(20, 4, (Voltage / 100), 1, 3);
	    Voltage = Voltage - (Voltage / 100) * 100;
	    OLED_ShowNum(28, 4, Voltage, 1, 3);
	    Voltage = Voltage - (Voltage / 10) * 10;
	    OLED_ShowNum(36, 4, Voltage, 1, 3);
	    OLED_ShowChar(44, 4, 'V');//显示单位
	    HAL_Delay(989);//显示1秒
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

II滤波

  • 编译并烧录代码后,已经能显示电压了,但显示的结果会一直会产生很大的变动,这就需要写入滤波算法了
  • 考虑到要测量不同的目标,这里采用算术平均滤波

算术平均滤波
img

  • 重构主循环的内容,加上滤波的算法
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  ADC_Value = 0;//清空采样值
	  for(uint8_t i = 0; i < 10; i++){
		  uint16_t Value;//定义单次采样值
		  HAL_Delay(10);
		  HAL_ADC_Start(&hadc1);
		  Value = HAL_ADC_GetValue(&hadc1);
		  ADC_Value += Value;//自加
	  }
	  ADC_Value /= 10;//除去样本数,得出采样平均值
	  Voltage = ADC_Analyse(ADC_Value);
  • 将加入滤波的程序编译并烧录后,测试相应的电压显示的结果就会相对稳定了

3、实验效果

  • 在开发板启动的并完成初始化后,屏幕会产生Simple Voltmeter的字符串
    img
  • 1秒后,会开始显示电压

测量干电池电压

img

实际测量的干电池电压
img

流程图

img

4、代码清单

OLED.h

void OLED_Init(void);//初始化屏幕
void OLED_Clear(void);//清屏
void OLED_ShowCHinese(u8 x,u8 y,u8 no,u8 mod);//显示汉字,需要x,y坐标,汉字的编码,字体大小
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 mod);//显示字符串,需要x,y坐标,字符串,字体大小
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size);//显示数字,需要x,y坐标,数字,位数,字体大小

ADC.c

//计算出去掉小数点的,精确到小数点后三位的电压值,需要采样值作为参数
uint32_t ADC_Analyse(uint32_t value){
	uint32_t Voltage;
	value *= 3300;
	Voltage = value / 4096;
	return Voltage;
}
posted @ 2025-09-12 13:00  奶龙大王  阅读(67)  评论(0)    收藏  举报