缥缈九哥 发表于 2023-9-19 09:11

基于华芯微特SWM181CBT6的XL9555的IIC扩展IO驱动源码

//有个项目IO口不够用,又不想换大的CPU,只好用了个QFN24的小芯片通过模拟 IIC来扩展IO口。

/********************************************************************************/
/* @file        xl9555.c                                                                                                                        */
/* @version        V1.00                                                                                                                                */
/* $author:        yuanxihua@21cn.com                                                                                                        */
/* $Date:         2023/09/13 01:54 $                                                                                                         */
/* @brief         SWM181CBT6 Series XL9555 Driver Sample Code                                                        */
/*                                                                                                                                                                */
/* @note                                                                                                                                                */
/* Copyright (C) 2010-2023 PM9GZY Technology Corp. All rights reserved.                        */
/*                                                                                                                                                                */
/********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/*
_________________________________________________
|        SWM181CBT6                                                XL9555                |
|                                                                                                |
|        PB2                SCL                 ---->                SCL                        |
|        PB1                SDA                 <--->                SDA                        |
|        PE4                INT                        <---                 INT                        |
|_______________________________________________|
*/
#include <stdint.h>
/* Private typedef -----------------------------------------------------------*/
#define I2C_Delay                              10                         /* us */
#define I2C_SCL                            GPIOB, PIN2
#define I2C_SDA                            GPIOB, PIN1
#define I2C_INT                            GPIOE, PIN4

/* Private define ------------------------------------------------------------*/
#define XL9555_SLAVEADDR                         0x42                         /* Clock i2c slave address */
/* Private macro -------------------------------------------------------------*/
#define XL9555_INPUT_PORT0                                0x00
#define XL9555_INPUT_PORT1                                0x01
#define XL9555_OUTPUT_PORT0                                0x02
#define XL9555_OUTPUT_PORT1                                0x03
#define XL9555_POLARITY_PORT0                        0x04
#define XL9555_POLARITY_PORT1                        0x05
#define XL9555_CONFIGURATION_PORT0                0x06
#define XL9555_CONFIGURATION_PORT1                0x07
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/
void XL9555_Init(void)
{
        GPIO_Init(I2C_INT, 0, 1, 0, 0);                //GPIOE.4 配置为输入引脚,开启上拉 INT
        GPIO_Init(I2C_SDA, 1, 0, 0, 0);                //GPIOB.1 配置为输出引脚,推挽输出 SDA
        GPIO_Init(I2C_SCL, 1, 0, 0, 0);                //GPIOB.2 配置为输出引脚,推挽输出 SCL
        GPIO_SetBit(I2C_SCL);                                //SCL 高
        GPIO_SetBit(I2C_SDA);                                //SDA 高
}
void XL9555_Pluse(void)
{
        GPIO_SetBit(I2C_SCL);                                //SCL 高
        delay_us(I2C_Delay);
        GPIO_ClrBit(I2C_SCL);                                //SCL 低
        delay_us(I2C_Delay);
}
void XL9555_Start(void)
{
        XL9555_Init();
        delay_us(I2C_Delay);
        GPIO_Init(I2C_SDA, 1, 0, 0, 0);                //I2C_SDA 配置为输出引脚,推挽输出 SDA
        GPIO_ClrBit(I2C_SDA);                                //SDA 低
        delay_us(I2C_Delay);
        GPIO_ClrBit(I2C_SCL);                                //SCL 低
        delay_us(I2C_Delay);
}
void XL9555_ACK(uint8_t ack)
{
        GPIO_Init(I2C_SDA, 1, 0, 0, 0);                //I2C_SDA 配置为输出引脚,推挽输出 SDA
        if(ack)        {GPIO_SetBit(I2C_SDA);}                //SDA 高 NAK
        else        {GPIO_ClrBit(I2C_SDA);}                //SDA 低 ACK
        delay_us(I2C_Delay);
        XL9555_Pluse();                                                //发送ACK
        GPIO_SetBit(I2C_SDA);                                //SDA 高         /* CPU释放SDA总线 */
}
uint8_t XL9555_WACK(void)
{
        GPIO_Init(I2C_SDA, 0, 1, 0, 0);                //I2C_SDA 配置为输入引脚,开启上拉 SDA
        delay_us(I2C_Delay);
        uint8_t ack=GPIO_GetBit(I2C_SDA);        //接收ACK
        XL9555_Pluse();                       
        return ack;
}
void XL9555_Stop(void)
{
        GPIO_Init(I2C_SDA, 1, 0, 0, 0);                //I2C_SDA 配置为输出引脚,推挽输出 SDA
        GPIO_ClrBit(I2C_SDA);                                //SDA 低
        delay_us(I2C_Delay);
        GPIO_SetBit(I2C_SCL);                                //SCL 高
        delay_us(I2C_Delay);
        GPIO_SetBit(I2C_SDA);                                //SDA 高
}
void XL9555_Send_Byte(uint8_t data,uint8_t ack)
{
        GPIO_Init(I2C_SDA, 1, 0, 0, 0);                //I2C_SDA 配置为输出引脚,推挽输出 SDA
        for(int i=0;i<8;i++)                                //发送DATA
        {
                if(data&0x80){GPIO_SetBit(I2C_SDA);}
                else{GPIO_ClrBit(I2C_SDA);}
                data<<=1;XL9555_Pluse();
        }
        if(XL9555_WACK()!=ack){XL9555_Stop();}        //等待ACK应答
}
uint16_t XL9555_Read_Byte(uint8_t ack)
{
        uint16_t data=0;
        GPIO_Init(I2C_SDA, 0, 1, 0, 0);                //I2C_SDA 配置为输入引脚,开启上拉 SDA
        for(int i=0;i<8;i++)                                //接收DATA
        {
                data<<=1;
                if(GPIO_GetBit(I2C_SDA)){data+=1;}else{;}
                XL9555_Pluse();
        }
        XL9555_ACK(ack);                //发送ACK或者NAK
        return data;
}

uint8_t XL9555_Write_buf(uint8_t addr,uint8_t reg,uint8_t *buf,uint8_t len)
{
        XL9555_Init();
    XL9555_Start();
    XL9555_Send_Byte(addr|0,0);                                 //发送器件地址+写命令+ACK
    XL9555_Send_Byte(reg,0);                                 //写寄存器地址+ACK
        while(len--){XL9555_Send_Byte(*buf++,0);}        //发送数据+ACK
    XL9555_Stop();
    return 0;
}
uint8_t XL9555_Read_buf(uint8_t addr,uint8_t reg,uint8_t *buf,uint8_t len)
{
        XL9555_Init();
    XL9555_Start();
    XL9555_Send_Byte(addr|0,0);                 //发送器件地址+写命令+ACK
    XL9555_Send_Byte(reg,0);                 //写寄存器地址+ACK
        XL9555_Start();               
    XL9555_Send_Byte(addr|1,0);                 //发送器件地址+读命令+ACK
    while(len--)
    {
      if(len==1)        {*buf++=XL9555_Read_Byte(1);}        //读数据+发送NAK
                else                 {*buf++=XL9555_Read_Byte(0);}        //读数据+发送ACK
    }
    XL9555_Stop();                               //产生一个停止条件
    return 0;      
}
void XL9555_Configuration(uint16_t val)
{
    XL9555_Write_buf(XL9555_SLAVEADDR, XL9555_CONFIGURATION_PORT0,(uint8_t *)&val,2);
}

void XL9555_OutPut(uint16_t val)
{
        XL9555_Configuration(0x0000);
        XL9555_Write_buf(XL9555_SLAVEADDR, XL9555_OUTPUT_PORT0,(uint8_t *)&val,2);
}

uint16_t XL9555_InPut(void)
{
        uint16_t val;
        XL9555_Configuration(0xffff);
        XL9555_Write_buf(XL9555_SLAVEADDR, XL9555_OUTPUT_PORT0,(uint8_t *)&val,2);
        return val;
}
uint16_t XL9555_InOutPut(uint16_t set,uint16_t val)
{
        XL9555_Configuration(set);
        uint8_t *buf=( uint8_t *)&val;
        XL9555_Write_buf(XL9555_SLAVEADDR, XL9555_OUTPUT_PORT0,buf,2);
        delay_us(1000);
        XL9555_Read_buf (XL9555_SLAVEADDR, XL9555_INPUT_PORT0 ,buf,2);
        return val;
}

void XL9555_Test(void)
{
        uint8_t buf;
        XL9555_Read_buf(XL9555_SLAVEADDR,0,buf,sizeof(buf));
        for(int i=0;i<sizeof(buf);i++){printf("0x%02x ",buf);}
}

//代码完毕

hotpower 发表于 2023-9-19 09:27

不错~~~

ayb_ice 发表于 2023-9-20 08:59

GPIO不需要多次初始化

缥缈九哥 发表于 2024-3-31 22:06

ayb_ice 发表于 2023-9-20 08:59
GPIO不需要多次初始化

为了切换IO的输出 输出 方向。

mervyn807 发表于 2024-4-27 18:18

换到其他MCU是不是也可以这样做,读写是一样的流程?
页: [1]
查看完整版本: 基于华芯微特SWM181CBT6的XL9555的IIC扩展IO驱动源码