RT-Thread 使用FAL多字节读写FLASH

FAL 简介

FAL (Flash Abstraction Layer) Flash 抽象层,是 RT-Thread 的一个软件包,是对 Flash 及基于 Flash的分区进行管理、操作的抽象层,对上层统一了 Flash 及分区操作的 API ,并具有以下特性:
• 支持静态可配置的分区表,并可关联多个 Flash 设备;
• 分区表支持 自动装载。避免在多固件项目,分区表被多次定义的问题;
• 代码精简,对操作系统 无依赖,可运行于裸机平台,比如对资源有一定要求的 bootloader;
• 统一的操作接口。保证了文件系统、OTA、NVM 等对 Flash 有一定依赖的组件,底层 Flash 驱动的
可重用性;
• 自带基于 Finsh/MSH 的测试命令,可以通过 Shell 按字节寻址的方式操作(读写擦)Flash 或分区,
方便开发者进行调试、测试;

如何使用官网文档都有介绍,这里就不再copy了.
https://www.rt-thread.org/document/site/search.html?q=FAL
简单来说,FAL把flash分成了多个单独的分区,FAL就像虚拟内存一样,每个分区也都是从0地址开始的.

由于FLASH和E2PROM不一样,不能随意写入,只能把bit置0,通过擦除置1,但是擦除只支持块级以上擦除,即不能一个字节一个字节的擦除,一般spi flash都是4k擦除,有的stm32 chip flash是2k擦除.由于这个特性,导致了我们如果想要对已经写入过数据的地址重新修改时,必须要将所在的块擦除,这样一来,其他的数据则会被一同擦除,也就是fal_partition_write实际上是block write,块写入.由于可能会遇到单字节或多字节写入情况,这就是本文的目的,能随意字节的可覆盖读写flash.

在RT-Thread上使用FAL

由于FAL 是对Flash的分区进行管理、操作的抽象层,所以还需要底层的FLASH驱动,目前的RTT已经支持了大部分FLASH,所以基本上不需要我们写驱动了.RTT也支持了SFUD (Serial Flash Universal Driver) 串行 Flash 通用驱动库.作者文档介绍的也比较详细,这里就不再赘诉.

添加SPI 总线驱动

在这里插入图片描述
如果你的BSP下board里面的Kconfig文件没有配置SPI,从其他BSP下复制一下配置即可.然后使用RTT env工具,进入Hardware Drivers Config -->On-Chip Peripheral Drivers,按空格键选择使能Enable SPI Bus,再进入,使能SPI1即可.
在这里插入图片描述
由于选择RTT使用STM32的HAL库,所以我们还需要stm32f1xx_hal_msp.c中添加spi的初始化函数.可以使用STM32CubeMX来获取配置.这里就不介绍了(我也不太熟悉-_-||).

void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hspi->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspInit 0 */

  /* USER CODE END SPI1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_SPI1_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**SPI1 GPIO Configuration    
    PA4     ------> SPI1_NSS
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    PA7     ------> SPI1_MOSI 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN SPI1_MspInit 1 */

  /* USER CODE END SPI1_MspInit 1 */
  }
}

/**
* @brief SPI MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param hspi: SPI handle pointer
* @retval None
*/
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
{
  if(hspi->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspDeInit 0 */

  /* USER CODE END SPI1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI1_CLK_DISABLE();
  
    /**SPI1 GPIO Configuration    
    PA4     ------> SPI1_NSS
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    PA7     ------> SPI1_MOSI 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);

  /* USER CODE BEGIN SPI1_MspDeInit 1 */

  /* USER CODE END SPI1_MspDeInit 1 */
  }

在stm32f1xx_hal_conf.h中打开宏HAL_GPIO_MODULE_ENABLED.

添加SFUD驱动

在你的BSP下使用RTT ENV工具打开,使用menuconfig进行配置.
在这里插入图片描述
将Using SPI Bus打开,并选择Using Serial Flash Universal Driver.
(如果不知道选项路径,输入 / 后,输入关键词,Enter进行查找),完毕后一直按ESC键,直到提示是否保持配置,选择Yes.

添加SPI DEVICE

上一步仅仅只是添加SPI BUS,添加SPI设备也很简单,只需要调用rt_hw_spi_device_attach(const char *bus_name, const char *device_name, GPIO_TypeDef *cs_gpiox, uint16_t cs_gpio_pin)函数即可.

rt_hw_spi_device_attach("spi1", "spi10", GPIOA, GPIO_PIN_4);

我的spi flash的片选IO为PA4.

使用SFUD添加SPI 块设备

调用 rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const char *spi_dev_name)即可添加.

rt_sfud_flash_probe("norflash0", "spi10");

相关spi flash型号和型号信息等都在sfud_flash_def.h中,如果没有你的spi flash,模仿其他flash添加在SFUD_MF_TABLE,SFUD_FLASH_CHIP_TABLE,SFUD_FLASH_EXT_INFO_TABLE这几个表里即可.

在这里插入图片描述

添加FAL

添加好SPI FLASH设备块,就可以添加FAL了,使用RTT env选择使用FAL(RT-Thread online packages —>system packages —> fal,并选择FAL uses SFUD drivers.保存退出.
在这里插入图片描述
在这里插入图片描述
使用pkgs --update指令下载fal包.
在这里插入图片描述
在这里复制fal_cfg.h到applications目录下.根据自己的情况配置分区.
在这里插入图片描述

接着使用scons构建项目

在这里插入图片描述
在这里插入图片描述
调用fal_init()初始化FAL.
在这里插入图片描述

添加fal_nbyte

貌似这个命名不太合适,fal的接口本来就是多字节读写的…
由于开篇提到的flash写入擦除问题,导致不能对已经写入过数据(0)的地址进行更改.所以我们需要在擦除的时候,把其他数据先读出来,再一同写入.
代码比较简单,就不注释了.


static rt_mutex_t fal_nbyte_mtx;


int fal_partition_write_nbyte(const struct fal_partition *part, 
                              uint32_t addr, uint8_t *buf, size_t size)
{
    size_t i, remain, offset, _size;
    const struct fal_flash_dev * fal_dev = RT_NULL;
    uint8_t *fal_cache;
    
    fal_dev = fal_flash_device_find(part->flash_name);
    RT_ASSERT(fal_dev != RT_NULL);
    RT_ASSERT(FLASH_CACHE >= fal_dev->blk_size);
    RT_ASSERT(fal_dev != RT_NULL);

    rt_mutex_take(fal_nbyte_mtx, RT_WAITING_FOREVER);
    
    offset = addr%fal_dev->blk_size;
    remain = fal_dev->blk_size - offset;
    
    fal_cache = (uint8_t *)rt_malloc(fal_dev->blk_size);
    if (NULL == fal_cache)
        goto ERR;
        
    if (remain > size)
        remain = size;
     
    _size = size;
    while (1) {
        if (fal_partition_read(part, addr - offset, fal_cache, fal_dev->blk_size) != fal_dev->blk_size) {
            rt_kprintf("fal_partition_read err!\r\n");
            goto ERR1;
        }
		
        for (i = 0; i < remain; i++) {
            if (fal_cache[offset+i] != 0xff)
                break;
		}
        if (i != remain)
            fal_partition_erase(part, addr - offset, remain);
        
		rt_memcpy(&fal_cache[offset], buf, remain);
        if (fal_partition_write(part, addr - offset, fal_cache, fal_dev->blk_size) != fal_dev->blk_size) {
			rt_kprintf("fal_partition_write err!\r\n");
			goto ERR1;
		}

        if (remain == size) {
            break;
        } else {
            buf += remain;
            size -= remain;
			addr += remain;
            offset = 0;
            if (size > fal_dev->blk_size)
                remain = fal_dev->blk_size;
            else
                remain = size;
        }
    }
    rt_free(fal_cache);
    rt_mutex_release(fal_nbyte_mtx);
    return _size;
ERR1:
    rt_free(fal_cache);
ERR:
    rt_mutex_release(fal_nbyte_mtx);
    return -1;
}

int fal_partition_read_nbyte(const struct fal_partition *part, uint32_t addr, uint8_t *buf, size_t size)
{
    size_t remain, offset, index, _size;
    const struct fal_flash_dev * fal_dev = RT_NULL;
    uint8_t *fal_cache;
    
    fal_dev = fal_flash_device_find(part->flash_name);
    RT_ASSERT(fal_dev != RT_NULL);
    RT_ASSERT(FLASH_CACHE >= fal_dev->blk_size);
    RT_ASSERT(fal_dev != RT_NULL);

    rt_mutex_take(fal_nbyte_mtx, RT_WAITING_FOREVER);
    
    offset = addr%fal_dev->blk_size;
    remain = fal_dev->blk_size - offset;
    
    fal_cache = (uint8_t *)rt_malloc(fal_dev->blk_size);
    if (NULL == fal_cache)
        goto ERR;
        
    if (remain > size)
        remain = size;
     
    _size = size;
    index = 0;
    while (1) {
        if (fal_partition_read(part, addr - offset, fal_cache, fal_dev->blk_size) != fal_dev->blk_size) {
            rt_kprintf("fal_partition_read err!\r\n");
            goto ERR1;
        }
        
        rt_memcpy(buf, &fal_cache[offset], remain);
        if (remain == size) {
            break;
        } else {
			addr += remain;
            buf += remain;
            index += remain;
            size -= remain;
            offset = 0;
            if (size > fal_dev->blk_size)
                remain = fal_dev->blk_size;
            else
                remain = size;
        }
    }
    rt_free(fal_cache);
    rt_mutex_release(fal_nbyte_mtx);
    return _size;
ERR1:
    rt_free(fal_cache);
ERR:
    rt_mutex_release(fal_nbyte_mtx);
    return -1;
}

int fal_nbyte_init(void)
{
	fal_nbyte_mtx = rt_mutex_create("fal_nbyte_mtx", RT_IPC_FLAG_FIFO);
	RT_ASSERT(fal_nbyte_mtx!=RT_NULL);
	return 0;
}
INIT_ENV_EXPORT(fal_nbyte_init);

验证

在这里插入图片描述
使用fal probe cfg匹配一下刚才cfg分区. fal read读取数据

在这里插入图片描述
在这里插入图片描述
可以看到,当数据为FF时,地址0写入1,读出来的数据正确,再次写入数据2,读出来的错了.

接着验证一下fal_nbyte读写.
在这里插入图片描述
读写没问题,再测试覆盖写.
在这里插入图片描述

fal_nbyte源码https://github.com/LostInOrion/fal_nbyte

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RT-Thread作品秀】通用型数据采集设备作者:鱼柯 概述(说明应用产生的背景、实现功能)在一些低频采集设备中,典型的运行策略是,采集数据,上传数据,关闭外设进入睡眠状态;但是,在运行过程中,需要根据实际需求,更改采集频率,连接不同的设备,如果每次通过修改代码解决,通用性就很难保证,这个项目将一些uart型的传感器进行归类,通过文件设置数据交互过程中的命令,解析方式等,可以适配大多数的uart型传感器;同时,对一些网络摄像头也以同样的方式进行处理; 实现数据采集调度配置,数据采集,数据上传,图片采集,图片上传, 配置文件解析,固件远程更新;由于contab配置文件中的event使用的是MSH_CMD_EXPRT宏导出的命令。所以,它也支持系统需要定时执行的相对时间间隔需要变化的任务,比如:12:00. 13:10, 15:35, 18:23分别执行一次任务; 开发环境(所采用的软、硬件方案)硬件:art-pi, INDUSTRY-IO, 微气象仪, 网络摄像头 RT-Thread版本:rt-thread 4.0.3 开发工具及版本:ubuntu 18.04,gcc-arm-none-eabi-6_2-2016q4,scons v3.0.1,python 3.6.9,pkgs RT-Thread使用情况概述(简要总结下应用中RT-Thread使用情况:内核部分、组件部分、软件包部分、内核、其他)内核部分Inter-thread communication Event Semaphore mutex memory management device object 组件部分Finsh DFS (device virtual file system) serial device, mtd nor flash device, gpio device, ntp rtc device, sd/mmc device, spi device, serial flash universal driver (device driver) posix layer and c stand library SAL (socket abstraction layer) ping, ifconfig, netstat, netdev (network interface) LwIP 2.0.2 Ymodem ulog 软件包部分agile_console-v1.0.0 fal-v0.5.0 ota_downloader-v1.0.0 agile_telnet-v2.0.0 littlefs-v2.2.1 SignalLed-latest cJSON-v1.0.2 netutils-v1.2.0 vi-latest EasyFlash-v4.1.0 webclient-v2.1.1 硬件框架(概述应用所采用的硬件方案框图,并对核心部分做介绍)软件框架说明(介绍应用所采用的软件方案框图、流程图等,并加以解说)软件模块说明(介绍应用软件关键部分的逻辑、采用的实现方式等)类似 linux定时任务contab解析相关json配置文件,构建设备运行数据树: "contab": [{"event":"misc_check","time":"0 18"},{"event":"img_cap_start","time":"20 7,9,14"},{"event":"app_image_upload","time":"20 7,9,14"},{"event":"sensor_acq_start","time":"5,10,15,20,25,30,35,40,45,50,55 *"},{"event":"app_data_upload","time":"5,10,15,20,25,30,35,40,45,50,55 *"}] 事件执行分钟: 表示xx:5, xx:25, xx:30, xx:36, xx:45, xx:54 事件执行小时:*通配符,表示1-24小时 上面参数表示:每个小时的5,25,30,45,54分,执行img_upload_invl事件; 上传数据每次采集数据后,将数据存在本地一个缓存文件中,按照采集时间从前到后写入;同时会生成一个读取位置的缓存文件指示,下一次从哪个文件的那一行读取数据进行上传,上传成功后,更新读取位置的缓存;如20201217,227, 表示从文件20201217.txt的227个字符后读取一行数据进行上传,避免文件过大引起设备死机; 上传图片每次拍照时,将拍照成功的照片名及端口追加记录到一个缓存文件中,每次从缓存文件中,读取需要上传的图片构造form-data上传图片;如4,/sd/1608167012_4.jpg;如果上传成功,则删
作者:杨红超 绪论 本章主要阐述多功能气压计的应用背景,包括根据大气压强判断和确定建筑工人的楼层位置、帮助建筑工人感知周围环境温度变化等,同时也可根据大气压强判断无人机的GPS定位。其次着重介绍气压计的具体功能,如可以通过对工人周围的气压和温度的采集计算出当前所在的楼层位置,并将数据信息通过ONENET上传到云服务器上,通过语音识别实现设备在线升级功能。最后对本次设计的组织结构进行介绍,以表明每章节的主要内容和作用。 1.1应用背景 为确保建筑工人在工地施工时的人身安全,故此设计一款工人们的“运行手环”——多功能气压计。它内置气体压强检测装置可实时检测建筑工人身处的大气压强和周围的环境温度,进而根据采集的数据推算出工人所在的楼层高度,并将数据实时上传到云服务器上通过管理者对数据的检测给建筑工人提供一份双保险。 此外,该多功能气压计还具有无人机GPS定位和判断吸尘器吸力大小等应用于多对象、多环境的特点。 1.2实现功能 本次多功能气压计的设计硬件采用ART-Pi开发板、LPS22HH气压传感器和LD3320语音识别模块,操作系统使用RT-Thread 4.0.3,软件使用RT-Thread Studio 1.1.5开发平台和使用C语言实现软件编程,具有如下功能: (1)利用LPS22HH气压传感器实时对大气压的压强进行采集,并通过SPI4接口将采集的数据传给单片机。 (2)利用AP6212 WIFI模块实时将经过处理后的数据,如温度值和楼层信息等上传到云服务器;同时通过WIFI模块实现在线升级用户程序。 (3)语音识别模块通过SPI2实现与开发板的数据交互,完成语音重启设备和语音在线升级功能。 1.3设计组织结构 本次基于ART-Pi开发板的多功能气压计设计,主要分为五个章节其具体设计组织结构如下: 第一章绪论,主要介绍多功能气压计的实际应用背景和具有的具体功能,以及设计组织结构的规划。 第二章RT-Thread概述,主要对在本设计中涉及的RT-Thread内核、及其组件和软件包进行阐述,欲以说明对RT-Thread操作系统的使用情况和了解程度,同时对其内容作些简单的介绍。 第三章硬件设计,主要阐述硬件模块的电气连接和本次设计使用的硬件电路,如LPS22HH气压传感器、ART-Pi开发板和语音识别模块等。 第四章软件设计,主要阐述软件实现的设计流程和各个软件模块设计的框架,以及模块之间的通讯方式。 第五章总结与展望,主要阐述对本次设计的评估,即软件设计存在的不足和功能与性能存在的不足,以及针对不足之处提出的具体改进措施和方案、参加比赛的感悟和心得。 1.4本章小节 本章主要介绍多功能气压计的应用背景和具体的应用功能,以及对软硬件开发环境和该设计文档的组织结构进行阐述。 RT-Thread概述 本章主要阐述在软件设计中关于RT-Thread操作系统的应用情况,如与线程运行有关的采用动态方式创建线程,与线程同步有关的信号量的动态创建、释放和获取,以及与网络有关的SAL组件、OneNET软件包等。 2.1内核 为了提高软件运行的并发性和数据采集的实时性,故使用内核中的核心部分——线程,使其维护和管理每个任务的运行,同时以使用信号量和事件集等的同步方式,以及使用邮箱和消息队列等的通信方式来确保每个任务在运行过程中能“自由飞翔”。 不仅如此,为增加任务在运行状态中的时间和提高每个任务响应的快慢速度,故使用线程中重要的两个属性即线程优先级和时间片,并根据应用的具体环境和软实时性的要求将每个任务赋予各自该具有的任务优先级和时间片。同时,使用rt_thread_mdelay延迟函数来定时释放线程(任务)确保在其处于非运行态时可以退出时间片以让其它任务能及时运行。 2.2驱动 在bootloader程序中主要初始化SPI和SFUD驱动实现对外部SPI FLASH读写操作,同时结合使用FAL软件包将操作FLASH的函数进行分层,进而实现在bootloader程序中读取“download”分区的升级固件,以及使用ota_downloader软件包完成升级固件的下载,最后使用出厂W25QXX函数实现固件搬运工作进而完成在线升级应用。 2.3组件 SAL组件完成并提供了基于RT-Thread操作系统的对不同网络协议栈或网络实现接口的抽象和与上层应用有关的一组标准BSD Socket API,在网络开发设计时可只需关心和使用网络应用层提供的网络接口,而无需关心底层具体网络协议栈类型和具体实现,如TCP/IP协议栈、LWIP和AT Socket网络。SAL组件不仅提高了软件系统对底层驱动的兼容性,而且缩短了网络开发周期。此外,SAL组件还具有一下功能特点[1]: 抽象、统一多种网络协议栈接口; 提供Socket层面的TLS加密传输特性; 支持标准BSP S
RT-Thread作品秀】智能天气小站作者:AlgoIdeas 概述嵌入式开发需要多动手,多实践才能不断取得成长和进步。第一次接触新的知识,难免会遇到挫折和困难,只要有足够的耐心和不断探索的信心,并不断学习和实践,同时有所思考,就会有收获。智能天气小站是一个很好的切入点,同时自己作为一名STM32新手,第一次接触RT-Thread、也第一次接触TouchGFX,感受颇多,收获颇丰。 开发环境硬件:ART-Pi RT-Thread版本:4.0.3 开发工具及版本:RT-ThreadStudio 2.0 ART-Pi SDK版本: SDK v1.0.1 RT-Thread使用情况概述项目主要基于ART-Pi SDK中的art_pi_factory例程,并在例程基础上增加其他软件基础组件。 内核采用RT-Thread原生内核,版本RT-Thread v4.0.3 组件列表: rt_ota_lib – 升级相关 touchgfx_lib – TouchGFX相关界面实现 wlan_wiced_lib – WLAN库 涉及软件包: EasyFlash-v4.1.0 -- 轻量级物联网存储库 adbd-v1.1.1 – ADB远程调试 btstack-v0.0.1 – 蓝牙协议栈 cJSON-v1.0.2 – JSON库 dht11-latest – DHT11温度传感器库 fal-v0.5.0 - gt9147-latest -- 触摸驱动 littlefs-v2.0.5 -- lwgps-latest -- 轻量级GPS解析库 netutils-v1.2.0 – 网络相关工具 webclient-v2.1.2 – WEB客户端 webnet-v2.0.2 – web接口相关实现 注:gps和presssensor相关包或模块可供二次开发 硬件框架主控芯片:STM32H750XB (ART-Pi开发板) 图形框架:TouchGFX SD卡1张: 8G 温湿度传感器DHT11:使用GPIO获取数据 网络:板端自带的AP6212A WIFI+蓝牙一体芯片 4.3寸电容屏:使用I2C总线驱动触摸(触摸芯片GT9147),LCD使用RGB888格式 时间的获取:例程自带的RTC+NTP自动网络对时 天气的获取:通过http客户端的方式获取网络开放API接口的天气数据,目前主要从心知天气(https://www.seniverse.com/api)获取, 后续二次开发,也可采用其他网站获取,如openweathermap(https://api.openweathermap.org/data/2.5/)等 软件框架说明软件如果需要通过网络获取天气信息,需要先进行联网,目前支持蓝牙配网(具体请参考ART-Pi官方教程),目前仅支持本地预先设置好的地区的温度的获取,后续可以扩展UI设计,或通过GPS定位来获取位置信息。 同时,默认支持DHT11数字温度传感器获取本地的实时温湿度数据,并通过GUI进行显示。软件主体框架如下图所示: 系统设置界面,支持将温湿度数据存储为日志文件到SD卡(后续可以二次开发,读取历史文件并直接在UI界面显示历史数据),可以开启或关闭该功能,同时支持自动关屏设置。 软件模块说明UI设计GUI采用TouchGFX来设计,目前采用的版本是TouchGFX 4.15.0,主要分为3个主要界面:主页、系统设置和历史温度数据分析,分别如下图图1、图2和图3所示。 TouchGFX官方介绍 TouchGFX 4.13 版本是继TouchGFX 4.12 之后的又一重要版本。4.13版具备了将动画推到60FPS的功能,还增加了可缓存容器、不完全帧缓冲区以及新的L8压缩格式等性能,这表明了 ToughGFX 不断追求优化性能和持续迭代的匠心。4.13版本还解决了另一个问题:嵌入式系统开发人员的用户界面可访问性。通过将TouchGFX Generator集成到 STM32CubeMX 中,经验较少的工程师在使用 TouchGFX 4.13 时,可以通过 STM32CubeMX 这个广为流行的 ST 实用软件程序快速启动项目。这样做的目的在于降低开发者入门门槛,让专业人士和爱好者都能受益于这个交互式的高效解决方案。 天气数据获取通过DHT11数字温湿度传感器获取; 通过注册心知天气(https://www.seniverse.com/),采用其Weather API,并配合web相关API获取当地的天气; 演示效果视频演示: 界面设计效果: 图1 主页 图2 系统设置 图3 温度历史数据与分析 比赛感悟 一次偶然翻看网页的机会,让我看到了RT-Thread x STM32全连接创意创客大赛,于是顺手点了进去,并于第二天才最终确认参加比赛。在这近
概述随着物联网应用的不断发展,传统的传输技术在各个物联网行业应用方面渐渐不能满足我们的需求,传统的局域网技术,如2.4GHz的WiFi,蓝牙、Zigbee等,以及传统广域网技术2G/3G/4G等无线技术,不能同时兼顾远距离和低功耗。直到在低功耗广域网(Low Power Wide Area Network, LPWAN)技术出现后,能在保证更远距离的通信传输的同时,最大限度的降低功耗,节约传输成本。 本应用使用ART-PI开发板,NUCLEO-L452开发板以及本人自制的扩展板,组成LORA采集端和接收转发端,即使在条件恶略的环境下也能采集数据并通过LORA传送接收并转发至云平台. 开发环境硬件:ART-PI开发板NUCLEO-L452开发板 LORA采集扩展板(安信可Ra-02,DHT11) LORA接收扩展板(安信可Ra-02,W5500,sp485) RT-Thread版本:RT-Thread4.03(ART-PI开发板)RT-Thread4.02(NUCLEO-L452开发板) 开发工具及版本:RT-ThreadStudio V2.0 STM32CuBeMx V6.1.0 RT-Thread使用情况概述内核部分:主要使用了线程管理 时钟管理 组件部分:FinSH控制台,netdev网卡,SAL套接字抽象层,ulog日志 软件包部分:cjson webclient,pahomqtt,fal,wiznet,dhtxx 硬件框架采集端:简单的LORA模组,通过SPI跟板卡通信,以及一个可控LDO和AHT10和BH1750,以LDO控制AHT10和BH1750以达到低功耗的效果. 接收端:一个LORA模组,一个W5500芯片,SPI通信,以及一个SP485. 主要部分就是LORA模组以及W5500,本设计使用立创EDA设计,W5500参考自立创官方团队. 软件框架说明ART-PINUCLEO-L452软件模块说明ART-PI(接收端),上电自动初始化LORA和W5500,等待W5500连接上网络,这里通过判断网卡的状态,当link_up状态后,开始连接mqtt服务器,就可以把LORA接受的数据通过MQTT发送至平台. NUCLEO-L452(采集端),上电初始化软件IIC,直接采集同一总线下AHT10和BH1750的数据,并通过LORA直接发送出去.(备注:因时间关系,采集端的低功耗并没有做,年前估计没时间完善了,以后有时间继续完善) 演示效果视频展示: 比赛感悟这次比赛又学到了不少东西,最主要的就是I2C总线设备和netdev 网卡,刚开始板载WIFI使用时无法使用W5500,因为默认网卡的原因,后来查询RT-Thread 文档中心,看看API和示例,轻松解决.还有就是使用I2C总线设备,刚开始一直想要使用硬件IIC和软件包去驱动AHT10和BH1750,后来发现软件IIC加PIN设备轻松解决,对着文档中心的例子,轻松举一反三出BH1750的程序.所以感觉RT-Thread的文档是真的全乎,所有自己解决不了的东西文档中心都有.但很遗憾的是这次由于出差的原因并没能很完美的展现出来作品,其中ART-PI扩展板上的485并没写到程序中,IWIFI也没应用到(现在是以太网),采集端的低功耗也没有做,年后一定把晚上出来!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值