低功耗2.4g无线模组ESP32-C2乐鑫科技代理商名单飞睿Rust+嵌入式开发介绍
Rust的起源
Rust编程语言的灵感源于一次偶然的事件。2006年,Graydon Hoare回到他位于温哥华的公寓时,发现电梯因为软件崩溃而无法正常运行。作为住在21楼的他,不得不步行爬楼。他心中不禁想道:“我们是计算机专业的人,怎么连一个正常运行的电梯都做不好呢!”这次经历让Hoare决定设计一门全新的编程语言,他希望这门语言能够在不引入内存错误的情况下,生成更短、更快的代码。
时光飞逝,已经过去了18个年头,如今Rust已经成为全球炙手可热的新兴编程语言,每年都吸引着越来越多的关注。截至2020年一季度,大约有60万开发者选择使用Rust进行开发,而到了2022年一季度,使用人数已经飙升至220万。许多知名科技巨头,比如Mozilla、Dropbox、Cloudflare、Discord、Facebook(Meta)、Microsoft等,都广泛采用Rust语言来编写他们的代码库。
根据2021年的开发者调查数据显示,低功耗2.4g无线模组ESP32-C2乐鑫科技代理商名单飞睿介绍到Rust语言连续六年获得了"受开发者喜爱的编程语言"的称号。
可以用于嵌入式开发的编程语言
与Web开发和桌面开发相比,嵌入式开发受到的关注较少。这可能是因为以下原因:
硬件限制:嵌入式系统硬件资源有限,例如性能和内存,这使得软件开发变得更加具有挑战性。
市场局限:与Web和桌面应用相比,嵌入式市场规模较小,嵌入式编程开发者的经济回报相对较少。
嵌入式开发的要求是开发者必须具备对具体硬件和底层编程语言的专业知识。
与为Web和桌面应用开发软件相比,嵌入式系统开发软件需要进行代码测试和优化,以适应特定硬件要求,因此开发周期更长。
底层编程语言的限制在于它们提供的抽象较少,比如汇编语言和C语言。这意味着开发者可以直接访问硬件资源和内存,但也可能会引入内存错误的风险。
通过上述几个方面,我们可以感受到嵌入式开发的独特性,并且也能够理解为什么年轻的程序员不太喜欢嵌入式开发,相比之下,Web开发更受欢迎。低功耗2.4g无线模组ESP32-C2乐鑫科技代理商名单飞睿介绍到在使用现代流行的编程语言如Python、JavaScript或C#进行开发时,开发者无需关注每个处理器周期或内存使用的细节。
尽管这种便利带来了巨大的变化,但对于初次接触嵌入式开发的开发者来说,无论是新手还是有经验的Web、桌面或移动开发者,都会感到困难。因此,有必要设计一种专门用于嵌入式开发的现代编程语言。
为什么要选用Rust语言?
Rust是一种现代编程语言,发展时间不长。它专注于内存和线程安全,旨在开发可靠且安全的软件。另外,Rust还支持并发和并行操作,可实现高效利用资源,这在嵌入式开发中非常重要。Rust的应用范围越来越广泛,生态系统也正逐渐完善,越来越多追求高效与安全性的开发者开始将其视为理想的开发语言。低功耗2.4g无线模组ESP32-C2乐鑫科技代理商名单飞睿介绍到这些都是选择Rust作为嵌入式开发或关注安全性和可靠性项目的主要原因。
Rust相较于C和C++有哪些优势?
内存安全问题:Rust通过引入所有权和借用的概念,有效地消除了空指针解引用和缓冲区溢出等与内存相关的错误。也就是说,通过使用所有权和借用系统,Rust能够在编译时保证内存的安全性。在嵌入式开发中,由于内存和资源有限,检测和解决内存相关错误变得困难,因此Rust提供的内存安全保证显得更加重要。
并发安全:Rust完美支持零成本抽象、并发编程和多线程。利用内置的async/await语法和强大的类型系统,能够有效地消除常见的并发错误,如数据竞争等。这个特性不仅适用于嵌入式系统,各个领域的开发者都可以利用它轻松地编写安全高效的并发代码。
出色的性能:Rust在性能方面与C和C++相媲美,而且还能确保更可靠的内存安全和并发安全。
与C和C++相比,Rust更注重代码的可读性和降低错误的发生率。它引入了模式匹配、类型推导和函数式编程结构等特性,使代码编写和维护更加便捷,尤其适用于复杂的大型项目。
不断增长的生态系统:Rust的生态系统涵盖了各种库、工具和资源,供各个领域的开发者使用,包括嵌入式开发。低功耗2.4g无线模组ESP32-C2乐鑫科技代理商名单飞睿介绍到随着生态系统的不断壮大,开发者能够轻松地使用Rust构建项目,并找到所需的特定支持和资源。
Rust内建了Cargo包管理器,能够自动化构建、测试和发布流程,还能够创建新项目并管理依赖项。
与C和C++相比,Rust的不足之处在于以下方面:
尽管Rust有明显的优势,但它并非一门无懈可击的语言。与其他编程语言(例如C和C++)相比,它也有一些不足之处。
Rust的学习曲线陡峭:相较于C等其他编程语言,Rust的学习曲线更陡峭。开发者需要投入更多的时间和精力来理解它独特的特性,例如上文提到的所有权和借用系统等。对初次接触Rust的开发者来说,这可能是一种挑战。
Rust的编译时间较长:与其他语言相比,由于其高级类型系统和借用检查器,Rust需要更长时间来进行编译,尤其在大型工程中更加明显。
工具支持不足:尽管Rust的生态系统正在迅速扩展,但与已经存在几十年并积累了大量代码库的编程语言如C和C++相比,Rust的工具支持还显不足。在特定的项目中,找到并使用合适的工具可能稍有难度。
底层控制不足:与C和C++相比,Rust的安全特性可能会限制其在底层控制方面的能力。尽管Rust仍然支持特定的底层优化和直接与硬件交互,但这方面的难度稍高。
缺乏社区支持:与已经发展成熟的C和C++等编程语言相比,Rust仍然是一个相对较新的编程语言。它的社区规模较小,贡献代码的开发者以及可用资源、库和工具都相对较少。
总之,低功耗2.4g无线模组ESP32-C2乐鑫科技代理商名单飞睿介绍到与传统的嵌入式开发语言C和C++相比,Rust在内存安全、并发支持、性能、代码可读性和生态系统等方面都有很多优势。因此,越来越多的开发者在嵌入式开发中,特别是在注重安全、可靠性和稳定性的项目中选择了使用Rust。虽然与C和C++相比,Rust作为一种相对较新的语言以及其独特的特性存在一些不足之处,但是Rust的优势已经足以使其成为某些项目的选择。
怎样才能执行Rust代码呢?
根据不同的环境和应用需求,我们可以通过多种方式来运行基于Rust的固件。这些固件通常可以在宿主环境或裸机环境下运行。下面将对这两种环境进行详细介绍。
所谓宿主环境,是指计算机系统或者其他电子设备的操作环境,包括硬件设备、系统软件、网络协议等方面的细节,这些细节会影响软件运行的效率和稳定性。在开发软件时,需要考虑宿主环境的因素,以确保软件能够在不同的环境中运行,避免出现不必要的错误和异常情况。
与一般的个人电脑环境相似,Rust的宿主环境也能提供一个操作系统,用于构建Rust标准库(std)。标准库(std)是包含在各个Rust安装程序中的一系列模块和类型,能够支持多种构建Rust程序所需的功能,例如数据结构、网络配对、互斥锁和其他同步工具、输入输出等。
在STD环境下,您可以使用基于C的ESP-IDF开发框架中提供的功能。ESP-IDF提供的newlib环境可以支持您在该框架上构建Rust标准库。此外,您还可以将ESP-IDF作为操作系统构建Rust应用程序。这意味着您可以使用ESP-IDFAPI中的基于C的功能,并且可以利用除列出的标准库功能之外的所有功能。
以下是在ESP-IDF(FreeRTOS)上运行的blinky示例(更多示例可以在esp-idf-hal仓库中找到):
// 导入示例所需外设
use esp_idf_hal::delay::FreeRtos;
use esp_idf_hal::gpio::*;
use esp_idf_hal::peripherals::Peripherals;
// Start of our main function i.e entry point of our example
fn main() -> anyhow::Result<()> {
// 应用所需 ESP-IDF 补丁
esp_idf_sys::link_patches();
// 初始化所有所需外设
let peripherals = Peripherals::take().unwrap();
// 创建一个 led 对象,将其设置为 GPIO4 引脚的输出模式
let mut led = PinDriver::output(peripherals.pins.gpio4)?;
// 设置一个每 500 毫秒即切换 LED 开/关状态的无限循环
loop {
led.set_high()?;
// 进入睡眠模式,以防触发看门狗
FreeRtos::delay_ms(1000);
led.set_low()?;
FreeRtos::delay_ms(1000);
}
}
适用于宿主环境下的情形
为了在嵌入式系统中实现多种功能,可以考虑使用宿主环境。宿主环境提供了丰富的标准库,以支持诸如网络协议、文件输入/输出和复杂数据结构等功能。通过利用这些功能,您可以快速高效地构建复杂的应用程序。
要求具备可移植性:标准库提供了一套标准化的API,可以在不同的平台和架构上使用,方便编写可移植性和可重用性的代码。
快速开发变得更轻松了:标准库提供了丰富的功能,能够快速高效地构建应用程序,而不需要过多关注底层细节。
裸机环境是指没有操作系统的环境。如果编译的Rust程序具有no_std属性,那么该程序无法使用上述std章节中提到的一些特定功能。低功耗2.4g无线模组ESP32-C2乐鑫科技代理商名单飞睿介绍到尽管仍然支持使用网络连接或复杂数据结构等功能,但实现方式会更加复杂。no_std程序依赖于Rust核心语言特性,包括数据类型、控制结构和底层内存管理,这些特性在所有Rust环境中都可用。这种环境在嵌入式编程中非常实用,特别适合于内存资源有限、需要对硬件进行低级别控制的场景。
下面是在裸机环境下(不使用操作系统)运行的blinky示例(更多示例存储在esp-hal仓库中):
#![no_std]
#![no_main]
// 导入示例所需外设
use esp32c3_hal::{
clock::ClockControl,
gpio::IO,
peripherals::Peripherals,
prelude::*,
timer::TimerGroup,
Delay,
Rtc,
};
use esp_backtrace as _;
// 设置程序执行的起始点
// 因为这是一个 `no_std` 程序,不存在主函数
#[entry]
fn main() -> ! {
// 初始化所有所需外设
let peripherals = Peripherals::take();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
// 禁用看门狗定时器。对于 ESP32-C3 来说,包括 Super WDT、
// RTC WDT 和 TIMG WDT
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
let timer_group0 = TimerGroup::new(
peripherals.TIMG0,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt0 = timer_group0.wdt;
let timer_group1 = TimerGroup::new(
peripherals.TIMG1,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt1 = timer_group1.wdt;
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
wdt1.disable();
// 将 GPIO4 设置为输出,并将其初始状态设置为高电平
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// 创建一个 led 对象,将其设置为 GPIO4 引脚的输出模式
let mut led = io.pins.gpio5.into_push_pull_output();
// 启动 LED
led.set_high().unwrap();
// 初始化延迟外设,并在循环中
// 使用它来切换 LED 的状态
let mut delay = Delay::new(&clocks);
// 设置一个每 500 毫秒即切换 LED 开/关状态的无限循环
loop {
led.toggle().unwrap();
delay.delay_ms(500u32);
}
}
适用于没有任何软件或应用程序的裸机环境
如果嵌入式系统资源有限,需要减少内存占用,可以考虑使用裸机环境,因为标准库会显著增加终二进制文件的大小和编译时间。
要实现嵌入式系统中的直接硬件控制,例如底层设备驱动程序或访问特定硬件功能,建议采用裸机环境,这样可以避免std(标准库)的抽象层增加与硬件直接交互的难度。
当涉及到需要实时约束或对时间敏感的应用程序时,如果嵌入式系统要求具备实时性能或低延迟响应时间,可以考虑使用裸机环境。低功耗2.4g无线模组ESP32-C2乐鑫科技代理商名单飞睿介绍到因为使用标准库可能会导致意外的延迟和开销问题。
定制需求:裸机环境能够支持更多自定义配置,并且可以准确控制应用程序的行为,非常适合特定或非标准的环境。
总结:是否应该从C语言转向Rust语言呢?
如果你想要开发一个对内存安全或并发性有要求的项目或任务,可以考虑将代码从C语言转换为Rust语言。但对于已经完成并正常运行的C语言项目来说,重新编写和测试整个代码库以适应Rust语言是没有必要的。使用Rust语言调用C语言函数并不困难,所以可以考虑保留现有的C代码,并使用Rust编写新的功能和模块。另外,你也可以尝试使用Rust语言来编写ESP-IDF组件。总之,是否将代码从C语言转换为Rust语言需要根据具体需求进行权衡。