STM32 入门 + 传感器采集 + 显示 综合实验,基于 STM32F103C8T6(蓝桥杯/最小系统板)。
一、系统总体方案
温湿度传感器 → USART1(RX) → STM32F103
│
├── USART2(TX) → PC串口助手(调试)
└── GPIO → 74HC595 → 4位数码管
硬件选型(最常见组合)
| 模块 | 型号 | 说明 |
|---|---|---|
| MCU | STM32F103C8T6 | 72MHz,3.3V |
| 温湿度 | DHT11 | 单总线(简单) |
| 数码管 | 4位共阳/共阴 | 带 74HC595 移位寄存器 |
| 下载 | ST-Link V2 | SWD 接口 |
推荐 :如果你不想自己写 DHT11 驱动,也可以用 SHT30(I2C),稳定性更好。
二、硬件连接表(重点)
1、DHT11 → STM32
| DHT11 | STM32F103 | 说明 |
|---|---|---|
| VCC | 3.3V | |
| GND | GND | |
| DATA | PA0 | 推挽输出 / 输入切换 |
2、数码管(74HC595) → STM32
| 74HC595 | STM32 | 说明 |
|---|---|---|
| SER | PB12 | 数据 |
| RCLK | PB13 | 锁存 |
| SRCLK | PB14 | 时钟 |
| OE | GND | 使能 |
| VCC | 5V | 数码管供电 |
数码管类型一定要确认
- 共阳:段码取反
- 共阴:段码原样
三、核心源码
1、DHT11 驱动(单总线)
c
// dht11.h
#ifndef __DHT11_H
#define __DHT11_H
#include "stm32f10x.h"
uint8_t DHT11_Read(uint8_t *temp, uint8_t *humi);
#endif
c
// dht11.c
#include "dht11.h"
#include "delay.h"
#define DHT11_PIN GPIO_Pin_0
#define DHT11_PORT GPIOA
static void DHT11_Mode_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = DHT11_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT11_PORT, &GPIO_InitStructure);
}
static void DHT11_Mode_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = DHT11_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(DHT11_PORT, &GPIO_InitStructure);
}
uint8_t DHT11_Read(uint8_t *temp, uint8_t *humi)
{
uint8_t buf[5] = {0};
uint8_t i, j;
DHT11_Mode_OUT();
GPIO_ResetBits(DHT11_PORT, DHT11_PIN);
Delay_ms(18);
GPIO_SetBits(DHT11_PORT, DHT11_PIN);
Delay_us(30);
DHT11_Mode_IN();
if(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) != 0)
return 1;
while(!GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN));
while(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN));
for(i=0;i<5;i++)
{
for(j=0;j<8;j++)
{
while(!GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN));
Delay_us(40);
buf[i] <<= 1;
if(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN))
buf[i] |= 1;
while(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN));
}
}
if(buf[0]+buf[1]+buf[2]+buf[3] != buf[4])
return 2;
*humi = buf[0];
*temp = buf[2];
return 0;
}
2、74HC595 驱动数码管
c
// seg.c
#include "seg.h"
#include "stm32f10x_gpio.h"
#define SER_H() GPIO_SetBits(GPIOB, GPIO_Pin_12)
#define SER_L() GPIO_ResetBits(GPIOB, GPIO_Pin_12)
#define RCLK_H() GPIO_SetBits(GPIOB, GPIO_Pin_13)
#define RCLK_L() GPIO_ResetBits(GPIOB, GPIO_Pin_13)
#define SRCLK_H() GPIO_SetBits(GPIOB, GPIO_Pin_14)
#define SRCLK_L() GPIO_ResetBits(GPIOB, GPIO_Pin_14)
// 共阳数码管段码(0~9)
const uint8_t SegCode[10] = {
0xC0,0xF9,0xA4,0xB0,0x99,
0x92,0x82,0xF8,0x80,0x90
};
void Seg_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void Seg_SendByte(uint8_t dat)
{
for(uint8_t i=0;i<8;i++)
{
(dat & 0x80) ? SER_H() : SER_L();
SRCLK_H(); SRCLK_L();
dat <<= 1;
}
}
void Seg_Display(uint16_t num)
{
Seg_SendByte(SegCode[num/1000]);
Seg_SendByte(SegCode[num%1000/100]);
Seg_SendByte(SegCode[num%100/10]);
Seg_SendByte(SegCode[num%10]);
RCLK_H(); RCLK_L();
}
3、串口打印(调试用)
c
// usart.c
void USART1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;
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_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
4、Main 主逻辑
c
int main(void)
{
uint8_t temp = 0, humi = 0;
Delay_Init();
Seg_Init();
USART1_Init();
while(1)
{
if(DHT11_Read(&temp, &humi) == 0)
{
// 显示温度(例如 25°C → 显示 25)
Seg_Display(temp);
// 串口打印
printf("Temp:%dC Humi:%d%%\r\n", temp, humi);
}
Delay_ms(1000);
}
}
四、串口上位机显示效果
Temp:26C Humi:58%
Temp:26C Humi:57%
Temp:27C Humi:56%
参考代码 STM32F103-串口控制数码管显示温湿度数据 www.youwenfan.com/contentcsv/103447.html
五、常见问题排查
| 现象 | 原因 |
|---|---|
| 数码管不亮 | 共阳/共阴段码搞反 |
| DHT11 一直 0 | 延时不准(必须精准 µs) |
| 数值跳动 | 未加延时 / 电源不稳 |
| 串口乱码 | 晶振频率 ≠ 72MHz |