Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
利用按键实现某个动态线程创建和删除
发布于 2020-03-28 16:17:05 浏览:2291
订阅该版
**作业题目3:利用按键实现某个动态线程创建和删除** 大家提交作业时,直接在本贴下方跟贴即可
查看更多
47
个回答
默认排序
按发布时间排序
风雨潇潇
2020-03-29
这家伙很懒,什么也没写!
[i=s] 本帖最后由 风雨潇潇 于 2020-3-29 14:43 编辑 [/i] 利用两个按键分别作为两个外部中断源。 首先还是可以利用STM32CUBEMX配置对应的引脚为外部中断,我的配置如下 ``` /*Configure GPIO pins : PCPin PCPin */ GPIO_InitStruct.Pin = KEY4_Pin|KEY3_Pin; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /* EXTI interrupt init*/ HAL_NVIC_SetPriority(EXTI0_IRQn, 1, 0); HAL_NVIC_EnableIRQ(EXTI0_IRQn); HAL_NVIC_SetPriority(EXTI1_IRQn, 1, 1); HAL_NVIC_EnableIRQ(EXTI1_IRQn); ``` 在外部中断的毁掉函数中进行动态的线程创建和删除,按下key1创建线程,按下key2删除线程。 此次的线程是课题一中的LED闪烁功能。 ``` void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_PIN_0 == GPIO_Pin) { //创建LED线程 if(led_thread == RT_NULL) { led_thread = rt_thread_create("ledThread", /* 线程名字 */ led_thread_entry, /* 线程入口函数 */ RT_NULL, /* 线程入口函数参数 */ 256, /* 线程栈大小 */ 5, /* 线程的优先级 */ 10 /* 线程时间片 */ ); if(led_thread != RT_NULL) { rt_thread_startup(led_thread); rt_kprintf("create success!\n"); } } } else if(GPIO_PIN_1 == GPIO_Pin) { //删除LED线程 if(led_thread != RT_NULL) { if(rt_thread_delete(led_thread) == RT_ERROR) { rt_kprintf("delete Faile!\n"); } else { rt_kprintf("delete success!\n"); led_thread = RT_NULL; HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET); } } else { rt_kprintf("led_thread not exist!\n"); } } ``` gif上传失败;效果连接[https://gitee.com/zhugexunyu/RT_Nano_L476/blob/master/GIF.gif](gif)
xinmeng_wit
2020-03-29
这家伙很懒,什么也没写!
首先在main函数中创建两个线程,一个是按键1的线程,一个是按键2的线程。 按键1按下后,创建led的线程,按键2按下后删除led线程。 如下: ``` #include "CH57x_common.h" #include "board.h" #include "rtthread.h" #include "gpio.h" static void led2_thread_entry(void *parameter); void touch_key_init(uint8_t ch) { R8_ADC_CFG|=RB_ADC_POWER_ON;//ADC模块电源使能 R8_ADC_CFG&=~RB_ADC_DIFF_EN;//ADC单端输入 ADC_SampClkCfg(2);//设置ADC采样时钟 R8_ADC_CFG|=RB_ADC_BUF_EN;//ADC输入缓冲使能 ADC_PGACfg(2);//设置信号增益 R8_TKEY_CTRL|=RB_TKEY_PWR_ON;//keytouch使能 R8_ADC_CHANNEL=ch;//ADC通道2 R8_TKEY_CNT=58; } //函数申明 static void key1_thread_entry(void *parameter); static void key2_thread_entry(void *parameter); static rt_thread_t key1_thread=RT_NULL;//定义线程控制块 static rt_thread_t key2_thread=RT_NULL;//定义线程控制块 static rt_thread_t led2_thread=RT_NULL;//定义线程控制块 int key_thread_create(void) { //led的线程创建 key1_thread=rt_thread_create("key1", key1_thread_entry, RT_NULL, 256, 4, 20);//线程创建 if(key1_thread!=RT_NULL) rt_thread_startup(key1_thread);//启动线程,开始调度 else return -1; key2_thread=rt_thread_create("key2", key2_thread_entry, RT_NULL, 256, 7, 20);//线程创建 if(key2_thread!=RT_NULL) rt_thread_startup(key2_thread);//启动线程,开始调度 else { rt_kprintf("key2线程创建失败\r\n"); return -1; } } static void key1_thread_entry(void *parameter) { uint16_t touch_key_value=0; while(1) { touch_key_init(2); R8_ADC_CONVERT|=(1<<0);//开始转换 rt_thread_delay(5); if((R8_ADC_CONVERT&(1<<4))==0)//转换完成 { touch_key_value=R16_ADC_DATA;//读取ad值 if(touch_key_value<50)//按下 { if(led2_thread==RT_NULL) { led2_thread = rt_thread_create("led2", led2_thread_entry, RT_NULL, 128, 5, 100); rt_kprintf("创建led2线程中...\r\n"); if(led2_thread!=RT_NULL) { rt_thread_startup(led2_thread);//启动线程,开始调度 rt_kprintf("LED2线程创建成功\r\n"); } else { rt_kprintf("LED2线程创建失败\r\n"); } } else { rt_kprintf("led2线程已存在,无法创建线程\r\n"); } } else//松开 { } } rt_thread_delay(20); } } static void key2_thread_entry(void *parameter) { rt_err_t uwRet=RT_EOK; uint16_t touch_key_value=0; while(1) { touch_key_init(3); R8_ADC_CONVERT|=(1<<0);//开始转换 rt_thread_delay(5); if((R8_ADC_CONVERT&(1<<4))==0)//转换完成 { touch_key_value=R16_ADC_DATA;//读取ad值 if(touch_key_value<50)//按下 { if(led2_thread!=RT_NULL) { uwRet = rt_thread_delete(led2_thread); rt_kprintf("删除led2线程中...\r\n"); if(uwRet==RT_EOK) { led2_thread=RT_NULL; rt_kprintf("LED2线程删除成功\r\n"); } else { rt_kprintf("LED2线程删除失败\r\n"); } } else { rt_kprintf("led2线程不存在,无法删除线程\r\n"); } } else//松开 { } } rt_thread_delay(100); } } static void led2_thread_entry(void *parameter) { while(1) { GPIOB_SetBits(GPIO_Pin_1); rt_thread_delay(1000); GPIOB_ResetBits(GPIO_Pin_1); rt_thread_delay(1000); //rt_kprintf("System running time:%d s\r\n",rt_tick_get()/RT_TICK_PER_SECOND); } } ``` 实际效果截图: [attach]14303[/attach]
风雨潇潇
2020-03-29
这家伙很懒,什么也没写!
是使用外部中断方式,用普通IO口设置为输入模式,配合定时器消抖完成。 配置相应的IO口和定时器设置。1ms进一次定时器中断,并且在board.c中初始化定时器 ``` /*Configure GPIO pins : PCPin PCPin */ GPIO_InitStruct.Pin = KEY2_Pin|KEY1_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); ``` ``` void MX_TIM1_Init(void) { TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; htim1.Instance = TIM1; htim1.Init.Prescaler = 79; htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 1000; htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter = 0; htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim1) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) { Error_Handler(); } } void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) { if(tim_baseHandle->Instance==TIM1) { /* USER CODE BEGIN TIM1_MspInit 0 */ /* USER CODE END TIM1_MspInit 0 */ /* TIM1 clock enable */ __HAL_RCC_TIM1_CLK_ENABLE(); /* USER CODE BEGIN TIM1_MspInit 1 */ HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, 1, 2); HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn); /* USER CODE END TIM1_MspInit 1 */ } } ``` ``` void rt_hw_board_init() { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); MX_USART3_UART_Init(); MX_TIM1_Init(); MX_IWDG_Init(); /* Call components board initial (use INIT_BOARD_EXPORT()) */ #ifdef RT_USING_COMPONENTS_INIT rt_components_board_init(); #endif #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP) rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get()); #endif } ``` 移植老师的Button方式,根据自己的硬件和需求做相应的修改。 当有按键事件发生时,利用消息队列发送消息, 在按键处理的线程中,一直接收消息,当接收到消息时,对接收到的数据进行解析和判断,如果符合要求则进行相应的处理 ``` // 按键定义 static Button_t s_tBtnKey3; static Button_t s_tBtnKey4; // Key3 按键引脚 #define Key3In HAL_GPIO_ReadPin(GPIOC , GPIO_PIN_2) // Key4 按键引脚 #define Key4In HAL_GPIO_ReadPin(GPIOC , GPIO_PIN_3) // 获取按键按下函数 static unsigned char IsKey3Down(void) {if (Key3In != KeyPressedLevel) return 0; return 1;} static unsigned char IsKey4Down(void) {if (Key4In != KeyPressedLevel) return 0; return 1;} void button_thread_entry(void *parameter)//用户消息处理入口函数 { rt_err_t uwRet = RT_EOK; uint8_t r_queue;//用于接收msg_mq消息队列信息 button_mq = rt_mq_create("button_mq", //消息队列名字 32, //消息的最大长度, bytes 10, //消息队列的最大容量(个数) RT_IPC_FLAG_FIFO //队列模式 FIFO ); if(button_mq != RT_NULL) rt_kprintf("button_mq create success\n\n"); ButtonInit();//按键硬件接口初始化 while(1) { //获取队列信息 uwRet = rt_mq_recv(button_mq, &r_queue, sizeof(r_queue), RT_WAITING_FOREVER ); if(RT_EOK == uwRet ) { switch(r_queue)//根据接收到的消息内容分别进行处理 { case KEY4_UP:K4PressHandle();break; case KEY4_LONG:K4LongPressHandle();break; case KEY3_UP:K3PressHandle();break; case KEY3_LONG:K3LongPressHandle();break; default: rt_kprintf("No button Message!\n\n");break; } } else { rt_kprintf("数据接收错误,错误代码:0x%lx\n\n",uwRet); } } } int button_process_init(void) { rt_thread_t tid; tid = rt_thread_create("button_process", button_thread_entry, RT_NULL, BUTTON_THREAD_STACK_SIZE, BUTTON_THREAD_PRIORITY, 10); if (tid != NULL) rt_thread_startup(tid); HAL_TIM_Base_Start_IT(&htim1); return 0; } ``` 在按键事件发生时,处理自定义的任务。 当Key3短按时LED_ON; 当Key4短按时LED_OFF; 当Key3长按时创建LED闪烁线程; 当Key4长按时删除LED线程。 ``` void K3PressHandle(void) { //LED_ON HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET); rt_kprintf("K3 Press!\n"); } void K3LongPressHandle(void) { //创建LED线程 //创建LED线程 if(led_thread == RT_NULL) { led_thread = rt_thread_create("ledThread", /* 线程名字 */ led_thread_entry, /* 线程入口函数 */ RT_NULL, /* 线程入口函数参数 */ 256, /* 线程栈大小 */ 5, /* 线程的优先级 */ 10 /* 线程时间片 */ ); if(led_thread != RT_NULL) { rt_thread_startup(led_thread); rt_kprintf("create success!\n"); } } else { rt_kprintf("led_thread exist!\n"); } } void K4PressHandle(void) { HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET); rt_kprintf("K4 Press!\n"); } void K4LongPressHandle(void) { //删除LED线程 if(led_thread != RT_NULL) { if(rt_thread_delete(led_thread) == RT_ERROR) { rt_kprintf("delete Faile!\n"); } else { rt_kprintf("delete success!\n"); led_thread = RT_NULL; HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET); } } else { rt_kprintf("led_thread not exist!\n"); } } ``` 在定时中断回调函数中调用按键扫描函数进行判断和消抖 ``` void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(TIM1 == htim->Instance) { ButtonProj(); } } ``` 效果链接[https://gitee.com/zhugexunyu/RT_Nano_L476/blob/master/GIF1.gif](GIF1)
瑞尧
2020-03-30
这家伙很懒,什么也没写!
需求:使用按键创建,删除动态线程 需要用到线程管理,外部中断(也可以是事件触发,使用事件集) 外部中断配置:将按键作为两个中断源,代码如下: ``` int EXTIX_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);//使能GPIOE时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3; //KEY1 KEY2对应引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉 GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE2,3 /* 为引脚赋初值 */ KEY1 = 1;KEY2 = 1; SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource2);//PE2 连接到中断线2 SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource3);//PE3 连接到中断线3 /* 配置EXTI_Line2,3 */ EXTI_InitStructure.EXTI_Line = EXTI_Line2 | EXTI_Line3; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发 EXTI_InitStructure.EXTI_LineCmd = ENABLE;//中断线使能 EXTI_Init(&EXTI_InitStructure);//配置 NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;//外部中断2 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道 NVIC_Init(&NVIC_InitStructure);//配置 NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;//外部中断3 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道 NVIC_Init(&NVIC_InitStructure);//配置 return RT_EOK; } INIT_APP_EXPORT(EXTIX_Init); ``` 再使用中断服务函数对线程的创建和删除进行操作,同时判断线程是否已经运行,防止多次创建或删除导致错误,代码如下; ``` //外部中断2服务程序 void EXTI2_IRQHandler(void) { if(led_thread == RT_NULL && KEY1==0) { led_thread = rt_thread_create("ledThread", /* 线程名字 */ led_thread_entry, /* 线程入口函数 */ RT_NULL, /* 线程入口函数参数 */ 256, /* 线程栈大小 */ 15, /* 线程的优先级 */ 10); /* 线程时间片 */ if(led_thread != RT_NULL) { /* 启动线程 */ rt_thread_startup(led_thread); rt_kprintf("led thread start ok!\n"); } else rt_kprintf("led thread start error!\n"); } else rt_kprintf("led thread started!\n"); EXTI_ClearITPendingBit(EXTI_Line2);//清除LINE2上的中断标志位 } void EXTI3_IRQHandler(void) { /* 线程已启动 */ if(led_thread != RT_NULL && KEY2 == 0) { /* 删除线程 */ if(rt_thread_delete(led_thread) == RT_ERROR) { rt_kprintf("delete led thread Faile!\n"); } else { rt_kprintf("delete led thread success!\n"); led_thread = RT_NULL; LED0 = 1; } } else rt_kprintf("led thread don`t start!\n"); EXTI_ClearITPendingBit(EXTI_Line3);//清除LINE3上的中断标志位 } ``` 至于创建的线程就是led闪烁操作,不再展示。 实现效果如下: [attach]14329[/attach]
BruceTan
2020-03-30
这家伙很懒,什么也没写!
一、开发环境: 1、硬件环境:野火霸道F103开发板 2、软件环境:RT-Thread Nano 源码、ST 3.5固件库、MDK5.25 二、实验目标: 熟悉按键的检测,熟悉线程的创建和删除。 三、实验思路: 1、首先需要进行按键检测,RT-Thread软件包里面有一些比较好用的按键软件包,不过我这里使用的是何老师提供的按键检测软件包。可以实现基本的消抖,短按,长按。还需要新建一个定时器,1ms检测一次按键,我使用的是RT-Thread的软件定时器。当检测到按键变化的时候,就通过消息队列发送消息,通知按键处理线程对不通的动作进行处理。 2、创建一个按键处理线程,接收消息队列的按键动作,创建或者删除线程。 3、为了方便观察,我这里动态创建和删除的是一个1s间隔的蜂鸣器响的线程。 四、实验步骤: 1、添加按键检测软件包,主要就是修改GPIO引脚为自己开发板的引脚,根据自己的板子电路设置按键按下是高电平还是低电平。 ``` /****************************************************************************************/ //用户添加自定义接口变量 /****************************************************************************************/ //------------------------------------------------------------------------------- // Key1 按键引脚 #define GPIO_CLK_Key1 RCC_APB2Periph_GPIOA #define GPIO_Pin_Key1 GPIO_Pin_0 #define GPIO_Mode_Key1 GPIO_Mode_IN_FLOATING #define GPIO_Key1 GPIOA #define Key1In GPIO_ReadInputDataBit(GPIO_Key1, GPIO_Pin_Key1) //------------------------------------------------------------------------------- // Key2 按键引脚 #define GPIO_CLK_Key2 RCC_APB2Periph_GPIOC #define GPIO_Pin_Key2 GPIO_Pin_13 #define GPIO_Mode_Key2 GPIO_Mode_IN_FLOATING #define GPIO_Key2 GPIOC #define Key2In GPIO_ReadInputDataBit(GPIO_Key2 , GPIO_Pin_Key2) /****************************************************************************************/ //用户添加自定义按键接口 /****************************************************************************************/ //----------------------------------------------------------------------------------------------- // Key按键按下时的电平,=0,按下时为低电平;=1,按下时为高电平 #define KeyPressedLevel 1 ``` 2、创建一个按键处理线程,接受消息队列的消息,根据消息进行按键处理。PS:按键的检测是通过软件定时器,以1ms为周期对按键进行检测。 ``` /******************************************************************************************************* ** 函数: button_timer_timeout 1ms周期调用底层按键检测函数 **------------------------------------------------------------------------------------------------------ ** 参数: void ** 返回: void ********************************************************************************************************/ void button_timer_timeout(void *parameter) { ButtonProj(); } ``` ``` /******************************************************************************************************* ** 函数: button_thread_entry,获取按键事件并进行处理 **------------------------------------------------------------------------------------------------------ ** 参数: void ** 返回: void ********************************************************************************************************/ void button_thread_entry(void *parameter)//用户消息处理入口函数 { rt_err_t uwRet = RT_EOK; uint8_t r_queue;//用于接收msg_mq消息队列信息 rt_timer_t button_timer;//用于定时调用按键检测函数 rt_thread_t tid = RT_NULL;//用于记录动态创建和删除线程的指针 button_mq = rt_mq_create("button_mq", //消息队列名字 1, //消息的最大长度, bytes 256, //消息队列的最大容量(个数) RT_IPC_FLAG_FIFO //如果有多个线程等待此消息,则使用先进先出的方式进行线程调用 ); if(button_mq != RT_NULL) rt_kprintf("button_mq create success\n\n"); ButtonInit();//按键硬件接口初始化 button_timer = rt_timer_create("button_timer", //定时器名字 button_timer_timeout, //定时器回调函数 RT_NULL, //参数 1, //1ms检测一次按键 RT_TIMER_FLAG_PERIODIC | //周期调用 RT_TIMER_FLAG_SOFT_TIMER ); //软件定时 if (button_timer != RT_NULL) rt_timer_start(button_timer); while(1) { //获取队列信息 uwRet = rt_mq_recv(button_mq, &r_queue, sizeof(r_queue), RT_WAITING_FOREVER ); if(RT_EOK == uwRet ) { switch(r_queue)//根据接收到的消息内容分别进行处理 { case KEY1_DOWN:rt_kprintf("Receive message:KEY1(PA.0) Down\n\n"); if( tid == RT_NULL ) { tid = beep_task_create(); if( tid != RT_NULL ) rt_kprintf("蜂鸣器线程创建成功!"); else rt_kprintf("蜂鸣器线程创建失败!"); } else rt_kprintf("蜂鸣器线程已存在!"); break; case KEY1_UP:rt_kprintf("Receive message:KEY1(PA.0) Up\n\n");break; case KEY1_LONG:rt_kprintf("Receive message:KEY1(PA.0) LongPressed Down\n\n"); break; case KEY2_DOWN:rt_kprintf("Receive message:KEY2(PC.13) Down\n\n"); if( tid != RT_NULL ) { if( rt_thread_delete(tid) == RT_EOK ) { rt_kprintf("蜂鸣器线程删除成功!"); tid = RT_NULL; } else rt_kprintf("蜂鸣器线程删除失败!"); } else { rt_kprintf("蜂鸣器线程还未创建!"); } break; case KEY2_UP:rt_kprintf("Receive message:KEY2(PC.13) Up\n\n");break; case KEY2_LONG:rt_kprintf("Receive message:KEY2(PC.13) LongPressed Down\n\n");break; default: rt_kprintf("No button Message!\n\n");break; } } else { rt_kprintf("数据接收错误,错误代码:0x%lx\n\n",uwRet); } } } ``` 四、实验结果: [attach]14361[/attach]
赵撵猪
2020-03-31
这家伙很懒,什么也没写!
[i=s] 本帖最后由 赵撵猪 于 2020-3-31 13:57 编辑 [/i] [list=1] [*]配置按键引脚[attach]14390[/attach] [*]代码编辑,代码先进行创建一个led闪烁的任务,通过按键将此任务删除,并且led最后是常亮的状态。 ``` #include
#include "led_task.h" #define led_task_PRIORITY 20 #define led_task_STACK_SIZE 1024 #define led_task_TIMESLICE 5 static rt_thread_t led_task_run_tid = RT_NULL; static rt_thread_t led_task_delete_tid = RT_NULL; static void led_task_entry(void *param) { while (1) { HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin); rt_thread_mdelay(800); } } int led_task_create(void) { led_task_run_tid = rt_thread_create("led_task_run", led_task_entry, RT_NULL, led_task_STACK_SIZE, led_task_PRIORITY, led_task_TIMESLICE); if (led_task_run_tid != RT_NULL) rt_thread_startup(led_task_run_tid); return 0; } INIT_DEVICE_EXPORT(led_task_create); MSH_CMD_EXPORT(led_task_create, led task create); static void led_task_delete_entry(void *param) { while (1) { if ((HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_12) == GPIO_PIN_RESET)&&(led_task_run_tid->stat != RT_THREAD_CLOSE)) { rt_thread_mdelay(20); if (HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_12) == GPIO_PIN_RESET) { rt_kprintf("led task delete...\r\n"); rt_thread_delete(led_task_run_tid); HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET); } } else if((HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_12) == GPIO_PIN_SET)&&(led_task_run_tid->stat == RT_THREAD_CLOSE)) { rt_thread_mdelay(20); if (HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_12) == GPIO_PIN_SET) { rt_kprintf("led task create...\r\n"); led_task_create(); } } rt_thread_mdelay(8000); } } int led_task_delete(void) { led_task_delete_tid = rt_thread_create("led_task_delete", led_task_delete_entry, RT_NULL, led_task_STACK_SIZE, led_task_PRIORITY, led_task_TIMESLICE); if (led_task_delete_tid != RT_NULL) rt_thread_startup(led_task_delete_tid); return 0; } INIT_DEVICE_EXPORT(led_task_delete); MSH_CMD_EXPORT(led_task_delete, led task delete); ``` [*]实验结果[attach]14393[/attach] [/list]
。。。
2020-04-01
这家伙很懒,什么也没写!
观看何老师的RT-Thread Nano-通用定时器(按键消抖)-消息队列的视频,我移植何老师编写的定时器与按键的两个代码文档,如下:[attach]14448[/attach] 我完成该作业的功能只需一个按键即可,连接按键的引脚为PE.3。 按键的相关代码和定时器的代码是使用老师编写的。 我采集了一个专门用来处理按键事件的线程。该线程中当按键按下弹起时动态线程button_Cre_th还没创建时,才创建一个动态线程button_Cre_th,该线程是实现每隔4秒打印一次当前系统运行时间;若按键按下弹起时动态线程button_Cre_th已经创建好了,则将该动态线程删除。有关该线程的代码如下: ``` static rt_thread_t button_Cre_th = RT_NULL; /******************************************************************************************************* ** 函数: button_thread_entry,获取按键事件并进行处理 **------------------------------------------------------------------------------------------------------ ** 参数: void ** 返回: void ********************************************************************************************************/ void button_thread_entry(void *parameter)//用户消息处理入口函数 { rt_err_t uwRet = RT_EOK; uint8_t r_queue;//用于接收msg_mq消息队列信息 button_mq = rt_mq_create("button_mq", //消息队列名字 1, //消息的最大长度, bytes 256, //消息队列的最大容量(个数) RT_IPC_FLAG_FIFO //队列模式 FIFO ); if(button_mq != RT_NULL) rt_kprintf("button_mq create success\n\n"); ButtonInit();//按键硬件接口初始化 while(1) { //获取队列信息 uwRet = rt_mq_recv(button_mq, &r_queue, sizeof(r_queue), RT_WAITING_FOREVER ); if(RT_EOK == uwRet ) { switch(r_queue)//根据接收到的消息内容分别进行处理 { case KEY1_DOWN:break; case KEY1_UP: if(button_Cre_th == RT_NULL) { button_Cre_th = rt_thread_create("button_Cre_th", button_Cre_thread_entry, RT_NULL, BUTTON_THREAD_STACK_SIZE, BUTTON_THREAD_PRIORITY, 10); if (button_Cre_th != RT_NULL) { rt_thread_startup(button_Cre_th); rt_kprintf("线程button_Cre_th创建成功\n\n"); } } else { uwRet = rt_thread_delete(button_Cre_th); if(RT_EOK == uwRet) { rt_kprintf("删除线程button_Cre_th成功\n\n"); button_Cre_th = RT_NULL; } } break; case KEY1_LONG:break; default: rt_kprintf("No button Message!\n\n");break; } } else { rt_kprintf("数据接收错误,错误代码:0x%lx\n\n",uwRet); } } } int button_process_init(void) { rt_thread_t tid; tid = rt_thread_create("button_process", button_thread_entry, RT_NULL, BUTTON_THREAD_STACK_SIZE, BUTTON_THREAD_PRIORITY, 10); if (tid != NULL) rt_thread_startup(tid); return 0; } INIT_APP_EXPORT(button_process_init); ``` 动态线程button_Cre_th实现每隔4秒打印一次当前系统运行时间的相关代码如下: ``` void button_Cre_thread_entry(void *parameter) { while(1) { rt_thread_mdelay(4000); rt_kprintf("System operation time:%dS\n",rt_tick_get()/RT_TICK_PER_SECOND); } } ``` 仿真情况如下: 1.未按过按键,线程的信息如下图: [attach]14451[/attach] 2.按一次按键,线程的信息如下图: [attach]14452[/attach] 线程中多出了一个button_Cre_th的线程。 3.按两次按键,线程的信息如下图: [attach]14453[/attach] 线程中的button_Cre_th线程被删除了。
ddllxxrr
2020-04-01
这家伙很懒,什么也没写!
#define MAIN_CONFIG #include "config.h" #include "stm32f10x.h" #define THREAD_PRIORITY 25 #define THREAD_STACK_SIZE 512 #define THREAD_TIMESLICE 5 static rt_thread_t tid1 = RT_NULL; static void thread1_entry(void *parameter) { rt_uint32_t count = 0; while (1) { rt_kprintf("thread1 count: %d\n", count ++); rt_thread_mdelay(500); } } int main(void) { TaskInit(); while(1) { LedToggle(GPIOA,GPIO_Pin_0); rt_thread_mdelay(1000); if( key1 == 1) { tid1 = rt_thread_create("thread1", thread1_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); if (tid1 != RT_NULL) rt_thread_startup(tid1); } else if(Key2 == 1) { rt_thread_delat(tid1); } } }
yichao
2020-04-01
这家伙很懒,什么也没写!
[i=s] 本帖最后由 yichao 于 2020-4-1 21:37 编辑 [/i] 1. 新建全局线程变量config.h EXT rt_thread_t create_by_key_thread; 2. 声明动态线程 task.h void create_by_key_thread_entry(void *parameter); task.c void create_by_key_thread_entry(void *parameter) { while(1) { rt_kprintf("thread by key created"); rt_thread_mdelay(500); } } 3. 按键触发 两个按键分别 动态创建和删除 void EXTI2_IRQHandler (void) { MSG_TYPE msg = MSG_KEY2_PRESS; if(EXTI_GetITStatus(EXTI_Line2) == SET ) { //Óû§´úÂë //rt_mq_send(msg_mq, "key2..pe.2", sizeof("key2..pe.2")); //rt_mq_send(msg_mq, &msg, sizeof(msg)); if(create_by_key_thread == RT_NULL) { create_by_key_thread = rt_thread_create("create_by_key_thread", create_by_key_thread_entry, RT_NULL, 256, 5, 10); if(create_by_key_thread != RT_NULL) { rt_thread_startup(create_by_key_thread); } } //-------------------------------- EXTI_ClearFlag(EXTI_Line2); } } void EXTI3_IRQHandler (void) { MSG_TYPE msg = MSG_KEY1_PRESS; if(EXTI_GetITStatus(EXTI_Line3) == SET ) { //Óû§´úÂë //rt_mq_send(msg_mq, "key1..pe.3", sizeof("key1..pe.3")); //rt_mq_send(msg_mq, &msg, sizeof(msg)); rt_err_t res = rt_thread_delete(create_by_key_thread); if(res == RT_EOK) { create_by_key_thread = RT_NULL; } //-------------------------------- EXTI_ClearFlag(EXTI_Line3); } } 软件仿真调试 通过msh list_thread查看是否按下创建成功和删除成功。 真实物理按键需要按键消抖。
guangying
2020-04-02
这家伙很懒,什么也没写!
[i=s] 本帖最后由 guangying 于 2020-4-2 10:04 编辑 [/i] [md]# 用按键创建和删除动态线程 **标准库函数(STD)版** ## 硬件平台介绍 正点原子NanoSTM32F103RBT6,本程序使用 2 个独立按键实现创建和删除线程,用 1 个 LED 的闪烁来说明线程创建成功。 ## 设计思路 使用两个独立按键,外部中断检测方式。因为只是用来练习线程的创建和删除,所以没有做按键消抖。按键 1 是创建线程,按键 2 是删除线程。当有按键被按下时,在外部中断中发送消息队列。按键信息处理线程接收消息队列,根据按键值创建或删除线程。 - 初始化按键GPIO - 初始化按键的外部中断(没有消抖) - 创建消息队列说明哪个按键按下 - 创建按键信息处理线程 - 填写被启动线程有关参数 ## 实现过程 ### 初始化按键 ``` c void Button_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入 GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化 PC8 和 PC9 } ``` ### 初始化按键外部中断 ``` c //外部中断初始化函数 void EXTIX_Init(void) { EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; //外部中断,需要使能AFIO时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO,ENABLE); //GPIOC.8 中断线以及中断初始化配置 GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource8); EXTI_InitStructure.EXTI_Line=EXTI_Line8; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发 EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); //初始化外设EXTI寄存器 //GPIOC.9 中断线以及中断初始化配置 GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource9); EXTI_InitStructure.EXTI_Line=EXTI_Line9; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); //初始化外设EXTI寄存器 //使能按键所在的外部中断通道 NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2, NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道 NVIC_Init(&NVIC_InitStructure); } void EXTI9_5_IRQHandler(void) { uint8_t msg = 0; if(EXTI_GetITStatus(EXTI_Line8)==SET) { msg = 1; rt_mq_send(msg_mq,&msg,sizeof(msg)); } if(EXTI_GetITStatus(EXTI_Line9)==SET) { msg = 2; rt_mq_send(msg_mq,&msg,sizeof(msg)); } EXTI_ClearITPendingBit(EXTI_Line8); //清除LINE8上的中断标志位 EXTI_ClearITPendingBit(EXTI_Line9); //清除LINE9上的中断标志位 } ``` ### 创建消息队列 ``` c //消息队列控制块定义---------------------------------- rt_mq_t msg_mq; //按键消息队列 //消息队列创建--------------------------------------- msg_mq = rt_mq_create("msg_mq_key",1,5,RT_IPC_FLAG_FIFO); if(msg_mq == RT_NULL) rt_kprintf("msg_mq_key Create failed\n"); ``` ### 创建按键信息处理线程 ``` c static rt_thread_t key_TH = RT_NULL; //按键处理线程控制块指针 //按键处理函数入口函数声明 static void msg_key_entry(void *parameter); // 创建按键信息处理线程 key_TH = rt_thread_create( "msg_key_TH", //线程名字 msg_key_entry, //线程入口函数名 RT_NULL, //线程入口函数参数 256, //栈大小 8, //优先级 10); //时间片 if(key_TH != RT_NULL) //线程创建成功则加入就绪队列 rt_thread_startup(key_TH); // 按键信息处理函数入口 static void msg_key_entry(void *parameter) { rt_err_t uwRet = RT_EOK; uint8_t r_queue; for(;;) { uwRet=rt_mq_recv( msg_mq, &r_queue, sizeof(r_queue), RT_WAITING_FOREVER); if(uwRet == RT_EOK) { switch(r_queue) { case 1: rt_kprintf("Rec Info:KEY1\n"); create_TH();break; //创建线程 case 0: rt_kprintf("Rec Info:KEY2\n"); delete_TH();break; //删除线程 default:rt_kprintf("Error\n"); } } else { rt_kprintf("Error Codes:0x%lx\n",uwRet); } } } ``` ### 填写被启动线程有关参数 ``` c //被创建线程控制块指针 static rt_thread_t dynamic_TH = RT_NULL; //被创建线程入口函数声明 static void create_led_entry(void *parameter); //线程创建 void create_TH(void) { dynamic_TH = rt_thread_create( "create_led_TH", //线程名字 create_led_entry, //线程入口函数名 RT_NULL, //线程入口函数参数 256, //栈大小 10, //优先级 10); //时间片 if(dynamic_TH != RT_NULL) //线程创建成功则加入就绪队列 { rt_thread_startup(key_TH); rt_kprintf("Thread created successfully\n"); } else rt_kprintf("Thread creation failed\n"); } //线程删除 void delete_TH(void) { rt_err_t uwRet = RT_EOK; uwRet = rt_thread_delete (dynamic_TH); if(uwRet == RT_EOK) rt_kprintf("Thread deleted successfully\n"); else rt_kprintf("Thread deleted failed\n"); } //被创建线程的入口函数 static void create_led_entry(void *parameter) { for(;;) { LED5 = !LED5; rt_thread_mdelay(500); } } ``` ## 下载验证 ### 查看按键信息处理线程,如下图 ![GGKNBq.png]( ![](https://s1.ax1x.com/2020/04/02/GGKNBq.png) ) ### 查看按键信息消息队列,如下图 ![GGKJjs.png]( ![](https://s1.ax1x.com/2020/04/02/GGKJjs.png) ) ### 按下创建线程按键,如下图 ![GGKGcj.png]( ![](https://s1.ax1x.com/2020/04/02/GGKGcj.png) ) ### 按下删除线程按键,如下图 ![GGK39g.png]( ![](https://s1.ax1x.com/2020/04/02/GGK39g.png) )[/md]
撰写答案
登录
注册新账号
关注者
0
被浏览
2.3k
关于作者
RT-Thread小喇叭
这家伙很懒,什么也没写!
提问
29
回答
54
被采纳
1
关注TA
发私信
相关问题
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
2
RT-Thread 发布 EtherKit开源以太网硬件!
3
rt-thread使用cherryusb实现虚拟串口
4
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
5
《原子操作:程序世界里的“最小魔法单位”解析》
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
ulog
C++_cpp
at_device
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
13
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
8
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
3
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部