0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

VD6283TX环境光传感器(2)----移植闪烁频率代码

嵌入式单片机MCU开发 来源:嵌入式单片机MCU开发 作者:嵌入式单片机MCU开 2023-12-28 10:17 次阅读

闪烁定义

光学闪烁是指人造光源产生的光的脉冲或波动现象。在低频下,闪烁是肉眼可见的,即人眼能够感知到光的闪动。然而,当频率超过100 Hz时,虽然闪烁对人眼不再可见,它仍然存在并可能对人体产生一定影响。大部分人造光源,如家庭和商业办公室使用的,会在接入电网时产生闪烁,其频率通常由所在国家的电力频率决定,一般为50 Hz或60 Hz。由于电流在光源中的交替流动,这些光源会在50 Hz或60 Hz的电网下产生100 Hz或120 Hz的闪烁频率。为了消除这种可见闪烁并减少其对人体的潜在影响,许多LED灯采用了脉冲宽度调制(PWM)的调光方法,从而实现更高的闪烁频率。VD6283传感器能够检测高达2 kHz的光闪烁频率,从而为光质量的监测提供精准数据。

最近在弄ST的课程,需要样片的可以加群申请:615061293 。

视频教学

[https://www.bilibili.com/video/BV1pt4y1f7eh/]

样品申请

[https://www.wjx.top/vm/OhcKxJk.aspx#]

源码下载

[https://download.csdn.net/download/qq_24312945/88671493]

参考代码

[https://www.st.com/zh/ecosystems/x-cube-als.html]

在下面目录下有对应的程序。

这个应用程序演示了如何使用X-NUCLEO-6283A1扩展板,通过UART从连接的STM32 Nucleo板向PC传输数据,并在通用应用程序(如Tera Term)上显示闪烁频率提取结果。一旦建立连接,用户可以使用超级终端查看来自板载光传感器的数据。该应用程序提供实时数值,并允许用户通过键盘更改增益、曝光时间和采样率。这个示例只能在软件包安装文件夹中访问。

硬件准备

首先需要准备一个开发板,这里我准备的是自己绘制的开发板: 最近在弄ST和瑞萨RA的课程,需要样片的可以加群申请:615061293 。

开发板设置

在手册种给出了,闪烁手册可以查看AN5639,资料链接如下。

https://www.st.com/content/ccc/resource/technical/document/application_note/group1/9f/7e/8c/ce/36/85/4c/08/DM00776948/files/DM00776948.pdf/jcr:content/translations/en.DM00776948.pdf

在AN5639手册中,需要对SB3进行连接。

同时GPIO2需要接到MCUADC通道中。

查看X-NUCLEO-6283A1手册,可以看到VD6283TX的GPIO2连接到MCU的ADC端口0-2。

在本章使用的测试板中,AFLR_1V8接入到MCU的PC0接口

需要将AFLR_1V8接到开发板的A0端口中。

生成STM32CUBEMX

用STM32CUBEMX生成例程,这里使用MCU为STM32WB55RG。 配置时钟树,配置时钟为32M。

串口配置

查看原理图,PB6和PB7设置为开发板的串口。

配置串口。

IIC配置

配置IIC为快速模式,速度为400k。

X-CUBE-ALS

ADC使用定时器触发采样

在app_als_adc_utils.c中,定义了ADC使用的频率,为8000Hz。

定时器的arr设置为4000-1,那么定时器频率为8000Hz。 Trigger Event Selection :update event 定时器自动更新。

配置ADC检测VD6283TX的GPIO2管脚的AD值。 设置触发方式为外部触发,选择刚刚配置的TIM2,触发方式为上升沿触发。

开启中断。

KEIL配置

FFT代码配置

arm_cortexM4lf_math.lib 库包含了一系列数学函数,特别是适用于基于Cortex-M4和Cortex-M7处理器的浮点运算单元的优化数学例程。这些例程涵盖了常见的数学运算,如信号处理、滤波、变换等。

arm_math.h 这个头文件包含了CMSIS-DSP库的函数声明、宏定义和结构体定义等,可以通过包含这个头文件,使用库中提供的各种数学函数,包括信号处理、滤波、变换等。 添加arm_cortexM4lf_math.lib文件。

同时导入arm_math.h文件。

app_x-cube-als.c

由于需要进行FFT算法,所以需要添加对应数学头文件。

#define ARM_MATH_CM4
#include "arm_math.h"
#include "app_als_adc_utils.h"

添加对应的函数申明。

#define FLK_CHANNEL    (5U)

/*
 * Increasing the value of the FLK_DATA_SIZE symbol will increase
 * processing time, flicker accuracy and memory footprint
 */
#define FLK_DATA_SIZE (1024U)
#define FFT_SIZE (FLK_DATA_SIZE)

/* Private variables ---------------------------------------------------------*/
static uint8_t is_quit_requested;
static uint8_t is_autogain_requested;
static int16_t flk_data[FLK_DATA_SIZE];
volatile uint8_t ALS_EventDetected;

/*
 * The FFT of a real N-point sequence has even symmetry in the frequency domain.
 * The second half of the data equals the conjugate of the first half flipped in frequency.
 * Looking at the data, we see that we can uniquely represent the FFT using only N/2 complex numbers.
 * These are packed into the output array in alternating real and imaginary components:
 * X = { real[0], imag[0], real[1], imag[1], real[2], imag[2] ... real[(N/2)-1], imag[(N/2)-1 }
 */
static arm_rfft_fast_instance_f32 instance_fft;
static float32_t fft_in[FLK_DATA_SIZE];
static float32_t fft_out_tmp[FFT_SIZE];
static float32_t fft_out[FFT_SIZE/2];




/*
 * The FFT of a real N-point sequence has even symmetry in the frequency domain.
 * The second half of the data equals the conjugate of the first half flipped in frequency.
 * Looking at the data, we see that we can uniquely represent the FFT using only N/2 complex numbers.
 * These are packed into the output array in alternating real and imaginary components:
 * X = { real[0], imag[0], real[1], imag[1], real[2], imag[2] ... real[(N/2)-1], imag[(N/2)-1 }
 */
static arm_rfft_fast_instance_f32 instance_fft;


static void MX_VD6283A1_AnalogFlicker_Process(void); 

static float32_t complex_abs(float32_t real, float32_t complex);
static void init_fft(arm_rfft_fast_instance_f32 *instance, uint32_t size);
static void perform_fft(arm_rfft_fast_instance_f32 *instance, int16_t *data, float32_t *ffti, float32_t *ffto, uint32_t size);
static void find_flk_freq(uint32_t fs, float32_t *ffto, uint32_t *freq, uint8_t skip_dc, uint32_t size);


static int32_t flicker_autogain(uint8_t Instance, uint32_t *pAppliedGain, uint32_t timeoutMs);


static void display_gain(uint32_t gain);

在MX_VD6283A1_LuxCCT_Init()函数中添加init_fft快速傅里叶变换初始化。

static void MX_VD6283A1_LuxCCT_Init(void)
{
  /* Initialize Virtual COM Port */
  BSP_COM_Init(COM1);

  printf("VD6283TX Lux / CCT Examplenn");
  display_commands_banner();

    /* initialize ARM FFT library */
    init_fft(&instance_fft, FFT_SIZE);

  status = VD6283A1_LIGHT_SENSOR_Init(LIGHT_SENSOR_INSTANCE_0);

  if (status)
  {
    printf("VD6283A1_LIGHT_SENSOR_Init failedn");
    while(1);
  }
}

初始化完毕之后,添加频率获取函数。

static void MX_VD6283A1_AnalogFlicker_Process(void)
{
    uint32_t fs; /* sampling frequency */
    uint32_t pos = 0; 
    uint32_t flk_freq = 0;
    uint32_t index;

    uint32_t current_gain;
    uint32_t current_exposure;

    /* initialize exposure time */
    VD6283A1_LIGHT_SENSOR_SetExposureTime(LIGHT_SENSOR_INSTANCE_0, 100000);
    VD6283A1_LIGHT_SENSOR_GetExposureTime(LIGHT_SENSOR_INSTANCE_0, ¤t_exposure);
    printf("Exposure set to %lu usn", (unsigned long)current_exposure);

    /* initialize gain */
    flicker_autogain(LIGHT_SENSOR_INSTANCE_0, ¤t_gain, 1);
    printf("Channel %u gain set to", FLK_CHANNEL);
    display_gain(current_gain);

    status = als_adc_start(&fs);

    if (status)
    {
        printf("ADC Start failedn");
        while (1);
    }

    VD6283A1_LIGHT_SENSOR_StartFlicker(LIGHT_SENSOR_INSTANCE_0, FLK_CHANNEL, LIGHT_SENSOR_FLICKER_ANALOG);

    while (!is_quit_requested)
    {
        status = als_adc_get_frame(&flk_data[pos], &index);

        /* fill the ADC frame buffer */
        if (status == 0)
        {
            pos += ADC_FRAME_SIZE;
        }

        /* if the ADC frame buffer is full, then process it */
        if (pos == FLK_DATA_SIZE)
        {
            perform_fft(&instance_fft, flk_data, fft_in, fft_out, FFT_SIZE);
            find_flk_freq(fs, fft_out, &flk_freq, 1, FFT_SIZE);
            pos = 0; /* reset position index */

            printf("Flicker freq: %4lu Hzr", (unsigned long)flk_freq);
            fflush(stdout);

            if (is_autogain_requested == 1)
            {
              VD6283A1_LIGHT_SENSOR_StopFlicker(LIGHT_SENSOR_INSTANCE_0);

              flicker_autogain(LIGHT_SENSOR_INSTANCE_0, ¤t_gain, 1);
              printf("Channel %u gain set to", FLK_CHANNEL);
              display_gain(current_gain);

              VD6283A1_LIGHT_SENSOR_StartFlicker(LIGHT_SENSOR_INSTANCE_0, FLK_CHANNEL, LIGHT_SENSOR_FLICKER_ANALOG);
              is_autogain_requested = 0;
            }
        }

        handle_cmd(get_key());
    }

    als_adc_stop();

    VD6283A1_LIGHT_SENSOR_StopFlicker(LIGHT_SENSOR_INSTANCE_0);
    VD6283A1_LIGHT_SENSOR_DeInit(LIGHT_SENSOR_INSTANCE_0);

    printf("Quitting the demo...n");
    while (1);
}

在MX_X_CUBE_ALS_Process函数中开启频率获取函数,关闭光强获取函数MX_VD6283A1_LuxCCT_Process。

添加增益设置函数。

/*
 * @brief find and apply appropriate gain value depending on saturation value
 * @warning this function mustn't be called when a capture is ongoing
 */
static int32_t flicker_autogain(uint8_t Instance, uint32_t *pAppliedGain, uint32_t timeoutMs)
{
  int32_t res;
  uint8_t i, j;
  uint8_t idx = 7; /* start with mid-table value */
  const uint8_t sat_limit = 2;
  uint32_t saturation;

  /* duplicate 0x42AB to avoid 100x and keep multiples of 2 for array size */
  const uint16_t Gains[] = {
    0x42AB, 0x42AB, 0x3200, 0x2154, 0x1900, 0x10AB, 0x0A00, 0x0723,
    0x0500, 0x0354, 0x0280, 0x01AB, 0x0140, 0x0100, 0x00D4, 0x00B5
  };

  /* clip timeout value */
  timeoutMs = timeoutMs == 0 ? 1 : timeoutMs;
  timeoutMs = timeoutMs >= 100 ? 100 : timeoutMs;

  for (i = 0; i <= 3; i++)
  {
    VD6283A1_LIGHT_SENSOR_SetGain(Instance, FLK_CHANNEL, Gains[idx]);
    VD6283A1_LIGHT_SENSOR_GetGain(Instance, FLK_CHANNEL, pAppliedGain);

    res = VD6283A1_LIGHT_SENSOR_StartFlicker(Instance, FLK_CHANNEL, LIGHT_SENSOR_FLICKER_ANALOG);

    if (res)
      return res;

    /* read saturation value each ms so we can exit early if saturation detected */
    for (j = 0; j < timeoutMs; j++)
    {
      HAL_Delay(1);

      res = VD6283A1_LIGHT_SENSOR_GetSaturation(Instance, &saturation);

      if (res)
        return res;
      if (saturation > sat_limit)
        break;
    }

    res = VD6283A1_LIGHT_SENSOR_StopFlicker(Instance);

    if (res)
      return res;

    /* update index to next value */
    if (i)
      idx += saturation > sat_limit ? 1 < < (i - 1) : -(1 < < (i - 1));
    else if (saturation > sat_limit)
      idx++;
  }

  /* clip index if it reaches max value */
  if (idx > 15) 
    idx = 15;

  VD6283A1_LIGHT_SENSOR_SetGain(Instance, FLK_CHANNEL, Gains[idx]);
  res = VD6283A1_LIGHT_SENSOR_GetGain(Instance, FLK_CHANNEL, pAppliedGain);

  return res;
}

在下方添加函数的定义。

/*
 * @brief initilize arm rfft library
 */
static void init_fft(arm_rfft_fast_instance_f32 *instance, uint32_t size)
{
  arm_rfft_fast_init_f32(instance, size);
}

打印增益函数。

/*
 * @brief normalize, convert and dislay gain 
 */
static void display_gain(uint32_t gain)
{
    uint32_t g = (gain * 100) / 256;

    printf(" %3lu.%02lun", (unsigned long)g / 100, (unsigned long)(g % 100));
}

执行FFT。

/*
 * @brief perform fft on the input buffer using arm rfft library
 */
static void perform_fft(arm_rfft_fast_instance_f32 *instance, int16_t *flk, float32_t *ffti, float32_t *ffto, uint32_t size)
{
    uint32_t i;
    uint32_t index = 0;

    /* copy the ADC sampled signal into the fft input buffer
     * this allows to convert the data from int16_t to float32_t */
    for (i = 0; i < size; i++)
    {
        ffti[i] = flk[i];
    }

    /* Perform the FFT on the input buffer:
     * results are packed in a way so that even indexes contain real values
     * and odd indexes contain the complex value of each bin.
     * Therefore the fft_output array contains FFT_SIZE / 2 bins */
    arm_rfft_fast_f32(instance, ffti, fft_out_tmp, 0);

    /* Calculate the magnitude for each bin from the temp fft output buffer */
    for (i = 0; i < size; i += 2)
    {
        ffto[index] = complex_abs(fft_out_tmp[i], fft_out_tmp[i+1]);
        if (ffto[index] < 0) ffto[index] = 0;
        index++;
    }
}

查找峰值频率值。

/*
 * @brief find peak frequency value
 */
static void find_flk_freq(uint32_t fs, float32_t *ffto, uint32_t *freq, uint8_t skip_dc, uint32_t size)
{
    uint32_t i;
    uint32_t res;
    uint32_t index_max = 0;
    uint32_t limit = size / 2;

    float32_t max_value = -1;

    /* do not take account of the DC value if the flag skip_dc is set */
    skip_dc ? (i = 1) : (i = 0);

    /* run through the output array to detect the peak */
    for (; i < limit; i++)
    {
        if (ffto[i] > max_value)
        {
            index_max = i;
            max_value = ffto[i];
        }
    }

    /* convert index of the bin into frequency */
    res = (index_max * fs) / size;

    /* return the result if the pointer is valid */
    if (freq)
    {
        *freq = res;
    }
}

计算一个复数的绝对值。

/*
 * @brief compute absolute value of a complex number
 */
static float32_t complex_abs(float32_t real, float32_t complex)
{
  float32_t res;

  arm_sqrt_f32(real * real + complex * complex, &res);

  return res;
}

需要添加函数

arm_cortexM4lf_math.lib 库包含了一系列数学函数,特别是适用于基于Cortex-M4和Cortex-M7处理器的浮点运算单元的优化数学例程。这些例程涵盖了常见的数学运算,如信号处理、滤波、变换等。

arm_math.h 这个头文件包含了CMSIS-DSP库的函数声明、宏定义和结构体定义等,可以通过包含这个头文件,使用库中提供的各种数学函数,包括信号处理、滤波、变换等。

app_als_adc_utils.c功能主要包括启动和停止ADC采样,获取采样数据,ADC采样速度设置,以及处理相关的硬件中断。 app_als_adc_utils.h是app_als_adc_utils.c对应头文件。

演示结果

在1K光源下的测试情况。

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 光源
    +关注

    关注

    3

    文章

    652

    浏览量

    67527
  • 代码
    +关注

    关注

    30

    文章

    4618

    浏览量

    67474
  • 环境光传感器

    关注

    3

    文章

    99

    浏览量

    21823
收藏 人收藏

    评论

    相关推荐

    近似人眼感知的传感器——环境传感器

    近似人眼感知的传感器——环境传感器   电子发烧友网报道(文/李诚)环境
    的头像 发表于 10-29 09:33 8067次阅读

    VD6283TX环境传感器驱动开发(1)----获取ID

    环境传感器是一种光电探测,能够将转换为电压或者电流,使用多光谱环境
    的头像 发表于 12-01 16:05 412次阅读
    <b class='flag-5'>VD6283TX</b><b class='flag-5'>环境</b><b class='flag-5'>光</b><b class='flag-5'>传感器</b>驱动开发(1)----获取ID

    VD6283TX环境传感器驱动开发(2)----获取光强和色温

    为了更好地利用VD6283TX传感器的特点和功能,本章专门用于捕获光强度和相关色温值。VD6283TX,作为ST的高级色感,具有并行感测多个通道的能力,这使得它成为光强和色温测量的理
    的头像 发表于 12-01 16:08 408次阅读
    <b class='flag-5'>VD6283TX</b><b class='flag-5'>环境</b><b class='flag-5'>光</b><b class='flag-5'>传感器</b>驱动开发(<b class='flag-5'>2</b>)----获取光强和色温

    VD6283TX环境传感器驱动开发(3)----测试闪烁频率代码

    ST提供了6283A1_AnalogFlicker代码在X-NUCLEO-6283A1获取闪烁频率,同时
    的头像 发表于 12-01 16:14 367次阅读
    <b class='flag-5'>VD6283TX</b><b class='flag-5'>环境</b><b class='flag-5'>光</b><b class='flag-5'>传感器</b>驱动开发(3)----测试<b class='flag-5'>闪烁</b><b class='flag-5'>频率</b><b class='flag-5'>代码</b>

    VD6283TX环境传感器驱动开发(4)----移植闪烁频率代码

    光学闪烁被定义为人造光源的脉动或波动的现象。
    的头像 发表于 12-01 16:24 422次阅读
    <b class='flag-5'>VD6283TX</b><b class='flag-5'>环境</b><b class='flag-5'>光</b><b class='flag-5'>传感器</b>驱动开发(4)----<b class='flag-5'>移植</b><b class='flag-5'>闪烁</b><b class='flag-5'>频率</b><b class='flag-5'>代码</b>

    环境传感器的介绍

    很可能无法经受这样的环境。  数字输出传感器的内在优势包括高耐噪声能力、可通过I2C总线存取数据、可对传感器编程,还有其他诸多特性,使这些
    发表于 11-05 16:11

    基于蓝牙BLE的环境传感器方案

      在万物互联时代,传感器是其中最关键的组件之一。常见的传感器中,环境传感器常被应用于智能家居场景中,这种
    发表于 07-09 11:31

    如何选择一款环境传感器环境传感器有哪些应用?

    环境传感器的基本原理是什么?如何选择一款环境传感器环境
    发表于 05-12 07:24

    环境传感器是如何工作的

    当夜幕降临,汽车仪表盘上有一双“眼睛”默默地感知周围的光线,从而自动调节背光亮度,以保证用户最佳的驾驶体验且降低功耗。这双神奇的 “眼睛”便是今天的主角---环境传感器。为什么要使用环境
    发表于 11-10 07:16

    环境传感器应用

    在万物互联时代,传感器是其中最关键的组件之一。常见的传感器中,环境传感器常被应用于智能家居场景中,这种
    的头像 发表于 09-28 09:56 5432次阅读

    意法半导体发布了一款多光谱环境传感器VD6281

    意法半导体影像产品部门总经理Eric Aussedat表示:“VD6281是基于我们广博的相机系统知识开发出的一款非常先进的多光谱环境传感器,我们的
    发表于 02-22 14:30 4281次阅读

    digilentPmodALS:环境传感器介绍

    作为一个环境传感器,DigilentPmodALS可以用来演示到数字的传感
    的头像 发表于 12-02 11:25 2622次阅读
    digilentPmodALS:<b class='flag-5'>环境</b><b class='flag-5'>光</b><b class='flag-5'>传感器</b>介绍

    找方案 | 基于ST环境传感器VD6283TX 针对LED投影机光源调变方案

    由于目前LED投影机已经普遍为主流产品,但是由于LED本身会产生闪频,容易造成眼睛疲劳及伤害。因此本方案主要是利用ST新一代VD6283TX环境传感器,具有
    的头像 发表于 12-09 14:39 545次阅读
    找方案 | 基于ST<b class='flag-5'>环境</b><b class='flag-5'>光</b><b class='flag-5'>传感器</b><b class='flag-5'>VD6283TX</b> 针对LED投影机光源调变方案

    基于ST环境传感器VD6283TX 针对LED投影机光源调变方案

    本方案主要是利用ST新一代VD6283TX 环境传感器,具有环境
    的头像 发表于 11-21 17:25 664次阅读
    基于ST<b class='flag-5'>环境</b><b class='flag-5'>光</b><b class='flag-5'>传感器</b><b class='flag-5'>VD6283TX</b> 针对LED投影机光源调变方案

    VD6283TX环境传感器(1)----获取光强和色温

    为了充分利用VD6283TX传感器的特性和功能,本章节重点介绍了如何捕获光强度和相关色温值。作为ST公司推出的高级色彩感应VD6283TX具备同时感测多个频道的能力,这使它成为测量
    的头像 发表于 12-28 10:12 474次阅读
    <b class='flag-5'>VD6283TX</b><b class='flag-5'>环境</b><b class='flag-5'>光</b><b class='flag-5'>传感器</b>(1)----获取光强和色温