CH423要如何使用,便宜的国产IO扩展芯片_arenascat的博客-程序员宝宝_ch423

技术标签: 硬件开发  

目录

前言

特点

如何使用

例子1  配置输出

例子2 配置OC1输出

例子3 配置OC14输出


前言

有时候会遇到IO不够用的情况,例如说驱动LED灯,那么有没有什么便宜的,容易买到的芯片?我这次就考虑使用WCH的CH423S,这是一个比较新的IO扩展芯片。

这一个芯片有最多24个输出引脚,双向IO有8个,可以说非常够用,价格在1.5元上下,并且货有不少。

特点

●通过两线串行接口远程扩展出8个通用输入输出引脚GPIO和16个通用输出引脚GPO。

●内置电流驱动级,连续驱动电流不小于15mA,OC引脚输出1/16脉冲灌电流不小于120mA。

●静态显示驱动方式支持24只发光管LED或者3位共阳数码管。

●分时动态扫描显示驱动方式支持128只发光管LED或者16位共阴数码管,支持亮度控制。

●双向I/O引脚在输入方式下具有输入电平变化时产生中断的功能,中断输出低电平有效。

●16个通用输出引脚可以选择推挽输出或者开漏输出。●支持3V~5V电源电压,支持低功耗睡眠,可以被输入电平变化唤醒。

●高速2线串行接口,时钟速度从0到1MHz,兼容两线I2C总线,节约引脚。

●提供DIP28S和SOP28两种无铅封装,兼容RoHS。

看一下原理图的部分,几乎不需要外围电路就可以可靠的运行。

如何使用

我根据官方的代码进行了一点修改,使得它非常的容易使用

代码如下,直接抄的官方例子然后简单修改,我用的是Arduino IDE来测试这一个芯片。

// 硬件相关定义, 请根据实际硬件修改本文件

#ifndef  CH423_H

#define CH423_H

#include <arduino.h>

#define DELAY_0_1US {delayMicroseconds(5);}


/* 2线接口的连接,与实际电路有关 */

unsigned int CH423_SCL = 5;

unsigned int CH423_SDA = 6;


/* 2线接口的位操作,与单片机有关 */


#define CH423_SCL_SET       { digitalWrite(CH423_SCL,HIGH); }

#define CH423_SCL_CLR       { digitalWrite(CH423_SCL,LOW); }

#define CH423_SCL_D_OUT     { pinMode(CH423_SCL,OUTPUT); }                // 设置SCL为输出方向,对于双向I/O需切换为输出

#define CH423_SDA_SET       { digitalWrite(CH423_SDA,HIGH);}

#define CH423_SDA_CLR       { digitalWrite(CH423_SDA,LOW);}


//#define CH423_SDA_IN        { digitalRead(CH423_SDA) }

#define CH423_SDA_D_OUT     { pinMode(CH423_SDA,OUTPUT); }                // 设置SDA为输出方向,对于双向I/O需切换为输出

#define CH423_SDA_D_IN      { pinMode(CH423_SDA,INPUT); }    // 设置SDA为输入方向,对于双向I/O需切换为输入




// CH423接口定义

#define     CH423_I2C_ADDR1     0x40         // CH423的地址

#define     CH423_I2C_MASK      0x3E         // CH423的高字节命令掩码


/*  设置系统参数命令 */


#define CH423_SYS_CMD     0x4800     // 设置系统参数命令,默认方式

#define BIT_X_INT         0x08       // 使能输入电平变化中断,为0禁止输入电平变化中断;为1并且DEC_H为0允许输出电平变化中断

#define BIT_DEC_H         0x04       // 控制开漏输出引脚高8位的片选译码

#define BIT_DEC_L         0x02       // 控制开漏输出引脚低8位的片选译码

#define BIT_IO_OE         0x01       // 控制双向输入输出引脚的三态输出,为1允许输出


/*  设置低8位开漏输出命令 */

#define CH423_L_CMD    0x0400      // 设置低8位推挽输出命令,默认方式

#define CH423_OC_L_CMD    0x4400     // 设置低8位开漏输出命令,默认方式

#define BIT_OC0_L_DAT     0x01       // OC0为0则使引脚输出低电平,为1则引脚不输出

#define BIT_OC1_L_DAT     0x02       // OC1为0则使引脚输出低电平,为1则引脚不输出

#define BIT_OC2_L_DAT     0x04       // OC2为0则使引脚输出低电平,为1则引脚不输出

#define BIT_OC3_L_DAT     0x08       // OC3为0则使引脚输出低电平,为1则引脚不输出

#define BIT_OC4_L_DAT     0x10       // OC4为0则使引脚输出低电平,为1则引脚不输出

#define BIT_OC5_L_DAT     0x20       // OC5为0则使引脚输出低电平,为1则引脚不输出

#define BIT_OC6_L_DAT     0x40       // OC6为0则使引脚输出低电平,为1则引脚不输出

#define BIT_OC7_L_DAT     0x80       // OC7为0则使引脚输出低电平,为1则引脚不输出


/*  设置高8位开漏输出命令 */

#define CH423_H_CMD    0x0600      // 设置低8位推挽输出命令,默认方式

#define CH423_OC_H_CMD    0x4600      // 设置低8位开漏输出命令,默认方式

#define BIT_OC8_L_DAT     0x01        // OC8为0则使引脚输出低电平,为1则引脚不输出

#define BIT_OC9_L_DAT     0x02        // OC9为0则使引脚输出低电平,为1则引脚不输出

#define BIT_OC10_L_DAT    0x04        // OC10为0则使引脚输出低电平,为1则引脚不输出

#define BIT_OC11_L_DAT    0x08        // OC11为0则使引脚输出低电平,为1则引脚不输出

#define BIT_OC12_L_DAT    0x10        // OC12为0则使引脚输出低电平,为1则引脚不输出

#define BIT_OC13_L_DAT    0x20        // OC13为0则使引脚输出低电平,为1则引脚不输出

#define BIT_OC14_L_DAT    0x40        // OC14为0则使引脚输出低电平,为1则引脚不输出

#define BIT_OC15_L_DAT    0x80        // OC15为0则使引脚输出低电平,为1则引脚不输出


/* 设置双向输入输出命令 */


#define CH423_SET_IO_CMD   0x6000    // 设置双向输入输出命令,默认方式

#define BIT_IO0_DAT        0x01      // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO0为0输出低电平,为1输出高电平

#define BIT_IO1_DAT        0x02      // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO1为0输出低电平,为1输出高电平

#define BIT_IO2_DAT        0x04      // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO2为0输出低电平,为1输出高电平

#define BIT_IO3_DAT        0x08      // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO3为0输出低电平,为1输出高电平

#define BIT_IO4_DAT        0x10      // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO4为0输出低电平,为1输出高电平

#define BIT_IO5_DAT        0x20      // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO5为0输出低电平,为1输出高电平

#define BIT_IO6_DAT        0x40      // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO6为0输出低电平,为1输出高电平

#define BIT_IO7_DAT        0x80      // 写入双向输入输出引脚的输出寄存器,当IO_OE=1,IO7为0输出低电平,为1输出高电平


/* 读取双向输入输出命令 */


#define CH423_RD_IO_CMD   0x4D  // 输入I/O引脚当前状态


// 对外子程序

extern void CH423_WriteByte( unsigned short cmd );   // 写出数据

extern unsigned char CH423_ReadByte( void );    // 读取数据


// 特定用途子程序

extern void CH423_Write( unsigned short cmd );    // 向CH423发出操作命令,该子程序与CH423_WriteByte不同,区别主要是前者先将命令码高8位移位

// 下述定义仅适用于CH423_Write子程序,这样定义是为了兼容I2C数据,如果不考虑兼容,那么高8位应该先左移1位

#define CH423_DIG0      0x1000              // 数码管位0显示

#define CH423_DIG1      0x1100              // 数码管位1显示

#define CH423_DIG2      0x1200              // 数码管位2显示

#define CH423_DIG3      0x1300              // 数码管位3显示

#define CH423_DIG4      0x1400              // 数码管位4显示

#define CH423_DIG5      0x1500              // 数码管位5显示

#define CH423_DIG6      0x1600              // 数码管位6显示

#define CH423_DIG7      0x1700              // 数码管位7显示

#define CH423_DIG8      0x1800              // 数码管位8显示

#define CH423_DIG9      0x1900              // 数码管位9显示

#define CH423_DIG10     0x1A00              // 数码管位10显示

#define CH423_DIG11     0x1B00              // 数码管位11显示

#define CH423_DIG12     0x1C00              // 数码管位12显示

#define CH423_DIG13     0x1D00              // 数码管位13显示   

#define CH423_DIG14     0x1E00              // 数码管位14显示   

#define CH423_DIG15     0x1F00              // 数码管位15显示


#endif



void CH423_I2c_Start( void )    // 操作起始

{

    CH423_SDA_SET;    // 发送起始条件的数据信号

    CH423_SDA_D_OUT;    // 设置SDA为输出方向

    CH423_SCL_SET;

    CH423_SCL_D_OUT;    // 设置SCL为输出方向

    DELAY_0_1US;

    CH423_SDA_CLR;    //发送起始信号

    DELAY_0_1US;     

    CH423_SCL_CLR;    //钳住I2C总线,准备发送或接收数据

}


void CH423_I2c_Stop( void )    // 操作结束

{

    CH423_SDA_CLR;

    DELAY_0_1US;

    CH423_SCL_SET;

    DELAY_0_1US;

    CH423_SDA_SET;    // 发送I2C总线结束信号

    DELAY_0_1US;

}


void CH423_I2c_WrByte( unsigned char dat )    // 写一个字节数据

{

    unsigned char i;

    for( i = 0; i != 8; i++ )    // 输出8位数据

    {

        if( dat&0x80 ) { CH423_SDA_SET; }

        else { CH423_SDA_CLR; }

        DELAY_0_1US;

        CH423_SCL_SET;

        dat<<=1;

        DELAY_0_1US;    // 可选延时

        CH423_SCL_CLR;

    }

    CH423_SDA_SET;

    DELAY_0_1US;

    CH423_SCL_SET;    // 接收应答

    DELAY_0_1US;

    CH423_SCL_CLR;

}


unsigned char CH423_I2c_RdByte( void )    // 读一个字节数据

{

    unsigned char dat,i;

    CH423_SDA_SET;

    CH423_SDA_D_IN;    // 设置SDA为输入方向

    dat=0;

    for( i = 0; i != 8; i++ )    // 输入8位数据

    {

        DELAY_0_1US;    // 可选延时

        CH423_SCL_SET;

        DELAY_0_1US;    // 可选延时

        dat<<=1;

        if(digitalRead(CH423_SDA)==HIGH)

        {

          dat++;    // 输入1位

        }

        CH423_SCL_CLR;

    }

    CH423_SDA_SET;

    DELAY_0_1US;

    CH423_SCL_SET;    // 发出无效应答

    DELAY_0_1US;

    CH423_SCL_CLR;

    return(dat);

}


void CH423_Write( unsigned short cmd )    // 写命令

{

    CH423_I2c_Start();    // 启动总线

    CH423_I2c_WrByte( ( ( unsigned char )( cmd>>7 ) & CH423_I2C_MASK ) | CH423_I2C_ADDR1 );

    CH423_I2c_WrByte( ( unsigned char ) cmd );    // 发送数据

    CH423_I2c_Stop();    // 结束总线

}


void CH423_WriteByte( unsigned short cmd )    // 写出数据

{

    CH423_I2c_Start();    // 启动总线

    CH423_I2c_WrByte( ( unsigned char )( cmd>>8 ) );

    CH423_I2c_WrByte( ( unsigned char ) cmd );    // 发送数据

    CH423_I2c_Stop();    // 结束总线 

}


unsigned char CH423_ReadByte()    // 读取数据

{

    unsigned char din;

    CH423_I2c_Start();    // 启动总线

    CH423_I2c_WrByte( CH423_RD_IO_CMD );    // 此值为0x4D

    din=CH423_I2c_RdByte();    // 读取数据

    CH423_I2c_Stop();    // 结束总线

    return( din );

}


void Test()

{

  CH423_WriteByte(CH423_SYS_CMD | BIT_IO_OE );//默认模式

  CH423_WriteByte(CH423_SET_IO_CMD | BIT_IO1_DAT);//IO1输出

  CH423_WriteByte(CH423_OC_L_CMD | BIT_OC0_L_DAT );//OC0输出

  delay(1300);


  CH423_WriteByte(CH423_SET_IO_CMD );//清空输出

  CH423_WriteByte(CH423_OC_L_CMD );//清空输出

  delay(1300);


}



如果要使用,那么只需要修改这几个地方,首先是通讯的两线的引脚





/* 2线接口的连接,与实际电路有关 */

unsigned int CH423_SCL = 5;

unsigned int CH423_SDA = 6;

然后就可以使用了,为了方便测试我配置了一个Test函数,可以让OC0和IO1都输出高电平其他则不输出。

下面以一些例子来说明如何初始化以及控制CH423s的输出

例子1  配置输出

一开始,先配置为默认模式,发送设置系统参数命令,设置双向引脚IO0到IO7为输出模式

CH423_WriteByte(CH423_SYS_CMD | BIT_IO_OE );//默认模式

然后,配置IO1为输出

CH423_WriteByte(CH423_SET_IO_CMD | BIT_IO1_DAT);

这样就可以实现IO1输出高电平。

例子2 配置OC1输出

CH423在上电的时候,OC0到OC15这些引脚默认下被配置为推挽输出

所以只需要

CH423_WriteByte(CH423_OC_L_CMD | BIT_OC1_L_DAT );//OC1输出

就可以让OC1输出高电平,其他低电平

例子3 配置OC14输出

因为有16个输出脚位(加8个双向一共24)所以说需要使用另一个代码来配置OC8到OC15

CH423_WriteByte(CH423_OC_H_CMD | BIT_OC14_L_DAT );//OC14输出

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u012388993/article/details/117388599

智能推荐

文献阅读2_彭于晏程序分晏的博客-程序员宝宝

Efficient Multi-User Computation Offloading for Mobile-Edge Cloud Computing(移动边缘云计算的高效多用户计算分流)摘要移动边缘云计算是一种新范例,可在与移动用户紧邻的普及无线电接入网络的边缘提供云计算功能。在本文中,我们首先研究了在多信道无线干扰环境下移动边缘云计算的多用户计算卸载问题。我们证明计算集中式最优解是NP难的,因此采用了博弈论的方法来以分布式方式实现有效的计算卸载。我们将移动设备用户之间的分布式计算卸载决策问题公式化为

通过addEventListener 绑定的事件会出现多次调用方法的情况_tang_jian_dong的博客-程序员宝宝_addeventlistener message

这会出现两次window.addEventListener("message", function( event ) { alert(event.data)});改为这种, 只会出现一次window.onmessage=function(event){ alert(event.data)}...

RK3399驱动开发 | 01 -RK3399 gpio的使用(用户态和设备树两种方式)_Mculover666的博客-程序员宝宝_rk3399驱动开发

一、RK3399的GPIORK3399有5组GPIO,GPIO0-GPIO4,每一组GPIO成为一个GPIO bank,每组GPIO包含32个引脚,需要注意,不是所有 bank 都有全部编号,例如 GPIO4 就只有 C0-C7,D0-D2,所以一共有122个可用GPIO二、计算GPIO编号Friendly的开发板上板载一个状态LED,如下:该LED接在GPIO0_B5上,想要使用这个GPIO,需要手动计算GPIO引脚编号。GPIO计算公式为:pin=bank∗32+group∗8+xp

CSS3练习笔记_谈晓鸣的博客-程序员宝宝_css 边框动画

CSS3被划分为模块,其中最重要的CSS3模块包括:选择器框模型背景和边框文本效果2D/3D转换动画多列布局用户界面1、边框border-image:设置所有border-image-*属性的简写形式。可能的值有:border-image-source:用在边框的图片的路径;border-image-slice:图片边框向内偏移;border-image-width:图片边框的宽度;border-image-outset:边框图像区域超出边框的量;border-image-repe

XML中的转义字符_土豆吞噬者的博客-程序员宝宝_xml转义字符

XML中不允许出现一些特殊字符,这些字符需要使用转义字符代替显示结果描述转义字符十进制&amp;nbsp;空格&amp;amp;nbsp;&amp;amp;#160;&amp;lt;小于号&amp;amp;lt;&amp;amp;#60;&amp;gt;大于号&amp;amp;gt;&amp;amp;#62;&amp;amp;与号&amp;amp;amp;&amp;amp;#38;&quot;双引号&amp;amp;quot;&

php脚本是啥意思,php脚本是什么意思_火石创造的博客-程序员宝宝

脚本英文为Script,是一种批处理文件的延伸,是一种纯文本保存的程序,一般来说的计算机脚本程序是确定的一系列控制计算机进行运算操作动作的组合,在其中可以实现一定的逻辑分支等。实际上脚本就是程序,一般都是有应用程序提供的编程语言。应用程序包括浏览器(javascript、VBScript)、多媒体创作工具,应用程序的宏和创作系统的批处理语言也可以归入脚本之类。(推荐学习:PHP编程从入门到精通)脚...

随便推点

取球游戏——第三届蓝桥杯省赛C语言A组第10题_FlyingPiggy-MissW的博客-程序员宝宝

今盒子里有n个小球,A、B两人轮流从盒中取球,每个人都可以看到另一个人取了多少个,也可以看到盒中还剩下多少个,并且两人都很聪明,不会做出错误的判断。每个人从盒子中取出的球的数目必须是:1,3,7或者8个。轮到某一方取球时不能弃权!A先取球,然后双方交替取球,直到取完。被迫拿到最后一个球的一方为负方(输方)请编程确定出在双方都不判断失误的情况下,对于特定的初始球数

Qt QML 基于平行四边形的进度条(Matrix4x4、drag)_火山上的企鹅的博客-程序员宝宝_qml 进度条

先上gif图思路:先实现平行四边形: 通过 Rectangle 的矩阵变化来实现 (transform: Matrix4x4):Rectangle { id: rect anchors.fill: parent color: "lightblue" // 切变矩阵 transform: Matrix4x4 { matrix: Qt.matrix4x4(1, xs, 0, 0, // xs平方向切变 +表示朝右

iPad3/iPad2/iPad 5.1.1完美越狱WIN版详细教程_artwebs的博客-程序员宝宝

Absinthe 2.0.4 更新 最新更新:5月30日,iOS 5.1.1完美越狱工具Absinthe 2.0.4再次更新!完美支持iPad2,4 iOS 5.1.1Absinthe 2.0.4(Win版下载地址    mac版下载地址    Linux版下载地址)已经越狱的不需要再重新越狱,这次更新最主要增加了对遗留的 iPad 2,4的支持。到现在为止还未成功

什么是ForkJoin、ForkJoin分支合并、ForkJoin工作窃取、ForkJoin大数据求和计算_郝开的博客-程序员宝宝

什么是ForkJoin、ForkJoin分支合并、ForkJoin工作窃取、ForkJoin大数据求和计算什么是ForkJoin?ForkJoin:分支合并ForkJoin特点:工作窃取如何让使用ForkJoinForkJoin求和计算Demo什么是ForkJoin?ForkJoin(分支合并)是jdk1.7之后出来的,并行执行任务,提高效率,用在大数据量场景下。大数据:Map Reduce(把大任务拆分成多个小任务,怎么拆分用到了二分算法),每个小任务得出自己的结果,之后再把结果汇总,汇总的过程就是

数据结构与算法之线性表基础——顺序表(C与C++双人打)_源代码•宸的博客-程序员宝宝

人狠话不多,干货先上咯先来个简单的线性表基本构造代码以及响应的运行测试程序seq.h#include&lt;stdio.h&gt;#include&lt;string.h&gt;#define MAXSIZE 100 //定义线性表的最大长度typedef struct{ char key[15]; //结点的关键字 char name[20]; int age;}DATA; //定义结点类型,可定义为简单类型,也可定义为结构typedef struct

Pandas作业练习_weixin_42331532的博客-程序员宝宝

```pythonimport pandas as pdimport numpy as np#读数据lianjia_df = pd.read_csv(r'lianjia9.csv')#print(lianjia_df)# 1. 观察结构,调整列索引顺序#如何调整呢?,就是查找所有数据,将排好序的标签填进去,达到各列换位的一种效果print(lianjia_df[["Region","Garden","Layout","Floor","Year","Size","Elevator","Di.