项目模板搭建

工程文件目录创建

  • Project:放工程文件,编译文件等。
  • Firmware:放 ARM 内核文件,标准外设库文件等。
  • Hardware:放开发板的硬件驱动文件。
  • User:放 main 函数,gd32f4xx_it 文件,systick 文件。
  • Doc: 放 readme.txt 文件,工程说明文件。

keil分组创建

新建分组:

  • User
  • CMSIS
  • Firmware
  • Hardware
  • Doc

GD32

固件库移植

找到固件库的下载目录,GD32F4xx_Firmware_Library_V3.0.4\GD32F4xx_Firmware_Library\Firmware 文件夹下的内容全部拷贝到新建目录的Firmware 下

程序入口移植

找到我们的固件库的下载目录,将GD32F4xx_Firmware_Library_V3.0.4\Template中的文件进行拷贝到工程目录的User目录中

CMSIS分组添加

  • 来到Firmware\CMSIS\GD\GD32F4xx\Source目录下,选择system_gd32f4xx.c
  • 来到Firmware\CMSIS\GD\GD32F4xx\Source\ARM目录下,选择startuo_gd32f450_470.s

Firmware分组添加

来到Firmware\GD32F4xx_standard_peripheral\Source目录下,选择如下:

  • gd32f4xx_rcu.c
  • gd32f4xx_gpio.c
  • gd32f4xx_misc.c

工程配置

  1. Target配置
    点击魔法棒,进入配置中的Target,选择ARM compiler 为V6
    勾选Use MicroLIB
  2. Output配置
    选择创建hex文件
  3. C/C++配置
    • Define配置为:USE_STDPERIPH_DRIVER,GD32F470
    • Warings选择AC5-like warnings
    • 选择c99和c++03
    • Optimization选择-O1
  4. Include配置
    添加如下几个目录:
    • User
    • Firmware\CMSIS\GD\GD32F4xx\Include
    • Firmware\CMSIS
    • Firmware\GD32F4xx_standard_peripheral\Include

程序代码修改

  • 打开 main.c 文件,删除一些不必要的代码

  • 打开 gd32f4xx_it.c 文件,拉到最后面,然后删掉 Systick_Handler 下面的代码

STM32

固件库移植

找到我们的固件库的下载目录,将 STM32F4xx_DSP_StdPeriph_Lib_V1.9.0\Libraries 文件夹下的内容全部拷贝到新建目录的Firmware 下

程序入口移植

找到我们的固件库的下载目录,将STM32F4xx_DSP_StdPeriph_Lib_V1.9.0/Project/STM32F4xx_StdPeriph_Templates中的.c.h文件拷贝到工程目录User目录中

CMSIS分组添加

来到Firmware\CMSIS\Device\ST\STM32F4xx\Source\Templates\arm目录下,选择startup_stm32f40_41xxx.s

Firmware分组添加

来到Firmware\STM32F4xx_StdPeriph_Driver\src目录下,选择如下:

  • stm32f4xx_rcc.c
  • stm32f4xx_gpio.c
  • misc.c

程序代码修改

  • 打开 main.c 文件,删除一些不必要的代码
  • 打开 stm32f4xx_it.c 文件,拉到最后面,然后删掉 Systick_Handler 下面的代码

工程配置

  1. Target配置
    点击魔法棒,进入配置中的Target,选择ARM compiler 为V6
    勾选Use MicroLIB

  2. Output配置
    选择创建hex文件

  3. C/C++配置

    • Define配置为:USE_STDPERIPH_DRIVER,STM32F40_41xxx
    • Warings选择AC5-like warnings
    • 选择c99和c++03
    • Optimization选择-O1
  4. Include配置

添加如下几个目录:

  • User
  • Firmware\CMSIS\Device\ST\STM32F4xx\Include
  • Firmware\CMSIS\Include
  • Firmware\STM32F4xx_StdPeriph_Driver\inc

编译错误

通常在编译过程中会报错,是由于当前CMSIS接口定义不符合AC6的编译环境,我们需要覆盖掉CMISIS的编译头文件。
首先,删除Firmware\CMSIS\Include中所有的头文件。
然后,找到你的Pack安装目录,查找方式如下:

  1. 点击Pack install
  2. 查看窗口上方路径

来到这个目录中的Packs\ARM\CMSIS\5.9.0\CMSIS\Core\Include中,
拷贝这个目录中所有的.h文件,拷贝到你的项目目录的Firmware/CMSIS/Include目录中

初始化模板代码

GPIO

输出初始化

推挽输出
1
2
3
rcu_periph_clock_enable(RCU_GPIOx);
gpio_mode_set(GPIOx, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_x);
gpio_output_options_set(GPIOx, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_x);
开漏输出
1
2
3
rcu_periph_clock_enable(RCU_GPIOx);
gpio_mode_set(GPIOx, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_x);
gpio_output_options_set(GPIOx, GPIO_OTYPE_OD, GPIO_OSPEED_MAX, GPIO_PIN_x);
开漏上拉输出
1
2
3
rcu_periph_clock_enable(RCU_GPIOx);
gpio_mode_set(GPIOx, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_x);
gpio_output_options_set(GPIOx, GPIO_OTYPE_OD, GPIO_OSPEED_MAX, GPIO_PIN_x);

输入初始化

浮空输入
1
2
rcu_periph_clock_enable(RCU_GPIOx);
gpio_mode_set(GPIOx, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_x);
上拉输入
1
2
rcu_periph_clock_enable(RCU_GPIOx);
gpio_mode_set(GPIOx, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN_x);
下拉输入
1
2
rcu_periph_clock_enable(RCU_GPIOx);
gpio_mode_set(GPIOx, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO_PIN_x);

输出电平

高电平
1
gpio_bit_set(GPIOx, GPIO_PIN_x);
低电平
1
gpio_bit_reset(GPIOx, GPIO_PIN_x);
高低电平
1
gpio_bit_write(GPIOx, GPIO_PIN_x, SET or RESET);
Toggle操作
1
gpio_bit_toggle(GPIOx, GPIO_PIN_x);
输入电平读取
1
FlagStatus state = gpio_input_bit_get(GPIOx, GPIO_PIN_x);

串口

串口初始化

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
// 哪个串口
uint32_t usartx = USART0;
uint32_t usartx_rcu = RCU_USART0;
uint32_t usartx_irq = USART0_IRQn;

// 波特率
uint32_t usartx_p_baudrate = 115200;

// tx和rx,用了哪个引脚
uint32_t usartx_tx_port_rcu = RCU_GPIOA;
uint32_t usartx_tx_port = GPIOA;
uint32_t usartx_tx_pin = GPIO_PIN_9;
// 复用功能编号
uint32_t usartx_tx_af = GPIO_AF_7;

// tx和rx,用了哪个引脚
uint32_t usartx_rx_port_rcu = RCU_GPIOA;
uint32_t usartx_rx_port = GPIOA;
uint32_t usartx_rx_pin = GPIO_PIN_10;
// 复用功能编号
uint32_t usartx_rx_af = GPIO_AF_7;


/*************** gpio *****************/
// TX
// 配置时钟
rcu_periph_clock_enable(usartx_tx_port_rcu);
// 配置模式: 复用功能
gpio_mode_set(usartx_tx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_tx_pin);
// 配置复用功能
gpio_af_set(usartx_tx_port, usartx_tx_af, usartx_tx_pin);
gpio_output_options_set(usartx_tx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_tx_pin);

// RX
// 配置时钟
rcu_periph_clock_enable(usartx_rx_port_rcu);
gpio_mode_set(usartx_rx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_rx_pin);
gpio_af_set(usartx_rx_port, usartx_rx_af, usartx_rx_pin);
// 配置输出参数
gpio_output_options_set(usartx_rx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_rx_pin);

/*************** usart ****************/
// 串口时钟
rcu_periph_clock_enable(usartx_rcu);
// USART复位
usart_deinit(usartx);

// 波特率
usart_baudrate_set(usartx, usartx_p_baudrate);
// 校验位
usart_parity_config(usartx, USART_PM_NONE);
// 数据位数
usart_word_length_set(usartx, USART_WL_8BIT);
// 停止位
usart_stop_bit_set(usartx, USART_STB_1BIT);
// 先发送高位还是低位
usart_data_first_config(usartx, USART_MSBF_LSB);

// 发送功能配置
usart_transmit_config(usartx, USART_TRANSMIT_ENABLE);



// 接收功能配置
usart_receive_config(usartx, USART_RECEIVE_ENABLE);
// 接收中断配置
nvic_irq_enable(usartx_irq, 2, 2);
// usart int rbne
usart_interrupt_enable(usartx, USART_INT_RBNE);
usart_interrupt_enable(usartx, USART_INT_IDLE);



// 使能串口
usart_enable(usartx);

串口发送字节

1
2
3
4
5
6
7
8
static void send_byte(uint8_t data) {
//通过USART发送
usart_data_transmit(USART0, data);

//判断缓冲区是否已经空了
//FlagStatus state = usart_flag_get(USART_NUM,USART_FLAG_TBE);
while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
}

发送字符串

1
2
3
4
5
6
static void send_string(char* data) {
while(data && *data){
send_byte((uint8_t)(*data));
data++;
}
}

配置Printf

1
2
3
4
int fputc(int ch, FILE *f){
send_byte((uint8_t)ch);
return ch;
}

中断接收

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
#define USART_RECEIVE_LENGTH  1024
//串口接收缓冲区大小
uint8_t g_recv_buff[USART_RECEIVE_LENGTH]; // 接收缓冲区
//接收到字符存放的位置
uint32_t g_recv_length = 0;



void USART0_IRQHandler(void) {
if ((usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) == SET) {
uint16_t value = usart_data_receive(USART0);
g_recv_buff[g_recv_length] = value;
g_recv_length++;
}
if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE) == SET) {
//读取缓冲区,清空缓冲区
usart_data_receive(USART0);
g_recv_buff[g_recv_length] = '\0';

// TODO: g_recv_buff为接收的数据,g_recv_length为接收的长度
printf("recv: %s\r\n", g_recv_buff);

g_recv_length = 0;
}
}

外部中断

硬件中断

初始化
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
static void EXTI_config() {
uint32_t extix = EXTI_0;
uint32_t extix_irq = EXTI0_IRQn;
uint32_t extix_irq_pre = 1;
uint32_t extix_irq_sub = 1;

uint32_t extix_trig = EXTI_TRIG_BOTH;

uint32_t extix_port = GPIOA;
uint32_t extix_pin = GPIO_PIN_0;
uint32_t extix_src_port = EXTI_SOURCE_GPIOA;
uint32_t extix_src_pin = EXTI_SOURCE_PIN0;

/*************** gpio ****************/
// PA0,
// 时钟初始化
rcu_periph_clock_enable(RCU_GPIOA);
// 配置GPIO模式
gpio_mode_set(extix_port, GPIO_MODE_INPUT, GPIO_PUPD_NONE, extix_pin);

/*************** exti ****************/
// 时钟配置
rcu_periph_clock_enable(RCU_SYSCFG);
// 配置中断源
syscfg_exti_line_config(extix_src_port, extix_src_pin);
// 中断初始化
exti_init(extix, EXTI_INTERRUPT, extix_trig);

// 配置中断优先级
nvic_irq_enable(extix_irq, extix_irq_pre, extix_irq_sub);
// 使能中断
exti_interrupt_enable(extix);
// 清除中断标志位
exti_interrupt_flag_clear(extix);
}
中断函数
1
2
3
4
5
6
7
8
void EXTI(xxxx)_IRQHandler() {
// 判断寄存器状态
if(SET == exti_interrupt_flag_get(EXTI_x)) {
// TODO:
}
// 清除中断标志位
exti_interrupt_flag_clear(EXTI_x);
}

软件中断

初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static void EXTI_config() {
uint32_t extix = EXTI_0;
uint32_t extix_irq = EXTI0_IRQn;
uint32_t extix_irq_pre = 1;
uint32_t extix_irq_sub = 1;

/*************** exti ****************/
// 时钟配置
rcu_periph_clock_enable(RCU_SYSCFG);
// 中断初始化
exti_init(extix, EXTI_INTERRUPT, EXTI_TRIG_NONE);
// 配置中断优先级
nvic_irq_enable(extix_irq, extix_irq_pre, extix_irq_sub);
// 使能中断
exti_interrupt_enable(extix);
// 清除中断标志位
exti_interrupt_flag_clear(extix);
}
中断函数
1
2
3
4
5
6
7
8
void EXTI(xxxx)_IRQHandler() {
// 判断寄存器状态
if(SET == exti_interrupt_flag_get(EXTI_x)) {
// TODO:
}
// 清除中断标志位
exti_interrupt_flag_clear(EXTI_x);
}
触发中断
1
exti_software_interrupt_enable(EXTI_x);

中断优先级

全局中断优先级分组

1
2
3
4
5
nvic_priority_group_set(NVIC_PRIGROUP_PRE0_SUB4);
nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
nvic_priority_group_set(NVIC_PRIGROUP_PRE3_SUB1);
nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);

抢占优先级和响应优先级配置

1
nvic_irq_enable(xxx_irqn, 抢占优先级, 响应优先级);

定时器

基本定时器

Timer初始化
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
static void TIMER_config() {
uint32_t timerx = TIMER5; // 哪个定时器
uint32_t timerx_rcu = RCU_TIMER5;
uint32_t timerx_psc = RCU_TIMER_PSC_MUL4;// 倍频
uint32_t timerx_irq = TIMER5_DAC_IRQn;

uint32_t timerx_prescaler = 10000 - 1; // 分频计数
uint32_t timerx_period = SystemCoreClock / 10000 - 1; // 周期计数

/*************** Timer config **************/
// 时钟配置
rcu_periph_clock_enable(timerx_rcu);
// 复位定时器
timer_deinit(timerx);
// 倍频配置
rcu_timer_clock_prescaler_config(timerx_psc);
// 初始化定时器
timer_parameter_struct tps;
timer_struct_para_init(&tps);
tps.prescaler = timerx_prescaler; // 分频系数 240 000 000
tps.period = timerx_period; // 周期
timer_init(timerx, &tps);
// 中断优先级
nvic_irq_enable(timerx_irq, 2, 2);
timer_interrupt_enable(timerx, TIMER_INT_UP);
timer_enable(timerx);
}
Timer中断函数
1
2
3
4
5
6
7
8
void TIMER5_DAC_IRQHandler(void) {
if(SET == timer_interrupt_flag_get(TIMER5, TIMER_INT_UP)) {
gpio_bit_toggle(GPIOD, GPIO_PIN_5);
// gpio_bit_set(GPIOD, GPIO_PIN_5);
}
//清除中断标志位
timer_interrupt_flag_clear(TIMER5,TIMER_INT_FLAG_UP);
}

通用定时器

初始化PWM
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
static void PWM_config() {
uint32_t timerx = TIMER1;
uint32_t timerx_chn = TIMER_CH_0;
uint32_t timerx_rcu = RCU_TIMER1;
uint32_t timerx_psc = RCU_TIMER_PSC_MUL2;

uint32_t timerx_prescaler = 10000 - 1; // 分频计数
uint32_t timerx_period = SystemCoreClock / 10000 - 1; // 周期计数

uint32_t timerx_port = GPIOA; // 哪个引脚和端口
uint32_t timerx_port_rcu = RCU_GPIOA;
uint32_t timerx_pin = GPIO_PIN_5;

/*************** GPIO config **************/
// 配置时钟
rcu_periph_clock_enable(timerx_port_rcu);
// 配置GPIO模式
gpio_mode_set(timerx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, timerx_pin);
// 配置GPIO输出
gpio_output_options_set(timerx_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, timerx_pin);
// 配置复用功能
gpio_af_set(timerx_port, GPIO_AF_1, timerx_pin);

/*************** Timer config *************/
// 时钟配置
rcu_periph_clock_enable(timerx_rcu);
// 复位定时器
timer_deinit(timerx);
// 倍频配置
rcu_timer_clock_prescaler_config(timerx_psc);

// 初始化定时器
timer_parameter_struct tps;
timer_struct_para_init(&tps);
tps.prescaler = timerx_prescaler; // 分频计数
tps.period = timerx_period; // 周期计数
timer_init(timerx, &tps);

// 配置输出通道
timer_oc_parameter_struct tops;
timer_channel_output_struct_para_init(&tops);
tops.outputstate = TIMER_CCX_ENABLE;
timer_channel_output_config(timerx, timerx_chn, &tops);

// 输出模式配置
timer_channel_output_mode_config(timerx, timerx_chn, TIMER_OC_MODE_PWM0);

// 初始化
timer_enable(timerx);
}
占空比控制
1
2
3
4
static void PWM_update(uint32_t pulse) {
// 配置输出的占空比
timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_0, pulse);
}

高级定时器

高级定时器多通道互补
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 "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "Usart0.h"

// T7
// ch0
// N: PA5 ON
// P: PC6 OP
// ch1
// N: PB14 ON
// P: PC7 OP
// ch2
// N: PB15 ON
// P: PC8 OP

// 分频计数
// 周期计数
#define PRESCALER (10 - 1)
#define PERIOD (SystemCoreClock / 100000 - 1)

void Usart0_recv(uint8_t *data, uint32_t len) {

}

static void PWM_config() {
uint32_t timerx = TIMER7;
uint32_t timerx_rcu = RCU_TIMER7;
uint32_t timerx_psc = RCU_TIMER_PSC_MUL2;

uint32_t timerx_prescaler = PRESCALER; // 分频计数
uint32_t timerx_period = PERIOD; // 周期计数

// ch0
uint32_t timerx_ch0_n_port = GPIOA;
uint32_t timerx_ch0_n_port_rcu = RCU_GPIOA;
uint32_t timerx_ch0_n_pin = GPIO_PIN_5;
uint32_t timerx_ch0_n_af = GPIO_AF_3;

uint32_t timerx_ch0_p_port = GPIOC;
uint32_t timerx_ch0_p_port_rcu = RCU_GPIOC;
uint32_t timerx_ch0_p_pin = GPIO_PIN_6;
uint32_t timerx_ch0_p_af = GPIO_AF_3;

// ch1
uint32_t timerx_ch1_n_port = GPIOB;
uint32_t timerx_ch1_n_port_rcu = RCU_GPIOB;
uint32_t timerx_ch1_n_pin = GPIO_PIN_14;
uint32_t timerx_ch1_n_af = GPIO_AF_3;

uint32_t timerx_ch1_p_port = GPIOC;
uint32_t timerx_ch1_p_port_rcu = RCU_GPIOC;
uint32_t timerx_ch1_p_pin = GPIO_PIN_7;
uint32_t timerx_ch1_p_af = GPIO_AF_3;

// ch2
uint32_t timerx_ch2_n_port = GPIOB;
uint32_t timerx_ch2_n_port_rcu = RCU_GPIOB;
uint32_t timerx_ch2_n_pin = GPIO_PIN_15;
uint32_t timerx_ch2_n_af = GPIO_AF_3;

uint32_t timerx_ch2_p_port = GPIOC;
uint32_t timerx_ch2_p_port_rcu = RCU_GPIOC;
uint32_t timerx_ch2_p_pin = GPIO_PIN_8;
uint32_t timerx_ch2_p_af = GPIO_AF_3;

/*************** GPIO config **************/
//// ch0
//// p
// 配置时钟
rcu_periph_clock_enable(timerx_ch0_p_port_rcu);
// 配置GPIO模式
gpio_mode_set(timerx_ch0_p_port, GPIO_MODE_AF, GPIO_PUPD_NONE, timerx_ch0_p_pin);
// 配置GPIO输出
gpio_output_options_set(timerx_ch0_p_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, timerx_ch0_p_pin);
// 配置复用功能
gpio_af_set(timerx_ch0_p_port, timerx_ch0_p_af, timerx_ch0_p_pin);
//// n
// 配置时钟
rcu_periph_clock_enable(timerx_ch0_n_port_rcu);
// 配置GPIO模式
gpio_mode_set(timerx_ch0_n_port, GPIO_MODE_AF, GPIO_PUPD_NONE, timerx_ch0_n_pin);
// 配置GPIO输出
gpio_output_options_set(timerx_ch0_n_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, timerx_ch0_n_pin);
// 配置复用功能
gpio_af_set(timerx_ch0_n_port, timerx_ch0_n_af, timerx_ch0_n_pin);

//// ch1
//// p
// 配置时钟
rcu_periph_clock_enable(timerx_ch1_p_port_rcu);
// 配置GPIO模式
gpio_mode_set(timerx_ch1_p_port, GPIO_MODE_AF, GPIO_PUPD_NONE, timerx_ch1_p_pin);
// 配置GPIO输出
gpio_output_options_set(timerx_ch1_p_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, timerx_ch1_p_pin);
// 配置复用功能
gpio_af_set(timerx_ch1_p_port, timerx_ch1_p_af, timerx_ch1_p_pin);
//// n
// 配置时钟
rcu_periph_clock_enable(timerx_ch1_n_port_rcu);
// 配置GPIO模式
gpio_mode_set(timerx_ch1_n_port, GPIO_MODE_AF, GPIO_PUPD_NONE, timerx_ch1_n_pin);
// 配置GPIO输出
gpio_output_options_set(timerx_ch1_n_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, timerx_ch1_n_pin);
// 配置复用功能
gpio_af_set(timerx_ch1_n_port, timerx_ch1_n_af, timerx_ch1_n_pin);

//// ch2
//// p
// 配置时钟
rcu_periph_clock_enable(timerx_ch2_p_port_rcu);
// 配置GPIO模式
gpio_mode_set(timerx_ch2_p_port, GPIO_MODE_AF, GPIO_PUPD_NONE, timerx_ch2_p_pin);
// 配置GPIO输出
gpio_output_options_set(timerx_ch2_p_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, timerx_ch2_p_pin);
// 配置复用功能
gpio_af_set(timerx_ch2_p_port, timerx_ch2_p_af, timerx_ch2_p_pin);
//// n
// 配置时钟
rcu_periph_clock_enable(timerx_ch2_n_port_rcu);
// 配置GPIO模式
gpio_mode_set(timerx_ch2_n_port, GPIO_MODE_AF, GPIO_PUPD_NONE, timerx_ch2_n_pin);
// 配置GPIO输出
gpio_output_options_set(timerx_ch2_n_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, timerx_ch2_n_pin);
// 配置复用功能
gpio_af_set(timerx_ch2_n_port, timerx_ch2_n_af, timerx_ch2_n_pin);

/*************** Timer config *************/
// 时钟配置
rcu_periph_clock_enable(timerx_rcu);
// 复位定时器
timer_deinit(timerx);
// 倍频配置
rcu_timer_clock_prescaler_config(timerx_psc);

// 初始化定时器
timer_parameter_struct tps;
timer_struct_para_init(&tps);
tps.prescaler = timerx_prescaler; // 分频计数
tps.period = timerx_period; // 周期计数
timer_init(timerx, &tps);

////////// 配置输出通道
timer_oc_parameter_struct tops;
///// ch0
timer_channel_output_struct_para_init(&tops);
// n config
tops.outputnstate = TIMER_CCXN_ENABLE;
tops.ocpolarity = TIMER_OC_POLARITY_LOW;
// p config
tops.outputstate = TIMER_CCX_ENABLE;
tops.ocpolarity = TIMER_OC_POLARITY_LOW;
timer_channel_output_config(timerx, TIMER_CH_0, &tops);

///// ch1
timer_channel_output_struct_para_init(&tops);
// n config
tops.outputnstate = TIMER_CCXN_ENABLE;
// p config
tops.outputstate = TIMER_CCX_ENABLE;
tops.ocpolarity = TIMER_OC_POLARITY_LOW;
timer_channel_output_config(timerx, TIMER_CH_1, &tops);

///// ch2
timer_channel_output_struct_para_init(&tops);
// n config
tops.outputnstate = TIMER_CCXN_ENABLE;
// p config
tops.outputstate = TIMER_CCX_ENABLE;
tops.ocpolarity = TIMER_OC_POLARITY_LOW;
timer_channel_output_config(timerx, TIMER_CH_2, &tops);


////////// 输出模式配置
// ch0
timer_channel_output_mode_config(timerx, TIMER_CH_0, TIMER_OC_MODE_PWM0);
// ch1
timer_channel_output_mode_config(timerx, TIMER_CH_1, TIMER_OC_MODE_PWM0);
// ch2
timer_channel_output_mode_config(timerx, TIMER_CH_2, TIMER_OC_MODE_PWM0);

////////// Break配置
timer_break_parameter_struct tbps;
timer_break_struct_para_init(&tbps);
tbps.breakpolarity = TIMER_BREAK_POLARITY_HIGH;
tbps.outputautostate = TIMER_OUTAUTO_ENABLE;
tbps.breakstate = TIMER_BREAK_ENABLE;
timer_break_config(timerx, &tbps);

// 初始化
timer_enable(timerx);
}

static void PWM_update_ch0(float duty) {
uint32_t timerx = TIMER7;
uint32_t timerx_chn = TIMER_CH_0;

uint32_t pulse = duty * (PERIOD + 1) / 100;
/***************** pwm update *******************/
// 配置输出的占空比
timer_channel_output_pulse_value_config(timerx, timerx_chn, pulse);
}

static void PWM_update_ch1(float duty) {
uint32_t timerx = TIMER7;
uint32_t timerx_chn = TIMER_CH_1;

uint32_t pulse = duty * (PERIOD + 1) / 100;
/***************** pwm update *******************/
// 配置输出的占空比
timer_channel_output_pulse_value_config(timerx, timerx_chn, pulse);
}

static void PWM_update_ch2(float duty) {
uint32_t timerx = TIMER7;
uint32_t timerx_chn = TIMER_CH_2;

uint32_t pulse = duty * (PERIOD + 1) / 100;
/***************** pwm update *******************/
// 配置输出的占空比
timer_channel_output_pulse_value_config(timerx, timerx_chn, pulse);
}

static void GPIO_config() {
// 配置时钟
rcu_periph_clock_enable(RCU_GPIOA);
// 配置GPIO模式
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);
// 配置GPIO输出
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_3);
}

int main(void)
{
systick_config();
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
Usart0_init();
GPIO_config();
PWM_config();

gpio_bit_reset(GPIOA, GPIO_PIN_3);

int8_t i;
while(1) {
for(i = 0; i < 25; i++) {
PWM_update_ch0(i);
PWM_update_ch1(i);
PWM_update_ch2(i);
delay_1ms(50);
}
for(i = 24; i >= 0; i--) {
PWM_update_ch0(i);
PWM_update_ch1(i);
PWM_update_ch2(i);
delay_1ms(50);
}

delay_1ms(1000);
}
}

DMA

内存到内存

固定地址
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
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "Usart0.h"

#define ARR_LEN 1024
char src[ARR_LEN] = "hello\0";
char dst[ARR_LEN] = {0};


void Usart0_recv(uint8_t* data, uint32_t len) {
printf("recv: %s\r\n", data);

dma_channel_enable(DMA1, DMA_CH0);
while(RESET == dma_flag_get(DMA1, DMA_CH0, DMA_FLAG_FTF));
dma_flag_clear(DMA1, DMA_CH0, DMA_FLAG_FTF);

printf("dst: %s\n", dst);
}

static void DMA_config() {

/***************** DMA m2m *******************/
// 时钟
rcu_periph_clock_enable(RCU_DMA1);
// 重置dma
dma_deinit(DMA1, DMA_CH0);

//////// dma 配置
dma_single_data_parameter_struct dsdps;
dma_single_data_para_struct_init(&dsdps);
// 方向
dsdps.direction = DMA_MEMORY_TO_MEMORY;
// 内存
dsdps.memory0_addr = (uint32_t)dst;
dsdps.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
// 外设
dsdps.periph_addr = (uint32_t)src;
dsdps.periph_inc = DMA_PERIPH_INCREASE_ENABLE;
// 数据长度
dsdps.number = ARR_LEN;
// 数据宽度
dsdps.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
dma_single_data_mode_init(DMA1, DMA_CH0, &dsdps);

// // 中断配置
// nvic_irq_enable(DMA1_Channel0_IRQn, 2, 2);
// // 中断使能
// dma_interrupt_enable(DMA1, DMA_CH0, DMA_CHXCTL_FTFIE);
// // 开启DMA通道
// dma_channel_enable(DMA1, DMA_CH0);
}

//void DMA1_Channel0_IRQHandler() {
// // 判断中断标记
// if(SET == dma_interrupt_flag_get(DMA1, DMA_CH0, DMA_INT_FLAG_FTF)) {
// printf("dst: %s\n", dst);
// }
// // 清理标记位
// dma_interrupt_flag_clear(DMA1, DMA_CH0, DMA_INT_FLAG_FTF);
//}


int main(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
systick_config();
Usart0_init();

DMA_config();

while(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
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "Usart0.h"

#define ARR_LEN 1024
char dst[ARR_LEN] = {0};


void Usart0_recv(uint8_t* data, uint32_t len) {
printf("recv: %s\r\n", data);

dma_periph_address_config(DMA1, DMA_CH0,(uint32_t)data);
dma_transfer_number_config(DMA1, DMA_CH0, len);

dma_channel_enable(DMA1, DMA_CH0);
while(RESET == dma_flag_get(DMA1, DMA_CH0, DMA_FLAG_FTF));
dma_flag_clear(DMA1, DMA_CH0, DMA_FLAG_FTF);

dst[len] = '\0';
printf("dst: %s\n", dst);
}

static void DMA_config() {

uint32_t dmax = DMA1;
uint32_t dmax_rcu = RCU_DMA1;
uint32_t dmax_ch = DMA_CH0;

uint32_t dmax_dirction = DMA_MEMORY_TO_MEMORY;

//uint32_t dmax_src = (uint32_t)src;
uint32_t dmax_src_inc = DMA_PERIPH_INCREASE_ENABLE;
uint32_t dmax_src_width = DMA_PERIPH_WIDTH_8BIT;
//uint32_t dmax_src_len = ARR_LEN;

uint32_t dmax_dst = (uint32_t)dst;
uint32_t dmax_dst_inc = DMA_MEMORY_INCREASE_ENABLE;
/***************** DMA m2m *******************/
// 时钟
rcu_periph_clock_enable(dmax_rcu);
// 重置dma
dma_deinit(dmax, dmax_ch);

//////// dma 配置
dma_single_data_parameter_struct dsdps;
dma_single_data_para_struct_init(&dsdps);
// 方向
dsdps.direction = dmax_dirction;
// 内存
dsdps.memory0_addr = dmax_dst;
dsdps.memory_inc = dmax_dst_inc;
// 外设
//dsdps.periph_addr = dmax_src;
dsdps.periph_inc = dmax_src_inc;
// 数据长度
//dsdps.number = dmax_src_len;
// 数据宽度
dsdps.periph_memory_width = dmax_src_width;
dma_single_data_mode_init(dmax, dmax_ch, &dsdps);
}


int main(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
systick_config();
Usart0_init();

DMA_config();

while(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
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>
#include "main.h"

static void DMA_config() {
/***************** DMA m2p *******************/
// 时钟
rcu_periph_clock_enable(RCU_DMA1);
// 重置dma
dma_deinit(DMA1, DMA_CH7);

//////// dma 配置
dma_single_data_parameter_struct dsdps;
dma_single_data_para_struct_init(&dsdps);
// 方向
dsdps.direction = DMA_MEMORY_TO_PERIPH;
// 内存: src
// dsdps.memory0_addr = (uint32_t)src;
dsdps.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
// 外设: dst
dsdps.periph_addr = (uint32_t)(&USART_DATA(USART0));
dsdps.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
// // 数据长度
// dsdps.number = ARR_LEN;
// dst数据宽度
dsdps.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
// 传输优先级
dsdps.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_single_data_mode_init(DMA1, DMA_CH7, &dsdps);

//////// 配置 dma 子连接
dma_channel_subperipheral_select(DMA1, DMA_CH7, DMA_SUBPERI4);
}

static void dma_send_byte(uint8_t data) {
// 数据来源 和 长度
dma_memory_address_config(DMA1, DMA_CH7, DMA_MEMORY_0, (uint32_t)(&data));
dma_transfer_number_config(DMA1, DMA_CH7, 1);

// 触发传输
dma_channel_enable(DMA1, DMA_CH7);

// 等待DMA传输完成
while(RESET == dma_flag_get(DMA1, DMA_CH7, DMA_FLAG_FTF));
// 清理标记
dma_flag_clear(DMA1, DMA_CH7, DMA_FLAG_FTF);
}

static void dma_send(uint8_t* data, uint32_t len) {
// 数据来源 和 长度
dma_memory_address_config(DMA1, DMA_CH7, DMA_MEMORY_0, (uint32_t)(&data));
dma_transfer_number_config(DMA1, DMA_CH7, len);

// 触发传输
dma_channel_enable(DMA1, DMA_CH7);

// 等待DMA传输完成
while(RESET == dma_flag_get(DMA1, DMA_CH7, DMA_FLAG_FTF));
// 清理标记
dma_flag_clear(DMA1, DMA_CH7, DMA_FLAG_FTF);
}

static void dma_send_string(const char* str) {
dma_send((uint8_t*)str, strlen(str));
}

static void Usart_config() {
// 哪个串口
uint32_t usartx = USART0;
uint32_t usartx_rcu = RCU_USART0;
uint32_t usartx_irq = USART0_IRQn;

// 波特率
uint32_t usartx_p_baudrate = 115200;

// tx和rx,用了哪个引脚
uint32_t usartx_tx_port_rcu = RCU_GPIOA;
uint32_t usartx_tx_port = GPIOA;
uint32_t usartx_tx_pin = GPIO_PIN_9;
// 复用功能编号
uint32_t usartx_tx_af = GPIO_AF_7;

// tx和rx,用了哪个引脚
uint32_t usartx_rx_port_rcu = RCU_GPIOA;
uint32_t usartx_rx_port = GPIOA;
uint32_t usartx_rx_pin = GPIO_PIN_10;
// 复用功能编号
uint32_t usartx_rx_af = GPIO_AF_7;


/*************** gpio *****************/
// TX
// 配置时钟
rcu_periph_clock_enable(usartx_tx_port_rcu);
// 配置模式: 复用功能
gpio_mode_set(usartx_tx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_tx_pin);
// 配置复用功能
gpio_af_set(usartx_tx_port, usartx_tx_af, usartx_tx_pin);
gpio_output_options_set(usartx_tx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_tx_pin);

// RX
// 配置时钟
rcu_periph_clock_enable(usartx_rx_port_rcu);
gpio_mode_set(usartx_rx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_rx_pin);
gpio_af_set(usartx_rx_port, usartx_rx_af, usartx_rx_pin);
// 配置输出参数
gpio_output_options_set(usartx_rx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_rx_pin);

/*************** usart ****************/
// 串口时钟
rcu_periph_clock_enable(usartx_rcu);
// USART复位
usart_deinit(usartx);

// 波特率
usart_baudrate_set(usartx, usartx_p_baudrate);
// 校验位
usart_parity_config(usartx, USART_PM_NONE);
// 数据位数
usart_word_length_set(usartx, USART_WL_8BIT);
// 停止位
usart_stop_bit_set(usartx, USART_STB_1BIT);
// 先发送高位还是低位
usart_data_first_config(usartx, USART_MSBF_LSB);

// 发送功能配置
usart_transmit_config(usartx, USART_TRANSMIT_ENABLE);

// 接收功能配置
usart_receive_config(usartx, USART_RECEIVE_ENABLE);
// 接收中断配置
nvic_irq_enable(usartx_irq, 2, 2);
usart_interrupt_enable(usartx, USART_INT_RBNE);
usart_interrupt_enable(usartx, USART_INT_IDLE);

// DMA发送功能配置
usart_dma_transmit_config(usartx, USART_TRANSMIT_DMA_ENABLE);

// 使能串口
usart_enable(usartx);
}

static void send_byte(uint8_t data) {
//通过USART发送
usart_data_transmit(USART0, data);

//判断缓冲区是否已经空了
//FlagStatus state = usart_flag_get(USART_NUM,USART_FLAG_TBE);
while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
}

static void send_string(char* data) {
while(data && *data){
send_byte((uint8_t)(*data));
data++;
}
}

int fputc(int ch, FILE *f){
send_byte((uint8_t)ch);
return ch;
}

int main(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
systick_config();
Usart_config();

DMA_config();

uint8_t cnt = 0;
while(1) {
// dma_send_byte(cnt++);
printf("hello %d\r\n", cnt++);
delay_1ms(1000);
}
}

外设到内存

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
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>
#include "main.h"


void Usart0_recv(uint8_t* data, uint32_t len) {
printf("recv: %s\r\n", data);
}

static void DMA_tx_config() {
uint32_t dmax = DMA1;
uint32_t dmax_rcu = RCU_DMA1;
uint32_t dmax_ch = DMA_CH7;
uint32_t damx_sub = DMA_SUBPERI4;

uint32_t dmax_dirction = DMA_MEMORY_TO_PERIPH;

// uint32_t dmax_src = (uint32_t)src;
uint32_t dmax_src_inc = DMA_MEMORY_INCREASE_ENABLE;
uint32_t dmax_src_width = DMA_MEMORY_WIDTH_8BIT;
// uint32_t dmax_src_len = ARR_LEN;

uint32_t dmax_dst = (uint32_t)(&USART_DATA(USART0));
uint32_t dmax_dst_inc = DMA_PERIPH_INCREASE_DISABLE;

/***************** DMA m2p *******************/
// 时钟
rcu_periph_clock_enable(dmax_rcu);
// 重置dma
dma_deinit(dmax, dmax_ch);

//////// dma 配置
dma_single_data_parameter_struct dsdps;
dma_single_data_para_struct_init(&dsdps);
// 方向
dsdps.direction = dmax_dirction;
// 内存: src
// dsdps.memory0_addr = (uint32_t)src;
dsdps.memory_inc = dmax_src_inc;
// 外设: dst
dsdps.periph_addr = dmax_dst;
dsdps.periph_inc = dmax_dst_inc;
// // 数据长度
// dsdps.number = ARR_LEN;
// 数据宽度
dsdps.periph_memory_width = dmax_src_width;
// 传输优先级
dsdps.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_single_data_mode_init(dmax, dmax_ch, &dsdps);

//////// 配置 dma 子连接
dma_channel_subperipheral_select(dmax, dmax_ch, damx_sub);
}

static void dma_send_byte(uint8_t data) {
// 数据来源 和 长度
dma_memory_address_config(DMA1, DMA_CH7, DMA_MEMORY_0, (uint32_t)(&data));
dma_transfer_number_config(DMA1, DMA_CH7, 1);

// 触发传输
dma_channel_enable(DMA1, DMA_CH7);

// 等待DMA传输完成
while(RESET == dma_flag_get(DMA1, DMA_CH7, DMA_FLAG_FTF));
// 清理标记
dma_flag_clear(DMA1, DMA_CH7, DMA_FLAG_FTF);
}

static void dma_send(uint8_t* data, uint32_t len) {
// 数据来源 和 长度
dma_memory_address_config(DMA1, DMA_CH7, DMA_MEMORY_0, (uint32_t)(&data));
dma_transfer_number_config(DMA1, DMA_CH7, len);

// 触发传输
dma_channel_enable(DMA1, DMA_CH7);

// 等待DMA传输完成
while(RESET == dma_flag_get(DMA1, DMA_CH7, DMA_FLAG_FTF));
// 清理标记
dma_flag_clear(DMA1, DMA_CH7, DMA_FLAG_FTF);
}

static void dma_send_string(const char* str) {
dma_send((uint8_t*)str, strlen(str));
}

static void Usart_config() {
// 哪个串口
uint32_t usartx = USART0;
uint32_t usartx_rcu = RCU_USART0;
uint32_t usartx_irq = USART0_IRQn;

// 波特率
uint32_t usartx_p_baudrate = 115200;

// tx和rx,用了哪个引脚
uint32_t usartx_tx_port_rcu = RCU_GPIOA;
uint32_t usartx_tx_port = GPIOA;
uint32_t usartx_tx_pin = GPIO_PIN_9;
// 复用功能编号
uint32_t usartx_tx_af = GPIO_AF_7;

// tx和rx,用了哪个引脚
uint32_t usartx_rx_port_rcu = RCU_GPIOA;
uint32_t usartx_rx_port = GPIOA;
uint32_t usartx_rx_pin = GPIO_PIN_10;
// 复用功能编号
uint32_t usartx_rx_af = GPIO_AF_7;


/*************** gpio *****************/
// TX
// 配置时钟
rcu_periph_clock_enable(usartx_tx_port_rcu);
// 配置模式: 复用功能
gpio_mode_set(usartx_tx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_tx_pin);
// 配置复用功能
gpio_af_set(usartx_tx_port, usartx_tx_af, usartx_tx_pin);
gpio_output_options_set(usartx_tx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_tx_pin);

// RX
// 配置时钟
rcu_periph_clock_enable(usartx_rx_port_rcu);
gpio_mode_set(usartx_rx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_rx_pin);
gpio_af_set(usartx_rx_port, usartx_rx_af, usartx_rx_pin);
// 配置输出参数
gpio_output_options_set(usartx_rx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_rx_pin);

/*************** usart ****************/
// 串口时钟
rcu_periph_clock_enable(usartx_rcu);
// USART复位
usart_deinit(usartx);

// 波特率
usart_baudrate_set(usartx, usartx_p_baudrate);
// 校验位
usart_parity_config(usartx, USART_PM_NONE);
// 数据位数
usart_word_length_set(usartx, USART_WL_8BIT);
// 停止位
usart_stop_bit_set(usartx, USART_STB_1BIT);
// 先发送高位还是低位
usart_data_first_config(usartx, USART_MSBF_LSB);

// 发送功能配置
usart_transmit_config(usartx, USART_TRANSMIT_ENABLE);

// 接收功能配置
usart_receive_config(usartx, USART_RECEIVE_ENABLE);
// 接收中断配置
nvic_irq_enable(usartx_irq, 2, 2);
usart_interrupt_enable(usartx, USART_INT_RBNE);
usart_interrupt_enable(usartx, USART_INT_IDLE);

// DMA发送功能配置
usart_dma_transmit_config(usartx, USART_TRANSMIT_DMA_ENABLE);
// DMA接收功能配置
usart_dma_receive_config(usartx, USART_RECEIVE_DMA_ENABLE);

// 使能串口
usart_enable(usartx);
}

static void send_byte(uint8_t data) {
//通过USART发送
usart_data_transmit(USART0, data);

//判断缓冲区是否已经空了
//FlagStatus state = usart_flag_get(USART_NUM,USART_FLAG_TBE);
while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
}

static void send_string(char* data) {
while(data && *data) {
send_byte((uint8_t)(*data));
data++;
}
}

int fputc(int ch, FILE *f) {
send_byte((uint8_t)ch);
return ch;
}

#define USART_RECEIVE_LENGTH 1024
//串口接收缓冲区大小
uint8_t g_recv_buff[USART_RECEIVE_LENGTH]; // 接收缓冲区
//接收到字符存放的位置
uint32_t g_recv_length = 0;

void USART0_IRQHandler(void) {
if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE) == SET) {
//读取缓冲区,清空缓冲区
usart_data_receive(USART0);

// 停止DMA传输,防止数据污染
dma_channel_disable(DMA1, DMA_CH5);

// 计算接收的数据长度
g_recv_length = USART_RECEIVE_LENGTH - dma_transfer_number_get(DMA1, DMA_CH5);
if(g_recv_length) {
g_recv_buff[g_recv_length] = '\0';
// TODO: g_recv_buff为接收的数据,g_recv_length为接收的长度
printf("rcv: %s\r\n", g_recv_buff);
}

g_recv_length = 0;
dma_flag_clear(DMA1, DMA_CH5, DMA_FLAG_FTF);
dma_channel_enable(DMA1, DMA_CH5);
}
}

static void DMA_rx_config() {
/**************** DMA p2m *******************/
// 时钟
rcu_periph_clock_enable(RCU_DMA1);
// 重置dma
dma_deinit(DMA1, DMA_CH5);

//////// dma 配置
dma_single_data_parameter_struct dsdps;
dma_single_data_para_struct_init(&dsdps);
// 方向
dsdps.direction = DMA_PERIPH_TO_MEMORY;
// 内存: dst
dsdps.memory0_addr = (uint32_t)(g_recv_buff);
dsdps.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
// 外设: src
dsdps.periph_addr = (uint32_t)(&USART_DATA(USART0));
dsdps.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
// 数据长度
dsdps.number = USART_RECEIVE_LENGTH;
// dst数据宽度
dsdps.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
// 传输优先级
dsdps.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_single_data_mode_init(DMA1, DMA_CH5, &dsdps);

//////// 配置 dma 子连接
dma_channel_subperipheral_select(DMA1, DMA_CH5, DMA_SUBPERI4);


// 默认开启接收
dma_flag_clear(DMA1, DMA_CH5, DMA_FLAG_FTF);
dma_channel_enable(DMA1, DMA_CH5);

}

int main(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
systick_config();
Usart_config();

DMA_tx_config();
DMA_rx_config();

uint8_t cnt = 0;
while(1) {
// dma_send_byte(cnt++);
//printf("hello %d\r\n", cnt++);
delay_1ms(1000);
}
}

RTC

RTC时钟

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
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "Usart.h"

// 十位取出左移4位 + 个位 (得到BCD数)
#define WRITE_BCD(val) ((val / 10) << 4) + (val % 10)
// 将高4位乘以10 + 低四位 (得到10进制数)
#define READ_BCD(val) (val >> 4) * 10 + (val & 0x0F)

void Usart0_recv(uint8_t *data, uint32_t len) {
printf("%s\r\n", data);
}

static void RTC_config() {
// 电池管理加载
rcu_periph_clock_enable(RCU_PMU);
pmu_backup_write_enable();
// 晶振加载
rcu_osci_on(RCU_LXTAL);
rcu_osci_stab_wait(RCU_LXTAL);
rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
// RTC功能加载
rcu_periph_clock_enable(RCU_RTC);
rtc_register_sync_wait();

rtc_parameter_struct rps;
rps.year = WRITE_BCD(23);
rps.month = WRITE_BCD(4);
rps.date = WRITE_BCD(20);
rps.day_of_week = WRITE_BCD(4);
rps.hour = WRITE_BCD(23);
rps.minute = WRITE_BCD(59);
rps.second = WRITE_BCD(55);
rps.display_format = RTC_24HOUR;
rps.am_pm = RTC_AM;
rps.factor_asyn = 0x7F;
rps.factor_syn = 0xFF;

rtc_init(&rps);
}

static void RTC_read() {
rtc_parameter_struct rps;
rtc_current_time_get(&rps);

uint16_t year = READ_BCD(rps.year) + 2000;
uint8_t month = READ_BCD(rps.month);
uint8_t date = READ_BCD(rps.date);
uint8_t week = READ_BCD(rps.day_of_week);
uint8_t hour = READ_BCD(rps.hour);
uint8_t minute = READ_BCD(rps.minute);
uint8_t second = READ_BCD(rps.second);

printf("%d-%d-%d %d %d:%d:%d\r\n", year, month, date, week, hour, minute, second);
}

int main(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
systick_config();
Usart0_init();

RTC_config();

while(1) {
RTC_read();

delay_1ms(1000);
}
}

RTC闹钟

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
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "Usart.h"

// 十位取出左移4位 + 个位 (得到BCD数)
#define WRITE_BCD(val) ((val / 10) << 4) + (val % 10)
// 将高4位乘以10 + 低四位 (得到10进制数)
#define READ_BCD(val) (val >> 4) * 10 + (val & 0x0F)


void Usart0_recv(uint8_t *data, uint32_t len) {
printf("%s\r\n", data);
}


static void RTC_config() {
// 电池管理加载
rcu_periph_clock_enable(RCU_PMU);
pmu_backup_write_enable();
// 晶振加载
rcu_osci_on(RCU_LXTAL);
rcu_osci_stab_wait(RCU_LXTAL);
rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
// RTC功能加载
rcu_periph_clock_enable(RCU_RTC);
rtc_register_sync_wait();

rtc_parameter_struct rps;
rps.year = WRITE_BCD(23);
rps.month = WRITE_BCD(04);
rps.date = WRITE_BCD(20);
rps.day_of_week = WRITE_BCD(04);
rps.hour = WRITE_BCD(23);
rps.minute = WRITE_BCD(59);
rps.second = WRITE_BCD(55);
rps.display_format = RTC_24HOUR;
rps.am_pm = RTC_AM;
rps.factor_asyn = 0x7F;
rps.factor_syn = 0xFF;

rtc_init(&rps);
}

static void RTC_read() {
rtc_parameter_struct rps;
rtc_current_time_get(&rps);

uint16_t year = READ_BCD(rps.year) + 2000;
uint8_t month = READ_BCD(rps.month);
uint8_t date = READ_BCD(rps.date);
uint8_t week = READ_BCD(rps.day_of_week);
uint8_t hour = READ_BCD(rps.hour);
uint8_t minute = READ_BCD(rps.minute);
uint8_t second = READ_BCD(rps.second);

printf("%d-%d-%d %d %d:%d:%d\r\n", year, month, date, week, hour, minute, second);
}

static void ALARM_config() {
// 闹钟外部中断
exti_flag_clear(EXTI_17);
exti_init(EXTI_17,EXTI_INTERRUPT,EXTI_TRIG_RISING);

// 重置闹钟
rtc_alarm_disable(RTC_ALARM0);

rtc_alarm_struct ras;
ras.alarm_mask = RTC_ALARM_HOUR_MASK | RTC_ALARM_MINUTE_MASK | RTC_ALARM_SECOND_MASK;
ras.weekday_or_date = RTC_ALARM_DATE_SELECTED;
ras.alarm_day = 0x21;
ras.alarm_hour = WRITE_BCD(23);
ras.alarm_minute = WRITE_BCD(59);
ras.alarm_second = WRITE_BCD(59);
ras.am_pm = RTC_AM;
rtc_alarm_config(RTC_ALARM0, &ras);

// 中断配置
nvic_irq_enable(RTC_Alarm_IRQn, 2, 2);
rtc_interrupt_enable(RTC_INT_ALARM0);
rtc_flag_clear(RTC_FLAG_ALRM0);

rtc_alarm_enable(RTC_ALARM0);
}

void RTC_Alarm_IRQHandler() {
if (SET == rtc_flag_get(RTC_FLAG_ALRM0)) {
// 处理RTC闹钟中断
printf("alarm \r\n");
}
rtc_flag_clear(RTC_FLAG_ALRM0);
exti_flag_clear(EXTI_17);
}


int main(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
systick_config();
Usart0_init();

RTC_config();
ALARM_config();

while(1) {
RTC_read();

delay_1ms(1000);
}
}

I2C

I2C0.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifndef __I2C0_H__
#define __I2C0_H__

#include "systick.h"
#include "gd32f4xx.h"

void I2C0_init();

uint8_t I2C0_read(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len);

uint8_t I2C0_write(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len);

uint8_t I2C0_write2(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t offset, uint32_t len);

void I2C0_deinit();

#endif

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

void I2C0_init() {
uint32_t i2cx_scl_port_rcu = RCU_GPIOB;
uint32_t i2cx_scl_port = GPIOB;
uint32_t i2cx_scl_pin = GPIO_PIN_6;
uint32_t i2cx_scl_af = GPIO_AF_4;

uint32_t i2cx_sda_port_rcu = RCU_GPIOB;
uint32_t i2cx_sda_port = GPIOB;
uint32_t i2cx_sda_pin = GPIO_PIN_7;
uint32_t i2cx_sda_af = GPIO_AF_4;

uint32_t i2cx = I2C0;
uint32_t i2cx_rcu = RCU_I2C0;
uint32_t i2cx_speed = 400000;
/****************** GPIO config **********************/
// 时钟配置
rcu_periph_clock_enable(i2cx_scl_port_rcu);
// 设置复用功能
gpio_af_set(i2cx_scl_port, i2cx_scl_af, i2cx_scl_pin);
// 设置输出模式
gpio_mode_set(i2cx_scl_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_scl_pin);
gpio_output_options_set(i2cx_scl_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_scl_pin);

// 时钟配置
rcu_periph_clock_enable(i2cx_sda_port_rcu);
// 设置复用功能
gpio_af_set(i2cx_sda_port, i2cx_sda_af, i2cx_sda_pin);
// 设置输出模式
gpio_mode_set(i2cx_sda_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_sda_pin);
gpio_output_options_set(i2cx_sda_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_sda_pin);

/****************** I2C config **********************/
i2c_deinit(i2cx);
// 时钟配置
rcu_periph_clock_enable(i2cx_rcu);
// I2C速率配置
i2c_clock_config(i2cx, i2cx_speed, I2C_DTCY_2);

// 使能i2c
i2c_mode_addr_config(i2cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00);
i2c_enable(i2cx);

// i2c ack enable
i2c_ack_config(i2cx, I2C_ACK_ENABLE);
//i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);

}

static uint8_t I2C_wait(uint32_t i2cx, uint32_t flag) {
uint16_t TIMEOUT = 50000;
uint16_t cnt = 0;

while(!i2c_flag_get(i2cx, flag)) {
cnt++;
if(cnt > TIMEOUT) return 1;
}
return 0;
}

static uint8_t I2C_waitn(uint32_t i2cx, uint32_t flag) {
uint16_t TIMEOUT = 50000;
uint16_t cnt = 0;

while(i2c_flag_get(i2cx, flag)) {
cnt++;
if(cnt > TIMEOUT) return 1;
}
return 0;
}


uint8_t I2C0_write(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t data_len) {
uint32_t i2cx = I2C0;
uint8_t address = addr << 1;

/************* start ***********************/
// 等待I2C闲置
if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;

// start
i2c_start_on_bus(i2cx);

// 等待I2C主设备成功发送起始信号
if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;

/************* device address **************/
// 发送设备地址
i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
// 等待地址发送完成
if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);

/************ register address ************/
// 寄存器地址
// 等待发送数据缓冲区为空
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;

// 发送数据
i2c_data_transmit(i2cx, reg);

// 等待数据发送完成
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;

/***************** data ******************/
// 发送数据
uint32_t i;
for(i = 0; i < data_len; i++) {
uint32_t d = data[i];

// 等待发送数据缓冲区为空
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;

// 发送数据
i2c_data_transmit(i2cx, d);

// 等待数据发送完成
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 7;
}

/***************** stop ********************/
// stop
i2c_stop_on_bus(i2cx);
if(I2C_waitn(i2cx, I2C_CTL0(I2C0)&I2C_CTL0_STOP)) return 8;

return 0;
}

uint8_t I2C0_write2(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t offset, uint32_t len) {
uint32_t i2cx = I2C0;
uint8_t address = addr << 1;

/************* start ***********************/
// 等待I2C闲置
if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;

// start
i2c_start_on_bus(i2cx);

// 等待I2C主设备成功发送起始信号
if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;

/************* device address **************/
// 发送设备地址
i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
// 等待地址发送完成
if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);

/************ register address ************/
// 寄存器地址
// 等待发送数据缓冲区为空
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;

// 发送数据
i2c_data_transmit(i2cx, reg);

// 等待数据发送完成
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;

/***************** data ******************/
// 发送数据
do {
// 等待发送数据缓冲区为空
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;

// 发送数据
i2c_data_transmit(i2cx, *data);
data += offset;

// 等待数据发送完成
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 7;
} while(--len);

/***************** stop ********************/
// stop
i2c_stop_on_bus(i2cx);
if(I2C_waitn(i2cx, I2C_CTL0(I2C0)&I2C_CTL0_STOP)) return 8;

return 0;
}


void I2C0_deinit() {

}


uint8_t I2C0_read(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len) {
uint32_t i2cx = I2C0;
uint8_t address = addr << 1;

/************* start ***********************/
// 等待I2C空闲
if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;

// 发送启动信号
i2c_start_on_bus(i2cx);
if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;

/************* device address **************/
// 发送从设备地址
i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);

// //ack
// i2c_ack_config(i2cx, I2C_ACK_ENABLE);
// i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
// if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 11;
// // i2c_ack_config(i2cx, I2C_ACK_DISABLE);

if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);

/********** register address **************/
// 等待发送缓冲区
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;

// 发送寄存器地址
i2c_data_transmit(i2cx, reg);

// 等待发送数据完成
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;

/************* start ***********************/
// 发送再启动信号
i2c_start_on_bus(i2cx);


if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 7;

/************* device address **************/
// 发送从设备地址
i2c_master_addressing(i2cx, address, I2C_RECEIVER);
if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 8;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);


/************* data **************/
//ack
i2c_ack_config(i2cx, I2C_ACK_ENABLE);
i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 23;

// 读取数据
uint8_t i;
for (i = 0; i < len; i++) {
if(i != len - 1) {
// 等待ACK发送完成
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 9;
}

// 等待ACK数据发送完成
// 等待接收缓冲区
if(I2C_wait(i2cx, I2C_FLAG_RBNE)) return 10;
data[i] = i2c_data_receive(i2cx);

if (i == len - 1) {
// 在读取最后一个字节之前,禁用ACK,并发送停止信号
// 配置自动NACK
//i2c_ackpos_config(i2cx, I2C_ACKPOS_NEXT);
//if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 9;
i2c_ack_config(i2cx, I2C_ACK_DISABLE);
}
}

/***************** stop ********************/
i2c_stop_on_bus(i2cx);
if(I2C_waitn(i2cx, I2C_CTL0(I2C0) & I2C_CTL0_STOP)) return 11;
return 0;
}