嵌入式系统设计

加粗样式@TOC

一.电路(模拟电路、数字电路、PCB设计)

1.超级电容

错误: 加载主类 com.intellij.idea.Main 时出现 LinkageError
java.lang.UnsupportedClassVersionError: com/intellij/idea/Main has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0

2.模拟电路

2.1.半导体器件

2.1.1.PN结
2.1.2.二极管,晶体三极管

2.2.基本放大电路

2.3.集成运算放大器

2.3.1.信号产生
2.3.2.波形产生

3.数字电路

4.PCB

二.处理器 (51单片机、STM32(寄存器,标准库,hal库)、树莓派、CH32、FPGA口袋机)

1.51单片机

2.stm32f407(寄存器编程,库函数编程)

3.树莓派

4.ch32(沁恒)

5.stm32h7系列驱动电机,跑视觉算法

6.TI

三.接口模块(传感器、物联网、PID电机控制)

1.红外避障模块(红外循迹)

1.1 原理与接口定义

该传感器模块对环境光线适应能力强,其具有一对红外线发射与接收管,发射管发射出一定频率的红外线,当检测方向遇到障碍物(反射面)时,红外线反射回来被接收管接收,经过比较器电路处理之后,绿色指示灯会亮起,同时信号输出接回输出数字信号(一个低电平信号),可通过电位器旋钮调节检测距离,有效距离范围2~30cm,工作电压为3.3v-5v。该传感器的探测距离可以通过电位器调节、具有干扰小、便于装配、使用方便等特点,可以广泛应用于机器人避障、避障小车、流水线计数及黑白线循迹等众多场合。

模块参数

当模块检测到前方障碍物信号时,电路板上绿色指示灯点亮,同时OUT端口持续输出低电平信号
该模块测距离2~~30cm,检测角度35°,检测距离可以通过电位器进行调节,顺时针调电位器,检测距离增加;逆时针调电位器,检测距离减少。
传感器主动红外线反射探测,因此目标的反射率和形状是探测距离的关键。其中黑色探测距离小,白色大;小面积物体距离小,大面积距离大。
传感器模块输出端口OUT可直接与单片机IO口连接即可,也可以直接驱动一个5v继电器
比较器采用LM393,工作稳定;
可采用3-5v直流电源对模块进行供电。当电源接通时,红色电源指示灯点亮;
具有3mm的螺丝孔,便于固定、安装;
电路板尺寸:3.2CM*1.4CM
每个模块在发货已经将阈值比较电压通过电位器调节好,非特殊情况,请勿随意调节电位器。

接口说明

1.VCC外接3.3v-5v电压(可以直接与5v单片机和3.3v单片机相连)
2、GND 外接GND
3、OUT小板数字量输出接口(0和1)

手册说明

TCRT5000传感器的红外发射二极管不断发射红外线 ,当发射出的红外线没有被反射回来或被反射回来但强度不够大时, 红外接收管一直处于关断状态,此时模块的输出端为高电平,指示二极管一直处于熄灭状态, 被检测物体出现在检测范围内时,红外线被反射回来且强度足够大,红外接收管饱和, 此时模块的输出端为低电平,指示二极管被点亮

总结就是一句话
没反射——D0输出高电平——灭灯
反射——D0输出低电平——亮灯

原文链接

2. 灰度传感器(7路模拟量)

3.TB6612 霍尔编码器电机(融合PID算法,速度环,位置环,角度环,转向环)

3.1.编码器脉冲数读取(2分频,4分频)

3.2.PID算法对脉冲数进行运算处理

3.3.PID参数调试

3.4.电机转动效果对比

4.mpu6050(融合PID控制电机)

4.1数据读取显示

4.2数据处理(融合PID算法)

5.多路舵机驱动板(总线,PWM)(幻尔)

5.1多舵机间隔控制,上位机调试角度

5.2串口通信,单片机控制驱动板

6.显示器模块(oled(IIC,SPI),tft)

7.超声波模块

四.视觉与图像算法

1.openmv数字识别

2.openmv图像识别(迷宫地图,颜色识别)

3.python图像生成

3.openmv黑线识别(k210)

五.算法设计调试(PID,模拟退火,蚁群算法)

1.模拟退火算法最短路径规划(迷宫问题)

六.外观设计(solidworks建模、3D打印、组装调试)

1.二维图纸生成三维模型

2.三维转二维,模型生成爆炸视图,渲染

3.Altair轻量化设计

3.1.拓扑优化-最佳材料分布

3.2.静力学分析

3.3.几何重构

七.操作系统(LINUX,ROS,FREERTOS,RTT)

1.freertos

2.linux

├── bin -> usr/bin # 用于存放二进制命令
├── boot # 内核及引导系统程序所在的目录
├── dev # 所有设备文件的目录(如磁盘、光驱等)
├── etc # 配置文件默认路径、服务启动命令存放目录
├── home # 用户家目录,root用户为/root
├── lib -> usr/lib # 32位库文件存放目录
├── lib64 -> usr/lib64 # 64位库文件存放目录
├── media # 媒体文件存放目录
├── mnt # 临时挂载设备目录
├── opt # 自定义软件安装存放目录
├── proc # 进程及内核信息存放目录
├── root # Root用户家目录
├── run # 系统运行时产生临时文件,存放目录
├── sbin -> usr/sbin # 系统管理命令存放目录
├── srv # 服务启动之后需要访问的数据目录
├── sys # 系统使用目录
├── tmp # 临时文件目录
├── usr # 系统命令和帮助文件目录
└── var # 存放内容易变的文件的目录
pwd				查看当前工作目录
clear 			清除屏幕
cd ~			当前用户目录
cd /			根目录
cd -			上一次访问的目录
cd ..			上一级目录
ll				查看当前目录下内容(LL的小写)
mkdir aaa		在当前目录下创建aaa目录,相对路径;
mkdir ./bbb		在当前目录下创建bbb目录,相对路径;
mkdir /ccc		在根目录下创建ccc目录,绝对路径;
mkdir -p temp/nginx 
find / -name 'b'		查询根目录下(包括子目录),名以b的目录和文件;
find / -name 'b*'		查询根目录下(包括子目录),名以b开头的目录和文件; 
find . -name 'b'		查询当前目录下(包括子目录),名以b的目录和文件;
mv 原先目录 文件的名称   mv tomcat001 tomcat 
mv	/aaa /bbb		    将根目录下的aaa目录,移动到bbb目录下(假如没有bbb目录,则重命名为bbb);
mv	bbbb usr/bbb		将当前目录下的bbbb目录,移动到usr目录下,并且修改名称为bbb;
mv	bbb usr/aaa			将当前目录下的bbbb目录,移动到usr目录下,并且修改名称为aaa;
cp -r /aaa /bbb			将/目录下的aaa目录复制到/bbb目录下,在/bbb目录下的名称为aaa
cp -r /aaa /bbb/aaa		将/目录下的aa目录复制到/bbb目录下,且修改名为aaa;
rm -rf /bbb			强制删除/目录下的bbb目录。如果bbb目录中还有子目录,也会被强制删除,不会提示;
rm -r /bbb			普通删除。会询问你是否删除每一个文件
rmdir test01		目录的删除
tree test01/
查看树状目录结构

3.ros

3.1 ros基础

3.1.1 ros基础
3.1.1.1 新建ws,vscode启动
mkdir -p ws/src
cd ws
catkin_make
code .//.是当前ws空间文件
3.1.1.2 新建功能包并添加依赖
添加依赖roscpp,rospy,msgs
working_ws
src
build
devel
pkg1
pkg2
src
CmakeLists.txt
launch
.launch
include
scripts
.py
.h
node1.cpp
node2.cpp
add_executable node src/node.cpp
target_link_libraries node catkin_LIBRARIES
cpp文件配置*2
3.1.1.3 ros基本命令操作

//vscode编译

ctrl+shift+B

//启动节点,launch文件

rosrun pkg node 
roslaunch pkg .launch

//查看节点之间关系

rqt_graph
3.1.2 C++基础
3.1.3 话题通信
3.1.3.1发布方
#include "ros/ros.h"
#include "std_msgs/String.h" //普通文本类型的消息
#include 

int main(int argc, char  *argv[])
{   
    //设置编码
    setlocale(LC_ALL,"");

    //2.初始化 ROS 节点:命名(唯一)
    // 参数1和参数2 后期为节点传值会使用
    // 参数3 是节点名称,是一个标识符,需要保证运行后,在 ROS 网络拓扑中唯一
    ros::init(argc,argv,"talker");
    //3.实例化 ROS 句柄
    ros::NodeHandle nh;//该类封装了 ROS 中的一些常用功能

    //4.实例化 发布者 对象
    //泛型: 发布的消息类型
    //参数1: 要发布到的话题
    //参数2: 队列中最大保存的消息数,超出此阀值时,先进的先销毁(时间早的先销毁)
    ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",10);

    //5.组织被发布的数据,并编写逻辑发布数据
    //数据(动态组织)
    std_msgs::String msg;
    // msg.data = "你好啊!!!";
    std::string msg_front = "Hello 你好!"; //消息前缀
    int count = 0; //消息计数器

    //逻辑(一秒10次)
    ros::Rate r(1);

    //节点不死
    while (ros::ok())
    {
        //使用 stringstream 拼接字符串与编号
        std::stringstream ss;
        ss << msg_front << count;
        msg.data = ss.str();
        //发布消息
        pub.publish(msg);
        //加入调试,打印发送的消息
        ROS_INFO("发送的消息:%s",msg.data.c_str());

        //根据前面制定的发送贫频率自动休眠 休眠时间 = 1/频率;
        r.sleep();
        count++;//循环结束前,让 count 自增
        //暂无应用
        ros::spinOnce();
    }


    return 0;
}
3.1.3.2订阅方
#include "ros/ros.h"
#include "std_msgs/String.h"

void doMsg(const std_msgs::String::ConstPtr& msg_p){
    ROS_INFO("我听见:%s",msg_p->data.c_str());
    // ROS_INFO("我听见:%s",(*msg_p).data.c_str());
}
int main(int argc, char  *argv[])
{
    setlocale(LC_ALL,"");
    //2.初始化 ROS 节点:命名(唯一)
    ros::init(argc,argv,"listener");
    //3.实例化 ROS 句柄
    ros::NodeHandle nh;

    //4.实例化 订阅者 对象
    ros::Subscriber sub = nh.subscribe<std_msgs::String>("chatter",10,doMsg);
    //5.处理订阅的消息(回调函数)

    //     6.设置循环调用回调函数
    ros::spin();//循环读取接收的数据,并调用回调函数处理

    return 0;
}
3.1.3.3自定义msg消息格式

1.定义msg文件:功能包下新建 msg 目录,添加文件 Person.msg

string name
uint16 age
float64 height

2.package.xml中添加编译依赖与执行依赖,CMakeLists.txt编辑 msg 相关配置

  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>
  <!-- 
  exce_depend 以前对应的是 run_depend 现在非法
  -->

message_generation表示在构建期间需要使用message_generation包来生成目标代码(通常为C++或Python)。这个标签告诉catkin,当构建依赖它的包时,需要首先确保安装了message_generation包。

message_runtime表示在运行时需要这个包的支持。message_runtime包包含用于运行时(或称为“部署”时)使用的存储格式,消息描述和转换函数。由于任何需要访问ROS话题和服务的节点都必须能够解析和发布特定消息类型的实例,因此在运行节点时需要安装此包。

message_generation是一个ROS(机器人操作系统)软件,它提供了在ROS中生成自定义消息的工具。在ROS中,消息是指一组结构化数据,通过ROS话题(topic)进行传输。每个消息都有一个特定的格式(描述)和转换函数(注意,这里的“消息”不是网络通信协议中的“消息”)。

message_generation包包含了生成自定义消息的工具,主要是依据msg文件生成相应的源码和文件(例如,C++头和Python脚本)。当用户用户定义了新的消息结体时,使用此工具根据此结构体创建新的消息类型,并在ROS系统中使用它。

需要说明的是,如果想要使用自己创建的消息类型还需要安装message_runtime包因为发布节点和订阅节点需要能够解析新消息类型以接受和处理该消息。

3.CMakeLists.txt编辑 msg 相关配置

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)
# 需要加入 message_generation,必须有 std_msgs

## 配置 msg 源文件
add_message_files(
  FILES
  Person.msg
)

# 生成消息时依赖于 std_msgs
generate_messages(
  DEPENDENCIES
  std_msgs
)

```c
#执行时依赖
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES demo02_talker_listener
  CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
#  DEPENDS system_lib
)

4.将前面生成的 head 文件路径配置进 c_cpp_properties.json 的 includepath属性:

{
  "configurations": [
    {
      "browse": {
        "databaseFilename": "${default}",
        "limitSymbolsToIncludedHeaders": false
      },
      "includePath": [
        "/opt/ros/melodic/include/**",
        "/home/lzl/class_one_ws/src/class_one_pkg/include/**",
        "/home/lzl/usb_cam_ws/src/usb_cam/include/**",
        "/usr/include/**",
        "/home/lzl/ros_ws/devel/include/**" //配置 head 文件的绝对路径
      ],
      "name": "ROS",
      "intelliSenseMode": "gcc-x64",
      "compilerPath": "/usr/bin/gcc",
      "cStandard": "gnu11",
      "cppStandard": "c++14"
    }
  ],
  "version": 4
}

每个功能包的msg对应生成的.h消息文件只能在一个功能包下使用,跟路径有关
使用rosmsg package 包名 列出某个功能包下的msg
嵌入式系统设计_第1张图片运行launch文件验证msg消息头文件的调用以及多个节点之间的通信
嵌入式系统设计_第2张图片

3.1.4 服务通信
3.1.4.1服务方
#include "ros/ros.h"
#include "demo03_server_client/AddInts.h"

// bool 返回值由于标志是否处理成功
bool doReq(demo03_server_client::AddInts::Request& req,
          demo03_server_client::AddInts::Response& resp){
    int num1 = req.num1;
    int num2 = req.num2;

    ROS_INFO("服务器接收到的请求数据为:num1 = %d, num2 = %d",num1, num2);

    //逻辑处理
    if (num1 < 0 || num2 < 0)
    {
        ROS_ERROR("提交的数据异常:数据不可以为负数");
        return false;
    }

    //如果没有异常,那么相加并将结果赋值给 resp
    resp.sum = num1 + num2;
    return true;


}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    // 2.初始化 ROS 节点
    ros::init(argc,argv,"AddInts_Server");
    // 3.创建 ROS 句柄
    ros::NodeHandle nh;
    // 4.创建 服务 对象
    ros::ServiceServer server = nh.advertiseService("AddInts",doReq);
    ROS_INFO("服务已经启动....");
    //     5.回调函数处理请求并产生响应
    //     6.由于请求有多个,需要调用 ros::spin()
    ros::spin();
    return 0;
}
3.1.4.2客户端
#include "ros/ros.h"
#include "demo03_server_client/AddInts.h"

// bool 返回值由于标志是否处理成功
bool doReq(demo03_server_client::AddInts::Request& req,
          demo03_server_client::AddInts::Response& resp){
    int num1 = req.num1;
    int num2 = req.num2;

    ROS_INFO("服务器接收到的请求数据为:num1 = %d, num2 = %d",num1, num2);

    //逻辑处理
    if (num1 < 0 || num2 < 0)
    {
        ROS_ERROR("提交的数据异常:数据不可以为负数");
        return false;
    }

    //如果没有异常,那么相加并将结果赋值给 resp
    resp.sum = num1 + num2;
    return true;


}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    // 2.初始化 ROS 节点
    ros::init(argc,argv,"AddInts_Server");
    // 3.创建 ROS 句柄
    ros::NodeHandle nh;
    // 4.创建 服务 对象
    ros::ServiceServer server = nh.advertiseService("AddInts",doReq);
    ROS_INFO("服务已经启动....");
    //     5.回调函数处理请求并产生响应
    //     6.由于请求有多个,需要调用 ros::spin()
    ros::spin();
    return 0;
}

3.1.4.3服务方自定义srv

//定义srv文件

# 客户端请求时发送的两个数字
int32 num1
int32 num2
---
# 服务器响应发送的数据
int32 sum

//编辑配置文件
package.xml中添加编译依赖与执行依赖

  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>
  <!-- 
  exce_depend 以前对应的是 run_depend 现在非法
  -->

CMakeLists.txt编辑 srv 相关配置

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)
# 需要加入 message_generation,必须有 std_msgs

add_service_files(
  FILES
  AddInts.srv
)

generate_messages(
  DEPENDENCIES
  std_msgs
)

3.1.4.4launch文件
<launch>
    <!--启动的节点-->
    <node pkg="topic_pkg" type="talker" name="talker_node1" output="screen" />
    <!--键盘控制节点-->
    <node pkg="topic_pkg" type="listener" name="listener_node1" output="screen" />
</launch>

3.1.5 参数服务器
3.1.6 坐标变换
3.1.6.1 geometry_msgs

常用的消息包消息:
geometry_msgs/TransformStamped消息类型包含了发送者与接收者之间的变换信息,包括变换的起点和终点、变换的旋转和平移矩阵等信息。
geometry_msgs/TransformStamped

std_msgs/Header header                     #头信息
  uint32 seq                                #|-- 序列号
  time stamp                                #|-- 时间戳
  string frame_id                            #|-- 坐标 ID
string child_frame_id                    #子坐标系的 id
geometry_msgs/Transform transform        #坐标信息
  geometry_msgs/Vector3 translation        #偏移量
    float64 x                                #|-- X 方向的偏移量
    float64 y                                #|-- Y 方向的偏移量
    float64 z                                #|-- Z 方向上的偏移量
  geometry_msgs/Quaternion rotation        #四元数
    float64 x                                
    float64 y                                
    float64 z                                
    float64 w

geometry_msgs/PointStamped消息类型则表示在3D空间中的一个点的坐标信息,包含了这个点在XYZ三个方向上的坐标位置以及时间戳信息,常用于目标检测、位置识别等任务中。
geometry_msgs/PointStamped

std_msgs/Header header                    #头
  uint32 seq                                #|-- 序号
  time stamp                                #|-- 时间戳
  string frame_id                            #|-- 所属坐标系的 id
geometry_msgs/Point point                #点坐标
  float64 x                                    #|-- x y z 坐标
  float64 y
  float64 z

rosmsg info

3.1.6.2 静态坐标变换实现

坐标变换通过发布订阅模型
功能包的依赖

find_package(catkin REQUIRED COMPONENTS
  geometry_msgs
  roscpp
  rospy
  std_msgs
  tf2
  tf2_geometry_msgs
  tf2_ros
)

发布方

/* 
    静态坐标变换发布方:
        发布关于 laser 坐标系的位置信息 

    实现流程:
        1.包含头文件
        2.初始化 ROS 节点
        3.创建静态坐标转换广播器
        4.创建坐标系信息
        5.广播器发布坐标系信息
        6.spin()
*/


// 1.包含头文件
#include "ros/ros.h"
#include "tf2_ros/static_transform_broadcaster.h"
#include "geometry_msgs/TransformStamped.h"
#include "tf2/LinearMath/Quaternion.h"

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    // 2.初始化 ROS 节点
    ros::init(argc,argv,"static_brocast");
    // 3.创建静态坐标转换广播器
    tf2_ros::StaticTransformBroadcaster broadcaster;
    // 4.创建坐标系信息
    geometry_msgs::TransformStamped ts;
    //----设置头信息
    ts.header.seq = 100;
    ts.header.stamp = ros::Time::now();
    ts.header.frame_id = "base_link";
    //----设置子级坐标系
    ts.child_frame_id = "laser";
    //----设置子级相对于父级的偏移量
    ts.transform.translation.x = 0.2;
    ts.transform.translation.y = 0.0;
    ts.transform.translation.z = 0.5;
    //----设置四元数:将 欧拉角数据转换成四元数
    tf2::Quaternion qtn;
    qtn.setRPY(0,0,0);
    ts.transform.rotation.x = qtn.getX();
    ts.transform.rotation.y = qtn.getY();
    ts.transform.rotation.z = qtn.getZ();
    ts.transform.rotation.w = qtn.getW();
    // 5.广播器发布坐标系信息
    broadcaster.sendTransform(ts);
    ros::spin();
    return 0;
}

订阅方

/*  
    订阅坐标系信息,生成一个相对于 子级坐标系的坐标点数据,转换成父级坐标系中的坐标点

    实现流程:
        1.包含头文件
        2.初始化 ROS 节点
        3.创建 TF 订阅节点
        4.生成一个坐标点(相对于子级坐标系)
        5.转换坐标点(相对于父级坐标系)
        6.spin()
*/
//1.包含头文件
#include "ros/ros.h"
#include "tf2_ros/transform_listener.h"
#include "tf2_ros/buffer.h"
#include "geometry_msgs/PointStamped.h"
#include "tf2_geometry_msgs/tf2_geometry_msgs.h" //注意: 调用 transform 必须包含该头文件

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    // 2.初始化 ROS 节点
    ros::init(argc,argv,"tf_sub");
    ros::NodeHandle nh;
    // 3.创建 TF 订阅节点
    tf2_ros::Buffer buffer;
    tf2_ros::TransformListener listener(buffer);

    ros::Rate r(1);
    while (ros::ok())
    {
    // 4.生成一个坐标点(相对于子级坐标系)
        geometry_msgs::PointStamped point_laser;
        point_laser.header.frame_id = "laser";
        point_laser.header.stamp = ros::Time::now();
        point_laser.point.x = 1;
        point_laser.point.y = 2;
        point_laser.point.z = 7.3;
    // 5.转换坐标点(相对于父级坐标系)
        //新建一个坐标点,用于接收转换结果  
        //--------------使用 try 语句或休眠,否则可能由于缓存接收延迟而导致坐标转换失败------------------------
        try
        {
            geometry_msgs::PointStamped point_base;
            point_base = buffer.transform(point_laser,"base_link");
            ROS_INFO("转换后的数据:(%.2f,%.2f,%.2f),参考的坐标系是:",point_base.point.x,point_base.point.y,point_base.point.z,point_base.header.frame_id.c_str());

        }
        catch(const std::exception& e)
        {
            // std::cerr << e.what() << '\n';
            ROS_INFO("程序异常.....");
        }


        r.sleep();  
        ros::spinOnce();
    }


    return 0;
}

嵌入式系统设计_第3张图片

第一个节点是一个 ROS 节点,它使用 tf2_ros 库实现了静态坐标变换发布方,可以发布关于 laser 坐标系的位置信息。该节点通过在创建 geometry_msgs::TransformStamped 类型的消息并填充相关信息(包括头信息、子级坐标系、相对于父级坐标系的偏移量和四元数)来定义所需的坐标系信息,并使用 tf2_ros::StaticTransformBroadcaster 类型的广播器来广播坐标系信息。

第二个节点是另一个 ROS 节点,它使用 tf2_ros 库实现了订阅坐标系信息,生成一个相对于子级坐标系的坐标点数据,并将其转换成父级坐标系中的坐标点。该节点通过使用 tf2_ros::TransformListener 类型的订阅节点来监听 base_link 和 laser 坐标系之间的坐标转换,并在程序中用 geometry_msgs::PointStamped 类型的消息存储相对于 laser 坐标系的坐标点的信息。 然后,该节点通过调用 tf2_geometry_msgs 库中的 transform 函数将坐标点中相对于 laser 坐标系的数据转换为相对于 base_link 坐标系的数据,并输出转换后的数据和参考坐标系的信息。最后,该节点在 while 循环中使用 ros::Rate 对象设置相应的循环频率,并使用 ros::spinOnce() 来处理未处理的 ROS 消息,从而实现节点的运行。

3.1.6.3 动态坐标变换实现
3.1.6.4 多坐标变换实现
3.1.7 机器人仿真

//urdf
//gazebo
//xacro

3.2 宇树机械狗

3.3 slam

4.rt-thead

4.1.STM32H7融合rt-thead驱动电机

4.2 lvgl

八.系统设计 (通信原理(SPI,IIC,USART,RS485)、信号处理、人工智能、自控原理等)

1.SPI

2.IIC

3.USART(USRT)

4.RS485,232

5.机器学习,速度学习,神经网络

5.1 STM32平台搭建神经网络模型

九.开发与调试(基本仪器仪表使用、焊接或者模块组装、系统分析能力)

十. 软件开发(EDA、C语言、云端编程、Android、IOS)

你可能感兴趣的:(stm32,嵌入式硬件,物联网,单片机)