一个秋天

  • 2024-11-17
  • 发表了主题帖: 《深度学习》CNN模型的简单实现

    在对深度学习一书的理论学习之后,尝试做了一下简单的CNN模型实现。 神经网络被组织成神经元层。通常有三种类型的层: 输入层:将输入数据传递到隐藏层。 隐藏层:这些是输入层和输出层之间的中间层,它们执行计算并学习给定数据中的模式。 输出层:基于隐藏层的计算产生最终输出。 神经元之间的每一个连接都有一个权重来表示它的重要性。在训练期间,这些权重被调整以最小化预测和实际输出之间的差异。 每个神经元也有一个偏差项,允许网络考虑权重没有捕捉到的输入可变性。 它们在训练期间调整神经网络的权重和偏差,以最小化损失函数,并在减少预测和实际输出之间的误差的方向上更新参数。 在前向传播中,数据从输入层通过隐藏层流向进行预测的输出层。前向传播的主要目标是基于神经网络的当前权重和偏差生成预测或输出。 反向传播用于根据损失函数计算的误差来更新CNN的权重和偏差,其主要目的是优化神经网络的参数,以便它学习随着时间的推移做出更准确的预测。 这两个过程对于训练CNN有效地完成诸如图像分类、对象检测和图像分割的任务是必不可少的。 学习率控制在训练过程中相对于损失梯度调整多少权重。这是一个关键的超参数,影响网络学习的快慢。 神经网络有不同的架构,适用于不同类型的数据和任务: 监督学习:涉及从标记数据中学习,以预测或分类新数据。人工神经网络(ANN)、前馈神经网络(FNN)和卷积神经网络(CNN)是一些常见的例子。 无监督学习:学习数据中的模式和关系,通常没有明确的标签。自动编码器、生成对抗网络(GAN)就是一些例子。 卷积神经网络(CNN)是一种监督学习模型,对涉及图像或视频分析的任务特别有效,可以通过一系列分层有效地学习和识别边缘、纹理和形状等模式。 让我们更深入地研究卷积神经网络(CNN): 1.CNN的架构: 一.卷积层:这些层是CNN中的基本构建块,用于从输入数据中提取重要特征,如边缘、纹理和形状。它包括以下几层: *卷积运算:包括采用一个称为内核(或过滤器)的小矩阵,并将其滑过输入数据(通常是一幅图像)以执行逐元素矩阵乘法,并对结果求和以在特征图中产生单个输出像素。每个过滤器从输入中提取特定的特征,例如边缘、纹理或更复杂的图案。 *参数:参数包括过滤器的大小(内核大小)、过滤器的数量以及过滤器在输入中移动的步幅(步长)。 *激活功能:典型地,ReLU(整流线性单元)被用作卷积运算之后的激活函数。 二.池层:这些图层对从卷积图层获得的要素地图进行下采样(减少宽度和高度等维度)。最大池和平均池是常用的方法,用于保留最重要的功能,同时降低计算复杂性。 池大小(内核大小)和步幅决定了如何在输入中应用池。 三.完全连接的层(致密层):这些层将卷积层和池层学习到的特征集成到预测中。它们将一层中的每个神经元连接到下一层中的每个神经元,产生最终输出。 神经元之间的每个连接都有自己的权重和偏差,这些权重和偏差在训练过程中进行调整,以提高模型精度。 2.CNN模型的工作示例: 使用小图像和过滤器检测3x3图像中的水平线。 输入图像:考虑灰度3×3图像矩阵(像素值表示为整数): [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 过滤器(内核):让我们定义一个简单的2x2滤波器来检测水平线。该过滤器在顶行具有正权重,在底行具有负权重。它将检测从亮到暗(或暗到亮)像素的水平转换。 [[1, 1], [-1, -1]] 应用过滤器:在输入图像上滑动滤镜,计算每个位置的点积。从图像左上角的2x2子区域开始。 [[1, 2], [4, 5]] 用过滤器计算乘积: (1 * 1) + (2 * 1) + (4 * -1) + (5 * -1) = 1 + 2 - 4 - 5 = -6 用结果替换输出要素地图中的中心像素(本例中为-6)。 滑动:将过滤器向右滑动一个像素,然后再次计算。 [[2, 3], [5, 6]] (2 * 1) + (3 * 1) + (5 * -1) + (6 * -1) = 2 + 3 - 5 - 6 = -6 输出要素地图:在整个图像上滑动过滤器后,生成的2x2输出特征地图可能如下所示: [[-6, -6], [-6, -6]] 输出特征图中的每个值表示滤波器对输入图像的相应子区域的响应。 一个简单的CNN模型 下面是一个如何使用PyTorch实现简单CNN模型的基本示例: 1.导入必要的头文件: import torch是PyTorch的核心库,提供基本的张量运算和神经网络功能。 import numpy as np用于数值运算和管理数组,是数据操作和预处理的一部分。 import torchvision和import torchvision.transforms as transforms用于处理图像数据集、预训练模型和图像预处理技术,帮助完成与计算机视觉相关的任务。 import time import torch import torch.nn as nn import numpy as np from torch.utils.data import random_split, DataLoader import torch.optim as optim import torchvision import torchvision.transforms as transforms import torch.nn.functional as F 2.设置参数: 以下参数对于配置机器学习模型的训练和验证过程至关重要。 batch_size指定每次训练迭代中处理的样本数,并帮助平衡训练速度和内存使用。 valid_size指定将为验证保留的数据集的百分比,允许在训练过程中根据看不见的数据对模型进行评估,以监视性能并防止过度拟合。 num_epochs设置训练期间整个数据集将通过模型的次数。 num_workers指定用于数据加载的工作线程数量,并且可以在更复杂的情况下进行调整以优化性能。 batch_size = 64 valid_size = 0.2 num_epochs = 20 num_workers = 4 3.准备数据集: transform用于在图像被用于训练机器学习模型之前准备图像。 transforms.ToTensor()将图像从常规图片格式转换为机器学习模型可以处理的结构化数字格式(张量)。*transforms.Normalize()调整图像的颜色,使其标准化。这意味着每张图像的颜色都将调整到相似的范围,这有助于模型更好、更一致地学习。 这些步骤确保所有图像都处于模型可以有效工作的格式和范围内。 transform = transforms.Compose( [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) 4.加载和分割数据集: 使用CIFAR10数据集,让我们下载并加载数据集,该数据集包含用于培训和测试目的的不同类别的图像。 full_train_data保存训练图像和标签,而test_data包含测试图像和标签。 valid_size参数指定20%的定型数据应用于验证。计算此百分比并用于分割full_train_data到…里面train_data和valid_data使用random_split,确保80%的数据用于训练,20%用于验证。 DataLoader然后,使用类为每个数据集创建加载器:train_loader用于使用混合批次训练模型,valid_loader用于使用非混合批次验证模型,test_loader用于使用整个测试数据集评估模型。 full_train_data = torchvision.datasets.CIFAR10('data', train=True, download=True, transform=transform) test_data = torchvision.datasets.CIFAR10('data', train=False, download=True, transform=transform) num_train = len(full_train_data) # store the test_dataset size as 20% of the total dataset split = int(np.floor(valid_size * num_train)) train_size = num_train - split # store the train_dataset size (80% in our case) # Random split of the dataset train_data, valid_data = random_split(full_train_data, [train_size, split]) #train the model using 80% of the dataset train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True, num_workers=num_workers) #validate the working a validation dataset which contains 20% of the dataset valid_loader = DataLoader(valid_data, batch_size=batch_size, shuffle=False, num_workers=num_workers) #run the test using the entire dataset test_loader = DataLoader(test_data, batch_size=batch_size, shuffle=False, num_workers=num_workers) 5.定义CNN模型: 基于测试精度和要求,有几种方法来优化和定制CNN模型。让我们来看一个示例模型,并理解各个层。 classes代表CIFAR-10数据集中的不同类别,如“飞机”、“车辆”、“鸟”等。 Net使用PyTorch的nn.Module定义卷积神经网络(CNN)模型。 网络模型包括: 一.爱达荷(Idaho的缩写)卷积层:卷积运算被应用于输入图像,以使用用于提取特征的3个连续层块来提取特征。Conv2d用于对输入图像应用卷积运算,而BatchNorm2d和ReLU分别用于批量标准化和激活功能。 二.池层:用于减少特征图的空间维度,有助于提高模型的计算效率,降低对输入中微小变化的敏感度。 三.完全连接的层:这些层用于根据卷积层提取的特征进行最终预测。他们首先增加图像的大小,然后将其简化,以关注最重要的细节,最后,制作一个列表,显示图像属于每个可能类别的可能性,如“猫”、“狗”或“飞机”。本质上,这些层帮助网络对图像作出明确和最终的决定。 四.脱落层:这些层确保网络即使在某些部分缺失的情况下也能很好地学习工作,这有助于它更好地进行归纳,而不仅仅是记住训练数据。 动词 (verb的缩写)正向方法:指定输入数据在网络中的流动方式:应用卷积、池化和激活函数,对数据进行整形,并通过在不同阶段应用丢弃的完全连接的图层传递数据。 最后,用net = Net()创建Net类的一个实例,初始化CNN模型。 classes = ['plane', 'vehicle', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck'] # Define the CNN model class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Sequential( nn.Conv2d(3, 32, 3, padding=1), nn.BatchNorm2d(32), nn.ReLU(), nn.MaxPool2d(2, 2) ) self.conv2 = nn.Sequential( nn.Conv2d(32, 64, 3, padding=1), nn.BatchNorm2d(64), nn.ReLU(), nn.MaxPool2d(2, 2) ) self.conv3 = nn.Sequential( nn.Conv2d(64, 128, 3, padding=1), nn.BatchNorm2d(128), nn.ReLU(), nn.MaxPool2d(2, 2) ) self.fc1 = nn.Linear(128 * 4 * 4, 256) self.fc2 = nn.Linear(256, 128) self.fc3 = nn.Linear(128, 10) self.dropout = nn.Dropout(0.5) def forward(self, x): x = self.conv1(x) x = self.conv2(x) x = self.conv3(x) x = x.view(-1, 128 * 4 * 4) x = self.dropout(F.relu(self.fc1(x))) x = self.dropout(F.relu(self.fc2(x))) x = self.fc3(x) return x net = Net() 6.定义损失函数和优化器: 这criterion用于衡量网络预测的好坏,以及optimizer用于根据测量结果调整网络的权重以提高其性能 criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(net.parameters(), lr=0.001) 7.培训、验证和损失计算: valid_loss_min是一个变量,用于跟踪迄今为止看到的最低验证损失。 对于每个时期,训练和验证过程重复多次。 培训阶段: I .网络进入训练模式net.train()对于每一批数据,我们清除旧的梯度optimizer.zero_grad() II.做预测net(data)并计算损失criterion(net(data), target). III.调整重量以减少这种损失loss.backward(),并累计总训练损失loss.item() * data.size(0). 验证阶段: I .网络切换到评估模式net.eval(). II.对于每批验证数据,我们在不更新权重的情况下计算损失torch.no_grad(),以及net(data)获取验证数据的网络预测。criterion(output, target)计算该批次的预测误差。 III.累计总验证损失loss.item() * data.size(0). 计算平均损失: I .在每个时期之后,代码通过将总损失除以每个数据集中的样本数来计算训练和验证数据的平均损失。 II.测量每个时期所用的时间。此外,检查验证损失与以前的时期相比是否有所改善,并将最佳模型的状态保存到文件中net_cifar10.pt. 该过程有助于跟踪模型的性能,监控进度,并确保保存性能最佳的模型。 valid_loss_min = np.Inf for epoch in range(num_epochs): start_time = time.time() train_loss = 0.0 valid_loss = 0.0 # Training net.train() for data, target in train_loader: data, target = data, target optimizer.zero_grad() output = net(data) loss = criterion(output, target) loss.backward() optimizer.step() train_loss += loss.item() * data.size(0) # Validation net.eval() with torch.no_grad(): for data, target in valid_loader: data, target = data, target output = net(data) loss = criterion(output, target) valid_loss += loss.item() * data.size(0) # Calculate average loss train_loss /= len(train_loader.dataset) valid_loss /= len(valid_loader.dataset) end_time = time.time() epoch_time = end_time - start_time print(f'Epoch: {epoch+1}/{num_epochs} | Time: {epoch_time:.3f}s | Training Loss: {train_loss:.4f} | Validation Loss: {valid_loss:.4f}') # Save model if validation loss decreases if valid_loss <= valid_loss_min: print(f'Validation loss decreased ({valid_loss_min:.4f} --> {valid_loss:.4f}). Saving model as net_cifar10.pt') torch.save(net.state_dict(), 'net_cifar10.pt') valid_loss_min = valid_loss 8.加载并测试最佳模型: net.load_state_dict(torch.load('net_cifar10.pt'))从名为的文件中加载最佳保存的模型net_cifar10.pt. 初始化变量test_loss, class_correct,以及class_total跟踪测试数据的总损失以及模型的整体表现。 测试阶段: I .模型被设置为评估模式net.eval(),以及torch.no_grad()再次用于阻止模型计算梯度,这样可以节省内存。 II.对于每批测试数据,模型进行预测,计算损失,并更新总测试损失。 III.然后检查每个预测是否正确,并记录每个类别的正确预测数和每个类别的样本总数。 通过在测试数据集上计算模型的性能来打印测试结果,计算平均损失和准确性,并打印出模型的总体性能。 # Load the best model net.load_state_dict(torch.load('net_cifar10.pt')) print('Finished Training') test_loss = 0.0 class_correct = [0] * 10 class_total = [0] * 10 net.eval() with torch.no_grad(): for data, target in test_loader: data, target = data, target output = net(data) loss = criterion(output, target) test_loss += loss.item() * data.size(0) _, pred = torch.max(output, 1) correct = pred.eq(target.view_as(pred)) for i in range(len(target)): label = target[i].item() class_correct[label] += correct[i].item() class_total[label] += 1 # Print test results test_loss /= len(test_loader.dataset) print(f'Test Loss: {test_loss:.6f}') overall_accuracy = 100. * np.sum(class_correct) / np.sum(class_total) print(f'\nTest Accuracy (Overall): {overall_accuracy:.2f}%') 下载数据集后CIFAR-10的随机样本测试数据集上对模型进行训练和评估CIFAR-10数据集。 Epoch: 1/20 | Time: 218.234s | Training Loss: 1.6360 | Validation Loss: 1.2467 Validation loss decreased (inf --> 1.2467). Saving model as net_cifar10.pt Epoch: 2/20 | Time: 223.496s | Training Loss: 1.2740 | Validation Loss: 1.0825 Validation loss decreased (1.2467 --> 1.0825). Saving model as net_cifar10.pt Epoch: 3/20 | Time: 232.533s | Training Loss: 1.1203 | Validation Loss: 0.9540 Validation loss decreased (1.0825 --> 0.9540). Saving model as net_cifar10.pt Epoch: 4/20 | Time: 230.899s | Training Loss: 1.0092 | Validation Loss: 0.8614 Validation loss decreased (0.9540 --> 0.8614). Saving model as net_cifar10.pt Epoch: 5/20 | Time: 231.082s | Training Loss: 0.9349 | Validation Loss: 0.8214 Validation loss decreased (0.8614 --> 0.8214). Saving model as net_cifar10.pt Epoch: 6/20 | Time: 252.445s | Training Loss: 0.8686 | Validation Loss: 0.8234 Epoch: 7/20 | Time: 234.719s | Training Loss: 0.8168 | Validation Loss: 0.7961 Validation loss decreased (0.8214 --> 0.7961). Saving model as net_cifar10.pt Epoch: 8/20 | Time: 244.801s | Training Loss: 0.7701 | Validation Loss: 0.7754 Validation loss decreased (0.7961 --> 0.7754). Saving model as net_cifar10.pt Epoch: 9/20 | Time: 284.708s | Training Loss: 0.7218 | Validation Loss: 0.7546 Validation loss decreased (0.7754 --> 0.7546). Saving model as net_cifar10.pt Epoch: 10/20 | Time: 255.791s | Training Loss: 0.6918 | Validation Loss: 0.7677 Epoch: 11/20 | Time: 203.933s | Training Loss: 0.6485 | Validation Loss: 0.7009 Validation loss decreased (0.7546 --> 0.7009). Saving model as net_cifar10.pt Epoch: 12/20 | Time: 393.549s | Training Loss: 0.6176 | Validation Loss: 0.7026 Epoch: 13/20 | Time: 253.282s | Training Loss: 0.5890 | Validation Loss: 0.6831 Validation loss decreased (0.7009 --> 0.6831). Saving model as net_cifar10.pt Epoch: 14/20 | Time: 284.252s | Training Loss: 0.5553 | Validation Loss: 0.6826 Validation loss decreased (0.6831 --> 0.6826). Saving model as net_cifar10.pt Epoch: 15/20 | Time: 229.772s | Training Loss: 0.5271 | Validation Loss: 0.6881 Epoch: 16/20 | Time: 257.720s | Training Loss: 0.5061 | Validation Loss: 0.6940 Epoch: 17/20 | Time: 271.851s | Training Loss: 0.4801 | Validation Loss: 0.7251 Epoch: 18/20 | Time: 240.566s | Training Loss: 0.4522 | Validation Loss: 0.6837 Epoch: 19/20 | Time: 243.856s | Training Loss: 0.4357 | Validation Loss: 0.6817 Validation loss decreased (0.6826 --> 0.6817). Saving model as net_cifar10.pt Epoch: 20/20 | Time: 278.209s | Training Loss: 0.4215 | Validation Loss: 0.7156 Finished Training Test Loss: 0.712707 Test Accuracy (Overall): 78.11% 本文提供了使用PyTorch实现基本CNN模型的基本方法。该模型通常用于图像分类任务,可以提供更复杂的架构和技术来处理深度学习中的各种问题。

  • 2024-10-15
  • 发表了主题帖: 《深度学习》一书中对于语言模型知识的学习

    第二阶段学习中对于循环神经网络的字符级语言模型进行了深入的了解,因为在平时工作中最长使用到的便是语言识别了,而字符语言识别根据的是文本内容,平时在单片机中也会有使用到。首先介绍一下基于循环神经网络(RNN)的字符级语言模型,它是通过捕捉序列数据中的时序依赖性来预测文本中接下来的字符。RNN由输入层、隐藏层和输出层组成。隐藏层之间的循环连接允许信息在时间步之间传播,从而捕捉序列中的依赖关系。通过时间展开,RNN可以被看作是一系列网络层的叠加,每一层对应于序列中的一个特定时间步。 RNN的训练涉及到前向计算和反向传播,其中反向传播通过时间(BPTT)算法来计算梯度。在训练过程中,RNN可能会遇到梯度消失或梯度爆炸的问题,这需要采用特定的技术来解决,比如梯度裁剪或使用LSTM/GRU等结构。RNN在自然语言处理(NLP)领域有广泛的应用,包括词性标注、命名实体识别、句子解析等任务。在机器翻译和文本生成领域,RNN能够理解和生成不同语言的句子结构,实现机器的创造性写作。基于RNN的字符级语言模型通过学习文本数据的统计特性,能够生成连贯和有意义的文本序列。这种模型在文本生成、机器翻译、语音识别等领域有着广泛的应用。但是目前由于单片机有些为本地部署工作,没有接入互联网可以利用大模型进行语音识别,所以一般来说还是基于数字信号处理和模式识别技术。 其核心步骤包括语音采集、特征提取、模式匹配和指令执行。其一般为: 语音采集:通过麦克风等声音传感器采集环境中的语音信号。采集到的语音信号是模拟信号,需要经过模数转换器(ADC)将其转换为数字信号,以便后续的数字信号处理。 特征提取:从采集到的语音信号中提取有用的特征以进行识别。常用的特征提取方法包括短时能量、过零率、梅尔频谱系数(MFCC)等。这些特征能够描述语音信号的频谱、语调、音量等特征。 模式匹配:将提取到的特征与预先训练好的模型进行匹配。模型可以采用传统的模式识别算法,如隐马尔可夫模型(HMM)、高斯混合模型(GMM)等,也可以使用深度学习算法,如卷积神经网络(CNN)、循环神经网络(RNN)等。匹配过程会计算出输入语音信号与各个模型之间的相似度或距离。 指令执行:根据模式匹配的结果,确定输入语音信号对应的指令或操作。根据识别结果,单片机可以执行相应的功能,如控制开关、播放音频等。 在实际应用中,单片机通常会配合专门的语音识别模块,如LD3320,来实现语音识别功能。LD3320是一款基于非特定人语音识别技术的语音识别/声控芯片,它集成了高精度的A/D和D/A接口,支持并行接口或SPI接口,可以在不需要外接辅助Flash和RAM的情况下实现语音识别功能。用户可以通过编程动态编辑识别的关键词语列表,实现语音控制。 此外,单片机在语音识别技术中的应用还包括通过ADC将模拟的语音信号转化为数字信号,内置的定时器和计数器功能也可以帮助实现对语音信号的精确采样,提高语音识别的准确性。单片机的高速计算能力和丰富的存储资源可以对采集到的语音信号进行数字信号处理,包括特征提取、语音编码和语音分析等,以提高语音识别的精度和稳定性。在设计单片机语音识别系统时,还需要考虑系统的硬件设计,如电源部分、主控单元、语音采样电路、LCD显示模块等,以及软件设计,包括语音处理算法和用户界面。通过这些设计,单片机可以实现对不同设备的语音控制,具有市场应用前景。 单片机语音识别的速度有一些常见的提高方法,就我本人的经验以及可查阅的资料总结来看,有以下方法: 1、硬件加速:使用具有硬件加速功能的单片机,如STM32的硬件DSP加速,可以显著提高语音处理的速度。例如,通过使用CMSIS-DSP库来加速音频处理,可以减少CPU的负担,提高执行效率。 2、使用DMA:通过使用直接内存访问(DMA),可以减少CPU的负载,提高数据传输效率。配置DMA以自动接收I2S数据,从而让CPU有更多资源处理其他任务。 3、优化算法:优化语音识别算法,例如简化计算流程、使用固定点运算代替浮点运算,可以提高系统性能。固定点运算通常比浮点运算更快,更适合资源受限的单片机环境。 4、前端处理和特征提取优化:优化前端处理和特征提取算法,可以提高语音信号的抗噪能力和区分度,从而对语音识别速度产生积极影响。 5、减少训练数据量:虽然增加训练数据量可以提高识别精度,但同时也会增加处理时间。在对速度有严格要求的应用中,可以通过减少训练数据量来加快识别速度。 6、定制化语音模型:开发具有定制化语音模型的语音识别技术,根据具体应用场景、用户群体、语音类型等,定制化语音模型并进行训练和优化,可以提高语音识别的速度和精确度。 7、代码优化:使用高效的编程语言和数据结构,例如C语言或汇编语言进行底层优化,可以显著提升处理速度。此外,适当使用查找表和固定点运算可以进一步提高效率。 8、合理的资源管理:合理分配单片机的RAM和ROM资源,例如,将部分数据存储在外部存储器中,只在需要时载入到RAM,可以减少内存占用,提高处理速度。 以上便是此次对于深度学习中语言模型的学习分享,最后一阶段我试试使用单片机测试一下部署相关模型的操作。

  • 2024-09-18
  • 发表了主题帖: 《深度学习》读后感1:深度学习在单片机上的应用知识点

    此次有幸申请到《深度学习》一书,在为期三周的时间内进行了阅读,由于本人之前是利用单片机进行开发,所以希望能够获取一些单片机上进行机器学习的相关知识。本书中对于深度学习内容的阐述较为生动形象,引用了许多贴近生活的示例,让人可以直观地感受深度学习的原理。通过阅读并且查阅资料,我希望和大家分享一下我所关注问题的一些收获,首先是对于机器学习中数据集获取的解决办法。通常我们在训练时需要有一定的数据才能完成,而此前通常都需要人工去产生数据集以满足使用需求。通过学习与查阅,还了解到以下的获取方法: 公开数据集:许多研究机构和大学会发布一些标准的公开数据集,这些数据集通常经过清洗和标注,适合用于学术研究和教育目的。例如,MNIST数据集是手写数字识别的入门级数据集,CIFAR-10和CIFAR-100是常用的图像识别数据集,ImageNet是一个大规模的图像识别数据集,而Pascal VOC则常用于对象检测和图像分割任务。 网络爬虫:可以通过编写网络爬虫程序从互联网上抓取数据,这种方法可以获得大量数据,但需要处理数据的不确定性和质量问题。 数据平台:一些数据平台如Kaggle、Google Dataset Search、AWS Public Datasets等提供了大量的数据集,这些数据集覆盖了各种领域和应用。 平时在进行项目开发时,有一些情况下需要对单片机部署机器学习模型,通常使用STM32Cube.AI来进行模型转换和代码生成。对于我自己使用单片机进行机器学习时,也了解了一些需要注意的地方用来优化性能,比如可以通过以下方式:使用位操作代替算术操作:位操作通常比算术操作更快,例如使用位与、位或、位异或等操作来处理标志位,或者使用位移操作来替代乘除法。避免不必要的操作:去除代码中不必要的变量赋值和函数调用,减少程序的复杂性和执行时间。控制数据类型大小:尽量使用较小的数据类型,如char或int,而不是float,因为浮点数运算通常需要更多的CPU周期和内存空间。利用硬件资源:例如,使用DMA(直接内存访问)来传输数据,减少CPU负载,或者利用单片机的硬件加速器(如果存在)来执行特定任务。自加、自减指令:使用i++和i--等自增自减操作,因为某些编译器对这些操作进行了优化,效率更高优化算法:选择或设计适合单片机资源限制的算法,例如使用简单的线性回归而不是复杂的神经网络模型。代码重用:通过函数或宏来重用代码,减少代码冗余,提高代码的可维护性。寄存器优化:将频繁使用的变量存储在寄存器中,以加快访问速度。指令流水线优化:通过合理组织代码,使得指令可以并行执行,提高执行效率。内存优化:优化数据结构和内存使用,减少内存碎片,提高内存访问速度。中断优化:合理配置中断,减少中断处理程序的复杂性,确保中断服务例程尽可能简短。模型优化:在模型训练阶段,可以通过模型压缩、量化等技术减小模型大小,使其更适合在单片机上运行。 不知道有无同行对于使用单片机进行机器学习模型部署有丰富的经验,希望可以交流学习,在这方面我还较为生疏。

  • 2024-08-22
  • 回复了主题帖: 读书入围名单: 《动手学深度学习(PyTorch版)》,配套视频、源码等

    个人信息确认无误,可以完成计划。

  • 2024-03-28
  • 发表了主题帖: 【国民技术车规MCU N32A455开发板】PWM方波产生测试

    本周对于N32A455的PWM产生进行了测试,首先连接接线图如下:   使用的示波器为PicoScope的3205,利用电脑查看波形,将探头使用探针夹夹在PA6上,地与板子的GND连接,接下来将下列代码下载至板子上: #include "main.h" TIM_TimeBaseInitType TIM_TimeBaseStructure; OCInitType TIM_OCInitStructure; uint16_t CCR1_Val = 333; uint16_t CCR2_Val = 249; uint16_t CCR3_Val = 166; uint16_t CCR4_Val = 83; uint16_t PrescalerValue = 0; void RCC_Configuration(void); void GPIO_Configuration(void); int main(void) { RCC_Configuration(); GPIO_Configuration(); PrescalerValue = (uint16_t)(SystemCoreClock / 24000000) - 1; TIM_InitTimBaseStruct(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.Period = 665; TIM_TimeBaseStructure.Prescaler = PrescalerValue; TIM_TimeBaseStructure.ClkDiv = 0; TIM_TimeBaseStructure.CntMode = TIM_CNT_MODE_UP; TIM_InitTimeBase(TIM3, &TIM_TimeBaseStructure); TIM_InitOcStruct(&TIM_OCInitStructure); TIM_OCInitStructure.OcMode = TIM_OCMODE_PWM1; TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE; TIM_OCInitStructure.Pulse = CCR1_Val; TIM_OCInitStructure.OcPolarity = TIM_OC_POLARITY_HIGH; TIM_InitOc1(TIM3, &TIM_OCInitStructure); TIM_ConfigOc1Preload(TIM3, TIM_OC_PRE_LOAD_ENABLE); TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE; TIM_OCInitStructure.Pulse = CCR2_Val; TIM_InitOc2(TIM3, &TIM_OCInitStructure); TIM_ConfigOc2Preload(TIM3, TIM_OC_PRE_LOAD_ENABLE); TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE; TIM_OCInitStructure.Pulse = CCR3_Val; TIM_InitOc3(TIM3, &TIM_OCInitStructure); TIM_ConfigOc3Preload(TIM3, TIM_OC_PRE_LOAD_ENABLE); TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE; TIM_OCInitStructure.Pulse = CCR4_Val; TIM_InitOc4(TIM3, &TIM_OCInitStructure); TIM_ConfigOc4Preload(TIM3, TIM_OC_PRE_LOAD_ENABLE); TIM_ConfigArPreload(TIM3, ENABLE); TIM_Enable(TIM3, ENABLE); while (1) { } } void RCC_Configuration(void) { RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM3, ENABLE); RCC_EnableAPB2PeriphClk( RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_GPIOB | RCC_APB2_PERIPH_GPIOC | RCC_APB2_PERIPH_AFIO, ENABLE); } void GPIO_Configuration(void) { GPIO_InitType GPIO_InitStructure; /* GPIOA Configuration:TIM3 Channel1, 2, 3 and 4 as alternate function push-pull */ GPIO_InitStruct(&GPIO_InitStructure); GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1; GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure); } #ifdef USE_FULL_ASSERT void assert_failed(const uint8_t* expr, const uint8_t* file, uint32_t line) { while (1) { } } #endif 该设置将PWM时钟设置为72MHz,PA6占空比为50%,PA7占空比为37.5%,PB0占空比为25%,PB1占空比为12.5%。相应波形如下: PA6: PA7: PB0:   PB1:   可以看出按照相应地占空比输出了PWM波形。测试过程较为顺利。    

  • 2024-03-23
  • 发表了主题帖: 【国民技术车规MCU N32A455开发板】ADC测试旋钮电位器

    再利用ADC读取电位器的测试中,首先我们利用单线连接电位器输出引脚PB15与读取引脚PC0,接线图如下:     再使用demo中的ADC_SingleRead程序,代码如下: /***************************************************************************** * Copyright (c) 2022, Nations Technologies Inc. * * All rights reserved. * **************************************************************************** * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Nations' name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /** * [url=home.php?mod=space&uid=1307177]@File[/url] main.c * [url=home.php?mod=space&uid=1315547]@author[/url] Nations * [url=home.php?mod=space&uid=252314]@version[/url] v1.0.0 * * @copyright Copyright (c) 2022, Nations Technologies Inc. All rights reserved. */ #include "main.h" /** @addtogroup ADC_ADC1_DMA * @{ */ ADC_InitType ADC_InitStructure; DMA_InitType DMA_InitStructure; __IO uint16_t ADC1ConvertedValue[5],ADC2ConvertedValue[5],ADC3ConvertedValue[5],ADC4ConvertedValue[5]; void RCC_Configuration(void); void GPIO_Configuration(void); uint16_t ADC_GetData(ADC_Module* ADCx, uint8_t ADC_Channel); void ADC_Initial(ADC_Module* ADCx); void ADC_Initial(ADC_Module* ADCx) { /* ADC configuration ------------------------------------------------------*/ ADC_InitStructure.WorkMode = ADC_WORKMODE_INDEPENDENT; ADC_InitStructure.MultiChEn = DISABLE; ADC_InitStructure.ContinueConvEn = DISABLE; ADC_InitStructure.ExtTrigSelect = ADC_EXT_TRIGCONV_NONE; ADC_InitStructure.DatAlign = ADC_DAT_ALIGN_R; ADC_InitStructure.ChsNumber = 1; ADC_Init(ADCx, &ADC_InitStructure); /* Enable ADC */ ADC_Enable(ADCx, ENABLE); /*Check ADC Ready*/ while(ADC_GetFlagStatusNew(ADCx,ADC_FLAG_RDY) == RESET) ; /* Start ADC calibration */ ADC_StartCalibration(ADCx); /* Check the end of ADC calibration */ while (ADC_GetCalibrationStatus(ADCx)) ; } /** * [url=home.php?mod=space&uid=159083]@brief[/url] Main program */ int main(void) { /* System clocks configuration ---------------------------------------------*/ RCC_Configuration(); /* GPIO configuration ------------------------------------------------------*/ GPIO_Configuration(); ADC_Initial(ADC1); ADC_Initial(ADC2); ADC_Initial(ADC3); ADC_Initial(ADC4); while (1) { ADC1ConvertedValue[0]=ADC_GetData(ADC1,ADC1_Channel_06_PC0); ADC1ConvertedValue[1]=ADC_GetData(ADC1,ADC1_Channel_07_PC1); ADC2ConvertedValue[0]=ADC_GetData(ADC2,ADC2_Channel_08_PC2); ADC2ConvertedValue[1]=ADC_GetData(ADC2,ADC2_Channel_09_PC3); ADC3ConvertedValue[0]=ADC_GetData(ADC3,ADC3_Channel_07_PD10); ADC3ConvertedValue[1]=ADC_GetData(ADC3,ADC3_Channel_08_PD11); ADC4ConvertedValue[0]=ADC_GetData(ADC4,ADC4_Channel_09_PD12); ADC4ConvertedValue[1]=ADC_GetData(ADC4,ADC4_Channel_10_PD13); } } /** * @brief Configures the different system clocks. */ void RCC_Configuration(void) { /* Enable peripheral clocks ------------------------------------------------*/ /* Enable GPIOC clocks */ RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOF|RCC_APB2_PERIPH_GPIOG|RCC_APB2_PERIPH_GPIOA|RCC_APB2_PERIPH_GPIOB|RCC_APB2_PERIPH_GPIOC|RCC_APB2_PERIPH_GPIOD|RCC_APB2_PERIPH_GPIOE, ENABLE); /* Enable ADC1, ADC2, ADC3 and ADC4 clocks */ RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC1 | RCC_AHB_PERIPH_ADC2 | RCC_AHB_PERIPH_ADC3 | RCC_AHB_PERIPH_ADC4, ENABLE); /* RCC_ADCHCLK_DIV16*/ ADC_ConfigClk(ADC_CTRL3_CKMOD_AHB,RCC_ADCHCLK_DIV16); RCC_ConfigAdc1mClk(RCC_ADC1MCLK_SRC_HSE, RCC_ADC1MCLK_DIV8); //selsect HSE as RCC ADC1M CLK Source } /** * @brief Configures the different GPIO ports. */ void GPIO_Configuration(void) { GPIO_InitType GPIO_InitStructure; /* Configure PC0 PC1 as analog input -------------------------*/ GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitPeripheral(GPIOC, &GPIO_InitStructure); /* Configure PC2 PC3 as analog input -------------------------*/ GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_3; GPIO_InitPeripheral(GPIOC, &GPIO_InitStructure); /* Configure PD10 PD11 as analog input -------------------------*/ GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_11; GPIO_InitPeripheral(GPIOD, &GPIO_InitStructure); /* Configure PD12 PD13 as analog input -------------------------*/ GPIO_InitStructure.Pin = GPIO_PIN_12 | GPIO_PIN_13; GPIO_InitPeripheral(GPIOD, &GPIO_InitStructure); } uint16_t ADC_GetData(ADC_Module* ADCx, uint8_t ADC_Channel) { uint16_t dat; ADC_ConfigRegularChannel(ADCx, ADC_Channel, 1, ADC_SAMP_TIME_239CYCLES5); /* Start ADC Software Conversion */ ADC_EnableSoftwareStartConv(ADCx, ENABLE); while(ADC_GetFlagStatus(ADCx, ADC_FLAG_ENDC)==0){ } ADC_ClearFlag(ADCx, ADC_FLAG_ENDC); ADC_ClearFlag(ADCx, ADC_FLAG_STR); dat=ADC_GetDat(ADCx); return dat; } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file pointer to the source file name * @param line assert_param error line source number */ void assert_failed(const uint8_t* expr, const uint8_t* file, uint32_t line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* Infinite loop */ while (1) { } } #endif /** * @} */ /** * @} */ 最终在旋钮位于最左边时读取PC0的值如下:   将旋钮调至最右边读取PC0的值:   发现PC1随着变化,于是将PC1接GND,接线图如下:   完成接线后读取旋钮位于最左边位置时的读数:   旋钮调至最右边的读数:   整体测试下来,ADC对于极限电压的抖动不大,感觉精度还是不错的。

  • 2024-03-16
  • 发表了主题帖: 【国民技术车规MCU N32A455开发板】串口通讯测试

    在进行串口测试时,板上PA9为TX,接USB转串口的RX;PA10为板上RX,接USB转串口的TX,波特率设置为115200。接线之后的照片如下: 首先进行芯片温度读取测试,仍然使用上一篇ADC测试中的程序ADC1_TEMP: /** * @File main.c * @author Nations * @version v1.0.0 * * @copyright Copyright (c) 2022, Nations Technologies Inc. All rights reserved. */ #include <stdio.h> #include "main.h" /** @addtogroup ADC_ADC1_TEMP * @{ */ ADC_InitType ADC_InitStructure; ADC_InitTypeEx ADC_InitStructureEx; DMA_InitType DMA_InitStructure; __IO uint16_t ADCConvertedValue; void RCC_Configuration(void); void Delay(__IO uint32_t nCount); void USART1_Config(void); #define Vc0 0 //X #define Tc1 1.5f /*V30 is the voltage value at 30 degree Celsius by factory default*/ uint16_t V30 = 0; uint16_t ADvalue = 0; uint32_t temp = 0; #ifdef DEFINEFLOAT //Float __IO float TempValue; /*xx mv per degree Celsius by datasheet define*/ #define AVG_SLOPE 0.0041f /** * @brief Cal temp use float result. */ float TempCal(uint16_t TempAdVal) { float Temperate; /* Get the temperature inside the chip */ Temperate=((V30+Vc0-TempAdVal)*3.3/4095)/AVG_SLOPE+30.0f-Tc1; return Temperate; } #else __IO int16_t TempValue; /*xx mv per degree Celsius by datasheet define*/ #define AVG_SLOPE 41 /** * @brief Cal temp use integer result. */ int16_t TempCal(uint16_t TempAdVal) { int16_t Temperate; /* Get the temperature inside the chip */ Temperate=(int16_t)((((V30+Vc0-TempAdVal)*33*10000)/(4095*10))/AVG_SLOPE+30-Tc1); return Temperate; } #endif /** * @brief Main program */ int main(void) { /* System clocks configuration ---------------------------------------------*/ RCC_Configuration(); /* DMA1 channel1 configuration ----------------------------------------------*/ DMA_DeInit(DMA1_CH1); DMA_InitStructure.PeriphAddr = (uint32_t)&ADC1->DAT; DMA_InitStructure.MemAddr = (uint32_t)&ADCConvertedValue; DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC; DMA_InitStructure.BufSize = 1; DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE; DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_DISABLE; DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD; DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.CircularMode = DMA_MODE_CIRCULAR; DMA_InitStructure.Priority = DMA_PRIORITY_HIGH; DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE; DMA_Init(DMA1_CH1, &DMA_InitStructure); /* Enable DMA1 channel1 */ DMA_EnableChannel(DMA1_CH1, ENABLE); /* ADC1 configuration ------------------------------------------------------*/ ADC_InitStructure.WorkMode = ADC_WORKMODE_INDEPENDENT; ADC_InitStructure.MultiChEn = DISABLE; ADC_InitStructure.ContinueConvEn = ENABLE; ADC_InitStructure.ExtTrigSelect = ADC_EXT_TRIGCONV_NONE; ADC_InitStructure.DatAlign = ADC_DAT_ALIGN_R; ADC_InitStructure.ChsNumber = 1; ADC_Init(ADC1, &ADC_InitStructure); /* ADC1 temp sensor enable */ ADC_EnableTempSensorVrefint(ENABLE); ADC_InitStructureEx.VbatMinitEn = ENABLE; ADC_InitStructureEx.DeepPowerModEn = DISABLE; ADC_InitStructureEx.JendcIntEn = DISABLE; ADC_InitStructureEx.EndcIntEn = DISABLE; ADC_InitStructureEx.ClkMode = ADC_CTRL3_CKMOD_AHB; ADC_InitStructureEx.CalAtuoLoadEn = DISABLE; ADC_InitStructureEx.DifModCal = false; ADC_InitStructureEx.ResBit = ADC_CTRL3_RES_12BIT; ADC_InitStructureEx.SampSecondStyle = false; ADC_InitEx(ADC1, &ADC_InitStructureEx); /* ADC1 regular configuration */ ADC_ConfigRegularChannel(ADC1, ADC_CH_16, 1, ADC_SAMP_TIME_239CYCLES5);//ADC_CH_16£º²âζȣ¬ADC_CH_18£º²âÄÚ²¿1.2V»ù×¼ /* ADC1 temp sensor enable */ ADC_EnableTempSensorVrefint(ENABLE); /* Enable ADC1 DMA */ ADC_EnableDMA(ADC1, ENABLE); /* Enable ADC1 */ ADC_Enable(ADC1, ENABLE); /*Check ADC Ready*/ while(ADC_GetFlagStatusNew(ADC1,ADC_FLAG_RDY) == RESET) ; /* Start ADC1 calibration */ ADC_StartCalibration(ADC1); /* Check the end of ADC1 calibration */ while (ADC_GetCalibrationStatus(ADC1)) ; /* Start ADC1 Software Conversion */ ADC_EnableSoftwareStartConv(ADC1, ENABLE); /* Config Uart1 as Temperature output */ USART1_Config(); V30 = *(__IO uint32_t*)((uint32_t)0x1FFFF7D0); while (1) { /* */ TempValue = TempCal(ADCConvertedValue); #ifdef DEFINEFLOAT printf("\r\n Temperature = %.3f C\r\n",TempValue); #else printf("\r\n Temperature = %d C\r\n",TempValue); #endif Delay(500); } } /* * @brief uart configure as 115200 8-N-1 */ void USART1_Config(void) { GPIO_InitType GPIO_InitStructure; USART_InitType USART_InitStructure; /* configure USART1 clock*/ RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_USART1 | RCC_APB2_PERIPH_GPIOA, ENABLE); /* USART1 GPIO config */ /* Configure USART1 Tx (PA.09) as alternate function push-pull */ GPIO_InitStructure.Pin = GPIO_PIN_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure); /* Configure USART1 Rx (PA.10) as input floating */ GPIO_InitStructure.Pin = GPIO_PIN_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure); /* USART1 work mode*/ USART_InitStructure.BaudRate = 115200; USART_InitStructure.WordLength = USART_WL_8B; USART_InitStructure.StopBits = USART_STPB_1; USART_InitStructure.Parity = USART_PE_NO ; USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE; USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX; USART_Init(USART1, &USART_InitStructure); USART_Enable(USART1, ENABLE); } /* retarget the C library printf function to the USART */ int fputc(int ch, FILE* f) { USART_SendData(USART1, (uint8_t)ch); while (USART_GetFlagStatus(USART1, USART_FLAG_TXDE) == RESET) ; return (ch); } /** * @brief Delay funciton. */ void Delay(__IO uint32_t nCount) { for(; nCount != 0; nCount--); } /** * @brief Configures the different system clocks. */ void RCC_Configuration(void) { /* Enable peripheral clocks ------------------------------------------------*/ /* Enable DMA1 clocks */ RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA1, ENABLE); /* Enable ADC1 clocks */ RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC1,ENABLE); /* RCC_ADCHCLK_DIV16*/ ADC_ConfigClk(ADC_CTRL3_CKMOD_AHB,RCC_ADCHCLK_DIV16); RCC_ConfigAdc1mClk(RCC_ADC1MCLK_SRC_HSE, RCC_ADC1MCLK_DIV8); //selsect HSE as RCC ADC1M CLK Source } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file pointer to the source file name * @param line assert_param error line source number */ void assert_failed(const uint8_t* expr, const uint8_t* file, uint32_t line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* Infinite loop */ while (1) { } } #endif 读取室温下的芯片温度如下: 再将手指置于芯片上进行升温,读取到的温度为: 之后也使用了ALGO程序进行测试串口的状态信息,程序如下: /** * @file main.c * @author Nations * @version v1.0.0 * * @copyright Copyright (c) 2022, Nations Technologies Inc. All rights reserved. */ #include "n32a455.h" #include "n32a455_rcc.h" #include "n32a455_rng.h" #include "n32a455_hash.h" #include "n32a455_des.h" #include "n32a455_aes.h" #include "log.h" #include <string.h> #ifdef __IAR_ARM #pragma pack(4) #endif /** * @brief show some words(32bit) in hex format */ void DumpWords(const uint32_t* words, uint32_t len) { for (uint32_t i = 0; i < len; ++i) { log_info("0x%08x, ", words); } } /** * @brief show some bytes(8bit) in hex format */ void DumpBytes(const uint8_t* bytes, uint32_t len) { for (uint32_t i = 0; i < len; ++i) { log_info("%02x", bytes); } } /** * @brief Example for how to get a randon number by ALGO lib */ void TestRand(void) { uint32_t buf[8]; uint32_t seed[2] = {1, 2}; log_info("\n"); if (RNG_OK != GetPseudoRand_U32(buf, 8, seed)) { log_error("GetPseudoRand_U32 failed.\n"); } else { log_info("Pseudo random with seed 1,2: "); DumpWords(buf, 8); log_info("\n"); } seed[0] = 3; seed[1] = 4; if (RNG_OK != GetPseudoRand_U32(buf, 8, seed)) { log_error("GetPseudoRand_U32 failed.\n"); } else { log_info("Pseudo random with seed 3,4: "); DumpWords(buf, 8); log_info("\n"); } if (RNG_OK != GetTrueRand_U32(buf, 8)) { log_error("GetTrueRand_U32 failed.\n"); } else { log_info("True random: "); DumpWords(buf, 8); log_info("\n"); } } #define HASH_TEST_MSG "Hello!" /** * @brief Show how to calculate hash value by ALGO lib for a message */ void CalcHASH(const HASH_ALG* hashAlg, char* msg, uint8_t* result) { HASH_CTX ctx; ctx.hashAlg = hashAlg; ctx.sequence = HASH_SEQUENCE_FALSE; if (HASH_Init_OK != HASH_Init(&ctx)) { log_error("HASH_Init failed.\n"); return; } if (HASH_Start_OK != HASH_Start(&ctx)) { log_error("HASH_Start failed.\n"); return; } if (HASH_Update_OK != HASH_Update(&ctx, (uint8_t*)msg, strlen(msg))) { log_error("HASH_Update failed.\n"); return; } if (HASH_Complete_OK != HASH_Complete(&ctx, result)) { log_error("HASH_Complete failed.\n"); return; } } /** * @brief Show how to calculate SHA1 value by ALGO lib for a message */ void TestSHA1() { uint8_t result[20]; log_info("\n"); CalcHASH(HASH_ALG_SHA1, HASH_TEST_MSG, result); log_info("SHA1 of message `%s` is: ", HASH_TEST_MSG); DumpBytes(result, 20); log_info("\n"); } /** * @brief Show how to calculate MD5 value by ALGO lib for a message */ void TestMD5() { uint8_t result[16]; log_info("\n"); CalcHASH(HASH_ALG_MD5, HASH_TEST_MSG, result); log_info("MD5 of message `%s` is: ", HASH_TEST_MSG); DumpBytes(result, 16); log_info("\n"); } /** * @brief Show how to calculate SHA224 value by ALGO lib for a message */ void TestSHA224() { uint8_t result[28]; log_info("\n"); CalcHASH(HASH_ALG_SHA224, HASH_TEST_MSG, result); log_info("SHA224 of message `%s` is: ", HASH_TEST_MSG); DumpBytes(result, 28); log_info("\n"); } /** * @brief Show how to calculate SHA256 value by ALGO lib for a message */ void TestSHA256() { uint8_t result[32]; log_info("\n"); CalcHASH(HASH_ALG_SHA256, HASH_TEST_MSG, result); log_info("SHA256 of message `%s` is: ", HASH_TEST_MSG); DumpBytes(result, 32); log_info("\n"); } /** * @brief Show how to encrypt a message by DES, then decrypt it and compare the result. */ void TestDES(void) { DES_PARM DES_Parm; #ifdef __IAR_ARM uint8_t key[8] = {1, 2, 3, 4, 5, 6, 7, 8}; uint8_t plain[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; uint8_t cipher[8]; uint8_t plainOut[8]; #else __align(4) uint8_t key[8] = {1, 2, 3, 4, 5, 6, 7, 8}; __align(4) uint8_t plain[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; __align(4) uint8_t cipher[8]; __align(4) uint8_t plainOut[8]; #endif log_info("\n"); DES_Parm.in = (uint32_t*)plain; DES_Parm.out = (uint32_t*)cipher; DES_Parm.key = (uint32_t*)key; DES_Parm.iv = NULL; // IV is not needed in ECB mode DES_Parm.inWordLen = sizeof(plain) / sizeof(uint32_t); DES_Parm.Mode = DES_ECB; DES_Parm.En_De = DES_ENC; DES_Parm.keyMode = DES_KEY; // encrypt data if (DES_Init_OK != DES_Init(&DES_Parm)) { log_error("DES_Init failed.\n"); return; } if (DES_Crypto_OK != DES_Crypto(&DES_Parm)) { log_error("DES_Crypto failed\n"); return; } log_info("DES ECB encrypt:\n"); log_info("key = "); DumpBytes(key, sizeof(key)); log_info("\n"); log_info("plain = "); DumpBytes(plain, sizeof(plain)); log_info("\n"); log_info("cipher = "); DumpBytes(cipher, sizeof(cipher)); log_info("\n"); DES_Parm.in = (uint32_t*)cipher; DES_Parm.out = (uint32_t*)plainOut; DES_Parm.En_De = DES_DEC; // decrypt data if (DES_Init_OK != DES_Init(&DES_Parm)) { log_error("DES_Init failed.\n"); return; } if (DES_Crypto_OK != DES_Crypto(&DES_Parm)) { log_error("DES_Crypto failed\n"); return; } log_info("decrypt out = "); DumpBytes(plainOut, 8); log_info("\n"); if (memcmp(plain, plainOut, sizeof(plain)) != 0) { log_error("DES decrypt result do not equal plain data.\n"); while(1); } else { log_info("DES test OK!\n"); } } /** * @brief Show how to encrypt a message by AES, then decrypt it and compare the result. */ void TestAES(void) { AES_PARM AES_Parm; #ifdef __IAR_ARM uint8_t key[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; uint8_t plain[16] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00}; uint8_t cipher[16]; uint8_t plainOut[16]; #else __align(4) uint8_t key[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; __align(4) uint8_t plain[16] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00}; __align(4) uint8_t cipher[16]; __align(4) uint8_t plainOut[16]; #endif log_info("\n"); AES_Parm.in = (uint32_t*)plain; AES_Parm.out = (uint32_t*)cipher; AES_Parm.key = (uint32_t*)key; AES_Parm.iv = NULL; // IV is not needed in ECB mode AES_Parm.inWordLen = sizeof(plain) / sizeof(uint32_t); AES_Parm.keyWordLen = sizeof(key) / sizeof(uint32_t); AES_Parm.Mode = AES_ECB; AES_Parm.En_De = AES_ENC; // encrypt data if (AES_Init_OK != AES_Init(&AES_Parm)) { log_error("AES_Init failed.\n"); return; } if (AES_Crypto_OK != AES_Crypto(&AES_Parm)) { log_error("AES_Crypto failed\n"); return; } log_info("AES ECB encrypt:\n"); log_info("key = "); DumpBytes(key, sizeof(key)); log_info("\n"); log_info("plain = "); DumpBytes(plain, sizeof(plain)); log_info("\n"); log_info("cipher = "); DumpBytes(cipher, sizeof(cipher)); log_info("\n"); AES_Parm.in = (uint32_t*)cipher; AES_Parm.out = (uint32_t*)plainOut; AES_Parm.En_De = AES_DEC; // decrypt data if (AES_Init_OK != AES_Init(&AES_Parm)) { log_error("AES_Init failed.\n"); return; } if (AES_Crypto_OK != AES_Crypto(&AES_Parm)) { log_error("AES_Crypto failed\n"); return; } log_info("decrypt out = "); DumpBytes(plainOut, sizeof(plainOut)); log_info("\n"); if (memcmp(plain, plainOut, sizeof(plain)) != 0) { log_error("AES decrypt result do not equal plain data.\n"); while(1); } else { log_info("AES test OK!\n"); } } /** * @brief main function. */ int main(void) { log_init(); log_info("-----------------------\nAlgorithm demo start.\n"); // RNG test TestRand(); // HASH test TestMD5(); TestSHA1(); TestSHA224(); TestSHA256(); // Cryptogram algorithm TestDES(); TestAES(); log_info("\r\nALGO demo all test OK!\r\n"); while (1) ; } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file pointer to the source file name * @param line assert_param error line source number */ void assert_failed(const uint8_t* expr, const uint8_t* file, uint32_t line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* Infinite loop */ while (1) { } } #endif 测试结果如下: 完成了串口通讯的测试。

  • 2024-03-12
  • 回复了主题帖: 2024开工大吉,你期待测评中心,能有哪些板卡或书籍等?

    希望可以提供一本AI方面或者机器学习方面的书籍学习阅读。

  • 2024-03-10
  • 发表了主题帖: 【国民技术车规MCU N32A455开发板】ADC测试

    在测试过GPIO之后,对于该开发板的使用算是熟悉了,于是测试ADC,这一次测试的芯片内部温度的读取。程序使用的是demo_ADC1_TEMP,将以下程序编译烧录至开发板中: /***************************************************************************** * Copyright (c) 2022, Nations Technologies Inc. * * All rights reserved. * **************************************************************************** * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Nations' name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /** * @File main.c * @author Nations * @version v1.0.0 * * @copyright Copyright (c) 2022, Nations Technologies Inc. All rights reserved. */ #include <stdio.h> #include "main.h" /** @addtogroup ADC_ADC1_TEMP * @{ */ ADC_InitType ADC_InitStructure; ADC_InitTypeEx ADC_InitStructureEx; DMA_InitType DMA_InitStructure; __IO uint16_t ADCConvertedValue; void RCC_Configuration(void); void Delay(__IO uint32_t nCount); void USART1_Config(void); #define Vc0 0 //X #define Tc1 1.5f /*V30 is the voltage value at 30 degree Celsius by factory default*/ uint16_t V30 = 0; uint16_t ADvalue = 0; uint32_t temp = 0; #ifdef DEFINEFLOAT //Float __IO float TempValue; /*xx mv per degree Celsius by datasheet define*/ #define AVG_SLOPE 0.0041f /** * @brief Cal temp use float result. */ float TempCal(uint16_t TempAdVal) { float Temperate; /* Get the temperature inside the chip */ Temperate=((V30+Vc0-TempAdVal)*3.3/4095)/AVG_SLOPE+30.0f-Tc1; return Temperate; } #else __IO int16_t TempValue; /*xx mv per degree Celsius by datasheet define*/ #define AVG_SLOPE 41 /** * @brief Cal temp use integer result. */ int16_t TempCal(uint16_t TempAdVal) { int16_t Temperate; /* Get the temperature inside the chip */ Temperate=(int16_t)((((V30+Vc0-TempAdVal)*33*10000)/(4095*10))/AVG_SLOPE+30-Tc1); return Temperate; } #endif /** * @brief Main program */ int main(void) { /* System clocks configuration ---------------------------------------------*/ RCC_Configuration(); /* DMA1 channel1 configuration ----------------------------------------------*/ DMA_DeInit(DMA1_CH1); DMA_InitStructure.PeriphAddr = (uint32_t)&ADC1->DAT; DMA_InitStructure.MemAddr = (uint32_t)&ADCConvertedValue; DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC; DMA_InitStructure.BufSize = 1; DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE; DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_DISABLE; DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD; DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.CircularMode = DMA_MODE_CIRCULAR; DMA_InitStructure.Priority = DMA_PRIORITY_HIGH; DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE; DMA_Init(DMA1_CH1, &DMA_InitStructure); /* Enable DMA1 channel1 */ DMA_EnableChannel(DMA1_CH1, ENABLE); /* ADC1 configuration ------------------------------------------------------*/ ADC_InitStructure.WorkMode = ADC_WORKMODE_INDEPENDENT; ADC_InitStructure.MultiChEn = DISABLE; ADC_InitStructure.ContinueConvEn = ENABLE; ADC_InitStructure.ExtTrigSelect = ADC_EXT_TRIGCONV_NONE; ADC_InitStructure.DatAlign = ADC_DAT_ALIGN_R; ADC_InitStructure.ChsNumber = 1; ADC_Init(ADC1, &ADC_InitStructure); /* ADC1 temp sensor enable */ ADC_EnableTempSensorVrefint(ENABLE); ADC_InitStructureEx.VbatMinitEn = ENABLE; ADC_InitStructureEx.DeepPowerModEn = DISABLE; ADC_InitStructureEx.JendcIntEn = DISABLE; ADC_InitStructureEx.EndcIntEn = DISABLE; ADC_InitStructureEx.ClkMode = ADC_CTRL3_CKMOD_AHB; ADC_InitStructureEx.CalAtuoLoadEn = DISABLE; ADC_InitStructureEx.DifModCal = false; ADC_InitStructureEx.ResBit = ADC_CTRL3_RES_12BIT; ADC_InitStructureEx.SampSecondStyle = false; ADC_InitEx(ADC1, &ADC_InitStructureEx); /* ADC1 regular configuration */ ADC_ConfigRegularChannel(ADC1, ADC_CH_16, 1, ADC_SAMP_TIME_239CYCLES5);//ADC_CH_16£º²âζȣ¬ADC_CH_18£º²âÄÚ²¿1.2V»ù×¼ /* ADC1 temp sensor enable */ ADC_EnableTempSensorVrefint(ENABLE); /* Enable ADC1 DMA */ ADC_EnableDMA(ADC1, ENABLE); /* Enable ADC1 */ ADC_Enable(ADC1, ENABLE); /*Check ADC Ready*/ while(ADC_GetFlagStatusNew(ADC1,ADC_FLAG_RDY) == RESET) ; /* Start ADC1 calibration */ ADC_StartCalibration(ADC1); /* Check the end of ADC1 calibration */ while (ADC_GetCalibrationStatus(ADC1)) ; /* Start ADC1 Software Conversion */ ADC_EnableSoftwareStartConv(ADC1, ENABLE); /* Config Uart1 as Temperature output */ USART1_Config(); V30 = *(__IO uint32_t*)((uint32_t)0x1FFFF7D0); while (1) { /* */ TempValue = TempCal(ADCConvertedValue); #ifdef DEFINEFLOAT printf("\r\n Temperature = %.3f C\r\n",TempValue); #else printf("\r\n Temperature = %d C\r\n",TempValue); #endif Delay(500); } } /* * @brief uart configure as 115200 8-N-1 */ void USART1_Config(void) { GPIO_InitType GPIO_InitStructure; USART_InitType USART_InitStructure; /* configure USART1 clock*/ RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_USART1 | RCC_APB2_PERIPH_GPIOA, ENABLE); /* USART1 GPIO config */ /* Configure USART1 Tx (PA.09) as alternate function push-pull */ GPIO_InitStructure.Pin = GPIO_PIN_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure); /* Configure USART1 Rx (PA.10) as input floating */ GPIO_InitStructure.Pin = GPIO_PIN_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure); /* USART1 work mode*/ USART_InitStructure.BaudRate = 115200; USART_InitStructure.WordLength = USART_WL_8B; USART_InitStructure.StopBits = USART_STPB_1; USART_InitStructure.Parity = USART_PE_NO ; USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE; USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX; USART_Init(USART1, &USART_InitStructure); USART_Enable(USART1, ENABLE); } /* retarget the C library printf function to the USART */ int fputc(int ch, FILE* f) { USART_SendData(USART1, (uint8_t)ch); while (USART_GetFlagStatus(USART1, USART_FLAG_TXDE) == RESET) ; return (ch); } /** * @brief Delay funciton. */ void Delay(__IO uint32_t nCount) { for(; nCount != 0; nCount--); } /** * @brief Configures the different system clocks. */ void RCC_Configuration(void) { /* Enable peripheral clocks ------------------------------------------------*/ /* Enable DMA1 clocks */ RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA1, ENABLE); /* Enable ADC1 clocks */ RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC1,ENABLE); /* RCC_ADCHCLK_DIV16*/ ADC_ConfigClk(ADC_CTRL3_CKMOD_AHB,RCC_ADCHCLK_DIV16); RCC_ConfigAdc1mClk(RCC_ADC1MCLK_SRC_HSE, RCC_ADC1MCLK_DIV8); //selsect HSE as RCC ADC1M CLK Source } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file pointer to the source file name * @param line assert_param error line source number */ void assert_failed(const uint8_t* expr, const uint8_t* file, uint32_t line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* Infinite loop */ while (1) { } } #endif /** * @} */ /** * @} */ 打开Debug模式: 开发板右下角白色LED亮起: 将变量ADCConvertedValue添加至Watch窗口: 首先读取室温下的ADC值,为1704: 将手指放置MCU上约分钟,提高温度,读取到的值为1673: 由于ADCConvertedValue的值越低,温度越高,所以该验证无问题,详细温度读取将在下一次的串口验证中实现。

  • 回复了主题帖: 国民技术车规MCU N32A455开发板开箱

    秦天qintian0303 发表于 2024-2-8 11:01 不过板子应该问题不大,上电看一下就行,之前有个开发板针都弯了 试了没问题

  • 回复了主题帖: 国民技术车规MCU N32A455开发板开箱

    lugl4313820 发表于 2024-2-18 19:35 申通快递:1、速度慢,我曾经15天才收到。 2、暴力,记得有一次米尔的开发板,差点报废。 原先看里面都是开模的塑料板保护啊,这次感觉不是原厂的包装

  • 2024-03-05
  • 加入了学习《泰克MSO6B探索营》,观看 MSO6B系列低噪声演示

  • 加入了学习《泰克MSO6B探索营》,观看 MSO6B技术介绍

  • 加入了学习《泰克MSO6B探索营》,观看 MSO6B-360度介绍

  • 2024-03-02
  • 发表了主题帖: N32A455开发板环境搭建以及GPIO测试

    在环境搭建时首先将PACK安装至Keil当中: 在PACK Installer当中选取Import Packs,然后找到文件安装即可 官方资料给出了PACK安装包, 安装完成之后再Pack当中可以找到N32A455VEL7: 首先测试例程中的LedBlink,程序如下: /***************************************************************************** * Copyright (c) 2022, Nations Technologies Inc. * * All rights reserved. * **************************************************************************** * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Nations' name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /** * @File main.c * @author Nations * @version v1.0.0 * * @copyright Copyright (c) 2022, Nations Technologies Inc. All rights reserved. */ #include "main.h" #include <stdio.h> #include <stdint.h> /** * @brief Inserts a delay time. * @param count specifies the delay time length. */ void Delay(uint32_t count) { for (; count > 0; count--) ; } /** * @brief Configures LED GPIO. * @param GPIOx x can be A to G to select the GPIO port. * @param Pin This parameter can be GPIO_PIN_0~GPIO_PIN_15. */ void LedInit(GPIO_Module* GPIOx, uint16_t Pin) { GPIO_InitType GPIO_InitStructure; /* Check the parameters */ assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); /* Enable the GPIO Clock */ if (GPIOx == GPIOA) { RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE); } else if (GPIOx == GPIOB) { RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE); } else if (GPIOx == GPIOC) { RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOC, ENABLE); } else if (GPIOx == GPIOD) { RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOD, ENABLE); } else if (GPIOx == GPIOE) { RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOE, ENABLE); } else { } /* Configure the GPIO pin */ if (Pin <= GPIO_PIN_ALL) { GPIO_InitStructure.Pin = Pin; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitPeripheral(GPIOx, &GPIO_InitStructure); } } /** * @brief Turns selected Led on. * @param GPIOx x can be A to G to select the GPIO port. * @param Pin This parameter can be GPIO_PIN_0~GPIO_PIN_15. */ void LedOn(GPIO_Module* GPIOx, uint16_t Pin) { GPIOx->PBC = Pin; } /** * @brief Turns selected Led Off. * @param GPIOx x can be A to G to select the GPIO port. * @param Pin This parameter can be GPIO_PIN_0~GPIO_PIN_15. */ void LedOff(GPIO_Module* GPIOx, uint16_t Pin) { GPIOx->PBSC = Pin; } /** * @brief Turns selected Led on or off. * @param GPIOx x can be A to G to select the GPIO port. * @param Pin This parameter can be one of the following values: * @arg GPIO_PIN_0~GPIO_PIN_15: set related pin on * @arg (GPIO_PIN_0<<16)~(GPIO_PIN_15<<16): clear related pin off */ void LedOnOff(GPIO_Module* GPIOx, uint32_t Pin) { GPIOx->PBSC = Pin; } /** * @brief Toggles the selected Led. * @param GPIOx x can be A to G to select the GPIO port. * @param Pin This parameter can be GPIO_PIN_0~GPIO_PIN_15. */ void LedBlink(GPIO_Module* GPIOx, uint16_t Pin) { GPIOx->POD ^= Pin; } /** * @brief Assert failed function by user. * @param file The name of the call that failed. * @param line The source line number of the call that failed. */ #ifdef USE_FULL_ASSERT void assert_failed(const uint8_t* expr, const uint8_t* file, uint32_t line) { while (1) { } } #endif // USE_FULL_ASSERT /** * @brief Main program. */ int main(void) { /*SystemInit() function has been called by startup file startup_n32a455.s*/ /* Initialize Led1~Led5 as output pushpull mode*/ LedInit(PORT_GROUP2, LED1_PIN | LED2_PIN); LedInit(PORT_GROUP2, LED3_PIN | LED4_PIN | LED5_PIN); /*Turn on Led1*/ LedOn(PORT_GROUP2, LED1_PIN); while (1) { /*LED1_PORT and LED2_PORT are the same port group.Enable Led2 blink and not effect Led1 by Exclusive-OR * operation.*/ LedBlink(PORT_GROUP2, LED2_PIN); /*LED3_PORT, LED4_PORT and LED5_PORT are the same port group.*/ /*Turn Led4 and Led5 off and not effect other ports by PBC register,correspond to * PORT_GROUP2->POD&=~(LED4_PIN|LED5_PIN);*/ LedOn(PORT_GROUP2, LED4_PIN | LED5_PIN); /* Insert delay */ Delay(0x28FFFF); /*Turn Led4 and Led5 on,turn Led3 off and not effect other ports by PBSC register,correspond to * PORT_GROUP2->POD&=~(LED3_PIN),then PORT_GROUP2->POD|=(LED4_PIN|LED5_PIN);*/ LedOnOff(PORT_GROUP2, (LED3_PIN << 16) | LED4_PIN | LED5_PIN); /* Insert delay */ Delay(0x28FFFF); /*Turn on Led3*/ LedOff(PORT_GROUP2, LED3_PIN); /* Insert delay */ Delay(0x28FFFF); } } /** * @} */ 编译以及下载不在此处赘述,以上程序完成红色LED常亮,绿色闪烁,照片如下: 之后修改程序,将其改为绿灯常亮,红灯闪烁,即修改程序中LED1和LED2即可 效果如图所示: 整体来说上手较为容易。

  • 2024-02-28
  • 回复了主题帖: 点评有礼:这些“最能打”国产芯榜的MCU,你知道的那些事儿

    ESP32S3是乐鑫的一款很不错的产品,双核LX7处理器,主频可达240MHz,集成2.4GHzWiFi和BLE5,满足AIoT市场。功能也很完善,基本的外设都有,模拟数字接口也有,有电容触摸输入端,可以满足一般传感互动需求,支持AI加速,并且有低功耗模式可以支持电池供电设备。在智能物联这一块很强大。

  • 2024-02-07
  • 发表了主题帖: 国民技术车规MCU N32A455开发板开箱

    昨天收到N32A455开发板快递,今天拆了进行开箱。在拿的时候听到了里面有晃动的声音,打开一看,果然是稍有损坏。不过目前看是支撑螺柱,不知道板子是不是损坏了。首先是外包装被电位器戳坏了,左下角的塑料螺柱已经断裂并与主板脱离,因为来的时候主板在快递盒中没有太固定,晃动厉害导致的。图片如下: 附赠了一根烧录通讯线。 接下来看一下开发板整体照片: 可以与官方说明中的图片对应: 主控的部分引脚通过2×40的排针引出: 接下来看一下局部,左下角为CODEC部分,主控为VS1053B,其中连接一个MIC(U16),两个双声道音频接口,J19和J21,以及TP12和TP13为DAC输出为喇叭的接口,左上为CAN通讯接口部分,中间为TF卡插槽: 右半部分图片如下: 右上白色为电源接入口,滑动开关为电源开关,电位器为ADC调值用,白色排针为JTAG接口,下方N32G452为NLINk。 比较有趣的是焊接的排针不是单独长度的,似乎是长排针掰断使用的,可以看到下图中的断面痕迹。 整体来说板子做工规整,并且可调式功能相对来说还比较丰富。好评!

  • 2024-02-04
  • 回复了主题帖: 测评入围名单: 国民技术车规MCU N32A455开发板

    个人信息无误,确认可以完成评测计划

  • 2024-01-25
  • 回复了主题帖: 领取审核名单(第五批): 辞旧,年底清仓,100+板卡来袭,有缘来领

    个人信息确认无误,如果是三通快递麻烦寄到付件。

  • 2024-01-24
  • 加入了学习《N32G45XVL-STB 按键+SSD1306》,观看 N32G45XVL-STB 按键+SSD1306

最近访客

< 1/2 >

统计信息

已有48人来访过

  • 芯积分:78
  • 好友:--
  • 主题:9
  • 回复:9

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言