TencentOS-tiny 功耗管理 (二十 二)- tickless(低功耗)

2023-11-17

一、功耗管理

  1. tickless

概述

TencentOS tiny的tickless机制提供了一套非周期性时钟的方案,在系统无需systick驱动调度的情况下,停掉systick。

初级功耗管理方案下,因为还有系统systick的存在,因此系统进入idle任务后,并不会在睡眠模式下停留太久。要想进入到更极致的低功耗状态,需要暂停systick。

arm架构提供三级低功耗模式,sleep、stop、standby模式,三种模式运行功耗逐次降低,standby模式最低。TencentOS tiny的内核提供了简洁清晰的接口来管理各级模式。

API讲解

void tos_tickless_wkup_alarm_install(k_cpu_lpwr_mode_t mode, k_tickless_wkup_alarm_t *wkup_alarm);

此接口用以安装各低功耗模式下的唤醒闹钟。当内核进入tickless模式下后,systick以及停止了,因此需要其他计时器来将CPU从低功耗模式下唤醒。

根据arm v7m的芯片规格,三种模式下的唤醒源分别为:

  • sleep

    CPU进入sleep模式后,可以由systick、硬件timer、RTC时钟唤醒(wakeup/alarm中断)。

  • stop

    CPU进入stop模式后,可以由RTC时钟(wakeup/alarm中断)唤醒。

  • standby

    CPU进入standby模式后,只可由RTC时钟的alarm中断唤醒(还可以通过外部管脚唤醒,但这不属于TencentOS tiny内核机制设计的范畴)。

k_tickless_wkup_alarm_t定义如下:

typedef struct k_tickless_wakeup_alarm_st {
    int         (*init)(void);
    int         (*setup)(k_time_t millisecond);
    int         (*dismiss)(void);
    k_time_t    (*max_delay)(void); /* in millisecond */
} k_tickless_wkup_alarm_t;

一个唤醒闹钟有四个成员方法:

  • init

    闹钟初始化函数。

  • setup

    闹钟设定函数,入参为闹钟到期时间(单位毫秒)。此闹钟在设定完毕后的millisecond毫秒时来中断。

  • dismiss

    闹钟解除函数,执行完后闹钟中断不会再来。

  • max_delay

    此闹钟最长的到期时间(单位为毫秒)。

k_err_t tos_tickless_wkup_alarm_init(k_cpu_lpwr_mode_t mode);

此函数用来初始化特定模式下的唤醒闹钟(实际上调用的是tos_tickless_wkup_alarm_install接口中安装的k_tickless_wkup_alarm_t的init方法)。

k_err_t tos_pm_cpu_lpwr_mode_set(k_cpu_lpwr_mode_t cpu_lpwr_mode);

设置内核在tickless模式下进入的CPU低功耗模式。

编程实例

1、在tos_config.h中,配置低功耗组件开关TOS_CFG_PWR_MGR_EN:

#define TOS_CFG_PWR_MGR_EN 1u

2、在tos_config.h中,配置tickless组件开关TOS_CFG_TICKLESS_EN:

#define TOS_CFG_TICKLESS_EN 1u

3、STM32CubeMX修改libraries配置:

3、编写main.c示例代码:

/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "rtc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "cmsis_os.h" 
#include "stdio.h"

#include "tos_k.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define STK_SIZE_TASK_DEMO      512 

#define PRIO_TASK_DEMO          4
 
k_stack_t stack_task_demo[STK_SIZE_TASK_DEMO]; 

k_task_t task_demo;

extern void entry_task_demo(void *arg);

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */


/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
void timer_callback(void *arg)
{
    printf("timer callback: %ld\n", tos_systick_get());
}

void entry_task_demo(void *arg)
{
    k_timer_t tmr;

    // 创建一个软件定时器,每6000个tick触发一次
    tos_timer_create(&tmr, 0u, 6000u, timer_callback, K_NULL, TOS_OPT_TIMER_PERIODIC);
    tos_timer_start(&tmr);

    // 此任务体内每3000个tick运行一次
    while (K_TRUE) {
        printf("entry task demo: %ld\n", tos_systick_get());
        tos_task_delay(3000);
    }
}

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_TIM6_Init();
  MX_RTC_Init();
  /* USER CODE BEGIN 2 */
	
	tos_knl_init();
	(void)tos_task_create(&task_demo, "demo1", entry_task_demo, NULL,
                        PRIO_TASK_DEMO, stack_task_demo, STK_SIZE_TASK_DEMO, 0); 
  tos_knl_start();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		
  }
  /* USER CODE END 3 */
}

4、实现tos_bsp_tickless_setup回调,直接在源码中找到tickless文件夹,复制到工程项目根目录即可,路径为:board\TOS_tiny_EVK_STM32L431CBT6\BSP\Src\tickless,同时把board\TOS_tiny_EVK_STM32L431CBT6\BSP\Inc\tickless中.h文件复制到tickless文件夹即可。

修改如下所示:

5、rtc.c文件,新增__weak字段

6、tim.c文件,新增__weak字段

7、bsp_pwr_mgr.c文件

8、bsp_pm_device.c文件

9、bsp_tickless_alarm.c文件

#include "tos_k.h"

#include "stm32l0xx_hal.h"
#include "stm32l0xx_hal_tim.h"
#include "stm32l0xx_hal_rtc.h"

#if TOS_CFG_TICKLESS_EN > 0u

static void tickless_systick_suspend(void)
{
    cpu_systick_suspend();
    cpu_systick_pending_reset();
}

static void tickless_systick_resume(void)
{
    cpu_systick_resume();
}

static void tickless_systick_wkup_alarm_expires_set(k_time_t millisecond)
{
    cpu_systick_expires_set(millisecond);
}

static int tickless_systick_wkup_alarm_setup(k_time_t millisecond)
{
    tickless_systick_suspend();
    tickless_systick_wkup_alarm_expires_set(millisecond);
    tickless_systick_resume();
    return 0;
}

static int tickless_systick_wkup_alarm_dismiss(void)
{
    // TODO:
    // if not wakeup by systick(that's say another interrupt), need to identify this and fix
    return 0;
}

static k_time_t tickless_systick_wkup_alarm_max_delay(void)
{
    return cpu_systick_max_delay_millisecond();
}

k_tickless_wkup_alarm_t tickless_wkup_alarm_systick = {
    .init       = K_NULL,
    .setup      = tickless_systick_wkup_alarm_setup,
    .dismiss    = tickless_systick_wkup_alarm_dismiss,
    .max_delay  = tickless_systick_wkup_alarm_max_delay,
};


/
/

static TIM_HandleTypeDef tim6;

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *tim_handler)
{
    if (tim_handler->Instance == TIM6) {
        __HAL_RCC_TIM6_CLK_ENABLE();

        /* TIM6 interrupt Init */
        HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 0, 0);
        HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
    }
}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *tim_handler)
{
    if (tim_handler->Instance == TIM6) {
        /* Peripheral clock disable */
        __HAL_RCC_TIM6_CLK_DISABLE();

        /* TIM6 interrupt Deinit */
        HAL_NVIC_DisableIRQ(TIM6_DAC_IRQn);
    }
}

static int tickless_tim6_wkup_alarm_init(void)
{
    tim6.Instance = TIM6;
    tim6.Init.Prescaler = 0;
    tim6.Init.CounterMode = TIM_COUNTERMODE_UP;
    tim6.Init.Period = 0;
    tim6.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    tim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    HAL_TIM_Base_Init(&tim6);
    return 0;
}

static int tickless_tim6_wkup_alarm_setup(k_time_t millisecond)
{
    tim6.Init.Prescaler = 8000 - 1;
    tim6.Init.Period = (millisecond * 10) - 1;

    HAL_TIM_Base_Stop(&tim6);
    __HAL_TIM_CLEAR_IT(&tim6, TIM_IT_UPDATE);

    HAL_TIM_Base_Init(&tim6);
    HAL_TIM_Base_Start_IT(&tim6);
    return 0;
}

static int tickless_tim6_wkup_alarm_dismiss(void)
{
    TOS_CPU_CPSR_ALLOC();

    TOS_CPU_INT_DISABLE();

    HAL_TIM_Base_Stop(&tim6);
    HAL_TIM_Base_Stop_IT(&tim6);

    TOS_CPU_INT_ENABLE();
    return 0;
}

static k_time_t tickless_tim6_wkup_alarm_max_delay(void)
{
    k_time_t millisecond;
    uint32_t max_period;

    max_period = ~((uint32_t)0u);
    millisecond = (max_period - 1) / 10;
    return millisecond;
}

void TIM6_DAC_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&tim6);
}

k_tickless_wkup_alarm_t tickless_wkup_alarm_tim = {
    .init       = tickless_tim6_wkup_alarm_init,
    .setup      = tickless_tim6_wkup_alarm_setup,
    .dismiss    = tickless_tim6_wkup_alarm_dismiss,
    .max_delay  = tickless_tim6_wkup_alarm_max_delay,
};


/
/

static RTC_HandleTypeDef rtc_handler;

static HAL_StatusTypeDef tickless_rtc_time_set(uint8_t hour, uint8_t minu, uint8_t sec, uint8_t format)
{
    RTC_TimeTypeDef rtc_time;

    rtc_time.Hours = hour;
    rtc_time.Minutes = minu;
    rtc_time.Seconds = sec;
    rtc_time.TimeFormat = format;
    rtc_time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
    rtc_time.StoreOperation = RTC_STOREOPERATION_RESET;
    return HAL_RTC_SetTime(&rtc_handler, &rtc_time, RTC_FORMAT_BIN);
}

static HAL_StatusTypeDef tickless_rtc_date_set(uint8_t year, uint8_t month, uint8_t date, uint8_t week)
{
    RTC_DateTypeDef rtc_date;

    rtc_date.Date = date;
    rtc_date.Month = month;
    rtc_date.WeekDay = week;
    rtc_date.Year = year;
    return HAL_RTC_SetDate(&rtc_handler, &rtc_date, RTC_FORMAT_BIN);
}

static int tickless_rtc_wkup_alarm_init(void)
{
    rtc_handler.Instance = RTC;
    rtc_handler.Init.HourFormat = RTC_HOURFORMAT_24;
    rtc_handler.Init.AsynchPrediv = 0X7F;
    rtc_handler.Init.SynchPrediv = 0XFF;
    rtc_handler.Init.OutPut = RTC_OUTPUT_DISABLE;
    rtc_handler.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
    rtc_handler.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;

    if (HAL_RTC_Init(&rtc_handler) != HAL_OK) {
        return -1;
    }

    if (HAL_RTCEx_BKUPRead(&rtc_handler, RTC_BKP_DR0) != 0X5050) {
        tickless_rtc_time_set(23, 59, 56, RTC_HOURFORMAT12_PM);
        tickless_rtc_date_set(15, 12, 27, 7);
        HAL_RTCEx_BKUPWrite(&rtc_handler, RTC_BKP_DR0,0X5050);
    }

    return 0;
}

static int tickless_rtc_wkupirq_wkup_alarm_setup(k_time_t millisecond)
{
    uint32_t wkup_clock = RTC_WAKEUPCLOCK_CK_SPRE_16BITS;
    if (millisecond < 1000) {
        millisecond = 1000;
    }
    uint32_t wkup_count = (millisecond / 1000) - 1;

    __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&rtc_handler, RTC_FLAG_WUTF);

    HAL_RTCEx_SetWakeUpTimer_IT(&rtc_handler, wkup_count, wkup_clock);

    HAL_NVIC_SetPriority(RTC_IRQn, 0x02, 0x02);
    HAL_NVIC_EnableIRQ(RTC_IRQn);
    return 0;
}

static int tickless_rtc_wkupirq_wkup_alarm_dismiss(void)
{
#if defined(STM32F0) || defined(STM32L0)
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
#endif

    __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&rtc_handler, RTC_FLAG_WUTF);

    if (HAL_RTCEx_DeactivateWakeUpTimer(&rtc_handler) != HAL_OK) {
        return -1;
    }

    HAL_NVIC_DisableIRQ(RTC_IRQn);
    return 0;
}

static k_time_t tickless_rtc_wkupirq_wkup_alarm_max_delay(void)
{
    return 0xFFFF * K_TIME_MILLISEC_PER_SEC;
}

void HAL_RTC_MspInit(RTC_HandleTypeDef *rtc_handler)
{
    RCC_OscInitTypeDef rcc_osc;
    RCC_PeriphCLKInitTypeDef periph_clock;

    __HAL_RCC_PWR_CLK_ENABLE();
    HAL_PWR_EnableBkUpAccess();

    rcc_osc.OscillatorType = RCC_OSCILLATORTYPE_LSE;
    rcc_osc.PLL.PLLState = RCC_PLL_NONE;
    rcc_osc.LSEState = RCC_LSE_ON;
    HAL_RCC_OscConfig(&rcc_osc);

    periph_clock.PeriphClockSelection = RCC_PERIPHCLK_RTC;
    periph_clock.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
    HAL_RCCEx_PeriphCLKConfig(&periph_clock);

    __HAL_RCC_RTC_ENABLE();
}

void RTC_WKUP_IRQHandler(void)
{
    HAL_RTCEx_WakeUpTimerIRQHandler(&rtc_handler);
}

void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *rtc_handler)
{
}

k_tickless_wkup_alarm_t tickless_wkup_alarm_rtc_wkupirq = {
    .init       = tickless_rtc_wkup_alarm_init,
    .setup      = tickless_rtc_wkupirq_wkup_alarm_setup,
    .dismiss    = tickless_rtc_wkupirq_wkup_alarm_dismiss,
    .max_delay  = tickless_rtc_wkupirq_wkup_alarm_max_delay,
};



/
/
static int tickless_rtc_alarmirq_wkup_alarm_setup(k_time_t millisecond)
{
    uint8_t hour, minute, second, subsecond, date;

    RTC_AlarmTypeDef rtc_alarm;
    RTC_TimeTypeDef rtc_time;
    RTC_DateTypeDef rtc_date;

    HAL_RTC_GetTime(&rtc_handler, &rtc_time, RTC_FORMAT_BIN);
    HAL_RTC_GetDate(&rtc_handler, &rtc_date, RTC_FORMAT_BIN);

    hour = rtc_time.Hours;
    minute = rtc_time.Minutes;
    second = rtc_time.Seconds;
#if 0
    date = rtc_date.Date;
#else
    date = rtc_date.WeekDay;
#endif

    printf("before >>>  %d  %d %d %d\n", date, hour, minute, second);

    /* I know it's ugly, I will find a elegant way. Welcome to tell me, 3ks~ */
    second += millisecond / K_TIME_MILLISEC_PER_SEC;
    if (second >= 60) {
        minute += 1;
        second -= 60;
    }
    if (minute >= 60) {
        hour += 1;
        minute -= 60;
    }
    if (hour >= 24) {
        date += 1;
        hour -= 24;
    }

    printf("after >>>  %d  %d %d %d\n", date, hour, minute, second);

    rtc_alarm.AlarmTime.Hours = hour;
    rtc_alarm.AlarmTime.Minutes = minute;
    rtc_alarm.AlarmTime.Seconds = second;
    rtc_alarm.AlarmTime.SubSeconds = 0;
    rtc_alarm.AlarmTime.TimeFormat = RTC_HOURFORMAT12_AM;

    rtc_alarm.AlarmMask = RTC_ALARMMASK_NONE;
    rtc_alarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_NONE;
    rtc_alarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_WEEKDAY; // RTC_ALARMDATEWEEKDAYSEL_DATE; // RTC_ALARMDATEWEEKDAYSEL_WEEKDAY;
    rtc_alarm.AlarmDateWeekDay = date;
    rtc_alarm.Alarm = RTC_ALARM_A;
    HAL_RTC_SetAlarm_IT(&rtc_handler, &rtc_alarm, RTC_FORMAT_BIN);

/*
		//STM32L0系列没有Alarm中断线
    HAL_NVIC_SetPriority(RTC_Alarm_IRQn, 0x01, 0x02);
    HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
*/

    // __HAL_PWR_GET_FLAG(PWR_FLAG_WU)


    __HAL_RCC_AHB_FORCE_RESET();        //复位所有IO口
    __HAL_RCC_PWR_CLK_ENABLE();         //使能PWR时钟

    // __HAL_RCC_BACKUPRESET_FORCE();      //复位备份区域
    HAL_PWR_EnableBkUpAccess();         //后备区域访问使能

    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
    __HAL_RTC_WRITEPROTECTION_DISABLE(&rtc_handler);//关闭RTC写保护

    //关闭RTC相关中断
    __HAL_RTC_WAKEUPTIMER_DISABLE_IT(&rtc_handler,RTC_IT_WUT);
#if 0
    __HAL_RTC_TIMESTAMP_DISABLE_IT(&rtc_handler,RTC_IT_TS);
    __HAL_RTC_ALARM_DISABLE_IT(&rtc_handler,RTC_IT_ALRA|RTC_IT_ALRB);
#endif

    //清除RTC相关中断标志位
    __HAL_RTC_ALARM_CLEAR_FLAG(&rtc_handler,RTC_FLAG_ALRAF|RTC_FLAG_ALRBF);
    __HAL_RTC_TIMESTAMP_CLEAR_FLAG(&rtc_handler,RTC_FLAG_TSF);
    __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&rtc_handler,RTC_FLAG_WUTF);

    // __HAL_RCC_BACKUPRESET_RELEASE();                    //备份区域复位结束
    __HAL_RTC_WRITEPROTECTION_ENABLE(&rtc_handler);     	 //使能RTC写保护


#ifdef STM32F4
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);                  	 //清除Wake_UP标志
#endif

#ifdef STM32F7
    // __HAL_PWR_CLEAR_WAKEUP_FLAG(PWR_WAKEUP_PIN_FLAG1);  //清除Wake_UP标志
#endif

    // HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);           //设置WKUP用于唤醒

    return 0;
}

static int tickless_rtc_alarmirq_wkup_alarm_dismiss(void)
{
#if 1
    // __HAL_PWR_GET_FLAG(PWR_FLAG_WU);

    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

    // __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&rtc_handler, RTC_FLAG_ALRAF);

    __HAL_RTC_ALARM_CLEAR_FLAG(&rtc_handler, RTC_FLAG_ALRAF);

#if 0
    if (HAL_RTCEx_DeactivateWakeUpTimer(&rtc_handler) != HAL_OK) {
        return -1;
    }
#endif

//    HAL_NVIC_DisableIRQ(RTC_Alarm_IRQn);		//STM32L0系列没有Alarm中断线
    return 0;
#endif
}

static k_time_t tickless_rtc_alarmirq_wkup_alarm_max_delay(void)
{
    return 0xFFFF; // just kidding, I will fix it out. Welcome to tell me, 3ks~ */
}

void RTC_Alarm_IRQHandler(void)
{
    HAL_RTC_AlarmIRQHandler(&rtc_handler);
}

void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *rtc_handler)
{
}

k_tickless_wkup_alarm_t tickless_wkup_alarm_rtc_alarmirq = {
    .init       = tickless_rtc_wkup_alarm_init,
    .setup      = tickless_rtc_alarmirq_wkup_alarm_setup,
    .dismiss    = tickless_rtc_alarmirq_wkup_alarm_dismiss,
    .max_delay  = tickless_rtc_alarmirq_wkup_alarm_max_delay,
};

#endif

10、为了观察在tickless时是否确实没有systick中断,在tos_sys.c的idle任务体内加一句调试代码:

__STATIC__ void knl_idle_entry(void *arg)
{
    arg = arg; // make compiler happy

    while (K_TRUE) {
#if TOS_CFG_TASK_DYNAMIC_CREATE_EN > 0u
			// 这里在idle任务体内加上一句打印,如果systick正常开启,在没有用户任务运行时,此调试信息会不断打印;如果是tickless状态,此调试信息应该只会第一次进入idle任务时,或在用户任务等待到期,或用户的软件定时器到期时,才打印一次。
			  printf("idle entry: %ld\n", tos_systick_get());
        task_free_all();
#endif

#if TOS_CFG_PWR_MGR_EN > 0u
        pm_power_manager();
#endif
    }
}

11、运行效果:

源码链接:Git

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TencentOS-tiny 功耗管理 (二十 二)- tickless(低功耗) 的相关文章

随机推荐

  • 代码检视/代码审查/Code Review

    目录 一 代码检视的目的 二 代码检视前的准备 三 代码检视九句箴言 四 代码检视checklist 经验检查项 五 代码检视结果度量 六 代码质量衡量指标 七 高质量代码 一 代码检视的目的 代码检视是一种用来确认方案设计和代码实现的质量
  • Kotlin之高阶函数

    一 定义高阶函数 高阶函数和Lambda的关系密不可分 在Lambda编程的基础知识 使用的一些与集合相关的函数式API用法 如map filter函数等 又比如Kotlin的标准函数 如run apply函数等 这几个函数都有一个共同的特
  • 用python进行FamaMacBeth回归

    from linearmodels import FamaMacBeth import pandas as pd import numpy as np 生成所用面板数据集 该数据集在不同的日期有不同的个体 期望回归模型 Y 3 6 X1 4
  • 前端例程20221227:下雪动画

    演示 动图太大了不好上传 这里就放个静态图吧 实际上这里是雪花从上到下飘落的效果 代码
  • 分集 复用 多址

    1 分集 是在多条独立路径上传输相同的数据 接收端通过分集合并技术 抵抗信道衰落 提高传输可靠性 降低误码率 复用 是在多条独立路径上传输不同数据 充分利用系统资源 提高系统容量 即总数据率 2 分集 是一个信号通过多条路径送达接收端 好处
  • UVA-11212 编辑书稿 题解答案代码 算法竞赛入门经典第二版

    GitHub jzplp aoapc UVA Answer 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版 这道题目在书上的 迭代加深搜索 章节出现 即是采用迭代加深搜索的方法来做 但是咋一看题目 我认为用广度优先搜索也合适 因为题目要求
  • python爬虫系列X--小知识汇总

    X系列不针对专门技术 只是一些辅助 内容零散添加 1 为爬虫运行状态设置邮件提醒 使用python smtp email模块完成 from email mime text import MIMETextfrom email header i
  • 【第63篇】CSI-Net:统一的人体特征和姿态识别

    摘要 https arxiv org pdf 1810 03064 pdf 我们构建了CSI Net 一个统一的深度神经网络 DNN 来学习WiFi信号的表示 使用CSI Net 我们共同解决了两个身体特征问题 生物特征估计 包括身体脂肪
  • 【美国大学生数学建模比赛】2020C题(总结和原创参赛论文)百度云请自取

    最新想法 本学期选修了下大数据 发现其实本题的解法还涉及到数据库 大数据各个层次数据处理和分布式数据流blabla 而之前那几天美赛做的还停留在最基础的数据处理层 而且我现在觉得如果要做大的话不应该在这个层里面进行深度学习 前面的数据库处理
  • 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?实现 int sqrt(int x) 函数。

    今天我们来爬一爬楼梯 假设你正在爬楼梯 需要 n 阶你才能到达楼顶 每次你可以爬 1 或 2 个台阶 你有多少种不同的方法可以爬到楼顶呢 注意 给定 n 是一个正整数 示例 1 输入 2 输出 2 解释 有两种方法可以爬到楼顶 1 阶 1
  • 为啥 Python 运行速度这么慢 ?

    作者 Anthony Shaw 是 Python 软件基金会成员和 Apache 基金会成员 近来Python可谓人气骤升 这门编程语言用于开发运维 DevOps 数据科学 网站开发和安全 然而 它没有因速度而赢得任何奖牌 Java在速度方
  • javascript防抖(Debouncing)和节流阀(Throttling)

    中文原文链接 https jinlong github io 2016 04 24 Debouncing and Throttling Explained Through Examples 英文原文链接 https css tricks c
  • C++ 生命周期

    C 程序的生命周期要经过编码 Coding 预处理 Pre processing 编译 Compiling 和运行 Running 四个阶段 编码即coding阶段 这阶段主要是定义变量 写语句 实现各种数据结构 函数和类 预处理是 C C
  • Qt::带返回值的信号发射方式

    一般来说 我们发出信号使用emit这个关键字来操作 但是会发现 emit并不算一个调用 所以它没有返回值 那么如果我们发出这个信号想获取一个返回值怎么办呢 两个办法 1 通过出参形式返回 引用或者指针的方式带回 比如emit sig int
  • 【SHELL脚本】MYSQLDUMP备份数据库,含忽略数据表

    背景介绍 项目的数据库十分重要 必须保证数据不能丢失 项目组的数据库为mysql5 7 12 采用备份工具mysqldump 开发需求 备份指定多个数据库 部分数据库的部分数据表需要指定忽略 打包上传到go FastDFS文件管理器 下面为
  • jvm 内存分配

    1 任何对象都是以8字节为粒度进行对齐的 2 类属性按照如下优先级进行排列 长整型和双精度类型 8字节 整型和浮点型 4字节 字符和短整型 2字节 字符类型和布尔类型 1字节 最后时引用类型 3 不同类型继承关系类的成员不能混合排列 首先按
  • 程序员究竟还需要读书么?

    近来看了2篇和读书有关的文章 一篇提到Joel讲现在程序员不太读书了 主要靠在网上找各种参考资料 一篇则是马总说的 成功与情商有关 与读书多少关系不大 一定程度上这两个观点都有点道理 可以靠StackOverflow com和搜索引擎找到各
  • 1 FFmpeg从入门到精通-FFmpeg简介

    1 FFmpeg从入门到精通 FFmpeg简介 2 FFmpeg从入门到精通 FFmpeg工具使用基础 3 FFmpeg从入门到精通 FFmpeg转封装 4 FFmpeg从入门到精通 FFmpeg转码 5 FFmpeg从入门到精通 FFmp
  • 一个人开发APP系列之实战1 制作APP产品启动图标

    声明 写这个博客系列也是为了清晰思路 新手写的不好 请大神们指导指导 建议想学的还是先去android develops官网看看相关资料吧 好了 不闲扯了 进入正题 今天的目的是使用Android Studio自带的工具Image Asse
  • TencentOS-tiny 功耗管理 (二十 二)- tickless(低功耗)

    一 功耗管理 tickless 概述 TencentOS tiny的tickless机制提供了一套非周期性时钟的方案 在系统无需systick驱动调度的情况下 停掉systick 初级功耗管理方案下 因为还有系统systick的存在 因此系