打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Cron表达式使用格式

SecondsMinutesHoursDayofMonth MonthDayofWeek[Year]

每个符号代表的含义:

  1. :匹配该域的任意值;如用在分所在的域,表示每分钟都会触发事件。
  2. ?:匹配该域的任意值。
  3. -:匹配一个特定的范围值;如时所在的域的值是10-12,表示10、11、12点的时候会触发事件。
  4. ,:匹配多个指定的值;如周所在的域的值是2,4,6,表示在周一、周三、周五就会触发事件(1表示周日,2表示周一,3表示周二,以此类推,7表示周六)。
  5. /:左边是开始触发时间,右边是每隔固定时间触发一次事件,如秒所在的域的值是5/15,表示5秒、20秒、35秒、50秒的时候都触发一次事件。
  6. L:last,最后的意思,如果是用在天这个域,表示月的最后一天,如果是用在周所在的域,如6L,表示某个月最后一个周五。(外国周日是星耀日,周一是月耀日,一周的开始是周日,所以1L=周日,6L=周五。)
  7. W:weekday,工作日的意思。如天所在的域的值是15W,表示本月15日最近的工作日,如果15日是周六,触发器将触发上14日周五。如果15日是周日,触发器将触发16日周一。如果15日不是周六或周日,而是周一至周五的某一个,那么它就在15日当天触发事件。
  8. #:用来指定每个月的第几个星期几,如6#3表示某个月的第三个星期五。

CMakeLists.txt 增加 add_definitions(-DCRON_USE_LOCAL_TIME)

/********************************************************************************
 * @file    appointment.cpp
 * @author  jianqiang.xue
 * @version V1.0.0
 * @date    2022-04-24
 * @brief   https://docs.espressif.com/projects/esp-idf/zh_CN/v4.3.1/esp32/api-reference/system/system_time.html
 * 			https://blog.csdn.net/qq_41741344/article/details/120117151
 ********************************************************************************/
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <sys/time.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

extern "C"
{
#include "cron.h"
#include "jobs.h"
}

#include "esp_log.h"
#include "appointment.h"

#define MAX_NUM 5

namespace appointment
{
	static const char TAG[] = "appointment";
	static cron_job *_jobs[MAX_NUM * 2];
	static AppoEntry _appoentry[MAX_NUM];
	static uint8_t _valid_num = 0;
	static bool _cb_state = 0; // 0 -- 未充电     1 -- 充电中

	static void _task_start_cb_callback(cron_job *job)
	{
		if (!_cb_state)
		{
			//start_cb();
			_cb_state = true;
		}
		ESP_LOGD(TAG, "task_start_cb_callback");
	}

	static void _task_stop_cb_callback(cron_job *job)
	{
		if (_cb_state)
		{
			//stop_cb();
			_cb_state = false;
		}
		ESP_LOGD(TAG, "task_stop_cb_callback");
	}

	void set(AppoEntry *entries, uint8_t num)
	{
		uint8_t buff[20] = {0};
		if (num > MAX_NUM || num == 0)
		{
			return;
		}
		memcpy(&_appoentry[0], entries, sizeof(AppoEntry) * num);

		cron_stop();
		cron_job_clear_all();

		for (uint8_t i = 0; i < num * 2; i += 2)
		{
			sprintf((char *)buff, "0 %02d %02d * * *",
			        (uint8_t)(_appoentry[i/2].start_cron & 0x00ff), (uint8_t)(_appoentry[i/2].start_cron >> 8));
			ESP_LOGD(TAG, "s buff:%s\n", buff);
			_jobs[i] = cron_job_create((const char *)buff, _task_start_cb_callback, NULL);

			sprintf((char *)buff, "0 %02d %02d * * *",
			         (uint8_t)_appoentry[i/2].stop_cron & 0x00ff, (uint8_t)(_appoentry[i/2].stop_cron >> 8));
			ESP_LOGD(TAG, "e buff:%s\n", buff);
			_jobs[i + 1] = cron_job_create((const char *)buff, _task_stop_cb_callback, NULL);
		}
		_valid_num = num;
		cron_start();
	}

	void get(AppoEntry *entries, uint8_t num)
	{
		if (num >= _valid_num || num == 0)
		{
			return;
		}
		memcpy(entries, &_appoentry[0], sizeof(AppoEntry) * num);
	}

	void clear()
	{
		cron_stop();
		cron_job_clear_all();
		memset(&_appoentry[0], 0, sizeof(AppoEntry) * MAX_NUM);
		_valid_num = 0;
	}

	static void set_time(int sc, int mn, int hr, int dy, int mt, int yr)
	{
		// seconds, minute, hour, day, month, year $ microseconds(optional)
		// ie setTime(20, 34, 8, 1, 4, 2021) = 8:34:20 1/4/2021
		struct tm t;		   // Initalize to all 0's
		t.tm_year = yr - 1900; // This is year-1900, so 121 = 2021
		t.tm_mon  = mt - 1;
		t.tm_mday = dy;
		t.tm_hour = hr;
		t.tm_min  = mn;
		t.tm_sec  = sc;
		time_t time_since_epoch = mktime(&t);
		struct timeval now;
		now.tv_sec = time_since_epoch;
		settimeofday(&now, NULL);
		ESP_LOGD(TAG, "set_time:%ld\n", time_since_epoch);
	}
}

extern "C" void app_main(void)
{
	// 后期需要根据当前地区,设置时区!!!
	setenv("TZ", "CST-8", 1);
	tzset();
	//预设时间,后期联网,通过esp_sntp.h,同步实时时间。
	appointment::set_time(55, 29, 12, 24, 4, 2022);
	appointment::AppoEntry appoentry[MAX_NUM];
	// 测试验证
	appoentry[0].start_cron = 12 << 8 | 30;
	appoentry[0].stop_cron  = 12 << 8 | 31;

	appoentry[1].start_cron = 12 << 8 | 32;
	appoentry[1].stop_cron  = 12 << 8 | 33;

	appoentry[2].start_cron = 12 << 8 | 34;
	appoentry[2].stop_cron  = 12 << 8 | 35;
	appointment::set(&appoentry[0], 3);
	ESP_LOGD("main", "time\n");
	while (1)
	{
		vTaskDelay(1000 / portTICK_PERIOD_MS);
	}
}


实用的例子 表达式 含义

  • “0 0 12 * * ?” 每天12:00触发事件
  • “0 15 10 ? * *” 每天10:15触发事件
  • “0 15 10 * * ?” 每天10:15触发事件
  • “0 15 10 * * ? *” 每天10:15触发事件
  • “0 15 10 * * ? 2005″ 2005年的每天10:15触发事件
  • “0 * 14 * * ?” 每天14点开始触发,每分钟触发一次,14:59分结束
  • “0 0/5 14 * * ?” 每天14点开始触发到14:59分结束的每5分钟触发一次事件
  • “0 0/5 14,18 * * ?” 每天14点开始到14:59期间和18点到18:59期间的每5分钟触发一次事件
  • “0 0-5 14 * * ?” 每天14点到14:05期间的每1分钟触发一次事件
  • “0 10,44 14 ? 3 WED” 每年3月的星期三的14:10和14:44触发一次事件
  • “0 15 10 ? * MON-FRI” 周一至周五的10:15触发一次事件
  • “0 15 10 15 * ?” 每月15日10:15触发一次事件
  • “0 15 10 L * ?” 每月最后一日的10:15触发一次事件
  • “0 15 10 ? * 6L” 每月的最后一个星期五10:15触发一次事件
  • “0 15 10 ? * 6L 2002-2005″ 2002年至2005年的每月的最后一个星期五10:15触发一次事件
  • “0 15 10 ? * 6#3″ 每月的第三个星期五10:15触发一次事件

cron表达式生成工具

cron模拟器

posted on 2022-08-13 11:00  xuejianqiang  阅读(132)  评论(0编辑  收藏  举报
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033