9ceb218f80
Co-authored-by: Cursor <cursoragent@cursor.com>
485 lines
17 KiB
C
485 lines
17 KiB
C
/*!
|
||
\file spi3_charger.c
|
||
\brief SPI3 for A&B gun charger voltage acquisition and insulation detection
|
||
|
||
\version 2026-03-09, V1.4.0, firmware for GD32H7xx
|
||
*/
|
||
|
||
/*
|
||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||
|
||
Redistribution and use in source and binary forms, with or without modification,
|
||
are permitted provided that the following conditions are met:
|
||
|
||
1. Redistributions of source code must retain the above copyright notice, this
|
||
list of conditions and the following disclaimer.
|
||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||
this list of conditions and the following disclaimer in the documentation
|
||
and/or other materials provided with the distribution.
|
||
3. Neither the name of the copyright holder nor the names of its contributors
|
||
may be used to endorse or promote products derived from this software without
|
||
specific prior written permission.
|
||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||
OF SUCH DAMAGE.
|
||
*/
|
||
|
||
#include "adc_spi3_insuVolt.h"
|
||
#include <stdio.h>
|
||
#include "gd32h7xx.h"
|
||
#include "FreeRTOS.h"
|
||
#include "task.h"
|
||
#include "spi_if.h"
|
||
#include "sgm51652hx.h"
|
||
#include <string.h>
|
||
#include "sys_drv_init.h"
|
||
// ======== 配置 =========
|
||
#define NUM_CHS 4 //通道数:芯片1(CH0、CH1)+芯片2(CH0、CH1)
|
||
#define NUM_COLL 5 //每个通道采集次数
|
||
|
||
#define V_REF 4.096f //芯片基准电压
|
||
|
||
int16_t adc3_final[NUM_CHS][NUM_COLL];
|
||
//uint8_t dma_buf[ADC_CHANNELS][BYTES_PER_CH]; //临时接收缓存
|
||
|
||
/* 私有变量 */
|
||
static uint8_t spi3_initialized = 0;
|
||
static spi_dev_t spi3_dev1; // SPI3设备(A枪)
|
||
static spi_dev_t spi3_dev2; // SPI3设备(B枪)
|
||
static sgm51652hx_dev_t sgm51652hx_chip1; // 芯片1(A枪)
|
||
static sgm51652hx_dev_t sgm51652hx_chip2; // 芯片2(B枪)
|
||
|
||
/* 私有函数声明 */
|
||
static void spi3_gpio_config(void);
|
||
static void spi3_config(void);
|
||
|
||
/*!
|
||
\brief configure SPI3 GPIO peripheral for charger
|
||
\param[in] none
|
||
\param[out] none
|
||
\retval none
|
||
\note SPI3引脚配置 for SGM51652H4XTS38G/T:
|
||
- SPI3_CSA -> PA4 (A枪片选)
|
||
- SPI3_CSB -> PA3 (B枪片选)
|
||
- SPI3_SCK -> PE12 (时钟)
|
||
- SPI3_MISO -> PE13 (数据输入)
|
||
- SPI3_MOSI -> PE14 (数据输出)
|
||
*/
|
||
void spi3_gpio_config(void)
|
||
{
|
||
/* 使能GPIO时钟 */
|
||
rcu_periph_clock_enable(SPI3_RCU_CS);
|
||
rcu_periph_clock_enable(SPI3_RCU_SCK_MSIO);
|
||
|
||
/* 使能SPI3时钟 */
|
||
rcu_periph_clock_enable(RCU_SPI3);
|
||
|
||
/* 使能DMA时钟 */
|
||
// rcu_periph_clock_enable(RCU_DMA0);
|
||
// rcu_periph_clock_enable(RCU_DMAMUX);
|
||
|
||
/* 配置SPI3时钟源 */
|
||
rcu_spi_clock_config(IDX_SPI3, RCU_SPISRC_APB2); //RCU_SPISRC_PLL0Q
|
||
|
||
/* 配置A枪片选引脚 (PA4) - 软件控制 */
|
||
gpio_mode_set(SPI3_CS1_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SPI3_CS1_PIN);
|
||
gpio_output_options_set(SPI3_CS1_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, SPI3_CS1_PIN);
|
||
/* 默认拉高,不选中 */
|
||
SPI3_CS1_HIGH(); //gpio_bit_set(GPIOA, GPIO_PIN_4);
|
||
|
||
/* 配置B枪片选引脚 (PA3) - 软件控制 */
|
||
gpio_mode_set(SPI3_CS2_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SPI3_CS2_PIN);
|
||
gpio_output_options_set(SPI3_CS2_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, SPI3_CS2_PIN);
|
||
/* 默认拉高,不选中B枪 */
|
||
SPI3_CS2_HIGH(); //gpio_bit_set(GPIOA, GPIO_PIN_3);
|
||
|
||
/* 配置SPI3引脚复用功能 */
|
||
//spi_related_ios_af_en(SPI3); //SPI标准库函数,一键配置SPIx所有引脚复用(SCK/MOSI/MISO/NSS)lyn260401
|
||
gpio_af_set(GPIOE, GPIO_AF_5, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14);
|
||
|
||
/* 配置SCK引脚 (PE12) - 复用功能输出 */
|
||
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_12);
|
||
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_12);
|
||
|
||
/* 配置MISO引脚 (PE13) - 复用功能输入 */
|
||
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13);
|
||
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_13);
|
||
|
||
/* 配置MOSI引脚 (PE14) - 复用功能输出 */
|
||
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14);
|
||
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_14);
|
||
}
|
||
|
||
/*!
|
||
\brief configure SPI3 peripheral for charger
|
||
\param[in] none
|
||
\param[out] none
|
||
\retval none
|
||
\note SPI3基本配置,针对SGM51652H4XTS38G/T优化
|
||
*/
|
||
void spi3_config(void)
|
||
{
|
||
spi_parameter_struct spi_init_struct;
|
||
|
||
/* 去初始化SPI3 */
|
||
spi_i2s_deinit(SPI3);
|
||
|
||
/* 初始化SPI参数结构体 */
|
||
spi_struct_para_init(&spi_init_struct);
|
||
|
||
/* SPI3参数配置 for SGM51652H4XTS38G/T */
|
||
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; // 全双工模式
|
||
spi_init_struct.device_mode = SPI_MASTER; // 主模式
|
||
spi_init_struct.data_size = SPI_DATASIZE_8BIT; // 8位数据帧
|
||
spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_1EDGE; // 模式3,sgm51652只能工作在Model
|
||
spi_init_struct.nss = SPI_NSS_SOFT; // 软件NSS控制:soft-自己用GPIO控制CS1/CS2
|
||
spi_init_struct.prescale = SPI_PSC_32; // 分频系数,sgm51652最高时钟10Mhz~10Mhz,SPI3在APB2(300Mhz)
|
||
spi_init_struct.endian = SPI_ENDIAN_MSB; // MSB先行 sgm51652规定必须高位先传
|
||
|
||
/* 初始化SPI3 */
|
||
spi_init(SPI3, &spi_init_struct);
|
||
|
||
/* 使能字节访问 */
|
||
spi_byte_access_enable(SPI3);
|
||
|
||
/* 使能NSS输出 (兼容性) */
|
||
spi_nss_output_enable(SPI3);
|
||
}
|
||
|
||
|
||
#if 0 //DMA相关配置,未调通 lyn20260410
|
||
/*!
|
||
\brief configure the DMA peripheral
|
||
\param[in] none
|
||
\param[out] none
|
||
\retval none
|
||
*/
|
||
void adc_read_single(uint8_t chip, uint8_t cmd, uint8_t index)
|
||
{
|
||
dma_single_data_parameter_struct dma_init_struct;
|
||
uint8_t buf[2];
|
||
|
||
//选中芯片
|
||
if(chip == CHIP_1)
|
||
{
|
||
SPI3_CS1_LOW();
|
||
SPI3_CS2_HIGH();
|
||
}
|
||
else
|
||
{
|
||
SPI3_CS2_LOW();
|
||
SPI3_CS1_HIGH();
|
||
}
|
||
|
||
//DMA配置
|
||
/* deinitialize DMA registers of a channel */
|
||
dma_deinit(DMA0, DMA_CH0);
|
||
|
||
dma_single_data_para_struct_init(&dma_init_struct);
|
||
|
||
/* SPI0 receive DMA config: DMA_CH0 */
|
||
dma_init_struct.request = DMA_REQUEST_SPI3_RX; //选哪个外设:SPI3-RX
|
||
dma_init_struct.periph_addr = (uint32_t)&SPI_RDATA(SPI3); //外设地址:SPI3
|
||
dma_init_struct.periph_inc = DMA_MEMORY_INCREASE_DISABLE; //禁止外设自增
|
||
dma_init_struct.memory0_addr = (uint32_t)buf; //内存地址:定义的数组
|
||
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; //内存地址自增
|
||
dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT; //数据位宽:8/16/32位
|
||
dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_ENABLE; //是否循环模式:是
|
||
dma_init_struct.direction = DMA_PERIPH_TO_MEMORY; //方向:外设->内存
|
||
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH; //优先级
|
||
dma_init_struct.number = 2; //SPI一次DMA收多少字节,与数据位宽对应 1路ADC=2字节
|
||
|
||
dma_single_data_mode_init(DMA0, DMA_CH0, &dma_init_struct); //初始化
|
||
|
||
/* enable DMA channel */
|
||
dma_channel_enable(DMA0, DMA_CH0);
|
||
|
||
//开启SPI3 DMA接收
|
||
spi_dma_enable(SPI3, SPI_DMA_RECEIVE);
|
||
#if 0
|
||
//发通道命令 = 软件启动转换
|
||
if(spi3_charger_read_data(CHARGER_GUN_A, cmd, data, 2) != 0) {
|
||
return -1.0f;
|
||
}
|
||
|
||
//等待DMA完成
|
||
// 等待 DMA 完成
|
||
while(!dma_flag_get(DMA0, DMA_CH0, DMA_INTF_FTFIF));
|
||
dma_flag_clear(DMA0, DMA_CH0, DMA_INTF_FTFIF);
|
||
|
||
// 关闭
|
||
spi_dma_disable(SPI3, SPI_DMA_RECEIVE);
|
||
dma_channel_disable(DMA0, DMA_CH0);
|
||
|
||
SPI3_CS1_HIGH();
|
||
SPI3_CS2_HIGH();
|
||
|
||
// 合并 16 位 ADC 数据
|
||
adc_result[index] = (int16_t)(buf[0] << 8 | buf[1]);
|
||
#endif
|
||
}
|
||
#endif
|
||
/*!
|
||
\brief SPI3完整初始化 for charger
|
||
\param[in] none
|
||
\param[out] none
|
||
\retval 0: 成功, -1: 失败
|
||
\note 专门为A&B枪充电电压采集和绝缘检测优化
|
||
*/
|
||
int adc_spi3_insuVolt_init(void)
|
||
{
|
||
if(spi3_initialized) {
|
||
return 0; // 已初始化
|
||
}
|
||
|
||
/* 配置GPIO */
|
||
spi3_gpio_config();
|
||
|
||
/* 配置SPI外设 */
|
||
spi3_config();
|
||
|
||
/* 使能SPI3 */
|
||
spi_enable(SPI3);
|
||
|
||
/* 初始化SPI设备。注意:芯片1/2使用不同的片选引脚,需要单独处理*/
|
||
/* 初始化芯片1(A枪) */
|
||
spi_init_dev(&spi3_dev1, SPI3, GPIOA, GPIO_PIN_4, 0, 0);
|
||
sgm51652hx_init(&sgm51652hx_chip1, &spi3_dev1);
|
||
|
||
/* 初始化芯片2(B枪) */
|
||
spi_init_dev(&spi3_dev2, SPI3, GPIOA, GPIO_PIN_3, 0, 0);
|
||
sgm51652hx_init(&sgm51652hx_chip2, &spi3_dev2);
|
||
|
||
/* 设置通道量程 */
|
||
for (uint8_t i = 0; i < 2; i++) {
|
||
sgm51652hx_set_range(&sgm51652hx_chip1, i, RGVL_BP_256); // ±2.56V
|
||
sgm51652hx_set_range(&sgm51652hx_chip2, i, RGVL_BP_256); // ±2.56V
|
||
}
|
||
|
||
spi3_initialized = 1;
|
||
return 0;
|
||
}
|
||
|
||
/*!
|
||
\brief SPI3去初始化
|
||
\param[in] none
|
||
\param[out] none
|
||
\retval none
|
||
*/
|
||
void adc_spi3_batVoltCurr_deinit(void)
|
||
{
|
||
/* 去初始化芯片 */
|
||
sgm51652hx_deinit(&sgm51652hx_chip1);
|
||
sgm51652hx_deinit(&sgm51652hx_chip2);
|
||
|
||
/* 去初始化SPI设备 */
|
||
spi_deinit_dev(&spi3_dev1);
|
||
spi_deinit_dev(&spi3_dev2);
|
||
|
||
/* 禁用SPI3 */
|
||
spi_disable(SPI3);
|
||
|
||
/* 去初始化SPI3 */
|
||
spi_i2s_deinit(SPI3);
|
||
|
||
/* 所有片选拉高 */
|
||
gpio_bit_set(GPIOA, GPIO_PIN_3);
|
||
gpio_bit_set(GPIOA, GPIO_PIN_4);
|
||
|
||
spi3_initialized = 0;
|
||
}
|
||
/*
|
||
函数功能:将MCU通过SPI接收到的数据转换为控制器端口采到的电压
|
||
输入: uint16_t read_data MCU通过SPI接收到的数据
|
||
uint8_t adc_zf 正负极区分,0正极,1负级
|
||
uint8_t flag 绝缘检测光电继电器闭合标志位,0:未闭合,1:已经闭合
|
||
float data 转换后的电压
|
||
备注:V_REF:芯片基准电压
|
||
芯片采集到的电压计算方式:
|
||
每个LSB代表的电压值 = 芯片输入范围(±0.625,即0.625 * 2) * 基准电压(V_REF) / 2^16;
|
||
ADC读到的电压值 = 每个LSB代表的电压值 * read_data;
|
||
0V对应点ADC读到电压值为0.625 * V_REF,ADC读到的电压值减去 0.625 * V_REF即为当前芯片采集电压值。
|
||
芯片采集到电压到控制器端口采集电压转换关系如下:
|
||
绝缘检测光电继电器闭合前:控制器端口电压 = 芯片采集电压值 * 1376.89/(0.625 *V_REF)
|
||
绝缘检测光电继电器闭合后:控制器端口电压:
|
||
正极电压 = 芯片采集电压值 * 689 /(0.625 *V_REF)
|
||
负极电压 = 芯片采集电压值 * 1380 /(0.625 *V_REF)
|
||
*/
|
||
float f_read_to_Vol(float read_data, uint8_t adc_zf, uint8_t flag)
|
||
{
|
||
float data = 0.0f;
|
||
|
||
//data = chip_volt; //等同于gm51652hx_calc_voltage(raw_value, RGVL_BP_256)
|
||
data = (0.625f * 2.0f * V_REF * read_data / 65535.0f) - (0.625f * V_REF);
|
||
|
||
if(flag == 0)
|
||
{
|
||
data = data * 1376.89f / (0.625f * V_REF);
|
||
}
|
||
else
|
||
{
|
||
if(adc_zf == 0) //正负极计算方式不同,分开计算
|
||
{
|
||
data = data * 689.0f / (0.625f * V_REF);
|
||
}
|
||
else
|
||
{
|
||
data = data * 1380.0f / (0.625f * V_REF);
|
||
}
|
||
}
|
||
|
||
return data;
|
||
}
|
||
|
||
//==================== 单通道读取 (核心函数) ====================
|
||
uint16_t sgm51652hx_spiReadBytes(uint8_t chip, uint8_t channel) //读取芯片chip通道channel的返回原始ADC值
|
||
{
|
||
uint16_t raw_value = 0;
|
||
sgm51652hx_dev_t *dev = NULL;
|
||
|
||
if(chip == CHIP_1)
|
||
dev = &sgm51652hx_chip1; //芯片1-A枪绝缘电压检测
|
||
else
|
||
dev = &sgm51652hx_chip2; //芯片2-B枪绝缘电压检测
|
||
|
||
/* 设置通道量程(TBD:上电初始化设置一次就行,还是需要每次发送都要设置?) */
|
||
//sgm51652hx_set_range(dev, channel, RGVL_BP_256);
|
||
|
||
/* 读取原始值 */
|
||
if(sgm51652hx_read_channel(dev, channel, &raw_value) != ERR_OK_SGM)
|
||
return 0;
|
||
|
||
//printf("spi3 chip=%d,channel=%d: %d\n", chip, channel, raw_value);
|
||
|
||
return raw_value;
|
||
}
|
||
|
||
/*
|
||
函数功能:获取指定控制器端口采集电压
|
||
输入:uint8_t chip 芯片号,等同于枪号,1 对应A枪,2 对应B枪
|
||
uint8_t channel 通道号,等同于正负级,channel_0对应正极,channel_1对应负级
|
||
uint8_t relayOnOff 绝缘检测光电继电器闭合标志位,0:未闭合,1:已经闭合
|
||
*/
|
||
float spi3_read_analog_voltage(uint8_t chip, uint8_t channel)
|
||
{
|
||
uint16_t raw_value[NUM_COLL] = {0};
|
||
uint16_t i = 0, j = 0;
|
||
uint32_t raw_sum_avg = 0;
|
||
uint8_t relayOnOff;
|
||
|
||
float real_voltage = 0;
|
||
if(chip == 1)
|
||
relayOnOff = GUN1_INS_KM_READ;
|
||
else
|
||
relayOnOff = GUN2_INS_KM_READ;
|
||
// printf("chip = %d,relayOnOff = %d\n",chip,relayOnOff);
|
||
//读取指定端口与通道数据NUM_COLL次
|
||
for(i=0; i<NUM_COLL; i++)
|
||
raw_value[i] = sgm51652hx_spiReadBytes(chip, channel);
|
||
|
||
for(j=0; j<NUM_COLL; j++)
|
||
raw_sum_avg += raw_value[j];
|
||
raw_sum_avg /= NUM_COLL;
|
||
|
||
/* 转换为芯片引脚电压值 --> 融合进f_read_to_vol() */
|
||
//chip_voltage = sgm51652hx_calc_voltage(raw_sum_avg, RGVL_BP_256);
|
||
#if 1
|
||
/* 根据绝缘回路,将芯片引脚电压转换为控制器端口电压数据 */
|
||
real_voltage = f_read_to_Vol(raw_sum_avg, channel, relayOnOff); //TODO: 参考DCU606
|
||
|
||
if(channel == 1) //通道1-负级
|
||
real_voltage = -real_voltage;
|
||
|
||
if(relayOnOff == 0) //光电继电器闭合标志,闭合前后,数据分开校准
|
||
{
|
||
if(channel == 0) //校准系数
|
||
{
|
||
real_voltage = real_voltage / 1000 * 993; //997(100欧/V);300V-990 ,400V-997 ,500V-997 ,600V-
|
||
//997(500欧/V);400V-997
|
||
}
|
||
else if(channel == 1)
|
||
{
|
||
real_voltage = real_voltage / 1000 * 997; //1004(100欧/V);300V-1007 ,500V-
|
||
//1004(500欧/V);400V-1007 ,
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if(channel == 0) //校准系数
|
||
{
|
||
real_voltage = real_voltage / 1000 * 998; //997(100欧/V);300V-990 ,400V-997 ,500V-997 ,600V
|
||
//997(500欧/V);400V-997
|
||
}
|
||
else if(channel == 1)
|
||
{
|
||
real_voltage = real_voltage / 1000 * 995; //1004(100欧/V);300V-1007 ,500V-
|
||
//1004(500欧/V);400V-1007 ,
|
||
}
|
||
}
|
||
#endif
|
||
// printf("SPI3 chip(%d)-channel(%d): raw=%d, realU=%.2f \n", chip, channel, raw_sum_avg, real_voltage);
|
||
return real_voltage;
|
||
}
|
||
|
||
//==================== 读取全部4通道 - TODO:改为对应用层接口函数 ====================
|
||
void sgm51652_read_all_channels(void)
|
||
{
|
||
float adc_result[4] = {0};
|
||
|
||
// 芯片1 CH0
|
||
adc_result[0] = spi3_read_analog_voltage(CHIP_1, CHNL_0);
|
||
|
||
// 芯片1 CH1
|
||
adc_result[1] = spi3_read_analog_voltage(CHIP_1, CHNL_1);
|
||
|
||
// 芯片2 CH0
|
||
adc_result[2] = spi3_read_analog_voltage(CHIP_2, CHNL_0);
|
||
|
||
// 芯片2 CH1
|
||
adc_result[3] = spi3_read_analog_voltage(CHIP_2, CHNL_1);
|
||
(void)adc_result;
|
||
}
|
||
|
||
/*!
|
||
\brief 充电器自检
|
||
\param[in] none
|
||
\param[out] none
|
||
\retval 0: 正常, -1: 故障
|
||
*/
|
||
void spi3_charger_self_test(void)
|
||
{
|
||
printf("spi3 adc-insuvolt test started...\n");
|
||
|
||
/* 检查SPI3初始化状态 */
|
||
if(!spi3_initialized) {
|
||
printf("SPI3 not initialized\n");
|
||
return;
|
||
}
|
||
|
||
// spi3_charger_write_command(1, 0, 0, 0);
|
||
//
|
||
// vTaskDelay(50);
|
||
// spi3_charger_read_command(1, 0, 0, 0);
|
||
|
||
while(1)
|
||
{
|
||
//sgm51652hx_spiReadBytes(1, 0);
|
||
//spi3_read_analog_voltage(1, 0, 5);
|
||
// spi3_charger_read_data_A_0(); //
|
||
sgm51652_read_all_channels();
|
||
|
||
vTaskDelay(250);
|
||
}
|
||
}
|
||
|
||
|
||
|