手势识别rtos小车(3)----运动部分

c8t6和mini的程序不可以互通在freertos的情况下,配置差别很大,所以提前选好

pwm部分:

这部分包括了pwm的配置以及电机驱动

cpp 复制代码
#include "timer.h"
#include "led.h"
#include "usart.h"
#include "malloc.h"
#include "string.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "pwm.h"

//TIM3 PWM部分初始化
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数

void TIM1_PWM_Init(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);// 
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  //使能GPIO外设时钟使能
   //设置该引脚为复用输出功能,输出TIM1 CH1 CH4的PWM脉冲波形
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_11; //TIM_CH1 //TIM_CH4
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  不分频
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;                            //设置待装入捕获比较寄存器的脉冲值
	TIM_OCInitStructure.TIM_Pulse = arr >> 1;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;     //输出极性:TIM输出比较极性高
	TIM_OC1Init(TIM1, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
	TIM_OC4Init(TIM1, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx

  TIM_CtrlPWMOutputs(TIM1,ENABLE);	//MOE 主输出使能	

	TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);  //CH1预装载使能	 
	TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);  //CH4预装载使能	 
	
	TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIMx在ARR上的预装载寄存器
	
	TIM_Cmd(TIM1, ENABLE);  //使能TIM1
}

void Motor_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口时钟
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;	//端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     //50MHZ
  GPIO_Init(GPIOB, &GPIO_InitStructure);					      //根据设定参数初始化GPIOB 
	AIN1=0,AIN2=0;
	BIN1=0,BIN1=0;
}
void go(void)
{
	AIN1 = 0;
	AIN2 = 1;
	BIN1 = 0;
	BIN2 = 1;
}
void left(void)
{
	AIN1 = 1;
	AIN2 = 1;
	BIN1 = 0;
	BIN2 = 1;
}
void right(void)
{
	AIN1 = 0;
	AIN2 = 1;
	BIN1 = 1;
	BIN2 = 1;
}
void stop(void)
{
	AIN1 = 1;
	AIN2 = 1;
	BIN1 = 1;
	BIN2 = 1;
}

pwm.h

cpp 复制代码
#ifndef __PWM_H
#define __PWM_H
#include "stdio.h"	
#include "sys.h"

#define AIN2   PBout(15)
#define AIN1   PBout(14)
#define BIN1   PBout(13)
#define BIN2   PBout(12)

#define PWMA   TIM1->CCR1  //PA8
#define PWMB   TIM1->CCR4  //PA11


void TIM1_PWM_Init(u16 arr,u16 psc);
void Motor_Init(void);
void go(void);
void left(void);
void right(void);
void stop(void);
#endif

串口部分:

使用了串口1和串口2,串口1用来调试信息,串口2用来接收蓝牙信息

cpp 复制代码
#include "sys.h"
#include "usart.h"	
#include "string.h"
// 	 
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "FreeRTOS.h"					//FreeRTOS使用
#include "task.h"
#include "semphr.h"	 
#endif
 
 

//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 

}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
	return ch;
}
#endif 

 
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   	
u8 USART_RX_BUF1[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART_RX_STA1=0;       //接收状态标记	  
  
void uart_init(u32 bound)
{
	//GPIO端口设置
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, 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  

	//Usart1 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=7;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;		//子优先级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_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
	USART_Cmd(USART1, ENABLE);                    //使能串口1 
}

extern SemaphoreHandle_t BinarySemaphore1;	//二值信号量句柄

void USART1_IRQHandler(void)                	//串口1中断服务程序
{
	u8 Res;
	BaseType_t xHigherPriorityTaskWoken;
	
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	{
		Res =USART_ReceiveData(USART1);	//读取接收到的数据
		
		if((USART_RX_STA1&0x8000)==0)//接收未完成
			{
			if(USART_RX_STA1&0x4000)//接收到了0x0d
				{
				if(Res!=0x0a)USART_RX_STA1=0;//接收错误,重新开始
				else USART_RX_STA1|=0x8000;	//接收完成了 
				}
			else //还没收到0X0D
				{	
				if(Res==0x0d)USART_RX_STA1|=0x4000;
				else
					{
					USART_RX_BUF1[USART_RX_STA1&0X3FFF]=Res ;
					USART_RX_STA1++;
					if(USART_RX_STA1>(USART_REC_LEN-1))USART_RX_STA1=0;//接收数据错误,重新开始接收	  
					}		 
				}
			}   		 
     } 
	//释放二值信号量
	if((USART_RX_STA1&0x8000)&&(BinarySemaphore1!=NULL))//接收到数据,并且二值信号量有效
	{
		xSemaphoreGiveFromISR(BinarySemaphore1,&xHigherPriorityTaskWoken);	//释放二值信号量
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的话进行一次任务切换
	}
}

u16 USART_RX_STA2=0;       //接收状态标记	
u8 USART_RX_BUF2[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.

void USART2_Initialise( u32 bound )
{
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    USART_InitTypeDef USART_InitStructure; 
    
    /* Enable the USART2 Pins Software Remapping */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2|RCC_APB2Periph_AFIO, ENABLE);
    
    /* Configure USART2 Rx (PA.03) as input floating */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    /* Configure USART2 Tx (PA.02) as alternate function push-pull */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    /* Enable the USART2 Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 8;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);    
    
    USART_InitStructure.USART_BaudRate = bound;                
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    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(USART2, &USART_InitStructure);
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
    /* Enable USART2 */
    USART_Cmd(USART2, ENABLE);
}

extern SemaphoreHandle_t BinarySemaphore2;	//二值信号量句柄
void USART2_IRQHandler(void)  
{  
  u8 Res;
	BaseType_t xHigherPriorityTaskWoken;
	
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	{
		Res =USART_ReceiveData(USART2);	//读取接收到的数据
		
		if((USART_RX_STA2&0x8000)==0)//接收未完成
			{
			if(USART_RX_STA2&0x4000)//接收到了0x0d
				{
				if(Res!=0x0a)USART_RX_STA2=0;//接收错误,重新开始
				else USART_RX_STA2|=0x8000;	//接收完成了 
				}
			else //还没收到0X0D
				{	
				if(Res==0x0d)USART_RX_STA2|=0x4000;
				else
					{
					USART_RX_BUF2[USART_RX_STA2&0X3FFF]=Res ;
					USART_RX_STA2++;
					if(USART_RX_STA2>(USART_REC_LEN-1))USART_RX_STA2=0;//接收数据错误,重新开始接收	  
					}		 
				}
			}   		 
     } 
	//释放二值信号量
	if((USART_RX_STA2&0x8000)&&(BinarySemaphore2!=NULL))//接收到数据,并且二值信号量有效
	{
		xSemaphoreGiveFromISR(BinarySemaphore2,&xHigherPriorityTaskWoken);	//释放二值信号量
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的话进行一次任务切换
	}
}

主函数部分:

声明两个二值信号量,去分别判断两个串口是否有信息,创建三个任务,串口1,串口2,以及运动部分的任务。

配置任务的句柄,优先级等基本信息:

cpp 复制代码
//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		256  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);

//任务优先级
#define TASK1_TASK_PRIO		2
//任务堆栈大小	
#define TASK1_STK_SIZE 		256  
//任务句柄
TaskHandle_t Task1Task_Handler;
//任务函数
void task1_task(void *pvParameters);

//任务优先级
#define DATAPROCESS_TASK_PRIO 5
//任务堆栈大小	
#define DATAPROCESS_STK_SIZE  128 
//任务句柄
TaskHandle_t DataProcess_Handler;
//任务函数
void DataProcess_task(void *pvParameters);

//任务优先级
#define LANYA_TASK_PRIO 4
//任务堆栈大小	
#define DATAPROCESS_STK_SIZE  128 
//任务句柄
TaskHandle_t Lanya_Task_Handler;
//任务函数
void Lanya_task(void *pvParameters);

//任务优先级
#define YUNDONG_TASK_PRIO 3
//任务堆栈大小	
#define YUNDONG_SIZE  256 
//任务句柄
TaskHandle_t Yundong_Task_Handler;
//任务函数
void Yundong_Task(void *pvParameters);
cpp 复制代码
//二值信号量句柄
SemaphoreHandle_t BinarySemaphore1;	//二值信号量句柄1
SemaphoreHandle_t BinarySemaphore2;	//二值信号量句柄2

核心部分:

cpp 复制代码
int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 
	delay_init();	    				//延时函数初始化	 
	uart_init(115200);					//初始化串口
	USART2_Initialise(9600);		//初始化串口
	LED_Init();		  					//初始化LED
	KEY_Init();							//初始化按键
	mem_init();            				//初始化内部内存池
	TIM1_PWM_Init(899,0);
	Motor_Init();
	//创建开始任务
    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();          //开启任务调度
}

//开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
	
	//创建二值信号量
	BinarySemaphore1=xSemaphoreCreateBinary();	
	BinarySemaphore2=xSemaphoreCreateBinary();
    //创建TASK1任务
    xTaskCreate((TaskFunction_t )task1_task,             
                (const char*    )"task1_task",           
                (uint16_t       )TASK1_STK_SIZE,        
                (void*          )NULL,                  
                (UBaseType_t    )TASK1_TASK_PRIO,        
                (TaskHandle_t*  )&Task1Task_Handler);   
    //创建串口任务
    xTaskCreate((TaskFunction_t )DataProcess_task,     
                (const char*    )"keyprocess_task",   
                (uint16_t       )DATAPROCESS_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )DATAPROCESS_TASK_PRIO,
                (TaskHandle_t*  )&DataProcess_Handler); 
		//创建蓝牙任务
		xTaskCreate((TaskFunction_t )Lanya_task,     
                (const char*    )"lanya_task",   
                (uint16_t       )DATAPROCESS_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )LANYA_TASK_PRIO,
                (TaskHandle_t*  )&Lanya_Task_Handler); 
		//创建运动任务
		xTaskCreate((TaskFunction_t )Yundong_Task,     
                (const char*    )"yundong_task",   
                (uint16_t       )YUNDONG_SIZE,
                (void*          )NULL,
                (UBaseType_t    )YUNDONG_TASK_PRIO,
                (TaskHandle_t*  )&Yundong_Task_Handler); 
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

//task1任务函数
void task1_task(void *pvParameters)
{
	while(1)
	{
		LED0=!LED0;
        vTaskDelay(500);             	//延时500ms,也就是500个时钟节拍	
	}
}

//DataProcess_task函数
void DataProcess_task(void *pvParameters)
{
	u8 len=0;
	BaseType_t err=pdFALSE;
	
	u8 *CommandStr;
	while(1)
	{
		printf("QAQ\r\n");
		err=xSemaphoreTake(BinarySemaphore1,portMAX_DELAY);	//获取信号量
		if(err==pdTRUE)										//获取信号量成功
		{
			len=USART_RX_STA1&0x3fff;						//得到此次接收到的数据长度
			CommandStr=mymalloc(len+1);						//申请内存
			sprintf((char*)CommandStr,"%s",USART_RX_BUF1);
			CommandStr[len]='\0';							//加上字符串结尾符号
			printf("%s\r\n",CommandStr);		
			USART_RX_STA1=0;
			memset(USART_RX_BUF1,0,USART_REC_LEN);			//串口接收缓冲区清零
			myfree(CommandStr);								//释放内存
		}
		else
			{
				printf("无效的命令,请重新输入!!\r\n");
			}
	}
}
void Lanya_task(void *pvParameters)
{
	u8 len=0;
	BaseType_t err=pdFALSE;
	
	u8 *CommandStr;
	while(1)
	{
		err=xSemaphoreTake(BinarySemaphore2,portMAX_DELAY);	//获取信号量
		if(err==pdTRUE)										//获取信号量成功
		{
			len=USART_RX_STA2&0x3fff;						//得到此次接收到的数据长度
			printf("%s\r\n",USART_RX_BUF2);
			if(strcmp(USART_RX_BUF2,"1") == 0)
				value = 1;
			else if(strcmp(USART_RX_BUF2,"2") == 0)
			  value = 2;
			else if(strcmp(USART_RX_BUF2,"3") == 0)
			  value = 3;
			else if(strcmp(USART_RX_BUF2,"4") == 0)
			  value = 4;
			
			USART_RX_STA2=0;
			memset(USART_RX_BUF2,0,USART_REC_LEN);			//串口接收缓冲区清零
			myfree(CommandStr);								//释放内存
		}
	}
}
void Yundong_Task(void *pvParameters)
{
	while(1)
	{
		printf("数据是:%d\r\n",value);
		if(value == 1)
		{
			go();
			printf("1");
		}
		else if(value == 2)
		{
			left();
			printf("2");
		}
		else if(value == 3)
		{
			right();
			printf("3");
		}
		else if(value == 4)
		{
			stop();
			printf("4");
		}
		value = 0;
		vTaskDelay(50);
	}
}

我遇到的几个问题和总结:

1.当我在运动任务中不加入延时函数,即使这个任务的优先级最低,也还是会卡死,整个程序不执行,我目前还不是很清楚原因。猜测可能是在while循环出不去,完全占用了CPU,加入延时,可是将任务转为阻塞态,从而解放CPU。【记得延时】

2.任何东西配置完记得在int main函数里面初始化,不然也会卡死

3.我的串口1和2必须是115200和9600,串口才会有反应,目前不知道为啥,希望看到的大佬帮我解答一些。

相关推荐
blessing。。1 小时前
I2C学习
linux·单片机·嵌入式硬件·嵌入式
嵌新程3 小时前
day03(单片机高级)RTOS
stm32·单片机·嵌入式硬件·freertos·rtos·u575
Lin2012303 小时前
STM32 Keil5 attribute 关键字的用法
stm32·单片机·嵌入式硬件
电工小王(全国可飞)3 小时前
STM32 RAM在Memory Map中被分为3个区域
stm32·单片机·嵌入式硬件
maxiumII3 小时前
Diving into the STM32 HAL-----DAC笔记
笔记·stm32·嵌入式硬件
美式小田6 小时前
单片机学习笔记 9. 8×8LED点阵屏
笔记·单片机·嵌入式硬件·学习
兰_博6 小时前
51单片机-独立按键与数码管联动
单片机·嵌入式硬件·51单片机
时光の尘7 小时前
C语言菜鸟入门·关键字·float以及double的用法
运维·服务器·c语言·开发语言·stm32·单片机·c
嵌入式大圣8 小时前
单片机结合OpenCV
单片机·嵌入式硬件·opencv
日晨难再10 小时前
嵌入式:STM32的启动(Startup)文件解析
stm32·单片机·嵌入式硬件