打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

一、简介

4pin控制16ping,IO扩展器件

二、特性

  1. 16 个等电流输出通道
  2. 等电流输出值不受输出端负载电压影响等电流范围值,
  3. 3-30mA@VDp=5V;
  4. 3-15mA@Vpp=3.3V
  5. 极为精确的电流输出值,
  6. 通道间差异值: <±1.5%(一般值);<±2.5%(最大值);
  7. 芯片间差异值: <±1.5%(一般值);<±3.0% (最大值)。
  8. 利用一个外接电阻,可设定电流输出值
  9. 快速的输出电流响应, OE: 45ns (保持输出一致性的条件下)高达 25MHz 时钟频率
  10. 具 Schmitt trigger 输入
  11. 装置操作电压: 3.3/5 伏特
  12. 封装湿度敏感等级:3

三、 示例代码

/********************************************************************************
* @file    extend_16ch.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2023-04-07
* @brief   16位恒流驱动芯片 MBI5020 JXI5020GP

对于ARM_M平台 @16M
1个NOP:(1/24000000)*1000*1000*1000==41.67ns
__NOP(); __NOP(); __NOP(); __NOP(); __NOP();      \
对于n76e003平台 @16M
1个nop      占用87ns
while(1)    占用194ns
函数调用     占用570ns

如果没有APP_IO,则需要在外部实现该结构体
static const extend_16ch_gpio_t io = {
    .clk_pin = {GPIOC, GPIO_PIN_5, GPIO_CLK(GPIOC)},
    .sdi_pin = {GPIOC, GPIO_PIN_6, GPIO_CLK(GPIOC)},
    .le_pin = {GPIOC, GPIO_PIN_4, GPIO_CLK(GPIOC)},
    .oe_pin = {GPIOC, GPIO_PIN_3, GPIO_CLK(GPIOC)},
}
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

/* Private Includes ----------------------------------------------------------*/
#include "extend_16ch.h"
#include "bsp_gpio.h"

#ifdef LISUN_SDK
#include "ls_gpio.h"
#include "ls_syscfg.h"
#endif

/* Private Define ------------------------------------------------------------*/
/* Private Typedef -----------------------------------------------------------*/
/* Private Macro -------------------------------------------------------------*/
/* Private Variables ---------------------------------------------------------*/
#ifndef APP_IO
#define GPIO_APBx                                   (0)
#else
#include "app_io.h"
#include "bsp_pwm.h"
#define PWMx    g_io.type[io->oe_pin]-IO_TYPE_TIM1_CH1
#endif
/* Private Function Prototypes -----------------------------------------------*/
/* Public Function Prototypes ------------------------------------------------*/
/**
 * @brief  器件硬件初始化
 * @param  *io: 引脚配置
 */
void extend_16ch_init(extend_16ch_gpio_t *io) {
#ifndef APP_IO
    /* Enable the GPIO Clock */
    bsp_gpio_set_clk(GPIO_APBx, io->clk_pin.periph, true);
    /* Configure the GPIO pin */
    bsp_gpio_init_output(io->clk_pin.port, io->clk_pin.pin, BSP_GPIO_PIN_OUT_PP);
    /* Reset PIN to switch off the */
    bsp_gpio_set_pin(io->clk_pin.port, io->clk_pin.pin, BSP_GPIO_PIN_RESET);

    /* Enable the GPIO Clock */
    bsp_gpio_set_clk(GPIO_APBx, io->sdi_pin.periph, true);
    /* Configure the GPIO pin */
    bsp_gpio_init_output(io->sdi_pin.port, io->sdi_pin.pin, BSP_GPIO_PIN_OUT_PP);
    /* Reset PIN to switch off the */
    bsp_gpio_set_pin(io->sdi_pin.port, io->sdi_pin.pin, BSP_GPIO_PIN_RESET);

    /* Enable the GPIO Clock */
    bsp_gpio_set_clk(GPIO_APBx, io->le_pin.periph, true);
    /* Configure the GPIO pin */
    bsp_gpio_init_output(io->le_pin.port, io->le_pin.pin, BSP_GPIO_PIN_OUT_PP);
    /* Reset PIN to switch off the */
    bsp_gpio_set_pin(io->le_pin.port, io->le_pin.pin, BSP_GPIO_PIN_RESET);

    /* Enable the GPIO Clock */
    bsp_gpio_set_clk(GPIO_APBx, io->oe_pin.periph, true);
    /* Configure the GPIO pin */
    bsp_gpio_init_output(io->oe_pin.port, io->oe_pin.pin, BSP_GPIO_PIN_OUT_PP);
    /* Reset PIN to switch off the */
    bsp_gpio_set_pin(io->oe_pin.port, io->oe_pin.pin, BSP_GPIO_PIN_SET);
#else
#endif
}

/**
 * @brief  注销器件引脚
 * @param  *io: 引脚配置
 */
void extend_16ch_deinit(extend_16ch_gpio_t *io) {
#ifndef APP_IO
    /* Turn off */
    bsp_gpio_set_pin(io->clk_pin.port, io->clk_pin.pin, BSP_GPIO_PIN_RESET);
    /* DeInit the GPIO pin */
    bsp_gpio_deinit(io->clk_pin.port, io->clk_pin.pin);

    /* Turn off */
    bsp_gpio_set_pin(io->sdi_pin.port, io->sdi_pin.pin, BSP_GPIO_PIN_RESET);
    /* DeInit the GPIO pin */
    bsp_gpio_deinit(io->sdi_pin.port, io->sdi_pin.pin);

    /* Turn off */
    bsp_gpio_set_pin(io->le_pin.port, io->le_pin.pin, BSP_GPIO_PIN_RESET);
    /* DeInit the GPIO pin */
    bsp_gpio_deinit(io->le_pin.port, io->le_pin.pin);

    /* Turn off */
    bsp_gpio_set_pin(io->oe_pin.port, io->oe_pin.pin, BSP_GPIO_PIN_SET);
    /* DeInit the GPIO pin */
    bsp_gpio_deinit(io->oe_pin.port, io->oe_pin.pin);
#else
#endif
}

/**
 * @brief  写入数据
 * @param  *io: 引脚配置
 * @param  data[]: IO数据,请以倒叙传入。如U5,U4,U3,U2,U1。
 * @param  num: 器件数量
 */
void extend_16ch_write(extend_16ch_gpio_t *io, uint16_t data[], uint8_t num) {
    //extend_16ch_close(io);
    uint16_t temp = 0;
    uint8_t bit_val = 0;
#ifndef APP_IO
    // 先关闭器件
    bsp_gpio_set_pin(io->clk_pin.port, io->clk_pin.pin, BSP_GPIO_PIN_RESET);
    bsp_gpio_set_pin(io->sdi_pin.port, io->sdi_pin.pin, BSP_GPIO_PIN_RESET);
    bsp_gpio_set_pin(io->le_pin.port, io->le_pin.pin, BSP_GPIO_PIN_RESET);
    for (uint8_t i = 0; i < num; i++) {
        temp = data[i];
        for (uint8_t bit = 0; bit < 16; bit++) {
            bit_val = temp & 0x8000 ? 1 : 0;
            temp <<= 1;
            if (bit_val)
                bsp_gpio_set_pin(io->sdi_pin.port, io->sdi_pin.pin, BSP_GPIO_PIN_SET);
            else
                bsp_gpio_set_pin(io->sdi_pin.port, io->sdi_pin.pin, BSP_GPIO_PIN_RESET);
            bsp_gpio_set_pin(io->clk_pin.port, io->clk_pin.pin, BSP_GPIO_PIN_SET);
            __NOP();__NOP();
            bsp_gpio_set_pin(io->clk_pin.port, io->clk_pin.pin, BSP_GPIO_PIN_RESET);
            __NOP();__NOP();
        }
    }
    bsp_gpio_set_pin(io->le_pin.port, io->le_pin.pin, BSP_GPIO_PIN_SET);
    __NOP();
    bsp_gpio_set_pin(io->le_pin.port, io->le_pin.pin, BSP_GPIO_PIN_RESET);
    __NOP();__NOP();
#else
    // 先关闭器件
    bsp_gpio_set_pin(g_io_cfg[io->clk_pin].port, g_io_cfg[io->clk_pin].pin, BSP_GPIO_PIN_RESET);
    bsp_gpio_set_pin(g_io_cfg[io->sdi_pin].port, g_io_cfg[io->sdi_pin].pin, BSP_GPIO_PIN_RESET);
    bsp_gpio_set_pin(g_io_cfg[io->le_pin].port, g_io_cfg[io->le_pin].pin, BSP_GPIO_PIN_RESET);
    for (uint8_t i = 0; i < num; i++) {
        temp = data[i];
        for (uint8_t bit = 0; bit < 16; bit++) {
            bit_val = temp & 0x8000 ? 1 : 0;
            temp <<= 1;
            if (bit_val)
                bsp_gpio_set_pin(g_io_cfg[io->sdi_pin].port, g_io_cfg[io->sdi_pin].pin, BSP_GPIO_PIN_SET);
            else
                bsp_gpio_set_pin(g_io_cfg[io->sdi_pin].port, g_io_cfg[io->sdi_pin].pin, BSP_GPIO_PIN_RESET);
            bsp_gpio_set_pin(g_io_cfg[io->clk_pin].port, g_io_cfg[io->clk_pin].pin, BSP_GPIO_PIN_SET);
            __NOP();__NOP();
            bsp_gpio_set_pin(g_io_cfg[io->clk_pin].port, g_io_cfg[io->clk_pin].pin, BSP_GPIO_PIN_RESET);
            __NOP();__NOP();
        }
    }
    bsp_gpio_set_pin(g_io_cfg[io->le_pin].port, g_io_cfg[io->le_pin].pin, BSP_GPIO_PIN_SET);
    __NOP();
    bsp_gpio_set_pin(g_io_cfg[io->le_pin].port, g_io_cfg[io->le_pin].pin, BSP_GPIO_PIN_RESET);
    __NOP();__NOP();
#endif
    //extend_16ch_open(io);
}

/**
 * @brief 器件使能脚--打开
 * @param io 引脚配置
 */
void extend_16ch_open(extend_16ch_gpio_t *io) {
#ifndef APP_IO
    bsp_gpio_set_pin(io->oe_pin.port, io->oe_pin.pin, BSP_GPIO_PIN_RESET);
#else
    if (g_io.type[io->oe_pin] == IO_TYPE_OUT_PP) {
        if (io->valid_level)
            bsp_gpio_set_pin(g_io_cfg[io->oe_pin].port, g_io_cfg[io->oe_pin].pin, BSP_GPIO_PIN_SET);
        else
            bsp_gpio_set_pin(g_io_cfg[io->oe_pin].port, g_io_cfg[io->oe_pin].pin, BSP_GPIO_PIN_RESET);
    } else { // 非输出脚,则为PWM模式
        if (io->valid_level)
            bsp_pwm_set_pulse(PWMx, bsp_pwm_pp_to_pulse(PWMx, io->intensity_ctrl));
        else
            bsp_pwm_set_pulse(PWMx, bsp_pwm_pp_to_pulse(PWMx, 100 - io->intensity_ctrl));
    }
#endif
}

/**
 * @brief 器件使能脚--关闭
 * @param io 引脚配置
 */
void extend_16ch_close(extend_16ch_gpio_t *io) {
#ifndef APP_IO
    bsp_gpio_set_pin(io->oe_pin.port, io->oe_pin.pin, BSP_GPIO_PIN_SET);
#else
    if (g_io.type[io->oe_pin] == IO_TYPE_OUT_PP) {
        if (io->valid_level)
            bsp_gpio_set_pin(g_io_cfg[io->oe_pin].port, g_io_cfg[io->oe_pin].pin, BSP_GPIO_PIN_RESET);
        else
            bsp_gpio_set_pin(g_io_cfg[io->oe_pin].port, g_io_cfg[io->oe_pin].pin, BSP_GPIO_PIN_SET);
    } else {
        if (io->valid_level)
            bsp_pwm_set_pulse(PWMx, 0);
        else
            bsp_pwm_set_pulse(PWMx, -1);
    }
#endif
}

/********************************************************************************
* @file    extend_16ch.h
* @author  jianqiang.xue
* @version V1.0.0
* @date    2023-04-07
* @brief   16位恒流驱动芯片 MBI5020 JXI5020GP

如果没有APP_IO则使用下面方式定义引脚:
static const extend_16ch_gpio_t io = {
    .clk_pin = {GPIOC, GPIO_PIN_5, GPIO_CLK(GPIOC)},
    .sdi_pin = {GPIOC, GPIO_PIN_6, GPIO_CLK(GPIOC)},
    .le_pin = {GPIOC, GPIO_PIN_4, GPIO_CLK(GPIOC)},
    .oe_pin = {GPIOC, GPIO_PIN_3, GPIO_CLK(GPIOC)},
};

如果启动了APP_IO则直接用ID号
#define LS_EXIO_CLK_ID                                             (7)
#define LS_EXIO_DIO_ID                                             (8)
#define LS_EXIO_LE_ID                                              (6)
#define LS_EXIO_OE_ID                                              (5)
static const extend_16ch_gpio_t io = {
    .clk_pin = LS_EXIO_CLK_ID,
    .sdi_pin = LS_EXIO_DIO_ID,
    .le_pin = LS_EXIO_LE_ID,
    .oe_pin = LS_EXIO_OE_ID,
};
********************************************************************************/

#ifndef __EXTEND_16CH_H
#define __EXTEND_16CH_H

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "bsp_gpio.h"
/* Public enum ---------------------------------------------------------------*/
/* Public Struct -------------------------------------------------------------*/
#ifndef APP_IO
typedef struct {
    bsp_gpio2_t clk_pin; // 时钟脚
    bsp_gpio2_t sdi_pin; // 数据脚
    bsp_gpio2_t le_pin;  // 锁存 低电平开始准备数据,高电平发送数据
    bsp_gpio2_t oe_pin;  // 使能脚  低电平打开IO0-IO15的输入,高电平关闭
} extend_16ch_gpio_t;
#else
typedef struct {  // 填写[g_io_cfg]中索引号
    uint8_t clk_pin;
    uint8_t sdi_pin;
    uint8_t le_pin;
    uint8_t oe_pin;          // 请在syscfg_gui中配置为PWM
    uint8_t intensity_ctrl;  // 亮度控制,通过调整[oe_pin]占空比
    uint8_t valid_level;     // 有效电平
} extend_16ch_gpio_t;
#endif
/* Public Function Prototypes ------------------------------------------------*/

void extend_16ch_init(extend_16ch_gpio_t *io);
void extend_16ch_deinit(extend_16ch_gpio_t *io);

void extend_16ch_write(extend_16ch_gpio_t *io, uint16_t data[], uint8_t num);
void extend_16ch_open(extend_16ch_gpio_t *io);
void extend_16ch_close(extend_16ch_gpio_t *io);

#endif

posted on 2023-04-22 13:09  xuejianqiang  阅读(70)  评论(0编辑  收藏  举报  来源
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033