STM32F103ZET6 Elite Board

元器件
开发板
库存 200

介绍

STM32F103ZET6 精英版开发板,基于 ARM Cortex-M3 内核,主频 72MHz,512KB Flash、64KB SRAM。LQFP-144 封装引出全部 GPIO(112个IO口)。板载丰富外设:1.8寸 TFT LCD、3路串口(含RS485)、CAN接口、SD卡槽、EEPROM(AT24C02)、SPI Flash(W25Q64)、温度传感器(DS18B20)、红外接收头、蜂鸣器、4×LED、4×按键、RTC电池座、USB转串口(CH340G)、JTAG/SWD调试接口。配套正点原子/野火等丰富教程,是国内STM32培训教育最经典的大板之一。

规格参数

参数
ADC3×12位(21通道)
DAC2×12位
SRAM64KB
Flash512KB
主频72MHz
内核ARM Cortex-M3
MCU型号STM32F103ZET6
PCB尺寸120mm×80mm
定时器8个(含2个高级+2个基本+4个通用)
GPIO数量112(LQFP-144)
扩展接口SD卡槽、CAN接口(带TJA1050)、RS485(带SP3485)、NRF24L01无线接口、摄像头接口(OV7670)
板载外设1.8寸TFT LCD(128×160)、CH340G USB转串口、AT24C02 EEPROM、W25Q64 SPI Flash、DS18B20温度传感器、红外接收头、蜂鸣器、4×LED、4×按键
通信接口USB 2.0 FS、CAN 2.0B、3×SPI、2×I2C、5×USART、SDIO、FSMC
配套教程正点原子/野火/普中科技等完整教程

代码例程

STM32F103ZET6 Elite Board 代码例程.md
# STM32F103ZET6 Elite Board 代码例程

本文档覆盖精英版板载各外设的驱动代码:LCD、SD卡+FATFS、SPI Flash、I2C EEPROM、DS18B20、CAN、RS485、红外遥控、蜂鸣器 PWM。

---

## 一、板级基础驱动 (BSP)

### 1.1 板载 LED 与 按键

```c
/* bsp_led_key.c - 精英版板载 LED 和按键驱动 */
#include "stm32f10x.h"

/* LED 初始化 (PE2-PE5) */
void LED_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOE, &GPIO_InitStructure);

    /* 初始全部熄灭 (高电平) */
    GPIO_SetBits(GPIOE, GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5);
}

/* LED 宏定义 */
#define LED0 PEout(2)
#define LED1 PEout(3)
#define LED2 PEout(4)
#define LED3 PEout(5)

#define LED0_ON()   GPIO_ResetBits(GPIOE, GPIO_Pin_2)
#define LED0_OFF()  GPIO_SetBits(GPIOE, GPIO_Pin_2)

/* 按键初始化 (PE0-PE3) */
void KEY_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  // 上拉输入
    GPIO_Init(GPIOE, &GPIO_InitStructure);
}

/* 按键扫描(简单消抖) */
#define KEY0  GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_0)
#define KEY1  GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_1)

uint8_t KEY_Scan(void)
{
    static uint8_t keyUp = 1;
    if (keyUp && (KEY0 == 0 || KEY1 == 0))
    {
        HAL_Delay(10);  // 消抖
        keyUp = 0;
        if (KEY0 == 0) return 1;
        if (KEY1 == 0) return 2;
    }
    else if (KEY0 == 1 && KEY1 == 1)
    {
        keyUp = 1;
    }
    return 0;
}
```

### 1.2 蜂鸣器 PWM 驱动

```c
/* 蜂鸣器 PB8 - TIM4_CH3 PWM */
#include "stm32f10x.h"

void BEEP_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;

    /* GPIO 时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

    /* PB8: 复用推挽输出 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* TIM4: 72MHz / 72 = 1MHz, ARR=2000 → 500Hz */
    TIM_TimeBaseStructure.TIM_Period = 2000 - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

    /* PWM 模式1 */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 1000;  // 50% 占空比
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC3Init(TIM4, &TIM_OCInitStructure);

    TIM_Cmd(TIM4, ENABLE);
}

/* 设置蜂鸣器占空比 0-1999 */
void BEEP_SetDuty(uint16_t duty)
{
    TIM_SetCompare3(TIM4, duty);
}

/* 蜂鸣器响/停 */
void BEEP_On(void)  { BEEP_SetDuty(1000); }
void BEEP_Off(void) { BEEP_SetDuty(0); }
```

---

## 二、板载外设驱动

### 2.1 I2C EEPROM (AT24C02)

```c
/* AT24C02 读写 - I2C1 PB6(SCL) PB7(SDA) */
#include "stm32f10x.h"

#define AT24C02_ADDR  0xA0  // 7位地址 1010 000x

void AT24C02_Init(void)
{
    I2C_InitTypeDef I2C_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    /* PB6(SCL), PB7(SDA) - 开漏复用 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = 0x00;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = 400000;
    I2C_Init(I2C1, &I2C_InitStructure);
    I2C_Cmd(I2C1, ENABLE);
}

/* 写入一个字节 */
void AT24C02_WriteByte(uint8_t addr, uint8_t data)
{
    I2C_GenerateSTART(I2C1, ENABLE);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(I2C1, AT24C02_ADDR, I2C_Direction_Transmitter);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    I2C_SendData(I2C1, addr);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_SendData(I2C1, data);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_GenerateSTOP(I2C1, ENABLE);
    HAL_Delay(5);  // AT24C02 写入周期 5ms
}

/* 读取一个字节 */
uint8_t AT24C02_ReadByte(uint8_t addr)
{
    uint8_t data;

    /* 先发送要读取的地址 */
    I2C_GenerateSTART(I2C1, ENABLE);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
    I2C_Send7bitAddress(I2C1, AT24C02_ADDR, I2C_Direction_Transmitter);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    I2C_SendData(I2C1, addr);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    /* 重新起始 + 读 */
    I2C_GenerateSTART(I2C1, ENABLE);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
    I2C_Send7bitAddress(I2C1, AT24C02_ADDR, I2C_Direction_Receiver);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    I2C_AcknowledgeConfig(I2C1, DISABLE);  // NACK 结束
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));

    data = I2C_ReceiveData(I2C1);
    I2C_GenerateSTOP(I2C1, ENABLE);

    return data;
}
```

### 2.2 SPI Flash (W25Q64)

```c
/* W25Q64 - SPI2 PB12(CS) PB13(SCK) PB14(MISO) PB15(MOSI) */
#include "stm32f10x.h"

#define W25Q_CS_LOW()   GPIO_ResetBits(GPIOB, GPIO_Pin_12)
#define W25Q_CS_HIGH()  GPIO_SetBits(GPIOB, GPIO_Pin_12)

/* 命令列表 */
#define W25Q_READ_ID        0x9F
#define W25Q_READ_DATA      0x03
#define W25Q_WRITE_ENABLE   0x06
#define W25Q_SECTOR_ERASE   0x20
#define W25Q_PAGE_PROGRAM   0x02
#define W25Q_READ_STATUS    0x05

void W25Q_Init(void)
{
    SPI_InitTypeDef SPI_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);

    /* SCK, MOSI, MISO */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* CS (软件控制) */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    W25Q_CS_HIGH();

    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_Init(SPI2, &SPI_InitStructure);
    SPI_Cmd(SPI2, ENABLE);
}

uint8_t SPI2_SendByte(uint8_t byte)
{
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI2, byte);
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
    return SPI_I2S_ReceiveData(SPI2);
}

/* 读取 ID */
uint32_t W25Q_ReadID(void)
{
    uint32_t id = 0;
    W25Q_CS_LOW();
    SPI2_SendByte(W25Q_READ_ID);
    id |= SPI2_SendByte(0xFF) << 16;
    id |= SPI2_SendByte(0xFF) << 8;
    id |= SPI2_SendByte(0xFF);
    W25Q_CS_HIGH();
    return id;  // W25Q64 → 0xEF4017
}

/* 读取数据 */
void W25Q_Read(uint32_t addr, uint8_t *buf, uint16_t len)
{
    W25Q_CS_LOW();
    SPI2_SendByte(W25Q_READ_DATA);
    SPI2_SendByte((addr >> 16) & 0xFF);
    SPI2_SendByte((addr >> 8) & 0xFF);
    SPI2_SendByte(addr & 0xFF);
    for (uint16_t i = 0; i < len; i++)
        buf[i] = SPI2_SendByte(0xFF);
    W25Q_CS_HIGH();
}

/* 页写入(最多256字节) */
void W25Q_PageProgram(uint32_t addr, uint8_t *buf, uint16_t len)
{
    W25Q_CS_LOW();
    SPI2_SendByte(W25Q_WRITE_ENABLE);  // 写使能
    W25Q_CS_HIGH();

    W25Q_CS_LOW();
    SPI2_SendByte(W25Q_PAGE_PROGRAM);
    SPI2_SendByte((addr >> 16) & 0xFF);
    SPI2_SendByte((addr >> 8) & 0xFF);
    SPI2_SendByte(addr & 0xFF);
    for (uint16_t i = 0; i < len; i++)
        SPI2_SendByte(buf[i]);
    W25Q_CS_HIGH();

    /* 等待写入完成 */
    while (W25Q_ReadStatus() & 0x01);
}

uint8_t W25Q_ReadStatus(void)
{
    uint8_t status;
    W25Q_CS_LOW();
    SPI2_SendByte(W25Q_READ_STATUS);
    status = SPI2_SendByte(0xFF);
    W25Q_CS_HIGH();
    return status;
}
```

### 2.3 DS18B20 温度传感器

```c
/* DS18B20 - PG11 单总线 */
#include "stm32f10x.h"

#define DS18B20_DQ       PGout(11)
#define DS18B20_DQ_IN    GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_11)

/* 微秒级延时 (72MHz, 非精确但单总线可接受) */
static void delay_us(uint32_t us)
{
    uint32_t i;
    for (i = 0; i < us * 8; i++);
}

void DS18B20_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOG, &GPIO_InitStructure);
    DS18B20_DQ = 1;
}

/* 复位脉冲 + 检测存在脉冲 */
uint8_t DS18B20_Reset(void)
{
    uint8_t presence;
    DS18B20_DQ = 0;       // 拉低 480us
    delay_us(480);
    DS18B20_DQ = 1;       // 释放
    delay_us(60);
    presence = DS18B20_DQ_IN;  // 检测存在脉冲
    delay_us(420);
    return presence;       // 0 = 存在, 1 = 不存在
}

/* 写一个 bit */
void DS18B20_WriteBit(uint8_t bit)
{
    DS18B20_DQ = 0;
    delay_us(2);
    if (bit) DS18B20_DQ = 1;
    delay_us(60);
    DS18B20_DQ = 1;
}

/* 写一个字节 */
void DS18B20_WriteByte(uint8_t data)
{
    for (uint8_t i = 0; i < 8; i++)
        DS18B20_WriteBit((data >> i) & 0x01);
}

/* 读一个 bit */
uint8_t DS18B20_ReadBit(void)
{
    uint8_t bit;
    DS18B20_DQ = 0;
    delay_us(2);
    DS18B20_DQ = 1;
    delay_us(12);
    bit = DS18B20_DQ_IN;
    delay_us(50);
    return bit;
}

/* 读一个字节 */
uint8_t DS18B20_ReadByte(void)
{
    uint8_t data = 0;
    for (uint8_t i = 0; i < 8; i++)
        data |= (DS18B20_ReadBit() << i);
    return data;
}

/* 读取温度 */
float DS18B20_ReadTemp(void)
{
    uint8_t TL, TH;
    int16_t temp;

    DS18B20_Reset();
    DS18B20_WriteByte(0xCC);  // 跳过 ROM
    DS18B20_WriteByte(0x44);  // 启动温度转换

    delay_us(750000);         // 等待转换 (750ms)

    DS18B20_Reset();
    DS18B20_WriteByte(0xCC);  // 跳过 ROM
    DS18B20_WriteByte(0xBE);  // 读暂存器

    TL = DS18B20_ReadByte();
    TH = DS18B20_ReadByte();

    temp = (TH << 8) | TL;
    return temp * 0.0625f;    // 分辨率 12bit = 0.0625°C
}
```

### 2.4 CAN 通信

```c
/* CAN1 - PD0(RX) PD1(TX) 经 TJA1050 */
#include "stm32f10x.h"

void CAN1_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    CAN_InitTypeDef CAN_InitStructure;
    CAN_FilterInitTypeDef CAN_FilterInitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

    /* PD0(RX) - 浮空输入, PD1(TX) - 复用推挽 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOD, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOD, &GPIO_InitStructure);

    /* CAN 初始化 500Kbps @ 36MHz APB1 */
    CAN_InitStructure.CAN_TTCM = DISABLE;
    CAN_InitStructure.CAN_ABOM = ENABLE;
    CAN_InitStructure.CAN_AWUM = DISABLE;
    CAN_InitStructure.CAN_NART = ENABLE;
    CAN_InitStructure.CAN_RFLM = DISABLE;
    CAN_InitStructure.CAN_TXFP = DISABLE;
    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
    CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
    CAN_InitStructure.CAN_BS1 = CAN_BS1_6tq;
    CAN_InitStructure.CAN_BS2 = CAN_BS2_5tq;
    CAN_InitStructure.CAN_Prescaler = 6;  // 36MHz / 6 / (1+6+5) = 500Kbps
    CAN_Init(CAN1, &CAN_InitStructure);

    /* 过滤器:接收所有 ID */
    CAN_FilterInitStructure.CAN_FilterNumber = 0;
    CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
    CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
    CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
    CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
    CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
    CAN_FilterInit(&CAN_FilterInitStructure);
}

/* 发送 CAN 消息 */
uint8_t CAN_SendMsg(uint32_t id, uint8_t *data, uint8_t len)
{
    CanTxMsg txMsg;
    txMsg.StdId = id;
    txMsg.ExtId = 0;
    txMsg.IDE = CAN_Id_Standard;
    txMsg.RTR = CAN_RTR_Data;
    txMsg.DLC = len;
    for (uint8_t i = 0; i < len; i++)
        txMsg.Data[i] = data[i];

    uint8_t mailbox = CAN_Transmit(CAN1, &txMsg);
    uint32_t timeout = 0xFFFF;
    while (CAN_TransmitStatus(CAN1, mailbox) != CAN_TxStatus_Ok && timeout--)
        ;
    return (timeout == 0) ? 0 : 1;
}

/* 接收 CAN 消息 */
uint8_t CAN_ReceiveMsg(uint32_t *id, uint8_t *data, uint8_t *len)
{
    CanRxMsg rxMsg;
    if (CAN_MessagePending(CAN1, CAN_FIFO0) == 0)
        return 0;

    CAN_Receive(CAN1, CAN_FIFO0, &rxMsg);
    *id = rxMsg.StdId;
    *len = rxMsg.DLC;
    for (uint8_t i = 0; i < rxMsg.DLC; i++)
        data[i] = rxMsg.Data[i];
    return 1;
}
```

### 2.5 RS485 通信

```c
/* RS485 - USART3 + SP3485 方向控制 PG7 */
#include "stm32f10x.h"

#define RS485_TX_EN()   GPIO_SetBits(GPIOG, GPIO_Pin_7)   // 发送模式
#define RS485_RX_EN()   GPIO_ResetBits(GPIOG, GPIO_Pin_7) // 接收模式

void RS485_Init(uint32_t baudrate)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOG, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);

    /* PB10(TX), PB11(RX) */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* PG7 - 方向控制 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOG, &GPIO_InitStructure);
    RS485_RX_EN();  // 默认接收模式

    USART_InitStructure.USART_BaudRate = baudrate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART3, &USART_InitStructure);
    USART_Cmd(USART3, ENABLE);
}

void RS485_Send(uint8_t *buf, uint16_t len)
{
    RS485_TX_EN();
    for (uint16_t i = 0; i < len; i++)
    {
        USART_SendData(USART3, buf[i]);
        while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
    }
    RS485_RX_EN();
}
```

---

## 三、综合示例:LCD 显示传感器数据

```c
/* 综合演示:读取 DS18B20 温度,显示在 LCD,通过串口打印,LED 闪烁 */
#include "stm32f10x.h"
#include "lcd.h"         // LCD 驱动(根据具体屏幕型号)
#include <stdio.h>

int main(void)
{
    float temperature;
    char lcdBuf[32];

    SystemInit();         // 系统初始化 72MHz
    LED_Init();
    KEY_Init();
    BEEP_Init();
    DS18B20_Init();
    USART1_Init(115200);  // CH340G 串口
    LCD_Init();

    LCD_Clear(BLACK);
    LCD_ShowString(0, 0, "STM32F103ZET6", WHITE, BLACK);
    LCD_ShowString(0, 16, "Elite Board", WHITE, BLACK);

    printf("System Started!\r\n");

    while (1)
    {
        temperature = DS18B20_ReadTemp();

        /* LCD 显示 */
        snprintf(lcdBuf, sizeof(lcdBuf), "Temp: %.1f C", temperature);
        LCD_ShowString(0, 48, lcdBuf, YELLOW, BLACK);

        /* 串口输出 */
        printf("Temperature: %.1f C\r\n", temperature);

        /* LED 闪烁 */
        LED0_ON();  HAL_Delay(100);  LED0_OFF();

        /* 按键检测 */
        if (KEY_Scan() == 1)
        {
            BEEP_On();
            HAL_Delay(100);
            BEEP_Off();
            printf("Key pressed!\r\n");
        }

        HAL_Delay(900);
    }
}
```

---

## 四、开发环境推荐

| 平台 | 说明 |
|------|------|
| Keil MDK-ARM | 正点原子/野火教程均基于此,兼容性最好 |
| STM32CubeIDE | 现代化 IDE,CubeMX 集成,推荐新项目 |
| IAR EWARM | 部分工业用户使用 |

参考资料

暂无参考文献