打印
[应用方案]

M263 I2C驱动TDK CH101模块

[复制链接]
2494|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wangjiahao88|  楼主 | 2021-7-31 11:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
TDK InvenSense CH101距离传感器是基于Chirp专利MEMS技术的微型超低功率超声波飞行时间(ToF)距离传感器。这些传感器采用系统级封装,以微型,可回流封装的形式集成了压电微机械超声换能器(PMUT)和超低功耗片上系统(SoC)。这些CH101传感器速度快,可在距离最远1.2m的目标上提供精确的距离测量。距离传感器可以检测多个物体,并可以在包括全日照在内的任何照明条件下工作,并提供毫米级的精确距离测量。这些CH101传感器具有运行高级超声波固件的低功耗微控制器,专用的可编程范围中断引脚以及用于接收和发送的单个传感器。

使用特权

评论回复
沙发
wangjiahao88|  楼主 | 2021-7-31 11:46 | 只看该作者


CH101距离传感器在1.62V至1.98V的电压范围内工作,需要60ms的时间进行编程。这些距离传感器采用8引脚焊盘栅格阵列(LGA)封装,尺寸为3.5mm x 3.5mm x 1.26mm。典型应用包括四轴飞行器和机器人技术,移动和计算设备,避障,打印机和扫描仪,接近感应和智能家居。

CH101距离传感器特征


快速准确的测距:

4cm至1.2m工作范围

采样率高达100个样本/秒

在30cm范围内1.0mm RMS范围噪声

针对中短距离感测应用而优化的可编程模式

可自定义的视野(FoV)高达180°

多目标检测

在阳光和任何其他照明下工作

对物体颜色不敏感,可检测光学透明的表面,例如玻璃窗

易于集成:

单个传感器用于接收和发送

1.8V单电源电压

I 2 C快速模式兼容接口,数据速率高达400kbps

专用可编程范围中断引脚

独立于平台的软件驱动程序可实现全程测距

微型集成模块:

与标准SMD回流兼容

低功耗微控制器,运行高级超声波固件

-40°C至85°C的工作温度范围

超低电源电流:

1个样本/秒:

13μA(最大10cm范围)

15μA(最大1.0m范围)

30个样本/秒:

33μA(最大10cm范围)

130μA(1.0m最大范围)

CH101距离传感器技术指标

1.62V至1.98V工作电压范围

3.5mm x 3.5mm x 1.26mm尺寸

8引脚LGA封装

60ms的编程时间

使用特权

评论回复
板凳
wangjiahao88|  楼主 | 2021-7-31 11:51 | 只看该作者

使用特权

评论回复
地板
wangjiahao88|  楼主 | 2021-7-31 11:56 | 只看该作者

使用特权

评论回复
5
wangjiahao88|  楼主 | 2021-7-31 11:57 | 只看该作者

使用特权

评论回复
6
wangjiahao88|  楼主 | 2021-7-31 11:58 | 只看该作者

使用特权

评论回复
7
wangjiahao88|  楼主 | 2021-7-31 11:59 | 只看该作者

使用特权

评论回复
8
wangjiahao88|  楼主 | 2021-7-31 11:59 | 只看该作者
范例程序 执行
1. 根据目录信息章节进入ExampleCode 路径中的KEIL文件夹,双击M263_I2C_TDK_CH101.uvprojx。
2. 进入编译模式界面
a. 编译
b. 下载代码至内存
c. 进入 / 离开仿真模式
3. 进入仿真模式界面
a. 执行代码

使用特权

评论回复
9
wangjiahao88|  楼主 | 2021-7-31 12:05 | 只看该作者
int main(void)
{
    ch_group_t  *grp_ptr = &chirp_group;
    uint8_t u8_chirp_error = 0;
    uint8_t u8_num_ports;
    uint8_t u8_dev_num;

    /* Initialize board hardware functions
     *   This call to the board support package (BSP) performs all necessary
     *   hardware initialization for the application to run on this board.
     *   This includes setting up memory regions, initializing clocks and
     *   peripherals (including I2C and serial port), and any processor-specific
     *   startup sequences.
     *
     *   The chbsp_board_init() function also initializes fields within the
     *   sensor group descriptor, including number of supported sensors and
     *   the RTC clock calibration pulse length.
     */
    chbsp_board_init(grp_ptr);

    printf("\n\nNuvoton M263 & Chirp SonicLib Example Application\n");
    printf("    Compile time:  %s %s\n", __DATE__, __TIME__);
    printf("    Version: %u.%u.%u", APP_VERSION_MAJOR, APP_VERSION_MINOR,
           APP_VERSION_REV);
    printf("    SonicLib version: %u.%u.%u\n", SONICLIB_VER_MAJOR,
           SONICLIB_VER_MINOR, SONICLIB_VER_REV);
    printf("\n");


    /* Get the number of (possible) sensor devices on the board
     *   Set by the BSP during chbsp_board_init()
     */
    u8_num_ports = ch_get_num_ports(grp_ptr);


    /* Initialize sensor descriptors.
     *   This loop initializes each (possible) sensor's ch_dev_t descriptor,
     *   although we don't yet know if a sensor is actually connected.
     *
     *   The call to ch_init() specifies the sensor descriptor, the sensor group
     *   it will be added to, the device number within the group, and the sensor
     *   firmware initialization routine that will be used.  (The sensor
     *   firmware selection effectively specifies whether it is a CH101 or
     *   CH201 sensor, as well as the exact feature set.)
     */
    printf("Initializing sensor(s)... ");

    for (u8_dev_num = 0; u8_dev_num < u8_num_ports; u8_dev_num++)
    {
        ch_dev_t *dev_ptr = &(chirp_devices[u8_dev_num]);  // init struct in array

        /* Init device descriptor
         *   Note that this assumes all sensors will use the same sensor
         *   firmware.  The CHIRP_SENSOR_FW_INIT_FUNC symbol is defined in
         *   app_config.h and is used for all devices.
         *
         *   However, it is possible for different sensors to use different
         *   firmware images, by specifying different firmware init routines
         *   when ch_init() is called for each.
         */
        u8_chirp_error |= ch_init(dev_ptr, grp_ptr, u8_dev_num,
                                  CHIRP_SENSOR_FW_INIT_FUNC);
    }

    /* Start all sensors.
     *   The ch_group_start() function will search each port (that was
     *   initialized above) for a sensor. If it finds one, it programs it (with
     *   the firmware specified above during ch_init()) and waits for it to
     *   perform a self-calibration step.  Then, once it has found all the
     *   sensors, ch_group_start() completes a timing reference calibration by
     *   applying a pulse of known length to the sensor's INT line.
     */
    if (u8_chirp_error == 0)
    {
        printf("starting group... ");
        u8_chirp_error = ch_group_start(grp_ptr);
    }

    if (u8_chirp_error == 0)
    {
        printf("OK\n");
    }
    else
    {
        printf("FAILED: %d\n", u8_chirp_error);
    }

    printf("\n");

    /* Get and display the initialization results for each connected sensor.
     *   This loop checks each device number in the sensor group to determine
     *   if a sensor is actually connected.  If so, it makes a series of
     *   function calls to get different operating values, including the
     *   operating frequency, clock calibration values, and firmware version.
     */
    printf("Sensor\tType \t   Freq\t\t RTC Cal \tFirmware\n");

    for (u8_dev_num = 0; u8_dev_num < u8_num_ports; u8_dev_num++)
    {
        ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, u8_dev_num);

        if (ch_sensor_is_connected(dev_ptr))
        {
            printf("%d\tCH%d\t %u Hz\t%u@%ums\t%s\n", u8_dev_num,
                   ch_get_part_number(dev_ptr),
                   (unsigned int) ch_get_frequency(dev_ptr),
                   ch_get_rtc_cal_result(dev_ptr),
                   ch_get_rtc_cal_pulselength(dev_ptr),
                   ch_get_fw_version_string(dev_ptr));
        }
    }

    printf("\n");

    /* Register callback function to be called when Chirp sensor interrupts */
    ch_io_int_callback_set(grp_ptr, sensor_int_callback);

    /* Configure each sensor with its operating parameters
     *   Initialize a ch_config_t structure with values defined in the
     *   app_config.h header file, then write the configuration to the
     *   sensor using ch_set_config().
     */
    printf("Configuring sensor(s)...\n");

    for (u8_dev_num = 0; u8_dev_num < u8_num_ports; u8_dev_num++)
    {
        ch_config_t dev_config;
        ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, u8_dev_num);

        if (ch_sensor_is_connected(dev_ptr))
        {

            /* Select sensor mode
             *   All connected sensors are placed in hardware triggered mode.
             *   The first connected (lowest numbered) sensor will transmit and
             *   receive, all others will only receive.
             */

            u8_num_connected_sensors++;             // count one more connected
            u32_active_devices |= (1 << u8_dev_num);   // add to active device bit mask

            if (u8_num_connected_sensors == 1)      // if this is the first sensor
            {
                dev_config.mode = CHIRP_FIRST_SENSOR_MODE;
            }
            else
            {
                dev_config.mode = CHIRP_OTHER_SENSOR_MODE;
            }

            if (dev_config.mode != CH_MODE_FREERUN)     // unless free-running
            {
                u8_num_triggered_devices++;             // will be triggered
            }

            /* Init config structure with values from app_config.h */
            dev_config.max_range       = CHIRP_SENSOR_MAX_RANGE_MM;
            dev_config.static_range    = CHIRP_SENSOR_STATIC_RANGE;

            /* If sensor will be free-running, set internal sample interval */
            if (dev_config.mode == CH_MODE_FREERUN)
            {
                dev_config.sample_interval = MEASUREMENT_INTERVAL_MS;
            }
            else
            {
                dev_config.sample_interval = 0;
            }

            dev_config.thresh_ptr = 0;

            /* Apply sensor configuration */
            u8_chirp_error = ch_set_config(dev_ptr, &dev_config);

            /* Enable sensor interrupt if using free-running mode
             *   Note that interrupt is automatically enabled if using
             *   triggered modes.
             */
            if ((!u8_chirp_error) && (dev_config.mode == CH_MODE_FREERUN))
            {
                chbsp_set_io_dir_in(dev_ptr);
                chbsp_io_interrupt_enable(dev_ptr);
            }

            /* Read back and display config settings */
            if (!u8_chirp_error)
            {
                display_config_info(dev_ptr);
            }
            else
            {
                printf("Device %d: Error during ch_set_config()\n", u8_dev_num);
            }
        }
    }

    printf("\n");

    /* Enable receive sensor pre-triggering, if specified */
    ch_set_rx_pretrigger(grp_ptr, RX_PRETRIGGER_ENABLE);

    /* Initialize the periodic timer we'll use to trigger the measurements.
     *   This function initializes a timer that will interrupt every time it
     *   expires, after the specified measurement interval.  The function also
     *   registers a callback function that will be called from the timer
     *   handler when the interrupt occurs.  The callback function will be
     *   used to trigger a measurement cycle on the group of sensors.
     */
    if (u8_num_triggered_devices > 0)
    {
        printf("Initializing sample timer for %dms interval... ",
               MEASUREMENT_INTERVAL_MS);

        chbsp_periodic_timer_init(MEASUREMENT_INTERVAL_MS,
                                  periodic_timer_callback);

        printf("OK\n");
    }

    printf("Starting measurements\n");

    /* Enter main loop
     *   This is an infinite loop that will run for the remainder of the system
     *   execution.  The processor is put in a low-power sleep mode between
     *   measurement cycles and is awakened by interrupt events.
     *
     *   The interrupt may be the periodic timer (set up above), a data-ready
     *   interrupt from a sensor, or the completion of a non-blocking I/O
     *   operation.  This loop will check flags that are set during the
     *   callback functions for the data-ready interrupt and the non-blocking
     *   I/O complete.  Based on the flags that are set, this loop will call
     *   the appropriate routines to handle and/or display sensor data.
     */
    while (1)
    {
        /* Check for sensor data-ready interrupt(s) */
        if (u32_taskflags & DATA_READY_FLAG)
        {
            /* All sensors have interrupted - handle sensor data */
            u32_taskflags &= ~DATA_READY_FLAG;  // clear flag
            handle_data_ready(grp_ptr);         // read and display measurement
        }
    }
}


/*
* periodic_timer_callback() - periodic timer callback routine
*
* This function is called by the periodic timer interrupt when the timer
* expires.  Because the periodic timer is used to initiate a new measurement
* cycle on a group of sensors, this function calls ch_group_trigger() during
* each execution.
*
* This function is registered by the call to chbsp_periodic_timer_init()
* in main().
*/

void periodic_timer_callback(void)
{
    if (u8_num_triggered_devices > 0)
    {
        ch_group_trigger(&chirp_group);
    }
}


/*
* sensor_int_callback() - sensor interrupt callback routine
*
* This function is called by the board support package's interrupt handler for
* the sensor's INT line every time that the sensor interrupts.  The device
* number parameter, u8_dev_num, is used to identify the interrupting device
* within the sensor group.  (Generally the device number is same as the port
* number used in the BSP to manage I/O pins, etc.)
*
* Each time this function is called, a bit is set in the u32_data_ready_devices
* variable to identify the interrupting device.  When all active sensors have
* interrupted (found by comparing with the u32_active_devices variable), the
* DATA_READY_FLAG is set.  That flag will be detected in the main() loop.
*
* This callback function is registered by the call to ch_io_int_callback_set()
* in main().
*/
static void sensor_int_callback(ch_group_t *grp_ptr, uint8_t u8_dev_num)
{
    ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, u8_dev_num);

    u32_data_ready_devices |= (1 << u8_dev_num);       // add to data-ready bit mask

    if (u32_data_ready_devices == u32_active_devices)
    {
        /* All active sensors have interrupted after performing a measurement */
        u32_data_ready_devices = 0;

        /* Set data-ready flag - it will be checked in main() loop */
        u32_taskflags |= DATA_READY_FLAG;

        /* Disable interrupt unless in free-running mode
         *   It will automatically be re-enabled by the next ch_group_trigger()
         */
        if (ch_get_mode(dev_ptr) == CH_MODE_FREERUN)
        {
            chbsp_set_io_dir_in(dev_ptr);               // set INT line as input
            chbsp_group_io_interrupt_enable(grp_ptr);
        }
        else
        {
            chbsp_group_io_interrupt_disable(grp_ptr);
        }
    }
}

/*
* display_config_info() - display the configuration values for a sensor
*
* This function displays the current configuration settings for an individual
* sensor.  The operating mode, maximum range, and static target rejection
* range (if used) are displayed.
*
* For CH201 sensors only, the multiple detection threshold values are also
* displayed.
*/
static uint8_t display_config_info(ch_dev_t *dev_ptr)
{
    ch_config_t     read_config;
    uint8_t         u8_chirp_error;
    uint8_t         u8_dev_num = ch_get_dev_num(dev_ptr);
    ch_thresholds_t read_thresholds;

    /* Read configuration values for the device into ch_config_t structure */
    u8_chirp_error = ch_get_config(dev_ptr, &read_config);

    if (!u8_chirp_error)
    {
        const char *mode_string;

        switch (read_config.mode)
        {
            case CH_MODE_IDLE:
                mode_string = "IDLE";
                break;

            case CH_MODE_FREERUN:
                mode_string = "FREERUN";
                break;

            case CH_MODE_TRIGGERED_TX_RX:
                mode_string = "TRIGGERED_TX_RX";
                break;

            case CH_MODE_TRIGGERED_RX_ONLY:
                mode_string = "TRIGGERED_RX_ONLY";
                break;

            default:
                mode_string = "UNKNOWN";
        }

        /* Display sensor number, mode and max range */
        printf("Sensor %d:\tmax_range=%dmm \tmode=%s  ", u8_dev_num,
               read_config.max_range, mode_string);

        /* Display static target rejection range, if used */
        if (read_config.static_range != 0)
        {
            printf("static_range=%d samples", read_config.static_range);
        }

        /* Display detection thresholds (only supported on CH201) */
        if (ch_get_part_number(dev_ptr) == CH201_PART_NUMBER)
        {
            /* Get threshold values in structure */
            u8_chirp_error = ch_get_thresholds(dev_ptr, &read_thresholds);

            if (!u8_chirp_error)
            {
                printf("\n  Detection thresholds:\n");

                for (int i = 0; i < CH_NUM_THRESHOLDS; i++)
                {
                    printf("     %d\tstart: %2d\tlevel: %d\n", i,
                           read_thresholds.threshold[i].start_sample,
                           read_thresholds.threshold[i].level);
                }
            }
            else
            {
                printf(" Device %d: Error during ch_get_thresholds()", u8_dev_num);
            }
        }

        printf("\n");

    }
    else
    {
        printf(" Device %d: Error during ch_get_config()\n", u8_dev_num);
    }

    return u8_chirp_error;
}


/*
* handle_data_ready() - get and display data from all sensors
*
* This routine is called from the main() loop after all sensors have
* interrupted. It shows how to read the sensor data once a measurement is
* complete.  This routine always reads out the range and amplitude, and
* optionally will read out the amplitude data or raw I/Q for all samples
* in the measurement.
*
* See the comments in app_config.h for information about the amplitude data
* and I/Q readout build options.
*
*/
static uint8_t handle_data_ready(ch_group_t *grp_ptr)
{
    uint8_t     u8_dev_num;
    uint8_t     u8_num_samples = 0;
    uint8_t     ret_val = 0;

    /* Read and display data from each connected sensor
     *   This loop will write the sensor data to this application's "chirp_data"
     *   array.  Each sensor has a separate chirp_data_t structure in that
     *   array, so the device number is used as an index.
     */

    for (u8_dev_num = 0; u8_dev_num < ch_get_num_ports(grp_ptr); u8_dev_num++)
    {
        ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, u8_dev_num);

        if (ch_sensor_is_connected(dev_ptr))
        {

            /* Get measurement results from each connected sensor
             *   For sensor in transmit/receive mode, report one-way echo
             *   distance,  For sensor(s) in receive-only mode, report direct
             *   one-way distance from transmitting sensor
             */

            if (ch_get_mode(dev_ptr) == CH_MODE_TRIGGERED_RX_ONLY)
            {
                chirp_data[u8_dev_num].range = ch_get_range(dev_ptr,
                                                            CH_RANGE_DIRECT);
            }
            else
            {
                chirp_data[u8_dev_num].range = ch_get_range(dev_ptr,
                                                            CH_RANGE_ECHO_ONE_WAY);
            }

            if (chirp_data[u8_dev_num].range == CH_NO_TARGET)
            {
                /* No target object was detected - no range value */

                chirp_data[u8_dev_num].amplitude = 0;  /* no updated amplitude */

                printf("Port %d:          no target found        ", u8_dev_num);

            }
            else
            {
                /* Target object was successfully detected (range available) */

                /* Get the new amplitude value - it's only updated if range
                 * was successfully measured.  */
                chirp_data[u8_dev_num].amplitude = ch_get_amplitude(dev_ptr);

                printf("Port %d:  Range: %0.1f mm  Amp: %u  ", u8_dev_num,
                       (float) chirp_data[u8_dev_num].range / 32.0f,
                       chirp_data[u8_dev_num].amplitude);
            }

            /* Store number of active samples in this measurement */
            u8_num_samples = ch_get_num_samples(dev_ptr);
            chirp_data[u8_dev_num].num_samples = u8_num_samples;

            /* If more than 2 sensors, put each on its own line */
            if (u8_num_connected_sensors > 2)
            {
                printf("\n");
            }
        }
    }

    printf("\n");

    return ret_val;
}


使用特权

评论回复
10
wangjiahao88|  楼主 | 2021-7-31 12:07 | 只看该作者
EC_M263_I2C_TDK_CH101_V1.00 源码压缩包

EC_M263_I2C_TDK_CH101_V1.00.rar

2.92 MB

使用特权

评论回复
11
wangjiahao88|  楼主 | 2021-7-31 12:10 | 只看该作者
欢迎一起探讨!

使用特权

评论回复
12
carefull3357dc| | 2021-7-31 22:08 | 只看该作者
这个属于新唐官方的资料 肯定很好用!

感谢分享!

使用特权

评论回复
13
carefull3357dc| | 2021-7-31 22:09 | 只看该作者
硬件IIC吗?

使用特权

评论回复
14
kylongmu| | 2022-2-20 00:55 | 只看该作者
有arduino版的代码吗?

使用特权

评论回复
15
kylongmu| | 2022-3-6 23:34 | 只看该作者
试了,ch101返回数值乱跳,无法使用。

使用特权

评论回复
16
guijial511| | 2022-3-7 08:24 | 只看该作者
精度咋样?

使用特权

评论回复
17
kylongmu| | 2022-3-7 23:33 | 只看该作者

目前测试根本没精度,数值乱跳,网上找不到一个成功应用的例子,只有TDK的说明。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

473

主题

7517

帖子

30

粉丝