欢迎来到stm32专栏~stm32+oled最小系统板
特写:
正面:
背面:
加上oled屏:
如果需要板子的原理图、PCB和示例代码工程文件,请从我上传的资源中下载:stm32+oled最小系统板资料(原理图、PCB、示例代码)。或者三连本文章后联系我免费获取!
我使用了最最最可爱的嘉立创EDA完成了stm32+oled最小系统板的绘制。
先介绍原理图部分:
整体原理图:
电源接口部分:最简单的,通过排针接入5V
电源。
电源降压部分:使用AMS1117
完成5V转3.3V
的任务。
滤波电路部分:该部分也可以称为电源滤波退耦电路。
按键部分:加入该部分是为了便于实现控制操作和交互操作,设计三个用户按键,满足多数设计开发需求。
MCU部分:在此我只使用了8M
的晶振,如果需要使用32.768KHz
的晶振,加入即可。
复位电路部分:就是正常的复位电路。
程序下载部分:SWD程序下载接口。
oled接口部分:为了方便直接使用oled显示屏,在画板子的时候直接引出对应的接口。
电源指示部分:用于显示电压是否正常。
板载led部分:板载led接了PC13
,使用时注意配置引脚。
其余引脚部分:将剩余的引脚引出。
对于PCB的布局,我从一些参考资料中进行了整理。
STM32F103C8T6相关布线知识点:
1、布局中应参考原理图,根据电路的主信号流向规律安排主要元器件。
2、Boot0和Boot1都接到地,就是正常工作模式:Boot0和Boot1都加一个10K的电阻,然后接到地。
3、晶振电路:
晶振与两个电容并联使用,电容的大小由晶振决定,一般使用22pF。
6、导线线宽最小为10mil。
7、同一功能模块集中原则。即实现同一功能的相关电路模块中的元器件就近集中布局。
8、遵守“先大后小,先难后易”的原则,即重要的单元电路、核心元器件应优先布局。
9、元器件的排列要便于调试和维修,即小元器件周围不能放置大元器件,需调试的元器件周围要有足够的空间。
10、布局时,位于电路板边缘的元器件离电路板边缘一般不小于2mm,如果空间允许,建议距离保持在5mm。
11、电源主干线原则上要加粗(尤其是电路板的电源输入/输出线)。
12、高频信号线,如STM32核心板上的晶振电路的布线,不要加粗,建议也按照线宽为10mil进行设计,而且尽可能布线在同一层。
13、100mil = 2.54mm(39.37mil = 1mm)。
14、过孔的放置:
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
结尾
- ❤️ 感谢您的支持和鼓励!
- 您可能感兴趣的内容:
- 【FPGA-Spirit_V2】基于FPGA的循迹小车-小精灵V2开发板
- 【Go黑帽子】使用Golang编写一个TCP扫描器(高级篇)
- 【Arduino TinyGo】【最新】使用Go语言编写Arduino-环境搭建和点亮LED灯
- 【全网首发开源教程】【Labview机器人仿真与控制】Labview与Solidworks多路支配关系-四足爬行机器人仿真与控制