一、实现的功能

  • 能够接收串口输入的数据
  • 数据范围设定为 0 — 65535,并设置超出范围设置错误提示
  • 利用freertos任务向电机发送数据
  • 利用串口控制电机位置

二、功能实现

省略基础配置
首先构建电机增量式位置环

float PID_Increase(Error sptr, PID_increase pid, float NowPlace, float Point)
{
 
	  float iError,//当前误差
	  Increase;	//最后得出的实际增量
 
	iError = Point - NowPlace;	// 计算当前误差
 
	Increase =  pid.P * (iError - sptr.Last_Error)   //比例P
			  + pid.I * iError      //积分I
			  + pid.D * (iError - 2 * sptr.Last_Error + sptr.Previous_Error);  //微分D
	
	sptr.Previous_Error = sptr.Last_Error;	// 更新前次误差
	sptr.Last_Error = iError;		  	// 更新上次误差
	
	return Increase;	// 返回增量
}

配置pid参数

typedef struct PID_INCREASE
{
	float P;
	float I;
	float D;
}PID_increase;

PID_increase increase6020;

最后得出赋给电机的电压值

current_6020 = PID_Increase( error6020 , increase6020 , GM6020_Receive[0].angel, angel);
//其中 angel为

配置串口收发程序(使用USART6)
收发原理具体看上一篇文章
《STM32串口收发》

int x;

struct __FILE 
{ 
	int handle; 
}; 

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

  
u8 USART_RX_BUF[USART_REC_LEN];     
u16 USART_RX_STA=0;       //接收状态标记	


void USART6_Init(u32 bound)      //打印使用
{
	GPIO_InitTypeDef gpio;
	USART_InitTypeDef usart;
	NVIC_InitTypeDef nvic;  
	
	//USART3时钟使能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6,ENABLE);
	RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOG, ENABLE);
	
	//串口3复用功能配置
	GPIO_PinAFConfig(GPIOG,GPIO_PinSource9,GPIO_AF_USART6); 
	GPIO_PinAFConfig(GPIOG,GPIO_PinSource14,GPIO_AF_USART6); 
	
	//USART3-->PD8,PD9
	GPIO_StructInit( &gpio);
	gpio.GPIO_Pin		= GPIO_Pin_9 | GPIO_Pin_14;
	gpio.GPIO_Mode 		= GPIO_Mode_AF;
	gpio.GPIO_OType		= GPIO_OType_PP;
	gpio.GPIO_Speed 	= GPIO_Speed_100MHz;
	gpio.GPIO_PuPd		= GPIO_PuPd_UP;
	GPIO_Init( GPIOG, &gpio);
	
	//串口初始化
	USART_DeInit(USART6);       
	usart.USART_BaudRate            = bound;  
	usart.USART_WordLength          = USART_WordLength_8b; 
  usart.USART_StopBits            = USART_StopBits_1; 
  usart.USART_Parity              = USART_Parity_No;					//无校验
	usart.USART_Mode                = USART_Mode_Tx | USART_Mode_Rx;    //收发模式
	usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 
	
	USART_Init(USART6,&usart);     	//串口3初始化
	USART_Cmd(USART6,ENABLE); 			//串口3使能
	USART_ClearFlag(USART6, USART_FLAG_TC);
	USART_ITConfig(USART6, USART_IT_RXNE, ENABLE);//串口3接收非空中断使能

	//USART3 NVIC 配置
	nvic.NVIC_IRQChannel 					= USART6_IRQn;			//串口3中断通道
	nvic.NVIC_IRQChannelPreemptionPriority	= 2;					//抢占优先级3
	nvic.NVIC_IRQChannelSubPriority 		= 2;					//子优先级2
	nvic.NVIC_IRQChannelCmd 				= ENABLE;				//IRQ通道使能
	NVIC_Init(&nvic);	//根据指定的参数初始化NVIC寄存器

}

/*************串口数据处理函数*********商洪涛2020.11.3*********************************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
	USART_SendData(pUSARTx,ch);
		
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET)
	{
	//	printf("Error:Can't get USART_FLAG_TXE");
	}		
}

void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
	unsigned int k=0;
  do 
  {
      Usart_SendByte( pUSARTx, *(str + k) );
      k++;
  } while(*(str + k)!='\0');
	
  while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
  {}
}
/*****************************串口数据处理函数*****end*********************************/



void USART6_IRQHandler(void)                	//串口6中断服务程序
{
	u8 Res,i;

	if(USART_GetITStatus(USART6, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	{
		Res =USART_ReceiveData(USART6);//(USART1->DR);	//读取接收到的数据
		
		if((USART_RX_STA&0x8000)==0)//接收未完成
		{
			if(USART_RX_STA&0x4000)//接收到了0x0d
			{
				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				else 
				{USART_RX_STA|=0x8000;	//接收完成了 
					x = 0;		
			    x = atoi(USART_RX_BUF);
					for(i=0;i<200;i++)
					{
                USART_RX_BUF[i] = 0;   
					}
				}
			}
			else //还没收到0X0D
			{	
				if(Res==0x0d)USART_RX_STA|=0x4000;
				else
				{
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
					USART_RX_STA++;
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
				}		 
			}
		}   
     		
  } 
}

USART.H

#define USART_REC_LEN  			200  	//定义最大接收字节数 200
#define EN_USART1_RX 			1		//使能(1)/禁止(0)串口1接收
	  	
extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART_RX_STA;         		//接收状态标记	
extern int x; //对接收的数据的整形类型

void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
void USART6_Init(u32 bound);

写中断函数计算闭环赋值电压

int counting = 0;
void TIM5_IRQHandler(void)  //中断服务函数
{
	if(TIM_GetITStatus(TIM5,TIM_IT_Update)==SET) //溢出中断
	{
		FreeRtosRuntimeticks++; //任务时间统计时基
		count++;
		if(count >= 20) //降低计算频率
		{
		YAW_spin(x);  //x为串口接收到的值
		count = 0;
		}
  }
    TIM_ClearITPendingBit(TIM5,TIM_IT_Update);
}

创建freertos任务

#define TASK_MOTOR_DEPTH    120    //堆栈
#define TASK_MOTOR_PRIO      3 //优先级

TaskHandle_t TASK_MOTOR_Handle;//任务句柄

void Task_MOTOR( void * pvParameters)//任务函数
{
	
	while(1)
	{
		taskENTER_CRITICAL();   //避免CAN加载函数被打断,故加入了临界保护段代码
		data_load_GM6020_pitch(current_6020);
		taskEXIT_CRITICAL();
		  vTaskDelay(5);
	}
}
//创建任务
xTaskCreate( (TaskFunction_t) Task_MOTOR,
                (const char *)  "Task_MOTOR", /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                (uint16_t) TASK_MOTOR_DEPTH,
                (void *) NULL,
                (UBaseType_t) TASK_MOTOR_PRIO,
                (TaskHandle_t *) &TASK_MOTOR_Handle );

三、功能演示


利用freertos实现串口控制CAN通信电机