閃爍定義
光學(xué)閃爍被定義為人造光源的脈動(dòng)或波動(dòng)的光現(xiàn)象。
在低頻閃爍中,光是可見的(人眼能夠察覺光的閃爍)。超過100 Hz的光學(xué)閃爍對(duì)于人眼來(lái)說不再可見,但仍然存在,可能對(duì)人體產(chǎn)生影響。
大多數(shù)類型的人造光源在連接到電力主網(wǎng)(家庭或商業(yè)辦公室)時(shí)會(huì)發(fā)出閃爍,這主要取決于國(guó)家的電力頻率,通常是50 Hz或60 Hz。
由于電流在光源中的交替流動(dòng),所有人造光源都會(huì)分別在50 Hz和60 Hz電力主網(wǎng)下發(fā)出100 Hz或120 Hz的閃爍頻率。
為了消除可見的閃爍并減少對(duì)人體的影響,大多數(shù)發(fā)光二極管(LED)使用脈沖寬度調(diào)制(PWM)調(diào)光方法,以實(shí)現(xiàn)更高的閃爍頻率。
VD6283傳感器可以檢測(cè)光的閃爍頻率,最高可達(dá)2 kHz。
最近在弄ST的課程,需要樣片的可以加群申請(qǐng):615061293 。
視頻教學(xué)
https://www.bilibili.com/video/BV1Fh4y1r7AS/
樣品申請(qǐng)
https://www.wjx.top/vm/OhcKxJk.aspx#px#)
源碼下載
https://download.csdn.net/download/qq_24312945/88394817
開發(fā)板設(shè)置
在手冊(cè)種給出了,閃爍手冊(cè)可以查看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手冊(cè)中,需要對(duì)SB3進(jìn)行連接。
查看X-NUCLEO-6283A1手冊(cè),可以看到VD6283TX的GPIO2連接到MCU的ADC端口0-2。
在VD6283TX-SATEL中,可以看到VD6283TX通過SB3連接到了AFLR_1V8。
需要將AFLR_1V8接到開發(fā)板的A0端口中。
開發(fā)板選擇
這里使用NUCLEO-F401RE 開發(fā)板。
IIC配置
串口配置
開啟X-CUBE-ALS軟件包
時(shí)鐘樹配置
ADC使用定時(shí)器觸發(fā)采樣
在app_als_adc_utils.c中,定義了ADC使用的頻率,為8000Hz。
定時(shí)器的arr設(shè)置為10500-1,那么定時(shí)器頻率為8000Hz。
Trigger Event Selection :update event 定時(shí)器自動(dòng)更新。
配置ADC檢測(cè)VD6283TX的GPIO2管腳的AD值。
設(shè)置觸發(fā)方式為外部觸發(fā),選擇剛剛配置的TIM2,觸發(fā)方式為上升沿觸發(fā)。
開啟中斷。
KEIL配置
FFT代碼配置
arm_cortexM4lf_math.lib 庫(kù)包含了一系列數(shù)學(xué)函數(shù),特別是適用于基于Cortex-M4和Cortex-M7處理器的浮點(diǎn)運(yùn)算單元的優(yōu)化數(shù)學(xué)例程。這些例程涵蓋了常見的數(shù)學(xué)運(yùn)算,如信號(hào)處理、濾波、變換等。
arm_math.h 這個(gè)頭文件包含了CMSIS-DSP庫(kù)的函數(shù)聲明、宏定義和結(jié)構(gòu)體定義等,可以通過包含這個(gè)頭文件,使用庫(kù)中提供的各種數(shù)學(xué)函數(shù),包括信號(hào)處理、濾波、變換等。
添加arm_cortexM4lf_math.lib文件。
同時(shí)導(dǎo)入arm_math.h文件。
app_x-cube-als.c
由于需要進(jìn)行FFT算法,所以需要添加對(duì)應(yīng)數(shù)學(xué)頭文件。
#define ARM_MATH_CM4
#include "arm_math.h"
#include "app_als_adc_utils.h"
添加對(duì)應(yīng)的函數(shù)申明。
#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()函數(shù)中添加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);
}
}
初始化完畢之后,添加頻率獲取函數(shù)。
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函數(shù)中開啟頻率獲取函數(shù),關(guān)閉光強(qiáng)獲取函數(shù)MX_VD6283A1_LuxCCT_Process。
添加增益設(shè)置函數(shù)。
/*
* @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;
}
在下方添加函數(shù)的定義。
/*
* @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);
}
打印增益函數(shù)。
/*
* @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));
}
執(zhí)行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;
}
}
計(jì)算一個(gè)復(fù)數(shù)的絕對(duì)值。
/*
* @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;
}
需要添加函數(shù)
arm_cortexM4lf_math.lib 庫(kù)包含了一系列數(shù)學(xué)函數(shù),特別是適用于基于Cortex-M4和Cortex-M7處理器的浮點(diǎn)運(yùn)算單元的優(yōu)化數(shù)學(xué)例程。這些例程涵蓋了常見的數(shù)學(xué)運(yùn)算,如信號(hào)處理、濾波、變換等。
arm_math.h 這個(gè)頭文件包含了CMSIS-DSP庫(kù)的函數(shù)聲明、宏定義和結(jié)構(gòu)體定義等,可以通過包含這個(gè)頭文件,使用庫(kù)中提供的各種數(shù)學(xué)函數(shù),包括信號(hào)處理、濾波、變換等。
app_als_adc_utils.c功能主要包括啟動(dòng)和停止ADC采樣,獲取采樣數(shù)據(jù),ADC采樣速度設(shè)置,以及處理相關(guān)的硬件中斷。
app_als_adc_utils.h是app_als_adc_utils.c對(duì)應(yīng)頭文件。
審核編輯:湯梓紅
-
光強(qiáng)傳感器
+關(guān)注
關(guān)注
0文章
6瀏覽量
12741 -
代碼
+關(guān)注
關(guān)注
30文章
4788瀏覽量
68603 -
環(huán)境光傳感器
+關(guān)注
關(guān)注
3文章
108瀏覽量
21912 -
驅(qū)動(dòng)開發(fā)
+關(guān)注
關(guān)注
0文章
130瀏覽量
12077
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論