18、基于FreeRTOS的正倒计时器程序设计
使用绝对延时函数产生0.01秒基时,进而产生秒、分,在LCD上显示分钟、秒、秒小数各2位;用4个按钮控制正计时、倒计时、启动、停止。在LCD上显示出当前的计时方式。
系统任务:键盘扫描任务,键值处理任务,正计时任务,倒计时任务;优先级按此顺序。
键盘扫描任务借助邮箱,把4个按钮的按键值1~4发送出去,键值处理任务接收邮箱消息。
键值处理任务:等待接收邮箱数据;根据接收到的键值做不同处理:键值为1时对时间变量清0,显示出当前时间,设置运行任务标志为正计时任务的优先级,然后恢复当前计时的任务;键值为2时设置时间变量为30分钟,显示出当前时间,设置运行任务标志为倒计时任务的优先级,然后恢复当前计时的任务;键值为3时恢复当前计时的任务;键值为4时挂起当前计时的任务。
正计时任务用绝对延时函数延时0.01秒进行计时;在任务的循环体之前,挂起自己任务。
倒计时任务用绝对延时函数延时0.01秒做倒计时;在任务的循环体之前,挂起自己任务。
主函数
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "lcd.h"
#include "key.h"
#include "beep.h"
#include "malloc.h"
#include "string.h"
#include "FreeRTOS.h"
#include "task.h"
#include "limits.h"
/************************************************
ALIENTEK Õ½½¢STM32F103¿ª·¢°å FreeRTOSʵÑé17-3
FreeRTOSÈÎÎñ֪ͨģÄâÏûÏ¢ÓÊÏä-¿âº¯Êý°æ±¾
¼¼ÊõÖ§³Ö£ºwww.openedv.com
ÌÔ±¦µêÆÌ£ºhttp://eboard.taobao.com
¹Øע΢ÐŹ«ÖÚƽ̨΢Ðźţº"ÕýµãÔ×Ó"£¬Ãâ·Ñ»ñÈ¡STM32×ÊÁÏ¡£
¹ãÖÝÊÐÐÇÒíµç×ӿƼ¼ÓÐÏÞ¹«Ë¾
×÷ÕߣºÕýµãÔ×Ó @ALIENTEK
************************************************/
//ÈÎÎñÓÅÏȼ¶
#define START_TASK_PRIO 1
//ÈÎÎñ¶ÑÕ»´óС
#define START_STK_SIZE 256
//ÈÎÎñ¾ä±ú
TaskHandle_t StartTask_Handler;
//ÈÎÎñº¯Êý
void start_task(void *pvParameters);
//ÈÎÎñÓÅÏȼ¶
#define TASK1_TASK_PRIO 2
//ÈÎÎñ¶ÑÕ»´óС
#define TASK1_STK_SIZE 256
//ÈÎÎñ¾ä±ú
TaskHandle_t Task1Task_Handler;
//ÈÎÎñº¯Êý
void task1_task(void *pvParameters);
//ÈÎÎñÓÅÏȼ¶
#define KEYPROCESS_TASK_PRIO 3
//ÈÎÎñ¶ÑÕ»´óС
#define KEYPROCESS_STK_SIZE 256
//ÈÎÎñ¾ä±ú
TaskHandle_t Keyprocess_Handler;
//ÈÎÎñº¯Êý
void Keyprocess_task(void *pvParameters);
extern u8 hour,minu,sec;
extern u8 run;
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//ÉèÖÃϵͳÖжÏÓÅÏȼ¶·Ö×é4
delay_init(); //ÑÓʱº¯Êý³õʼ»¯
uart_init(115200); //³õʼ»¯´®¿Ú
LED_Init(); //³õʼ»¯LED
KEY_Init(); //³õʼ»¯°´¼ü
BEEP_Init(); //³õʼ»¯·äÃùÆ÷
LCD_Init(); //³õʼ»¯LCD
my_mem_init(SRAMIN); //³õʼ»¯ÄÚ²¿ÄÚ´æ³Ø
LCD_Clear(YELLOW);
POINT_COLOR=BLUE;//ÉèÖÃ×ÖÌåΪÀ¶É«
LCD_ShowString(100,130,200,24,24," : : ");
//´´½¨¿ªÊ¼ÈÎÎñ
xTaskCreate((TaskFunction_t )start_task, //ÈÎÎñº¯Êý
(const char* )"start_task", //ÈÎÎñÃû³Æ
(uint16_t )START_STK_SIZE, //ÈÎÎñ¶ÑÕ»´óС
(void* )NULL, //´«µÝ¸øÈÎÎñº¯ÊýµÄ²ÎÊý
(UBaseType_t )START_TASK_PRIO, //ÈÎÎñÓÅÏȼ¶
(TaskHandle_t* )&StartTask_Handler); //ÈÎÎñ¾ä±ú
vTaskStartScheduler(); //¿ªÆôÈÎÎñµ÷¶È
}
//¿ªÊ¼ÈÎÎñÈÎÎñº¯Êý
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //½øÈëÁÙ½çÇø
//´´½¨TASK1ÈÎÎñ
xTaskCreate((TaskFunction_t ) task1_task,
(const char* )"task1_task",
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_TASK_PRIO,
(TaskHandle_t* )&Task1Task_Handler);
//´´½¨°´¼ü´¦ÀíÈÎÎñ
xTaskCreate((TaskFunction_t )Keyprocess_task,
(const char* )"keyprocess_task",
(uint16_t )KEYPROCESS_STK_SIZE,
(void* )NULL,
(UBaseType_t )KEYPROCESS_TASK_PRIO,
(TaskHandle_t* )&Keyprocess_Handler);
vTaskDelete(StartTask_Handler); //ɾ³ý¿ªÊ¼ÈÎÎñ
taskEXIT_CRITICAL(); //Í˳öÁÙ½çÇø
}
//task1ÈÎÎñº¯Êý
void task1_task(void *pvParameters)
{
u8 key;
BaseType_t err;
while(1)
{
key=KEY_Scan(0); //ɨÃè°´¼ü
if((Keyprocess_Handler!=NULL)&&(key))
{
err=xTaskNotify((TaskHandle_t )Keyprocess_Handler, //½ÓÊÕÈÎÎñ֪ͨµÄÈÎÎñ¾ä±ú
(uint32_t )key, //ÈÎÎñֵ֪ͨ
(eNotifyAction )eSetValueWithOverwrite); //¸²Ð´µÄ·½Ê½·¢ËÍÈÎÎñ֪ͨ
if(err==pdFAIL)
{
printf("ÈÎÎñ֪ͨ·¢ËÍʧ°Ü\r\n");
}
}
vTaskDelay(10); //ÑÓʱ10ms£¬Ò²¾ÍÊÇ0.01s½øÐÐÈÎÎñµÄÇл»
}
}
//Keyprocess_taskº¯Êý
void Keyprocess_task(void *pvParameters)
{
uint32_t NotifyValue;
BaseType_t err;
while(1)
{
err=xTaskNotifyWait((uint32_t )0x00, //½øÈ뺯ÊýµÄʱºò²»Çå³ýÈÎÎñbit
(uint32_t )ULONG_MAX, //Í˳öº¯ÊýµÄʱºòÇå³ýËùÓеÄbit
(uint32_t* )&NotifyValue, //±£´æÈÎÎñֵ֪ͨ
(TickType_t )portMAX_DELAY); //×èÈûʱ¼ä
if(err==pdTRUE) //»ñÈ¡ÈÎÎñ֪ͨ³É¹¦
{
switch((u8)NotifyValue)
{
case WKUP_PRES://Æô¶¯
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
break;
case KEY2_PRES: //Õýת
run=0;
hour=0;
minu=0;
sec=0;
break;
case KEY1_PRES: //µ¹×ª
run=1;
hour=29;
minu=59;
sec=60;
break;
case KEY0_PRES: //ÔÝÍ£
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, DISABLE);
break;
}
}
vTaskDelay(10); //ÑÓʱ10ms£¬Ò²¾ÍÊÇ0.01s½øÐÐÈÎÎñµÄÇл»
}
}
按键的配置函数
#include "stm32f10x.h"
#include "key.h"
#include "sys.h"
#include "delay.h"
//
//±¾³ÌÐòÖ»¹©Ñ§Ï°Ê¹Óã¬Î´¾×÷ÕßÐí¿É£¬²»µÃÓÃÓÚÆäËüÈκÎÓÃ;
//ALIENTEKÕ½½¢STM32¿ª·¢°å
//°´¼üÇý¶¯´úÂë
//ÕýµãÔ×Ó@ALIENTEK
//¼¼ÊõÂÛ̳:www.openedv.com
//ÐÞ¸ÄÈÕÆÚ:2012/9/3
//°æ±¾£ºV1.0
//°æȨËùÓУ¬µÁ°æ±Ø¾¿¡£
//Copyright(C) ¹ãÖÝÊÐÐÇÒíµç×ӿƼ¼ÓÐÏÞ¹«Ë¾ 2009-2019
//All rights reserved
//
//°´¼ü³õʼ»¯º¯Êý
void KEY_Init(void) //IO³õʼ»¯
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);//ʹÄÜPORTA,PORTEʱÖÓ
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;//KEY0-KEY2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //ÉèÖóÉÉÏÀÊäÈë
GPIO_Init(GPIOE, &GPIO_InitStructure);//³õʼ»¯GPIOE2,3,4
//³õʼ»¯ WK_UP-->GPIOA.0 ÏÂÀÊäÈë
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0ÉèÖóÉÊäÈ룬ĬÈÏÏÂÀ
GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIOA.0
}
//°´¼ü´¦Àíº¯Êý
//·µ»Ø°´¼üÖµ
//mode:0,²»Ö§³ÖÁ¬Ðø°´;1,Ö§³ÖÁ¬Ðø°´;
//0£¬Ã»ÓÐÈκΰ´¼ü°´ÏÂ
//1£¬KEY0°´ÏÂ
//2£¬KEY1°´ÏÂ
//3£¬KEY2°´ÏÂ
//4£¬KEY3°´Ï WK_UP
//×¢Òâ´Ëº¯ÊýÓÐÏìÓ¦ÓÅÏȼ¶,KEY0>KEY1>KEY2>KEY3!!
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;//°´¼ü°´ËÉ¿ª±êÖ¾
if(mode)key_up=1; //Ö§³ÖÁ¬°´
if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))
{
delay_ms(10);//È¥¶¶¶¯
key_up=0;
if(KEY0==0)return KEY0_PRES;
else if(KEY1==0)return KEY1_PRES;
else if(KEY2==0)return KEY2_PRES;
else if(WK_UP==1)return WKUP_PRES;
}else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)key_up=1;
return 0;// ÎÞ°´¼ü°´ÏÂ
}
定时器3的配置函数
#include "timer.h"
#include "led.h"
#include "led.h"
#include "usart.h"
#include "malloc.h"
#include "string.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "lcd.h"
#include "delay.h"
//
//±¾³ÌÐòÖ»¹©Ñ§Ï°Ê¹Óã¬Î´¾×÷ÕßÐí¿É£¬²»µÃÓÃÓÚÆäËüÈκÎÓÃ;
//ALIENTEKÕ½½¢STM32¿ª·¢°å
//¶¨Ê±Æ÷ Çý¶¯´úÂë
//ÕýµãÔ×Ó@ALIENTEK
//¼¼ÊõÂÛ̳:www.openedv.com
//ÐÞ¸ÄÈÕÆÚ:2012/9/3
//°æ±¾£ºV1.0
//°æȨËùÓУ¬µÁ°æ±Ø¾¿¡£
//Copyright(C) ¹ãÖÝÊÐÐÇÒíµç×ӿƼ¼ÓÐÏÞ¹«Ë¾ 2009-2019
//All rights reserved
//
//FreeRTOSʱ¼äͳ¼ÆËùÓõĽÚÅļÆÊýÆ÷
volatile unsigned long long FreeRTOSRunTimeTicks;
u8 hour=0,minu=0,sec=0;
u8 run=0;
//³õʼ»¯TIM3ʹÆäΪFreeRTOSµÄʱ¼äͳ¼ÆÌṩʱ»ù
void ConfigureTimeForRunTimeStats(void)
{
//¶¨Ê±Æ÷3³õʼ»¯£¬¶¨Ê±Æ÷ʱÖÓΪ72M£¬·ÖƵϵÊýΪ72-1£¬ËùÒÔ¶¨Ê±Æ÷3µÄƵÂÊ
//Ϊ72M/72=1M£¬×Ô¶¯ÖØ×°ÔØΪ50-1£¬ÄÇô¶¨Ê±Æ÷ÖÜÆÚ¾ÍÊÇ50us
FreeRTOSRunTimeTicks=0;
TIM3_Int_Init(50-1,72-1); //³õʼ»¯TIM3
}
//ͨÓö¨Ê±Æ÷3Öжϳõʼ»¯
//ÕâÀïʱÖÓÑ¡ÔñΪAPB1µÄ2±¶£¬¶øAPB1Ϊ36M
//arr£º×Ô¶¯ÖØ×°Öµ¡£
//psc£ºÊ±ÖÓÔ¤·ÖƵÊý
//ÕâÀïʹÓõÄÊǶ¨Ê±Æ÷3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //ʱÖÓʹÄÜ
//¶¨Ê±Æ÷TIM3³õʼ»¯
TIM_TimeBaseStructure.TIM_Period = arr; //ÉèÖÃÔÚÏÂÒ»¸ö¸üÐÂʼþ×°Èë»î¶¯µÄ×Ô¶¯ÖØ×°ÔؼĴæÆ÷ÖÜÆÚµÄÖµ
TIM_TimeBaseStructure.TIM_Prescaler =psc; //ÉèÖÃÓÃÀ´×÷ΪTIMxʱÖÓƵÂʳýÊýµÄÔ¤·ÖƵֵ
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //ÉèÖÃʱÖÓ·Ö¸î:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIMÏòÉϼÆÊýģʽ
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯TIMxµÄʱ¼ä»ùÊýµ¥Î»
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //ʹÄÜÖ¸¶¨µÄTIM3ÖжÏ,ÔÊÐí¸üÐÂÖжÏ
//ÖжÏÓÅÏȼ¶NVICÉèÖÃ
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3ÖжÏ
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //ÏÈÕ¼ÓÅÏȼ¶4¼¶
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //´ÓÓÅÏȼ¶0¼¶
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQͨµÀ±»Ê¹ÄÜ
NVIC_Init(&NVIC_InitStructure); //³õʼ»¯NVIC¼Ä´æÆ÷
TIM_Cmd(TIM3, ENABLE); //ʹÄÜTIMx
}
//¶¨Ê±Æ÷3ÖжϷþÎñº¯Êý
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //Òç³öÖжÏ
{
FreeRTOSRunTimeTicks++;//ÔËÐÐʱ¼äͳ¼Æʱ»ùÊý¼ÆÊýÆ÷¼Ó1
if(FreeRTOSRunTimeTicks==3000)
{
FreeRTOSRunTimeTicks=0;
if(run==0)
{
sec++;
if(sec>59)
{
sec=0;
minu++;
if(minu>59)
{
minu=0;
hour++;
if(hour>23)
hour=0;
}
}
}
if(run==1)
{
sec--;
if(sec==0)
{
sec=60;
minu--;
if(minu==0)
{
minu=60;
hour--;
if(hour==0)
hour=29;
}
}
}
LCD_ShowNum(100,130,hour,2,24);
LCD_ShowNum(140,130,minu,2,24);
LCD_ShowNum(170,130,sec,2,24);
}
}
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //Çå³ýÖжϱê־λ
}