LR物联网代表了连接的未来,一场开启物联网通信新可能的长距离革命。
A
A
硬件概览
它是如何工作的?
LR IoT Click基于Semtech Corporation的LR1110,这是一款旨在增强基于LoRa®的地理定位应用的长距离、超低功耗收发器。该平台解决方案支持LoRa®和(G)FSK调制,用于通过主动的868/915MHz ISM频段天线进行LPWAN应用,Mikroe也提供这种天线。LR1110还具有低功耗的多频段前端,可以获取多个用于地理定位的机会信号(802.11b/g/n WiFi AP MAC地址、GNSS(GPS、北斗)卫星信号),然后使用LPWAN网络将它们传输到地理定位服务器,该服务器计算物体的位置。此Click板™经过优化,适用于需要室内和室外地理定位的低功耗应用,例如资产定位、可追溯性、遗失和盗窃预防、资产回收和库存管理。LR1110使用三种操作模式:WiFi被动扫描和两种用于户外地理定位的GNSS模式,例如GNSS自主和辅助模式。通过WiFi被动扫描,LR1110可以发现设备附近可用的WiFi
b/g/n接入点并提取MAC地址以进行地理定位。目标是至少获取2个MAC地址,并在发送到在线WiFi查找服务后定位设备。LR1110实现的WiFi被动扫描还可以提取接入点在信标或探测响应中包含的国家代码信息。除了WiFi,还有一个快速且低功耗的GNSS扫描器,使用我们提供的主动GNSS天线,捕捉GNSS卫星广播的信号的一小部分并提取计算设备位置所需的信息。这些信息然后被汇集成NAV消息,可以发送到后端系统以计算设备位置。如前所述,GNSS扫描器有两种操作模式:自主和辅助。在自主模式下,不需要任何辅助数据,LR1110会搜索和解码强卫星的信号以进行室内/室外检测,而在辅助模式下,可以搜索所有可见卫星,并且需要与地理定位服务器连接以计算设备位置。此Click板™通过标准SPI接口与MCU通信,支持最常见的SPI模式——SPI模式0,最大频率为16MHz。它还具有
一个中断引脚,连接到mikroBUS™插槽的INT引脚,使主机MCU可以对LR1110系统中的特殊事件作出反应而无需寄存器轮询。一个“BUSY”指示器,标记为BSY,并连接到mikroBUS™插槽的PWM引脚,表示内部MCU无法接收来自主机MCU的任何命令,还有一个连接在mikroBUS™插槽RST引脚和板载复位按钮上的通用复位功能。它还使用两个LED指示器,标记为STAT1和STAT2,用于可选的GNSS和WiFi网络活动状态的视觉指示,当然也可以根据用户自己的愿望和需求进行配置。此Click板™仅可在3.3V逻辑电压水平下运行。使用具有不同逻辑电平的MCU之前,板必须进行适当的逻辑电压电平转换。此外,它配备了包含函数和示例代码的库,可用作进一步开发的参考。
功能概述
开发板
Arduino UNO 是围绕 ATmega328P 芯片构建的多功能微控制器板。它为各种项目提供了广泛的连接选项,具有 14 个数字输入/输出引脚,其中六个支持 PWM 输出,以及六个模拟输入。其核心组件包括一个 16MHz 的陶瓷谐振器、一个 USB 连接器、一个电
源插孔、一个 ICSP 头和一个复位按钮,提供了为板 子供电和编程所需的一切。UNO 可以通过 USB 连接到计算机,也可以通过 AC-to-DC 适配器或电池供电。作为第一个 USB Arduino 板,它成为 Arduino 平台的基准,"Uno" 符号化其作为系列首款产品的地
位。这个名称选择,意为意大利语中的 "一",是为了 纪念 Arduino Software(IDE)1.0 的推出。最初与 Arduino Software(IDE)版本1.0 同时推出,Uno 自此成为后续 Arduino 发布的基础模型,体现了该平台的演进。
微控制器概述
MCU卡片 / MCU

建筑
AVR
MCU 内存 (KB)
32
硅供应商
Microchip
引脚数
28
RAM (字节)
2048
你完善了我!
配件
Click Shield for Arduino UNO 具有两个专有的 mikroBUS™ 插座,使所有 Click board™ 设备能够轻松与 Arduino UNO 板进行接口连接。Arduino UNO 是一款基于 ATmega328P 的微控制器开发板,为用户提供了一种经济实惠且灵活的方式来测试新概念并构建基于 ATmega328P 微控制器的原型系统,结合了性能、功耗和功能的多种配置选择。Arduino UNO 具有 14 个数字输入/输出引脚(其中 6 个可用作 PWM 输出)、6 个模拟输入、16 MHz 陶瓷谐振器(CSTCE16M0V53-R0)、USB 接口、电源插座、ICSP 头和复位按钮。大多数 ATmega328P 微控制器的引脚都连接到开发板左右两侧的 IO 引脚,然后再连接到两个 mikroBUS™ 插座。这款 Click Shield 还配备了多个开关,可执行各种功能,例如选择 mikroBUS™ 插座上模拟信号的逻辑电平,以及选择 mikroBUS™ 插座本身的逻辑电压电平。此外,用户还可以通过现有的双向电平转换电压转换器使用任何 Click board™,无论 Click board™ 运行在 3.3V 还是 5V 逻辑电压电平。一旦将 Arduino UNO 板与 Click Shield for Arduino UNO 连接,用户即可访问数百种 Click board™,并兼容 3.3V 或 5V 逻辑电压电平的设备。
868MHz直角橡胶天线是一种紧凑而多功能的无线通信解决方案。其工作频率范围为868-915MHz,确保最佳的信号接收和传输。具有50欧姆阻抗,兼容各种设备和系统。这款天线具有2dB增益,增强信号强度并延长通信范围。其垂直极化进一步提高了信号清晰度。设计能够处理高达50W的输入功率,是各种应用的坚固选择。天线长度仅为48毫米,既隐蔽又实用。SMA公头连接器确保与设备的连接安全可靠。无论是与物联网设备、远程传感器或其他无线技术配合使用,868MHz直角天线都能提供您所需的性能和灵活性,实现无缝通信。
这款GPS有源嵌入式天线是我们提供的所有GPS/GNSS Click板™的绝佳选择。凭借其高增益和有源频段过滤功能,当需要增强定位时,它是完美的选择。它可以直接安装在PCB上。GPS/GNSS模块配有一根10厘米长的小电缆,允许其远离小型IPEX连接器进行定位。
WiFi橡胶2.4GHz天线是一款为搭载WiFi模块的Click板™应用设计的多功能配件。这款天线专为增强无线连接而量身定制,是开发人员和工程师的必备之选。天线顶端采用直角SMA公头连接器,能够与Click板™或SMA母模块连接器无缝集成。这种用户友好型设计简化了安装,并确保在各种设置中的灵活性。工作在2400-2500MHz频率范围内,这款天线保证在广泛的WiFi网络中提供可靠连接。其50欧姆阻抗促进了高效的信号传输,而2dB增益显著增强了信号强度和范围。100MHz带宽轻松满足数据传输和通信稳定性需求。垂直极化进一步提高了信号接收能力。天线可以处理最高50W的输入功率,使其适用于高功率应用而不影响性能。其紧凑的50毫米长度确保其隐蔽且不引人注目。无论您是在设计物联网设备、智能家居应用还是工业设备,这款配备SMA公头连接器的WiFi橡胶天线都是确保最佳无线连接的理想选择。它是一款强大的工具,可使您的设备在无线技术中保持可靠连接和有效通信。
使用的MCU引脚
mikroBUS™映射器
“仔细看看!”
Click board™ 原理图

一步一步来
项目组装
实时跟踪您的结果
应用程序输出
1. 应用程序输出 - 在调试模式下,“应用程序输出”窗口支持实时数据监控,直接提供执行结果的可视化。请按照提供的教程正确配置环境,以确保数据正确显示。

2. UART 终端 - 使用UART Terminal通过USB to UART converter监视数据传输,实现Click board™与开发系统之间的直接通信。请根据项目需求配置波特率和其他串行设置,以确保正常运行。有关分步设置说明,请参考提供的教程。

3. Plot 输出 - Plot功能提供了一种强大的方式来可视化实时传感器数据,使趋势分析、调试和多个数据点的对比变得更加直观。要正确设置,请按照提供的教程,其中包含使用Plot功能显示Click board™读数的分步示例。在代码中使用Plot功能时,请使用以下函数:plot(insert_graph_name, variable_name);。这是一个通用格式,用户需要将“insert_graph_name”替换为实际图表名称,并将“variable_name”替换为要显示的参数。

软件支持
库描述
该库包含 LR IoT Click 驱动程序的 API。
关键功能:
lriot_get_wifi_scan_results
- 此函数执行WiFi扫描并读取结果lriot_get_gnss_scan_results
- 此函数执行GNSS扫描并读取结果lriot_send_lora_message
- 此函数向接收器发送LoRa消息
开源
代码示例
完整的应用程序代码和一个现成的项目可以通过NECTO Studio包管理器直接安装到NECTO Studio。 应用程序代码也可以在MIKROE的GitHub账户中找到。
/*!
* @file main.c
* @brief LR IoT Click example
*
* # Description
* This example demonstrates the use of LR IoT click board by reading a GNSS and WiFi
* scanning results and displaying it on the USB UART. In the case of a tranceive firmware
* the communication between two devices over LoRa will be demonstrated as well.
*
* The demo application is composed of two sections :
*
* ## Application Init
* Initializes the driver, performs the click default configuration, and after that reads
* and displays the chip's firmware information. In the case you need to update or change the default
* firmware refer to the @b LRIOT_UPDATE_FIRMWARE and @b LRIOT_FIRMWARE_SELECTOR macro definition.
*
* ## Application Task
* There are 3 types of the example:
* 1. Modem firmware: reads a GNSS and WiFi scanning results and displays them on the USB UART.
* 2. Transcever firmware (application mode transmitter ): reads a GNSS and WiFi scanning results
* as well as the chip internal temperature and sends specific LoRa messages containing that information
* to the LoRa receiver.
* 3. Transcever firmware (application mode receiver): reads all incoming LoRa packets and displays them
* on the USB UART.
*
* @author Stefan Filipovic
*
*/
#include "board.h"
#include "log.h"
#include "lriot.h"
#include "conversions.h"
static lriot_t lriot;
static log_t logger;
#if ( LRIOT_FIRMWARE_SELECTOR == LRIOT_TRANSCEIVE_FIRMWARE )
// Comment out the line below in order to switch the application mode to receiver
#define DEMO_APP_TRANSMITTER
#endif
/**
* @brief LR IoT display gnss scan results function.
* @details This function parses a GNSS scan results object and displays it on the USB UART.
* @param[in] results : GNSS scan results object.
* See #lriot_gnss_scan_results_t object definition for detailed explanation.
* @return None.
* @note None.
*/
static void lriot_display_gnss_scan_results ( lriot_gnss_scan_results_t results );
/**
* @brief LR IoT display wifi scan results function.
* @details This function parses a WiFi scan results object and displays it on the USB UART.
* @param[in] results : WiFi scan results object.
* See #lriot_wifi_scan_results_t object definition for detailed explanation.
* @return None.
* @note None.
*/
static void lriot_display_wifi_scan_results ( lriot_wifi_scan_results_t results );
/**
* @brief LR IoT display chip info function.
* @details This function parses a chip firmware information object and displays it on the USB UART.
* @param[in] info : Chip information object.
* See #lriot_chip_info_t object definition for detailed explanation.
* @return None.
* @note None.
*/
static void lriot_display_chip_info ( lriot_chip_info_t info );
void application_init ( void )
{
log_cfg_t log_cfg; /**< Logger config object. */
lriot_cfg_t lriot_cfg; /**< Click config object. */
/**
* Logger initialization.
* Default baud rate: 115200
* Default log level: LOG_LEVEL_DEBUG
* @note If USB_UART_RX and USB_UART_TX
* are defined as HAL_PIN_NC, you will
* need to define them manually for log to work.
* See @b LOG_MAP_USB_UART macro definition for detailed explanation.
*/
LOG_MAP_USB_UART( log_cfg );
log_init( &logger, &log_cfg );
log_info( &logger, " Application Init " );
// Click initialization.
lriot_cfg_setup( &lriot_cfg );
LRIOT_MAP_MIKROBUS( lriot_cfg, MIKROBUS_1 );
if ( SPI_MASTER_ERROR == lriot_init( &lriot, &lriot_cfg ) )
{
log_error( &logger, " Communication init." );
for ( ; ; );
}
if ( LRIOT_ERROR == lriot_default_cfg ( &lriot ) )
{
log_error( &logger, " Default configuration." );
for ( ; ; );
}
lriot_chip_info_t chip_info;
if ( LRIOT_OK == lriot_get_chip_info ( &lriot, &chip_info ) )
{
lriot_display_chip_info ( chip_info );
}
log_info( &logger, " Application Task " );
}
void application_task ( void )
{
#if ( LRIOT_FIRMWARE_SELECTOR == LRIOT_TRANSCEIVE_FIRMWARE )
uint8_t lora_buffer[ LRIOT_LORA_PKT_PAYLOAD_LEN ] = { 0 };
#ifdef DEMO_APP_TRANSMITTER
lriot_gnss_scan_results_t gnss_results = { 0 };
lriot_wifi_scan_results_t wifi_results = { 0 };
uint8_t tmp_buf[ 30 ] = { 0 };
float temperature = 0;
if ( LRIOT_OK == lriot_get_gnss_scan_results ( &lriot, &gnss_results ) )
{
lriot_display_gnss_scan_results ( gnss_results );
}
memset( lora_buffer, 0, sizeof ( lora_buffer ) );
strcpy( lora_buffer, "Number of sattelites found is " );
uint16_to_str ( gnss_results.num_satellites, tmp_buf );
l_trim ( tmp_buf );
strcat( lora_buffer, tmp_buf );
if ( LRIOT_OK == lriot_send_lora_message ( &lriot, lora_buffer ) )
{
log_printf( &logger, "Send LoRa message - done\r\n" );
}
if ( LRIOT_OK == lriot_get_wifi_scan_results ( &lriot, &wifi_results ) )
{
lriot_display_wifi_scan_results ( wifi_results );
}
memset( lora_buffer, 0, sizeof ( lora_buffer ) );
strcpy( lora_buffer, "Number of WiFi scan results is " );
uint16_to_str ( wifi_results.num_wifi_results, tmp_buf );
l_trim ( tmp_buf );
strcat( lora_buffer, tmp_buf );
if ( LRIOT_OK == lriot_send_lora_message ( &lriot, lora_buffer ) )
{
log_printf( &logger, "Send LoRa message - done\r\n" );
}
log_printf ( &logger, "**************************************************************\r\n" );
if ( LRIOT_OK == lriot_get_temperature ( &lriot, &temperature ) )
{
log_printf ( &logger, "Temperature : %.2f degC\r\n", temperature );
}
memset( lora_buffer, 0, sizeof ( lora_buffer ) );
strcpy( lora_buffer, "My temperature is " );
float_to_str ( temperature, tmp_buf );
l_trim ( tmp_buf );
tmp_buf[ 5 ] = 0;
strcat( lora_buffer, tmp_buf );
strcat( lora_buffer, " degC" );
if ( LRIOT_OK == lriot_send_lora_message ( &lriot, lora_buffer ) )
{
log_printf( &logger, "Send LoRa message - done\r\n" );
}
#else
lriot_lora_packet_status_t pkt_status;
if ( LRIOT_OK == lriot_read_lora_message ( &lriot, &pkt_status, lora_buffer ) )
{
log_printf ( &logger, "**************************************************************\r\n" );
log_printf ( &logger, "* RECEIVED LORA PACKET *\r\n" );
log_printf ( &logger, "**************************************************************\r\n" );
log_printf ( &logger, " RSSI : %d dBm\r\n", ( uint16_t ) pkt_status.rssi_pkt_in_dbm );
log_printf ( &logger, " Signal RSSI : %d dBm\r\n", ( uint16_t ) pkt_status.signal_rssi_pkt_in_dbm );
log_printf ( &logger, " SNR : %d dB\r\n", ( uint16_t ) pkt_status.snr_pkt_in_db );
log_printf ( &logger, " Message : \"%s\"\r\n\n", lora_buffer );
}
#endif
#else
lriot_gnss_scan_results_t gnss_results = { 0 };
lriot_wifi_scan_results_t wifi_results = { 0 };
if ( LRIOT_OK == lriot_get_gnss_scan_results ( &lriot, &gnss_results ) )
{
lriot_display_gnss_scan_results ( gnss_results );
}
if ( LRIOT_OK == lriot_get_wifi_scan_results ( &lriot, &wifi_results ) )
{
lriot_display_wifi_scan_results ( wifi_results );
}
#endif
}
void main ( void )
{
application_init( );
for ( ; ; )
{
application_task( );
}
}
static void lriot_display_gnss_scan_results ( lriot_gnss_scan_results_t results )
{
log_printf ( &logger, "**************************************************************\r\n" );
log_printf ( &logger, "* GNSS SCAN RESULTS *\r\n" );
log_printf ( &logger, "**************************************************************\r\n" );
log_printf ( &logger, "Number of satellites found: %u\r\n", ( uint16_t ) results.num_satellites );
#if ( LRIOT_FIRMWARE_SELECTOR == LRIOT_TRANSCEIVE_FIRMWARE )
for ( uint8_t cnt = 0; cnt < results.num_satellites; cnt++ )
{
log_printf ( &logger, "{\r\n\tSatellite ID : %u", results.satellite_id_cnr_doppler[ cnt ].satellite_id );
log_printf ( &logger, "\r\n\tC/N0 : %d dB-Hz", results.satellite_id_cnr_doppler[ cnt ].cnr );
log_printf ( &logger, "\r\n\tSV doppler : %d Hz\r\n},\r\n", results.satellite_id_cnr_doppler[ cnt ].doppler );
}
#else
for ( uint8_t cnt = 0; cnt < results.num_satellites; cnt++ )
{
log_printf ( &logger, "{\r\n\tSatellite ID : %u", results.satellite_id_cnr[ cnt ].satellite_id );
log_printf ( &logger, "\r\n\tC/N0 : %d dB-Hz\r\n},\r\n", results.satellite_id_cnr[ cnt ].cnr );
}
#endif
if ( ( results.scan_results_len > 0 ) &&
( LR1110_GNSS_DESTINATION_SOLVER == results.destination_id ) )
{
log_printf ( &logger, "NAV message : " );
for ( uint16_t cnt = 0; cnt < results.scan_results_len; cnt++ )
{
log_printf ( &logger, "%.2X", results.scan_results[ cnt ] );
}
log_printf ( &logger, "\r\n" );
}
}
static void lriot_display_wifi_scan_results ( lriot_wifi_scan_results_t results )
{
log_printf ( &logger, "**************************************************************\r\n" );
log_printf ( &logger, "* WiFi SCAN RESULTS *\r\n" );
log_printf ( &logger, "**************************************************************\r\n" );
log_printf ( &logger, "Number of WiFi results: %u\r\n", ( uint16_t ) results.num_wifi_results );
for ( uint8_t i = 0; i < results.num_wifi_results; i++ )
{
log_printf ( &logger, "{\r\n\tSSID : \"%s\",\r\n\tMAC : \"", results.scan_results[ i ].ssid_bytes );
for ( uint16_t j = 0; j < LR1110_WIFI_MAC_ADDRESS_LENGTH; j++ )
{
log_printf ( &logger, "%.2x", ( uint16_t ) results.scan_results[ i ].mac_address_2[ j ] );
if ( j < ( LR1110_WIFI_MAC_ADDRESS_LENGTH - 1 ) )
{
log_printf ( &logger, ":" );
}
}
log_printf ( &logger, "\",\r\n\tChannel: %u,\r\n", ( int16_t ) results.scan_results[ i ].current_channel );
log_printf ( &logger, "\tType : %u,\r\n", ( int16_t ) results.scan_results[ i ].data_rate_info_byte );
log_printf ( &logger, "\tRSSI : %d dBm\r\n},\r\n", ( int16_t ) results.scan_results[ i ].rssi );
}
log_printf ( &logger, "Scanning time : %d ms\r\n",
( results.timings.demodulation_us + results.timings.rx_capture_us +
results.timings.rx_correlation_us + results.timings.rx_detection_us ) / 1000 );
}
static void lriot_display_chip_info ( lriot_chip_info_t info )
{
log_printf ( &logger, "**************************************************************\r\n");
log_printf ( &logger, "* CHIP INFO *\r\n");
log_printf ( &logger, "**************************************************************\r\n");
#if ( LRIOT_FIRMWARE_SELECTOR == LRIOT_TRANSCEIVE_FIRMWARE )
log_printf ( &logger, "HARDWARE : 0x%.2X\r\n", ( uint16_t ) info.version.hw );
log_printf ( &logger, "TYPE : 0x%.2X\r\n", ( uint16_t ) info.version.type );
log_printf ( &logger, "FIRMWARE : 0x%.4X\r\n", info.version.fw );
log_printf ( &logger, "UID : " );
for ( uint8_t cnt = 0; cnt < ( LR1110_SYSTEM_UID_LENGTH - 1 ); cnt++ )
{
log_printf ( &logger, "%.2X-", ( uint16_t ) info.uid[ cnt ] );
}
log_printf ( &logger, "%.2X\r\n", ( uint16_t ) info.uid[ LR1110_SYSTEM_UID_LENGTH - 1 ] );
log_printf ( &logger, "JOIN EUI : " );
for ( uint8_t cnt = 0; cnt < ( LR1110_SYSTEM_JOIN_EUI_LENGTH - 1 ); cnt++ )
{
log_printf ( &logger, "%.2X-", ( uint16_t ) info.join_eui[ cnt ] );
}
log_printf ( &logger, "%.2X\r\n", ( uint16_t ) info.join_eui[ LR1110_SYSTEM_JOIN_EUI_LENGTH - 1 ] );
log_printf ( &logger, "PIN : " );
for ( uint8_t cnt = 0; cnt < LR1110_SYSTEM_PIN_LENGTH; cnt++ )
{
log_printf ( &logger, "%.2X", ( uint16_t ) info.pin[ cnt ] );
}
log_printf ( &logger, "\r\n\n" );
#else
log_printf ( &logger, "BOOTLOADER : 0x%.8LX\r\n", info.version.bootloader );
log_printf ( &logger, "FIRMWARE : 0x%.8LX\r\n", info.version.firmware );
log_printf ( &logger, "LORAWAN : 0x%.4X\r\n", info.version.lorawan );
log_printf ( &logger, "CHIP EUI : " );
for ( uint8_t cnt = 0; cnt < ( LR1110_MODEM_CHIP_EUI_LENGTH - 1 ); cnt++ )
{
log_printf ( &logger, "%.2X-", ( uint16_t ) info.chip_eui[ cnt ] );
}
log_printf ( &logger, "%.2X\r\n", ( uint16_t ) info.chip_eui[ LR1110_MODEM_CHIP_EUI_LENGTH - 1 ] );
log_printf ( &logger, "DEV EUI : " );
for ( uint8_t cnt = 0; cnt < ( LR1110_MODEM_DEV_EUI_LENGTH - 1 ); cnt++ )
{
log_printf ( &logger, "%.2X-", ( uint16_t ) info.dev_eui[ cnt ] );
}
log_printf ( &logger, "%.2X\r\n", ( uint16_t ) info.dev_eui[ LR1110_MODEM_DEV_EUI_LENGTH - 1 ] );
log_printf ( &logger, "JOIN EUI : " );
for ( uint8_t cnt = 0; cnt < ( LR1110_MODEM_JOIN_EUI_LENGTH - 1 ); cnt++ )
{
log_printf ( &logger, "%.2X-", ( uint16_t ) info.join_eui[ cnt ] );
}
log_printf ( &logger, "%.2X\r\n", ( uint16_t ) info.join_eui[ LR1110_MODEM_JOIN_EUI_LENGTH - 1 ] );
log_printf ( &logger, "PIN : %.8LX\r\n\n", info.pin );
#endif
}
// ------------------------------------------------------------------------ END