按键消抖,这个古老的话题,如今再拿出来和大家讨论讨论。
本文不仅讨论按键消抖,也说说ucos-3的使用。
几句话概括完ucos-3的功能。
用于时间管理的有两个函数,一个是OSTimeDly();另一个是OSTimeDlyHMSM();其实也就是用于延时,具体的用法大家查查API就知道了。
然后定时器&回调函数,对于cortex-M3,定时器是基于systick定时器模拟的,可以创建无数个定时器。但是精度取决于systick(一般为10-1000Hz),相对较低。不能用于高精度定时。
用于资源管理的是互斥型信号量,也可以使用信号量,但可能造成任务优先级反转,所以推荐使用互斥型信号量。
任务同步用信号量,也可以用事件标志组。信号量具体的用法比如我们可以在ISR里边向对应的任务发送信号量,这样能大大缩短ISR的执行时间。事件标志组用于多任务同步。
用于消息传递的是消息队列。注意消息与信号的区别。信号只是0或者1(可以递增,表示事件发生了多少次),标志某种事件的发生与否。而消息是一个指针,可以指向任意的数据结构,甚至函数。
大致就说到这儿。下面是我做的按键外部中断的代码。
/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/
#include <includes.h>
/*
*********************************************************************************************************
* main()
*
* Description : This is the standard entry point for C code. It is assumed that your code will call
* main() once you have performed all necessary initialization.
*
* Arguments : none
*
* Returns : none
*********************************************************************************************************
*/
int main (void)
{
OS_ERR err;
BSP_IntDisAll(); /* Disable all interrupts. */
OSInit(&err); /* Init uC/OS-III. */
OSTaskCreate((OS_TCB *)&AppTaskStartTCB, /* Create the start task */
(CPU_CHAR *)"App Task Start",
(OS_TASK_PTR ) AppTaskStart,
(void *) 0,
(OS_PRIO ) APP_TASK_START_PRIO,
(CPU_STK *)&AppTaskStartStk[0],
(CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_START_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
OSStart(&err); /* Start multitasking (i.e. give control to uC/OS-III). */
// SystemInit();
}
/*
*********************************************************************************************************
* STARTUP TASK
*
* Description : This is an example of a startup task. As mentioned in the book's text, you MUST
* initialize the ticker only once multitasking has started.
*
* Arguments : p_arg is the argument passed to 'AppTaskStart()' by 'OSTaskCreate()'.
*
* Returns : none
*
* Notes : 1) The first line of code is used to prevent a compiler warning because 'p_arg' is not
* used. The compiler should not generate any code for this statement.
*********************************************************************************************************
*/
static void AppTaskStart (void *p_arg)
{
CPU_INT32U cpu_clk_freq;
CPU_INT32U cnts;
OS_ERR err;
(void)p_arg;
BSP_Init(); /* Initialize BSP functions */
CPU_Init();
cpu_clk_freq = BSP_CPU_ClkFreq(); /* Determine SysTick reference freq. */
cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz ; /* Determine nbr SysTick increments */
OS_CPU_SysTickInit(cnts); /* Init uC/OS periodic time src (SysTick). */
Mem_Init(); /* Initialize Memory Management Module */
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err); /* Compute CPU capacity with no task running */
#endif
CPU_IntDisMeasMaxCurReset();
//#if (APP_CFG_SERIAL_EN == DEF_ENABLED)
// BSP_Ser_Init(115200); /* Enable Serial Interface */
//#endif
STM_EVAL_COMInit(COM2);
printf("Creating Application Events...\n\r");
AppObjCreate(); /* Create Application Objects */
printf("Creating Application Tasks...\n\r");
AppTaskCreate(); /* Create Application Tasks */
printf("cpu_clk_freq: %dMHz\n\r",cpu_clk_freq/1000000);
BSP_LED_Off(0);
BSP_BEEP_On();
OSTimeDlyHMSM(0, 0, 0, 10,
OS_OPT_TIME_HMSM_STRICT,
&err);
BSP_BEEP_Off();
while (DEF_TRUE)
{ /* Task body, always written as an infinite loop. */
BSP_LED_Toggle(1);
OSTimeDlyHMSM(0, 0, 0, 500,
OS_OPT_TIME_HMSM_STRICT,
&err);
}
}
/*
*********************************************************************************************************
* CREATE APPLICATION TASKS
*
* Description: This function creates the application tasks.
*
* Arguments : none
*
* Returns : none
*********************************************************************************************************
*/
static void AppTaskCreate (void)
{
OS_ERR err;
OSTaskCreate((OS_TCB *)&AppTask_EXTI4_TCB,
(CPU_CHAR *)"App Task EXTI4",
(OS_TASK_PTR )AppTaskEXTI4,
(void *)0,
(OS_PRIO )APP_TASK_EXTI4_PRIO,
(CPU_STK *)&AppTask_EXTI4_Stk[0],
(CPU_STK_SIZE)APP_TASK_EXTI4_STK_SIZE / 10,
(CPU_STK_SIZE)APP_TASK_EXTI4_STK_SIZE,
(OS_MSG_QTY )10,
(OS_TICK ) 0,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
OSTaskCreate((OS_TCB *)&AppTask_EXTI15_10_TCB,
(CPU_CHAR *)"App Task EXTI15_10",
(OS_TASK_PTR )AppTaskEXTI15_10,
(void *)0,
(OS_PRIO )APP_TASK_EXTI15_10_PRIO,
(CPU_STK *)&AppTask_EXTI15_10_Stk[0],
(CPU_STK_SIZE)APP_TASK_EXTI15_10_STK_SIZE / 10,
(CPU_STK_SIZE)APP_TASK_EXTI15_10_STK_SIZE,
(OS_MSG_QTY )10,
(OS_TICK ) 0,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
if(err==OS_ERR_NONE)
printf("OSTaskCreate OK!\n\r");
else
printf("OSTaskCreate err=%d\n\r",err);
}
/*
*********************************************************************************************************
* CREATE APPLICATION EVENTS
*
* Description: This function creates the application kernel objects.
*
* Arguments : none
*
* Returns : none
*********************************************************************************************************
*/
static void AppObjCreate (void)
{
}
static void AppTaskEXTI4 (void *p_arg)
{
OS_ERR err;
OS_SEM_CTR ctr;
CPU_TS ts;
static NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
BSP_IntVectSet((CPU_INT08U )BSP_INT_ID_EXTI4, /* Set the Interrupt vector */
(CPU_FNCT_VOID)App_IntHandlerEXTI4);
while(1)
{
ctr=OSTaskSemPend(0, OS_OPT_PEND_BLOCKING, &ts, &err);
NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE; //关中断
NVIC_Init(&NVIC_InitStructure);
BSP_LED_Toggle(2);
OSTaskSemSet(&AppTask_EXTI4_TCB, 0, &err); //设置ctr=0
printf("AppTaskEXTI4 ctr=%d\n\r",ctr);
OSTimeDlyHMSM(0, 0, 1, 0, //延时
OS_OPT_TIME_HMSM_STRICT,
&err);
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //开中断
NVIC_Init(&NVIC_InitStructure);
}
}
static void AppTaskEXTI15_10 (void *p_arg)
{
OS_ERR err;
OS_SEM_CTR ctr;
CPU_TS ts;
static NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
BSP_IntVectSet((CPU_INT08U )BSP_INT_ID_EXTI15_10, /* Set the Interrupt vector */
(CPU_FNCT_VOID)App_IntHandlerEXTI15_10);
while(1)
{
ctr=OSTaskSemPend(0, OS_OPT_PEND_BLOCKING, &ts, &err);
NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE; //关中断
NVIC_Init(&NVIC_InitStructure);
BSP_LED_Toggle(3);
OSTaskSemSet(&AppTask_EXTI15_10_TCB, 0, &err); //设置ctr=0
printf("AppTaskEXTI15_10 ctr=%d\n\r",ctr);
OSTimeDlyHMSM(0, 0, 1, 0, //延时
OS_OPT_TIME_HMSM_STRICT,
&err);
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //开中断
NVIC_Init(&NVIC_InitStructure);
}
}
static void App_IntHandlerEXTI4 (void)
{
OS_ERR err;
EXTI_ClearITPendingBit(EXTI_Line4); /* Clear the Timer #1 Update interrupt */
OSTaskSemPost(&AppTask_EXTI4_TCB, OS_OPT_POST_NO_SCHED, &err);
}
static void App_IntHandlerEXTI15_10(void)
{
OS_ERR err;
if(EXTI_GetFlagStatus(EXTI_Line10)==SET)
{
EXTI_ClearITPendingBit(EXTI_Line10); /* Clear the Timer #1 Update interrupt */
OSTaskSemPost(&AppTask_EXTI15_10_TCB, OS_OPT_POST_NO_SCHED, &err);
}
}
有一点需要注意,内核对象需要在创建任务之前建立,也就是AppObjCreate(); 要在AppTaskCreate();之前执行。
程序的整体思路是ISR给任务发送信号量,然后在任务里边关中断,LED取反,延时1s,再开中断。之所以延时1s,是因为按键按下和松开都会有抖动的波形,触发中断。所以我希望用户在1s内按下并且松开按键。但是现在还是不够稳定。有时候会执行一次,有时候是两次。这里应该是NVIC的问题,大家帮忙看看,共同讨论。
|
|