1. FreeRTOS 创建一个任务 BeepSoftwareTimers
#define BEEP_NOTIFICATION_SOFTWARE_TIMERS_TASK_STACK_SIZE 128
#define BEEP_NOTIFICATION_SOFTWARE_TIMERS_TASK_PRIORITY 6
xTaskCreate((TaskFunction_t)BeepSoftwareTimers, \
(const char *)"beep_software_timers", \
(uint16_t)BEEP_NOTIFICATION_SOFTWARE_TIMERS_TASK_STACK_SIZE, \
(void *)NULL, \
(UBaseType_t)BEEP_NOTIFICATION_SOFTWARE_TIMERS_TASK_PRIORITY, \
(TaskHandle_t *)&g_beepSoftwareTimersTask_Handler);
2. 在任务里面创建定时器队列, 创建了 7 个软件定时器,创建完定时器后将该任务删除,只保留定时器队列,在未启动定时器之前,定时器是处于休眠状态的,功耗很低
static void BeepSoftwareTimers(void)
{
g_beepNotifyTimer_BeepOn_2ms = xTimerCreate((const char *)"beepNotification_beep_on_2ms",
(TickType_t)pdMS_TO_TICKS(beepDelayTimeToTick_2ms), // timer period
(UBaseType_t)pdFALSE, // pdTRUE - period mode, pdFALSE - one times mode
(void *)BeepSoftwareTimer_ID_1, // software timer id
(TimerCallbackFunction_t)beepNotificationSoftwareTimer_BeepOn_2ms_Callback);
if (NULL == g_beepNotifyTimer_BeepOn_2ms)
{
// TODO
}
g_beepNotifyTimer_BeepOn_100ms = xTimerCreate((const char *)"beepNotification_beep_on_100ms",
(TickType_t)pdMS_TO_TICKS(beepDelayTimeToTick_100ms), // timer period
(UBaseType_t)pdFALSE, // pdTRUE - period mode, pdFALSE - one times mode
(void *)BeepSoftwareTimer_ID_2, // software timer id
(TimerCallbackFunction_t)beepNotificationSoftwareTimer_BeepOn_100ms_Callback);
if (NULL == g_beepNotifyTimer_BeepOn_100ms)
{
}
g_generalNotify_BeepOn_100ms = xTimerCreate((const char *)"generalNotification_BeepOn_100ms",
(TickType_t)pdMS_TO_TICKS(beepDelayTimeToTick_100ms), // timer period, please do not set to too small
(UBaseType_t)pdTRUE, // pdTRUE - period mode, pdFALSE - one times mode
(void *)BeepSoftwareTimer_ID_3, // software timer id
(TimerCallbackFunction_t)GeneralNotificationSoftwareTimer_BeepOn_100ms_Callback);
if (NULL == g_generalNotify_BeepOn_100ms)
{
}
g_beepNotifyTimer_BeepOff_20ms = xTimerCreate((const char *)"beepNotification_beep_off_20ms",
(TickType_t)pdMS_TO_TICKS(beepDelayTimeToTick_20ms), // timer period
(UBaseType_t)pdFALSE, // pdTRUE - period mode, pdFALSE - one times mode
(void *)BeepSoftwareTimer_ID_4, // software timer id
(TimerCallbackFunction_t)beepNotificationSoftwareTimer_BeepOff_20ms_Callback);
if (NULL == g_beepNotifyTimer_BeepOff_20ms)
{
}
g_beepNotifyTimer_BeepOff_100ms = xTimerCreate((const char *)"beepNotification_beep_off_100ms",
(TickType_t)pdMS_TO_TICKS(beepDelayTimeToTick_100ms), // timer period
(UBaseType_t)pdFALSE, // pdTRUE - period mode, pdFALSE - one times mode
(void *)BeepSoftwareTimer_ID_5, // software timer id
(TimerCallbackFunction_t)beepNotificationSoftwareTimer_BeepOff_100ms_Callback);
if (NULL == g_beepNotifyTimer_BeepOff_100ms)
{
}
g_beepNotifyTimer_BeepOff_200ms = xTimerCreate((const char *)"beepNotification_beep_off_200ms",
(TickType_t)pdMS_TO_TICKS(beepDelayTimeToTick_100ms), // timer period
(UBaseType_t)pdFALSE, // pdTRUE - period mode, pdFALSE - one times mode
(void *)BeepSoftwareTimer_ID_6, // software timer id
(TimerCallbackFunction_t)beepNotificationSoftwareTimer_BeepOff_200ms_Callback);
if (NULL == g_beepNotifyTimer_BeepOff_200ms)
{
}
g_beepNotifyTimer_BeepOff_500ms = xTimerCreate((const char *)"beepNotification_beep_off_500ms",
(TickType_t)pdMS_TO_TICKS(beepDelayTimeToTick_100ms), // timer period
(UBaseType_t)pdFALSE, // pdTRUE - period mode, pdFALSE - one times mode
(void *)BeepSoftwareTimer_ID_7, // software timer id
(TimerCallbackFunction_t)beepNotificationSoftwareTimer_BeepOff_500ms_Callback);
if (NULL == g_beepNotifyTimer_BeepOff_500ms)
{
}
vTaskDelete(g_beepNotificationSoftwareTimersTask_Handler); // 创建完定时器后将该任务删除
}
3. 需要在FreeRTOS 的配置文件FreeRTOSConfig.h 中打开FreeRTOS 软件定时器宏开关,并配置最多可以创建多少个软件定时器
// FreeRTOS related to soft timer configuration options
#define configUSE_TIMERS 1 // 1 - enable soft timer, 0 - disable soft timer
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) // soft timer priority
#define configTIMER_QUEUE_LENGTH 10 // soft timer queue len
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) // soft timer task stack size
4. 在创建软件定时器的时候可以选择定时器的模式,由xTimerCreate() 第三个参数决定
4.1 (UBaseType_t)pdFALSE: 定时器只启动一次
4.2 (UBaseType_t)pdTRUE: 每隔一段时间启动一次定时器
5. 定时器回调函数,启动定时器后,到了时间点就会进一次回调函数,然后你就可以在回调函数里面做你想做的事情了,xTimerCreate() 第五个参数
// IO port operation macro definition, refer to <<Corterx-M3/M4 authoritative guide>> chapter 5, page 87 ~ 92
#define BITBAND(addr, bitnum) ((addr & 0xF0000000) + 0x2000000 + ((addr & 0xFFFFF) << 5) + (bitnum << 2))
#define MEM_ADDR(addr) (*((volatile unsigned long *)(addr)))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr, n)
#define BUZZER_GPIO_PORT 8
#define BEEP_CTRL PAout(BUZZER_GPIO_PORT)
#define EVEN_NUMBER 0
#define ODD_NUMBER 1
#define PARITY_OPERATION 2
static void GeneralNotificationSoftwareTimer_BeepOn_100ms_Callback(void *parameter)
{
UNUSED(parameter);
static uint8_t g_notificationCounter = BeepSoftwareTimerCounters_Min;
g_notificationCounter++;
if (g_notificationCounter < BeepSoftwareTimerCounters_3) // you can set 3, 5, 7 ... (BeepSoftwareTimerCounters_3)
{
if (EVEN_NUMBER == (g_notificationCounter % PARITY_OPERATION))
{
BEEP_CTRL = BEEP_OFF;
}
else if (ODD_NUMBER == (g_notificationCounter % PARITY_OPERATION))
{
BEEP_CTRL = BEEP_ON;
}
}
else
{
xTimerStop(g_generalNotify_BeepOn_100ms, BeepSoftwareTimerTicksToWait_Min);
g_notificationCounter = BeepSoftwareTimerCounters_Min;
}
}
我这里配置的是循环启动定时器,每隔100ms启动一次定时器,启动定时器后,过100ms 就会进回调函数,然后在回调函数里面判断进来回调函数次数是奇数次还是偶数次,奇数次进回调就把蜂鸣器打开,偶数次就会把蜂鸣器关闭,同时计数蜂鸣器打开的次数,可以控制蜂鸣器响几次
6. 关闭定时器
xTimerStop(g_generalNotify_BeepOn_100ms, BeepSoftwareTimerTicksToWait_Min); // BeepSoftwareTimerTicksToWait_Min = 0,
6.1 第一个参数是创建定时器函数的第一个参数xTimerCreate(),定时器句柄
6.2 第二个参数,调用关闭函数xTimerStop的时候,什么时候真正关闭定时器,我这里是调用xTimerStop() 的就立即把定时器关了
7. 创建定时器
TimerHandle_t xTimerCreate(const char * const pcTimerName,
const TickType_t xTimerPeriod,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction);
7.1 参数说明:
7.1.1 pcTimerName:定时器的名称,以字符串形式表示。
7.1.2 xTimerPeriod:定时器的周期时间,单位是 tick, 系统时钟节拍,一般是1ms
7.1.3 uxAutoReload:指示定时器是否自动重载的标志。如果设置为 1,则定时器将在每次触发后自动重新启动;如果设置为 0,则定时器只会触发一次。
7.1.4 pvTimerID:用户自定义的定时器 ID,可以作为回调函数的参数传递给用户使用。
7.1.5 pxCallbackFunction:定时器触发时要执行的回调函数。
7.1.6 该函数返回一个 TimerHandle_t 类型的定时器句柄,可以在后续操作中使用该句柄进行定时器的修改、启动、停止等操作。
7.1.7 需要注意的是,使用 xTimerCreate 创建的定时器需要在合适的时机通过 xTimerStart 函数启动,才能开始计时。
8. 启动定时器
/*
* startup the timer, which create by xTimerCreate()
* xTimer: software timer handle, xTimerCreate() first parameter
* xTicksToWait: when you want to startup the timer, usually set 0
* startup success: return pdPASS
* startup failure: return errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY, errQUEUE_BLOCKED, errQUEUE_YIELD
*/
#define xTimerStart(xTimer, xTicksToWait) xTimerGenericCommand((xTimer), tmrCOMMAND_START, (xTaskGetTickCount()), NULL, (xTicksToWait))
8.1 xTimer 第一个参数,是创建定时器函数xTimerCreate() 的第一个参数,定时器句柄
8.2 xTicksToWait 调用启动函数xTimerStart() 之后,什么时候真正启动定时器,开始计数
9. 在中断服务函数里面只能用专门的启动函数,这是FreeRTOS 的特性,所有中断服务只能用专门的API
#define xTimerStartFromISR(xTimer, pxHigherPriorityTaskWoken) xTimerGenericCommand((xTimer), tmrCOMMAND_START_FROM_ISR, (xTaskGetTickCountFromISR()), (pxHigherPriorityTaskWoken), 0U)