任务的调度怎么实现按键终端和串口中断

u8 rx_i, count = 0;
volatile u8 rx_flag = 0; //rx_flag == 1 表示一帧数据接受完成 rx_flag == 0 清空标志位
u8 buffer[32] = {0};
u8 rx_buffer[32] = {0};

void USART1_IRQHandler(void)
{
//判断中段标志位是否置1
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
//清除中断标志位
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
//从串口1接收数据
buffer[count++] = USART_ReceiveData(USART1);
//判断接收到的数据是否’:’
if(buffer[count-1] == ‘:’)
{
//将buffer数据存储在rx_buffer,并过滤’:’
for(rx_i=0; rx_i<(count-1); rx_i++)
{
rx_buffer[rx_i] = buffer[rx_i];
}
count = 0; //下一帧从buffer[0]开始接收数据
memset(buffer, 0, sizeof(buffer));
}
rx_flag = 1; //表示一帧数据接受完成
}
}

//按键控制vcom值增减任务
void key1i_task(void *pvParameters)
{
while(1)
{

	if(PB5flag == 1)
	{		
			IncreaseVCOMS();
			LCD_Fill(0,0,20,20,YELLOW);
			TFT_display_number(0,0,vcoms,RED);
		PB5flag = 0;
	}	
	if(PB6flag == 1)
	{
			PB6flag = 0;
			DecreaseVCOMS();
			LCD_Fill(0,0,20,20,YELLOW);
			TFT_display_number(0,0,vcoms,RED);
	}	
	vTaskDelay(1); 
}

}
//屏幕显示vcom数值任务
void showScrNum_task(void *pvParameters)
{
while(1)
{
if(rx_flag == 1)
{
LCD_Fill(120,0,240,120,RED);//刷屏
LCD_ShowString(120,60,rx_buffer,GREEN,GREEN,32,1);
printf(“rx_buffer:%s\r\n”,rx_buffer);//电脑端打印
memset(rx_buffer, 0, sizeof(rx_buffer));
rx_flag = 0;
}
vTaskDelay(1);
}
}

我有一个功能是上位机输出字符串传到TFT然后接收显示在屏幕上,按键任务是实现寄存器读取vcom实现自增自减,这两个任务不能交替执行,当我按下按键后,上位机点击发送后TFT屏幕没有反应,直到按键按下他才显示,但是我的字符串显示任务都不关这个按键的事,要怎么做使得这两个任务可以交替执行?

Hi @Lin,
Could you please clarify the rationale behind delaying for only one tick in the vTaskDelay function? Is this intentional behavior or an unintended consequence?

According to the vTaskDelay documentation, the input parameter xTicksToDelay is measured in ticks, not milliseconds. A delay of one tick might be too brief for the kernel to switch to another task. Would you kindly consider increasing the delay duration to verify if task switching is executed as expected?

Here is the sample code:

vTaskDelay( pdMS_TO_TICKS(1) ); // This delays the task for 1 milisecond.

Thank you.

What you are doing here seems a bit strange. When you call vTaskDelay(1) it will result in the task being blocked and the scheduler runs immediately to schedule another task. What should happen (depending on the tick speed on your device of course) is that task 1 will run to the delay, and switch context in the middle of the first tick, then it will switch to the second task and this will run until the delay and then both tasks will sleep (be blocked) until the next tick happens. This does not seem like it is intentional.

It is also possible (depending what else is going on e.g. UART interrupts) that the task runs past the end of the current tick, in which case the first task will be interrupted in the middle of doing something like talking to the LCD, and then the second task will run and probably interfere with the 1st task LCD work.

If you want both tasks to run concurrently the best way to do this is to just remove the vTaskDelay(), but this seems not to be safe as both functions call LCD_Fill which will most likely interfere with each other.

When I look at your code it seems actually you do not want concurrency but you want to run alternately, if that is the case the best approach would be to create only one task doing the 2 things alternately like this, and remove the “while (1)” and “vTaskDelay” from each of those functions.

void taskFunction() {
  while (1)
  {
      key1i_task(...);
      showScrNum_task(...);
  }
}

If you do want to use tasks there are a few simple changes you can make that will cause the tasks to block until it is time to work which will free the CPU for other activities. These changes will also remove the need for vTaskDelay in your current code.

  1. The RX interrupt sets rx_flag on every RX interrupt, this could be a task notification or a semaphore, or even a queue write. I would recommend a queue write. If it is a queue write then the buffer code of the ISR can be removed and each character received would be written into the queue. The showScrNum_task would use a queue read to block until a character was added to the queue. Then the showScrNum_task would do all the processing of the messages and update the LCD as needed. showScrNum_task would stay blocked until a byte arrived, consuming zero CPU and the the RX ISR would be much simpler.

  2. Similarly the key1i_task could use an event_group with 1 bit for each flag. Then the process that sets PB5_flag and PB6_flag would set the appropriate bits in the event_group. The key1i_task would block waiting for a change in the event_group. Upon awaking, it would execute the two PBx_flag handlers and then go back to blocking. This would allow these tasks to use very little CPU only when something happened that needed attention.

  3. Check your LCD operations. It is possible that due to task concurrency, both tasks may attempt writing to the LCD at the same time and produce unexpected results including hanging the LCD controller. It is possible you already have that issue resolved and simply did not include the solution in this code snippet.

Good Luck