STM32F103C8T6+FreeRTOS+USART1、3

STM32F103C8T6+FreeRTOS+USART1、3

1.FreeRTOS的配置

见文章

https://blog.csdn.net/weixin_39092315/article/details/108343954?spm=1001.2014.3001.5501

2.串口配置

		//GPIO端口设置
		GPIO_InitTypeDef GPIO_InitStructure;
		USART_InitTypeDef USART_InitStructure;
		NVIC_InitTypeDef NVIC_InitStructure;
		
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);	//使能USART1,GPIOA时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);												//使能USART1,GPIOA时钟
	
	//USART1_TX   GPIOA.9
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 															//PA.9
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;														//复用推挽输出
	GPIO_Init(GPIOA, &GPIO_InitStructure);																//初始化GPIOA.9
	
	//USART1_RX	  GPIOA.10初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;															//PA10
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;												//浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);																//初始化GPIOA.10  
	
	//USART3_TX   GPIOB.10
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;															//PB.10
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;														//复用推挽输出
	GPIO_Init(GPIOB, &GPIO_InitStructure);																//初始化GPIOA.9
	
	//USART3_RX	  GPIOB.11初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;															//PB11
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;												//浮空输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);																//初始化GPIOA.10  
	
	//Usart1 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;											//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;													//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;														//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);																		//根据指定的参数初始化VIC寄存器
	
	//Usart3 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;											//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;													//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;														//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);																		//根据指定的参数初始化VIC寄存器
	
	//USART 初始化设置
	
	USART_InitStructure.USART_BaudRate = bound;															//串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;											//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;												//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;													//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;						//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;										//收发模式
	
	USART_Init(USART1, &USART_InitStructure); 															//初始化串口1
	USART_Init(USART3, &USART_InitStructure); 															//初始化串口3
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);														//开启串口接受中断
	
	USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);														//开启串口接受中断
	
	USART_Cmd(USART1, ENABLE);                    														//使能串口1 
	USART_Cmd(USART3, ENABLE);                    														//使能串口3
	}
	```

这里配置串口1/2的方式和普通的方式基本一致,但是需要注意中断的优先级:

FreeRTOSconfig.h的 **“系统可管理优先级“#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	5  **           //系统可管理的最高中断优先级

意味着中断的优先级不能小于5,因为在FreeRTOS中数字越小优先级越高,所以我们需要取7,小于5大于32即可。

## 3.任务初始化

```//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);

//任务优先级
#define UART_TASK_PRIO		2
//任务堆栈大小	
#define UART_STK_SIZE 		50  
//任务句柄
TaskHandle_t UARTTask_Handler;
//任务函数
void UART_task(void *pvParameters);

这里定义了两个任务,优先级-运行内存-任务句柄-任务名称声明,运行内存C8只有10个1024,注意省着点。

4.主函数配置

	{
		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 
		delay_init();	    				//延时函数初始化	  
		uart_init(115200);					//初始化串口
		LED_Init();		  					//初始化LED
	//创建开始任务
	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();          //开启任务调度
	}```
	
中断优先级分组默认为4,,具体看注释即可。在这创建开始任务后,程序运行就不局限于main函数里了,开始由内核接管,开始任务调度的进程管理。

	//开始任务任务函数
	void start_task(void *pvParameters)
	{
	    taskENTER_CRITICAL();           //进入临界区
	    //创建UART任务
	    xTaskCreate((TaskFunction_t )UART_task,     	
	                (const char*    )"UART_task",   	
	                (uint16_t       )UART_STK_SIZE, 
	                (void*          )NULL,				
	                (UBaseType_t    )UART_TASK_PRIO,	
	                (TaskHandle_t*  )&UART_Handler); 
		vTaskDelete(StartTask_Handler); //删除开始任务
		taskEXIT_CRITICAL();            //退出临界区
	}
在main函数里创建完开始任务函数后,内核就会调用这个start_task任务,执行里面的语句,临界区的作用就是屏蔽外部中断、任务调度等,防止临界区内的代码被打断。但是尽量用在重要的地方。

start_task任务的作用就是创建真正的需要做的事情。

```void UART_task(void *pvParameters)
{
	while(1)
    {
        printf("111");
        vTaskDelay(500);
    }

}

创建任务后,就开始调用任务了。vTaskDelay(500)的作用就是告诉内核,我需要500ms的空闲时间,在这500ms中,内核就可以去调用其他任务(这里没有),如果每个任务都需要空闲时间,那么内核就会调用空闲任务。当空闲时间到了之后,内核就会按照到达的时间顺序执行任务,这时候就会有优先级的问题,详情请见手册介绍。

后,就开始调用任务了。vTaskDelay(500)的作用就是告诉内核,我需要500ms的空闲时间,在这500ms中,内核就可以去调用其他任务(这里没有),如果每个任务都需要空闲时间,那么内核就会调用空闲任务。当空闲时间到了之后,内核就会按照到达的时间顺序执行任务,这时候就会有优先级的问题,详情请见手册介绍。

注:printf是基于UART1包装的,可以基于此开拓。 后面应该会更新DMA的版本

上一篇:FreeRTOS例程3-串口中断接收不定长的数据与二值信号量的使用


下一篇:uart_init