??歡迎來到stm32專欄~stm32+oled最小系統(tǒng)板
- ☆* o(≧▽≦)o *☆嗨~我是小夏與酒??
- ?博客主頁:小夏與酒的博客
- ??該系列文章專欄:stm32專欄
- 文章作者技術(shù)和水平有限,如果文中出現(xiàn)錯(cuò)誤,希望大家能指正??
- ?? 歡迎大家關(guān)注! ??
![]()
一、效果演示
??示例代碼演示
特寫:
??外觀展示
正面:
背面:
加上oled屏:
如果需要板子的原理圖、PCB和示例代碼工程文件,請(qǐng)從我上傳的資源中下載:stm32+oled最小系統(tǒng)板資料(原理圖、PCB、示例代碼)。或者三連本文章后聯(lián)系我免費(fèi)獲取!
二、原理圖與PCB
我使用了最最最可愛的嘉立創(chuàng)EDA完成了stm32+oled最小系統(tǒng)板的繪制。
2.1 原理圖
先介紹原理圖部分:
??整體原理圖:
??電源接口部分:最簡單的,通過排針接入5V
電源。
??電源降壓部分:使用AMS1117
完成5V轉(zhuǎn)3.3V
的任務(wù)。
??濾波電路部分:該部分也可以稱為電源濾波退耦電路。
??按鍵部分:加入該部分是為了便于實(shí)現(xiàn)控制操作和交互操作,設(shè)計(jì)三個(gè)用戶按鍵,滿足多數(shù)設(shè)計(jì)開發(fā)需求。
??MCU部分:在此我只使用了8M
的晶振,如果需要使用32.768KHz
的晶振,加入即可。
??復(fù)位電路部分:就是正常的復(fù)位電路。
??程序下載部分:SWD程序下載接口。
??oled接口部分:為了方便直接使用oled顯示屏,在畫板子的時(shí)候直接引出對(duì)應(yīng)的接口。
??電源指示部分:用于顯示電壓是否正常。
??板載led部分:板載led接了PC13
,使用時(shí)注意配置引腳。
??其余引腳部分:將剩余的引腳引出。
2.2 PCB
頂層:
底層:
3D:
2.3 PCB布局
對(duì)于PCB的布局,我從一些參考資料中進(jìn)行了整理。
STM32F103C8T6相關(guān)布線知識(shí)點(diǎn):
1、布局中應(yīng)參考原理圖,根據(jù)電路的主信號(hào)流向規(guī)律安排主要元器件。
2、Boot0和Boot1都接到地,就是正常工作模式:Boot0和Boot1都加一個(gè)10K的電阻,然后接到地。
3、晶振電路:
晶振與兩個(gè)電容并聯(lián)使用,電容的大小由晶振決定,一般使用22pF。
- 畫板時(shí)晶振盡量離芯片近一點(diǎn);
- 晶振底部盡量不要穿過其他支路,防止信號(hào)串?dāng)_;
- 晶振、芯片、電容(與晶振相連的電容要緊鄰晶振)之間的走線要盡量直且短;
- 不同型號(hào)的晶振可能需要不同的電路設(shè)計(jì),根據(jù)自己使用的晶振型號(hào)設(shè)計(jì)。
4、AMS1117降壓電路,5V轉(zhuǎn)3.3V:
- 輸入濾波電容的作用:
輸入電壓,當(dāng)接入電源,其幅值是從零起始的,波動(dòng)非常大,加入足夠容量的電容進(jìn)行濾波后,因電容的充放電效應(yīng),該脈動(dòng)直流變成紋波不大的直流電,這是輸入濾波的作用。 - 輸出濾波電容的作用:
穩(wěn)壓電路的工作過程需要從輸出采樣,然后根據(jù)其反饋值調(diào)節(jié)輸出以達(dá)穩(wěn)壓的目的。如果此時(shí)沒有輸出濾波電容,只要因負(fù)載變化帶來的電壓波動(dòng)頻率恰好與穩(wěn)壓電路的調(diào)節(jié)速率差不多就會(huì)產(chǎn)生振蕩效應(yīng),導(dǎo)致輸出失控,所以穩(wěn)壓輸出也必須加濾波電容,而且增加濾波電容也可以進(jìn)一步增加穩(wěn)壓輸出的穩(wěn)定性。 - 大電容和小電容并聯(lián)的作用:
至于與大容量電解電容并聯(lián)的小電容,其作用在于旁路頻率較高的波動(dòng)電壓,因?yàn)殇X電解電容的制造工藝導(dǎo)致其具有較大的ESL(等效電感),無法濾除高頻成份,故需加個(gè)小電容。
5、去耦電容:
- 主要用來濾除雜波,保持引腳電壓的穩(wěn)定。
- 這些電容也盡量離芯片相關(guān)引腳近一點(diǎn)。
- 分布在芯片四周即可。
- 去耦電容應(yīng)盡量放置在相應(yīng)的VCC和GND引腳之間,且距離IC盡可能近,使之與VCC和GND之間形成的回路最短。
6、導(dǎo)線線寬最小為10mil。
7、同一功能模塊集中原則。即實(shí)現(xiàn)同一功能的相關(guān)電路模塊中的元器件就近集中布局。
8、遵守“先大后小,先難后易”的原則,即重要的單元電路、核心元器件應(yīng)優(yōu)先布局。
9、元器件的排列要便于調(diào)試和維修,即小元器件周圍不能放置大元器件,需調(diào)試的元器件周圍要有足夠的空間。
10、布局時(shí),位于電路板邊緣的元器件離電路板邊緣一般不小于2mm,如果空間允許,建議距離保持在5mm。
11、電源主干線原則上要加粗(尤其是電路板的電源輸入/輸出線)。
12、高頻信號(hào)線,如STM32核心板上的晶振電路的布線,不要加粗,建議也按照線寬為10mil進(jìn)行設(shè)計(jì),而且盡可能布線在同一層。
13、100mil = 2.54mm(39.37mil = 1mm)。
14、過孔的放置:
- 普通的電阻、電容、電感、磁珠焊盤周圍的過孔邊緣與焊盤邊緣至少保持在0.15mm(5.91mil)以上。
- IC、SOT、大型電感、電解電容、二極管、連接器等焊盤周圍的過孔與焊盤邊緣至少保持在0.5mm(19.69mil)以上。
- 防止元件回流時(shí),錫膏從過孔流失。
15、添加淚滴:使信號(hào)傳輸時(shí)平滑阻抗,減少阻抗的急劇跳變。
大家在畫PCB時(shí),可以參考上述布線規(guī)則,如果有誤或者更好的建議,希望能在評(píng)論區(qū)中指出。
三、示例代碼
示例代碼使用江協(xié)科技的教學(xué)代碼:STM32入門教程-2023持續(xù)更新中。
??項(xiàng)目一覽:
??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,所以需要對(duì)PC13進(jìn)行相應(yīng)的配置。
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發(fā)送一個(gè)字節(jié)
* @param Byte 要發(fā)送的一個(gè)字節(jié)
* @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); //額外的一個(gè)時(shí)鐘,不處理應(yīng)答信號(hào)
OLED_W_SCL(0);
}
/**
* @brief OLED寫命令
* @param Command 要寫入的命令
* @retval 無
*/
void OLED_WriteCommand(uint8_t Command)
{
OLED_I2C_Start();
OLED_I2C_SendByte(0x78); //從機(jī)地址
OLED_I2C_SendByte(0x00); //寫命令
OLED_I2C_SendByte(Command);
OLED_I2C_Stop();
}
/**
* @brief OLED寫數(shù)據(jù)
* @param Data 要寫入的數(shù)據(jù)
* @retval 無
*/
void OLED_WriteData(uint8_t Data)
{
OLED_I2C_Start();
OLED_I2C_SendByte(0x78); //從機(jī)地址
OLED_I2C_SendByte(0x40); //寫數(shù)據(jù)
OLED_I2C_SendByte(Data);
OLED_I2C_Stop();
}
/**
* @brief OLED設(shè)置光標(biāo)位置
* @param Y 以左上角為原點(diǎn),向下方向的坐標(biāo),范圍:0~7
* @param X 以左上角為原點(diǎn),向右方向的坐標(biāo),范圍:0~127
* @retval 無
*/
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
OLED_WriteCommand(0xB0 | Y); //設(shè)置Y位置
OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4)); //設(shè)置X位置高4位
OLED_WriteCommand(0x00 | (X & 0x0F)); //設(shè)置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顯示一個(gè)字符
* @param Line 行位置,范圍:1~4
* @param Column 列位置,范圍:1~16
* @param Char 要顯示的一個(gè)字符,范圍:ASCII可見字符
* @retval 無
*/
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{
uint8_t i;
OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8); //設(shè)置光標(biāo)位置在上半部分
for (i = 0; i < 8; i++)
{
OLED_WriteData(OLED_F8x16[Char - ' '][i]); //顯示上半部分內(nèi)容
}
OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8); //設(shè)置光標(biāo)位置在下半部分
for (i = 0; i < 8; i++)
{
OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]); //顯示下半部分內(nèi)容
}
}
/**
* @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次方函數(shù)
* @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顯示數(shù)字(十進(jìn)制,正數(shù))
* @param Line 起始行位置,范圍:1~4
* @param Column 起始列位置,范圍:1~16
* @param Number 要顯示的數(shù)字,范圍:0~4294967295
* @param Length 要顯示數(shù)字的長度,范圍: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顯示數(shù)字(十進(jìn)制,帶符號(hào)數(shù))
* @param Line 起始行位置,范圍:1~4
* @param Column 起始列位置,范圍:1~16
* @param Number 要顯示的數(shù)字,范圍:-2147483648~2147483647
* @param Length 要顯示數(shù)字的長度,范圍: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顯示數(shù)字(十六進(jìn)制,正數(shù))
* @param Line 起始行位置,范圍:1~4
* @param Column 起始列位置,范圍:1~16
* @param Number 要顯示的數(shù)字,范圍:0~0xFFFFFFFF
* @param Length 要顯示數(shù)字的長度,范圍: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顯示數(shù)字(二進(jìn)制,正數(shù))
* @param Line 起始行位置,范圍:1~4
* @param Column 起始列位置,范圍:1~16
* @param Number 要顯示的數(shù)字,范圍:0~1111 1111 1111 1111
* @param Length 要顯示數(shù)字的長度,范圍: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++) //上電延時(shí)
{
for (j = 0; j < 1000; j++);
}
OLED_I2C_Init(); //端口初始化
OLED_WriteCommand(0xAE); //關(guān)閉顯示
OLED_WriteCommand(0xD5); //設(shè)置顯示時(shí)鐘分頻比/振蕩器頻率
OLED_WriteCommand(0x80);
OLED_WriteCommand(0xA8); //設(shè)置多路復(fù)用率
OLED_WriteCommand(0x3F);
OLED_WriteCommand(0xD3); //設(shè)置顯示偏移
OLED_WriteCommand(0x00);
OLED_WriteCommand(0x40); //設(shè)置顯示開始行
OLED_WriteCommand(0xA1); //設(shè)置左右方向,0xA1正常 0xA0左右反置
OLED_WriteCommand(0xC8); //設(shè)置上下方向,0xC8正常 0xC0上下反置
OLED_WriteCommand(0xDA); //設(shè)置COM引腳硬件配置
OLED_WriteCommand(0x12);
OLED_WriteCommand(0x81); //設(shè)置對(duì)比度控制
OLED_WriteCommand(0xCF);
OLED_WriteCommand(0xD9); //設(shè)置預(yù)充電周期
OLED_WriteCommand(0xF1);
OLED_WriteCommand(0xDB); //設(shè)置VCOMH取消選擇級(jí)別
OLED_WriteCommand(0x30);
OLED_WriteCommand(0xA4); //設(shè)置整個(gè)顯示打開/關(guān)閉
OLED_WriteCommand(0xA6); //設(shè)置正常/倒轉(zhuǎn)顯示
OLED_WriteCommand(0x8D); //設(shè)置充電泵
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
??按鍵控制: 用于實(shí)現(xiàn)按鍵控制和人機(jī)交互。
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
文章來源:http://www.zghlxwxcb.cn/news/detail-484971.html
??結(jié)尾文章來源地址http://www.zghlxwxcb.cn/news/detail-484971.html
- ?? 感謝您的支持和鼓勵(lì)! ????
- ??您可能感興趣的內(nèi)容:
- 【FPGA-Spirit_V2】基于FPGA的循跡小車-小精靈V2開發(fā)板
- 【Go黑帽子】使用Golang編寫一個(gè)TCP掃描器(高級(jí)篇)
- 【Arduino TinyGo】【最新】使用Go語言編寫Arduino-環(huán)境搭建和點(diǎn)亮LED燈
- 【全網(wǎng)首發(fā)開源教程】【Labview機(jī)器人仿真與控制】Labview與Solidworks多路支配關(guān)系-四足爬行機(jī)器人仿真與控制
![]()
到了這里,關(guān)于【stm32開發(fā)】stm32+oled最小系統(tǒng)板資料(原理圖、PCB、示例代碼)【六一】的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!