STM32标准库开发的常用API整理

以下资料适用于STM32F103C8T6标准库开发,其他型号可根据实际情况自行修改

STM32内部资源

1. 位带操作

STM32可通过位带操作来实现类似51单片机的位操作,以下是实现位带操作的io_bit.h文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#ifndef _IO_BIT_H_
#define _IO_BIT_H_

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr&0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//F103XXIO 口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+0x0C) //0x40020014
#define GPIOB_ODR_Addr (GPIOB_BASE+0x0C) //0x40020414
#define GPIOC_ODR_Addr (GPIOC_BASE+0x0C) //0x40020814
#define GPIOD_ODR_Addr (GPIOD_BASE+0x0C) //0x40020C14
#define GPIOE_ODR_Addr (GPIOE_BASE+0x0C) //0x40021014
#define GPIOA_IDR_Addr (GPIOA_BASE+0x08) //0x40020010
#define GPIOB_IDR_Addr (GPIOB_BASE+0x08) //0x40020410
#define GPIOC_IDR_Addr (GPIOC_BASE+0x08) //0x40020810
#define GPIOD_IDR_Addr (GPIOD_BASE+0x08) //0x40020C10
#define GPIOE_IDR_Addr (GPIOE_BASE+0x08) //0x40021010

//F103XXIO 口操作,只对单一的IO 口,n 的值范围[0-15]
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //GPIOA 某一位输出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //GPIOA 某一位输入
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //GPIOB 某一位输出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //GPIOB 某一位输入
#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //GPIOC 某一位输出
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //GPIOC 某一位输入
#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //GPIOD 某一位输出
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //GPIOD 某一位输入
#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //GPIOE 某一位输出
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //GPIOE 某一位输入

#endif

使用示例

1
2
3
4
5
#include "io_bit.h"
......
PCout(13) = 1; // PC13输出高电平 使用前须对PC13初始化为输出
uint8_t key = PCin(14); // 获取PC14输入电平 使用前须对PC14初始化为输入
......

2. 利用系统滴答计时器实现延时

delay.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include "delay.h"

void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD = 9*nus;
SysTick->VAL=0X00;//清空计数器
SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
do
{
temp=SysTick->CTRL;//读取当前倒计数值
}while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD = 9000*nms;
SysTick->VAL=0X00;//清空计数器
SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
do
{
temp=SysTick->CTRL;//读取当前倒计数值
}while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}

delay.h

1
2
3
4
5
6
7
8
9
#ifndef _delay_H_
#define _delay_H_

#include "stm32f10x.h"

void delay_us(u32 nus);
void delay_ms(u16 nms);

#endif

3. 定时器

以定时器2产生1ms中断为例
timer.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include "timer.h"

void tim_Init(void)
{
TIM_TimeBaseInitTypeDef timInitStructure;
NVIC_InitTypeDef nvicInitStructure;

//1.配置定时器时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

//2.配置定时器结构体
timInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
timInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
timInitStructure.TIM_Period = 1000-1;
timInitStructure.TIM_Prescaler = 72-1; // 1ms

TIM_TimeBaseInit(TIM2, &timInitStructure);
//3.开启定时器中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE);

//4.配置中断结构体
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

nvicInitStructure.NVIC_IRQChannel = TIM2_IRQn;
nvicInitStructure.NVIC_IRQChannelPreemptionPriority = 2;
nvicInitStructure.NVIC_IRQChannelSubPriority = 1;
nvicInitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvicInitStructure);
}

//5.搭建定时器中断服务函数
uint16_t timer_t = 0;
void TIM2_IRQHandler(void)
{
if( TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
timer_t++;
}
}

timer.h

1
2
3
4
5
6
7
8
9
#ifndef __TIMER_H
#define __TIMER_H

#include "stm32f10x.h"

void tim_Init(void);
extern uint16_t timer_t; // 将timer_t计数变量导出到外部,可在其他文件中使用

#endif

4. 串口

以串口1为例
usart.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include "usart.h"

void usart_init(unsigned int bound) // 设置波特率
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟

//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9

//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10

//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器

//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
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(USART1, &USART_InitStructure); //初始化串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USART1, ENABLE); //使能串口1
}

void Uart_Send(unsigned char data)//发送单个字符
{
while(!USART_GetFlagStatus(USART1, USART_FLAG_TC));//不能少分号
USART_SendData(USART1, data);
}


void Uart_SendString(unsigned char *string)
{
while(*string != 0)
{
Uart_Send(*string++);
}
}
unsigned char Uart_Read(void)//读单个字符
{
while(!USART_GetFlagStatus(USART1, USART_FLAG_RXNE));//不能少分号
return USART_ReceiveData(USART1);
}
char Rx_buff[512]; //接收缓冲区
char Rx_flag; //接收标志位
void Uart_ReadString(void)
{
static unsigned cnt = 0;
unsigned char ch;//负责接收字符的中间变量
if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)//当接收数据有的时候进行接收
{
ch = USART_ReceiveData(USART1);
if(ch != '\r' && ch != '\n')//判断是否是结束符
{
Rx_buff[cnt] = ch;//存储当前的字符数据
cnt++;//数组下标偏移
}
else if(ch == '\n')
{
Rx_buff[cnt] = '\0';//给组成数组末尾进行结束
cnt = 0;//归零计数值以便下次进来的时候进行再次计算
Rx_flag = 1;//这个标志位的目的是为了通知主函数进行数据打印
}
}
}

void USART1_IRQHandler(void){
Uart_ReadString();
}
/* 以下是串口的重定向函数,实现printf重定向到串口输出,根据需要使用 */
// int fputc(int ch,FILE* file)
// {
// Uart_Send(ch);
// return ch;
// }

usart.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef _USART_H_
#define _USART_H_

#include "stm32f10x.h"
#include "stdio.h"

extern char Rx_buff[512];
extern char Rx_flag;

void usart_init(unsigned int bound);
void Uart_Send(unsigned char data); // 发送单个字符
void Uart_SendString(unsigned char *string); // 发送字符串

#endif

5. adc模数转换

以adc1的通道0和1为例,可自行添加或修改
adc.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include "adc.h"

void ADC1_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

RCC_ADCCLKConfig(RCC_PCLK2_Div6);


GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);

ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);

ADC_Cmd(ADC1, ENABLE);

ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);
}

uint16_t AD_GetValue(uint8_t ADC_Channel)
{
ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
return ADC_GetConversionValue(ADC1);
}

adc.h

1
2
3
4
5
6
7
8
9
#ifndef _ADC_H
#define _ADC_H

#include "stm32f10x.h"

uint16_t AD_GetValue(uint8_t ADC_Channel); // 获取某通道的adc数值

void ADC1_Init(void);
#endif

6. 硬件IIC

以IIC1为例,即PB6与PB7引脚,硬件iic只封装了写数据和读数据的函数,可根据需要自行拆解或修改
iic.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include "iic.h"

void i2c_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
// 打开GPIOB和I2C1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
// 配置PB6和PB7为复用推挽输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 配置I2C1控制器
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 = 200 * 1000; // I2C时钟频率为100kHz
I2C_Init(I2C1, &I2C_InitStructure);
// 启动I2C1控制器
I2C_Cmd(I2C1, ENABLE);
}

void i2c_write_byte(uint8_t addr, uint8_t reg, uint8_t data)
{
// 发送起始信号
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
// 发送设备地址和写命令
I2C_Send7bitAddress(I2C1, addr, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
// 发送寄存器地址
I2C_SendData(I2C1, reg);
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);
}

uint8_t i2c_read_byte(uint8_t addr0, uint8_t addr1, uint8_t reg)
{
uint8_t data;
// 发送起始信号
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
// 发送设备地址和写命令
I2C_Send7bitAddress(I2C1, addr0, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
// 发送寄存器地址
I2C_SendData(I2C1, reg);
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, addr1, I2C_Direction_Receiver);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
// 读取数据
I2C_AcknowledgeConfig(I2C1, DISABLE);
I2C_GenerateSTOP(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
data = I2C_ReceiveData(I2C1);
I2C_GenerateSTOP(I2C1, ENABLE);
return data;
}

iic.h

1
2
3
4
5
6
7
8
9
10
#ifndef _IIC_H_
#define _IIC_H_

#include "stm32f10x.h"

void i2c_init(void);
uint8_t i2c_read_byte(uint8_t addr0, uint8_t addr1, uint8_t reg);
void i2c_write_byte(uint8_t addr, uint8_t reg, uint8_t data);

#endif

7. 软件IIC

软件IIC可以在 .h 文件自定义引脚
iic_soft.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include "iic_soft.h"

void IIC_Pin_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(IIC_GPIO_RCC,ENABLE);
//SCL
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = IIC_SCL_PIN;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(IIC_GPIO,&GPIO_InitStruct);
//SDA
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStruct.GPIO_Pin = IIC_SDA_PIN;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(IIC_GPIO,&GPIO_InitStruct);
}


void IIC_Start(void)
{
IIC_SCL = 1;
IIC_SDA = 1;
delay_us(5);
IIC_SDA = 0;
delay_us(5);
IIC_SCL = 0;
}

void IIC_Stop(void)
{
IIC_SCL = 0;
// IIC_SDA = 0;
IIC_SDA = 1;
delay_us(5);
IIC_SCL = 1;
delay_us(5);
IIC_SDA = 0;
}

void IIC_Send_Ack(u8 ack)
{
IIC_SCL = 1;
delay_us(5);
IIC_SCL = 0;
delay_us(5);
if(ack)
{
IIC_SDA = 1;
}
else
{
IIC_SDA = 0;
}

delay_us(5);
//保持周期完整性
IIC_SCL = 1;
delay_us(5);
IIC_SCL = 0;
}

u8 IIC_Reception_Ack(void)
{
IIC_SDA = 1;
delay_us(5);
IIC_SCL = 0;
delay_us(5);
IIC_SCL = 1;
if(IIC_SDA_IN)
{
return 1;
}
return 0;
}

u8 IIC_Send_Data(u8 data)
{
u8 i = 0;
for(i = 0; i < 8; i++)
{
IIC_SCL = 0;
if(data & 0x80)
{
IIC_SDA = 1;
}
else
{
IIC_SDA = 0;
}
data <<= 1;
delay_us(5);
//保持周期完整性
IIC_SCL = 1;
delay_us(5);
// IIC_SCL = 0;
}
IIC_SCL = 0;
return IIC_Reception_Ack();
//接收应答
}

u8 IIC_Read_Data(void)
{
u8 data = 0;
u8 i = 0;
IIC_SDA = 1;
for(i = 0; i < 8; i++)
{
IIC_SCL = 0;
delay_us(5);
IIC_SCL = 1;
if(IIC_SDA_IN)
{
data |= 1;
}
data <<= 1;
}
IIC_Send_Ack(1);
return data;
}

iic_soft.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef _IIC_SOFT_H_
#define _IIC_SOFT_H_

#include "stm32f10x.h"
#include "io_bit.h" // 需要位带操作的头文件
#include "delay.h" // 需要delay的头文件

/* ***********自定义配置*********** */
#define IIC_GPIO_RCC RCC_APB2Periph_GPIOB
#define IIC_GPIO GPIOB
#define IIC_SCL_PIN GPIO_Pin_6
#define IIC_SDA_PIN GPIO_Pin_7

#define IIC_SCL PBout(6)
#define IIC_SDA PBout(7)
#define IIC_SDA_IN PBin(7)
/* ******************************** */

void IIC_Pin_Init(void); //初始化引脚
void IIC_Start(void); //发送起始信号
void IIC_Stop(void); //发送停止信号
void IIC_Send_Ack(u8 ack); //发送应答
u8 IIC_Send_Data(u8 data); //发送数据
u8 IIC_Read_Data(void); //读取数据

#endif

常用外设驱动

1. dht22温湿度传感器

det22的out引脚在 .h 文件中定义
dht22.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include "dht22.h"

uint8_t humi_int;
uint8_t humi_deci;
uint8_t temp_int;
uint8_t temp_deci;
static unsigned char tempIsNegative = 0;

void DHT22_Init() {
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_GPIO_DHT22, ENABLE);
GPIO_InitStructure.GPIO_Pin = PIN_DHT22;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIO_DHT22, &GPIO_InitStructure);
GPIO_SetBits(GPIO_DHT22, PIN_DHT22);
}

void Pin_Mode_In() {
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = PIN_DHT22;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
GPIO_Init(GPIO_DHT22, &GPIO_InitStructure);
}

void Pin_Mode_Out() {
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = PIN_DHT22;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIO_DHT22, &GPIO_InitStructure);
}

uint8_t Read_Byte() {
uint8_t i, temp=0;
for(i=0;i<8;i++) {
/*每bit以50us低电平标置开始,轮询直到从机发出 的50us 低电平 结束*/
while(Pin_Read() == Bit_RESET);
/*22~30us的高电平表示“0”,以68~75us高电平表示“1”*/
delay_us(50); //延时50us
/*50us后仍为高电平表示数据“1”*/
if(Pin_Read() == Bit_SET) {
/*轮询直到从机发出的剩余的 30us 高电平结束*/
while(Pin_Read() == Bit_SET);
temp|=(uint8_t)(0x01<<(7-i)); //把第7-i位 置1
}
/*50us后为低电平表示数据“0”*/
else {
temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位 置0
}
}
return temp;
}

uint8_t DHT22_Read() {
uint8_t humiHigh;
uint8_t humiLow;
uint8_t tempHigh;
uint8_t tempLow;
uint8_t check_sum;

/*实际值的10倍*/
unsigned int humi_val;
unsigned int temp_val;

Pin_Mode_Out();
Pin_Out(LOW);
delay_ms(2);
Pin_Out(HIGH);
delay_us(30);
Pin_Mode_In();

if(Pin_Read() == Bit_RESET) {
while(Pin_Read() == Bit_RESET);
while(Pin_Read() == Bit_SET);
humiHigh = Read_Byte();
humiLow = Read_Byte();
tempHigh = Read_Byte();
tempLow = Read_Byte();
check_sum = Read_Byte();

Pin_Mode_Out();
Pin_Out(HIGH);

if(check_sum == (humiHigh + humiLow + tempHigh + tempLow) % 256) {
humi_val = humiHigh * 256 + humiLow;
humi_int = humi_val/10;
humi_deci = humi_val%10;

if(tempHigh < 128) {
temp_val = tempHigh * 256 + tempLow;
}
else {
tempIsNegative = 1;
temp_val = (tempHigh - 128) * 256 + tempLow;
}
temp_int = temp_val/10;
temp_deci = temp_val%10;
return SUCCESS;
}
else return ERROR;
}
else return ERROR;
}

dht22.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#ifndef _DHT22_H_
#define _DHT22_H_

#include "stm32f10x.h"
#include "delay.h"

/* 引脚定义 */
#define RCC_GPIO_DHT22 RCC_APB2Periph_GPIOA
#define GPIO_DHT22 GPIOA
#define PIN_DHT22 GPIO_Pin_12

#define HIGH 1
#define LOW 0
#define Pin_Read() GPIO_ReadInputDataBit(GPIO_DHT22,PIN_DHT22)
#define Pin_Out(a) if (a) \
GPIO_SetBits(GPIO_DHT22,PIN_DHT22);\
else \
GPIO_ResetBits(GPIO_DHT22,PIN_DHT22);

void DHT22_Init(); //初始化引脚
uint8_t DHT22_Read(); //读取数据,返回值为SUCCESS/ERROR(对应1/0)

// 导出十进制
extern uint8_t humi_int; //湿度整数
extern uint8_t humi_deci; //湿度小数
extern uint8_t temp_int; //温度整数
extern uint8_t temp_deci; //温度小数

extern unsigned char tempIsNegative; //温度是否为负数
#endif

大部分代码来自网上,本人对其中的代码做了修改与封装,仅供学习查阅使用,如有侵权,请联系我