嵌入式通讯协议全解析:UART、I2C、SPI、CAN与Modbus实战指南

嵌入式面试通讯协议手册:UART/I2C/SPI/CAN/RS485与Modbus考点全解析 串行通信是嵌入式系统的基础,根据时钟与数据线的关系可分为同步与异步,例如UART、I2C、SPI、CAN等协议各有不同的电气特性与传输机制。理解差分信号、开漏上拉、波特率误差与帧格式,是解决通信稳定性问题的关键。这些协议在物联网传感器采集、工业总线控制、汽车电子等领域有广泛的应用,面试中常通过逻辑分析仪抓波形、手写CRC校验、配置总线仲裁等实际问题考察工程师的排错能力。RS485与Modbus的组合更是工业现场主从通信的标配,而CAN总线凭借非破坏性仲裁成为车载网络的核心。扎实掌握这些协议的原理与应用,能帮 阅读详情

1. 通讯协议,为什么是嵌入式面试的“必考题”

如果你正在准备嵌入式软件工程师的面试,翻过面经的朋友应该都有一个感受:通讯协议几乎是绕不过去的一关。不管是做单片机、驱动、RTOS 还是 Linux 应用开发,面试官都会从 UART、I2C、SPI、CAN、RS485、Modbus 这些词里挑几个来问。热搜词里频繁出现的“modbus通讯协议”“rs485通讯协议详解”“can通讯协议”“嵌入式八股文”,其实就是这个需求的直接反映。

原因是通讯协议不是一门孤立的“面试知识点”,它贯穿了嵌入式开发的全链路:硬件工程师要选型电平标准和收发器,嵌入式软件工程师要写驱动和解析帧格式,上位机开发要对齐协议字段,系统联调时要靠逻辑分析仪和串口助手定位问题。任何一个环节理解不到位,设备之间就是“鸡同鸭讲”。

但这里也有一个误区。很多初学者把通讯协议当成“背参数”,比如 I2C 最大速率 400kbps,SPI 有四个模式,CAN 的仲裁机制是“显性覆盖隐性”……背得滚瓜烂熟,一到实际项目中仍然不知道怎么选型、怎么排查通信失败、怎么设计一版健壮的帧协议。

这篇文章的目的,就是把这些高频协议放到真实开发场景里重新讲一遍。我会从一个嵌入式面试和实际项目结合的视角,把一个完整的通讯协议知识体系拆开:先讲清楚每类协议解决什么问题、怎么工作,再给出代码层面和应用层面的落地内容,最后整理一份面试答题框架和常见坑。

读完这篇文章,你至少能做到三件事:

  1. 面对“UART、I2C、SPI 怎么选”这种问题,能给出有条理、有场景依据的回答。
  2. 能独立画出 Modbus RTU 的一帧报文,并完成 CRC 校验的代码实现。
  3. 对 RS485 和 CAN 这类工业总线,不仅知道电平标准,还知道工程上为什么这样设计。

2. 串口 UART:最简单的通讯协议,但最容易出问题

UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是嵌入式世界最基础的通讯协议,没有之一。从调试打印到 GPS 模块、蓝牙模块、4G 模组、传感器数据输出,几乎所有设备默认都提供串口接口。

UART 的工作方式是异步的,也就是说收发双方不需要共享时钟信号,而是约定一个波特率(Baud Rate),比如 9600、115200,然后在两条数据线上按位传输。

一帧典型的 UART 数据包含:

字段 内容
起始位 1 位,拉低表示开始传输
数据位 通常 8 位,从低位到高位
校验位 可选,奇校验或偶校验
停止位 1 位或 2 位,拉高表示结束

面试时经常问“为什么 UART 需要起始位和停止位”。答案是:因为 UART 没有时钟线,接收方必须通过起始位的下降沿来同步自己的采样时钟位置,然后按波特率在每一位的中心点采样。停止位则保证一帧结束后,线路有足够时间回到空闲电平(高电平),方便下一帧的起始位识别。

在实际工程中,UART 最容易踩坑的地方不是原理,而是这几个点:

第一,TXD 和 RXD 要交叉连接。 两个设备通信时,A 设备的 TXD 接 B 设备的 RXD,A 设备的 RXD 接 B 设备的 TXD。新手经常把两个 TXD 接到一起,结果完全收不到数据。

第二,共地问题。 两个使用独立电源的设备进行串口通信时,除了 TXD/RXD,还必须连接 GND。否则信号参考电位不一致,接收到的数据可能全是乱码。

第三,波特率误差。 很多单片机内部时钟精度不高,如果通信双方的波特率误差超过一定范围(通常是 ±2%~±3%),就会出现偶发乱码。尤其是使用内部 RC 振荡器跑 115200 以上波特率时,要格外小心。

第四,缓冲区溢出。 如果 MCU 主循环处理太慢,而串口持续有数据进来,硬件接收缓冲区会溢出,导致丢数据。工程上通常使用中断 + 环形缓冲区的方式来解决。

下面是一个典型的串口中断接收框架,使用环形缓冲区:

// 文件路径:uart_ring_buffer.c
#define UART_RX_BUF_SIZE 256

static uint8_t rx_buffer[UART_RX_BUF_SIZE];
static volatile uint16_t rx_head = 0;
static volatile uint16_t rx_tail = 0;

// 串口中断服务函数(以 STM32 HAL 库为例)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART1) {
        rx_buffer[rx_head] = received_byte;
        rx_head = (rx_head + 1) % UART_RX_BUF_SIZE;
        HAL_UART_Receive_IT(huart, &received_byte, 1);
    }
}

// 应用层读取一字节
uint8_t uart_read_byte(uint8_t *byte)
{
    if (rx_head == rx_tail) {
        return 0; // 缓冲区为空
    }
    *byte = rx_buffer[rx_tail];
    rx_tail = (rx_tail + 1) % UART_RX_BUF_SIZE;
    return 1;
}

// 应用层查询缓冲区数据长度
uint16_t uart_rx_data_length(void)
{
    return (uint16_t)((rx_head + UART_RX_BUF_SIZE - rx_tail) % UART_RX_BUF_SIZE);
}

环形缓冲区的核心价值在于:中断只负责往缓冲区写数据,主循环或任务从缓冲区读数据,读写通过头尾指针解耦,不会长期阻塞中断。它几乎是所有串口驱动的基本盘。

3. I2C:两根线连接多个设备的“总线式”方案

I2C(Inter-Integrated Circuit,集成电路间总线)是由飞利浦公司提出的一种两线式串行总线,只需要 SCL(时钟线)和 SDA(数据线)两根线,就可以挂载多个设备,通过设备地址区分通信对象。

I2C 最核心的设计思想是“总线 + 地址寻址”。所有设备并联在 SDA 和 SCL 上,主机(Master)发起通信时,先发送一个 7 位或 10 位从机地址,再附带一位读写标志位。从机收到地址后,如果和自己的地址匹配,就回一个 ACK 应答信号。主机和从机之间就这样建立了一次通信会话。

I2C 的物理层要求 SDA 和 SCL 都是开漏输出,必须接上拉电阻。这也是面试高频考点:为什么 I2C 需要上拉电阻?因为开漏输出只能拉低电平,不能主动输出高电平,必须靠上拉电阻把线路拉回高电平。同时,开漏结构也允许多个设备共同驱动这条线,从而实现总线仲裁。

I2C 的通信时序简单概括就是:

  • 起始条件:SCL 高电平时,SDA 从高变低。
  • 数据传输:SCL 高电平期间,SDA 数据必须保持稳定;SCL 低电平期间,SDA 允许变化。
  • 停止条件:SCL 高电平时,SDA 从低变高。

用代码描述一次 I2C 读操作,主设备写入寄存器地址后,再发起读命令。以常用的软件模拟 I2C 为例:

// 文件路径:soft_i2c.c(伪代码,用于理解时序)
static void i2c_start(void)
{
    SDA_HIGH();
    SCL_HIGH();
    delay_us(5);
    SDA_LOW();
    delay_us(5);
    SCL_LOW();
}

static void i2c_stop(void)
{
    SDA_LOW();
    SCL_HIGH();
    delay_us(5);
    SDA_HIGH();
    delay_us(5);
}

uint8_t i2c_write_byte(uin
嵌入式通讯协议核心解析:UART、SPI、I2C、Modbus与CAN的工程实战指南 在嵌入式开发中,通讯协议是连接硬件与逻辑的桥梁,其本质是分层的:从物理层的电平标准、数据链路层的帧结构,到应用层的语义映射,每一层都解决特定问题。理解RS485差分传输为何能抗干扰,SPI与I2C在速率和引脚占用上的取舍,Modbus RTU帧间隔与CRC校验的设计意图,以及CAN总线多主仲裁的机制,远比死记参数更重要。这些协议广泛用于工业控制、汽车电子、智能家居等场景,掌握其工作原理和调试方法,能帮助开发者快速定位乱码、丢帧、总线冲突等实际问题。本文从基础概念出发,结合工程实践经验,系统梳理嵌入式最常用的 阅读详情

相关推荐

嵌入式面试必考:UART、SPI、I2C、RS485、Modbus与CAN协议核心解析

在嵌入式开发与工业控制领域,串行通信是设备间数据交换的基石。工程师不仅需要掌握UART、SPI、I2C等常见总线的基本时序,更要理解物理层、数据链路层与应用层的分层逻辑,才能应对RS485组网、Modbus RTU报文解析、CAN总线仲裁等真实工程场景。通讯协议设计的核心在于帧格式、字节序、CRC校验、超时重传与状态机实现,这些知识既是嵌入式笔试面试的高频考点,也是产品联调中排查乱码、无响应、总线冲突等问题的关键技能。理解差分信号抗干扰原理、开漏上拉机制、主从仲裁机制,并能编写一套可运行的可靠帧收发代码,是

weixin_33377602的博客 264

嵌入式开发必知:五大通信协议(485/CAN/单总线/SPI/I2C)核心对比与实战选型

在嵌入式系统与工业控制领域,通信协议是连接各个功能模块的神经系统,其选型直接决定了系统的稳定性、实时性与成本。从基本原理来看,通信协议定义了设备间数据交换的规则,包括电气特性、数据格式和访问机制。其技术价值在于,通过标准化的方式解决了设备互联的互操作性问题,是构建复杂分布式系统的基石。在应用场景上,不同的协议因其独特的设计哲学而各擅胜场:例如,**SPI**凭借其同步、全双工和主从式架构,在需要高速数据吞吐的板内通信(如连接Flash或显示屏)中表现出色;而**CAN总线**则因其基于优先级的非破坏性仲裁和

weixin_33850890的博客 490

嵌入式开发必知:USART、IIC、SPI、485、CAN五大通讯协议核心对比与实战选型

在嵌入式系统与物联网设备开发中,串行通讯协议是实现芯片间、设备间数据交换的基础。其核心原理在于通过特定的电气标准、时序逻辑与数据帧格式,在有限的硬件资源下,在速度、成本、可靠性与传输距离之间取得平衡。掌握这些协议的技术价值在于能够为传感器数据采集、外设控制、工业总线组网等关键应用场景选择最合适的解决方案。例如,IIC协议以其极简的两线制和多设备管理能力,广泛应用于连接各类传感器和EEPROM;而RS-485则凭借其差分信号带来的强大抗干扰能力和远距离传输特性,成为工业自动化领域仪表组网的物理层支柱。本文将从

weixin_28285943的博客 250

自动化通信协议全解析:从UART到EtherCAT,从BLE到MQTT

通信协议是自动化系统设备间互联互通的共同语言,决定了数据如何建立连接、传输与纠错。从板级UART的异步串口、I2C多设备总线、SPI高速同步通信,到设备级的CAN/CANopen与Modbus,再到工业以太网EtherCAT的微秒级实时同步,每一层协议都有其对应的物理约束与典型场景。无线领域BLE低功耗、WiFi大带宽、Zigbee自组网、LoRa远距离遥测,更是让布线困难的环境有了可靠选择。上位机侧则多借助串口、HTTP与MQTT完成数据采集与远程控制。理解协议背后的原理、适用边界与工程坑点,是自动化工程

weixin_30363285的博客 113

STM32与威纶通触摸屏RS485通信实战:Modbus RTU协议与避坑指南

在工业自动化与嵌入式系统开发中,串行通信是实现设备间数据交换的基础技术。RS485总线凭借其差分信号传输、抗干扰能力强、支持多点通信及长距离传输等特性,成为工业现场广泛应用的物理层标准。其核心原理是利用一对双绞线进行平衡传输,有效抑制共模噪声。在协议层,Modbus RTU作为开放、简洁的主从式应用层协议,定义了统一的数据模型(如线圈、寄存器)和功能码,极大简化了不同厂商设备间的互操作性。结合STM32微控制器的UART外设与威纶通(Weinview)人机界面(HMI),可以构建稳定可靠的监控与控制系统。本

weixin_33925615的博客 324

基于反相器的超声波发生和气泡检测电路

本文主要介绍了关于超声波的两种电路——基于反相器的振荡电路和基于逻辑们的气泡检测电路

xehagy的博客 1948

Plot3d 网格数据格式

PLOT3D是一个计算机图形程序,旨在可视化计算流体力学的网格和解决方案。PLOT3D文件可以是ASCII, 也可是Fortran unformatted 或 C binary形式。PLOT3D文件分为网格文件(XYZ 文件), 空气动力学结果文件 (Q 文件)和通用结果文件(函数文件 + 函数名称文件)。网格文件中可加入所谓的IBlank参数。

weixin_62592231的博客 3714

sentaurus学习笔记(VDMOS仿真)(三)

在Sentaurus中,这通常意味着在2D仿真中,x轴指向下,y轴指向右。定义了在2D模拟中,网格尺寸按照一定的增长率进行扩展,这里的增长率为2.0,意味着远离最小尺寸区域的网格单元大小将是最小尺寸的两倍。定义了2D模拟中网格单元的最小尺寸为0.001微米,这有助于控制网格的最小大小,从而影响仿真的精度和计算成本。表示启用中等级别的日志信息输出,这有助于用户了解仿真过程中发生的事件和可能的问题。表示启用保存调试文件,这可以帮助用户在仿真过程中检查和验证模型的状态。这行代码设置了仿真过程中使用的线程数。

qq_52640792的博客 1800

Buck电源设计常见的一些问题(一)半桥栅极驱动芯片共性失效问题

半桥驱动芯片主要用在器件可应用于电信,数据通信,便携式存储或更低电压系统中的电源转换器,半桥、全桥、推挽、同步降压,正激变换器和同步整流器等方面。当然难免会遇到不少问题。基本上我们在产品开发的过程中都遇到过栅极驱动芯片坏掉的情况,所以找了一些资料,学习学习。也查找查找原因。

小幽余生不加糖 2360

magic-api的鉴权机制配置 (附实战代码)

引入magic-api及相关数据库驱动依赖 配置yml文件和编辑器JS文件 实现登录鉴权逻辑,包括用户验证和Token处理 接口鉴权拦截器设计,确保接口访问安全性 文章提供了完整的代码示例,帮助开发者快速集成magic-api框架并实现权限控制功能。

码农研究僧的博客 219

Debezium报错处理系列之第112篇:Cannot replicate because the master purged required binary logs. Replicate the

Debezium报错处理系列之第112篇:Cannot replicate because the master purged required binary logs.

zhengzaifeidelushang的博客 721

基于潜在空间分数匹配的混合型表格数据合成方法

然而,在我们的模型中,β 预计会更小,因为我们不需要嵌入的分布精确地遵循标准高斯分布,因为我们还有一个额外的扩散模型。受 Transformer 在表格数据分类/回归任务中取得成功的启发,我们首先为每一列学习一个独特的标记器,然后将标记(列)级表示输入到 Transformer 中,以捕捉列之间错综复杂的关系。在第 4 节中,我们证明了通过这种设计,TABSYN 可以在不到 20 次函数评估(NFE)的情况下生成高质量的合成表格数据,这比其他基于扩散的表格数据合成方法要少得多。是标记器的可学习参数。

步子哥的博客 850

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

上一篇: Java搭建MQTT服务端与客户端:从零实现物联网通信链路
下一篇: Tcl/Tk搭建FPGA仿真文件获取界面:波形、日志与归档一键管理
偷浪漫
博客等级 码龄6年 52粉丝 4573原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值