tag 标签: 开源

相关帖子
相关博文
  • 热度 1
    2024-9-30 15:52
    53 次阅读|
    0 个评论
    01 物联网系统中为什么要使用OLED屏 物联网系统中使用OLED屏的原因主要有以下几点: 显示效果的优越性 高对比度与色彩表现:OLED屏能够实现自发光,无需背光,因此能够展现更高的对比度和更深的黑色,使得画面更加鲜明逼真。同时,OLED屏能够提供更广阔的色域和更准确的色彩表现,使图像更加饱满、细腻,色彩更加真实。 视角宽广:OLED屏具有较大的视角范围,即使从不同角度观看,图像的亮度和色彩仍然保持稳定,不会出现颜色失真或亮度降低的情况。 响应速度快:OLED屏的像素点能够快速切换,响应速度更快,能够呈现更流畅的动态画面,减少运动模糊。 轻薄与灵活性 薄型轻便:OLED屏由于不需要背光模组,可以设计得更薄更轻,非常适合物联网设备中对于轻薄化的需求。这种特性使得OLED屏在智能手表、可穿戴设备等物联网设备中得到广泛应用。 柔性特性:OLED屏还具有柔性特性,可以弯曲和折叠,这为物联网设备的设计提供了更多的可能性。例如,在智能家居中,OLED屏可以嵌入到各种曲 面或不规则形状的设备中,提升设备的美观性和实用性。 低功耗与长续航 OLED屏在低功耗方面表现优异,因为它只在需要显示内容的像素点上发光,而不需要像传统LCD屏那样整个背光模组都保持开启状态。这种特性使得OLED屏在物联网设备中能够延长电池寿命,提升用户体验。 适应性与扩展性 多种应用场景:OLED屏的优异性能使得它适用于多种物联网应用场景,包括智能家居、可穿戴设备、工业自动化等。在智能家居中,OLED屏可以作为智能控制面板或家电显示屏;在可穿戴设备中,OLED屏可以呈现丰富的信息并提升设备的时尚感。 易于集成:OLED屏通常具有标准的接口和通信协议,易于与其他物联网设备或系统进行集成。这种集成能力使得在物联网系统中部署OLED屏变得更加简单快捷。 具体应用场景 OLED屏的应用场景非常广泛,包括但不限于以下几个领域: 商业展示:如透明屏展示窗口、广告宣传等。 博物馆和展览:用于展示文物、艺术品等,提供沉浸式的观展体验。 建筑和室内设计:应用于玻璃幕墙、楼梯扶手等,增强建筑的现代感和创意性。 汽车内部:如仪表盘、中控台和车载娱乐系统等,提升驾驶体验和乘车舒适度。 广告和展示活动:在户外广告牌、展览展示和活动现场中创造视觉冲击力。 舞台和演艺表演:用于舞台背景、舞美设计等,提升演出的震撼力和艺术感。 电视和显示屏:在家庭娱乐和专业领域中提供高对比度、广阔色域和快速响应时间的显示效果。 移动设备:如智能手机、平板电脑和可穿戴设备等,轻薄柔软、功耗低且亮度高。 综上所述,物联网系统中使用OLED屏的原因主要包括其显示效果的优越性、轻薄与灵活性、低功耗与长续航以及适应性与扩展性等方面。这些优势使得OLED屏成为物联网设备中不可或缺的重要组成部分。 本文会再为大家详解显示屏家族中的一员——OLED屏。 02 OLED的屏定义 OLED(Organic Light-Emitting Diode)即有机发光二极管,是一种采用有机材料制成的显示屏幕。它无需背光灯,通过非常薄的有机材料涂层和玻璃基板(或柔性有机基板),在电流通过时,这些有机材料会自行发光,从而实现图像的显示。OLED屏幕被誉为“梦幻显示器”,是第三代显示技术的代表。 03 OLED屏的原理 OLED的显示原理与LCD有着本质上的区别。它主要通过电场驱动,使有机半导体材料和发光材料在过载流子注入和复合后实现发光。具体来说,OLED屏幕以ITO玻璃透明电极作为器件阳极,金属电极作为阴极,通过电源驱动,将电子从阴极传输到电子传输层,空穴从阳极注入到空穴传输层。电子和空穴在发光层中相遇后形成激子,激子使发光分子激发,经过辐射后产生光源。简单来说,一块OLED屏幕就是由无数个“小灯泡”组成。 04 OLED屏分类 根据使用有机功能材料的不同,OLED器件可以分为两大类:小分子器件和高分子器件(也称为PLED)。根据驱动方式的不同,OLED器件又可以分为无源驱动型(Passive Matrix, PM)和有源驱动型(Active Matrix, AM)。此外,还有透明OLED、顶部发光OLED、可折叠OLED、白光OLED等多种类型,每种OLED都有其独特的用途和优势。 05 OLED屏选型参数 在选型OLED屏时,需要考虑以下参数: 屏幕尺寸与分辨率:根据实际应用场景选择合适的屏幕尺寸和分辨率,以确保图像的清晰度和显示效果。 亮度与对比度:OLED屏具有高亮度和高对比度的特点,但具体数值仍需根据实际需求进行选择。 刷新率:刷新率越高,画面越流畅,需要根据应用场景选择合适的刷新率。 能耗:OLED屏具有较低的能耗,但不同型号的能耗可能存在差异,需根据实际应用场景和需求进行选择。 透明度:对于透明OLED屏,透明度是一个重要的选型参数,需要根据实际需求选择合适的透明度。 06 OLED屏使用注意事项 在使用OLED屏时,需要注意以下事项: 防止长时间显示静态图像:OLED屏容易出现“烧屏”问题,因此需避免长时间显示静态图像或在同一位置显示相同图像。 合理控制屏幕亮度:过高的亮度会加速像素灯的老化,需根据实际情况合理控制屏幕亮度。 避免频繁开关机:频繁的开关机操作会对OLED屏产生冲击,影响其使用寿命,需合理安排开关机时间。 避免长时间曝光:OLED屏在长时间曝光下易出现像素灯老化,需尽量避免长时间暴露在阳光下或其他强光源下。 定期清洁屏幕:使用专用的屏幕清洁剂和无纺布定期清洁屏幕,避免硬物刮伤屏幕。 注意适宜的温湿度:OLED屏对环境温度和湿度有一定要求,需放置在温度适宜、湿度适中的环境中。 07 OLED屏厂商 目前,OLED技术的主要厂商包括三星、LG等国际巨头,他们在OLED领域具有领先的技术和市场份额。同时,我国也有多家厂商在不断加强对OLED屏幕的研究和生产,如华星光电、京东方、天马科技等,这些厂商在OLED技术上不断取得突破,并成功将OLED产品应用到各类设备中。 供应商A:郑州中景园电子技术有限公司 1、产品能力 (1)选型手册 (2)主推型号1:0.96英寸OLED显示屏 对应的产品详情介绍 尺 寸 0.96英寸OLED 材 料 PM OLED 分 辨 率 128*64 接口类型 IIC接口 管脚数量 4 控制芯片 SSD1306 显示颜色 白色,蓝色,黄蓝双色三种,根据需要选择 显示区域 21.744 × 10.864 (mm) 模组尺寸 27.3x27.8 (mm) 像素间距 0.17 × 0.17 (mm) 像素尺寸 0.154 × 0.154 (mm) 配套裸屏 0.96老款插接式30PIN短排线(G39) 工作电压 3.3V 视角方向 全视角 工作温度 -40~70度 白色型号 ZJY096I0400WG03 蓝色型号 ZJY096I0400BG03 双色型号 ZJY096I0400YBG03 硬件参考设计 (如有侵权,联系删除) 本文章源自奇迹物联开源的物联网应用知识库Cellular IoT Wiki,更多技术干货欢迎关注收藏Wiki: Cellular IoT Wiki 知识库(https://rckrv97mzx.feishu.cn/wiki/wikcnBvAC9WOkEYG5CLqGwm6PHf)
  • 2024-9-30 14:42
    86 次阅读|
    0 个评论
    01 物联网系统中为什么要使用IIC I/O扩展芯片 在物联网系统中使用IIC(也称为I2C)I/O扩展芯片的原因主要可以归结为以下几点: 1、扩大I/O端口数量 硬件资源限制:许多微控制器(MCU)自带的I/O端口数量有限,但物联网项目往往需要连接大量的传感器、执行器和其他外设。I2C I/O扩展芯片能够通过I2C接口提供额外的I/O端口,从而满足项目需求。 灵活性:通过扩展芯片,设计者可以根据项目需求灵活增加或减少外设连接,而无需更换主控制器。 2、简化布线和连接 减少引脚需求:I2C总线仅需要两根线(SCL时钟线和SDA数据线)即可实现多个设备之间的通信,这大大减少了系统布线的复杂性和成本。 便于管理:通过I2C总线连接的设备可以使用统一的通信协议进行通信,简化了系统的维护和管理工作。 3、提高系统性能 高效通信:I2C协议具有高效的通信机制,能够支持高速数据传输,提高系统的整体性能。 时钟控制:I2C I/O扩展芯片可以控制外部设备的时钟,有助于优化系统的时序控制,提高系统的稳定性和可靠性。 4、降低成本和功耗 减少元件数量:使用I2C I/O扩展芯片可以减少系统中其他类型扩展元件的使用,从而降低整体成本。 低功耗:I2C总线支持低功耗模式,有助于降低系统的整体功耗,延长电池寿命(在便携式或无线物联网设备中尤为重要)。 5、广泛应用场景 传感器网络 :在物联网系统中,传感器是不可或缺的组成部分。I2C I/O扩展芯片可以方便地连接各种类型的传感器(如温度、湿度、加速度计等),实现数据的采集和传输。 工业自动化 :在工业自动化领域,PLC等控制系统需要与大量外设进行通信。I2C I/O扩展芯片能够满足这一需求,提高工业自动化系统的集成度和可靠性。 智能家居 :智能家居系统需要连接和控制各种智能家电和设备。I2C I/O扩展芯片可以扩展智能家居系统的控制能力,实现更多样化的功能。 工业自动化和控制 :在工业自动化系统中,经常需要连接和控制大量的传感器、执行器和其他设备。IIC IO扩展芯片可以提供更多的IO端口,以便与这些设备进行通信和控制。例如,它们可以用于读取传感器的数据、控制执行器的动作或与其他工业设备进行交互。 消费电子产品 :在消费电子产品中,如智能家居设备、智能音箱、智能手环等,IIC IO扩展芯片也发挥着重要作用。它们可以用于扩展设备的IO接口,以便连接更多的外部设备或传感器。例如,智能音箱可以通过IIC IO扩展芯片连接更多的麦克风或扬声器,提高音频处理的性能和质量。 嵌入式系统 :在嵌入式系统中,由于资源限制和成本考虑,微控制器的IO端口数量往往有限。IIC IO扩展芯片可以有效地解决这个问题,为嵌入式系统提供额外的IO端口。这些端口可以用于连接外部设备、扩展系统功能或实现与其他系统的通信。 测试与测量设备 :在测试和测量领域,IIC IO扩展芯片可以用于连接各种测试设备和传感器。通过扩展IO端口,测试设备可以获取更多的数据输入,提高测试的准确性和效率。同时,IIC IO扩展芯片还可以用于控制测试过程中的各种设备和参数。 医疗设备 :在医疗设备中,IIC IO扩展芯片可以用于连接各种医疗传感器和执行器。例如,在监护仪中,IIC IO扩展芯片可以连接多个生命体征传感器,实时监测患者的血压、心率等生理参数。在医疗机器人中,IIC IO扩展芯片可以控制机器人的运动和操作。 综上所述, IIC(I2C)I/O扩展芯片在物联网系统中扮演着重要角色,它们通过提供额外的I/O端口、简化布线和连接、提高系统性能、降低成本和功耗以及支持广泛应用场景等方式,为物联网系统的设计和实现带来了诸多便利和优势。 02 IIC I/O扩展芯片的行业知识介绍 IIC I/O扩展芯片定义 IIc接口IO扩展芯片是一种可以为电子设备添加输入输出功能的集成电路,它可以有效提高设备的性能。 IIC 原理 I²C通信协议 :I²C是一种串行通信协议,用于连接微控制器及其外围设备。它只需要两根线(SDA数据线和SCL时钟线)即可实现全双工通信,同时还可以连接多个设备到同一总线上。 设备寻址 :每个I²C设备都有一个唯一的地址,主控制器通过发送设备的地址来选中并与之通信。I²C扩展IO芯片也具备一个或多个可设置的地址,以便主控制器能够识别并与之通信。 数据传输 :在选中特定的I²C设备后,主控制器可以通过I²C总线发送数据到该设备,或者从该设备读取数据。对于I²C扩展IO芯片,主控制器可以发送命令来设置或读取IO端口的电平状态,从而实现对外围设备的控制或监测。 中断机制 :许多I²C扩展IO芯片还具备中断功能。当IO端口的电平状态发生变化时,芯片可以产生一个中断信号,通知主控制器进行相应的处理。这样,主控制器可以更加高效地响应外部事件,而无需持续轮询IO端口的状态。 内部寄存器 :I²C扩展IO芯片内部通常包含多个寄存器,用于存储IO端口的配置信息、数据等。主控制器可以通过I²C总线访问这些寄存器,以实现对IO端口的控制和管理。 IIC I/O扩展芯片的参数选型 电源电压 :确保你的系统电源电压与IO扩展芯片的电源电压兼容。常见的电源电压范围包括1.8V、3.3V、5V等。 IO口数量 :根据你的应用需求确定所需的IO口数量。有些IO扩展芯片提供8个、16个或更多的IO口。 IO口类型 :考虑你需要的IO口类型,如准双向口、开漏输出等。准双向口既可以作为输入也可以作为输出,而开漏输出则可以用于驱动LED等外部设备。 通信接口 :确保IO扩展芯片支持你的主控制器所使用的通信接口,如I²C、SPI等。I²C接口通常使用两根线(SDA和SCL)进行通信,具有简单易用、支持多设备连接等优点。 中断功能 :如果你的应用需要实时监测外部设备状态的变化,那么选择具有中断功能的IO扩展芯片将非常有用。当中断引脚被触发时,主控制器可以立即响应并处理相应的事件。 封装和尺寸 :根据你的应用需求和电路板空间限制选择合适的封装和尺寸。常见的封装类型包括TSSOP、QFN、SSOP等,尺寸范围也有所不同。 工作温度和功耗 :考虑你的应用所在的环境温度和功耗要求。选择具有适当工作温度和低功耗的IO扩展芯片将有助于提高系统的稳定性和可靠性。 其他特性 :根据你的应用需求,还可以考虑其他特性,如驱动能力(最大输出电流)、输入/输出电平范围、可编程性(是否支持通过编程来配置IO口)等。 IIC I/O扩展芯片的厂商 NXP Semiconductors(恩智浦半导体) :NXP是全球领先的半导体公司之一,提供广泛的IIC IO扩展芯片产品。其产品线包括PCF8574、PCA9555等,这些芯片具有高性能、低功耗和易用性等特点,广泛应用于各种领域。 Microchip Technology(微芯科技) :Microchip是一家专注于嵌入式控制和混合信号半导体解决方案的供应商。其IIC IO扩展芯片产品包括MCP23017、MCP23S17等,这些芯片具有高集成度、高可靠性和低功耗等特点,适用于工业自动化、消费电子和汽车电子等领域。 Texas Instruments(德州仪器) :德州仪器是一家全球性的半导体设计和制造公司,其IIC IO扩展芯片产品包括TPS2113、TPS2296等。这些芯片具有高性能、高精度和低功耗等特点,广泛应用于电源管理、电机控制和工业自动化等领域。 STMicroelectronics(意法半导体) :意法半导体是一家全球领先的半导体公司,提供广泛的IIC IO扩展芯片产品。其产品线包括VLSI Solution的82C55A等,这些芯片具有高速、高可靠性和低功耗等特点,适用于各种嵌入式系统和工业自动化应用。 此外,还有其他一些厂商也提供IIC IO扩展芯片产品,如Maxim Integrated、Renesas Electronics等。在选择IIC IO扩展芯片时,需要根据具体的应用需求和性能要求来选择合适的厂商和产品。国内也有一些知名的IIC(实际上是I²C,即Inter-Integrated Circuit)IO扩展芯片厂商,以下是一些例子: 中微爱芯 :作为中国领先的半导体公司之一,中微爱芯专注于消费电子芯片和小家电芯片的研发。他们的产品可能包括IIC IO扩展芯片,但具体型号和规格可能需要查询其官方渠道。 紫光展锐 :紫光展锐是中国集成电路设计和解决方案供应商,他们在移动通信、数字多媒体等领域积累了丰富的经验。虽然他们主要以手机芯片闻名,但他们的产品线可能也涵盖IIC IO扩展芯片。 华大半导体 :华大半导体是中国电子信息产业集团有限公司(CEC)旗下的核心企业,是中国“909”工程集成电路项目的重点承担单位。他们提供多种类型的半导体产品,包括可能包含IIC IO扩展芯片的产品。 03 IIC I/O扩展芯片的硬件设计方案 本文主要采用了信路达的XL9535做为驱动芯片。 1、XL9535概述 XL9535是一款24引脚CMOS器件,通过I²C总线/SMBus接口 串行时钟线(SCL)、串行数据(SDA)为大多数微控制器系列提供16位通用并行输入/输出(GPIO)扩展。这些设备设计用于2.3-V至5.5-V Vcc操作。这些改进包括更高的驱动能力、5V I/O容差、更低的电源电流、单独的I/O配置和更小的封装。 通电时,I/O被配置为输入。系统主机可以通过写入I/O配置位来启用I/O作为输入或输出。每个输入或输出的数据都保存在相应的输入或输出寄存器中。输入端口寄存器的极性可以用极性反转寄存器反转。所有寄存器均可由系统主控器读取。 当任何输入状态与其对应的输入端口寄存器状态不同时,这些设备开漏中断(/INT)输出被激活,并用于向系统主机指示输入状态已改变。在超时或其他不当操作的情况下,系统主设备可以利用上电重置功能重置这些设备。通电重置将寄存器设置为默认值,并初始化I²C/SMBus状态机。三个硬件引脚(A0、A1和A2)改变固定的I²C总线地址, 并允许多达八个设备共享同一I²C总线/SMBus。 2、 XL9535特性 I²C总线至16位GPIO扩展器 工作电源电压范围为2.3 V至5.5 V 低待机电流消耗 5 V容错I/O端口 400 kHz快速模式I²C总线时钟频率 SCL/SDA输入上的噪声滤波器 内部通电复位 通电时无故障 极性反转寄存器 开漏有源低中断输出 16个I/O引脚,默认为16个输入 3、XL9535引脚配置和功能 4、XL9535功能框图和参考设计 04 IIC I/O扩展芯片的软件设计方案 本文采用了奇迹物联的红豆版开源技术平台为主控单元,一步步手把手教会读者如何使用红豆版开源平台编写XL9535驱动。这里对代码就不多详解,如果需要详细了解,请到奇迹物联的红豆版开源平台了解详细代码讲解。 1 Gitee链接地址 Demo位于amaziot_bloom_os_sdk\sample\3rd\1.0_XL9535 Gitee源码地址:https://gitee.com/ning./hongdou Github源码地址:https://github.com/ayumid/hongdou 编译指令:.\build.bat -l .\amaziot_bloom_os_sdk\sample\3rd\1.0_XL9535 2 组件功能介绍 驱动XL9535芯片,实现输入IO检测。 3 代码讲解 1 drv_xl9535_i2c_init 功能:该函数用于,将发送数据长度写入xl9535寄存器。 参数:五 返回值:无 示例: C //初始化i2c总线 ret = drv_xl9535_i2c_init(); 2 drv_xl9535_i2c_read 功能:该函数用于,读取I2C从机。 参数:五 返回值:无 示例: C RegAddr = 0x00; ret = drv_xl9535_i2c_read(&RegAddr, &RegReadValue0); sample_xl9535_catstudio_printf("read reg 00 i2c value=0x%x, ret=%d\n", RegReadValue0, ret); 3 drv_xl9535_i2c_write 功能:该函数用于,发送数据到I2C从机。 参数:五 返回值:无 示例: C RegAddr = 0x06; RegWriteValue = 0xFF; ret = drv_xl9535_i2c_write(&RegAddr, &RegReadValue0); sample_xl9535_catstudio_printf("write i2c value=0x%x, ret=%d\n", RegWriteValue, ret); 4 Demo实战 4.1 概述 上电后,按下按键,串口会打印出按下了哪一个按键 4.2 测试 测试步骤: 参考编译教程,和文档开头的编译指令,进行编译 按照编译教程选择对应的选项 烧录 4.3 宏定义介绍 sample_xl9535_uart_printf 输出日志到DEBUG 串口,日志比较少,可以输出到这个串口,如果日志比较多,需要输出到usb口,以免不必要的问题出现 sample_xl9535_catstudio_printf 输出日志到USB 串口,使用catstudio查看,catstudio查看日志需要更新对应版本mdb.txt文件,软件打开filtter过滤日志,只查看用户输出的日志 SAMPLE_XL9535_STACK_SIZE 栈空间宏定义 4.4 全局变量介绍 sample_xl9535_int_detect_stack_ptr 任务栈空间,本例使用数组实现,用户在做项目时,可以预先估算下当先任务需要的大致栈空间,OS没有提供可以查看栈空间使用情况的API sample_xl9535_int_detect_task_ref 任务指针 4.5 函数介绍 Phase1Inits_enter 底层初始化,本例空 Phase1Inits_exit 底层初始化,本例空 Phase2Inits_enter 底层初始化,本例空 Phase2Inits_exit 创建主任务,初始化INT 引脚 代码片段: C int ret = 0; GPIOConfiguration config = {0}; //创建定时器 OSATimerCreate(&sample_xl9535_int_detect_timer_ref); //创建中断事件 OSAFlagCreate( &sample_xl9535_int_detect_flg_ref); Os_Create_HISR(&sample_xl9535_int_detect_hisr, "sample_xl9535_int_detect_hisr", sample_xl9535_detect_handler, 2); //创建中断处理任务 OSATaskCreate(&sample_xl9535_int_detect_task_ref, sample_xl9535_int_detect_stack_ptr, SAMPLE_XL9535_STACK_SIZE, 100, "detect_task", sample_xl9535_detect_task, NULL); //初始化int引脚,这里使用70脚 gpio126 config.pinDir = GPIO_IN_PIN; config.pinEd = GPIO_RISE_EDGE; config.pinPull = GPIO_PULLUP_ENABLE; config.isr = sample_xl9535_irq_handler; GpioInitConfiguration(SAMPLE_GPIO_ISR_PIN_NUM, config); sample_xl9535_detect_task 主任务,代码发分为两部分,一部分是发送不定长数据;另一部分是上电后等待其它模块发送的数据,收到后打印到串口。 代码片段: C void sample_xl9535_detect_task(void *param) { GPIO_ReturnCode ret = 0; UINT32 value = 0; OSA_STATUS status = OS_SUCCESS; UINT32 flag_value = 0; unsigned char RegAddr = 0; unsigned char RegWriteValue = 0; unsigned char RegReadValue0 = 0; unsigned char RegReadValue1 = 0; UINT8 down_en = 0; UINT8 up_en = 0; UINT8 sig_en = 0; UINT8 mul_en = 0; UINT8 read_en = 0; UINT8 de_en = 0; UINT8 ck_en = 0; UINT8 sim_en = 0; UINT8 gnss_en = 0; UINT8 nb_en = 0; UINT8 fourg_en = 0; //初始化i2c总线 ret = drv_xl9535_i2c_init(); sample_xl9535_catstudio_printf("ql_i2c_init ret %d", ret); //上电后,读xl9535 io扩展芯片的8个寄存器,测试用 RegAddr = 0x00; ret = drv_xl9535_i2c_read(&RegAddr, &RegReadValue0); sample_xl9535_catstudio_printf("read reg 00 i2c value=0x%x, ret=%d\n", RegReadValue0, ret); RegAddr = 0x01; ret = drv_xl9535_i2c_read(&RegAddr, &RegReadValue0); sample_xl9535_catstudio_printf("read reg 01 i2c value=0x%x, ret=%d\n", RegReadValue0, ret); RegAddr = 0x02; ret = drv_xl9535_i2c_read(&RegAddr, &RegReadValue0); sample_xl9535_catstudio_printf("read reg 02 i2c value=0x%x, ret=%d\n", RegReadValue0, ret); RegAddr = 0x03; ret = drv_xl9535_i2c_read(&RegAddr, &RegReadValue0); sample_xl9535_catstudio_printf("read reg 03 i2c value=0x%x, ret=%d\n", RegReadValue0, ret); RegAddr = 0x04; ret = drv_xl9535_i2c_read(&RegAddr, &RegReadValue0); sample_xl9535_catstudio_printf("read reg 04 i2c value=0x%x, ret=%d\n", RegReadValue0, ret); RegAddr = 0x05; ret = drv_xl9535_i2c_read(&RegAddr, &RegReadValue0); sample_xl9535_catstudio_printf("read reg 05 i2c value=0x%x, ret=%d\n", RegReadValue0, ret); RegAddr = 0x06; ret = drv_xl9535_i2c_read(&RegAddr, &RegReadValue0); sample_xl9535_catstudio_printf("read reg 06 i2c value=0x%x, ret=%d\n", RegReadValue0, ret); RegAddr = 0x07; ret = drv_xl9535_i2c_read(&RegAddr, &RegReadValue0); sample_xl9535_catstudio_printf("read reg 07 i2c value=0x%x, ret=%d\n", RegReadValue0, ret); //等1s OSATaskSleep(1 * 200); //初始化xl0535 io扩展芯片的06 07寄存器,设置所有的io都是输入 RegAddr = 0x06; RegWriteValue = 0xFF; ret = drv_xl9535_i2c_write(&RegAddr, &RegReadValue0); sample_xl9535_catstudio_printf("write i2c value=0x%x, ret=%d\n", RegWriteValue, ret); RegAddr = 0x07; RegWriteValue = 0xFF; ret = drv_xl9535_i2c_write(&RegAddr, &RegReadValue0); sample_xl9535_catstudio_printf("write i2c value=0x%x, ret=%d\n", RegWriteValue, ret); while(1) { // sample_xl9535_catstudio_printf("sample_xl9535_detect_task\r\n"); status = OSAFlagWait(sample_xl9535_int_detect_flg_ref, 0x01, OSA_FLAG_OR_CLEAR, &flag_value, OSA_SUSPEND); //红豆版,设置了边沿,但是还是会上升沿,下降沿都触发,所以会执行两次 if(flag_value & 0x01) { RegAddr = 0x00; //ret = ql_i2c_read(i2c_no, SAMPLE_I2C_SLAVE_ADDR, RegAddr, &RegReadValue0, 1); ret = drv_xl9535_i2c_read(&RegAddr, &RegReadValue0); // sample_xl9535_catstudio_printf("read reg 00 i2c value=0x%x, ret=%d\n", RegReadValue0, ret); RegAddr = 0x01; //ret = ql_i2c_read(i2c_no, SAMPLE_I2C_SLAVE_ADDR, RegAddr, &RegReadValue0, 1); ret = drv_xl9535_i2c_read(&RegAddr, &RegReadValue1); // sample_xl9535_catstudio_printf("read reg 01 i2c value=0x%x, ret=%d\n", RegReadValue1, ret); //寄存器值非默认值,表示有io输入,否则表示是上升沿中断 if(RegReadValue0 != 0xff || RegReadValue1 != 0x07) { event_ticks = OSAGetTicks(); int_status = 0; //判断是那个IO这里使用寄存器值判断,后续可以改为根据位判断 if(RegReadValue1 == DRV_XL9535_BUTTON_DOWN_EN) { // sample_xl9535_catstudio_printf("down int"); down_en = 1; } else if(RegReadValue1 == DRV_XL9535_BUTTON_UP_EN) { // sample_xl9535_catstudio_printf("up int"); up_en = 1; } else if(RegReadValue1 == DRV_XL9535_BUTTON_SIG_EN) { // sample_xl9535_catstudio_printf("sig int"); sig_en = 1; } else if(RegReadValue0 == DRV_XL9535_BUTTON_MUL_EN) { // sample_xl9535_catstudio_printf("mul int"); mul_en = 1; } else if(RegReadValue0 == DRV_XL9535_BUTTON_READ_EN) { // sample_xl9535_catstudio_printf("read int"); read_en = 1; } else if(RegReadValue0 == DRV_XL9535_BUTTON_DE_EN) { // sample_xl9535_catstudio_printf("de int"); de_en = 1; } else if(RegReadValue0 == DRV_XL9535_BUTTON_CK_EN) { // sample_xl9535_catstudio_printf("ck int"); ck_en = 1; } else if(RegReadValue0 == DRV_XL9535_BUTTON_SIM_EN) { // sample_xl9535_catstudio_printf("sim int"); sim_en = 1; } else if(RegReadValue0 == DRV_XL9535_BUTTON_GNSS_EN) { // sample_xl9535_catstudio_printf("gnss int"); gnss_en = 1; } else if(RegReadValue0 == DRV_XL9535_BUTTON_NB_EN) { // sample_xl9535_catstudio_printf("nb int"); nb_en = 1; } else if(RegReadValue0 == DRV_XL9535_BUTTON_4G_EN) { // sample_xl9535_catstudio_printf("4g int"); fourg_en = 1; } } else { if(int_status == 0) { UINT32 keep_ticks = OSAGetTicks() - event_ticks; 20) { //检测到某个IO被按下后,可以在这里,或者发送信号,消息等去其它任务执行相应操作 // sample_xl9535_catstudio_printf("keep_ticks:%d, event_ticks:%d", keep_ticks, event_ticks); if(down_en == 1) { sample_xl9535_catstudio_printf("down en"); } else if(up_en == 1) { sample_xl9535_catstudio_printf("up en"); } else if(sig_en == 1) { sample_xl9535_catstudio_printf("sig en"); } else if(mul_en == 1) { sample_xl9535_catstudio_printf("mul en"); } else if(read_en == 1) { sample_xl9535_catstudio_printf("read en"); } else if(de_en == 1) { sample_xl9535_catstudio_printf("de en"); } else if(ck_en == 1) { sample_xl9535_catstudio_printf("ck en"); } else if(sim_en == 1) { sample_xl9535_catstudio_printf("sim en"); } else if(gnss_en == 1) { sample_xl9535_catstudio_printf("gnss en"); } else if(nb_en == 1) { sample_xl9535_catstudio_printf("nb en"); } else if(fourg_en == 1) { sample_xl9535_catstudio_printf("4g en"); } } down_en = 0; up_en = 0; sig_en = 0; mul_en = 0; read_en = 0; de_en = 0; ck_en = 0; sim_en = 0; gnss_en = 0; nb_en = 0; fourg_en = 0; } int_status = 1; } } } } 4.6 固件 上电后,按下按键,串口会打印出按下了哪一个按键 注:本文部分内容来源于网络,如有侵权,请及时联系我们。 本文章源自奇迹物联开源的物联网应用知识库Cellular IoT Wiki,更多技术干货欢迎关注收藏Wiki: Cellular IoT Wiki 知识库(https://rckrv97mzx.feishu.cn/wiki/wikcnBvAC9WOkEYG5CLqGwm6PHf)
  • 2024-9-30 14:38
    65 次阅读|
    0 个评论
    01 概述 IO输入检测是嵌入式开发场景中,经常会遇到的情况,按键检测,外部IC中断检测,都需要输入检测。 输入信号的检测的前提条件,那就是需要在读取信号前,将输入信号的IO端口进行置1,然后就可以读取该端口上的状态,由于我们的单片机是带上拉电阻的,所以当我们把端口置1后,端口上如果什么也不接,就是处于悬空状态,那么我们读到的就是1,也就是说,单片机的常态是1,要想检测到外界的信号变化,就需要对端口置0,我们的外电路的输入信号应该是接地的才会有效。 02 按键的消抖问题 按键是机械的, 在按下和松手的瞬间会伴随有一定时间的抖动,按键开关不会马上稳定接通或一下断开,使用按键时会产生图中所示波浪信号,我们写程序的时候需要用软件消抖处理滤波。 当然也可以设计硬件进行消抖,如果有硬件消抖,软件就不用再设计消抖处理。硬件消抖一般是利用RC电路的电容充放电特性来对抖动产生的电压毛刺进行滤波,简单示意图如图 03 检测IC消抖 大多数IC的输出INT接口,不需要消抖。具体可以使用示波器,查看当外部IC的INT信号发生时,是否会产生抖动。 如果需要去抖,可以参考按键去抖电路,硬件消抖,或者世界在软件上消抖。但如果外部IC产生的INT的信号频率很高,注意软件消抖的延时问题。 04 组件的使用 1 Gitee链接地址 Demo位于amaziot_bloom_os_sdk\sample\3rd\3.2_MUL_MENU-SSD1315 Gitee源码地址:https://gitee.com/ning./hongdou Github源码地址:https://github.com/ayumid/hongdou 编译指令:.\build.bat -l .\amaziot_bloom_os_sdk\sample\3rd\3.2_MUL_MENU-SSD1315 2 组件功能介绍 INPUT组件适用于所有需要数据检测的场景,例如按键,中断等。组件中实现了4路输出检测,如需增加更多,可以参考组件中的代码增加。 该组件配合MENU组件使用,实现了按键多级菜单。客户可以根据自己的场景进行微改。 3 代码讲解 4路代码重复性较高,所以这里只列出第X路的API 1 input_keyX_irq_hadler 功能:该函数用于,中断回调函数。 参数:无 返回值:无 示例: C config.isr = input_key0_irq_hadler; 2 input_keyX_hadler 功能:该函数用于,回调函数。 参数:无 返回值:无 示例: C Os_Create_HISR(&input_key0_hisr, "Gpio_Hisr", input_key0_hadler, 2); 3 input_keyX_callback 功能:该函数用于,去抖定时器回调函数。 参数:无 返回值:无 示例: C OSATimerStart(input_key0_timer_ref, 2, 0, input_key0_callback, 0); 4 input_key_init 功能:该函数用于,初始化菜单按键使用的gpio。 参数:无 返回值:无 示例: C //初始化按键 input_key_init(); 返回值:无 4 Demo实战 该组件需要和MENU配合实验,实战内容和MENU中一样,不重复增加Demo。 4.1 创建一个Demo 复制3.1_SSD1315示例工程,到同一个文件夹下,修改文件名为3.2_MUL_MENU-SSD1315,如图: 4.2 修改makefile 增加文件组件所在目录头文件路径,和源文件路径,如图: 4.3 增加头文件 使用代码编辑器,将新建的工程文件加入代码编辑器中,打开main.c,修改main.c,加入am.h等头文件,如图: 4.4 修改代码 在Phase2Inits_exit 创建一个任务,如图: 4.5 宏定义介绍 sample_ssd1315_uart_printf 输出日志到DEBUG 串口,日志比较少,可以输出到这个串口,如果日志比较多,需要输出到usb口,以免不必要的问题出现 sample_ssd1315_catstudio_printf 输出日志到USB 串口,使用catstudio查看,catstudio查看日志需要更新对应版本mdb.txt文件,软件打开filtter过滤日志,只查看用户输出的日志 SAMPLE_SSD1315_STACK_SIZE 栈空间宏定义 4.6 全局变量介绍 sample_ssd1315_stack_ptr 任务栈空间,本例使用数组实现,用户在做项目时,可以预先估算下当先任务需要的大致栈空间,OS没有提供可以查看栈空间使用情况的API sample_ssd1315_task_ref 任务指针 4.7 函数介绍 Phase1Inits_enter 底层初始化,本例空 Phase1Inits_exit 底层初始化,本例空 Phase2Inits_enter 底层初始化,本例空 Phase2Inits_exit 创建主任务,初始化消息队列,定时器,任务等。 代码片段: C int ret = 0; GPIOConfiguration config = {0}; //创建定时�? OSATimerCreate(&sample_xl9535_int_detect_timer_ref); //创建中断处理任务 OSATaskCreate(&sample_ssd1315_task_ref, sample_ssd1315_stack_ptr, SAMPLE_SSD1315_STACK_SIZE, 100, "ssd1315_task", sample_ssd1315_task, NULL); input_run_main_menu 显示主界面,用户任务中调用这个函数。 代码片段: C static input_OPTION_TYPE_T input_OptionList = { {"TOOLS1", NULL}, {"TOOLS2", NULL}, {"TOOLS3", NULL}, {"TOOLS4", NULL}, {"TOOLS5", NULL}, {".."}}; static input_HANDLE_TYPE_T MENU = {.OptionList = input_OptionList}; input_run_menu(&MENU); input_run_tools_menu 根据按键选择运行工具界面。 代码片段: C static input_OPTION_TYPE_T input_OptionList SDK_CUST_SKU : SDK_PS_MODE : SDK_CHIP_VER : SDK_OS_TYPE : Platform Convertion Tools v4.01 with PS option extension Convertion done! |INPUT |out\bin\cp_1606L.bin |MARK |NAME |EXEADDR .LOADADDR.LENGTH .CPZLADDR|COMPRESS STASTIC | |--------|--------|--------.--------.--------.--------|------------------------------| |This Is LteOnly 4M| 00003000 |This Is LteOnly 4M| 00001000 |This Is LteOnly 4M| 0000a000 |This Is LteOnly 4M| 0001e000 |This Is LteOnly 4M| 0001b000 |This Is LteOnly 4M| 0001b000 |This Is LteOnly 4M| 0001a000 |This Is LteOnly 4M| 0001a000 |This Is LteOnly 4M| 00011000 |This Is LteOnly 4M| 0001e000 |This Is LteOnly 4M| 00021000 |This Is LteOnly 4M| 00012000 |--------|--------|--------.--------.--------.--------|------------------------------| 0x0014a000| 1.289(MB)| |------------------------------------------------------------------------------------| cp_1606L.axf cp_1606L.bin cp_1606L.map gnumake: Leaving directory `F:/3.asr-b/cat.1-asr1606/1.software/BlOOM_OS_1606_OPENCPU_1191_A09_WIHT_NEWRF/amaziot_bloom_os_sdk/sample/3rd/3.2_MUL_MENU-SSD1315' "copy NEZHAC_CP_CNR_MIFI_TX.bin to ./ " 已复制 1 个文件。 4.9 生成固件 参考入门中开发工具,生成工具。 4.10 测试 测试步骤: 参考编译教程,和文档开头的编译指令,进行编译 按照编译教程选择对应的选项 烧录 4.11 固件 上电后,屏幕会显示主菜单,通过4个按键:选择,返回,上,下。可以选择不同的菜单; 点击下载 OLED 多级菜单 Demo固件 5 生态组件链接 注:本文部分内容来源于网络,如有侵权,请及时联系我们。 本文章源自奇迹物联开源的物联网应用知识库Cellular IoT Wiki,更多技术干货欢迎关注收藏Wiki: Cellular IoT Wiki 知识库(https://rckrv97mzx.feishu.cn/wiki/wikcnBvAC9WOkEYG5CLqGwm6PHf)
  • 2024-9-30 14:37
    60 次阅读|
    0 个评论
    01 概述 导航和可查找性是用户体验设计的核心方面。如果用户无法到达他们想去的地方或找到他们需要的东西,他们会感到沮丧,并可能决定去别处寻找。在具有特别复杂的信息架构的网站上, 多级菜单是改善导航和可查找性的有效方法,从而提供高效的Web体验,从而促进产品信任度和转化率。 由于产品及其使用设备的差异很大,因此没有一种万能的解决方案可以产生完美的多级菜单。但是,有一些经验法则可以帮助您构建多级菜单,以增强任何屏幕尺寸的导航和可查找性。 02 多级菜单的程序设计 1 循环方式   循环方式的设计思路:预先定义一个包含6个结构元素的结构体、5个字符型和1个指针型。第1个字符变量存放当前界面的索引号;第2个字符变量存放按下“down(向下)”键时需要跳转到的索引号;第3个字符变量存放按下“up(向上)”键时需要跳转到的索引号;第4个字符变量存放按下“enter(进入)”键时需要跳转的索引号;第5个字符变量存放按下“esc(退出)”键时需要跳转的索引号;第6个变量为函数指针变量,存放当前索引号下需要执行的函数的入口地址。 将所有需要显示的界面其所对应的执行函数和按键索引号以结构体的形式列表存储。具体实现如下: typedef struct{ uchar down_index; uchar up_index; uchar enter_index; uchar esc_index; void (*operate)(); }Key_index_struct;   假设菜单分3级,共10个界面,则有: Key_index_struct const Key_tab ={ {0, 0, 0, 1, 0,(*main_menu)}, {1, 2, 3, 4, 0,(*sub_menu1)}, {2, 3, 1, 5, 0,(*sub_menu2)}, {3, 1, 2, 7, 0,(*sub_menu3)}, {4, 4, 4, 4, 1,(*sub_menu1_1)}, {5, 6, 6, 5, 2,(*sub_menu2_1)}, {6, 5, 5, 5, 2,(*sub_menu2_2)}, {7, 8, 9, 7, 3,(*sub_menu3_1)}, {8, 9, 7, 8, 3,(*sub_menu3_2)}, {9, 7, 8, 9, 3,(*sub_menu3_3)}, }; void Lcd_display(void){ switch(Key_status){ case enter: Key_fun=Key_tab .enter_index; break; case down: Key_fun=Key_tab .down_index; break; case up: Key_fun=Key_tab .up_index; break; case esc: Key_fun=Key_tab .esc_index; break; default: return; break; } Key_fun_Pt=Key_tab .operate; (*Key_fun_Pt)();//执行当前按键的操作 }   当微处理器扫描键盘检测到有按键按下时,根据按键按下的类型,返回在当前界面下其所对应的跳转索引号,并执行相应的函数。   由于每个界面的绘制都是由一个独立函数实现的,从循环方式的实现过程中发现,每发生一次按键按下操作都需要重新绘制整个屏幕。如果核心处理器是低速主频的处理器,在界面切换的时候会闪烁。而且,每一个界面都有固定不变的索引号,在增加或删除界面的时候需要重新修改整个列表,降低了程序的可移植性。 2 查询方式   查询方式是通过结构体对自身的递归调用实现菜单的多级嵌套。   结构体通过对自身的两次调用构建双向列表。一个菜单界面即为一个节点,节点的前驱和后继分别存放其父节点和子节点的入口地址。 3 状态机方式   状态机是由事件驱动,在各个状态之间跳转。采用状态机方式时,只需要提供驱动事件(在此设计中驱动事件为有效的按键按下),然后根据按键扫描返回的键值,决定所要跳转的下一状态。   如图3所示,系统启动初始化是显示Main_menu界面,当按键检测有返回值(即有按键按下)时,根据按下的按键所代表的操作跳转到指定的状态。例如:按下Up或者是down键时,只是在Main_menu界面内高亮显示不同区域;按下Enter时,则要根据原来按下的Up和down键来选择需要跳转的方向,假设在按下Enter之前仅按下一次down键,则key_v的值为2(key_v的值默认为1,即默认选中子菜单的第一项),就跳转为Sub_menu2界面;按下Esc键时,为从子菜单返回到上一级菜单,如果已经是主菜单了则返回的还是主菜单。 由于使用的是状态机的方式,只有发生一次有效的按键,状态才会发生一次跳转。而且,仅当Enter和Esc键按下时,才会切换界面。所以即便是在高速CPU应用中,也不会出现屏幕闪烁的效果。 从图3中可以看出,当要发生状态跳转时,目的状态只能是当前状态几个分支预测中的一个,从而不需要遍历整个列表,能够适应高速数据处理的场合。 多级菜单的程序流程如图4所示。系统上电初始化后显示主菜单,键盘扫描可以通过主程序中循环查询或者中断扫描来实现,最终根据键盘返回的键值选择下一状态。 03 组件的使用 1 Gitee链接地址 Demo位于amaziot_bloom_os_sdk\sample\3rd\3.2_MUL_MENU-SSD1315 Gitee源码地址:https://gitee.com/ning./hongdou Github源码地址:https://github.com/ayumid/hongdou 编译指令:.\build.bat -l .\amaziot_bloom_os_sdk\sample\3rd\3.2_MUL_MENU-SSD1315 2 组件功能介绍 驱动OLED显示多级菜单,所有的OLED都可以使用这个组件,都可以使用本驱动。驱动使用模拟spi实现。 menu相关代码可以移植到其它任意尺寸屏幕上,修改menu.c相关显示尺寸即可。 3 代码讲解 1 menu_command_callback 功能:该函数用于,菜单指令回调函数。 参数: 参数 释义 command 起点坐标 ... 可变参数 返回值:无 示例: C menu_command_callback(GET_EVENT_ENTER) 2 menu_run_menu 功能:该函数用于,菜单运行函数。 参数: 参数 释义 hMENU 菜单句柄 返回值:无 示例: C menu_run_main_menu(); 3 menu_handle_init 功能:该函数用于,菜单初始化。 参数: 参数 释义 hMENU 菜单句柄 返回值:无 示例: C menu_handle_init(hMENU); // 初始化 4 menu_event_and_action 功能:该函数用于,处理相应按键事件。 参数: 参数 释义 hMENU 菜单句柄 返回值:无 示例: C menu_event_and_action(hMENU); // 检查事件及作相应操作 5 menu_updata_idx 功能:该函数用于,更新菜单选中下标。 参数: 参数 释义 hMENU 菜单句柄 返回值:无 示例: C menu_updata_idx(hMENU); 6 menu_show_option_list 功能:该函数用于,菜单显示列表。 参数: 参数 释义 hMENU 菜单句柄 返回值:无 示例: C menu_show_option_list(hMENU); /* 显示选项列表 */ 7 menu_show_option 功能:该函数用于,根据数据类型显示。 参数: 参数 释义 x,y 起始坐标 hMENU 菜单句柄 返回值:无 示例: C /* 显示选项, 并记录长度 */ Show_i + i]); 8 menu_show_cursor 功能:该函数用于,显示光标。 参数: 参数 释义 hMENU 菜单句柄 返回值:无 示例: C menu_show_cursor(hMENU); /* 显示光标 */ 9 menu_show_border 功能:该函数用于,显示边框。 参数: 参数 释义 hMENU 菜单句柄 返回值:无 示例: C menu_show_border(hMENU); // 显示边框 10 menu_oled_set_cursor 功能:该函数用于,画OLED设置显示光标位置。 参数: 参数 释义 Page 指定光标所在的页,范围:0~7 X 指定光标所在的X轴坐标,范围:0~127 返回值:无 示例: C /*设置光标位置为每一页的第一列*/ menu_oled_set_cursor(j, 0); 11 menu_oled_write_data 功能:该函数用于,OLED写数据。 参数: 参数 释义 Data 要写入数据的起始地址 Count 要写入数据的数量 返回值:无 示例: C /*连续写入128个数据,将显存数组的数据写入到OLED硬件*/ menu_oled_write_data(menu_display_buf , 128); 12 menu_oled_clear 功能:该函数用于,将OLED显存数组全部清零。 参数:无 返回值:无 示例: C drv_ssd1315_refresh(); 13 menu_oled_clear_area 功能:该函数用于,将OLED显存数组部分清零。 参数: 参数 释义 X 指定区域左上角的横坐标,范围:0~127 Y 指定区域左上角的纵坐标,范围:0~63 Width 指定区域的宽度,范围:0~128 Height 指定区域的高度,范围:0~64 返回值:无 示例: C /*将图像所在区域清空*/ menu_oled_clear_area(X, Y, Width, Height); 14 menu_oled_show_image 功能:该函数用于,OLED显示图像。 参数: 参数 释义 X 指定区域左上角的横坐标,范围:0~127 Y 指定区域左上角的纵坐标,范围:0~63 Width 指定区域的宽度,范围:0~128 Height 指定区域的高度,范围:0~64 Image 指定要显示的图像 返回值:无 示例: C /*将ASCII字模库OLED_F6x8的指定数据以6*8的图像格式显示*/ menu_oled_show_image(X, Y, 6, 8, OLED_F6x8 ); 15 menu_oled_show_char 功能:该函数用于,屏幕旋转180度。 参数: 参数 释义 X 指定区域左上角的横坐标,范围:0~127 Y 指定区域左上角的纵坐标,范围:0~63 Char 指定要显示的字符,范围:ASCII码可见字符 FontSize 指定字体大小 范围:OLED_8X16 宽8像素,高16像素 OLED_6X8 宽6像素,高8像素 返回值:无 示例: C menu_oled_show_char(X + len * FontSize, Y, String , FontSize); 16 menu_oled_show_chn 功能:该函数用于,反显函数。 参数: 参数 释义 X 指定区域左上角的横坐标,范围:0~127 Y 指定区域左上角的纵坐标,范围:0~63 Char 指定要显示的字符,范围:ASCII码可见字符 FontSize 指定字体大小 范围:OLED_8X16 宽8像素,高16像素 OLED_6X8 宽6像素,高8像素 返回值:无 示例: C menu_oled_show_chn(X + len * FontSize, Y, SingleChinese, FontSize); 17 menu_oled_show_str 功能:该函数用于,OLED显示字符串。 参数: 参数 释义 X 指定区域左上角的横坐标,范围:0~127 Y 指定区域左上角的纵坐标,范围:0~63 Hanzi 指定要显示的字符,范围:字库字符 FontSize 指定字体大小 范围:OLED_8X16 宽8像素,高16像素 OLED_6X8 宽6像素,高8像素 返回值:无 示例: C menu_oled_show_str(X, Y, String, FontSize);//OLED显示字符数组(字符串) 18 menu_oled_printf 功能:该函数用于,OLED使用printf函数打印格式化字符串。 参数: 参数 释义 X 指定区域左上角的横坐标,范围:0~127 Y 指定区域左上角的纵坐标,范围:0~63 FontSize 指定字体大小 范围:OLED_8X16 宽8像素,高16像素 OLED_6X8 宽6像素,高8像素 format 指定要显示的格式化字符串,范围:ASCII码可见字符组成的字符串 ... 格式化字符串参数列表 返回值:无 示例: C /* 按需使用参数 */ menu_oled_printf(show_x, show_y, MENU_FONT_W, show_string); // 显示字符串 19 menu_oled_reverse_area 功能:该函数用于,将OLED显存数组部分取反。 参数: 参数 释义 X 指定区域左上角的横坐标,范围:0~127 Y 指定区域左上角的纵坐标,范围:0~63 Width 指定区域的宽度,范围:0~128 Height 指定区域的高度,范围:0~64 返回值:无 示例: C menu_oled_show_chn(X + len * FontSize, Y, SingleChinese, FontSize); 20 menu_oled_draw_point 功能:该函数用于,OLED在指定位置画一个点。 参数: 参数 释义 X 指定区域左上角的横坐标,范围:0~127 Y 指定区域左上角的纵坐标,范围:0~63 返回值:无 示例: C menu_oled_show_chn(X + len * FontSize, Y, SingleChinese, FontSize); 21 menu_keyX_irq_hadler 功能:该函数用于,中断回调函数。 参数:无 返回值:无 示例: C config.isr = menu_key0_irq_hadler; 22 menu_keyX_hadler 功能:该函数用于,回调函数。 参数:无 返回值:无 示例: C Os_Create_HISR(&menu_key0_hisr, "Gpio_Hisr", menu_key0_hadler, 2); 23 menu_keyX_callback 功能:该函数用于,去抖定时器回调函数。 参数:无 返回值:无 示例: C OSATimerStart(menu_key0_timer_ref, 2, 0, menu_key0_callback, 0); 24 menu_key_init 功能:该函数用于,初始化菜单按键使用的gpio。 参数:无 返回值:无 示例: C //初始化按键 menu_key_init(); 返回值:无 4 Demo实战 4.1 创建一个Demo 复制3.1_SSD1315示例工程,到同一个文件夹下,修改文件名为3.2_MUL_MENU-SSD1315,如图: 4.2 修改makefile 增加文件组件所在目录头文件路径,和源文件路径,如图: 4.3 增加头文件 使用代码编辑器,将新建的工程文件加入代码编辑器中,打开main.c,修改main.c,加入am.h等头文件,如图: 4.4 修改代码 在Phase2Inits_exit 创建一个任务,如图: 4.5 宏定义介绍 sample_ssd1315_uart_printf 输出日志到DEBUG 串口,日志比较少,可以输出到这个串口,如果日志比较多,需要输出到usb口,以免不必要的问题出现 sample_ssd1315_catstudio_printf 输出日志到USB 串口,使用catstudio查看,catstudio查看日志需要更新对应版本mdb.txt文件,软件打开filtter过滤日志,只查看用户输出的日志 SAMPLE_SSD1315_STACK_SIZE 栈空间宏定义 4.6 全局变量介绍 sample_ssd1315_stack_ptr 任务栈空间,本例使用数组实现,用户在做项目时,可以预先估算下当先任务需要的大致栈空间,OS没有提供可以查看栈空间使用情况的API sample_ssd1315_task_ref 任务指针 4.7 函数介绍 Phase1Inits_enter 底层初始化,本例空 Phase1Inits_exit 底层初始化,本例空 Phase2Inits_enter 底层初始化,本例空 Phase2Inits_exit 创建主任务,初始化消息队列,定时器,任务等。 代码片段: C int ret = 0; GPIOConfiguration config = {0}; //创建定时�? OSATimerCreate(&sample_xl9535_int_detect_timer_ref); //创建中断处理任务 OSATaskCreate(&sample_ssd1315_task_ref, sample_ssd1315_stack_ptr, SAMPLE_SSD1315_STACK_SIZE, 100, "ssd1315_task", sample_ssd1315_task, NULL); menu_run_main_menu 显示主界面,用户任务中调用这个函数。 代码片段: C static MENU_OPTION_TYPE_T MENU_OptionList = { {"TOOLS1", NULL}, {"TOOLS2", NULL}, {"TOOLS3", NULL}, {"TOOLS4", NULL}, {"TOOLS5", NULL}, {".."}}; static MENU_HANDLE_TYPE_T MENU = {.OptionList = MENU_OptionList}; menu_run_menu(&MENU); menu_run_tools_menu 根据按键选择运行工具界面。 代码片段: C static MENU_OPTION_TYPE_T MENU_OptionList SDK_CUST_SKU : SDK_PS_MODE : SDK_CHIP_VER : SDK_OS_TYPE : Platform Convertion Tools v4.01 with PS option extension Convertion done! |INPUT |out\bin\cp_1606L.bin |MARK |NAME |EXEADDR .LOADADDR.LENGTH .CPZLADDR|COMPRESS STASTIC | |--------|--------|--------.--------.--------.--------|------------------------------| |This Is LteOnly 4M| 00003000 |This Is LteOnly 4M| 00001000 |This Is LteOnly 4M| 0000a000 |This Is LteOnly 4M| 0001e000 |This Is LteOnly 4M| 0001b000 |This Is LteOnly 4M| 0001b000 |This Is LteOnly 4M| 0001a000 |This Is LteOnly 4M| 0001a000 |This Is LteOnly 4M| 00011000 |This Is LteOnly 4M| 0001e000 |This Is LteOnly 4M| 00021000 |This Is LteOnly 4M| 00012000 |--------|--------|--------.--------.--------.--------|------------------------------| 0x0014a000| 1.289(MB)| |------------------------------------------------------------------------------------| cp_1606L.axf cp_1606L.bin cp_1606L.map gnumake: Leaving directory `F:/3.asr-b/cat.1-asr1606/1.software/BlOOM_OS_1606_OPENCPU_1191_A09_WIHT_NEWRF/amaziot_bloom_os_sdk/sample/3rd/3.2_MUL_MENU-SSD1315' "copy NEZHAC_CP_CNR_MIFI_TX.bin to ./ " 已复制 1 个文件。 4.9 生成固件 参考入门中开发工具,生成工具。 4.10 测试 测试步骤: 参考编译教程,和文档开头的编译指令,进行编译 按照编译教程选择对应的选项 烧录 4.11 固件 上电后,屏幕会显示主菜单,通过4个按键:选择,返回,上,下。可以选择不同的菜单; 点击下载 OLED 多级菜单 Demo固件 5 生态组件链接 OLED屏 注:本文部分内容来源于网络,如有侵权,请及时联系我们。 本文章源自奇迹物联开源的物联网应用知识库Cellular IoT Wiki,更多技术干货欢迎关注收藏Wiki: Cellular IoT Wiki 知识库(https://rckrv97mzx.feishu.cn/wiki/wikcnBvAC9WOkEYG5CLqGwm6PHf)
  • 2024-9-30 14:34
    38 次阅读|
    0 个评论
    01 概述 W25Q128是一种NOR Flash芯片,掉电后数据不丢失的特点。 W25Q128FV阵列被组织成65,536个可编程页面,每个页面256字节。每次最多可编程256字节。可以以16页为一组(即一个Sector)、128页为一组(8个Sector)、256页为一组(16个Sector)或整个芯片(芯片擦除)进行擦除。 W25Q128FV分别有4,096个可擦除扇区和256个可擦除块。较小的4KB扇区为需要数据和参数存储的应用程序提供了更大的灵活性。 标准SPI通信支持时钟频率高达104MHz,Dual SPI通信支持时钟频率高达208MHz,QSPI通信支持时钟频率高达416MHz。 注意:W25Q128一共为128M bits(16M Byte),又分为256个块(每个块512K bit(64K Byte)),每个块又分为16个扇区(每个扇区32K bit(4 KByte)),每个扇区又分为16页(每个页2K bit(256 Byte)) 02 物理特性 可以将 1 写成 0,但是不能将 0 写成 1,要想将 0 写成 1,必须进行擦除操作。如果要改变数据,就需要先擦除后写数据。 如果想要修改小于扇区大小的数据,需要将整个扇区的数据,在内存中进行备份,然后修改内存中的数据,再将数据写回到原扇区位置。因此,驱动要达到支持自动完成这个过程,用户可以使用驱动修改任意位置的数据。 03 存储结构 W25Q128可以存储16777216字节,存储一个字节占用一个地址,所以寻址范围是0-(16777216-1),对应的16进制为0-0xFFFFFF(所以寄存器地址是24位的) 04 命令总览 05 组件的使用 1 Gitee链接地址 Demo位于amaziot_bloom_os_sdk\sample\3rd\2.1_W25Q128 Gitee源码地址:https://gitee.com/ning./hongdou Github源码地址:https://github.com/ayumid/hongdou 编译指令:.\build.bat -l .\amaziot_bloom_os_sdk\sample\3rd\2.1_W25Q128 2 组件功能介绍 实现软件模拟SPI,驱动W25Q128芯片,实现数据存储。 3 代码讲解 1 drv_w25q128_delay_us 功能:该函数用于,延时。 参数: 参数 释义 count 死循环次数 返回值:无 示例: C //初始化i2c总线 ret = drv_xl9535_i2c_init(); 2 drv_w25q128_gpio_set 功能:该函数用于,模拟SPI设置IO输出电平。 参数: 参数 释义 num 引脚号 val 0 低电平,1 高电平 返回值:0 成功,-1 失败 示例: C drv_w25q128_gpio_set(DRV_w25q128_SPI_CS, DRV_w25q128_GPIO_LOW); 3 drv_w25q128_byte_wr 功能:该函数用于,SPI写读一个字节 mode3。 参数: 参数 释义 byte 发送数据 返回值:flash返回数据 示例: C drv_w25q128_byte_wr(DRV_w25q128_DUMMY_BYTE); 4 drv_w25q128_byte_rd 功能:该函数用于,SPI只读一个字节。 参数:无 返回值:flash返回数据 示例: C drv_w25q128_byte_rd (DRV_w25q128_DUMMY_BYTE); 5 drv_w25q128_busy_wait 功能:该函数用于,W25Q128 忙等待。 参数:无 返回值:无 示例: C while(drv_w25q128_read_reg1() & BIT_BUSY); 6 drv_w25q128_read_reg 功能:该函数用于,读reg。 参数:无 返回值:无 示例: C while(drv_w25q128_read_reg() & BIT_BUSY); 7 drv_w25q128_read_jedecid 功能:该函数用于,读 W25Q128 JEDEC_ID(制造商、类型、容量)。 参数:无 返回值:无 示例: C sample_w25q128_uart_printf("identification is 0x%X, Device id is 0x%X, Manufacturer Device ID is 0x%X", drv_w25q128_read_identification(), drv_w25q128_read_device_id(), drv_w25q128_read_manufacturer_id()); 8 drv_w25q128_read_manufacturer_id 功能:该函数用于,读 W25Q128 制造商 ID。 参数:无 返回值:无 示例: C sample_w25q128_uart_printf("identification is 0x%X, Device id is 0x%X, Manufacturer Device ID is 0x%X", drv_w25q128_read_identification(), drv_w25q128_read_device_id(), drv_w25q128_read_manufacturer_id()); 9 drv_w25q128_read_device_id 功能:该函数用于,读 W25Q128 设备 ID。 参数:无 返回值:无 示例: C sample_w25q128_uart_printf("identification is 0x%X, Device id is 0x%X, Manufacturer Device ID is 0x%X", drv_w25q128_read_identification(), drv_w25q128_read_device_id(), drv_w25q128_read_manufacturer_id()); 10 drv_w25q128_write_enable 功能:该函数用于,写使能。 参数:无 返回值:无 示例: C sample_w25q128_uart_printf("identification is 0x%X, Device id is 0x%X, Manufacturer Device ID is 0x%X", drv_w25q128_read_identification(), drv_w25q128_read_device_id(), drv_w25q128_read_manufacturer_id()); 11 drv_w25q128_write_disable 功能:该函数用于,写失能。 参数:无 返回值:无 示例: C 无 12 drv_w25q128_write_page 功能:该函数用于,页编程(调用本函数写入数据前需要先擦除扇区)。 参数: 参数 释义 pbuf 数据 addr 地址 len 长度 返回值:无 示例: C drv_w25q128_write_page(pbuf, addr, pageremain); 13 drv_w25q128_read 功能:该函数用于,读闪存数据。 参数: 参数 释义 pbuf 数据 addr 地址 len 长度 返回值:无 示例: C drv_w25q128_read((UINT8*)rx_buff1, 8181, strlen(tx_buff1)); 14 drv_w25q128_sector_erase 功能:该函数用于,扇区擦除。 参数: 参数 释义 addr 地址 返回值:无 示例: C drv_w25q128_sector_erase(secpos * DRV_w25q128_SOCTOR_SIZE); 15 drv_w25q128_chip_rease 功能:该函数用于,FLASH整片擦除(为了安全起见,若要调用,请先调用 drv_w25q128_write_enable 函数)。 参数:无 返回值:无 示例: C 无 16 drv_w25q128_powr_down 功能:该函数用于,掉电。 参数:无 返回值:无 示例: C 无 17 drv_w25q128_release_powr_down 功能:该函数用于,读闪存数据。 参数: 参数 释义 pbuf 数据 addr 地址 len 长度 返回值:无 示例: C drv_w25q128_read((UINT8*)rx_buff1, 8181, strlen(tx_buff1)); 18 drv_w25q128_write_nocheck 功能:该函数用于,写数据。 参数: 参数 释义 pbuf 数据 addr 地址 len 长度 返回值:无 示例: C drv_w25q128_write_nocheck(w25q128_buffer, secpos * DRV_w25q128_SOCTOR_SIZE, DRV_w25q128_SOCTOR_SIZE); 19 drv_w25q128_write 功能:该函数用于,写闪存数据,可以使任意地址。 参数: 参数 释义 pbuf 数据 addr 地址 len 长度 返回值:无 示例: C drv_w25q128_write((UINT8*)tx_buff1, 8181, strlen(tx_buff1)); 20 drv_w25q128_init 功能:该函数用于,写数据。 参数:无 返回值:无 示例: C drv_w25q128_init(); 4 Demo实战 4.1 创建一个Demo 复制20.1_file_xtu示例工程,到同一个文件夹下,修改文件名为3.1_SSD1315,如图: 4.2 修改makefile 增加文件组件所在目录头文件路径,和源文件路径,如图: 4.3 增加头文件 使用代码编辑器,将新建的工程文件加入代码编辑器中,打开main.c,修改main.c,加入am.h等头文件,如图: 4.4 修改代码 在Phase2Inits_exit 创建一个任务,如图: 4.1 概述 上电后,按下按键,串口会打印出按下了哪一个按键 4.2 测试 测试步骤: 参考编译教程,和文档开头的编译指令,进行编译 按照编译教程选择对应的选项 烧录 4.3 宏定义介绍 sample_w25q128_uart_printf 输出日志到DEBUG 串口,日志比较少,可以输出到这个串口,如果日志比较多,需要输出到usb口,以免不必要的问题出现 sample_w25q128_catstudio_printf 输出日志到USB 串口,使用catstudio查看,catstudio查看日志需要更新对应版本mdb.txt文件,软件打开filtter过滤日志,只查看用户输出的日志 SAMPLE_W25Q128_STACK_SIZE 栈空间宏定义 4.4 全局变量介绍 sample_w25q128_task_ref 任务指针 4.5 函数介绍 Phase1Inits_enter 底层初始化,本例空 Phase1Inits_exit 底层初始化,本例空 Phase2Inits_enter 底层初始化,本例空 Phase2Inits_exit 创建主任务,初始化INT 引脚 代码片段: C void Phase2Inits_exit(void) { int ret; sample_w25q128_task_stack = malloc(SAMPLE_W25Q128_STACK_SIZE); ret = OSATaskCreate(&sample_w25q128_task_ref, sample_w25q128_task_stack, SAMPLE_W25Q128_STACK_SIZE, 88, "sample_w25q128_task", sample_w25q128_task, NULL); ASSERT(ret == OS_SUCCESS); } sample_w25q128_task 主任务,代码发分为两部分,一部分是发送不定长数据;另一部分是上电后等待其它模块发送的数据,收到后打印到串口。 代码片段: C static void sample_w25q128_task(void *ptr) { int ret = 0; uint32_t identification = 0; // unsigned char writeBuf = {0}; // unsigned char readBuf = {0}; // ret = ql_spi_init(QL_SPI_PORT0, QL_SPI_MODE3, QL_SPI_CLK_812_5KHZ); // sample_w25q128_catstudio_printf("ql_spi_init ret %d", ret); drv_w25q128_init(); identification = drv_w25q128_read_jedecid(); sample_w25q128_uart_printf("identification is 0x%X, Device id is 0x%X, Manufacturer Device ID is 0x%X", drv_w25q128_read_jedecid(), drv_w25q128_read_device_id(), drv_w25q128_read_manufacturer_id()); // while(1) // { // drv_w25q128_gpio_set(DRV_w25q128_SPI_CS, 0); // sample_w25q128_uart_printf("low"); // OSATaskSleep(5*200); // drv_w25q128_gpio_set(DRV_w25q128_SPI_CS, 1); // sample_w25q128_uart_printf("high"); // OSATaskSleep(5*200); // } if(identification != JEDECID) { /* 读取错误处理 */ sample_w25q128_uart_printf("SPI read-write Error, please check the connection between MCU and SPI Flash\n"); } else { //读取成功处理 char tx_buff1 = "abcdefghigklmnopqrstuvwxyz0123456789"; char rx_buff1 = {0}; char tx_buff2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ9876543210"; char rx_buff2 = {0}; int i = 0; //测试跨sector写,并且读出数据,写两次,第二次保留第一次部分数据,证明数据擦除,写入正常 drv_w25q128_write((UINT8*)tx_buff1, 8181, strlen(tx_buff1));//从8181地址开始写数据,需要写第二和第三个扇区 drv_w25q128_read((UINT8*)rx_buff1, 8181, strlen(tx_buff1)); sample_w25q128_uart_printf("read flash:%s", rx_buff1); if(!strncmp(tx_buff1, rx_buff1, strlen(tx_buff1))) { sample_w25q128_uart_printf("SPI read-write succeed 1"); } //验证驱动擦除扇区时,可以保留之前有效内容 drv_w25q128_write((UINT8*)tx_buff2, 8186, strlen(tx_buff2));//从8186地址开始写数据,需要写第二和第三个扇区,同时不能擦掉8181 - 8186的5字节数据 drv_w25q128_read((UINT8*)rx_buff2, 8181, strlen(tx_buff2) + 5); sample_w25q128_uart_printf("read flash:%s", rx_buff2); if(!strncmp(rx_buff2, "abcdeABCDEFGHIJKLMNOPQRSTUVWXYZ9876543210", strlen("abcdeABCDEFGHIJKLMNOPQRSTUVWXYZ9876543210"))) { sample_w25q128_uart_printf("SPI read-write succeed 2"); } } // memset(writeBuf, 0x00, sizeof(writeBuf)); // memset(readBuf, 0x00, sizeof(readBuf)); // writeBuf = 0x9F; while (1) { // ret = ql_spi_write_read(QL_SPI_PORT0, readBuf, writeBuf, 1); // sample_w25q128_catstudio_printf("ql_spi_write_read ret %d, readBuf %02X,%02X,%02X\n", ret, readBuf , readBuf , readBuf ); // ret = ql_spi_write(QL_SPI_PORT0, writeBuf, 1); // sample_w25q128_catstudio_printf("ql_spi_write_read ret %d, readBuf %02X\n", ret, writeBuf ); // ret = ql_spi_read(QL_SPI_PORT0, readBuf, 3); // sample_w25q128_catstudio_printf("ql_spi_write_read ret %d, readBuf %02X,%02X,%02X\n", ret, readBuf , readBuf , readBuf ); OSATaskSleep(5 * 200); } } 4.6 固件 点击下载 Lora Demo固件 5 生态组件链接 SPI NOR FLASH 注:本文部分内容来源于网络,如有侵权,请及时联系我们。 本文章源自奇迹物联开源的物联网应用知识库Cellular IoT Wiki,更多技术干货欢迎关注收藏Wiki: Cellular IoT Wiki 知识库(https://rckrv97mzx.feishu.cn/wiki/wikcnBvAC9WOkEYG5CLqGwm6PHf)
相关资源