基于STM32的OLED显示的简易示波器

1. 项目概述

本项目旨在使用STM32微控制器和OLED显示屏实现一个简易的示波器。该示波器能够实时采集模拟信号,并通过OLED显示屏显示波形。项目的主要功能包括:

  • 模拟信号的采集与处理

  • 波形的实时显示

  • 简单的触发功能

2. 硬件设计
2.1 主要硬件组件
  • STM32微控制器:负责信号采集、处理和显示控制。

  • OLED显示屏:用于显示波形,通常使用I2C或SPI接口。

  • 模拟信号输入:通过STM32的ADC(模数转换器)采集模拟信号。

  • 按键:用于控制触发、时间基准等参数。

2.2 硬件连接
  • OLED显示屏

    • SCL -> STM32的SCL引脚(I2C时钟)

    • SDA -> STM32的SDA引脚(I2C数据)

    • VCC -> 3.3V

    • GND -> GND

  • 模拟信号输入

    • 信号源 -> STM32的ADC输入引脚(如PA0)

  • 按键

    • 按键1 -> STM32的GPIO引脚(用于触发控制)

    • 按键2 -> STM32的GPIO引脚(用于时间基准调整)

3. 软件设计
3.1 开发环境
  • IDE:STM32CubeIDE

  • :HAL库

3.2 程序结构
  • main.c:主程序,包含初始化、主循环和中断处理。

  • adc.c:ADC配置和信号采集。

  • oled.c:OLED显示屏的驱动和波形显示。

  • key.c:按键检测和处理。

3.3 程序讲解
3.3.1 主程序(main.c)
#include "stm32f1xx_hal.h"
#include "adc.h"
#include "oled.h"
#include "key.h"

int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_ADC1_Init();
    OLED_Init();
    KEY_Init();

    uint16_t adc_value;
    uint8_t trigger = 0;

    while (1) {
        adc_value = ADC_Read();
        if (KEY_Read() == 1) {
            trigger = 1;
        }
        if (trigger) {
            OLED_DrawWaveform(adc_value);
        }
    }
}
3.3.2 ADC配置和信号采集(adc.c)
#include "adc.h"

ADC_HandleTypeDef hadc1;

void MX_ADC1_Init(void) {
    ADC_ChannelConfTypeDef sConfig = {0};

    hadc1.Instance = ADC1;
    hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
    hadc1.Init.ContinuousConvMode = ENABLE;
    hadc1.Init.DiscontinuousConvMode = DISABLE;
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc1.Init.NbrOfConversion = 1;
    HAL_ADC_Init(&hadc1);

    sConfig.Channel = ADC_CHANNEL_0;
    sConfig.Rank = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLETIME_13CYCLES_5;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

uint16_t ADC_Read(void) {
    HAL_ADC_Start(&hadc1);
    HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
    return HAL_ADC_GetValue(&hadc1);
}
3.3.3 OLED显示屏驱动和波形显示(oled.c)
#include "oled.h"
#include "stm32f1xx_hal.h" 

void OLED_Init(void) {
    
	OLED_GPIO_Init();			//先调用底层的端口初始化
	
	/*写入一系列的命令,对OLED进行初始化配置*/
	OLED_WriteCommand(0xAE);	//设置显示开启/关闭,0xAE关闭,0xAF开启
	
	OLED_WriteCommand(0xD5);	//设置显示时钟分频比/振荡器频率
	OLED_WriteCommand(0x80);	//0x00~0xFF
	
	OLED_WriteCommand(0xA8);	//设置多路复用率
	OLED_WriteCommand(0x3F);	//0x0E~0x3F
	
	OLED_WriteCommand(0xD3);	//设置显示偏移
	OLED_WriteCommand(0x00);	//0x00~0x7F
	
	OLED_WriteCommand(0x40);	//设置显示开始行,0x40~0x7F
	
	OLED_WriteCommand(0xA1);	//设置左右方向,0xA1正常,0xA0左右反置
	
	OLED_WriteCommand(0xC8);	//设置上下方向,0xC8正常,0xC0上下反置
	

	OLED_WriteCommand(0xDA);	//设置COM引脚硬件配置
	OLED_WriteCommand(0x12);
	
	OLED_WriteCommand(0x81);	//设置对比度
	OLED_WriteCommand(0xCF);	//0x00~0xFF

	OLED_WriteCommand(0xD9);	//设置预充电周期
	OLED_WriteCommand(0xF1);

	OLED_WriteCommand(0xDB);	//设置VCOMH取消选择级别
	OLED_WriteCommand(0x30);

	OLED_WriteCommand(0xA4);	//设置整个显示打开/关闭

	OLED_WriteCommand(0xA6);	//设置正常/反色显示,0xA6正常,0xA7反色

	OLED_WriteCommand(0x8D);	//设置充电泵
	OLED_WriteCommand(0x14);

	OLED_WriteCommand(0xAF);	//开启显示
	
	OLED_Clear();				//清空显存数组
	OLED_Update();				//更新显示,清屏,防止初始化后未显示内容时花屏
}

void OLED_DrawWaveform(uint16_t value) {
   	int16_t x, y, dx, dy, d, incrE, incrNE, temp;
	int16_t x0 = X0, y0 = Y0, x1 = X1, y1 = Y1;
	uint8_t yflag = 0, xyflag = 0;
	
	if (y0 == y1)		//横线单独处理
	{
		/*0号点X坐标大于1号点X坐标,则交换两点X坐标*/
		if (x0 > x1) {temp = x0; x0 = x1; x1 = temp;}
		
		/*遍历X坐标*/
		for (x = x0; x <= x1; x ++)
		{
			OLED_DrawPoint(x, y0);	//依次画点
		}
	}
	else if (x0 == x1)	//竖线单独处理
	{
		/*0号点Y坐标大于1号点Y坐标,则交换两点Y坐标*/
		if (y0 > y1) {temp = y0; y0 = y1; y1 = temp;}
		
		/*遍历Y坐标*/
		for (y = y0; y <= y1; y ++)
		{
			OLED_DrawPoint(x0, y);	//依次画点
		}
	}
	else				//斜线
	{
		/*使用Bresenham算法画直线,可以避免耗时的浮点运算,效率更高*/
		/*参考文档:https://www.cs.montana.edu/courses/spring2009/425/dslectures/Bresenham.pdf*/
		/*参考教程:https://www.bilibili.com/video/BV1364y1d7Lo*/
		
		if (x0 > x1)	//0号点X坐标大于1号点X坐标
		{
			/*交换两点坐标*/
			/*交换后不影响画线,但是画线方向由第一、二、三、四象限变为第一、四象限*/
			temp = x0; x0 = x1; x1 = temp;
			temp = y0; y0 = y1; y1 = temp;
		}
		
		if (y0 > y1)	//0号点Y坐标大于1号点Y坐标
		{
			/*将Y坐标取负*/
			/*取负后影响画线,但是画线方向由第一、四象限变为第一象限*/
			y0 = -y0;
			y1 = -y1;
			
			/*置标志位yflag,记住当前变换,在后续实际画线时,再将坐标换回来*/
			yflag = 1;
		}
		
		if (y1 - y0 > x1 - x0)	//画线斜率大于1
		{
			/*将X坐标与Y坐标互换*/
			/*互换后影响画线,但是画线方向由第一象限0~90度范围变为第一象限0~45度范围*/
			temp = x0; x0 = y0; y0 = temp;
			temp = x1; x1 = y1; y1 = temp;
			
			/*置标志位xyflag,记住当前变换,在后续实际画线时,再将坐标换回来*/
			xyflag = 1;
		}
		
		/*以下为Bresenham算法画直线*/
		/*算法要求,画线方向必须为第一象限0~45度范围*/
		dx = x1 - x0;
		dy = y1 - y0;
		incrE = 2 * dy;
		incrNE = 2 * (dy - dx);
		d = 2 * dy - dx;
		x = x0;
		y = y0;
		
		/*画起始点,同时判断标志位,将坐标换回来*/
		if (yflag && xyflag){OLED_DrawPoint(y, -x);}
		else if (yflag)		{OLED_DrawPoint(x, -y);}
		else if (xyflag)	{OLED_DrawPoint(y, x);}
		else				{OLED_DrawPoint(x, y);}
		
		while (x < x1)		//遍历X轴的每个点
		{
			x ++;
			if (d < 0)		//下一个点在当前点东方
			{
				d += incrE;
			}
			else			//下一个点在当前点东北方
			{
				y ++;
				d += incrNE;
			}
			
			/*画每一个点,同时判断标志位,将坐标换回来*/
			if (yflag && xyflag){OLED_DrawPoint(y, -x);}
			else if (yflag)		{OLED_DrawPoint(x, -y);}
			else if (xyflag)	{OLED_DrawPoint(y, x);}
			else				{OLED_DrawPoint(x, y);}
		}	
	}
}

3.3.4 按键检测和处理(key.c)
#include "key.h"
#include "stm32f1xx_hal.h"

void KEY_Init(void) {
    // 按键GPIO初始化
    GPIO_InitTypeDef GPIO_InitStruct;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA时钟
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2; // 假设按键连接到PA0
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入模式
    GPIO_Init(GPIOA, &GPIO_InitStruct);
}

uint8_t KEY_Read(void) {
    // 读取按键状态
 uint8_t current_key_state = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2); // 读取当前按键状态

    // 检测按键状态变化
    if (current_key_state != last_key_state) {
        Delay_ms(DEBOUNCE_TIME); // 延时去抖
        current_key_state = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2); // 再次读取按键状态

        if (current_key_state == Bit_RESET) { // 按键按下
            key_state = 1;
        } else {
            key_state = 0;
        }
    }

    last_key_state = current_key_state; // 更新上一次按键状态
}
 
4. 功能实现
4.1 信号采集

通过STM32的ADC模块实时采集模拟信号,并将其转换为数字信号。

4.2 波形显示

将采集到的数字信号映射到OLED显示屏的Y坐标,并在屏幕上绘制波形。

4.3 触发功能

通过按键控制波形的触发,确保波形在屏幕上稳定显示。

5. 总结

本项目实现了一个基于STM32的简易示波器,能够实时采集和显示模拟信号。通过OLED显示屏,用户可以直观地观察波形。项目代码结构清晰,易于扩展和修改,适合初学者学习和实践。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值