一、 拆箱及硬件
熟悉特性和时序:
先熟悉一下这个器件的一些特性和时序。
数据格式
时序图
从时序图来看,只需要先把PC9拉高然后拉低大于18ms然后再拉高,激活模块,就可以等待模块相应低电平,在等待响应高电平,就可以接收40bit数据。然后再拉高PC9引脚就可以读取到湿度和温度数据。
学习一个新的东西的最快方式是看他的使用示例,并且驱动起来
没有USB转串口的模块,这意味着,想要使用串口调试,必须外接一个转串口工具。用以前项目开发用过的CH340,该芯片有5个引脚,2个VCC(5V/3.3V),1个GND,1个RXD,1个TXD。
它和F427的接线方法如下:
CH340 F427
VCC3.3 ------> VCC3.3
GND ------> GND
TXD ------> RXD(PB7)
RXD -------> TXD(PB6)
CH340一端接F427,一端通过USB口接电脑,同时F427也通过USB供电。如图所示:
二、 环境配置
(1)Keil安装
建议安装高版本的,5.3以上的,我用的5.37的。需要安装包的可以加我QQ 984719097
(2)安装芯片pack包
pack包可以从https://aijishu.com/a/1060000000356925下载,选第8个选项 GD32F4xx AddOn中的 GigaDevice.GD32F4xx \_DFP.3.0.0.pack ,如下图所示:
下载到本地直接安装即可。
(3)demo程序下载
首先将demo下载下来,然后按此路径打开:\GD32F4xx\_Demo\_Suites\_V2.6.1\GD32427V\_START\_Demo\_Suites\Projects 可以看到F427V\_START有6个demo,先将第一个demo下载到板子上。
下载前注意事项:
demo中的代码是keil4编写的,因此,想要让demo能下载,建议参考【GD32F427开发板试用】+demo的正确打开方式(一),转换成keil5,再配置下GDlink,即可点击下载。
(4)创建project
demo程序下载后,验证了开发板的基础功能,接下来就是创建自己的project。
首先,keil5点创建项目,再选择芯片:
接着引入文件,第一次创建project,使用官方的固件库和demo内的文件完成project的搭建:
固件库需要用到的目录有:
接着开始创建,参照如下顺序:
首先点击1所在的图标,然后点击2修改project name,接着点击3按钮,新增代码目录。将代码设计成4个目录:
- APP(应用目录)
- BSP(板级别文件的目录)
- FMW\_CORE(内核相关文件目录)
- FMW\_PERI(外设相关文件目录)
创建完代码目录,向每个目录中添加对应的文件。
此项目参照固件库中的GPIO的例程,如下所示:
例程中的文件包括了应用文件和板级别文件,应用文件main.c添加到APP目录,其余板级文件添加到BSP。
除了这些文件外,还要去utilities中添加F427的头文件,但此目录下,只有f450的文件,如下所示:
因此,可以去demo的utilities中添加F427的文件,如下图所示:
接着添加 FMW\_CORE内核相关文件目录,在固件库Firmware\CMSIS\GD\GD32F4xx\添加内核文件和.s汇编启动文件,在Firmware\GD32F4xx\_standard\_peripheral添加此project涉及的外设,如uart,gpio,exit等。如下图所示:
创建完project:
接着开始编译,报了一些错误,找不到头文件,因此需要对project做一些配置:在C/C++处设置头文件路径,如下所示:
将BSP,内核,外设的头文件路径都包含进来。
Keil5目前使用的Compiler6,要用编译器5来编译。因此,需要安装编译器5,编译器5的安装文件,可以去嵌入式小学生公众号,回复ARMCC即可获得,下载后直接安装,在project配置中就会出现2个编译器,如图所示:
用编译器5,此project正常编过。
三、 移植及体征参数测试
以前项目做过体征参数测试,这次简单移植,并做体温、心率、心电、舒张压收缩压及血氧饱和度六中数据,分别对应对应了四种传感器设备,即温度传感器、心电模块、气压传感器、SpO²模块。
原系统基于STM32
使用传感器型号
传感器使用
| 功能监测 | 型号 |
| 血氧、心率 | MAX86174A |
| 心电 | ECG,AD8232 |
| 呼吸 | MAX30001 |
| 体温 | 10k NTC热敏电阻 |
| 血压 | XGZP6847 |
| 加速度 | ADXL345BCCZ-RL7 |
数据流程
需要多路ADC偶同时采样传输,开启浮点运算,进行ADC1采样四路传感器,使用DMA1将数据搬运至内存,并串口打印显示。
此处参考Hello\_eQN7e7的配置分享。https://aijishu.com/a/1060000000375869
- 使用keil进行浮点运算开启 如图所示开启即可:
- 检查文件中关于FPU寄存器配置是否高亮 如图所示即可:
硬件配置: - ADC硬件查询:通过相应数据手册查询可得PC1 PC2 PC3 PC4分别对应ADC的通道11 通道12 通道13 通道14,基于此信息将此三个引脚作为模拟引脚进行采样数据,数据手册信息如下所示:
- DMA硬件查询:通过GDF4的用户手册得知DMA的通道2 通道3对应ADC1 这里选择通道3作为ADC1传输数据的通道 外设请求通道信息如下所示:
ADC软件编写 - ADC四路引脚初始化:
- ADC各参数初始化:
- 总体初始化函数:
DMA软件编写 - DMA基本参数初始化:
- DMA通道参数初始化:
- DMA数据简单处理打印:
打印采集数据
下面采集各传感器的ADC值
/ _阅读采集自心率传感器的ADC值_ /
static void Ps\_ReadSampleValueFromAdc(void)
{
rt_uint32_t value;
/* 读取采样值 */
value = Adc_ChSample(ADC_CHANNEL_1);
/* 转换采集到的ADC值的精度为10bits */
Signal = value>>2;
}
其他三种传感器采集类似。
多种传感器信息融合:
借助paddlepaddle环境移植信息已训练好的融合算法模型进行预测:
import argparse
import os
import paddle
from paddleseg.cvlibs import manager, Config
from paddleseg.utils import get\_sys\_env, logger, config\_check
from paddleseg.core import predict
def parse\_args():
parser = argparse.ArgumentParser(description='Model prediction')
# params of prediction
parser.add_argument(
"--config_1", dest="cfg_1", help="The config file.", default=None, type=str)
parser.add_argument(
"--config_2", dest="cfg_2", help="The config file.", default=None, type=str)
parser.add_argument(
'--model_path_1',
dest='model_path_1',
help='The path of model 1 for evaluation',
type=str,
default=None)
parser.add_argument(
'--model_path_2',
dest='model_path_2',
help='The path of model 2 for evaluation',
type=str,
default=None)
parser.add_argument(
'--image_path',
dest='image_path',
help=
'The path of image, it can be a file or a directory including images',
type=str,
default=None)
parser.add_argument(
'--save_dir',
dest='save_dir',
help='The directory for saving the predicted results',
type=str,
default='./output/result')
# augment for prediction
parser.add_argument(
'--aug_pred',
dest='aug_pred',
help='Whether to use mulit-scales and flip augment for prediction',
action='store_true')
parser.add_argument(
'--scales',
dest='scales',
nargs='+',
help='Scales for augment',
type=float,
default=1.0)
parser.add_argument(
'--flip_horizontal',
dest='flip_horizontal',
help='Whether to use flip horizontally augment',
action='store_true')
parser.add_argument(
'--flip_vertical',
dest='flip_vertical',
help='Whether to use flip vertically augment',
action='store_true')
# sliding window prediction
parser.add_argument(
'--is_slide',
dest='is_slide',
help='Whether to prediction by sliding window',
action='store_true')
parser.add_argument(
'--crop_size',
dest='crop_size',
nargs=2,
help=
'The crop size of sliding window, the first is width and the second is height.',
type=int,
default=None)
parser.add_argument(
'--stride',
dest='stride',
nargs=2,
help=
'The stride of sliding window, the first is width and the second is height.',
type=int,
default=None)
return parser.parse_args()
def get\_image\_list(image\_path):
"""Get image list"""
valid_suffix = [
'.JPEG', '.jpeg', '.JPG', '.jpg', '.BMP', '.bmp', '.PNG', '.png'
]
image_list = []
image_dir = None
if os.path.isfile(image_path):
if os.path.splitext(image_path)[-1] in valid_suffix:
image_list.append(image_path)
elif os.path.isdir(image_path):
image_dir = image_path
for root, dirs, files in os.walk(image_path):
for f in files:
if '.ipynb_checkpoints' in root:
continue
if os.path.splitext(f)[-1] in valid_suffix:
image_list.append(os.path.join(root, f))
else:
raise FileNotFoundError(
'`--image_path` is not found. it should be an image file or a directory including images'
)
if len(image_list) == 0:
raise RuntimeError('There are not image file in `--image_path`')
return image_list, image_dir
def main(args):
env_info = get_sys_env()
place = 'gpu' if env_info['Paddle compiled with cuda'] and env_info[
'GPUs used'] else 'cpu'
paddle.set_device(place)
if not args.cfg_1:
raise RuntimeError('No configuration file specified.')
if not args.cfg_2:
raise RuntimeError('No configuration file specified.')
cfg_1 = Config(args.cfg_1)
cfg_2 = Config(args.cfg_2)
val_dataset = cfg_1.val_dataset
if not val_dataset:
raise RuntimeError(
'The verification dataset is not specified in the configuration file.'
)
msg = '\n---------------Config Information---------------\n'
msg += str(cfg_1)
msg += str(cfg_2)
msg += '------------------------------------------------'
logger.info(msg)
model_1 = cfg_1.model
transforms = val_dataset.transforms
image_list, image_dir = get_image_list(args.image_path)
logger.info('Number of predict images = {}'.format(len(image_list)))
model_2 = cfg_2.model
transforms = val_dataset.transforms
image_list, image_dir = get_image_list(args.image_path)
logger.info('Number of predict images = {}'.format(len(image_list)))
config_check(cfg_1, val_dataset=val_dataset)
predict(
model_1,
model_2,
model_path_1=args.model_path_1,
model_path_2=args.model_path_2,
transforms=transforms,
image_list=image_list,
image_dir=image_dir,
save_dir=args.save_dir,
aug_pred=args.aug_pred,
scales=args.scales,
flip_horizontal=args.flip_horizontal,
flip_vertical=args.flip_vertical,
is_slide=args.is_slide,
crop_size=args.crop_size,
stride=args.stride,
)
if **name** == '\_\_main\_\_':
args = parse_args()
main(args)
显示:
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED\_ShowChar(uint8\_t x, uint8\_t y, uint8\_t chr)
{
uint8_t c = 0, i = 0;
c = chr - ' ';//得到偏移后的值
if(x > Max_Column - 1)
{
x = 0;
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函数
uint32\_t oled\_pow(uint8\_t m,uint8\_t n)
{
uint32_t result = 1;
while(n --)
{
result *= m;
}
return result;
}
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式 0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED\_ShowNum(uint8\_t x, uint8\_t y, uint32\_t num, uint8\_t len, uint8\_t size)
{
uint8_t t,temp;
uint8_t 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(uint8\_t x, uint8\_t y, uint8\_t \*chr)
{
uint8_t j = 0;
while (chr[j] != '\0')
{
OLED_ShowChar(x, y, chr[j]);
x += 8;
if(x > 120)
{
x = 0;
y += 2;
}
j++;
}
}
////显示汉字
void OLED\_ShowCHinese(uint8\_t x, uint8\_t y, uint8\_t no)
{
uint8_t 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;
}
}
运算结果
测量页面
在交互界面上的显示:
四、 总结
感谢极术社区提供的开发板,让我亲身体验国产芯片资源的优势。
祝极术社区越办越好,也祝国产芯片、国家科技和创新节节攀升!
五、 参考链接
- 【极术社区】GD32F47x/42x系列ARM Cortex-M4高性能MCU资料汇总
- 【Keil官网】 MDK v4 Legacy Support (keil.com)
- 【GD官网】GD32F427xx数据手册: https://www.gigadevice.com.cn...
- 【GD官网】GD32F427xx用户手册: https://www.gigadevice.com.cn...
- 【CSDN】STM32 arm-none-eabi-gcc 交叉编译重定向printf: https://blog.csdn.net/weixin\_...
- 【CSDN】编译报错—undefined reference to \\_sbrk: https://blog.csdn.net/jackcsd...
- 【腾讯云社区】ARM探索之旅03 | 如何使用 ARM FPU 加速浮点计算:https://cloud.tencent.com/dev...