要点:
片上系统 (SoC) 与 MCU 类似,但与那些类型的嵌入式系统不同,它具有一定程度的集成,同时仍需要大量外部组件才能运行。 它们通常作为单板实现(单板计算机 (SBC))的一部分,包括 PC/104 标准,以及最近的外形尺寸,例如 Raspberry Pi 和衍生板。
大多数 SoC 都是基于 ARM(Cortex-A 系列)的,尽管 MIPS 也很常见。 SBC 通常用于工业环境中。
其他实例是批量生产的电路板,例如智能手机的电路板,它们没有形成预定义的外形尺寸,但仍然遵循具有 SoC 和外部 RAM、ROM 和存储以及各种外围设备的相同模式。
外围设备被定义为向计算机系统添加 I/O 或其他功能的辅助设备。 它可以是从 I2C、SPI 或 SD 卡控制器到音频或图形设备的任何设备。 其中大部分是物理 SoC 的一部分,其他部分是通过 SoC 向外界公开的接口添加的。 外部外设的示例包括 RAM(通过 RAM 控制器)和实时时钟 (RTC)。
我们将研究基于 SBC 的解决方案的实际实施,该解决方案为房间监控执行以下功能:
示例基础情景是,我们有一个房间,我们希望能够监控其锁定的状态,并在房间内部有一个开关,调节房间中的非永久性电源插座是否通电。 打开房间状态开关将为这些插座供电。 我们还希望通过 MQTT 发送通知,以便房间或其他地方的其他设备可以更新其状态。
MQTT 是一种基于 TCP/IP 的简单二进制发布/订阅协议。 它提供了一种轻量级通信协议,适用于资源受限的应用,例如传感器网络。 每个 MQTT 客户端都与中央服务器通信:MQTT 代理。
为了让植物保持活力,你需要考虑以下因素:营养、灯光和水。
其中,前两种通常分别采用营养丰富的土壤和将植物放置在光线充足的地方,满足这两点后,保持植物存活的主要问题通常是第三点,因为这必须每天处理。
在这里,不仅仅是保持水加满那么简单,而是保持在土壤有足够水但又不过多的范围内。 土壤中水分过多会影响植物通过根部吸收的氧气量。 结果,土壤中的水分过多,植物就会枯萎死亡。
另一方面,水太少意味着植物无法吸收足够的水来补偿通过叶子蒸发的水,也无法将营养物质输送到根部。 在这种情况下,植物也会枯萎死亡。
当手动给植物浇水时,我们倾向于粗略估计植物何时可能需要更多的水,并用手指对表层土壤的湿度进行表面测试。 这不能告诉我们植物根部周围实际存在多少水,是否远低于土壤上层。
基础代码:
#include "base_module.h"
BaseModule::SubModule BaseModule::modules[32];
uint32 BaseModule::active_mods = 0x0;
bool BaseModule::initialized = false;
uint8 BaseModule::modcount = 0;
void BaseModule::init() {
CO2Module::initialize();
IOModule::initialize();
JuraModule::initialize();
JuraTermModule::initialize();
MotionModule::initialize();
PlantModule::initialize();
PwmModule::initialize();
SwitchModule::initialize();
THPModule::initialize();
}
bool BaseModule::registerModule(ModuleIndex index, modStart start, modShutdown shutdown) {
// Initialise if necessary.
if (!initialized) {
for (uint8 i = 0; i < 32; i++) {
modules[i].start = 0;
modules[i].shutdown = 0;
modules[i].index = index;
modules[i].bitmask = (1 << i);
modules[i].started = false;
}
initialized = true;
}
if (modules[index].start) {
return false;
}
// Add the module if it hasn't been registered yet.
modules[index].start = start;
modules[index].shutdown = shutdown;
++modcount;
return true;
}
// --- NEW CONFIG ---
bool BaseModule::newConfig(uint32 config) {
OtaCore::log(LOG_DEBUG, String("Mod count: ") + String(modcount));
uint32 new_config = config ^ active_mods; // XOR comparison.
if (new_config == 0x0) {
OtaCore::log(LOG_INFO, "New configuration was 0x0. No change.");
return true;
}
OtaCore::log(LOG_INFO, "New configuration: " + new_config);
for (uint8 i = 0; i < 32; ++i) {
if (new_config & (1 << i)) {
OtaCore::log(LOG_DEBUG, String("Toggling module: ") + String(i));
if (modules[i].started) {
if ((modules[i]).shutdown()) {
modules[i].started = false;
active_mods ^= modules[i].bitmask;
}
else {
OtaCore::log(LOG_ERROR, "Failed to shutdown module.");
return false;
}
}
else {
if ((modules[i].start) && (modules[i]).start()) {
modules[i].started = true;
active_mods |= modules[i].bitmask;
}
}
}
}
return true;
}
温湿度检测代码示例:
#include "bme280_module.h"
BME280* BME280Module::bme280 = 0; //(DHT_PIN);
Timer BME280Module::timer;
// --- INIT ---
bool BME280Module::init() {
// Ensure we got a sensor class instance.
if (!bme280) { bme280 = new BME280(); }
// Wait for sensor startup, then start logging.
if (bme280->EnsureConnected()) {
OtaCore::log(LOG_INFO, "Connected to BME280 sensor.");
bme280->SoftReset(); // Ensure clean start.
bme280->Initialize(); // Initialise and pull calibration data (?).
}
else {
OtaCore::log(LOG_ERROR, "Not connected to BME280 sensor.");
return false;
}
// Create timer.
timer.initializeMs(2000, BME280Module::readSensor).start();
return true;
}
bool BME280Module::shutdown() {
timer.stop();
delete bme280;
bme280 = 0;
return true;
}
void BME280Module::config(String cmd) {
Vector output;
int numToken = splitString(cmd, '=', output);
if (output[0] == "set_pin" && numToken > 1) {
//dhtPin = output[1].toInt();
}
}
// --- READ SENSOR ---
void BME280Module::readSensor() {
float t, h, p;
if (bme280->IsConnected) {
t = bme280->GetTemperature();
h = bme280->GetHumidity();
p = bme280->GetPressure();
// Publish via MQTT.
OtaCore::publish("nsa/temperature", OtaCore::getLocation() + ";" + t);
OtaCore::publish("nsa/humidity", OtaCore::getLocation() + ";" + h);
OtaCore::publish("nsa/pressure", OtaCore::getLocation() + ";" + p);
}
else {
OtaCore::log(LOG_ERROR, "Disconnected from BME280 sensor.");
}
}
此示例基本概述了如何在嵌入式项目中使用 FPGA。 它使用 FPGA 对输入进行采样并测量电压或类似电压,就像示波器一样。 然后,生成的 ADC 数据通过串行链路发送到基于 C++/Qt 的应用程序,该应用程序将显示数据。