0%

硬件开发|stm32使用案例

image-20210904104854742

GPIO库导入

添加USE_STDPERIPH_DRIVER到C/C++配置中

点亮LED

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
#include <stm32f10x.h>

// 定义一个GPIO信息结构体(静态变量)
static GPIO_InitTypeDef GPIO_InitStructure;

int main()
{

/* 1.打开GPIOB组的时钟(降低功耗)选择对应外设 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

// 配置开启端口号
/* 2.配置为输出推挽(多个IO使用位或添加) */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //引脚选择
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //端口输出速率(功耗)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //端口模式:推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);

// 选择外设并控制端口号输出信号
while(1)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_0); // PB1低电平

}

}
  • 定义GPIO_InitTypeDef类型结构体,可修改其端口配置

    image-20210618200840443

  • GPIO_Init函数选择输出外设,并指向端口配置

  • GPIO_ResetBits选择外设与端口,并输出低电平

  • GPIO_setBits选择外设与端口,并输出高电平

蜂鸣器

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
#include <stm32f10x.h>

// 定义一个GPIO信息结构体(静态变量)
static GPIO_InitTypeDef GPIO_InitStructure;


void delay(void)
{
int i = 5000000;
while(i--); // 没有任何意义,只是为了消耗时间
}



// 蜂鸣器初始化
void BEEP_Init(void)
{
/* 1.打开GPIOB组的时钟(降低功耗)选择对应外设 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

/* 2.配置为输出推挽(多个IO使用位或添加) */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //引脚选择
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //端口输出速率(功耗)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //端口模式:推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);

// 3.给蜂鸣器初始化电平(不响)
GPIO_SetBits(GPIOA, GPIO_Pin_1); // 不响
}

int main()
{

BEEP_Init(); // 初始化蜂鸣器

while(1)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
delay(); // 延时一段时间

GPIO_SetBits(GPIOA, GPIO_Pin_1);
delay(); // 延时一段时间
}

}
  • 切换外设为A则可以选择到蜂鸣器(以开发板手册为准)

按钮

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
#include <stm32f10x.h>

// 定义一个GPIO信息结构体(静态变量)
static GPIO_InitTypeDef GPIO_InitStructure;

#define LED_ALL GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7

void delay(void)
{
int i = 5000000;
while(i--); // 没有任何意义,只是为了消耗时间
}

// LED初始化
void LED_Init(void)
{
/* 1.打开GPIOB组的时钟(降低功耗) */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);

/* 2.关闭JTAG引脚映射(PA13/14/15 PB3/4) */
GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);

/* 3.配置为输出推挽(多个IO使用位或添加) */
GPIO_InitStructure.GPIO_Pin = LED_ALL; //引脚选择
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //端口输出速率(功耗)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //端口模式:推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);

// 4.初始化电平(不亮)
GPIO_SetBits(GPIOB, LED_ALL);
}



// 按键初始化
void KEY_Init(void)
{
/* 1.打开GPIO组的时钟(降低功耗) */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

/* 2.配置为输入(多个IO使用位或添加) */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //引脚选择
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 按钮开关使用浮空输入模式
GPIO_Init(GPIOA, &GPIO_InitStructure);

}

int main()
{
LED_Init(); // 初始化LED
KEY_Init(); // 初始化按键
GPIO_SetBits(GPIOB, GPIO_Pin_1);

while(1)
{
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_7)==0)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_1);
}
else
{
GPIO_SetBits(GPIOB, GPIO_Pin_1);
}

}

}
  • 浮空输入_IN_FLOATING ——浮空输入,IO的电平状态是不确定的,完全由外部输入决定;如果在该引脚悬空的情况下,读取该端口的电平是不确定的;
  • 带上拉输入IPU——IO内部上拉电阻输入 ==悬空时,处于高电平状态
  • 带下拉输入IPD—— IO内部下拉电阻输入 ==悬空时,处于低电平状态
  • 模拟输入AIN ——应用ADC模拟输入,或者低功耗下省电

串口通信

(1)串口通信电路连接

串口通信电路连接:

image-20210622112304168

  • 12,78 为蓝牙串口(手机app)
  • 34为串口调试
  • 56 stm32芯片

通讯对象将两边引脚短接即可

(2)重写printf函数

重写printf函数使其可以将文本输出到串口

输出字符串到串口:

  • 配置相关库:

image-20210622114338205

  • 重新定义fputc函数,让printf输出数据到串口1image-20210622114454922

(3)串口单字符发送

(芯片与串口通信)

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
#include <stdio.h>
#include "stm32f10x.h"

//GPIO信息结构体初始化
// 配置IO口结构体
GPIO_InitTypeDef GPIO_InitStructure;
// 配置中断结构体
EXTI_InitTypeDef EXTI_InitStructure;
// 配置中断优先级结构体
NVIC_InitTypeDef NVIC_InitStructure;
// 配置串口结构题
USART_InitTypeDef USART_InitStructure;

//设置串口1-->PA9+PA10
void usart1_init(u32 bound)
{

//1.使能GPIO外设、IO复用时钟、USART2时钟 PA9 和PA10
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

//2.配置GPIO + 初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // PA2 TX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO

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

//3.配置USART1 + 初始化USART1
USART_InitStructure.USART_BaudRate = bound;//波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//数据位8位
USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位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); //把配置信息加载到串口2

//4.配置NVIC + 初始化NVIC
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //选择串口2的中断
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //设置抢占优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //设置响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能串口2的中断
NVIC_Init(&NVIC_InitStructure); //把配置信息加载到中断

//5.使能串口中断
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//接收到数据触发中断

//6.使能串口
USART_Cmd(USART1,ENABLE);

}

// 单字符发送到串口
int main()
{
// 配置串口比特率
usart1_init(9600);

while(1)
{

//发送字符到串口1
USART_SendData(USART1,'h');
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);

//发送字符到串口1
USART_SendData(USART1,'e');
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);

//发送字符到串口1
USART_SendData(USART1,'l');
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);

//发送字符到串口1
USART_SendData(USART1,'l');
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);

//发送字符到串口1
USART_SendData(USART1,'o');
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);

//发送字符到串口1
USART_SendData(USART1,'\r');
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);

//发送字符到串口1
USART_SendData(USART1,'\n');
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);

delay();
}

}





(4)使用printf发送字符串到串口

(芯片与串口通信)

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
#include <stdio.h>
#include "stm32f10x.h"

//GPIO信息结构体初始化
// 配置IO口结构体
GPIO_InitTypeDef GPIO_InitStructure;
// 配置中断结构体
EXTI_InitTypeDef EXTI_InitStructure;
// 配置中断优先级结构体
NVIC_InitTypeDef NVIC_InitStructure;
// 配置串口结构题
USART_InitTypeDef USART_InitStructure;

//重定义fputc函数---》每次发送一个字符到
int fputc(int ch, FILE *f)
{
//发送字符到串口1
USART_SendData(USART1,ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);

return ch;
}


//设置串口1-->PA9+PA10
void usart1_init(u32 bound)
{

//1.使能GPIO外设、IO复用时钟、USART2时钟 PA9 和PA10
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

//2.配置GPIO + 初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // PA2 TX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO

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

//3.配置USART1 + 初始化USART1
USART_InitStructure.USART_BaudRate = bound;//波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//数据位8位
USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位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); //把配置信息加载到串口2

//4.配置NVIC + 初始化NVIC
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //选择串口2的中断
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //设置抢占优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //设置响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能串口2的中断
NVIC_Init(&NVIC_InitStructure); //把配置信息加载到中断

//5.使能串口中断
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//接收到数据触发中断

//6.使能串口
USART_Cmd(USART1,ENABLE);

}

// printf发送字符串到串口
int main()
{
usart1_init(9600);

while(1)
{
printf("good\r\n");
delay();
}

}

(5)手机蓝牙与芯片通信

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
122
123
124
125
126
#include <stdio.h>
#include "stm32f10x.h"

//GPIO信息结构体体初始化
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
USART_InitTypeDef USART_InitStructure; //串口配置的信息结构体

unsigned char data;


//led-》GPIO信息结构体初始化
void led_init()
{
//关闭引脚JTAG复用功能-->PA13、PA14、PA15、PB3、PB4
RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

/* GPIOB Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

/* Configure PD0 and PD2 in output pushpull mode */
GPIO_InitStructure.GPIO_Pin = 0xff ;//GPIO_Pin_0~GPIO_Pin_7
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//设置运行频率50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_SetBits(GPIOB, 0xff);
}




void delay()
{
unsigned int i, j;
for(i=0; i<1000; i++)
for(j=0; j<10000; j++);

}


//设置串口1-->PA9+PA10
void usart1_init(u32 bound)
{

//1.使能GPIO外设、IO复用时钟、USART2时钟 PA9 和PA10
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

//2.配置GPIO + 初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // PA2 TX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO

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

//3.配置USART1 + 初始化USART1
USART_InitStructure.USART_BaudRate = bound;//波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//数据位8位
USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位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); //把配置信息加载到串口2

//4.配置NVIC + 初始化NVIC
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //选择串口2的中断
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //设置抢占优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //设置响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能串口2的中断
NVIC_Init(&NVIC_InitStructure); //把配置信息加载到中断

//5.使能串口中断
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//接收到数据触发中断

//6.使能串口
USART_Cmd(USART1,ENABLE);

}

int main()
{
usart1_init(9600);
led_init();
while(1)
{
delay();
// data接收来自蓝牙通信的数据(手机app)
if(data == 'A')
{
GPIO_ResetBits(GPIOB, GPIO_Pin_0);
}
else if(data == 'a')
{
GPIO_SetBits(GPIOB, GPIO_Pin_0);
}

}

}

//串口1中断服务函数(可以让主函数中断其他事物回来处理串口1,从而接收到蓝牙发送的数据data)
void USART1_IRQHandler(void)
{

//判断中断是否产生
if( USART_GetITStatus(USART1,USART_IT_RXNE) == SET )//如果接收到数据
{
//接收数据
data = USART_ReceiveData(USART1);//接收从USART2发送过来的中断,每次接收1个字节

while( USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
//发送字符到串口1
//USART_SendData(USART1,n);
//while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);

//清空中断标志位
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
}

液晶屏显示

(1)工具函数与文件

液晶显示工具包
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/* oled.c文件实现液晶屏文字显示 */
#include "oled.h"
#include "stdlib.h"
#include "oledfont.h"
#include "SysTick.h"

u8 OLED_GRAM[128][8];

//更新显存到LCD
void OLED_Refresh_Gram(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA);
}
}

//向SSD1306写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 cmd)
{
u8 i;
OLED_RS=cmd; //写命令
OLED_CS=0;
for(i=0;i<8;i++)
{
OLED_SCLK=0;
if(dat&0x80)OLED_SDIN=1;
else OLED_SDIN=0;
OLED_SCLK=1;
dat<<=1;
}
OLED_CS=1;
OLED_RS=1;
}

//开启OLED显示
void OLED_Display_On(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON
OLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON
}

//关闭OLED显示
void OLED_Display_Off(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF
OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF
}

//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i<8;i++)for(n=0;n<128;n++)OLED_GRAM[n][i]=0X00;
OLED_Refresh_Gram();//更新显示
}

//画点
//x:0~127
//y:0~63
//t:1 填充 0,清空
void OLED_DrawPoint(u8 x,u8 y,u8 t)
{
u8 pos,bx,temp=0;
if(x>127||y>63)return;//超出范围了.
pos=7-y/8;
bx=y%8;
temp=1<<(7-bx);
if(t)OLED_GRAM[x][pos]|=temp;
else OLED_GRAM[x][pos]&=~temp;
}

//x1,y1,x2,y2 填充区域的对角坐标
//确保x1<=x2;y1<=y2 0<=x1<=127 0<=y1<=63
//dot:0,清空;1,填充
void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot)
{
u8 x,y;
for(x=x1;x<=x2;x++)
{
for(y=y1;y<=y2;y++)OLED_DrawPoint(x,y,dot);
}
OLED_Refresh_Gram();//更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode)
{
u8 temp,t,t1;
u8 y0=y;
u8 csize=(size/8+((size%8)?1:0))*(size/2); //得到字体一个字符对应点阵集所占的字节数
chr=chr-' ';//得到偏移后的值
for(t=0;t<csize;t++)
{
if(size==12)temp=asc2_1206[chr][t]; //调用1206字体
else if(size==16)temp=asc2_1608[chr][t]; //调用1608字体
else if(size==24)temp=asc2_2412[chr][t]; //调用2412字体
else return; //没有的字库
for(t1=0;t1<8;t1++)
{
if(temp&0x80)OLED_DrawPoint(x,y,mode);
else OLED_DrawPoint(x,y,!mode);
temp<<=1;
y++;
if((y-y0)==size)
{
y=y0;
x++;
break;
}
}
}
}


//m^n函数
u32 mypow(u8 m,u8 n)
{
u32 result=1;
while(n--)result*=m;
return result;
}
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式 0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size)
{
u8 t,temp;
u8 enshow=0;
for(t=0;t<len;t++)
{
temp=(num/mypow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(size/2)*t,y,' ',size,1);
continue;
}else enshow=1;

}
OLED_ShowChar(x+(size/2)*t,y,temp+'0',size,1);
}
}
//显示字符串
//x,y:起点坐标
//size:字体大小
//*p:字符串起始地址
void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size)
{
while((*p<='~')&&(*p>=' '))//判断是不是非法字符!
{
if(x>(128-(size/2))){x=0;y+=size;}
if(y>(64-size)){y=x=0;OLED_Clear();}
OLED_ShowChar(x,y,*p,size,1);
x+=size/2;
p++;
}

}
//初始化SSD1306
void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC, ENABLE );

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_4|GPIO_Pin_6|GPIO_Pin_3); //拉高电平

OLED_WR_Byte(0xAE,OLED_CMD); //关闭显示
OLED_WR_Byte(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率
OLED_WR_Byte(80,OLED_CMD); //[3:0],分频因子;[7:4],震荡频率
OLED_WR_Byte(0xA8,OLED_CMD); //设置驱动路数
OLED_WR_Byte(0X3F,OLED_CMD); //默认0X3F(1/64)
OLED_WR_Byte(0xD3,OLED_CMD); //设置显示偏移
OLED_WR_Byte(0X00,OLED_CMD); //默认为0

OLED_WR_Byte(0x40,OLED_CMD); //设置显示开始行 [5:0],行数.

OLED_WR_Byte(0x8D,OLED_CMD); //电荷泵设置
OLED_WR_Byte(0x14,OLED_CMD); //bit2,开启/关闭
OLED_WR_Byte(0x20,OLED_CMD); //设置内存地址模式
OLED_WR_Byte(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
OLED_WR_Byte(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127;
OLED_WR_Byte(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
OLED_WR_Byte(0xDA,OLED_CMD); //设置COM硬件引脚配置
OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置

OLED_WR_Byte(0x81,OLED_CMD); //对比度设置
OLED_WR_Byte(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮)
OLED_WR_Byte(0xD9,OLED_CMD); //设置预充电周期
OLED_WR_Byte(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2;
OLED_WR_Byte(0xDB,OLED_CMD); //设置VCOMH 电压倍率
OLED_WR_Byte(0x30,OLED_CMD); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;

OLED_WR_Byte(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
OLED_WR_Byte(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示
OLED_WR_Byte(0xAF,OLED_CMD); //开启显示
OLED_Clear();
}
精准延时工具包
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
/*SysTick.c文件实现精准延时函数*/
#include "SysTick.h"

static u8 fac_us=0; //us延时倍乘数
static u16 fac_ms=0; //ms延时倍乘数


//初始化延迟函数
//SYSTICK的时钟固定为AHB时钟的1/8
//SYSCLK:系统时钟频率
void SysTick_Init(u8 SYSCLK)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
fac_us=SYSCLK/8;
fac_ms=(u16)fac_us*1000;
}


void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD=nus*fac_us; //时间加载
SysTick->VAL=0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(1<<16)));//等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
//延时nms
//注意nms的范围
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK单位为Hz,nms单位为ms
//对72M条件下,nms<=1864
void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD为24bit)
SysTick->VAL =0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(1<<16)));//等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}

(2)数字与字母显示

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
#include <stdio.h>
#include "stm32f10x.h"
#include "SysTick.h"
#include "oled.h"

int main()
{
int num = 1000;
u8 buf[10] = "ZhangSan";

SysTick_Init(72); // 初始化延时(72MHz芯片主频)
OLED_Init(); // 初始化OLED

while(1)
{

OLED_ShowNum(0,0,num,4,16);//显示数字
OLED_ShowString(0,16,buf,16);
OLED_ShowChar(50,0,'S', 16, 1);
OLED_Refresh_Gram(); //更新数据到OLED


}
}

  • 调用SysTick_Init()函数延时规定的时间

  • 调用oled.c定义的OLED_ShowNum等方法

  • 相关参数可以查看oled.c内的定义

    1
    2
    3
    4
    //x,y :起点坐标	
    // num or char : 要显示的数据内容或地址
    // len字长(一般填16)
    // size:字体大小(一般填16)

(3)汉字显示

延时工具包
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
122
#include "delay.h"
#include "sys.h"
//////////////////////////////////////////////////////////////////////////////////
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_UCOS
#include "includes.h" //ucos 使用
#endif

static u8 fac_us=0;//us延时倍乘数
static u16 fac_ms=0;//ms延时倍乘数
#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.
//systick中断服务函数,使用ucos时用到
void SysTick_Handler(void)
{
OSIntEnter(); //进入中断
OSTimeTick(); //调用ucos的时钟服务程序
OSIntExit(); //触发任务切换软中断
}
#endif

//初始化延迟函数
//当使用ucos的时候,此函数会初始化ucos的时钟节拍
//SYSTICK的时钟固定为HCLK时钟的1/8
//SYSCLK:系统时钟
void delay_init()
{

#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.
u32 reload;
#endif
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8
fac_us=SystemCoreClock/8000000; //为系统时钟的1/8

#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.
reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为K
reload*=1000000/OS_TICKS_PER_SEC;//根据OS_TICKS_PER_SEC设定溢出时间
//reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右
fac_ms=1000/OS_TICKS_PER_SEC;//代表ucos可以延时的最少单位
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断
SysTick->LOAD=reload; //每1/OS_TICKS_PER_SEC秒中断一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
#else
fac_ms=(u16)fac_us*1000;//非ucos下,代表每个ms需要的systick时钟数
#endif
}

#ifdef OS_CRITICAL_METHOD //使用了ucos
//延时nus
//nus为要延时的us数.
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD; //LOAD的值
ticks=nus*fac_us; //需要的节拍数
tcnt=0;
told=SysTick->VAL; //刚进入时的计数器值
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{
if(tnow<told)tcnt+=told-tnow;//这里注意一下SYSTICK是一个递减的计数器就可以了.
else tcnt+=reload-tnow+told;
told=tnow;
if(tcnt>=ticks)break;//时间超过/等于要延迟的时间,则退出.
}
};
}
//延时nms
//nms:要延时的ms数
void delay_ms(u16 nms)
{
if(OSRunning==TRUE)//如果os已经在跑了
{
if(nms>=fac_ms)//延时的时间大于ucos的最少时间周期
{
OSTimeDly(nms/fac_ms);//ucos延时
}
nms%=fac_ms; //ucos已经无法提供这么小的延时了,采用普通方式延时
}
delay_us((u32)(nms*1000)); //普通方式延时,此时ucos无法启动调度.
}
#else//不用ucos时
//延时nus
//nus为要延时的us数.
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD=nus*fac_us; //时间加载
SysTick->VAL=0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(1<<16)));//等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
//延时nms
//注意nms的范围
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK单位为Hz,nms单位为ms
//对72M条件下,nms<=1864
void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD为24bit)
SysTick->VAL =0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(1<<16)));//等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}


液晶显示工具包
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
#include "oled.h"
#include "stdlib.h"
#include "oledfont.h"
#include "delay.h"
//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127
//[1]0 1 2 3 ... 127
//[2]0 1 2 3 ... 127
//[3]0 1 2 3 ... 127
//[4]0 1 2 3 ... 127
//[5]0 1 2 3 ... 127
//[6]0 1 2 3 ... 127
//[7]0 1 2 3 ... 127

#if OLED_MODE==1
//向SSD1106写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 cmd)
{
DATAOUT(dat);
if(cmd)
OLED_DC_Set();
else
OLED_DC_Clr();
OLED_CS_Clr();
OLED_WR_Clr();
OLED_WR_Set();
OLED_CS_Set();
OLED_DC_Set();
}
#else
//向SSD1106写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 cmd)
{
u8 i;
if(cmd)
OLED_DC_Set();
else
OLED_DC_Clr();
OLED_CS_Clr();
for(i=0;i<8;i++)
{
OLED_SCLK_Clr();
if(dat&0x80)
OLED_SDIN_Set();
else
OLED_SDIN_Clr();
OLED_SCLK_Set();
dat<<=1;
}
OLED_CS_Set();
OLED_DC_Set();
}
#endif
void OLED_Set_Pos(unsigned char x, unsigned char y)
{
OLED_WR_Byte(0xb0+y,OLED_CMD);
OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
OLED_WR_Byte((x&0x0f)|0x01,OLED_CMD);
}
//开启OLED显示
void OLED_Display_On(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON
OLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON
}
//关闭OLED显示
void OLED_Display_Off(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF
OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF
}
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
} //更新显示
}


//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED_ShowChar(u8 x,u8 y,u8 chr)
{
unsigned char c=0,i=0;
c=chr-' ';//得到偏移后的值
if(x>Max_Column-1){x=0;y=y+2;}
if(SIZE ==16)
{
OLED_Set_Pos(x,y);
for(i=0;i<8;i++)
OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
OLED_Set_Pos(x,y+1);
for(i=0;i<8;i++)
OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
}
else {
OLED_Set_Pos(x,y+1);
for(i=0;i<6;i++)
OLED_WR_Byte(F6x8[c][i],OLED_DATA);

}
}
//m^n函数
u32 oled_pow(u8 m,u8 n)
{
u32 result=1;
while(n--)result*=m;
return result;
}
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式 0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size)
{
u8 t,temp;
u8 enshow=0;
for(t=0;t<len;t++)
{
temp=(num/oled_pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(size/2)*t,y,' ');
continue;
}else enshow=1;

}
OLED_ShowChar(x+(size/2)*t,y,temp+'0');
}
}
//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr)
{
unsigned char j=0;
while (chr[j]!='\0')
{ OLED_ShowChar(x,y,chr[j]);
x+=8;
if(x>120){x=0;y+=2;}
j++;
}
}
//显示汉字--no表示行数
void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{
u8 t,adder=0;
OLED_Set_Pos(x,y);
for(t=0;t<16;t++)
{
OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);
adder+=1;
}
OLED_Set_Pos(x,y+1);
for(t=0;t<16;t++)
{
OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);
adder+=1;
}
}
/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
{
unsigned int j=0;
unsigned char x,y;

if(y1%8==0) y=y1/8;
else y=y1/8+1;
for(y=y0;y<y1;y++)
{
OLED_Set_Pos(x0,y);
for(x=x0;x<x1;x++)
{
OLED_WR_Byte(BMP[j++],OLED_DATA);
}
}
}


//初始化SSD1306
void OLED_Init(void)
{


GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能A端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_6| GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOD3,6
GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_7|GPIO_Pin_4);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能A端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOD3,6

GPIO_SetBits(GPIOB,GPIO_Pin_8);




OLED_RST_Set();
delay_ms(100);
OLED_RST_Clr();
delay_ms(200);
OLED_RST_Set();

OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
OLED_WR_Byte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
OLED_WR_Byte(0x00,OLED_CMD);//-not offset
OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
OLED_WR_Byte(0x12,OLED_CMD);
OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
OLED_WR_Byte(0x02,OLED_CMD);//
OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel

OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/
OLED_Clear();
OLED_Set_Pos(0,0);
}
中断优先工具包
1
2
3
4
5
6
7
8
#include "sys.h"

void NVIC_Configuration(void)
{

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级

}

串口通信配置工具包

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
122
123
124
125
126
127
128
129
130
131
132
#include "sys.h"
#include "usart.h"

//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;

};

FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
_sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
#endif

/*使用microLib的方法*/
/*
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (uint8_t) ch);

while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {}

return ch;
}
int GetKey (void) {

while (!(USART1->SR & USART_FLAG_RXNE));

return ((int)(USART1->DR & 0x1FF));
}
*/

#if EN_USART1_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0; //接收状态标记

void uart_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE); //使能USART1,GPIOA时钟以及复用功能时钟
//USART1_TX PA.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);

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

//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;//一般设置为9600;
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); //初始化串口
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
USART_Cmd(USART1, ENABLE); //使能串口

}

void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 Res;
#ifdef OS_TICKS_PER_SEC //如果时钟节拍数定义了,说明要使用ucosII了.
OSIntEnter();
#endif
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据

if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
#ifdef OS_TICKS_PER_SEC //如果时钟节拍数定义了,说明要使用ucosII了.
OSIntExit();
#endif
}
#endif

  • 支持中断处理串口通信
  • 支持printf输出内容到串口
文字取模添加

在oledfont.h可以看到字符串的16进制对应,我们也可以取模然后添加汉字

汉字显示
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
#include <stdio.h>
#include "stm32f10x.h"
#include "delay.h"
#include "sys.h"
#include "oled.h"
#include "bmp.h"
int main()
{
u8 t;
delay_init(); //延时函数初始化
NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 LED_Init();
//LED端口初始化
OLED_Init(); //初始化OLED
OLED_Clear() ;
t=' ';
while(1)
{
OLED_Clear();
// LED_ON;
OLED_ShowCHinese(0,0,0);//中
OLED_ShowCHinese(18,0,1);//景
OLED_ShowCHinese(36,0,2);//园
OLED_ShowCHinese(54,0,3);//电
OLED_ShowCHinese(72,0,4);//子
OLED_ShowCHinese(90,0,5);//科
OLED_ShowCHinese(108,0,6);//技

OLED_ShowCHinese(0,6,7);//佛
OLED_ShowCHinese(18,6,8);//科
OLED_ShowString(0,3,(unsigned char *)"1.3' OLED TEST");
}

}

温度测量

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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
#include <stdio.h>
#include "stm32f10x.h"

//GPIO信息结构体体初始化
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
USART_InitTypeDef USART_InitStructure; //串口配置的信息结构体

unsigned char dht11_data[5];


unsigned char data;

//重定义fputc函数
int fputc(int ch, FILE *f)
{
//发送字符到串口1
USART_SendData(USART1,ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);

return ch;
}


//延时100ms ,计数72000000次时间过了1s , 计数72000次时间过了1ms,计数72次表示时间过了1us
void delay_ms(int x)
{


SysTick->LOAD = 72000*x; //把计数值加载到LOAD寄存器 --->每次计数100ms

SysTick->VAL = 0; //清空VAL寄存器的计数值

SysTick->CTRL |= 0x1<<0; //开始计时,打开定时器把CTRL的第0位置1

while(0 == (SysTick->CTRL & (0x1<<16)) ); //判断CTRL是否为1,如果为1表示计时时间到了

SysTick->CTRL &= ~(0x1<<0); //关闭定时器,把CTRL的第0位清零

}

//微妙级别延时
void delay_us(int x)
{



SysTick->LOAD = 72*x; //把计数值加载到LOAD寄存器 --->每次计数100ms

SysTick->VAL = 0; //清空VAL寄存器的计数值

SysTick->CTRL |= 0x1<<0; //开始计时,打开定时器把CTRL的第0位置1

while(0 == (SysTick->CTRL & (0x1<<16)) ); //判断CTRL是否为1,如果为1表示计时时间到了

SysTick->CTRL &= ~(0x1<<0); //关闭定时器,把CTRL的第0位清零

}

//led-》GPIO信息结构体初始化
void led_init()
{
//关闭引脚JTAG复用功能-->PA13、PA14、PA15、PB3、PB4
RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

/* GPIOB Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

/* Configure PD0 and PD2 in output pushpull mode */
GPIO_InitStructure.GPIO_Pin = 0xff ;//GPIO_Pin_0~GPIO_Pin_7
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//设置运行频率50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_SetBits(GPIOB, 0xff);
}






void delay()
{
unsigned int i, j;
for(i=0; i<100; i++)
for(j=0; j<10000; j++);


}



//设置串口1-->PA9+PA10
void usart1_init(u32 bound)
{

//1.使能GPIO外设、IO复用时钟、USART2时钟 PA9 和PA10
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

//2.配置GPIO + 初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // PA2 TX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO

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

//3.配置USART1 + 初始化USART1
USART_InitStructure.USART_BaudRate = bound;//波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//数据位8位
USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位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); //把配置信息加载到串口2

//4.配置NVIC + 初始化NVIC
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //选择串口2的中断
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //设置抢占优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //设置响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能串口2的中断
NVIC_Init(&NVIC_InitStructure); //把配置信息加载到中断

//5.使能串口中断
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//接收到数据触发中断

//6.使能串口
USART_Cmd(USART1,ENABLE);

}


//把PB15设置为输出模式
void set_PA15_outputmode()
{
/* GPIOB Peripheral clock enable 使能对应GPIO组的硬件时钟,使能第B组的硬件时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

/* Configure PB15 in output pushpull mode */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; //选择15号引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置运行速度为100MHz


GPIO_Init(GPIOA, &GPIO_InitStructure);


}
//把PB15设置为输入模式
void set_PA15_inputmode()
{

/* GPIOB Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

/* Configure PD0 and PD2 in output pushpull mode */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//设置运行频率50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //设置推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);

}

//MCU请求dht11发送数据
int ask_dht11_data()
{
int i=0;
//请求dht11发送数据
set_PA15_outputmode(); //--》设置为输出模式
GPIO_ResetBits(GPIOA, GPIO_Pin_15);
delay_ms(20);
GPIO_SetBits(GPIOA, GPIO_Pin_15);

delay_us(30);

//判断dht11是否有回应--》在一定的时间内没有回应,就要重新请求数据
set_PA15_inputmode();

//超时控制--》设置100us


while(i<100)
{

if(0 == GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15))
break;
delay_us(1);
i++;

}
//如果超时,就结束函数
if(i>= 100)
return -1;

i=0;
//检测低电平持续时间--》也要设置超时控制
while(i<100)
{

if(1 == GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15))
break;
delay_us(1);
i++;

}
//如果超时,就结束函数
if(i>= 100)
return -1;



return 0;

}

//每次读取一个字节数据
unsigned char read_dht11_data_1byte()
{
int i;
unsigned char data=0;
//等待高电平时间持续结束
//while(1 == PAin(15));
while(1 == GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15));
//读取8bit数据--》合成一个unsigned char 数据
for(i=0; i<8; i++)
{

//判断是1还是0-->等待低电平时间持续结束
while( 0 == GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15));
delay_us(40);
//40us后,仍然是高电平,该bit则为1
if(1 == GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15))
{
data |= 1<< (7-i); //先读到是高位
}
//等待高电平时间持续结束
while(1 == GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15));
}

return data;

}

//读取全部数据
int read_dht11_all_data()
{
int i;
//不断请求dht11发送数据
while( -1 == ask_dht11_data());

for(i=0; i<5; i++)
{

dht11_data[i]= read_dht11_data_1byte();

}
//判断校验和
if(dht11_data[4] == dht11_data[0]+dht11_data[1]+dht11_data[2]+dht11_data[3])
{

return 1;

}
else
{
return 0;
}
}
int main()
{

//初始化系统定时器时钟--》时钟频率为72MHz
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
led_init();

usart1_init(9600);


while(1)
{


delay();
//if(data == 'D')
//{
//读取温湿度数据 成功
if(1 == read_dht11_all_data())
{
printf("H:%d.%d T:%d.%d\r\n", dht11_data[0],dht11_data[1], dht11_data[2],dht11_data[3]);


}

//}
}

}

//串口1中断服务函数
void USART1_IRQHandler(void)
{

//判断中断是否产生
if( USART_GetITStatus(USART1,USART_IT_RXNE) == SET )//如果接收到数据
{
//接收数据
data = USART_ReceiveData(USART1);//接收从USART2发送过来的中断



while( USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);

//清空中断标志位
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
}

`