4.订阅服务主任务
基于FreeRTOS系统设计定时器订阅主任务,具体设计流程如下:
/* 定义订阅任务Time_Subscribe_Task_Handle */
osThreadId_t Time_Subscribe_Task_Handle; //任务9的句柄为TimerprocessHandle
const osThreadAttr_t Time_Subscribe_Task_attributes = {
.name = "SubscribeTask", //定义任务8的名称为"timerprocess"
.priority = (osPriority_t) osPriorityNormal1, //定义任务8的优先级为osPriorityLow6
.stack_size = 128 * 4 //定义任务8的栈大小是128 * 4
};
/* 定义订阅任务的消息队列 Subscribe_Queue_Handle */
osMessageQueueId_t Subscribe_Queue_Handle;
const osMessageQueueAttr_t Subscribe_Queue_attributes = {
.name = "SubscribeQueue"
};
/**
* @brief FreeRTOS initialization,在freertos的初始化工作中创建订阅任务及其接收队列
* @param None
* @retval None
*/
void MX_FREERTOS_Init(void)
{
/* 创建定时器订阅任务消息队列 Subscribe_Queue_Handle */
Subscribe_Queue_Handle = osMessageQueueNew (10, 4, &Subscribe_Queue_attributes);
/* 创建定时器订阅任务subscribe_task */
Time_Subscribe_Task_Handle = osThreadNew(subscribe_task, NULL, &Time_Subscribe_Task_attributes);
}
/**
* @brief 定时器订阅处理任务
* @param argument: Not used
* @retval None
*/
void subscribe_task(void *argument)
{
BaseType_t err=pdFALSE;
period_subscribe *my_period_subscribe;
u8 ret=0; //返回
static u8 sub_flag=0; //定义订阅标志,1表示订阅,2表示取消订阅
u32 read_count=0; //当前读取的定时器的值
u32 address_temp=0; //接收传递过来的地址
static message_type message_id=default_messageid; //解析出来uuid号,用来判断不同的消息源
static Thread_uuid uuid=uuid_default; //解析出来uuid号,用来判断不同的消息源
static u32 period=0; //解析出来周期值,用来判断订阅任务的订阅周期
static u32 timers=0; //解析出来订阅次数
static u32 time_base=0; //定义中断时基
u32 time_base_temp=0; //定义中断时基
for(;;)
{
if(Subscribe_Queue_Handle!=NULL)
{
err=xQueueReceive(Subscribe_Queue_Handle,(u8*)&address_temp,portMAX_DELAY);//请求消息Message_Queue1,为无限期等待
if(err==pdTRUE) //接收到消息
{
my_period_subscribe=(period_subscribe *)address_temp; //地址转换为订阅结构体类型
message_id=my_period_subscribe->message_id; //获取message_id
switch(message_id)
{
/*****************************lprtim2定时器中断处理**************************************/
case lprtim2_interupter_sign: //lprtim2定时器中断
portENTER_CRITICAL(); /*进入临界区*/
time_base_temp=Subscrible_timer.Process_Lsit(&Subscrible_timer.Head_Node,time_base,process_node_time);
if(time_base_temp == 0)
{
//printf("订阅链表为空了,停止计时器\r\n");
HAL_LPTIM_PWM_Stop_IT(&hlptim2); //订阅链表为空了,停止计时器
}
else if(time_base_temp!=time_base)
{
time_base = time_base_temp;
//printf("时基需要调整,调整为:%d\r\n",time_base);
HAL_LPTIM_PWM_Stop_IT(&hlptim2); //首先停止定时器中断,相当关于复位一次,至关重要!!!
HAL_LPTIM_PWM_Start_IT(&hlptim2,(u32)(25.6*time_base),0); //重新设置定时器
}
portEXIT_CRITICAL();/*退出临界区*/
break;
/*****************************订阅处理部分*************************************/
case key1_lptim2_send_subscribe: //按键任务订阅定时器
sub_flag=1; //订阅标志
break;
case key2_lptim2_send_subscribe: //按键任务订阅定时器
sub_flag=1; //订阅标志
break;
/*****************************取消订阅处理部分*************************************/
case key1_lptim2_send_dissubscribe: //取消电源管理订阅定时器
sub_flag=2; //订阅标志
break;
case key2_lptim2_send_dissubscribe: //取消电源管理订阅定时器
sub_flag=2; //订阅标志
break;
default:break;
}
if(sub_flag == 1) //订阅处理
{
uuid=my_period_subscribe->uuid; //获取进程号
period=my_period_subscribe->period;//获取订阅周期
timers=my_period_subscribe->timers;//获取订阅次数
//printf("uuid=%d period=%d timers=%d 订阅\r\n",uuid,period,timers);
if(Subscrible_timer.Add_Node(&Subscrible_timer.Head_Node,uuid,period,timers)==HAL_OK)//添加该节点到订阅链表上,添加成功才执行
{
if(Subscrible_timer.Head_Node.next->next==NULL) //如果链表为空,则为首个订阅定时器任务到来
{
//printf("首个任务 %d 订阅时钟,订阅时间为%d,订阅次数为%d S\r\n",uuid,period,timers);
time_base=period<2400 ? period:2400; //更新时基为首个订阅周期(其中最大定时周期=240S=4min)
//printf("------当前时基为:%d--------\r\n",time_base);
MX_LPTIM2_Init(LPTIM_PRESCALER_DIV128,(u32)(25.6*time_base),0); //设置lptim2的中断周期为time_base S
}
else { //如果链表不为空,那么要进行时基调整
read_count=HAL_LPTIM_ReadCounter(&hlptim2); //获取当前计数器的值
//printf("当前计数器的值为:%d\r\n",read_count);
time_base_temp=Subscrible_timer.Time_Compensate(&Subscrible_timer.Head_Node,time_base,(u32)(read_count/25.6)); //进行时钟补偿
if(time_base_temp!=time_base)
{
time_base = time_base_temp;
//printf("121212时基需要调整,调整为:%d\r\n",time_base);
}
//printf("------当前时基为:%d--------\r\n",time_base);
HAL_LPTIM_PWM_Stop_IT(&hlptim2); //首先停止定时器中断,相当关于复位一次,至关重要!!!
HAL_LPTIM_PWM_Start_IT(&hlptim2,(u32)(25.6*time_base),0); //重新设置定时器
//printf("------定时器设置完成--------\r\n");
}
}
else{ //该进程已经订阅过时钟,订阅失败
//printf("该进程已经订阅过时钟,订阅失败!!! uuid=%d period=%d \r\n",uuid,period);
}
sub_flag = 0; //处理标志清零
}
else if(sub_flag == 2) //取消订阅处理
{
uuid=my_period_subscribe->uuid; //获取进程号
ret = Subscrible_timer.Delete_Node(&Subscrible_timer.Head_Node,uuid); //从订阅列表中删除节点
if(ret == HAL_OK)//链表中有该节点,删除成功
{
//printf("删除该节点成功\r\n");
if(Subscrible_timer.Head_Node.next == NULL) //链表为空了,关闭定时器
{
//printf("链表为空了,关闭定时器\r\n");
HAL_LPTIM_PWM_Stop_IT(&hlptim2); //关闭定时器
}
}
else{ //链表中没有该节点,删除失败
//printf("该节点未订阅,删除该节点失败\r\n");
}
sub_flag = 0; //处理标志清零
}
}
else if(err==pdFALSE)
{
osDelay(10); //延时1ms,也就是10个时钟节拍
}
}
}
}
|