“告别检测系统能力缺陷!10+年LabVIEW视觉资深专家手把手教你:5000+分钟高清教程(含工具、算法原理、实战操作、项目优化全流程讲解)”——从传统视觉算法→深度学习建模→工业级部署"
2025-12-30 08:06:30
67 
在现代工业自动化中,PLC远程控制功能越来越重要,尤其是在设备分布广泛或环境复杂的场景中。通过无线通信技术,可以实现PLC的远程控制,显著提高生产效率和运维便捷性。本文将详细介绍基于无线的PLC远程控制设置方法。 以DTD418MB 实现组态王对AB820 PLC 的远程无线控制为例。 一、硬件连接 将上位机与 DTD418MB 通过通讯线连接,一端接入 DTD418MB 的 RJ45 接口,另一端接入上位机的 RJ45 接口; 同样,用通讯线将 PLC 与 DTD418MB 连接,一端接入 DTD418MB 的
2025-12-24 11:36:55
95 
中小工厂砸几十万搞智能改造,结果踩了最冤的坑:花 “智慧工厂系统” 的钱,买的只是个 “升级款工厂监控系统”—— 只能看设备转不转,没法调生产、降能耗,钱直接打了水漂。智能改造选系统,真的像开盲盒?其实只要搞懂核心区别,再找对工具,就能避开 “花大钱买错工具” 的坑 —— 有人物联网就是中小厂的 “智能改造避坑指南库” 。 一、智能改造最易踩的坑:系统认错,钱白扔 很多厂刚入门时,都会把这俩核心系统搞混: 智慧工厂系
2025-12-19 14:20:21
137 
一、文字教程简介本教程旨在演示EWD22S-A01TR的正确接线方法。材料准备EWD22S-A01TR一台220V交流电源一根220V交流电灯一台433M天线一根接线步骤电源输入端连接将220V交流电源火线与EWD22S-A01TR的电源输入L端连接将220V交流电源零线与EWD22S-A01TR的电源输入N端连接电灯输出端连接将220V交流电灯火线与E
2025-12-11 19:33:48
192 
不同的开发环境,设置方法也各不相同。本文将手把手教你如何在主流的CS+for CC、e2studio和IAR Embedded Workbench中完成这两项重要配置。
2025-12-11 16:33:20
4263 
你是否在选购SG三相隔离变压器时感到迷茫,担心选错型号导致能效低下或设备损坏?对于设备维护人员和采购者来说,错误选择不仅浪费资金,更可能带来持续的运维问题。今天,我们从专业角度出发,手把手教你
2025-12-11 15:47:41
213 
在电商竞争日益激烈的今天,掌握商品价格动态已成为商家制定灵活定价策略的关键。本文将手把手教你如何通过京东API实现实时价格监控,为您的商业决策提供数据支撑。 一、京东API的价值解析 京东开放平台
2025-12-09 17:36:26
781 
视觉算子详解》一书;开发了《龙哥手把手教你学视觉》系列包含视觉、运动控制、深度学习在内的全套5000+分钟视频教程。
发烧友官方统计累计学员达20000余人,部分学员现任职于华为、比亚迪、富士康等头部
2025-12-04 09:28:20
视觉算子详解》一书;开发了《龙哥手把手教你学视觉》系列包含视觉、运动控制、深度学习在内的全套5000+分钟视频教程。
发烧友官方统计累计学员达20000余人,部分学员现任职于华为、比亚迪、富士康等头部
2025-12-03 13:50:14
“告别检测系统能力缺陷!10+年LabVIEW视觉资深专家手把手教你:5000+分钟高清教程(含工具、算法原理、实战操作、项目优化全流程讲解)”——从传统视觉算法→深度学习建模→工业级部署"
2025-12-02 08:07:22
310 
当我们谈论“智能工厂”时,许多传统企业的管理者第一反应是:推倒重来,投资千万,周期漫长,望而却步。但这其实是一个巨大的误解! 智能化的本质是“赋能”,而非“替代” 。本文将为你揭秘,如何利用成熟可靠的工业互联网技术,像给老汽车安装“自动驾驶套件”一样,让你的传统工厂实现低成本、高效率的“赛博重生”! 一、灵魂拷问:为什么要改造?目标在哪? 改造不是跟风,而是为了解决切肤之痛。在动工前,必须先进行灵魂拷问:
2025-11-25 16:51:42
355 
迅为Hi3403开发板极速启航 | 手把手带你玩转核心例程,轻松上手AI视觉!
2025-11-19 13:56:08
1537 
【迅为RK3568开发板NPU实战】别再闲置你的NPU!手把手教你玩转RKNN-Toolkit2 的使用
2025-11-11 14:21:10
696 
对智慧视觉领域感兴趣,或是行业从业者注意啦!11月13日20:00,RT-Thread携手富瀚微技术专家,为您带来FH8626V300L全栈开发实战线上直播,手把手带你从芯片解读到RT-Thread
2025-11-11 11:53:35
628 
【RK3568 NPU实战】别再闲置你的NPU!手把手带你用迅为资料跑通Android AI检测Demo,附完整流程与效果
2025-11-10 15:58:29
942 
《手把手教你设计CPU》书上运行Verilog仿真测试那章说为了重现仿真环境,最好在Linux环境下。不知道移植蜂鸟是否需要在Linux环境下,直接在Windows操作系统可否移植开发。
2025-11-10 07:42:13
前提条件:
1)开发板是Digilent的ARTY A7-35T开发版,也就是《手把手教你设计CPU-RISC-V处理器》中介绍的那块板子
2)vivado安装正常,可以启动,跑make mcs
2025-11-07 06:05:07
想用ESP32-S3开发板驱动无刷电机却不知从何下手?本教程将手把手教你完成从硬件连接到软件编程的全流程,无论你是新手还是有一定经验的开发者,都能轻松掌握!本教程代码已全部开源!后台私信关键词
2025-11-06 18:03:59
457 
想要快速掌握LuatOS GNSS定位调试?本文将以手把手的方式,带领您一步步完成调试流程。无论您是初学者还是有一定经验的开发者,这份实用操作指南都能帮助您有效提升调试效率,确保定位功能稳定可靠
2025-11-04 18:30:08
1323 
你是否也遇到过这些困扰:电脑突然变得异常卡顿,程序无响应?想知道电脑状态,却懒得每次都打开任务管理器?想要实时监控系统性能,又没有合适的工具?别担心!今天我们教你一个简单又低成本的方法——用
2025-11-04 18:05:07
403 
最近发布的202102版本的Nuclei Studio IDE增加了QEMU仿真器,可支持RV-STAR开发板的仿真,本教程旨在介绍如何使用该仿真环境进行RISC-V嵌入式开发。
系统环境
Windows 10-64bit
软件平台
Nuclei Studio IDE 202102版
Nuclei Studio的下载和安装
在芯来科技官网文档与工具页面可以下载 Nuclei Studio IDE软件,其链接如下:
https://www.nucleisys.com/download.php
根据自己的操作系统下载对应的文件即可,IDE不需要安装,下载后直接解压缩即可使用;
启动Nuclei Studio
在 Nuclei Studio 解压缩的目录下双击 NucleiStudio.exe 即可启动 IDE;第一次启动 Nuclei Studio 将会弹出对话框要求设置 Workspace 目录路径,该目录将用于存放后续创建的项目工程文件。设置好 Workspace 路径,再单击 “Launch” 启动 Nuclei Studio;启动后页面如下图,推荐打开 Launch Bar 功能,方便快速编译和调试。打开菜单栏 “Window -> Preferences”,搜索 “bar”,勾选第一个选项 “Enable the Launch Bar”即可启用 Launch Bar 功能。下滑查看更多
新建模板helloworld工程
在菜单栏中,选择 “File-> New -> C/C++ Project” 开始新建工程,在弹窗中双击选择 “C Managed Build” ;
新的页面中 “Project name” 填写 “helloworld” , “Project type”选择 “Nuclei SDK Project For GD32VF103 SoC” 和 “RISC-V Cross GCC” ,如下图,点击 “Next” 。新的页面不用修改,直接点击 “Next” 即可;
我们在选择 Board 时,请记得一定要选 gd32vf103v_rvstar 这块板子噢!
在选择模板工程页面修改“Project Example”选项为“baremetal_helloworld”。
后续页面不需要修改,点击“Next”直到最后一页,点击“Finish”完成新建模板helloworld工程。最终IDE界面显示如下:
调试helloworld
在Launch Bar可以看到有两个配置如下图
我们看一下QEMU的配置,这些已经配置好了,如果不太了解的同学,这里基本上可以不用进行任何设置。
然后选中 debug 模式并启动 debug
编译器对代码进行编译后,会跳出 Switch 框,选 Switch 后进入调试模式
调试模式的界面如下
IDE提供了丰富的调试工具,具体的就不一一介绍了,大家可以去尝试。
虽然是在QEMU仿真环境下,但应用的还是gdb调试工具,所以也是支持gdb命令行调试的,选中Debugger Console,就可以输入gdb命令了。
我们可以查看一下仿真环境下的寄存器。结果如下图,更多命令使用大家可以自行查阅gdb的使用手册。
当然,也可以在图形界面中查看寄存器。
在工具栏选 :
Window ->Show View ->Registers
在弹出的 Registers 框中,就可以非常方便的查看寄存器信息。我们可以在调试过程中查看相关信息的变化。
运行helloworld
在调试模式下代码无bug,我们可以直接运行代码查看运行结果,在run程序前,一定要将之前启动的QEMU结束掉,不管是openOCD还是QEMU的进程都是排它性,所以运行或者调试结束后,一定要记得点关闭按钮。不然后报错如下图:
结束QEMU依次点下面三个按钮,确保进程已结束。
结束调试后开始运行前,建议clean一下工程,在工程名上左键->clean Project,IDE就会帮您清除掉编译生成的编译文件。
直接点运行,就可以了看到IDE开始编译代码并运行,如果代码正确,就会输出代码的结果。
下滑查看更多
在没有连接板子的情况下,我们成功运行了helloworld程序。
至此,在Nuclei Studio中基于QEMU进行嵌入式代码开发和调试的介绍就结束了。
2025-10-31 08:54:30
上期内容讲解了UART串口通信的应用方法,本期内容的主角是另一种嵌入式系统中常用的通信协议——I²C(Inter-Integrated Circuit)。本期内容将带领大家使用RV-STAR开发板来控制OLED液晶屏显示不同的字符和图像,从而初步了解I²C总线通信的应用方法。
系统环境
Windows 10-64bit
软件平台
[size=14.6667px]NucleiStudio IDE 202102版或PlatformIO IDE
硬件需求
RV-STAR开发板、
0.96英寸OLED显示屏(I2C接口)
I²C协议介绍
I²C是由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接微控制器及其外围芯片,目前已成为一种行业标准,在微控制器设计中被大量采用,在RV-STAR所使用的GD32VF103微控制器上也集成了I²C接口。
I²C总线的主要特点是接线简单,硬件上只需两条线,一根SCL时钟线用于收发双方的时钟节拍,一根SDA数据线负责传输数据,因此I²C是一种同步通信。
I²C可以挂载多个参与通信的器件,即多机模式,且任何一个器件都可以作为主机,在多数情况下由微控制器作为主机,在本次的实验中也是如此。
I²C的数据传输流程和UART具有相似之处,包括起始信号、数据传输和停止信号,其中和UART不同的地方在于,数据传输的字节数没有限制,可以一次传输很多个字节,每个字节后跟有一个应答位(即ACK),有点类似于UART的停止位。
I²C在应用时,在发送了起始信号(Start)后,要先发送一个7位的从机地址,紧跟着的第8位是数据方向位(R/W),“0”表示接下来要发送数据,“1”表示接下来要读数据。当发送完这个8个位后,如果发送的地址有设备存在,这个设备应该回复一个ACK(拉低SDA,输出“0”),这样才会继续进行通信流程。
OLED液晶屏介绍
OLED(Organic Light-Emitting Diode,有机发光二极管)因为具备轻薄、省电、显示效果好等特性,被广泛应用手机、音乐播放器等电子设备中。
本次实验用到的OLED液晶屏参数如下:
尺寸0.96英寸
分辨率128*64
可视角度大于160°
功耗0.06w
供电范围3.3v~5v
工作温度-30℃~70℃
体积27mm*27mm*2mm
亮度可通过指令控制
驱动芯片SSD1306
接口I2C
GD32VF103的I²C接口
GD32VF103的I²C(内部集成电路总线)模块提供了符合工业标准的两线串行制接口,可用于MCU和外部I²C设备的通讯。I²C总线使用两条串行线:串行数据线SDA和串行时钟线SCL。I²C接口模块实现了I²C协议的标速模式(最高100KHz)和快速模式(最高400KHz),具备CRC计算和校验功能,支持SMBus(系统管理总线)和 PMBus(电源管理总线)。此外还支持多主机I²C总线架构。I²C接口模块也支持DMA模式,可有效减轻CPU的负担。
更详细内容请参考《GD32VF103用户手册》。
实验部分
首先需要将RV-STAR开发板及OLED显示屏参照下图使用杜邦线进行连线:
然后在IDE中进行代码编写,在使用I²C接口的时候,首先要对其进行初始化:先使能外设时钟,然后将SDA、SCL两个引脚配置为开漏模式,之后需要依次设置I²C的时钟速率、地址,然后使能I²C和ACK。其相关代码如下:
[size=0.85em]void I2C_Configuration(void)
{
uint32_t GPIO_SDA, GPIO_SCL;
uint32_t GPIO_PIN_SDA, GPIO_PIN_SCL;
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_I2C1);
GPIO_SDA = GPIOB;
GPIO_PIN_SDA = GPIO_PIN_11;
GPIO_SCL = GPIOB;
GPIO_PIN_SCL = GPIO_PIN_10;
gpio_init(GPIO_SCL, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_SCL);
gpio_init(GPIO_SDA, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_SDA);
i2c_clock_config(I2C1, 400000, I2C_DTCY_2);
i2c_mode_addr_config(I2C1, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x30);
i2c_enable(I2C1);
i2c_ack_config(I2C1, I2C_ACK_ENABLE);
}
在本次实验中,由于使用的是“主发从收”模式,RV-STAR开发板作为主机,通过向OLED屏幕发送指令和数据,从而控制OLED屏幕显示不同的字符和图像,所以除初始化I²C外设的函数外,接下来需要实现一个让主机向从机发送字节的函数,其代码和注释如下:
void I2C_WriteByte(uint8_t addr, uint8_t data)
{
/* wait until I2C bus is idle */
while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
/* send a start condition to I2C bus */
i2c_start_on_bus(I2C1);
/* wait until SBSEND bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_SBSEND));
/* send slave address to I2C bus*/
i2c_master_addressing(I2C1, 0x78, I2C_TRANSMITTER);
/* wait until ADDSEND bit is set*/
while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
/* clear ADDSEND bit */
i2c_flag_clear(I2C1, I2C_FLAG_ADDSEND);
/* send a addr byte */
i2c_data_transmit(I2C1, addr);
/* wait until the transmission data register is empty*/
while(!i2c_flag_get(I2C1, I2C_FLAG_TBE));
/* send a data byte */
i2c_data_transmit(I2C1, data);
/* wait until the transmission data register is empty*/
while(!i2c_flag_get(I2C1, I2C_FLAG_TBE));
/* send a stop condition to I2C bus*/
i2c_stop_on_bus(I2C1);
/* wait until stop condition generate */
while(I2C_CTL0(I2C1)&0x0200);
}
发送字节的过程在代码中配有详细注释(其中OLED屏幕的I²C地址默认为0x78),在实现了I²C的初始化和字节发送功能后,OLED的具体控制实现起来就相当容易了,其相关接口和函数的说明在代码中都进行了注释,这里不进行赘述,大家可以通过阅读项目源代码进行了解。
完整代码请参考https://github.com/Nuclei-Software/nuclei-board-labs/tree/master/rvstar/i2c/i2c_oled_screen
实验现象参考以下动图
2025-10-31 08:48:56
相对于抽象层次更高的C/C++语言,汇编语言是一门抽象层次比较低的语言,面向的是最底层的硬件,直接使用处理器的基本指令。虽然现在大多数的程序设计已经不再使用汇编语言,但是在一些特殊的场合,譬如底层驱动、引导程序、高性能算法库等领域,汇编语言还经常扮演着重要的角色。
系统环境
Windows 10-64bit
软件平台
Nuclei Studio IDE 202102版
汇编语句组成
汇编程序的最基本元素是指令,指令集是处理器架构的最基本要素,因此RISC-V汇编语言的最基本元素自然是一条条的RISC-V指令。除了指令之外,由于此处所用RISC-V工具链是GCC工具链,因此一般的GNU汇编语法也能被GCC的汇编器识别,GNU汇编语法中定义的伪操作、操作符、标签等语法规则均可以在RISC-V汇编语言中使用。
一条典型的RISC-V汇编语句由4部分组成,包含如下字段:
[size=0.85em][label:] opcode [operands] [;comment]
[标签:]操作码[操作数][;注释]
标签
表示当前指令的位置标记。
操作码
可以是如下任意一种:
RISC-V指令的指令名称,譬如addi指令、lw指令等。
汇编语言的伪操作。
用户自定义的宏。
操作数
操作码所需的参数,与操作码之间以空格分开,可以是符号、常量,或者由符号和常量组成的表达式。
注释
为了程序代码便于理解而添加的信息,注释并不发挥实际功能,仅起到注解作用。注释是可选的,如果添加注释,需要注意以下规则:
以“;”或者“#”作为分隔号,以分隔号开始的本行之后部分到本行结束都会被当作注释。
或者使用类似C语言的注释语法//和/* */对单行或者大段程序进行注释。
汇编程序伪操作
在汇编语言中,有一些特殊的操作助记符通常被称为伪操作(Pseudo Ops)。伪操作在汇编程序中的作用是指导汇编器处理汇编程序的行为,且仅在汇编过程中起作用,一旦汇编结束,伪操作的使命就此结束。
此处所用的RISC-V工具链是GCC工具链,一般的GNU汇编语法中定义的伪操作均可在RISC-V汇编语言中使用。经过不断地增加,目前GNU汇编中定义的伪操作数目众多,感兴趣的读者可以自行查阅完整的GNU汇编语法手册。这里将仅简单介绍一些常见的伪操作。.globalsymbol_name 或者 .globlsymbol_name.global和.globl伪操作用于定义一个全局的符号,使得链接器能够全局识别它,即一个程序文件中定义的符号能够被所有其他程序文件可见。.weaksymbol_name
在汇编程序中,符号的默认属性为强 (strong),.weak伪操作则用于设置符号的属性为弱 (weak),如果此符号之前没有定义过,那么同时创建此符号并定义其属性为 weak。如果符号的属性为 weak,那么它无须定义具体的内容。在链接的过程中,另外一个属性为 strong的同名符号可以将此weak符号的内容强制覆盖。利用此特性, .weak伪操作常用于预留一个空符号,使得其能够通过汇编器语法检查,但是在后续的程序中定义符号的真正实体,并且在链接阶段将空符号覆盖并链接。.aligninteger
.align 伪操作用于将当前PC地址推进到 “2的integer次方字节” 对齐的位置。譬如 “.align 3” 表示将当前PC地址推进到8个字节对齐的位置处。.sectionname [, subsection]
.section 伪操作指明将接下来的代码汇编链接到名为 name的段 (Section)中,还可以指定可选的子段 (Subsection),常见的段有 .text、.data、.rodata、.bss。例如 ,“.section .text”伪操作将接下来的代码汇编链接到 .text段。
汇编程序定义标签
标签名称通常在一个冒号(:)之前,常见的标签分为文本标签和数字标签。
文本标签在一个程序文件中是全局可见的,因此定义必须使用独一无二的命名,文本标签通常被作为分支或跳转指令的目标地址,示例如下:
loop://定义一个名为loop的标签,该标签代表了此处的PC地址
......
j loop//跳转指令跳转到标签loop所在的位置
数字标签为0~9之间的数字表示的标签,数字标签属于一种局部标签,需要时可以被重新定义。在被引用时,数字标签通常需要带上一个字母“f”或者“b”的后缀,“f”表示向前,“b”表示向后,示例如下:
j 1f //跳转到“向前寻找第一个数字为1的标签”所在的位置,即下一行
//(标签为1)所在的位置
1:
j 1b//跳转到“向后寻找第一个数字为1的标签”所在的位置,即上一行
//(标签为1)所在的位置
汇编程序定义宏
宏(macro)是将汇编语言中具有一组独立功能的汇编语句组织在一起,然后可以以宏调用的方式进行调用。示例如下:
.macro mac, a, b, c //定义一个名为mac的宏,参数为a、b、c
mul t0, b, c// mul指令将b和c相乘得到乘积写入t0寄存器
add a, t0, a// add指令将a与t0相加,将乘累加结果写入a
.endm
//调用mac宏
mac x1, x2, x3
完整实例
为了便于理解汇编程序,我们以 RV-STAR工程的非向量中断处理汇编代码为实例,讲解汇编程序。
在 Nuclei Studio中新建一个 helloworld工程。芯来科技官网的文档与工具页面可以下载Nuclei Studio,下载后解压缩,在 Nuclei Studio解压缩的目录下双击 NucleiStudio.exe即可启动 IDE。
第一次启动 Nuclei Studio将会弹出对话框要求设置 Workspace目录路径,该目录将用于存放后续创建的项目工程文件。设置好 Workspace路径,再单击 “Launch”启动 Nuclei Studio。
启动后推荐打开Launch Bar功能,方便快速编译和调试。打开菜单栏“Window -> Preferences”,搜索“bar”,勾选第一个选项“Enable the Launch Bar”即可启用Launch Bar功能。
在菜单栏中,选择“File-> New -> C/C++ Project”开始新建工程,在弹窗中双击选择“C Managed Build”。
新的页面中“Project name”填写“iasm”,“Project type” 选择“Nuclei SDK Project For GD32VF103 SoC”和“RISC-V Cross GCC”,如下图,点击“Next”。新的页面不用修改,直接点击“Next”即可。
在选择模板工程页面修改“Project Example”选项为“baremetal_helloworld”,后续页面不需要修改,点击“Next”直到最后一页,点击“Finish”完成新建helloworld工程。
打开 “nuclei_sdk->SoC->gd32vf103->Common->Source->GCC->intexc_g32vf103.S” 文件,翻到第144行开始到184行结束就是非向量中断处理汇编代码。这里列出具体代码,逐行讲解各个汇编代码的作用。
.section .text.trap//将接下来的代码汇编链接到text段的trap段中
.align 6//2的6次方字节位置对齐
.global exc_entry//全局变量exc_entry
.weak exc_entry//定义属性为弱的变量exc_entry
exc_entry://名为exc_entry的标签
SAVE_CONTEXT//调用宏SAVE_CONTEXT,作用是保存上下文
SAVE_CSR_CONTEXT//调用宏SAVE_CSR_CONTEXT,作用是保存寄存器内容
csrr a0, mcause//将寄存器mcause的值传入通用寄存器a0
mv a1, sp//将sp的值传入通用寄存器a1
call core_exception_handler//调用中断处理函数,将前面传的a0和a1作为函数的参数
RESTORE_CSR_CONTEXT//调用宏RESTORE_CSR_CONTEXT,作用是恢复保存的寄存器内容
RESTORE_CONTEXT //调用宏RESTORE_CONTEXT,作用是恢复保存的上下文
mret //退出中断处理函数
在汇编中调用C/C++函数
除了在C/C++程序中内嵌汇编程序之外,还可以在汇编程序中调用C/C++函数。这种情形在实际的工程中也很常见,C/C++语言构造的函数非常普遍,前面的中断处理函数中正是调用C/C++的函数。
在介绍C/C++函数调用之前,先介绍应用程序二进制接口(Abstract Binary Interface,ABI),ABI描述了应用程序和操作系统之间、应用和它的库之间,以及应用的组成部分之间的接口。
ABI涵盖了如下细节:
数据类型的大小、布局和对齐。
函数调用约定(控制着函数的参数如何传送以及接受返回值),例如,是所有的参数都通过栈传递,还是部分参数通过寄存器传递;哪个寄存器用于哪个函数参数;通过栈传递的第一个函数参数是最先还是最后推到栈上。
系统调用的编码和一个应用如何向操作系统进行系统调用。
在一个完整的操作系统ABI中,目标文件的二进制格式、程序库等。
其中,函数调用约定决定了函数调用时参数传递和函数返回结果的规则,有关RISC-V架构ABI的函数调用约定,可以查看RISC-V的架构手册。
对于RISC-V汇编程序而言,在汇编程序中调用C/C++语言函数,必须遵照ABI所定义的函数调用规则,即函数参数由寄存器a0~a7传递,函数返回由寄存器a0~a1指定。上面汇编实例中调用的c函数代码如下:
uint32_t core_exception_handler(unsigned long mcause, unsigned long sp)
{
uint32_t EXCn = (uint32_t)(mcause & 0X00000fff);
EXC_HANDLER exc_handler;
if ((EXCn < MAX_SYSTEM_EXCEPTION_NUM) && (EXCn >= 0)) {
exc_handler = (EXC_HANDLER)SystemExceptionHandlers[EXCn];
} else if (EXCn == NMI_EXCn) {
exc_handler = (EXC_HANDLER)SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM];
} else {
exc_handler = (EXC_HANDLER)system_default_exception_handler;
}
if (exc_handler != NULL) {
exc_handler(mcause, sp);
}
return 0;
}
此函数有两个参数,分别为mcause和sp,返回一个返回值。所以汇编中调用此函数前,分别向a0和a1寄存器中写入mcause和sp的值。
2025-10-31 08:46:48
上期内容我们介绍了定时器的PWM输出功能,本期内容来介绍一下定时器的正交译码器功能(编码器接口)。正交译码器是和正交编码器外设配合使用的,可对编码器输入的脉冲进行计数进而实现速度测量,本期内容我们通过一个使用旋转编码器的计数小实验,来初步了解它的应用方法。
系统环境
Windows 10-64bit
软件平台
NucleiStudio IDE 202102版
或 PlatformIO IDE
硬件需求
RV-STAR开发板
旋转编码器
正交编码器
正交编码器(Quadrature Encoder)是一种用于测量旋转速度和方向的传感器。常见的正交编码器有两个输出信号:A信道和B信道。每个信道可以对运动进行测量并产生数字脉冲,这两个脉冲的相位相差90度(因此称为“正交”),这使得你可以根据它们判断运动的方向,通过积分(累加)运算后,还可以用来测算距离。
上图中,A和B分别连接到两个传感器单元上,黑白相间的圆环称之为「栅格」。传感器单元和栅格的实现方式有很多种,包括「反射式传感器+反光率不同的栅格」「对射式传感器+镂空光栅」「霍尔传感器+磁极圆环」「触点+导轨」等。
本次实验中,我们使用的是下图所示的市面上常见的旋转编码器(数字电位器):
GD32VF103的正交译码器
正交译码器功能使用TIMERx_CH0和TIMERx_CH1引脚生成的CI0和CI1正交信号各自相互作用产生计数值。通过设置SMC=0x01、0x02或0x03来选择是仅由CI0、仅由CI1、或者由CI0和CI1来决定定时器的计数方向。在每个方向选择源的电平改变期间,DIR位是由硬件自动改变的。计数器计数方向改变的机制如下方的图表所示。
正交译码器可以当作一个带有方向选择的外部时钟,这意味着计数器会在0和自动加载值之间连续地计数。因此,用户必须在计数器开始计数前配置TIMERx_CAR寄存器。
实验部分
首先需要参照如下的示意图,对RV-STAR开发板和旋转编码器进行连线:
然后在集成开发环境中创建一个新工程,开始编写代码。
首先需要对定时器的编码器接口进行配置,我们使用的是TIMER2的编码器接口,对应的是PA6和PA7引脚,首先要使能它们的外设时钟和复用时钟,然后配置为浮空输入模式。
接着需要创建定时器初始化参数结构体,对定时器的功能进行配置,其中需要注意的是要将结构体参数的预分频系数设为0,周期设为10000(即定时器的自动加载值,也可以设为其他值),然后需要将定时器的模式设置为TIMER_ENCODER_MODE2(编码器模式,使用CI0和CI1计数),然后将定时器的计数值配置为5000(这样读取定时器计数的初值就是5000),最后使能TIMER2。
相关代码实现如下:
[size=0.85em]void encoder_init()
{
/* TIMER2_CH0 - PA6, TIMER2_CH1 - PA7 */
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_AF);
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
rcu_periph_clock_enable(RCU_TIMER2);
timer_deinit(TIMER2);
/* initialize TIMER init parameter struct */
timer_parameter_struct timer_initpara;
timer_struct_para_init(&timer_initpara);
/* TIMER2 configuration */
timer_initpara.prescaler = 0;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 10000; /* set auto-reload value */
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_init(TIMER2, &timer_initpara);
/* select the encoder mode */
timer_slave_mode_select(TIMER2, TIMER_ENCODER_MODE2);
timer_counter_value_config(TIMER2, 5000); /* config the initial value */
timer_enable(TIMER2);
}
本次实验,我们通过串口的打印输出来查看编码器的计数值,因此在主程序中需要对串口进行初始化,然后在循环体中,每次读取依次定时器的计数值,再打印输出到串口。
[size=0.85em]int main()
{
encoder_init();
gd_com_init(GD32_COM0);
int counter = 0;
while (1) {
counter = timer_counter_read(TIMER2);
printf("Counter: %dn", counter);
delay_1ms(500);
}
}
代码编写完成后,进行编译和上传,然后打开串口终端(波特率115200),可以查看到在串口终端中输出定时器的初值为5000:
然后顺时针旋转编码器的旋钮,观察到计数值增加,并且每转动一个单位计数值增加4,符合芯片数据手册中的功能描述:
逆时针旋转,计数值减少:
扫码获取实验源码https://github.com/Nuclei-Software/nuclei-board-labs/tree/master/rvstar/timer/timer_encoder_counter
2025-10-31 08:21:16
外部中断是单片机实时地处理外部事件的一种机制。具体指的是,当某种外部事件发生时,单片机的中断系统迫使CPU暂停正在执行的程序,转而去进行中断事件的处理;中断处理完毕后,又返回被中断的程序处,继续执行下去。这里我们以Nuclei Board Labs中exti_key_interrupt应用程序为例,简单讲解外部中断的非向量处理模式。
系统环境
Windows 10-64bit
软件平台
[size=14.6667px]NucleiStudio IDE 202102版
硬件需求
RV-STAR开发板
中断知识介绍
外部中断处理介绍
在SoC层面,GD32VF103芯片有多个外部中断源,具体包含哪些外部中断,可以在GD32VF103用户手册的第六章:中断/事件控制器(EXTI)中查看。
本次实验使用用户按键连接的GPIO作为外部中断触发源,经过SoC层面的中断/事件控制器(EXTI)检测后,再传递给增强的内核中断控制器(ECLIC),交由内核进行中断管理。
关于GPIO的使用请看《RVMCU课堂[11]——GPIO使用篇》,这里不做介绍。
中断/事件控制器(EXTI)的架构框图如下:
EXTI(中断/事件控制器)有19个独立的边沿检测单元,分别对应连接EXTI0~18,其中的16个中断源连接的是GPIO。EXTI有三种触发类型:上升沿触发、下降沿触发和任意沿触发。EXTI中的每 一个边沿检测电路都可以独立配置和屏蔽。
中断初始化函数介绍
为了方便进一步讲解,我们先打开Nuclei Board Labs中exti_key_interrupt实验的main.c函数源码。其中,main函数调用的“ECLIC_Register_IRQ”函数就是中断配置函数。截取ECLIC初始化函数代码如下:[size=0.85em]/* ECLIC config */
returnCode = ECLIC_Register_IRQ( EXTI0_IRQn, ECLIC_NON_VECTOR_INTERRUPT,
ECLIC_LEVEL_TRIGGER,
1,
0,
NULL);
在《RVMCU课堂[10]——处理器内部中断篇》已经对此函数各参数的作用有了比较详细的介绍,在这里我们只讲一下会产生疑惑的两个参数,也就是第一个和最后一个参数。
第一个参数设置要配置的中断号。这里我们讲解一下如何确定这个参数的值。已知实验要使用外部按键接GPIO触发外部中断,那么我们从按键看起。
RV-STAR的按键的电路原理图如下:
可以看到,按键接到了PA0引脚上。接下来我们查阅GD32VF103用户手册的第六章:中断/事件控制器(EXTI),发现PA0对应的EXTI中断源为0号。
由此可知,我们知道本次实验使用的GPIO引脚PA0对应的是EXTI0,所以这里是EXTI0中断。所有可用的中断号都在“IRQn_Type”枚举当中,在gd32vf103.h文件当中可以查看RV-STAR的所有中断号。可以看出,从19号开始后面的都是外部中断,如果配置不同的中断,需要修改此参数为对应的中断号。
最后一个参数配置的是中断处理函数。直接来看的话,虽然这里写的是“NULL”,但是并不代表没有中断处理函数。RV-STAR的中断向量表是存储在flash当中的,这就意味着运行时不能直接修改其中的数据,所以在不修改源码的情况下,RV-STAR不能通过这个参数修改中断向量表。这里填写任何函数,都不会修改这个中断号对应的中断处理函数的地址。所以这个参数写“NULL”,实际上还是使用中断向量表里面的默认函数。
后面的“EXTI0_IRQHandler”函数就是外部中断0的默认中断处理函数。详细的中断向量表可以在startup_gd32vf103.S文件开头部分查看,这里就不一一列举。
中断处理函数介绍
知道了中断处理函数是什么,我们再回到main.c当中,找到“EXTI0_IRQHandler”函数,具体内容如下:
[size=0.85em]void EXTI0_IRQHandler(void)
{
if (RESET != exti_interrupt_flag_get(WAKEUP_KEY_PIN)){
if(RESET == gd_rvstar_key_state_get(KEY_WAKEUP)){
/* toggle RED led */
gd_rvstar_led_toggle(LED3);
}
}
/* clear EXTI lines pending flag */
exti_interrupt_flag_clear(WAKEUP_KEY_PIN);
}
中断处理函数中开始是按键去抖。之后切换LED的状态,也就是由亮到灭或者由灭到亮。最后一步是清除EXTI0的中断等待标志。
因为使用的是中断的非向量处理模式,所以在执行中断处理函数前会跳转到非向量中断统一的中断入口,保存上下文入栈,再跳转至对应的中断处理函数中执行里面的指令,所以函数内不需要手动增加保存上下文和恢复上下文的操作。
完整实例
为了便于理解外部中断程序,我们以Nuclei Board Labs中exti_key_interrupt实验为实例,实际感受一下外部中断的流程。
新建一个RV-STAR的helloworld工程,具体步骤请参考往期内容。
打开Nuclei Board Labs中的exti_key_interrupt文件夹,复制main.c的内容替换之前新建的helloworld工程main.c的内容。
工程运行框图如下:
在main函数当中,一开始是一系列的初始化内容,包括开发板初始化,外部中断初始化和ECLIC初始化。
开发板初始化(Board Config)包含开发板上LED3初始化和按键初始化。
外部中断初始化(EXTI config)包含按键外部中断初始化,主要是GPIO的配置。
ECLIC初始化(ECLIC config)是之前讲的ECLIC初始化函数。
以上初始化完成后,main函数执行while(1)循环,等待中断的到来。
当按下PA0按键,触发外部中断,进入外部中断处理函数当中,按键弹起,执行LED状态转换的功能,最后退出中断处理函数。
例子main函数代码和对照介绍如下:[size=0.85em]int main(void)
{
int32_t returnCode;
/* Board Config */
gd_rvstar_led_init(LED3);
gd_rvstar_key_init(WAKEUP_KEY_GPIO_PORT,KEY_MODE_EXTI);
/* EXIT config */
key_exti_init();
/* ECLIC config */
returnCode = ECLIC_Register_IRQ(EXTI0_IRQn, ECLIC_NON_VECTOR_INTERRUPT,
ECLIC_LEVEL_TRIGGER, 1, 0, NULL);
/* Enable interrupts in general */
__enable_irq();
while(1);
return 0;
}
实际运行
工程新建完毕,需要在Launchbar工具中切换使用openocd的debug配置,如下图:
点击编译工程,再点击Debug下拉框切换为Run,点击开始运行。下载结束记得点击关闭openocd。
最终运行效果如下:
每当按键抬起,led的状态切换一次。
2025-10-31 07:39:46
GPIO是通用输入输出接口(General Purpose Input Output)的简称,是微控制器最基本也是最常用的外设,本期内容将介绍GPIO的基本原理,然后通过「点亮LED」与「按键控制LED」两个小实验带领大家了解GPIO基本输出与输入功能的使用方法。
系统环境
Windows 10-64bit
软件平台
[size=14.6667px]NucleiStudio IDE 202102版
[size=14.6667px]或 PlatformIO IDE
硬件需求
RV-STAR开发板
GPIO基本原理
GPIO的全称是通用输入输出接口(General Purpose Input/Output),是很多外设能够正常工作的基础,MCU上除了一些特定功能的引脚(如电源引脚)外,其他的引脚基本都可以作为GPIO来使用。
GD32VF103的GPIO端口以“组”的形式工作,命名方式为Px(x=A, B, C, D, E···),每组配置有16个引脚。GPIO端口和其他的备用功能(AFs)共用引脚,在特定的封装下获得最大的灵活性。
每个GPIO引脚都可以通过软件配置为输出(推挽或开漏)、输入、外设备用功能或者模拟模式。每个GPIO引脚都可以配置为上拉、下拉或浮空。除模拟模式外,所有的GPIO引脚都具备大电流驱动能力。
(标准GPIO端口的基本结构)
GPIO具有下列特征:
输入/输出方向控制
施密特触发器输入功能使能控制
每个引脚都具有弱上拉/下拉功能
推挽/开漏输出使能控制
置位/复位输出使能
可编程触发沿的外部中断——使用EXTI配置寄存器
模拟输入/输出配置
备用功能输入/输出配置
端口锁定配置
实验1:点亮LED
RVSTAR有一个板载的RGB LED,通过PA1、PA2、PA3三个引脚控制LED_G、LED_R、LED_B三个颜色,通过原理图可以得知:要点亮LED需要通过GPIO引脚输出一个低电平,当然也可以通过输出PWM控制三个颜色LED的亮度,进而组合产生不同的颜色。
下面将通过实验点亮LED_G,并令其以2秒为间隔闪烁:
(RGB LED原理图 - 1)
(RGB LED原理图 - 2)
[size=14.6667px]首先参照之前的教程,使用NucleiStudio IDE或PlatformIO IDE创建工程,[size=14.6667px]在main.c文件内编写代码如下:
/* 实验1:点亮LED */
#include "nuclei_sdk_hal.h"
void led_config();
void led_on();
void led_off();
int main(void)
{
// 首先对外设进行初始化操作
led_config();
while (1)
{
led_on();// 点亮LED
delay_1ms(2000); // 延时2秒
led_off(); // 熄灭LED
delay_1ms(2000); // 延时2秒
}
}
void led_config()
{
// 使能GPIOA端口的外设时钟
rcu_periph_clock_enable(RCU_GPIOA);
// 将PA1初始化为推挽输出模式
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
}
void led_on()
{
// 将输出引脚置位为0,输出低电平,灯亮
gpio_bit_reset(GPIOA, GPIO_PIN_1);
}
void led_off()
{
// 将输出引脚置位为1,输出高电平,灯熄
gpio_bit_set(GPIOA, GPIO_PIN_1);
}
[size=14.6667px]然后将工程文件进行编译和上传,将可以观察到板载的绿色LED以2秒为间隔进行闪烁。[size=14.6667px]运行结果如下:
实验2:按键控制LED
[size=14.6667px]实验1我们使用了GPIO的输出功能点亮了LED,实验2将带领大家[size=14.6667px]使用GPIO的输入功能:[size=14.6667px]用RVSTAR的板载按键控制LED的亮和灭,在使用它之前我们需要了解一点[size=14.6667px]按键消抖的知识。
(按键的原理图)
[size=14.6667px]RVSTAR有一个板载的按键,连接到了MCU的PA1引脚上,按键没按下时,PA1引脚通过一个下拉电阻接地,处于低电平状态,按键按下时PA1引脚被拉高到3.3V,处于高电平状态。由于按键是机械结构,在按下和弹起的瞬间会产生抖动,即引脚上的电平状态不会被立刻拉高或拉低到稳定状态,因此[size=14.6667px]为了能够准确检测用户的按键操作[size=14.6667px],往往需要通过一定的方法进行[size=14.6667px]消抖处理[size=14.6667px]:
常用的按键消抖方法有硬件消抖和软件消抖:硬件消抖是通过在按键两端增加电容的方式实现的,成本较高;而软件消抖是在第一次检测到电平变化后延时一定时间后再次检测电平状态,如果检测到仍处于按下时的电平状态,那么说明用户进行了完整的按键操作,这个延时时间跟具体的硬件有关,经测试,在RVSTAR的按键上大约需要是设置100毫秒的延时比较合适。
使用NucleiStudio IDE或PlatformIO IDE创建工程,在main.c文件内编写代码如下:
/* 实验2:按键控制LED */
#include "nuclei_sdk_hal.h"
void led_config();
void led_on();
void led_off();
void key_config();
bit_status key_get_status();
bit_status led_status = 0; // 用来记录led的当前状态
int main(void)
{
led_config();
key_config();
led_off();
while (1)
{
// 第一次检测按键按下
if(key_get_status() == SET)
{
// 软件延时100ms用以消除抖动
delay_1ms(100);
// 再次检测按键是否按下
if(key_get_status() == SET)
{
switch (led_status)
{
case 0:
led_on();
break;
case 1:
led_off();
break;
default:
break;
}
led_status = !led_status; // 每次按键操作后切换led的状态
}
}
}
}
void led_config()
{
// 打开GPIOA端口的外设时钟
rcu_periph_clock_enable(RCU_GPIOA);
// 将PA1初始化为推挽输出模式
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
}
void led_on()
{
// 将输出引脚置位为0,输出低电平,灯亮
gpio_bit_reset(GPIOA, GPIO_PIN_1);
}
void led_off()
{
// 将输出引脚置位为1,输出高电平,灯熄
gpio_bit_set(GPIOA, GPIO_PIN_1);
}
void key_config()
{
rcu_periph_clock_enable(RCU_GPIOA); // 开启外设时钟
rcu_periph_clock_enable(RCU_AF); // 开启复用时钟
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_0); // 将PA0初始化为浮空输入模式
}
bit_status key_get_status()
{
// 获得输入引脚的状态,其中bit_status是一个固件库定义的枚举类型
return gpio_input_bit_get(GPIOA, GPIO_PIN_0);
}
[size=14.6667px]然后将工程文件进行编译和上传,将可以观察到:上电后LED不亮,每次按下按键后LED的状态会发生切换。
运行结果如下:
实验完整资料
实验源码:https://github.com/Nuclei-Software/nuclei-board-labs/tree/master/rvstar/gpio
原理图:
https://www.rvmcu.com/quickstart-doc-u-pdf-id-235.html
2025-10-31 07:16:40
PWM(脉冲宽度调制)可用于电机的调速、LED的亮度调节、无源蜂鸣器输出音调等,是嵌入式系统开发中经常采用的方法。本期内容以一个用无源蜂鸣器播放音乐的例子,带领大家了解使用定时器PWM输出功能的方法。
系统环境
Windows 10-64bit
软件平台
NucleiStudio IDE 202102版
或 PlatformIO IDE
硬件需求
RV-STAR开发板
无源蜂鸣器
脉冲宽度调制
脉冲宽度调制(Pulse Width Modulation,PWM)是利用微控制器的数字输出来对模拟电路进行控制的一种非常有效的技术。
PWM的控制方式就是对逆变电路开关器件的通断进行控制,使输出端得到一系列幅值相等的脉冲,用这些脉冲来代替正弦波或所需要的波形。也就是在输出波形的半个周期中产生多个脉冲,使各脉冲的等值电压为正弦波形,所获得的输出平滑且低次谐波少。按一定的规则对各脉冲的宽度进行调制,既可改变逆变电路输出电压的大小,也可改变输出频率。其中,一个周期内脉冲时间占总时间的比值称为占空比。
简言之,如果你想让电机的速度变慢或者控制的LED变暗,只需降低PWM的占空比,这使得原本需要控制模拟电压或电流才能达到的效果,通过数字方式也能够实现,这样可以大幅度降低系统的成本和功耗。
无源蜂鸣器
无源蜂鸣器是很常见的一个电子元件,相信读者朋友们都见过可以播放生日歌的电子蜡烛,那个就是靠无源蜂鸣器来播放的。无源蜂鸣器的内部不带振荡源,通过使用50%占空比、频率500Hz~4.5kHz的PWM驱动,就可以播放出不同音调的声音。
GD32VF103的定时器
GD32VF103的定时器分为三种类型,分别是基本定时器、通用定时器和高级定时器,其中普通定时器和高级定时器都支持PWM输出功能,在本次的实验中使用TIMER2(普通定时器)来进行PWM输出实验。
实验部分
首先通过NucleiStudio或者PlatformIO等开发工具创建工程,然后在工程目录中添加“tone.h”和“main.c”文件,然后开始进行代码的编写。
首先,我们要为蜂鸣器发出的不同音调所需要的频率进行预先的定义,以下的经调音测试后的D调的不同音符所对应的频率,直接复制到“tone.h”中即可:
[size=0.85em]#define NTD0 -1
#define NTD1 293
#define NTD2 329
#define NTD3 368
#define NTD4 390
#define NTD5 438
#define NTD6 492
#define NTD7 554
#define NTDL1 147
#define NTDL2 166
#define NTDL3 185
#define NTDL4 196
#define NTDL5 221
#define NTDL6 248
#define NTDL7 278
#define NTDH1 585
#define NTDH2 657
#define NTDH3 700
#define NTDH4 781
#define NTDH5 882
#define NTDH6 990
#define NTDH7 1112
然后,在“main.c”中,我们要实现三个函数:
buzzer_init() -- 初始化蜂鸣器
buzzer_on(int freq) -- 蜂鸣器根据频率发声
buzzer_off() -- 关闭蜂鸣器
下面依次进行讲解,首先是buzzer_init(),我们使用的是PB1引脚,它对应着TIMER2的CH3通道,要依次使能端口时钟、复用时钟、定时器时钟,然后把引脚初始化为推挽输出模式。
[size=0.85em]void buzzer_init()
{
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_AF);
rcu_periph_clock_enable(RCU_TIMER2);
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
}
然后是buzzer_on(int freq),它接收不同的频率参数,对定时器进行配置,输出50%占空比的不同频率的PWM波,进而控制蜂鸣器发声。实现方法参考下方代码,其中要注意的是预分频系数、周期以及PWM输出的占空比等几个参数的配置。
[size=0.85em]void buzzer_on(int freq)
{
timer_oc_parameter_struct timer_ocinitpara;
timer_parameter_struct timer_initpara;
timer_deinit(TIMER2);
/* initialize TIMER init parameter struct */
timer_struct_para_init(&timer_initpara);
/* TIMER2 configuration */
timer_initpara.prescaler = 107;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 1000000 / freq;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER2, &timer_initpara);
/* initialize TIMER channel output parameter struct */
timer_channel_output_struct_para_init(&timer_ocinitpara);
/* CH3 configuration in PWM mode */
timer_ocinitpara.outputstate = TIMER_CCX_ENABLE;
timer_ocinitpara.outputnstate = TIMER_CCXN_DISABLE;
timer_ocinitpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocinitpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
timer_ocinitpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
timer_ocinitpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
timer_channel_output_config(TIMER2, TIMER_CH_3, &timer_ocinitpara);
/* auto-reload preload enable */
timer_auto_reload_shadow_enable(TIMER2);
timer_enable(TIMER2);
/* CH3 configuration in PWM mode1,duty cycle 50% */
timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_3, 500000 / freq);
timer_channel_output_mode_config(TIMER2, TIMER_CH_3, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER2, TIMER_CH_3, TIMER_OC_SHADOW_DISABLE);
}
第三个函数buzzer_off(),这个比较简单,只需复位定时器即可。
[size=0.85em]void buzzer_off()
{
timer_deinit(TIMER2);
}
最后需要用两个数组分别存储一段音乐的音符、节拍,这里以“小星星”的前16拍为例,然后在主循环中对这两个数组进行遍历,就可以实现播放音乐的效果。
[size=0.85em]int notes[] = {
NTD1, NTD1, NTD5, NTD5,
NTD6, NTD6, NTD5,
NTD4, NTD4, NTD3, NTD3,
NTD2, NTD2, NTD1
};
int beats[] = {
1, 1, 1, 1,
1, 1, 2,
1, 1, 1, 1,
1, 1, 2
};
int main()
{
buzzer_init();
int length = sizeof(notes) / sizeof(notes[0]);
while (1) {
for (int i = 0; i < length; i++) {
buzzer_on(notes);
delay_1ms(500 * beats);
buzzer_off();
}
delay_1ms(1000);
}
}
完成代码编写后,将无源蜂鸣器的(+)引脚接到RV-STAR开发板的PB5引脚上,另一个引脚接地,然后编译、上传,就可以听到蜂鸣器播放“小星星”啦~
实验源码https://github.com/Nuclei-Software/nuclei-board-labs/tree/master/rvstar/timer/timer_pwmout_buzzer
2025-10-31 06:38:13
面对复杂多样的嵌入式通信需求,Air8000 模块的 CAN 接口开发尤为重要。本文以实战为导向,详细拆解 Air8000 模块 CAN 接口的开发流程与配置方法,从环境搭建到代码实现,再到实际测试,让你零基础也能轻松掌握,实现高效、稳定的数据通信。 一、CAN 概述 控制器局域网(Controller Area Network,CAN)是一种广泛应用于工业控制、汽车电子等领域的实时通信协议,由德国博世公司于 1986 年提出并标准化(ISO 11898)。其核心采用多主(Multi-Master)总线架构
2025-10-29 14:04:55
256 
ADC(Analog to Digital Converter,模数转换器)是指将连续变化的模拟信号转换为离散的数字信号的电子器件。ADC可以将真实世界的模拟信号,例如温度、压力、声音等,转换成更容易储存、处理和发射的数字形式,因此被广泛应用在各种产品中。本期我们将通过一个读取电位器电压值的小实验来了解RV-STAR开发板上ADC的使用方法。
系统环境
Windows 10-64bit
软件平台
NucleiStudio IDE 202102版或 PlatformIO IDE
硬件需求
RV-STAR开发板
旋转电位器
GD32VF103的ADC外设
GD32VF103包含一个12位精度的ADC,它是一种采用逐次逼近方式的模拟数字转换器,它有18个多路复用通道,可以转换来自16个外部通道和2个内部通道的模拟信号。模拟看门狗允许应用程序来检测输入电压是否超出用户设定的高低阈值。各种通道的A/D转换可以配置成单次、连续、扫描或间断转换模式。ADC转换的结果可以按照左对齐或右对齐的方式存储再16位寄存器中。片上的硬件过采样机制可以通过减少来自MCU的相关计算负担来提高性能。
高性能:
可配置12位、10位、8位、或者6位分辨率;
自校准;
可编程采样时间;
数据寄存器可配置数据对齐方式;
支持规则数据转换的DMA请求。
模拟输入通道:
16个外部模拟输入通道;
1个内部温度传感通道(VSENSE);
1个内部参考电压输入通道(VREFINT)。
转换开始的发起:
软件;
硬件触发。
转换模式:
转换单个通道,或者扫描一序列的通道;
单次模式,每次触发转换一次选择的输入通道;
连续模式,连续转换所选择的输入通道;
间断模式;
同步模式(适用于具有两个或多个ADC的设备)。
模拟看门狗。
中断的产生:
规则组或注入组转换结束;
模拟看门狗事件。
过采样:
16位的数据寄存器;
可调整的过采样率,从2x到256x;
高达8位的可编程数据移位。
ADC供电要求:2.6V到3.6V,一般电源电压为3.3V。
ADC输入范围:VREF- ≤VIN ≤VREF+。
实验部分
本次实验使用的外设部件为旋转电位器,它是一个典型的模拟器件,通过旋转旋钮可以输出0到供电电压VCC之间的模拟量。
通过查阅电路原理图得知,RV-STAR的PC0引脚对应着一个ADC复用通道,我们使用它来连接旋转电位器外设,连线参考如下表:
RV-STAR旋转编码器
PC0OUT
3V3VCC
GNDGND
旋转编码器的供电一定要接3V3不能接5V,否则可能因为输入电压过高而烧坏芯片。
完成电路连线之后就可以创建工程开始编写代码了,首先需要定义一系列的配置函数,用于初始化时钟、外设引脚和进行ADC的配置:
void rcu_config(void)
{
rcu_periph_clock_enable(RCU_GPIOC);
rcu_periph_clock_enable(RCU_ADC1);
rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8);
}
void gpio_config(void)
{
gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
}
void adc_config(void)
{
/* reset ADC */
adc_deinit(ADC1);
/* ADC mode config */
adc_mode_config(ADC1, ADC_MODE_FREE);
/* ADC scan function enable */
adc_special_function_config(ADC1, ADC_SCAN_MODE, ENABLE);
/* ADC contineous function enable */
adc_special_function_config(ADC1, ADC_CONTINUOUS_MODE, ENABLE);
/* ADC data alignment config */
adc_data_alignment_config(ADC1, ADC_DATAALIGN_RIGHT);
/* ADC channel length config */
adc_channel_length_config(ADC1, ADC_REGULAR_CHANNEL, 1);
adc_external_trigger_source_config(ADC1, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_NONE);
adc_external_trigger_config(ADC1, ADC_REGULAR_CHANNEL, ENABLE);
delay_1ms(1);
adc_enable(ADC1);
adc_calibration_enable(ADC1);
adc_software_trigger_enable(ADC1, ADC_REGULAR_CHANNEL);
adc_regular_channel_config(ADC1, 0, ADC_CHANNEL_10, ADC_SAMPLETIME_55POINT5);
}
其中,我们使用的PC0管脚对应着ADC1的通道10,编写配置函数的时候要注意,另外在本应用中,ADC被配置为独立的连续扫描模式,使用常规通道触发(即软件触发)。
在主函数中,周期性的读取ADC的值,然后打印到串口终端,对应的代码如下:
#include "nuclei_sdk_hal.h"
#include
void rcu_config(void);
void gpio_config(void);
void adc_config(void);
uint16_t adc_value;
int main(void)
{
rcu_config();
gpio_config();
adc_config();
gd_com_init(GD32_COM0);
while (1) {
delay_1ms(1000);
adc_value = adc_regular_data_read(ADC1);
printf("rn ADC1 regular channel 10 data = %d rn", adc_value);
printf("rn ***********************************rn");
}
}
以上就是完整的代码内容,完成后,将RV-STAR开发板连接到电脑,编译并上传代码,打开串口终端,旋转电位器旋钮,可以观察到打印到串口终端的读数发生了改变,说明ADC功能正常开启。
实验源码:https://github.com/Nuclei-Software/nuclei-board-labs/tree/master/rvstar/adc/adc_regular_scan
2025-10-29 06:56:24
本文将分享我们团队提高E203软核主频的办法。
查阅芯来科技官方出版的《手把手教你设计CPU——RISC-V处理器篇》教材,我们发现,原本设计的E203主时钟域应该是100MHZ
2025-10-29 06:19:19
看门狗定时器(Watch Dog Timer,WDT或WDGT),是一种微控制器为了防止程序“跑飞”而设计的一种硬件机制,让系统在因电磁干扰或者软件错误而当机的时候可以复位系统,从而具备自修复的能力。本期内容将带领大家了解看门狗的基本原理和RV-STAR的独立看门狗(FWDGT)的使用方法。
系统环境
Windows 10-64bit
软件平台
NucleiStudio IDE 202102版或 PlatformIO IDE
硬件需求
RV-STAR开发板
看门狗定时器的基本原理
看门狗定时器实际上一个计数器,在计数溢出时会产生一个复位信号,正常情况下首先给看门狗定时器设置一个超时时间,然后程序在超时时间内定期对定时器进行重载操作(也叫做“喂狗”操作),从而避免正常程序发生复位。
当系统发生意料之外的故障使得软件跑飞,看门狗定时器无法被按时重载时,看门狗硬件就会产生一个系统复位,让系统重新运行,从而达到恢复功能的效果。
GD32VF103的独立看门狗定时器(FWDGT)
独立看门狗定时器(FWDGT)具有独立的时钟源(IRC40K)。因此就算主时钟失效的,它仍然能保持工作状态,这适用于需要独立环境且对计时精度要求不高的场合。
当内部向下计数器的值达到0,独立看门狗会产生一个复位。使能独立看门狗的寄存器写保护功能可以避免寄存器的值被意外的配置篡改。
主要特性:
自由运行的12位向下计数器
如果看门狗定时器被使能,那么当向下计数器的值达到0时产生系统复位;
独立时钟源,独立看门狗定时器在主时钟故障时仍能工作;
独立看门狗定时器硬件控制位,可以用来控制是否在上电时自动启动看门狗定时器;
可以配置独立看门狗定时器在调试模式下选择停止还是继续工作。
实验部分
FWDGT实验的思路如下:
首先对系统进行初始化操作,然后让红色的LED点亮50ms(用于指示系统发生了复位),接着将FWDGT的超时时间设置为1000ms(非精确),然后在主函数中每间隔900ms做一次FWDGT计数器重载防止其复位,并且用绿色LED状态切换表示程序正在运行(FWDGT没有复位)。
同时用KEY_WKUP按键连线的中断线来模拟一个软件故障,当该按键被按下时触发中断服务,在该中断服务程序中写入一个点亮蓝色LED并进入while(1)的死循环来模拟软件跑飞,不能返回主程序。这样FWDGT计数器不能及时被重载,当计数值到0时,发生FWDGT复位,在系统复位后,通过点亮红色LED来指示FWDGT发生。
完整的实现代码如下:
#include "nuclei_sdk_hal.h"
uint32_t millis(void);
uint32_t start = 0;
uint32_t now = 0;
int main()
{
/* enable IRC40K */
rcu_osci_on(RCU_IRC40K);
/* wait till IRC40K is ready */
while (SUCCESS != rcu_osci_stab_wait(RCU_IRC40K)) ;
/* confiure FWDGT counter clock: 40KHz(IRC40K) / 64 = 0.625 KHz */
fwdgt_config(625, FWDGT_PSC_DIV64);
/* after 1 seconds to generate a reset */
fwdgt_enable();
gd_rvstar_led_init(LED1);
gd_rvstar_led_init(LED2);
gd_rvstar_led_init(LED3);
gd_rvstar_led_on(LED3);
delay_1ms(50);
gd_rvstar_led_off(LED3);
start = millis();
gd_rvstar_key_init(KEY_WAKEUP, KEY_MODE_EXTI);
__enable_irq();
while (1) {
now = millis();
if (now - start >= 900) {
fwdgt_counter_reload();
start = now;
}
/* toggle green led */
gd_rvstar_led_toggle(LED1);
delay_1ms(100);
}
}
void EXTI0_IRQHandler(void)
{
if (RESET != exti_interrupt_flag_get(WAKEUP_KEY_EXTI_LINE)) {
if (RESET == gd_rvstar_key_state_get(KEY_WAKEUP)) {
gd_rvstar_led_off(LED1);
gd_rvstar_led_on(LED2);
while (1);
}
}
/* clear EXTI lines pending flag */
exti_interrupt_flag_clear(WAKEUP_KEY_EXTI_LINE);
}
/**
* brief Returns the number of milliseconds since the board began running the current program.
*
* return Number of milliseconds since the program started (uint32_t)
*/
uint32_t millis(void)
{
return (uint32_t)(SysTimer_GetLoadValue() * (4000.F / SystemCoreClock));
}
在IDE中创建工程,将上述代码编译上传到开发板,可以观察到,开发板的板载LED短暂闪了下红色后,开始进入持续的绿色快速闪烁状态,当按下WKUP按键后,LED开始亮蓝色,持续不到1s后,又闪了下红色后然后进入持续的绿色快速闪烁状态,说明看门狗起到了作用使系统发生了复位。
实验源码:
https://github.com/Nuclei-Software/nuclei-board-labs/tree/master/rvstar/wdgt/fwdgt_key_int
2025-10-29 06:01:39
前言:在嵌入式开发中,一个小小的接口问题往往会卡壳半天,尤其是像HDMI热插拔这种和硬件、内核驱动都挂钩的场景。最近调试T527板卡时,就遇到了HDMI热插拔失灵的麻烦,经过一番排查终于解决,今天把整个过程整理成笔记,希望能帮到有同样困扰的朋友。一、明确HDMI“失效”现象在开始排查前,得先把问题现象摸透。这次遇到的HDMI问题主要集中在“插拔检测”上,具体
2025-10-17 08:32:25
994 
在 BUCK 电源设计中,MOS 管的 “快开快关” 是减少损耗的关键,而实现这一需求的核心,离不开前级驱动与滞回比较器的精妙配合。今天我们就从电路搭建到参数计算,手把手教你搞定 BUCK 电源的滞回电路,即使是新手也能跟着一步步实操!
2025-10-16 11:03:33
2364 
本开发指南将手把手帮工程师们了解芯片的各个模块,对照手册熟悉各个模块的寄存器配置。同时,分享一些常见的错误用法,助您规避误区,从而提高开发效率。
2025-10-07 09:15:00
858 
以下文章内容由CW32生态社区用户End提供: https://gitee.com/xcet/embedded-cw32-board-template/tree/master/ref/CW32-GCC-Clion-Template 最近 CLion 对非商业用途免费了,我立马下载了最新的CLion2025,现在针国产武汉芯源半导体的 CW32单片机 搭建CLion+GCC+ CMake 开发环境。 CLion是一款由JetBrains开发的跨平台集成开发环境(IDE),专门为C和C++设计。以其智能编码辅助、易用的项目管理和强大的内置工具(如调试器、静态分析工具、单元测试框架)而著称,支持远程协作和嵌入式开发
2025-09-29 18:00:31
6699 
BLE蓝牙配网如何兼顾便捷性与稳定性?STA+SoftAP双模式给出最优解。下面从技术原理到实战案例,手把手教你搭建双模式配网系统,无需复杂代码,轻松实现设备快速联网,小白也能秒变专家。
2025-09-20 15:20:43
1307 
一、IO调试方法使用组态软件在线数据监控功能进行第三方ProfinetIO或Profinet网关调试,通过西门子(STEP7-MicroWINSMART、TIAPortal)和Codesys进行调试验证。1.1STEP7-MicroWINSMART平台在使用STEP7-MicroWINSMART平台调试ProfinetIO时,需先借助S7-200PLC才可进
2025-09-18 19:33:00
1657 
,我们就整理了一版超详细的手把手开发教程,从架构解析、代码实战,到知识库配置与智能体调试,流程完善、操作门槛低!大家也可以根据实际场景需求,大胆发挥想象,自定义开
2025-09-12 17:40:07
1702 
H100服务器停工一天损失的算力成本可能比维修费还高。今天,我们给大家总结一套“防掉卡秘籍”,从日常管理到环境把控,手把手教你把掉卡风险压到最低。一、供电是“生命线”,这3点必须盯紧H100满载功耗
2025-09-05 11:03:06
855 
我司产品ECAN-E02拥有MQTT工作模式,在此工作模式下,可以选择使用阿里云平台进行相关测试与通信。1MQTT工作模式概述首先让我们了解一下什么是MQTT工作模式。MQTT(MessageQueuingTelemetryTransport)是一种轻量级的消息传输协议,特别适用于物联网(IoT)和资源受限的环境。相较于传统的请求-响应模式,发布-订阅(Pu
2025-09-04 19:34:20
1214 
无论你的技术背景如何,本教程都将以手把手的方式,拆解AT指令APN设置的全流程。专网连接不再是门槛,即刻开启自主配置之旅! APN是设备连接到运营商网络的“身份证” ——当设备插入SIM卡并注册到
2025-09-04 14:40:47
875 
我们正在参加全球电子成就奖的评选,欢迎大家帮我们投票~~~谢谢支持来源:内容由半导体行业观察编译自semiengineeringChiplet是一种满足持续增长的计算能力和I/O带宽需求的方法,它将SoC功能拆分成更小的异构或同构芯片(称为芯片集),并将这些Chiplet集成到单个系统级封装(SIP)中,其中总硅片尺寸可能超过单个SoC的光罩尺寸。SIP不仅
2025-09-04 11:51:37
643 
宏集MC系列模块化控制器是基于RaspberryPi的高性能4核控制器,运动控制循环时间最快可达500微秒,实现了计算能力和成本之间的最佳平衡,适用于多轴运动控制和CNC控制。教程目的本系列教程将使用宏集MC系列控制器,详细介绍通过CODESYSV3来进行PLC测试编程的步骤,旨在使初次接触宏集MC系列控制器的使用者了解该板卡的连接、配置、调试。通过该教程的
2025-08-26 17:31:25
1030 
在云原生时代,存储是制约应用性能的关键瓶颈。本文将带你深入理解K8s存储类的设计原理,并手把手实现与Ceph的完美集成,让你的集群存储性能提升300%!
2025-08-22 11:50:09
698 车载以太网时间同步精度不足?gPTP协议实现±50ns级同步革命!本文深度剖析gPTP协议在自动驾驶多传感器融合中的关键作用,从硬件选型到LinuxPTP工具链配置,手把手教你搭建高精度时间同步系统!
2025-08-20 11:39:26
2024 
ISO 26262合规指南,从ASIL分级到工具落地,手把手教你用静态代码分析(Perforce QAC)实现高效合规。
2025-08-07 17:33:55
970 
认识频率漂移 一 、 频率漂移的概念 频率漂移,简单来说,就是晶振实际输出频率和标称频率之间出现了偏差。就好比你买了一个标称每分钟摆动60次的摆钟,但实际使用时,它每分钟可能摆动61次或者59次,这多出来或者少掉的摆动次数,就类似于晶振的频率漂移。在电子设备中,晶振就如同一个精准的时钟,为整个系统提供稳定的频率信号,一旦出现频率漂移,就相当于这个时钟走不准了。 二 、 漂移带来的严重后果 别小看这小小的频率漂移,它可
2025-07-25 16:36:22
544 E104-BT01是成都亿佰特电子科技有限公司基于德州仪器(TI)CC2541射频芯片研发的符合蓝牙协议5.0的模块,该模块主从一体,可实现模块点对点间的蓝牙连接,实现模块间数据透传,支持串口指令配置模块参数和功能。广泛应用于智能穿戴、家庭自动化、家庭安防、个人保健、智能家电、配饰与遥控器、汽车、照明、工业互联网、智能数据采集、智能控制等领域。本文将通过模块
2025-07-24 19:33:33
1399 
在现代工业自动化控制领域,实现PLC无线控制可以带来更高的灵活度和便利性。PLC可以配备无线通讯模块,这些模块可以直接与PLC连接,能够与触摸屏或上位机等其他设备或系统进行无线通信,实现数据的传输和控制命令的发送。 PLC无线控制模块采用全数字加密无线传输技术,应用范围覆盖冶炼、化工、新能源、石油等16大工业行业,在复杂恶劣环境中平均连续使用寿命超过8年。以下是两例无线通讯模块在工业现场实现PLC无线控制的典型应用: 一、无
2025-07-24 17:07:27
414 
VGLite是NXP提供的轻量级2D图形API,本文将手把手带你实现VGLite图形驱动适配RT-Thread。文章分为上、下两篇,将手把手教您移植。上篇对RT-ThreadNano内核与Finsh组件进行移植,下篇则教您改写SDK中的VGLite代码以将其适配到RT-ThreadNano中。
2025-07-17 14:40:47
3160 
零基础搭建本次实验将会使用到的软件是Keil和STM32CubeMX,没有这两个软件没有请在网上自行下载。本章节零基础手把手教会你搭建最快捷、最简单的STM32代码
2025-07-03 19:32:31
1190 
《手把手教你做PC》系列直播课再度开播!《KaihongOS笔记本电脑开发实战第十二课:WIFI驱动框架适配》将于07月02日19:00开播↑扫码入群,领课程讲义资料包↑深开鸿资深工程师亲临直播间
2025-07-01 08:08:03
454 
感谢大家对Splashtop的热情关注!目前我们的应用已在苹果AppStore及安卓GooglePlay全面上线。但由于上架审核需要一定的时间,所以暂时未登陆国内应用市场。不过,别担心,今天这份详细指南将手把手教你如何在国内安
2025-06-27 17:01:24
534 
项目越大,越需要靠谱的版本控制系统。Perforce P4不仅是Epic官方推荐的源代码控制工具,更是大厂团队协作的核心支持之一。如何配置P4+UE?手把手教你怎么用↓↓↓
2025-06-25 11:22:11
1247 
识别三个维度,手把手教你高效完成防护器件选型!一、选型必看:核心参数解析不同防护器件的参数差异较大,抓住关键参数才能精准匹配客户的需求:TVS(瞬态电压抑制二极管)
2025-06-11 14:19:42
683 
《手把手教你做星闪无人机》系列直播课再度开播!《KaihongOS星闪无人机开发实战⑩:KaihongOSLite系统专题》↑扫码入群,领课程讲义资料包↑深开鸿资深工程师亲临直播间依托笔电实战产品
2025-06-10 08:06:24
427 
使用BasicStation或PiWAN连接到TheThingsNetwork将树莓派设置为LoRaWAN网关乍一看可能令人望而生畏,但有了合适的工具和指导,它就会成为一个有意义的DIY网络项目。在本文中,我们将介绍如何使用手动构建的BasicStation或基于Docker的PiWAN堆栈将树莓派连接到TheThingsNetwork(TTN)。但首先,什
2025-06-09 16:23:40
1778 
如果您对远程errDump调试功能感到陌生,本教程将通过一步步操作演示,教您如何配置远程日志采集、解析errDump文件,以及定位关键错误信息,让您轻松独立完成调试任务。 下文特别分享errDump功能及Air8101开发板实操验证。 一、errDump功能介绍 1.1 errDump有什么用? errDump是LuatOS系统中的错误日志上报模块,主要用于远程调试与故障诊断。 其原理是将模块运行过程中产生的错误信息或者应用日志,通过TCP/UDP上报到互联网上的指定服务器,技术人员可以在服
2025-06-05 18:32:53
1005 
在高并发网络服务场景中,Linux内核的默认网络参数往往无法满足需求,导致性能瓶颈、连接超时甚至服务崩溃。本文基于真实案例分析,从参数解读、问题诊断到优化实践,手把手教你如何调优Linux网络参数,支撑百万级并发连接。
2025-05-29 09:21:13
758 《手把手教你做星闪无人机》系列直播课再度开播!《KaihongOS星闪无人机开发实战⑨:无线通信编程之SLE专题》↑扫码入群,领课程讲义资料包↑深开鸿资深工程师亲临直播间依托笔电实战产品案例细致剖析
2025-05-27 08:05:45
418 
MIMO设备功率测量太复杂?TS-RadiMation帮你一键搞定!本文详细解析MIMO功率测量全流程,从配置到数据分析,助你快速掌握关键测试技巧,提升测试效率!
2025-05-26 17:42:05
593 
《手把手教你做PC》系列直播课再度开播!《KaihongOS笔记本电脑开发实战第九课:全功能TypeC驱动框架适配》将于5月21日19:00开播↑扫码入群,领课程讲义资料包↑深开鸿资深工程师亲临直播
2025-05-20 08:07:51
496 
正点原子Linux系列全新视频教程来啦!手把手教你MP257开发板,让您轻松入门!
一、视频观看
正点原子手把手教你学STM32MP257-第1期:https://www.bilibili.com/video/BV1UtEizyE7Z
二、更多详细介绍
2025-05-16 10:42:23
针对全栈开发者设计的实战教程,本文聚焦LuatOS平台log库的高效使用,从基础配置到高级调试策略,手把手教你搭建可扩展的日志系统,提升项目维护效率。 今天,我们一起来认识LuatOS的log库
2025-05-12 15:23:30
1380 
都会觉得无从下手。别担心!这篇文章将用通俗易懂的方式,带你了解 CentOS 中的防火墙配置,并通过一个实际案例,手把手教你如何正确设置防火墙规则。
2025-05-08 11:52:03
978 
《手把手教你做PC》系列直播课再度开播!《KaihongOS笔记本电脑开发实战⑦:Audio音频驱动框架适配》将于4月23日19:00开播↑扫码入群,领课程讲义资料包↑深开鸿资深工程师亲临直播间依托
2025-04-22 08:05:41
493 
注意事项,从安装准备到后期维护,手把手教你正确操作,确保监测数据真实可靠!一、安装前:做好3项准备,事半功倍1.检查设备完整性开箱验货:核对测缝计型号、配件(护管、
2025-04-21 15:31:47
461 
困惑。别担心!接下来南京峟思手把手教你正确使用VW-102A读数仪,快速获取精准数据!一、VW-102A读数仪是什么?为什么需要它?VW-102A读数仪是专门为振
2025-04-21 14:28:41
638 
总结,手把手教你逆袭甩锅。Modbus TCP常见问题主要包括连接建立、错误代码识别、数据处理和地址冲突等。 以下是一些常见问题的解答: 问题一: 如何判断Modbus TCP连接是否建立? 答:进行
2025-04-16 17:17:57
1259 
;HelloWorld"到"Hey,AI"记得刚入行时,点亮一个LED灯都激动半天。如今,我们的嵌入式设备已经可以直接和AI大模型对话了!这不仅是技术的进步,更是开发思路的革命。今天,我将手把手教大家如何在开发板上接
2025-04-11 18:19:08
1889 
博主好!致敬叶涛 管锴 张心雨三位AI具身智能-智能体方面的专家、导师!
《零基础开发AI Agent——手把手教你用扣子做智能体》一不懂编程的多数大众也可以开发Agent,这意义深远,功德无量
2025-04-10 12:16:28
一、物理层深度剖析 1.1 差分信号的本质 CAN总线采用****双线差分传输 ,核心原理图解: markdown CAN_H ────── /───────── / ___ / CAN_L ──────/ ───────── 显性状态(Dominant) :CAN_H电压 ≥ 2.5V,CAN_L ≤ 1.5V → 差值≥1V 隐性状态(Recessive) :CAN_H/CAN_L均为2.5V → 差值≈0V 物理层参数对照表 : 参数 标准值 测试方法 终端电阻 120Ω ±1% 万用表直接测量 最大传输距离 10km @ ≤5Kbps 示波器+时延测试仪 波特率容差 ±1% 专用CAN分析仪
2025-04-10 11:10:29
1054 一、物理层深度剖析
1.1 差分信号的本质
CAN总线采用****双线差分传输,核心原理图解:
markdown
CAN_H ──────\\\\ /─────────
\\\\/
\\\\___/
CAN_L ──────/\\\\─────────
显性状态(Dominant):CAN_H电压 ≥ 2.5V,CAN_L ≤ 1.5V → 差值≥1V
隐性状态(Recessive):CAN_H/CAN_L均为2.5V → 差值≈0V
物理层参数对照表:
参数
标准值
测试方法
终端电阻
120Ω ±1%
万用表直接测量
最大传输距离
10km @ ≤5Kbps
示波器+时延测试仪
波特率容差
±1%
专用CAN分析仪
共模电压抑制
±2V
隔离示波器测量
1.2 波特率计算公式
markdown
位时间 = 同步段 + 传播时间段 + 相位缓冲段1 + 相位缓冲段2
总位数 = 同步段(SJW) + 时间段1(TS1) + 时间段2(TS2)
STM32配置示例(500Kbps):
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; // 同步跳转宽度=1TQ
hcan1.Init.TimeSeg1 = CAN_BS1_9TQ;// 时间段1=9TQ
hcan1.Init.TimeSeg2 = CAN_BS2_4TQ;// 时间段2=4TQ
// 总位时间=1+9+4=14TQ → 时钟频率=8MHz → TQ=0.125μs → 波特率=1/(14 * 0.125μs)=500Kbps
1.3 终端电阻调试技巧
错误现象:总线波形畸变、通信不稳定
检测方法:
断电测量总线两端电阻(应为120Ω±5%)
上电后用示波器观察终端反射波形
解决方案:
# 终端电阻计算公式(单位Ω)
def calc_termination_resistance(length):
# 每米电缆约60Ω特性阻抗
return 120 - (length * 60) / 1000
# 示例:总线长度40m → 120 - 24 = 96Ω → 需补48Ω电阻
二、数据链路层全解析(帧结构+仲裁机制)
2.1 CAN帧类型对比表
帧类型
标识符长度
用途
DLC最大值
标准帧
11位
普通数据传输
8字节
扩展帧
29位
复杂设备通信
8字节
远程帧
11/29位
请求数据
-
错误帧
-
错误通知
-
2.2 经典仲裁过程演示
场景:三个节点同时发送数据
markdown
节点A: ID=0x100 (0b000100000000)
节点B: ID=0x200 (0b001000000000)
节点C: ID=0x080 (0b000010000000)
仲裁过程:
第一位:全显性 → 继续比较
**第二位:A=0, B=0, C=1 → C失去仲裁权**
后续位比较后,A胜出总线使用权
STM32仲裁配置要点:
// 使能自动重传功能(默认开启)
hcan1.Init.AutoRetransmission = ENABLE;
// 设置重试次数(最大16次)
hcan1.Init.RetryCount = 3;
2.3 错误检测机制详解
五级错误防护体系:
CRC校验:15位循环冗余校验
位填充:每5个相同电平插入相反电平
ACK校验:接收节点必须发送显性确认
帧格式校验:7个保留位必须为隐性
总线监控:持续检测总线逻辑电平
错误计数器动态调整算法:
markdown
当检测到错误时:
TEC += 8(发送错误)或 REC += 1(接收错误)
当TEC > 127时:进入总线关闭状态
2.4 位时间同步技术
同步机制:
硬同步:在帧起始位强制对齐
重新同步:通过调整时间段2补偿时钟偏差
STM32时间参数配置示例:
// 配置同步跳转宽度为1个时间量子
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
// 时间段分配(假设系统时钟16MHz)
CAN_BtrTypeDef sCanBtr;
sCanBtr.SyncJumpWidth = CAN_SJW_1TQ;
sCanBtr.TimeSeg1 = CAN_BS1_9TQ;// 传播延迟补偿
sCanBtr.TimeSeg2 = CAN_BS2_4TQ;// 相位缓冲
三、数据链路层核心机制
3.1 CAN协议栈全景图
应用层(CANopen/J1939)
↓
网络层(路由/错误处理)
↓
数据链路层(帧结构/仲裁)
↓
物理层(差分信号/终端电阻)
3.2 帧结构深度拆解
标准帧格式(11位ID):
| 仲裁场(11b) | 控制场(6b) | 数据场(0-8B) | CRC场(15b) | ACK场(1b) | 帧结束(7b) |
仲裁场:包含节点ID和帧类型标识
控制场:DLC(数据长度码) + IDE(扩展标识符)
CRC场:15位循环冗余校验(生成多项式:x¹⁵+x¹⁴+...+1)
STM32 CRC配置示例:
// CAN1 CRC初始化
hcan1.Instance->CRCD = 0xFFFF; // 初始值
hcan1.Instance->CRCSA = 0x0000;// 起始地址
3.3 仲裁机制详解
29位扩展帧仲裁过程:
优先级位 → 源地址 → 参数组号(PGN)
优先级计算:ID31-ID26位决定(数值越小优先级越高)
源地址冲突检测:同一网络内节点地址必须唯一
仲裁时序仿真:
def can_arbitration(id_list):
sorted_ids = sorted(id_list, key=lambda x: bin(x).count(\'1\'))
return sorted_ids[0]
# 示例:三个节点同时发送
nodes = [0x18FEF100, 0x18FEF200, 0x18FEF300]
winner = can_arbitration(nodes)# 输出0x18FEF100
四、CANopen协议深度实战
4.1 对象字典(Object Dictionary)
OD结构示例:
索引类型描述
0x2000ARRAY 电机控制参数
0x2000[0]UINT16目标转速(rpm)
0x2000[1]FLOAT 加速度(m/s²)
0x2001RECORD故障代码
0x2001[0]BITFIELD 故障标志位
STM32 SDO传输实现:
// SDO客户端上传数据
void SDO_Upload(uint16_t index, uint8_t subindex) {
CO_SDO_Req req;
CO_SDO_ReqInit(&req);
req.Cmd = CO_SDO_CMD_UPLOAD_REQ;
req.Index = index;
req.SubIndex = subindex;
if (CO_SDO_Transmit(&req) == CO_SDO_OK) {
Process_SDO_Response(req.Data);
}
}
4.2 NMT网络管理
状态迁移图:
INIT → PRE-OPERATIONAL → OPERATIONAL → STOPPED
↑↑↓
└──RESET←───────────────────┘
心跳报文配置:
// 心跳生产者配置
CO_NMT_HeartbeatConfig(0x01, 0x00, 500);// 节点ID=1,周期500ms
五、J1939协议核心要点
5.1 参数组号(PGN)编码规则
PGN = PF(8b) << 8 | PS(8b)
PF: 参数组功能(0-255)
PS: 参数组子功能(0-255)
典型PGN解析:
PGN
PF
PS
描述
0xFEFC
0xFE
0xFC
发动机转速请求
0xFEF0
0xFE
0xF0
冷却液温度
0xFECA
0xFE
0xCA
车辆位置报告
5.2 多包数据传输
传输流程:
请求 → 确认 → 数据包1 → 数据包2 → ... → 结束符
STM32多包发送实现:
// 多包数据发送(最大12字节/包)
void CAN_Send_MultiPacket(uint8_t *data, uint16_t length) {
uint8_t packets[6][8] = {0};
uint8_t packet_count = (length + 7) / 8;
for (int i=0; i<packet_count; i++) {
packets[i][0] = 0x00;// 流控制字段
memcpy(&packets[i][1], &data[i*8], 8);
CAN_TransmitPacket(packets[i]);
}
}
六、STM32HAL库实战进阶
6.1 完整初始化流程
// 1. GPIO配置(CubeMX生成)
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
// CAN_RX/TX引脚配置
GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
// 2. CAN初始化(含过滤器配置)
void MX_CAN1_Init(void)
{
CAN_HandleTypeDef hcan1;
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 5;// 500Kbps
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_9TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_4TQ;
hcan1.Init.Mode = CAN_MODE_NORMAL;
if (HAL_CAN_Init(&hcan1) != HAL_OK) {
Error_Handler();
}
// 滤波器配置(接收ID=0x100-0x1FF)
CAN_FilterTypeDef sFilterConfig = {0};
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x100 << 13;
sFilterConfig.FilterIdLow = 0x1FF << 13 | 0xFFFF;
HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig);
}
6.2 数据收发实战
// 数据发送(PDO模拟)
void CAN_Send_PDO(uint8_t node_id, uint16_t position) {
CAN_TxHeaderTypeDef TxHeader = {0};
uint8_t TxData[8] = {0};
TxHeader.StdId = 0x200 + node_id;// PDO ID
TxHeader.IDE = CAN_ID_STD;
TxHeader.DLC = 2;
TxData[0] = (position >> 8) & 0xFF;
TxData[1] = position & 0xFF;
HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxData, &TxMailbox);
}
// 接收回调(带错误检测)
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
CAN_RxHeaderTypeDef RxHeader;
uint8_t RxData[8] = {0};
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData) == HAL_OK) {
if (RxHeader.DLC != 2) {
// 数据长度异常处理
return;
}
uint16_t value = (RxData[0] << 8) | RxData[1];
Process_Sensor_Data(value);
}
}
七、工业级应用案例解析
7.1 电动汽车三电系统
BMS电池管理:通过CAN总线监控单体电压/温度
电机控制器:接收扭矩指令并反馈转速
OBC车载充电机:与BMS通信实现充电保护
通信拓扑:
BMS → CAN → MCU → CAN → 电机控制器
↑↓
充电桩
7.2 智能仓储机器人
多机协同:50+台AGV通过CAN总线同步路径规划
实时监控:电量/故障状态实时上报
抗干扰方案:
双绞线屏蔽层接地
隔离收发器(如ADuM1201)
冗余帧重传机制
八、调试与优化技巧
示波器观察:
检查CAN_H/CAN_L差分波形(正常应为方波)
波特率验证(500Kbps对应周期2μs)
错误分析:
错误帧计数:HAL_CAN_GetError(&hcan1)
总线负载率:CAN总线分析仪检测
性能优化:
使用CAN FD(Flexible Data Rate)提升带宽
优化过滤器配置减少CPU开销
采用环形缓冲区处理高频率数据
九、扩展学习资源
经典CAN vs CAN FD:带宽从1Mbps提升至5Mbps
AUTOSAR架构:标准化汽车软件架构
TSN时间敏感网络:工业4.0通信新标准
2025-04-10 11:08:08
随着工业自动化和信息化的快速发展,不同系统之间需要高效、灵活地进行数据交互与通信。然而,各系统往往采用不同的通信协议和报文格式,导致数据传输存在兼容性问题。软件网关应运而生,它通过图形界面配置、零代码开发的方式,实现报文的灵活映射与转发。这种模块化设计不仅降低了开发难度和成本,还提高了系统的可扩展性和维护性,能够满足复杂多变的工业场景需求,为系统集成与数据交
2025-04-03 20:02:56
1163 
为例,给大家从测量范围、精度、环境适应性三大核心维度,手把手教你选对型号!第一步:明确工程监测需求选型前需明确以下问题:1、监测目标:需监测的缝宽变化范围是多大?
2025-04-03 10:58:41
654 
在土木工程中,振弦式土体沉降计是监测土石坝、边坡、地基等沉降变形的“眼睛”。但想要它精准工作,安装步骤是关键!如果埋设不当或组件连接错误,可能导致数据偏差甚至设备损坏。南京峟思将一步步为大家解析振弦式土体沉降计的安装流程,从钻孔到调试,帮你避开常见“坑点”,确保测量结果可靠耐用!一、安装前:准备工作别马虎工具备齐,事半功倍钻孔工具:钻孔机(孔径≥90mm)、
2025-04-03 10:20:44
536 
的今天,高端显卡维修已成“暴利暗流”。虚高报价、偷换配件、技术陷阱……用户稍有不慎,轻则损失数万,重则设备报废。今天小助手将揭露行业乱象,手把手教你识别套路,并推荐
2025-04-02 20:31:44
3453 
甚至微型服务器时,你是否也遇到过程序卡顿、视频处理延迟的尴尬?今天我们就手把手教你用Python并行处理技术,让树莓派的性能瞬间翻倍!欢迎在评论区晒出你的优化方案,
2025-03-26 17:08:28
757 
在物联网开发领域,选择合适的硬件平台与操作系统是项目成功的关键。本文将带领你从零开始,通过详细的步骤与示例代码,掌握Air780EPM与LuatOS的入门开发流程,并深入探讨其核心功能与扩展潜力。 一、必须先要告诉你的一些废话 这里,先要告诉你一些前提条件,虽然听着像是废话,但是如果你不知道的话,可能后面会比较懵逼,所以还是希望你能够认真看一看这一节。 这个项目的产品定义是:模组每隔3秒,就往串口输出一次 “ hello world” 字符
2025-03-25 16:38:31
570 
Developer Ethan 同学,手把手教您编译/构建 KiCad 源码: 开发工具安装 环境变量配置 使用 VS2022 构建 KiCad 参与直播的小伙伴还有机会获得 KiCon Badge
2025-03-24 11:14:00
1472 
资料介绍:
STM32Cube学习笔记,一步一步手把手带你进入STM32Cube的世界,包括点灯,按键,串口,ADC,DAC等等一共16篇。
纯分享贴,有需要可以直接下载附件获取完整资料!
(如果内容有帮助可以关注、点赞、评论支持一下哦~)
2025-03-22 17:02:25
介绍本文适用于零基础,手把手教你搭建基于STM32单片机控制亿佰特E22-M系列、E220-M系列和E32-M系列模块,旨在降低M系列模块开发难度,帮助大家更快上手M系列的模组。本次教程分为“上篇
2025-03-20 19:33:08
728 
《零基础开发AI Agent——手把手教你用扣子做智能体》是一本为普通人量身打造的AI开发指南。它不仅深入浅出地讲解了Agent的概念和发展,还通过详细的工具介绍和实战案例,帮助读者快速掌握
2025-03-18 12:03:28
为助力开发者迅速掌握『KaihongOS轻量系统开发技术』与『星闪无线通信技术』,实现快速上手与深度体验,“开鸿Developer社区”携手“电子发烧友”再次联合推出《手把手教你做星闪无人机
2025-03-18 10:33:15
”携手“电子发烧友”联合推出了 《KaihongOS手把手系列直播课程》,该系列课程以实际产品为案例,详细讲解每个产品的开发全流程。
此次首发内容是《手把手教你做PC-KaihongOS笔记本电脑开发
2025-03-18 10:25:04
4G模组Air780EPM作为广和通推出的高性能Cat.1bis无线通信模块,凭借其低功耗、高集成度及丰富的外设接口,在工业物联网、智能终端、车载设备等领域展现出卓越的适配性。 一、概述 开发方式 :Air780EPM 仅支持 LuatOS 软件开发方式,不支持 AT 指令开发方式。若使用 AT 指令开发方式,可选择 Air780EQ。 LuatOS 开发优势 :相对 C-SDK 入门更简单,开发更方便,开发时间更快。 适用对象 :本文的 GPIO 设计指导针对 Air780EPM 用于 LuatOS 开发方式时的注意事项。 G
2025-03-17 16:07:20
928 
【第四章 定时任务】手把手教你玩转新版正点原子云
承接上篇,除了报警联动这个功能,原子云还有一个特色功能也是各开发者喜欢用的,定时任务功能。
【正点原子】云平台:原子云(点击登录原子云)
前言
2025-03-13 10:19:45
本帖最后由 jf_85110202 于 2025-3-13 14:43 编辑
【第三章 警报联动】手把手教你玩转新版正点原子云
新版原子云网址:原子云(点击登录原子云)
原子云特色功能:设置
2025-03-12 16:05:20
【第二章 模型与设备连接】手把手教你玩转新版正点原子云玩过物联网的朋友们都知道,我们在接触各大主流云平台时会知道物模型的概念。
本实验就是针对原子云中模型与设备连接,举个简单例子说明,温度传感器通过
2025-03-12 09:27:14
的新技术实践指南,助你把握科技大势。
▊《零基础开发AI Agent——手把手教你用扣子做智能体》
叶涛管锴张心雨 著
不懂编程也可以开发Agent
Agent(智能体)是大模型落地的重要方向
2025-03-10 16:29:54
【第一章 透传策略】手把手教你玩转新版正点原子云
1. 本次实验使用正点原子D40 Mini 4G Cat1 DTU数传模块
1.1 D40数传模块资料
具体使用和资料下载可到:D40 Mini
2025-03-05 16:52:19
开发者集结!《手把手教你做星闪无人机》第二课开讲啦!
2025-02-17 19:40:50
703 
带来的现实。无论你是开发者、研究员、内容创作者,还是 AI 爱好者,OpenAI 强大的语言模型都能为你的工作和生活带来无限可能。 本指南将手把手教你获取并使用 OpenAI API 密钥,从零基础到高级应用,全程无障碍!针对中国用户,我们提供独家优化方案,让你轻松绕过
2025-02-15 17:26:43
5582 
导读面对一台ZMC600E运动控制器与多台伺服电机,我们该怎样让它工作起来?本文带你了解PLCOPen,并详细讲解如何使用AWStudio控制电机运动。在自动化领域,运动控制是一件很复杂的事情,包含了上位机通讯,工业现场总线通信协议,运动控制算法,伺服电机控制等领域知识。致远电子自主研发的AWStudio的AWPLC解决方案可以快速实现运动控制编程。AWSt
2025-02-10 11:38:23
1217 
在这篇教程中,将教你使用Arduino创建一个互动式LED墙壁时钟。这个项目结合了创意和技术,设计出一个功能性强且视觉效果惊人的时钟,它配备了互动式的LED灯。无论你是Arduino的新手还是已有
2025-02-08 17:47:12
”再次联合推出《手把手教你做星闪无人机—KaihongOS星闪无人机开发实战》系列课程,该课程与《手把手教你做PC—KaihongOS笔记本电脑开发实战》同步并行,
2025-01-13 19:42:52
921 
直播预告看了这么多期直播,你是否也会好奇?NVH实际用起来难不难?不同类型故障的探头布置有何差异?软件该如何设置?燃油车与新能源电车测试时有何不同?我们又为何总是强调,维修后再次诊断的重要性?关于这些问题,你都可以在我们本周的直播中找到答案!本周四,1月9日晚8点,全国技术能手、上海市五一劳动奖章获得者——林创创老师,将空降虹科Pico直播间!从汽修冠军到经
2025-01-08 11:40:59
824 
”携手“电子发烧友”联合推出了《KaihongOS手把手系列直播课程》,该系列课程以实际产品为案例,详细讲解每个产品的开发全流程。此次首发内容是《手把手教你做PC-
2025-01-06 20:46:51
916 
评论