NCA9555/PCA9555代码 通用总线IO扩展器芯片驱动

芯片引脚及描述:
在这里插入图片描述
在这里插入图片描述
驱动代码:
头文件:nca9555.h


/*
 * nca9555.h
 *
 *  Created on: 2021年11月11日
 *      Author: lhsmd
 */

#ifndef USER_APP_NCA9555_H_
#define USER_APP_NCA9555_H_

#include "em_gpio.h"


/***************************************************IIC 驱动部门**********************************************************/
#define IIC_SCL_GPIO_PORT  gpioPortB
#define IIC_SCL_GPIO_PIN    1

#define IIC_SDA_GPIO_PORT   gpioPortB
#define IIC_SDA_GPIO_PIN    2

#define IIC_SCL_SET_GPIO_OUTPUT_STATUS(status)      if(status == 1)   GPIO_PinOutSet(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN);\
                                                    else if(status == 0)  GPIO_PinOutClear(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN);

#define IIC_SDA_SET_GPIO_OUTPUT_STATUS(status)     if(status == 1)   GPIO_PinOutSet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN);\
                                                    else if(status == 0)  GPIO_PinOutClear(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN);

#define IIC_SDA_GET_GPIO_INPUT_STATUS   GPIO_PinInGet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN)


void IIC_gpio_init(void);
void IIC_start(void);
void IIC_stop(void);
uint8_t IIC_wait_ack(void);
void IIC_ack(void);
void IIC_nack(void);
void IIC_send_byte(uint8_t txd);
void IIC_send_byte(uint8_t txd);
uint8_t IIC_read_byte(unsigned char ack);
/***********************************************************IIC 驱动 END**********************************************************************/

/************************************************************NCA9555 驱动***********************************************************/
#define SUCCESS 0
#define ERROR   1

#define SLAVE_ADDR0   0x40
#define SLAVE_ADDR1   0x42
#define SLAVE_ADDR2   0x44

#define HOST_WRITE_COMMAND 0x00
#define HOST_READ_COMMAND  0x01

#define INPUT_PORT_REGISTER0                    0x00   /* 输入端口寄存器0,负责IO00-IO07 */
#define INPUT_PORT_REGISTER1                    0x01   /* 输入端口寄存器1,负责IO10-IO17 */
#define OUTPUT_PORT_REGISTER0                   0x02   /* 输入端口寄存器0,负责IO00-IO07 */
#define OUTPUT_PORT_REGISTER1                   0x03   /* 输入端口寄存器1,负责IO10-IO17 */
#define POLARITY_INVERSION_PORT_REGISTER0       0x04   /* 输入端口寄存器0,负责IO00-IO07 */
#define POLARITY_INVERSION_PORT_REGISTER1       0x05   /* 输入端口寄存器1,负责IO10-IO17 */
#define CONFIG_PORT_REGISTER0                   0x06   /* 输入端口寄存器0,负责IO00-IO07 */
#define CONFIG_PORT_REGISTER1                   0x07   /* 输入端口寄存器1,负责IO10-IO17 */

#define GPIO_PORT0 0
#define GPIO_PORT1 1

#define GPIO_0 0x01
#define GPIO_1 0x02
#define GPIO_2 0x04
#define GPIO_3 0x08
#define GPIO_4 0x10
#define GPIO_5 0x20
#define GPIO_6 0x40
#define GPIO_7 0x80


#define NCA9555_WAIT_IS_RETURN_SUCCESS(flag, tips)    if(flag != SUCCESS)\
                                                        { \
                                                            printf("%s", tips); \
                                                            return ERROR;\
                                                        }

void nca9555_init(void);
void nca9555_read_wtite_test(void);
void nca9555_set_output_mode(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num);
void nca9555_set_gpio_output_status(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num, uint8_t status);
void nca9555_set_input_mode(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num);
uint8_t nca9555_get_gpio_status(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num);
/************************************************************NCA9555 驱动  END***********************************************************/

#endif /* USER_APP_NCA9555_H_ */

源文件:nca9555.c

/*
 * nca9555.c
 *
 *  Created on: 2021年11月11日
 *      Author: lhsmd
 */

#include "nca9555.h"
#include "sl_udelay.h"
#include "em_cmu.h"
#include <stdio.h>
#include "ads1220.h"

void IIC_gpio_init(void)
{
    CMU_ClockEnable(cmuClock_GPIO, true);  /* 使能GPIO时钟 */
    GPIO_PinModeSet(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, gpioModePushPull, 1);
    GPIO_PinModeSet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, gpioModePushPull, 1);
}


static void IIC_SDA_set_output(void)
{
    GPIO_PinModeSet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, gpioModePushPull, 1);
}

static void IIC_SDA_set_input(void)
{
    GPIO_PinModeSet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, gpioModeInputPull, 0);
}


//产生IIC起始信号
void IIC_start(void)
{
    IIC_SDA_set_output(); //sda线输出
    IIC_SDA_SET_GPIO_OUTPUT_STATUS(1);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(1);
    sl_udelay_wait(6);
    IIC_SDA_SET_GPIO_OUTPUT_STATUS(0);//START:when CLK is high,DATA change form high to low
    sl_udelay_wait(6);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);//钳住I2C总线,准备发送或接收数据
}

//产生IIC停止信号
void IIC_stop(void)
{
    IIC_SDA_set_output();//sda线输出
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);
    IIC_SDA_SET_GPIO_OUTPUT_STATUS(0);//STOP:when CLK is high DATA change form low to high
    sl_udelay_wait(6);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(1);
    IIC_SDA_SET_GPIO_OUTPUT_STATUS(1);//发送I2C总线结束信号
    sl_udelay_wait(6);
}

//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
uint8_t IIC_wait_ack(void)
{
    uint8_t ucErrTime=0;
    IIC_SDA_set_input();  //SDA设置为输入
    IIC_SDA_SET_GPIO_OUTPUT_STATUS(1);
    sl_udelay_wait(1);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(1);
    sl_udelay_wait(1);

    while(IIC_SDA_GET_GPIO_INPUT_STATUS)
    {
        ucErrTime++;
        sl_udelay_wait(1);
        if(ucErrTime>250)
        {
            IIC_stop();
            printf("return 1\r\n");
            return 1;
        }
    }
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);//时钟输出0
    return 0;
}

//产生ACK应答
 void IIC_ack(void)
{
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);
    IIC_SDA_set_output();
    IIC_SDA_SET_GPIO_OUTPUT_STATUS(1);
    sl_udelay_wait(5);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(1);
    sl_udelay_wait(5);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);
}

//不产生ACK应答
void IIC_nack(void)
{
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);
    IIC_SDA_set_output();
    IIC_SDA_SET_GPIO_OUTPUT_STATUS(1);
    sl_udelay_wait(5);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(1);
    sl_udelay_wait(5);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);
}

//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_send_byte(uint8_t txd)
{
    uint8_t t;
    IIC_SDA_set_output();
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {
        //printf("\r\n1 GPIO_PinInGet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN) = %d\r\n",  GPIO_PinInGet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN));
        IIC_SDA_SET_GPIO_OUTPUT_STATUS((txd&0x80)>>7);
        txd<<=1;
        sl_udelay_wait(4);
        IIC_SCL_SET_GPIO_OUTPUT_STATUS(1);
        sl_udelay_wait(4);
        IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);
        sl_udelay_wait(4);
    }
}

//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
uint8_t IIC_read_byte(unsigned char ack)
{
    unsigned char i,receive=0;
    IIC_SDA_set_input();//SDA设置为输入
    for(i=0;i<8;i++ )
    {
        IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);
        sl_udelay_wait(4);
        IIC_SCL_SET_GPIO_OUTPUT_STATUS(1);
        receive<<=1;
        if(IIC_SDA_GET_GPIO_INPUT_STATUS)receive++;
        //printf("\r\n2 GPIO_PinInGet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN) = %d\r\n",  GPIO_PinInGet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN));
        sl_udelay_wait(4);
    }
    if (!ack)
        IIC_nack();//发送nACK
    else
        IIC_ack(); //发送ACK
    return receive;
}



void nca9555_init(void)
{
    IIC_gpio_init();
}



uint8_t nca9555_write_byte(uint8_t addr, uint8_t command, uint8_t write_register_data)
{
    uint8_t ret = 1;
    IIC_start();
    IIC_send_byte(addr);
    ret =  IIC_wait_ack();
    NCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n");

    IIC_send_byte(command);
    ret =  IIC_wait_ack();
    NCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n");

    IIC_send_byte(write_register_data);
    ret =  IIC_wait_ack();
    NCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n");

    IIC_stop();
    sl_udelay_wait(10000);
    return SUCCESS;
}

/*
 * nca9555读取寄存器值
 *
 * addr 读取地址
 * read_register_data 要读取的寄存器
 * read_data 读取数据存放地址
 *
 *
 * 返回值:读取成功返回SUCCESS  失败返回ERROR
 *
 * */
uint8_t nca9555_read_byte(uint8_t slave_num, uint8_t addr, uint8_t read_register_data, uint8_t *read_data)
{
    uint8_t ret = 0;
    IIC_start();
    IIC_send_byte(slave_num);
    ret =  IIC_wait_ack();
    NCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n");

    IIC_send_byte(read_register_data);
    ret = IIC_wait_ack();
    NCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n");

    IIC_start(); /* 开始接收数据 */
    IIC_send_byte(addr);
    ret = IIC_wait_ack();
    NCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n");

    *read_data = IIC_read_byte(0);

    IIC_stop();
    return SUCCESS;
}


/*
 * 设置指定GPIO的模式
 *
 * slave_num  需要操作的从机设备
 * gpio_port  gpio端口  端口0/1
 * gpio_num   哪一个GPIO
 *
 * 返回值:void
 * */
void nca9555_set_output_mode(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num)
{
    uint8_t register_original_data = 0;
    if(gpio_port > 1 || gpio_num > 0x80)  return;
    if(gpio_port == 0)
    {
        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, CONFIG_PORT_REGISTER0, &register_original_data);
        nca9555_write_byte(slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER0, register_original_data & (~gpio_num));
    }
    else if(gpio_port == 1)
    {
        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, CONFIG_PORT_REGISTER1, &register_original_data);
        nca9555_write_byte( slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER1, register_original_data & (~gpio_num));
    }
}

/*
 * 设置GPIO为输入模式
 *
 * slave_num  需要操作的从机设备
 * gpio_port  gpio端口  端口0/1
 * gpio_num   哪一个GPIO
 *
 * 返回值:void
 **/
void nca9555_set_input_mode(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num)
{
    uint8_t register_original_data = 0;
    if(gpio_port > 1 || gpio_num > 0x80)  return;
    if(gpio_port == 0)
    {
        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, CONFIG_PORT_REGISTER0, &register_original_data);
        nca9555_write_byte(slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER0, register_original_data & gpio_num);
    }
    else if(gpio_port == 1)
    {

        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, CONFIG_PORT_REGISTER1, &register_original_data);

        nca9555_write_byte(slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER1, register_original_data & gpio_num);
    }
}

/*
 * 设置GPIO输出状态
 *
 * slave_num  需要操作的从机设备
 * gpio_port  gpio端口  端口0/1
 * gpio_num   哪一个GPIO
 * status     输出状态
 *
 * 返回值:void
 **/
void nca9555_set_gpio_output_status(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num, uint8_t status)
{
    uint8_t register_original_data = 0;
    if(gpio_port > 1 || gpio_num > 0x80)  return;
    if(gpio_port == 0)
    {
        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, OUTPUT_PORT_REGISTER0, &register_original_data);
        if(status == 1)
        {
            nca9555_write_byte(slave_num | HOST_WRITE_COMMAND, OUTPUT_PORT_REGISTER0, register_original_data | gpio_num);
        }
        else
        {
            nca9555_write_byte(slave_num | HOST_WRITE_COMMAND, OUTPUT_PORT_REGISTER0, register_original_data & (~gpio_num));
        }
    }
    else if(gpio_port == 1)
    {
        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, OUTPUT_PORT_REGISTER1, &register_original_data);
        if(status == 1)
        {
            nca9555_write_byte(slave_num | HOST_WRITE_COMMAND, OUTPUT_PORT_REGISTER1, register_original_data | gpio_num);
        }
        else
        {
            nca9555_write_byte(slave_num | HOST_WRITE_COMMAND, OUTPUT_PORT_REGISTER1, register_original_data & (~gpio_num));
        }
    }
}

/*
 * 获取GPIO状态
 *
 * slave_num  需要操作的从机设备
 * gpio_port  gpio端口  端口0/1
 * gpio_num   哪一个GPIO
 *
 * 返回值:GPIO状态
 **/
uint8_t nca9555_get_gpio_status(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num)
{
    uint8_t register_original_data = 0;
    uint8_t gpio_status = 0;
    if(gpio_port > 1 || gpio_num > 0x80)
    {
        printf("[ERROR] gpio_port > 1 || gpio_num > 0x80\r\n");
        return 2;
    }
    if(gpio_port == 0)
    {

        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, INPUT_PORT_REGISTER0, &register_original_data);

    }
    else if(gpio_port == 1)
    {
        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, INPUT_PORT_REGISTER1, &register_original_data);
    }
    switch(gpio_num)
    {
        case 0x01:  gpio_status = register_original_data & gpio_num;break;
        case 0x02:  gpio_status = (register_original_data & gpio_num) >> 1;break;
        case 0x04:  gpio_status = (register_original_data & gpio_num) >> 2;break;
        case 0x08:  gpio_status = (register_original_data & gpio_num) >> 3;break;
        case 0x10:  gpio_status = (register_original_data & gpio_num) >> 4;break;
        case 0x20:  gpio_status = (register_original_data & gpio_num) >> 5;break;
        case 0x40:  gpio_status = (register_original_data & gpio_num) >> 6;break;
        case 0x80:  gpio_status = (register_original_data & gpio_num) >> 7;break;
        default:  printf("[ERROR] gpio error!\r\n");
    }
    return gpio_status;
}

注:
NCA9555采用IIC通信,协议中涉及的延时函数务必保证精确。
上面代码可直接运行在芯科科技的EFR32BG22中。需要移植到其他的芯片中只需要确定两点:
①GPIO输入输出设置
②精确到us级别的延时函数
将对应的的部分替换掉就可以了。

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

芯片引脚及描述:
在这里插入图片描述
在这里插入图片描述
驱动代码:
头文件:nca9555.h


/*
 * nca9555.h
 *
 *  Created on: 2021年11月11日
 *      Author: lhsmd
 */

#ifndef USER_APP_NCA9555_H_
#define USER_APP_NCA9555_H_

#include "em_gpio.h"


/***************************************************IIC 驱动部门**********************************************************/
#define IIC_SCL_GPIO_PORT  gpioPortB
#define IIC_SCL_GPIO_PIN    1

#define IIC_SDA_GPIO_PORT   gpioPortB
#define IIC_SDA_GPIO_PIN    2

#define IIC_SCL_SET_GPIO_OUTPUT_STATUS(status)      if(status == 1)   GPIO_PinOutSet(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN);\
                                                    else if(status == 0)  GPIO_PinOutClear(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN);

#define IIC_SDA_SET_GPIO_OUTPUT_STATUS(status)     if(status == 1)   GPIO_PinOutSet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN);\
                                                    else if(status == 0)  GPIO_PinOutClear(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN);

#define IIC_SDA_GET_GPIO_INPUT_STATUS   GPIO_PinInGet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN)


void IIC_gpio_init(void);
void IIC_start(void);
void IIC_stop(void);
uint8_t IIC_wait_ack(void);
void IIC_ack(void);
void IIC_nack(void);
void IIC_send_byte(uint8_t txd);
void IIC_send_byte(uint8_t txd);
uint8_t IIC_read_byte(unsigned char ack);
/***********************************************************IIC 驱动 END**********************************************************************/

/************************************************************NCA9555 驱动***********************************************************/
#define SUCCESS 0
#define ERROR   1

#define SLAVE_ADDR0   0x40
#define SLAVE_ADDR1   0x42
#define SLAVE_ADDR2   0x44

#define HOST_WRITE_COMMAND 0x00
#define HOST_READ_COMMAND  0x01

#define INPUT_PORT_REGISTER0                    0x00   /* 输入端口寄存器0,负责IO00-IO07 */
#define INPUT_PORT_REGISTER1                    0x01   /* 输入端口寄存器1,负责IO10-IO17 */
#define OUTPUT_PORT_REGISTER0                   0x02   /* 输入端口寄存器0,负责IO00-IO07 */
#define OUTPUT_PORT_REGISTER1                   0x03   /* 输入端口寄存器1,负责IO10-IO17 */
#define POLARITY_INVERSION_PORT_REGISTER0       0x04   /* 输入端口寄存器0,负责IO00-IO07 */
#define POLARITY_INVERSION_PORT_REGISTER1       0x05   /* 输入端口寄存器1,负责IO10-IO17 */
#define CONFIG_PORT_REGISTER0                   0x06   /* 输入端口寄存器0,负责IO00-IO07 */
#define CONFIG_PORT_REGISTER1                   0x07   /* 输入端口寄存器1,负责IO10-IO17 */

#define GPIO_PORT0 0
#define GPIO_PORT1 1

#define GPIO_0 0x01
#define GPIO_1 0x02
#define GPIO_2 0x04
#define GPIO_3 0x08
#define GPIO_4 0x10
#define GPIO_5 0x20
#define GPIO_6 0x40
#define GPIO_7 0x80


#define NCA9555_WAIT_IS_RETURN_SUCCESS(flag, tips)    if(flag != SUCCESS)\
                                                        { \
                                                            printf("%s", tips); \
                                                            return ERROR;\
                                                        }

void nca9555_init(void);
void nca9555_read_wtite_test(void);
void nca9555_set_output_mode(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num);
void nca9555_set_gpio_output_status(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num, uint8_t status);
void nca9555_set_input_mode(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num);
uint8_t nca9555_get_gpio_status(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num);
/************************************************************NCA9555 驱动  END***********************************************************/

#endif /* USER_APP_NCA9555_H_ */

源文件:nca9555.c

/*
 * nca9555.c
 *
 *  Created on: 2021年11月11日
 *      Author: lhsmd
 */

#include "nca9555.h"
#include "sl_udelay.h"
#include "em_cmu.h"
#include <stdio.h>
#include "ads1220.h"

void IIC_gpio_init(void)
{
    CMU_ClockEnable(cmuClock_GPIO, true);  /* 使能GPIO时钟 */
    GPIO_PinModeSet(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, gpioModePushPull, 1);
    GPIO_PinModeSet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, gpioModePushPull, 1);
}


static void IIC_SDA_set_output(void)
{
    GPIO_PinModeSet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, gpioModePushPull, 1);
}

static void IIC_SDA_set_input(void)
{
    GPIO_PinModeSet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, gpioModeInputPull, 0);
}


//产生IIC起始信号
void IIC_start(void)
{
    IIC_SDA_set_output(); //sda线输出
    IIC_SDA_SET_GPIO_OUTPUT_STATUS(1);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(1);
    sl_udelay_wait(6);
    IIC_SDA_SET_GPIO_OUTPUT_STATUS(0);//START:when CLK is high,DATA change form high to low
    sl_udelay_wait(6);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);//钳住I2C总线,准备发送或接收数据
}

//产生IIC停止信号
void IIC_stop(void)
{
    IIC_SDA_set_output();//sda线输出
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);
    IIC_SDA_SET_GPIO_OUTPUT_STATUS(0);//STOP:when CLK is high DATA change form low to high
    sl_udelay_wait(6);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(1);
    IIC_SDA_SET_GPIO_OUTPUT_STATUS(1);//发送I2C总线结束信号
    sl_udelay_wait(6);
}

//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
uint8_t IIC_wait_ack(void)
{
    uint8_t ucErrTime=0;
    IIC_SDA_set_input();  //SDA设置为输入
    IIC_SDA_SET_GPIO_OUTPUT_STATUS(1);
    sl_udelay_wait(1);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(1);
    sl_udelay_wait(1);

    while(IIC_SDA_GET_GPIO_INPUT_STATUS)
    {
        ucErrTime++;
        sl_udelay_wait(1);
        if(ucErrTime>250)
        {
            IIC_stop();
            printf("return 1\r\n");
            return 1;
        }
    }
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);//时钟输出0
    return 0;
}

//产生ACK应答
 void IIC_ack(void)
{
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);
    IIC_SDA_set_output();
    IIC_SDA_SET_GPIO_OUTPUT_STATUS(1);
    sl_udelay_wait(5);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(1);
    sl_udelay_wait(5);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);
}

//不产生ACK应答
void IIC_nack(void)
{
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);
    IIC_SDA_set_output();
    IIC_SDA_SET_GPIO_OUTPUT_STATUS(1);
    sl_udelay_wait(5);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(1);
    sl_udelay_wait(5);
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);
}

//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_send_byte(uint8_t txd)
{
    uint8_t t;
    IIC_SDA_set_output();
    IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {
        //printf("\r\n1 GPIO_PinInGet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN) = %d\r\n",  GPIO_PinInGet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN));
        IIC_SDA_SET_GPIO_OUTPUT_STATUS((txd&0x80)>>7);
        txd<<=1;
        sl_udelay_wait(4);
        IIC_SCL_SET_GPIO_OUTPUT_STATUS(1);
        sl_udelay_wait(4);
        IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);
        sl_udelay_wait(4);
    }
}

//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
uint8_t IIC_read_byte(unsigned char ack)
{
    unsigned char i,receive=0;
    IIC_SDA_set_input();//SDA设置为输入
    for(i=0;i<8;i++ )
    {
        IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);
        sl_udelay_wait(4);
        IIC_SCL_SET_GPIO_OUTPUT_STATUS(1);
        receive<<=1;
        if(IIC_SDA_GET_GPIO_INPUT_STATUS)receive++;
        //printf("\r\n2 GPIO_PinInGet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN) = %d\r\n",  GPIO_PinInGet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN));
        sl_udelay_wait(4);
    }
    if (!ack)
        IIC_nack();//发送nACK
    else
        IIC_ack(); //发送ACK
    return receive;
}



void nca9555_init(void)
{
    IIC_gpio_init();
}



uint8_t nca9555_write_byte(uint8_t addr, uint8_t command, uint8_t write_register_data)
{
    uint8_t ret = 1;
    IIC_start();
    IIC_send_byte(addr);
    ret =  IIC_wait_ack();
    NCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n");

    IIC_send_byte(command);
    ret =  IIC_wait_ack();
    NCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n");

    IIC_send_byte(write_register_data);
    ret =  IIC_wait_ack();
    NCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n");

    IIC_stop();
    sl_udelay_wait(10000);
    return SUCCESS;
}

/*
 * nca9555读取寄存器值
 *
 * addr 读取地址
 * read_register_data 要读取的寄存器
 * read_data 读取数据存放地址
 *
 *
 * 返回值:读取成功返回SUCCESS  失败返回ERROR
 *
 * */
uint8_t nca9555_read_byte(uint8_t slave_num, uint8_t addr, uint8_t read_register_data, uint8_t *read_data)
{
    uint8_t ret = 0;
    IIC_start();
    IIC_send_byte(slave_num);
    ret =  IIC_wait_ack();
    NCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n");

    IIC_send_byte(read_register_data);
    ret = IIC_wait_ack();
    NCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n");

    IIC_start(); /* 开始接收数据 */
    IIC_send_byte(addr);
    ret = IIC_wait_ack();
    NCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n");

    *read_data = IIC_read_byte(0);

    IIC_stop();
    return SUCCESS;
}


/*
 * 设置指定GPIO的模式
 *
 * slave_num  需要操作的从机设备
 * gpio_port  gpio端口  端口0/1
 * gpio_num   哪一个GPIO
 *
 * 返回值:void
 * */
void nca9555_set_output_mode(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num)
{
    uint8_t register_original_data = 0;
    if(gpio_port > 1 || gpio_num > 0x80)  return;
    if(gpio_port == 0)
    {
        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, CONFIG_PORT_REGISTER0, &register_original_data);
        nca9555_write_byte(slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER0, register_original_data & (~gpio_num));
    }
    else if(gpio_port == 1)
    {
        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, CONFIG_PORT_REGISTER1, &register_original_data);
        nca9555_write_byte( slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER1, register_original_data & (~gpio_num));
    }
}

/*
 * 设置GPIO为输入模式
 *
 * slave_num  需要操作的从机设备
 * gpio_port  gpio端口  端口0/1
 * gpio_num   哪一个GPIO
 *
 * 返回值:void
 **/
void nca9555_set_input_mode(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num)
{
    uint8_t register_original_data = 0;
    if(gpio_port > 1 || gpio_num > 0x80)  return;
    if(gpio_port == 0)
    {
        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, CONFIG_PORT_REGISTER0, &register_original_data);
        nca9555_write_byte(slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER0, register_original_data & gpio_num);
    }
    else if(gpio_port == 1)
    {

        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, CONFIG_PORT_REGISTER1, &register_original_data);

        nca9555_write_byte(slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER1, register_original_data & gpio_num);
    }
}

/*
 * 设置GPIO输出状态
 *
 * slave_num  需要操作的从机设备
 * gpio_port  gpio端口  端口0/1
 * gpio_num   哪一个GPIO
 * status     输出状态
 *
 * 返回值:void
 **/
void nca9555_set_gpio_output_status(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num, uint8_t status)
{
    uint8_t register_original_data = 0;
    if(gpio_port > 1 || gpio_num > 0x80)  return;
    if(gpio_port == 0)
    {
        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, OUTPUT_PORT_REGISTER0, &register_original_data);
        if(status == 1)
        {
            nca9555_write_byte(slave_num | HOST_WRITE_COMMAND, OUTPUT_PORT_REGISTER0, register_original_data | gpio_num);
        }
        else
        {
            nca9555_write_byte(slave_num | HOST_WRITE_COMMAND, OUTPUT_PORT_REGISTER0, register_original_data & (~gpio_num));
        }
    }
    else if(gpio_port == 1)
    {
        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, OUTPUT_PORT_REGISTER1, &register_original_data);
        if(status == 1)
        {
            nca9555_write_byte(slave_num | HOST_WRITE_COMMAND, OUTPUT_PORT_REGISTER1, register_original_data | gpio_num);
        }
        else
        {
            nca9555_write_byte(slave_num | HOST_WRITE_COMMAND, OUTPUT_PORT_REGISTER1, register_original_data & (~gpio_num));
        }
    }
}

/*
 * 获取GPIO状态
 *
 * slave_num  需要操作的从机设备
 * gpio_port  gpio端口  端口0/1
 * gpio_num   哪一个GPIO
 *
 * 返回值:GPIO状态
 **/
uint8_t nca9555_get_gpio_status(uint8_t slave_num, uint8_t gpio_port,  uint8_t gpio_num)
{
    uint8_t register_original_data = 0;
    uint8_t gpio_status = 0;
    if(gpio_port > 1 || gpio_num > 0x80)
    {
        printf("[ERROR] gpio_port > 1 || gpio_num > 0x80\r\n");
        return 2;
    }
    if(gpio_port == 0)
    {

        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, INPUT_PORT_REGISTER0, &register_original_data);

    }
    else if(gpio_port == 1)
    {
        nca9555_read_byte(slave_num, slave_num  | HOST_READ_COMMAND, INPUT_PORT_REGISTER1, &register_original_data);
    }
    switch(gpio_num)
    {
        case 0x01:  gpio_status = register_original_data & gpio_num;break;
        case 0x02:  gpio_status = (register_original_data & gpio_num) >> 1;break;
        case 0x04:  gpio_status = (register_original_data & gpio_num) >> 2;break;
        case 0x08:  gpio_status = (register_original_data & gpio_num) >> 3;break;
        case 0x10:  gpio_status = (register_original_data & gpio_num) >> 4;break;
        case 0x20:  gpio_status = (register_original_data & gpio_num) >> 5;break;
        case 0x40:  gpio_status = (register_original_data & gpio_num) >> 6;break;
        case 0x80:  gpio_status = (register_original_data & gpio_num) >> 7;break;
        default:  printf("[ERROR] gpio error!\r\n");
    }
    return gpio_status;
}

注:
NCA9555采用IIC通信,协议中涉及的延时函数务必保证精确。
上面代码可直接运行在芯科科技的EFR32BG22中。需要移植到其他的芯片中只需要确定两点:
①GPIO输入输出设置
②精确到us级别的延时函数
将对应的的部分替换掉就可以了。

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

生成海报
点赞 0

LH_SMD

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

串口配置TMC2209电机驱动模块

串口配置TMC2209电机驱动模块 本文主要记录TMC2209调试过程,通过串口助手配置TMC2209的寄存器实现转速,方向,细分数等寄存器设置。 1.首先要实现uart配置TMC2209寄存器就要先

PCA9555详细学习

2022.01.27 控制寄存器和命令寄存器,及英文理解 一般8位作为地址,其中前四位时固定的,中间三位为地址配置,最后一位是读写位,即读是1,写是0 当地址