【stm32开发】stm32+oled最小系统板资料(原理图、PCB、示例代码)【六一】

🎉欢迎来到stm32专栏~stm32+oled最小系统板


  • ☆* o(≧▽≦)o *☆~我是小夏与酒🍹
  • 博客主页:小夏与酒的博客
  • 🎈该系列文章专栏:stm32专栏
  • 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
  • 📜 欢迎大家关注! ❤️
    专栏图片

CSDN

遇见未来

一、效果演示

🥝示例代码演示

代码演示
特写:
特写

🥝外观展示

正面:
正面1
背面:
背面
加上oled屏:
正面2
如果需要板子的原理图、PCB和示例代码工程文件,请从我上传的资源中下载:stm32+oled最小系统板资料(原理图、PCB、示例代码)或者三连本文章后联系我免费获取
狗头保命

二、原理图与PCB

我使用了最最最可爱的嘉立创EDA完成了stm32+oled最小系统板的绘制。

2.1 原理图

先介绍原理图部分:
🔸整体原理图
完整原理图
🔸电源接口部分:最简单的,通过排针接入5V电源。
电源接口

🔸电源降压部分:使用AMS1117完成5V转3.3V的任务。
电源部分
🔸滤波电路部分:该部分也可以称为电源滤波退耦电路。
滤波电路
🔸按键部分:加入该部分是为了便于实现控制操作和交互操作,设计三个用户按键,满足多数设计开发需求。
按键部分
🔸MCU部分:在此我只使用了8M的晶振,如果需要使用32.768KHz的晶振,加入即可。
MCU部分
🔸复位电路部分:就是正常的复位电路。
复位电路
🔸程序下载部分:SWD程序下载接口。
程序下载
🔸oled接口部分:为了方便直接使用oled显示屏,在画板子的时候直接引出对应的接口。
oled接口
🔸电源指示部分:用于显示电压是否正常。
电源指示
🔸板载led部分:板载led接了PC13,使用时注意配置引脚。
板载led
🔸其余引脚部分:将剩余的引脚引出。
引脚

2.2 PCB

顶层:
顶层

底层:
底层

3D:
3D

2.3 PCB布局

对于PCB的布局,我从一些参考资料中进行了整理。

STM32F103C8T6相关布线知识点:
1、布局中应参考原理图,根据电路的主信号流向规律安排主要元器件。

2、Boot0和Boot1都接到地,就是正常工作模式:Boot0和Boot1都加一个10K的电阻,然后接到地。

3、晶振电路:

晶振与两个电容并联使用,电容的大小由晶振决定,一般使用22pF。

  • 画板时晶振尽量离芯片近一点;
  • 晶振底部尽量不要穿过其他支路,防止信号串扰;
  • 晶振、芯片、电容(与晶振相连的电容要紧邻晶振)之间的走线要尽量直且短;
  • 不同型号的晶振可能需要不同的电路设计,根据自己使用的晶振型号设计。

4、AMS1117降压电路,5V转3.3V:
降压

  • 输入滤波电容的作用:
    输入电压,当接入电源,其幅值是从零起始的,波动非常大,加入足够容量的电容进行滤波后,因电容的充放电效应,该脉动直流变成纹波不大的直流电,这是输入滤波的作用。
  • 输出滤波电容的作用:
    稳压电路的工作过程需要从输出采样,然后根据其反馈值调节输出以达稳压的目的。如果此时没有输出滤波电容,只要因负载变化带来的电压波动频率恰好与稳压电路的调节速率差不多就会产生振荡效应,导致输出失控,所以稳压输出也必须加滤波电容,而且增加滤波电容也可以进一步增加稳压输出的稳定性。
  • 大电容和小电容并联的作用:
    至于与大容量电解电容并联的小电容,其作用在于旁路频率较高的波动电压,因为铝电解电容的制造工艺导致其具有较大的ESL(等效电感),无法滤除高频成份,故需加个小电容。

5、去耦电容:
去耦电容

  • 主要用来滤除杂波,保持引脚电压的稳定。
  • 这些电容也尽量离芯片相关引脚近一点。
  • 分布在芯片四周即可。
  • 去耦电容应尽量放置在相应的VCC和GND引脚之间,且距离IC尽可能近,使之与VCC和GND之间形成的回路最短。

6、导线线宽最小为10mil。

7、同一功能模块集中原则。即实现同一功能的相关电路模块中的元器件就近集中布局。

8、遵守“先大后小,先难后易”的原则,即重要的单元电路、核心元器件应优先布局。

9、元器件的排列要便于调试和维修,即小元器件周围不能放置大元器件,需调试的元器件周围要有足够的空间。

10、布局时,位于电路板边缘的元器件离电路板边缘一般不小于2mm,如果空间允许,建议距离保持在5mm。

11、电源主干线原则上要加粗(尤其是电路板的电源输入/输出线)。

12、高频信号线,如STM32核心板上的晶振电路的布线,不要加粗,建议也按照线宽为10mil进行设计,而且尽可能布线在同一层。

13、100mil = 2.54mm(39.37mil = 1mm)。

14、过孔的放置:

  • 普通的电阻、电容、电感、磁珠焊盘周围的过孔边缘与焊盘边缘至少保持在0.15mm(5.91mil)以上。
  • IC、SOT、大型电感、电解电容、二极管、连接器等焊盘周围的过孔与焊盘边缘至少保持在0.5mm(19.69mil)以上。
  • 防止元件回流时,锡膏从过孔流失。

15、添加泪滴:使信号传输时平滑阻抗,减少阻抗的急剧跳变。

大家在画PCB时,可以参考上述布线规则,如果有误或者更好的建议,希望能在评论区中指出。

三、示例代码

示例代码使用江协科技的教学代码:STM32入门教程-2023持续更新中

🔸项目一览:
项目一览

🔸main.c:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Key.h"
#include "LED.h"
#include "GPIOPC13.h"

int main(void)
{
	OLED_Init();
	
	OLED_Init_Display();
	
	Key1_Init();
	Key2_Init();
	Key3_Init();
	
	DIO_GPIO_OUT_Init();//PC13
	
	while (1)
	{
		Key_Ctrl_OLED();
	}
	
}

🔸PC13: 由于板载led接了PC13,所以需要对PC13进行相应的配置。

GPIOPC13.c:

#include "stm32f10x.h"                  // Device header

#include "Delay.h"

#define      TM1668_APBxClock_FUN    RCC_APB2PeriphClockCmd

#define      TM1668_RCC_DIO          RCC_APB2Periph_GPIOC
#define      TM1668_DIO_PORT         GPIOC
#define      TM1668_DIO_PIN          GPIO_Pin_13

void DIO_GPIO_OUT_Init(void)
{       
      GPIO_InitTypeDef GPIO_InitStructure;
      TM1668_APBxClock_FUN(TM1668_RCC_DIO|RCC_APB2Periph_AFIO,ENABLE);
      BKP_TamperPinCmd(DISABLE);
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    
      GPIO_InitStructure.GPIO_Pin =TM1668_DIO_PIN;
      GPIO_Init(TM1668_DIO_PORT, &GPIO_InitStructure);    
}
void DIO_GPIO_IN_Init(void)
{    
      GPIO_InitTypeDef GPIO_InitStructure;
      TM1668_APBxClock_FUN(TM1668_RCC_DIO|RCC_APB2Periph_AFIO,ENABLE);
      BKP_TamperPinCmd(DISABLE);
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
      GPIO_InitStructure.GPIO_Pin = TM1668_DIO_PIN;
      GPIO_Init(TM1668_DIO_PORT, &GPIO_InitStructure);          
}

GPIOPC13.h:

#ifndef __GPIO_PC13
#define __GPIO_PC13

void DIO_GPIO_OUT_Init(void);
 
void DIO_GPIO_IN_Init(void);
 
#endif

🔸OLED: 用于显示屏输出。

OLED.c:

#include "stm32f10x.h"
#include "OLED_Font.h"

/*引脚配置*/
#define OLED_W_SCL(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_6, (BitAction)(x))
#define OLED_W_SDA(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_7, (BitAction)(x))

/*引脚初始化*/
void OLED_I2C_Init(void)
{
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	OLED_W_SCL(1);
	OLED_W_SDA(1);
}

/**
  * @brief  I2C开始
  * @param  无
  * @retval 无
  */
void OLED_I2C_Start(void)
{
	OLED_W_SDA(1);
	OLED_W_SCL(1);
	OLED_W_SDA(0);
	OLED_W_SCL(0);
}

/**
  * @brief  I2C停止
  * @param  无
  * @retval 无
  */
void OLED_I2C_Stop(void)
{
	OLED_W_SDA(0);
	OLED_W_SCL(1);
	OLED_W_SDA(1);
}

/**
  * @brief  I2C发送一个字节
  * @param  Byte 要发送的一个字节
  * @retval 无
  */
void OLED_I2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		OLED_W_SDA(Byte & (0x80 >> i));
		OLED_W_SCL(1);
		OLED_W_SCL(0);
	}
	OLED_W_SCL(1);	//额外的一个时钟,不处理应答信号
	OLED_W_SCL(0);
}

/**
  * @brief  OLED写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void OLED_WriteCommand(uint8_t Command)
{
	OLED_I2C_Start();
	OLED_I2C_SendByte(0x78);		//从机地址
	OLED_I2C_SendByte(0x00);		//写命令
	OLED_I2C_SendByte(Command); 
	OLED_I2C_Stop();
}

/**
  * @brief  OLED写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void OLED_WriteData(uint8_t Data)
{
	OLED_I2C_Start();
	OLED_I2C_SendByte(0x78);		//从机地址
	OLED_I2C_SendByte(0x40);		//写数据
	OLED_I2C_SendByte(Data);
	OLED_I2C_Stop();
}

/**
  * @brief  OLED设置光标位置
  * @param  Y 以左上角为原点,向下方向的坐标,范围:0~7
  * @param  X 以左上角为原点,向右方向的坐标,范围:0~127
  * @retval 无
  */
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
	OLED_WriteCommand(0xB0 | Y);					//设置Y位置
	OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));	//设置X位置高4位
	OLED_WriteCommand(0x00 | (X & 0x0F));			//设置X位置低4位
}

/**
  * @brief  OLED清屏
  * @param  无
  * @retval 无
  */
void OLED_Clear(void)
{  
	uint8_t i, j;
	for (j = 0; j < 8; j++)
	{
		OLED_SetCursor(j, 0);
		for(i = 0; i < 128; i++)
		{
			OLED_WriteData(0x00);
		}
	}
}

/**
  * @brief  OLED显示一个字符
  * @param  Line 行位置,范围:1~4
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的一个字符,范围:ASCII可见字符
  * @retval 无
  */
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{      	
	uint8_t i;
	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);		//设置光标位置在上半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i]);			//显示上半部分内容
	}
	OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);	//设置光标位置在下半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);		//显示下半部分内容
	}
}

/**
  * @brief  OLED显示字符串
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串,范围:ASCII可见字符
  * @retval 无
  */
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i++)
	{
		OLED_ShowChar(Line, Column + i, String[i]);
	}
}

/**
  * @brief  OLED次方函数
  * @retval 返回值等于X的Y次方
  */
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y--)
	{
		Result *= X;
	}
	return Result;
}

/**
  * @brief  OLED显示数字(十进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~4294967295
  * @param  Length 要显示数字的长度,范围:1~10
  * @retval 无
  */
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/**
  * @brief  OLED显示数字(十进制,带符号数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-2147483648~2147483647
  * @param  Length 要显示数字的长度,范围:1~10
  * @retval 无
  */
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
	uint8_t i;
	uint32_t Number1;
	if (Number >= 0)
	{
		OLED_ShowChar(Line, Column, '+');
		Number1 = Number;
	}
	else
	{
		OLED_ShowChar(Line, Column, '-');
		Number1 = -Number;
	}
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/**
  * @brief  OLED显示数字(十六进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFFFFFF
  * @param  Length 要显示数字的长度,范围:1~8
  * @retval 无
  */
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i, SingleNumber;
	for (i = 0; i < Length; i++)							
	{
		SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
		if (SingleNumber < 10)
		{
			OLED_ShowChar(Line, Column + i, SingleNumber + '0');
		}
		else
		{
			OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
		}
	}
}

/**
  * @brief  OLED显示数字(二进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
	}
}

/**
  * @brief  OLED初始化
  * @param  无
  * @retval 无
  */
void OLED_Init(void)
{
	uint32_t i, j;
	
	for (i = 0; i < 1000; i++)			//上电延时
	{
		for (j = 0; j < 1000; j++);
	}
	
	OLED_I2C_Init();			//端口初始化
	
	OLED_WriteCommand(0xAE);	//关闭显示
	
	OLED_WriteCommand(0xD5);	//设置显示时钟分频比/振荡器频率
	OLED_WriteCommand(0x80);
	
	OLED_WriteCommand(0xA8);	//设置多路复用率
	OLED_WriteCommand(0x3F);
	
	OLED_WriteCommand(0xD3);	//设置显示偏移
	OLED_WriteCommand(0x00);
	
	OLED_WriteCommand(0x40);	//设置显示开始行
	
	OLED_WriteCommand(0xA1);	//设置左右方向,0xA1正常 0xA0左右反置
	
	OLED_WriteCommand(0xC8);	//设置上下方向,0xC8正常 0xC0上下反置

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

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

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

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

	OLED_WriteCommand(0xA6);	//设置正常/倒转显示

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

	OLED_WriteCommand(0xAF);	//开启显示
		
	OLED_Clear();				//OLED清屏
}

void OLED_Init_Display(void)
{
	OLED_ShowChar(1, 1, 'A');
	OLED_ShowString(1, 3, "Hello World!");
	OLED_ShowNum(2, 1, 12345, 5);
	OLED_ShowSignedNum(2, 7, -66, 2);
	OLED_ShowHexNum(3, 1, 0xAA55, 4);
	OLED_ShowBinNum(4, 1, 0xAA55, 16);
}

OLED.h:

#ifndef __OLED_H
#define __OLED_H

void OLED_Init_Display(void);

void OLED_Init(void);
void OLED_Clear(void);
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char);
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String);
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length);
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);

#endif

🔸按键控制: 用于实现按键控制和人机交互。

Key.c:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "LED.h"

void Key1_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

void Key2_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void Key3_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

void Key_Ctrl_OLED(void)
{
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0)
	{
		LED_ON();
		OLED_Init();
		OLED_ShowString(1, 1, "Hello World!");
	}
	else
	{
		LED_OFF();
	}
	
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13) == 0)
	{
		LED_ON();
		OLED_Init();
		OLED_ShowString(2, 1, "Stm32 + OLED!");
	}
	else
	{
		LED_OFF();
	}
	
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0)
	{
		LED_ON();
		OLED_Init();
		OLED_ShowString(3, 1, "XiaoXia!");
	}
	else
	{
		LED_OFF();
	}
	
}

Key.h:

#ifndef __KEY_H
#define __KEY_H

void Key1_Init(void);
void Key2_Init(void);
void Key3_Init(void);
void Key_Ctrl_OLED(void);

#endif

csdn

🧸结尾


  • 40
    点赞
  • 107
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 25
    评论
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小夏与酒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值