原创 物联网硬件设计时IO不够用?IO扩展芯片的使用

2024-9-30 12:26 161 0 分类: 物联网


01

概述


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。


02

特性


  • I²C总线至16位GPIO扩展器
  • 工作电源电压范围为2.3 V至5.5 V
  • 低待机电流消耗
  • 5 V容错I/O端口
  • 400 kHz快速模式I²C总线时钟频率
  • SCL/SDA输入上的噪声滤波器
  • 内部通电复位
  • 通电时无故障
  • 极性反转寄存器
  • 开漏有源低中断输出
  • 16个I/O引脚,默认为16个输入


03

引脚配置和功能



04

功能框图



05

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;

if(keep_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)

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
0
关闭 站长推荐上一条 /3 下一条