6a10

在这里插入图片描述
Appmain.c

#include "cmsis_os2.h"                  // ::CMSIS:RTOS2
#include "main.h"
#include "gpio.h"
#include "usart.h"
#include "MotorControl.h" 
#include "Appmain.h"
#include "canSendThread.h"
#include "spiwrite.h"
#include "appmain.h"

//uint16_t test_buf[256] __attribute__((at(0xC0000000)));	//定义一个数组,该数组首地址为SDRAM首地址0xC0000000 

uint64_t appThread_StackMemory[STACK_SIZE512] __attribute__((at(0x20028800)));

const osThreadAttr_t appmainthread_attr = {                           // 定义优先级
  .stack_mem = &appThread_StackMemory[0],
	.stack_size =sizeof(appThread_StackMemory)
};

osMessageQueueId_t canQSendMsgQ;                                      // CAN 发送队列 2k
const osMessageQueueAttr_t canSendMsgQ_attr = {
	.mq_mem = (void*)(0xc0013200),
	.mq_size = 4096
};

osMessageQueueId_t encodeQSendMsgQ;                                      // CAN 发送队列 2k
/*const osMessageQueueAttr_t encodeSendMsgQ_attr = {
	.mq_mem = &encodeQMsg_StackMemory[0],
	.mq_size = sizeof(encodeQMsg_StackMemory)
};*/


void app_main (void * arg);

/****************************************************************************
  File name:      motor.C
  Author: Wangyong      Version: 1.0        Date: 2020-04-14 
* 名称:  Init_MotorControlThreadThread
* 功能:  初始化电机控制线程 优先级 osPriorityAboveNormal 
          初始化队列 
* 调用者: kernal            
* 调用      
* 入口参数:无
* 出口参数:0 成功 1 失败
****************************************************************************/

int Init_appMainThreadThread (void) {
 
	canQSendMsgQ = osMessageQueueNew(16,sizeof(canReplyMsg_t),&canSendMsgQ_attr);
	encodeQSendMsgQ = osMessageQueueNew(4,sizeof(Message_t),NULL);
	osThreadNew (app_main, NULL, &appmainthread_attr);
	return 0;
}

void app_main (void * arg) {

   //Init_SpiWriteThread();
   Init_canSendThread();
	 Init_MotorControlThreadThread ();
	 while(1)
	 {
	  //HAL_UART_Transmit(&huart3, (uint8_t *)"Hello World", 12,0xFFFF);
		SETH(Run_Led_GPIO_Port,Run_Led_Pin);
		osDelay(1000);
		CLRL(Run_Led_GPIO_Port,Run_Led_Pin);
		osDelay(1000);
  }
	 
}




Appmain.h

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : aPPmain.h
  * @brief          : Header for main.c file.
  *                   This file contains the common defines of the application.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __APPMAIN_H
#define __APPMAIN_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
#define CANMSGSEND_SIZE  2048
#define ENCODEMSGSEND_SIZE 512

typedef struct
{
	 uint8_t buf[126];  // 数据
	 uint16_t Length;   // 长度
}Message_t;


typedef struct
{
	 uint16_t PackId;
	 uint8_t  packData[6];
	
}canReplayDataMsg_t;

#pragma pack(1)
typedef struct
{
	uint16_t heagPackId;
	uint32_t packLength;
	uint16_t packNum;
	canReplayDataMsg_t data[5];
	
}canReplyMsg_t;
#pragma pack()

typedef struct
{

	    uint8_t device_id;
	    uint8_t cmd;
	    uint8_t data[22];

	
}canReplyMsgbuf_t;

typedef union
{
	 struct
	 {
		  uint8_t state;
		  uint8_t action;
		  uint8_t hole;
		  uint8_t doorhole;
		  uint32_t errCode;
	 } openLidstatus;
	 uint8_t buf[8];
	 
}DevStatus_t;

/* USER CODE END ET */

/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
extern osMessageQueueId_t canQSendMsgQ; 
extern osMessageQueueId_t encodeQSendMsgQ; 
/* USER CODE END EC */

/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */

/* USER CODE END EM */

/* Exported functions prototypes ---------------------------------------------*/
extern void app_main (void * arg);
extern int Init_appMainThreadThread (void);
/* USER CODE BEGIN EFP */

/* USER CODE END EFP */

/* Private defines -----------------------------------------------------------*/
/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

#ifdef __cplusplus
}
#endif

#endif /* __MAIN_H */

MotorControl.c

#include "cmsis_os2.h"                                        // CMSIS RTOS header file
#include "MotorControl.h" 
#include "gpio.h"
#include "usart.h"
#include "w25qxx.h"
#include "pcd4641.h"
#include "string.h"
#include "ResetAction.h"
#include "CentrifugeTubeAction.h"
#include "pcrTubeAction.h"
#include "appmain.h"
#include "BaseAction.h"
#include "discMotorAction.h"
#include <stdlib.h>

#define DEV_NO    5

#define RST_CMD         1
#define READ_STATUS_CMD 0
#define OPEN_CAP_CMD    2
#define CLOSE_CAP_CMD   3
#define MOVE_DISC_CMD   4
#define READ_VER_CMD    5

#define NODATA_REPALY   3
#define VER_DATA        17

#define CAN_ERROR_STATE 7
#define CAN_ERROR_PARAM 6
#define CAM_ERROR_COMMAND 4

#define ADDR_FLASH_SECTOR_22 ((uint32_t) 0x81c0000)
#define ADDR_FLASH_SECTOR_23 ((uint32_t) 0x81E0000)
#define ADDR_OUTFLASH_SECTOR ((uint32_t) 0x8200000)
#define FLASH_SECTOR_22USE   ((uint32_t) ADDR_FLASH_SECTOR_22 - 4)
#define FLASH_SECTOR_23USE   ((uint32_t) ADDR_OUTFLASH_SECTOR - 4)
#define FLASH_WRITE_MAXNUM    ((uint32_t) 4096)

#define FLASH_DELAYTIME 50000
#define SECTOR_SIZE 0X20000

uint8_t verNo[VER_DATA] = {"V1.0.01rc20200605"};

osTimerId_t period10ms;
osThreadId_t MotorControl_Thread;                              // thread id
osSemaphoreId_t canRcvID;                                      // Can 消息接受信号
osSemaphoreId_t uart3RcvID;                                    // Can 消息接受信号
osEventFlagsId_t period10msEvt_id;
uint16_t canRcv_rd;                                            // Can 读指针
uint16_t canRcvPackId;                                         // Can 收到的包号
uint16_t canMsgRdPoint;
canRcv_Msg_t canMsg,*pCanRcvMsg;
uint32_t Timer_arg;
Motor_Action_t motorAction,*p_MotorAction;
Motor_ActionInfo_t *p_ExcuteAction;
uint8_t motorActionStep;
ActionType_e MotorMoveStatus;
uint8_t MotorMoveAxis;
uint16_t uart3Rcv_rd;
motor_Save_t saveMotorPara;
DiscAngle_Save_t saveDiscAnglePara;

uint8_t motorHasAction;
uint8_t motorActionStep;     
uint32_t motorExtStatus[Max_Axis];  //  马达状态
uint8_t actionCreateStep;
int32_t currentPosition;

int32_t motorRstsStatus;
Motor_ActionInfo_t *pAction;
int8_t HasCentrifugeTube; 
Message_t positionRcvMsg;
int32_t disc_Position;
uint32_t moveTime;
uint32_t canEcvCnt;
uint32_t canRcvPackCnt;

canReplyMsg_t canRepalyMsg;

DevStatus_t devStatus;

uint32_t statusWirteAdd;
uint16_t currentCapStatus;
uint64_t motor_StackMemory[STACK_SIZE2K] __attribute__((at(0x20028000)));

const osThreadAttr_t Motorthread_attr = {
  .priority = osPriorityAboveNormal ,                            // 定义优先级
  .stack_mem = &motor_StackMemory[0],
	.stack_size =sizeof(motor_StackMemory)
};

void MotorControlThread (void *argument);                              // thread function
void axis_stop(uint8_t axis_n);


const int32_t axisLimitDistance[Max_Axis] = {0,350,350,2200,0,3810,3810,350};

void Timer10msFunction(void *arg)
{
    osEventFlagsSet(period10msEvt_id, 0x00000001U);	
}
/****************************************************************************
  File name:      motor.C
  Author: Wangyong      Version: 1.0        Date: 2020-04-14 
* 名称:  Init_MotorControlThreadThread
* 功能:  初始化电机控制线程 优先级 osPriorityAboveNormal 
          初始化队列 
* 调用者: kernal            
* 调用      
* 入口参数:无
* 出口参数:0 成功 1 失败
****************************************************************************/

int Init_MotorControlThreadThread (void) {
 
	canRcvID = osSemaphoreNew(canBufLength,0,NULL);
  if (canRcvID == NULL)
		return -1;
	uart3RcvID = osSemaphoreNew(uartMsgBufLength,0,NULL);
  if (uart3RcvID == NULL)
		return -1;
	
	period10msEvt_id = osEventFlagsNew(NULL);
	
	period10ms = osTimerNew(Timer10msFunction,osTimerPeriodic,&Timer_arg,NULL);
	osTimerStart(period10ms,10);
	
	MotorControl_Thread = osThreadNew (MotorControlThread, NULL, &Motorthread_attr);
  if (!MotorControl_Thread) return(-1);
  
  return(0);
}

void changeDevRunStatus(uint8_t action)
{
	  devStatus.openLidstatus.doorhole = 0;
		devStatus.openLidstatus.hole = 0;
		devStatus.openLidstatus.action = action;
		devStatus.openLidstatus.state = 4;
}

void packCanReplayData(uint8_t cmd,uint8_t *pdata,uint8_t length)
{
	  canReplyMsgbuf_t pd;
	  uint8_t i,j,Fcs;
	  canReplayDataMsg_t *pCandata;
	  uint8_t *p;
	  
	  canRepalyMsg.heagPackId = 0;// 起始包Id  
	  canRepalyMsg.packLength = length+2;// 数据长度	  
	  canRepalyMsg.packNum = (canRepalyMsg.packLength+6)/6+1;// 命令包个数
	  
	  pd.cmd = cmd;
	  pd.device_id = DEV_NO;
	  Fcs= pd.cmd ^ pd.device_id;
	  if (length>0 && pdata!=NULL)
		{
	      for (i=0;i<length;i++)
	      {
			     pd.data[i] = pdata[i];
			     Fcs = Fcs^pd.data[i];
		    }
	   }
		pd.data[canRepalyMsg.packLength-2] = Fcs;
		p = (uint8_t *)(&pd);
	  for (i=0;i<canRepalyMsg.packNum;i++)
	  {
		 pCandata = &canRepalyMsg.data[i];
		 pCandata->PackId = i+1;
		 for (j=0;j<6;j++)
		    pCandata->packData[j] = *p++;
	  } 
}

void packErrReplay(uint8_t cmd,uint32_t Errcode)
{
    packCanReplayData(cmd,(uint8_t *)&Errcode,sizeof(Errcode));	 
}

uint16_t readuInt16(uint8_t *p)
{
	 return (uint16_t)p[0]+((uint16_t)p[1]<<8);
}

uint32_t readuInt32(uint8_t *p)
{
	 return (uint32_t)p[0]+((uint32_t)p[1]<<8)+((uint32_t)p[2]<<16)+((uint32_t)p[3]<<24);
}

/****************************************************************************
  File name:      motor.C
  Author: Wangyong      Version: 1.0        Date: 2020-04-14 
* 名称:  unSerilazePackData()
* 功能:  解包
* 调用者: MotorControlThread           
* 调用      
* 入口参数:无
* 出口参数:2 成功 0 失败 
****************************************************************************/

uint8_t unSerilazePackData()
{
	  //canPack *p;
	  uint8_t hole,doorhole;
	  canMsgPackData_t *p;
	  p = &canMsg.Data;
	
	  if (p->packdata[0] == DEV_NO)
    {
        switch (p->packdata[1])
				{
					case READ_STATUS_CMD:					
					     packCanReplayData(READ_STATUS_CMD,(uint8_t *)&devStatus,sizeof(devStatus));
						break;
					case RST_CMD:
					  if (devStatus.openLidstatus.state ==1 || devStatus.openLidstatus.state ==2 || devStatus.openLidstatus.state ==0)
						{    
						   changeDevRunStatus(0x1); 
							 CreateRstActionWithCapStatus();
			         motorHasAction = 1;  
               motorActionStep = 0;
							 packCanReplayData(RST_CMD,NULL,0);
							  
						}
					  else
							  packErrReplay(READ_STATUS_CMD|0x80,CAN_ERROR_STATE);

						break;
					case OPEN_CAP_CMD:
					  if (devStatus.openLidstatus.state !=1 && devStatus.openLidstatus.state !=2)
						{
							  packErrReplay(OPEN_CAP_CMD|0x80,CAN_ERROR_STATE);
						}	
            else
            {							
					      hole = (uint8_t)readuInt32(&p->packdata[2]);
					    	if (hole>0 && hole<=16)
						    {
					          changeDevRunStatus(0x2);
									  packCanReplayData(OPEN_CAP_CMD,NULL,0);
									  if (hole%2==0)
						          createOpendPcrTubeAction(hole/2,Omit_Well);
						        else
				  	          createLoosedCentrifugeAction(hole/2+1,Omit_Well);
						        motorHasAction = 1;  
                    motorActionStep = 0;
					      }	
                else
                {
                    packErrReplay(OPEN_CAP_CMD|0x80,CAN_ERROR_PARAM);
                }		
					   }				
						break;
					case CLOSE_CAP_CMD:					
					  if (devStatus.openLidstatus.state !=1 && devStatus.openLidstatus.state !=2)
						{
							  packErrReplay(CLOSE_CAP_CMD|0x80,CAN_ERROR_STATE);
						}
					  else
						{
					      hole = (uint8_t)readuInt16(&p->packdata[2]);
						    if (hole<=16)
						    {
						        changeDevRunStatus(0x3);
									  packCanReplayData(CLOSE_CAP_CMD,NULL,0); 
							      if (hole == 0)
									  hole = devStatus.openLidstatus.hole;
					           doorhole = (uint8_t)readuInt16(&p->packdata[4]);

					           if (hole%2==0)
						            createClosedPcrTubeAction(hole/2,doorhole);
						         else
				  	            createTiedCentrifugeAction(hole/2+1,doorhole);
						         motorHasAction = 1;  
                     motorActionStep = 0;
					     }
               else
               {
                    packErrReplay(CLOSE_CAP_CMD|0x80,CAN_ERROR_PARAM);
					     }
			  	 } 					  					 
					break;
					case MOVE_DISC_CMD:
					  if (devStatus.openLidstatus.state !=1 && devStatus.openLidstatus.state !=2)
							  packErrReplay(MOVE_DISC_CMD|0x80,CAN_ERROR_STATE);
					  else
						{
					      hole = (uint8_t)readuInt32(&p->packdata[2]);
							  if (hole>0 && hole<=16)
								{
					          changeDevRunStatus(2);
									  discMotorMove(hole);
						        packCanReplayData(MOVE_DISC_CMD,NULL,0);
									  motorHasAction = 1;  
                    motorActionStep = 0;
								}
								else
								    packErrReplay(READ_STATUS_CMD|0x80,CAN_ERROR_PARAM);	
						}
						break;
					case READ_VER_CMD:
						packCanReplayData(READ_VER_CMD,verNo,sizeof(verNo));
						break;
					default:
						packErrReplay(p->packdata[1]|0x80,CAM_ERROR_COMMAND);
						break;
				}
		}	
    else
    {
        packErrReplay(READ_STATUS_CMD|0x80,CAN_ERROR_PARAM);
    }			
    return 0;		
}

uint32_t stm32FlashReadWord(uint32_t readAdd)
{
	  return *(uint32_t *) readAdd;
}

uint16_t stm32FlashReadHalfWord(uint32_t readAdd)
{
	  return *(uint32_t *) readAdd;
}

uint32_t eraseSector(uint32_t page)
{
	  uint32_t SectorError = 0;
	  FLASH_EraseInitTypeDef FlashEraseInit;
	  FlashEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;
	  FlashEraseInit.Sector = page;
		FlashEraseInit.NbSectors =1;
	  FlashEraseInit.VoltageRange = FLASH_VOLTAGE_RANGE_3;
		HAL_FLASHEx_Erase(&FlashEraseInit,&SectorError);
		FLASH_WaitForLastOperation(FLASH_DELAYTIME);
	  return SectorError;
}

void CheckSector(uint32_t checkAdd,uint32_t NumToWrite,uint32_t page)
{
	 uint32_t endAddr;
	 endAddr = checkAdd+NumToWrite *4;
	 while (checkAdd<endAddr)
	 {
		  if (stm32FlashReadWord(checkAdd) != 0xffffffff)
			{
				 eraseSector(page);
			}
			else
				checkAdd = checkAdd+4;
	 }
}

void saveCurrentCapStatus(uint16_t capStatus)
{
	 HAL_FLASH_Unlock();
	 if (statusWirteAdd>ADDR_FLASH_SECTOR_22 && statusWirteAdd<ADDR_FLASH_SECTOR_23) // 写扇区23
	 {
		    if (statusWirteAdd>=(ADDR_FLASH_SECTOR_22+FLASH_WRITE_MAXNUM)) // 是否需要切换扇区
        {
           statusWirteAdd = ADDR_FLASH_SECTOR_23-2;
					 HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,statusWirteAdd,0x1); // 写擦除标记
					 FLASH_WaitForLastOperation(FLASH_DELAYTIME);				 
					 statusWirteAdd = ADDR_FLASH_SECTOR_23;
					 CheckSector(statusWirteAdd,SECTOR_SIZE/4,23); // 是否需要擦除 仅保护
					 HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,FLASH_SECTOR_23USE,0x1); // 写运行标记
					 FLASH_WaitForLastOperation(FLASH_DELAYTIME);
        }					
	 }
	 else if (statusWirteAdd>ADDR_FLASH_SECTOR_23 && statusWirteAdd<ADDR_OUTFLASH_SECTOR)
	 {
		   if (statusWirteAdd>=(ADDR_FLASH_SECTOR_23+FLASH_WRITE_MAXNUM)) // 是否需要切换扇区
        {
            statusWirteAdd = ADDR_OUTFLASH_SECTOR-2;
				    HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,statusWirteAdd,0x1); // 写擦除标记
				    FLASH_WaitForLastOperation(FLASH_DELAYTIME);					  
				    statusWirteAdd = ADDR_FLASH_SECTOR_22;
		        CheckSector(statusWirteAdd,SECTOR_SIZE/4,22); // 是否需要擦除 仅保护
					  HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,FLASH_SECTOR_22USE,0x1); // 写运行标记
					  FLASH_WaitForLastOperation(FLASH_DELAYTIME);
				}
	 }
	 FLASH_WaitForLastOperation(FLASH_DELAYTIME);
	 HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,statusWirteAdd,capStatus); // 写状态
	 statusWirteAdd=statusWirteAdd+2;
	 
	 HAL_FLASH_Lock();
	 
}

uint16_t getCurrentcapStatus()
{
    uint16_t status = 0;
	  if (stm32FlashReadHalfWord(FLASH_SECTOR_22USE) == 0xffff &&  stm32FlashReadHalfWord(FLASH_SECTOR_23USE == 0xffff))
		{
			 HAL_FLASH_Unlock();
			 HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,FLASH_SECTOR_22USE,0x1);
			 HAL_FLASH_Lock();
			 statusWirteAdd=ADDR_FLASH_SECTOR_22;
			 
		}
		else if (stm32FlashReadHalfWord(FLASH_SECTOR_22USE) == 1 && stm32FlashReadHalfWord(FLASH_SECTOR_22USE+2) == 0xffff)
		{
		     statusWirteAdd=ADDR_FLASH_SECTOR_22;				 
         while (stm32FlashReadHalfWord(statusWirteAdd)!=0xffff)
             statusWirteAdd +=2;
				 if(statusWirteAdd == ADDR_FLASH_SECTOR_22) // 如果首地址 说明 最后一个状态未写入 尝试读取另一个扇区数据
				    status =  stm32FlashReadHalfWord(ADDR_FLASH_SECTOR_23+FLASH_WRITE_MAXNUM-2);
         else				 
             status =  stm32FlashReadHalfWord(statusWirteAdd-2);	
			   if (stm32FlashReadHalfWord(FLASH_SECTOR_23USE) == 1 && stm32FlashReadHalfWord(FLASH_SECTOR_23USE+2) == 1)		
         {
            HAL_FLASH_Unlock();
			      eraseSector(23);
			      HAL_FLASH_Lock();			
		     } 				 
		}
		else if (stm32FlashReadHalfWord(FLASH_SECTOR_23USE) == 1 && stm32FlashReadHalfWord(FLASH_SECTOR_23USE+2) == 0xffff)
    {
        statusWirteAdd=ADDR_FLASH_SECTOR_23;				 
        while (stm32FlashReadHalfWord(statusWirteAdd)!=0xffff)
             statusWirteAdd +=2;
				if(statusWirteAdd == ADDR_FLASH_SECTOR_23) // 如果首地址 说明 最后一个状态未写入 尝试读取另一个扇区数据
				    status =  stm32FlashReadHalfWord(ADDR_FLASH_SECTOR_22+FLASH_WRITE_MAXNUM-2);
         else				 
             status =  stm32FlashReadHalfWord(statusWirteAdd-2);
				
			  if (stm32FlashReadHalfWord(FLASH_SECTOR_22USE) == 1 && stm32FlashReadHalfWord(FLASH_SECTOR_22USE+2) == 1)		
        {
           HAL_FLASH_Unlock();
			     eraseSector(22);
			     HAL_FLASH_Lock();			
		    }
				
    }
    else // 异常情况 重新擦除
		{
			 if (stm32FlashReadHalfWord(FLASH_SECTOR_22USE) == 1 
				 && stm32FlashReadHalfWord(FLASH_SECTOR_22USE+2) == 1
			   && stm32FlashReadHalfWord(FLASH_SECTOR_23USE) == 0xffff )		// 扇区满 但标记有问题 尝试读取另一个扇区数据
       {
	        status =  stm32FlashReadHalfWord(FLASH_SECTOR_22USE+FLASH_WRITE_MAXNUM-2);					 
			 }		 
			 if (stm32FlashReadHalfWord(FLASH_SECTOR_23USE) == 1 
				 && stm32FlashReadHalfWord(FLASH_SECTOR_23USE+2) == 1
			   && stm32FlashReadHalfWord(FLASH_SECTOR_22USE) == 0xffff )		// 扇区满 但标记有问题 尝试读取另一个扇区数据
       {
				  status =  stm32FlashReadHalfWord(FLASH_SECTOR_23USE+FLASH_WRITE_MAXNUM-2);	
			 }

			     HAL_FLASH_Unlock(); //全部复位
			     eraseSector(22);
			     eraseSector(23);
			     HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,FLASH_SECTOR_22USE,0x1); //写标志
			     HAL_FLASH_Lock();
			     statusWirteAdd=ADDR_FLASH_SECTOR_22;
       			 
		}   
		return status;		
}

/****************************************************************************
  File name:      motor.C
  Author: Wangyong      Version: 1.0        Date: 2020-04-14 
* 名称:  unPackCanMsg()
* 功能:  解包
* 调用者: MotorControlThread           
* 调用      
* 入口参数:无
* 出口参数:2 成功 0 失败 
****************************************************************************/

uint8_t unPackCanMsg()
{
	 canPack *p;
	 uint8_t i;
	
   p = &canRcvData[canRcv_rd];
   pCanRcvMsg = &canMsg;
	
	 canRcvPackId = (((uint16_t)p->packdata[1])<<8)+p->packdata[0];
	
	  // TODO 开缓冲判断stdID  由于目前只接受一个ID 不开缓冲
	 
	 if (canRcvPackId == 0) // 第一个数据包
	 {
		  canMsgRdPoint = 0;
		  pCanRcvMsg->Head.packNum =  (((uint16_t)p->packdata[7])<<8)+p->packdata[6]; //包个数
		  pCanRcvMsg->Head.packLength =(((uint16_t)p->packdata[5])<<24)+(((uint16_t)p->packdata[4])<<16)+
		                                (((uint16_t)p->packdata[3])<<8)+p->packdata[2]; //包长度
		 canRcvPackCnt++;
	 }
	 else
	 {
		   if (canRcvPackId > pCanRcvMsg->Head.packNum-1)
				 return 0;
			 if (pCanRcvMsg->Head.packNum == 0)
				 return 0;
		   for (i=0;i<6;i++)
		   {
				 pCanRcvMsg->Data.packdata[(canRcvPackId-1)*6+i]=p->packdata[i+2];
			 }
			 if (canRcvPackId == pCanRcvMsg->Head.packNum-1)
			 {
				   unSerilazePackData();
				   osMessageQueuePut(canQSendMsgQ,&canRepalyMsg,0,0);
				   pCanRcvMsg->Head.packNum = 0;
				   canEcvCnt++;
	
				   return 1;
			 }
	 }
	
	 return 0;
}

/****************************************************************************
  File name:      motorControl.C
  Author: Wangyong      Version: 1.0        Date: 2020-04-14 
* 名称:  readUint16_3Byte()
* 功能:  读取 3字节 转换为short
* 调用者: MotorControlThread           
* 调用      
* 入口参数:无
* 出口参数:2 成功 0 失败 
****************************************************************************/

uint16_t readUint16_3Byte(uint8_t *rp)
{
	  uint16_t value;
	  value = (*rp-0x30)*100+(*(rp+1)-0x30)*10+*(rp+2)-0x30;
	  //p= p+3;
	  return value;
}

/****************************************************************************
  File name:      motorControl.C
  Author: Wangyong      Version: 1.0        Date: 2020-04-14 
* 名称:  readUint16_3Byte()
* 功能:  读取 3字节 转换为short
* 调用者: MotorControlThread           
* 调用      
* 入口参数:无
* 出口参数:2 成功 0 失败 
****************************************************************************/

uint16_t readUint16_4Byte(uint8_t *rp)
{
	  uint16_t value;
	  value = (*rp-0x30)*1000+(*(rp+1)-0x30)*100+(*(rp+2)-0x30)*10 + *(rp+3)-0x30;
	  //p= p+3;
	  return value;
}   

/****************************************************************************
  File name:      motorControl.C
  Author: Wangyong      Version: 1.0        Date: 2020-04-14 
* 名称:  unPackUsart3Msg()
* 功能:  解包
* 调用者: MotorControlThread           
* 调用      
* 入口参数:无
* 出口参数:2 成功 0 失败 
****************************************************************************/

void unPackUsart3Msg()
{
	  uartPack *p_uart3Pack;
	  motor_Para_t *p;
	  uint8_t *rdCh;
	  uint32_t moveDistance;
	  uint8_t axis;
	  DiscAngle_Save_t *angleP;
	
	  //p = &saveMotorPara.DetalPara.para[0];
	  uint8_t  i;
	  p_uart3Pack=&uart3_MsgRcvBuf[uart3Rcv_rd];
	  rdCh = &p_uart3Pack->packdata[1];
	  if (p_uart3Pack->packdata[0] == 'K') // 电机参数设定
		{
			for (i=0;i<Max_Axis;i++)
			 {
				 p = &saveMotorPara.DetalPara.para[i];  
				 rdCh++; // Axis 信息忽略
				 p->LowSpeed =  readUint16_3Byte(rdCh);
				 rdCh = rdCh +3;
				 p->HighSpeed = readUint16_3Byte(rdCh);
				 rdCh = rdCh +3;
				 p->AssessTime = readUint16_3Byte(rdCh);
				 rdCh = rdCh +3;
				 p->DistancePerCycle = readUint16_3Byte(rdCh);
				 rdCh = rdCh +3;
				 p->PluseNumPerCycle = (uint32_t)readUint16_3Byte(rdCh) * 200;
				 rdCh = rdCh + 3;
				 p->MoveDistace = readUint16_4Byte(rdCh);
				 rdCh = rdCh+4;
				 p->Roate_logic = POSTIVE_LOGIC;
				 p->LimitDistance = 0;
				 p->LimitDistance=axisLimitDistance[i];
			 }
			 saveMotorPara.DetalPara.flag = 1;
			 W25QXX_Write(saveMotorPara.buf,0,sizeof(saveMotorPara)*8+1);
		}
		else if (p_uart3Pack->packdata[0] == 'D') //圆盘角度设定
		{
			 angleP = &saveDiscAnglePara;
			 angleP->AnglePara.centrifugeTubeAngle[0] = readUint16_4Byte(rdCh);
			 rdCh = rdCh+4;
			 angleP->AnglePara.pcrTubeAngle[0] = readUint16_4Byte(rdCh);
			 rdCh = rdCh+4;
			 angleP->AnglePara.discCentrifugeAngle = readUint16_4Byte(rdCh);
			 rdCh = rdCh+4;
			 angleP->AnglePara.discPcrAngle = readUint16_4Byte(rdCh);
			 angleP->AnglePara.flag = 1;
			 for (i=1;i<8;i++)
			 {
				  angleP->AnglePara.centrifugeTubeAngle[i] = angleP->AnglePara.centrifugeTubeAngle[i-1] + 450;
				  angleP->AnglePara.pcrTubeAngle[i] = angleP->AnglePara.pcrTubeAngle[i-1] +450;
				  
			 }
			 W25QXX_Write(saveDiscAnglePara.buf,4096,sizeof(DiscAngle_Save_t));
		}
		else if (p_uart3Pack->packdata[0] == 'r')
		{
        CreateRstActionWithCapStatus();
			  motorHasAction = 1;  
        motorActionStep = 0;			
		}
		else if (p_uart3Pack->packdata[0] == 'o')
		{
        //createTiedCentrifugeAction();
			  rdCh = &p_uart3Pack->packdata[1];
			  if (*rdCh == 0x31)
				{
			      rdCh++;
					  createLoosedCentrifugeAction((*rdCh-0x30),Omit_Well);
				}
				else
			  {						 
					  rdCh++;
					  createOpendPcrTubeAction((*rdCh-0x30),Omit_Well);
			  }
			   motorHasAction = 1;   
         motorActionStep = 0;  			
		}
	  else if (p_uart3Pack->packdata[0] == 'c')
		{
			  if (*rdCh == 0x31)
				{
			      rdCh++;
					  createTiedCentrifugeAction((*rdCh-0x30),Omit_Well);
				}
				else
			  {		
					  rdCh++;
					  createClosedPcrTubeAction((*rdCh-0x30),Omit_Well);
			  }
			  //createLoosedCentrifugeAction();
			  motorHasAction = 1;
				motorActionStep = 0;
		}
		else if (p_uart3Pack->packdata[0] == 't')
		{
			  axis = *rdCh-0x31;
			  rdCh++;
			  moveDistance = readUint16_4Byte(rdCh);
			  if (axis<8)
				{
				    if (axis == DISC_TURNING_AXIS)
						{
							  osMessageQueueReset(encodeQSendMsgQ);
							  rstActtionList();
							  disRotation(moveDistance);
							  motorAction.Step = actionCreateStep;
							  motorHasAction = 1;
				        motorActionStep = 0;
						}
						else if (axis == CENTRIFUGE_CAP)
						{
						     //SETM0();
						     //startCentrifugeTubeCapMotor();
							  rstActtionList();
							  loose_CentrifugeTubeCap();
							  motorAction.Step = actionCreateStep;
							  motorHasAction = 1;
				        motorActionStep = 0;
						}
						else
						{
					      createMoveAxisTestModeAction(axis,moveDistance);
			          //createLoosedCentrifugeAction();
			          motorHasAction = 1;
				        motorActionStep = 0;
						}
				}
		}
		else if (p_uart3Pack->packdata[0] == 'a')
		{		    
			  rstDiscMotorAction();
			  motorHasAction = 1;
				motorActionStep = 0;
		}
}

/****************************************************************************
  File name:      motorControl.C
  Author: wangyong      Version: 1.0        Date: 2015-01-19
* 名称:Excute_Motor_Action() 
* 功能:读圆盘绝对位置
* 调用者:MotorControlThread
* 入口参数:无
* 出口参数:无
****************************************************************************/
void read_EncodePosition()
{
	 uint8_t ReadPositionCmd[4] = {0x44,0x30,0x31,0x0d};
	 HAL_UART_Transmit(&huart4,ReadPositionCmd,4,4);
}

void calcEncodePosition()
{
	 uint8_t i;
	 disc_Position = 0;
	 for(i=0;i<10;i++)
	 {
		 disc_Position*=10;
		 disc_Position += (uint32_t)(positionRcvMsg.buf[5+i] -0x30);
	 }
}

/****************************************************************************
  File name:      motorControl.C
  Author: wangyong      Version: 1.0        Date: 2015-01-19
* 名称:changeStep()
* 功能:序列器切换
* 调用者:Excute_Motor_Action() 
* 入口参数:无
* 出口参数:0 运行结束 1 运行未结束
****************************************************************************/
uint8_t changeStep()
{
	   uint8_t i;
	   if (1 == p_MotorAction->RepeatFlag)  // 有重复动作
     {
         if (motorActionStep<p_MotorAction->RepeatEnd-1)
         {
             motorActionStep++;
         }  
         else
         {
             motorActionStep = p_MotorAction->RepeatStart-1;
             for (i=motorActionStep;i<p_MotorAction->RepeatEnd;i++)
             {
                  p_MotorAction->Action[i].ExcuteStatus = 0;
             }
          }  
          return 1; 
     }   // if (1 == MotorActionptr->RepeatFlag)
     else  // 无重复动作
     {
        if (motorActionStep<p_MotorAction->Step-1) // 不是最后一节
        {                 
            motorActionStep++;
            return 1;
        }
        else
        {
            return 0;  // 运行结束
        }
     }
}



/****************************************************************************
  File name:      motorControl.C
  Author: wangyong      Version: 1.0        Date: 2015-01-19
* 名称:Excute_Motor_Action() 
* 功能:马达动作序列执行
* 调用者:MotorControlThread
* 入口参数:无
* 出口参数:UCHAR 0-- 运行全部结束  1--运行未结束  2-- 开门状态 
****************************************************************************/

uint8_t Excute_Motor_Action()
{  
   uint8_t excuteStatus;  
	 int32_t pluse;
	 int32_t disc_MovePosition;
	 uint16_t writeCapStatus;
	 osStatus_t status;
	  uint32_t flags;
	 //uint16_t io;
	  
	  motor_Para_t *pAxis;
	
	  p_MotorAction = &motorAction;
	  p_ExcuteAction = &motorAction.Action[motorActionStep];
    MotorMoveAxis = p_ExcuteAction ->ActionAxis;
    MotorMoveStatus = p_ExcuteAction ->status;
	
	  if (0 == p_ExcuteAction->ExcuteStatus)   // 动作未执行完毕
		{
        p_ExcuteAction->ExcuteStatus = 1; 

				switch(MotorMoveStatus)
        {
				    case STOP:
									 axis_stop_dec(MotorMoveAxis);
							     break;
					  case MOVE_LIMIT:
						case MOVE_ORG:
								   axis_Move(MotorMoveAxis,p_ExcuteAction);                 
                   break;
						case MOVE_POSITION:							    
	                  pAxis = &saveMotorPara.DetalPara.para[MotorMoveAxis];
	                  pluse = p_ExcuteAction->Postiontion *pAxis->PluseNumPerCycle/ pAxis->DistancePerCycle; 
	                  currentPosition = axis_read_pulse_count(MotorMoveAxis);
	                  pluse -=currentPosition;
							      if (pluse>=0)
	    	               p_ExcuteAction->ControlMode = Liner_Nes_Pre_NoOrgSL;
		                else
			                 p_ExcuteAction->ControlMode = Liner_Pos_Pre_NoOrgSL;
	                  p_ExcuteAction->StartMode= Start_Motor_IntDisable_HighSpeed;
							      p_ExcuteAction->Postiontion = abs(pluse);

						case MOVE_PLUSE:
								   axis_rmv_write(MotorMoveAxis,p_ExcuteAction->Postiontion);
								   axis_Move(MotorMoveAxis,p_ExcuteAction); 
							     break;    
						case ENCODE_POSION_READ: // 编码电机数据读取
								    read_EncodePosition();
								    break;
						case LOOSE:
						     SETM0();
						     startCentrifugeTubeCapMotor();
						     osDelay(2);
						     moveTime = 0;
							    break;
						case TIED:
						     CLRM0();
						     startCentrifugeTubeCapMotor();
						     osDelay(2);
						     moveTime =0;
							   break;
						case DISC_ROTATION:
							   pAxis = &saveMotorPara.DetalPara.para[MotorMoveAxis];
							   currentPosition = axis_read_pulse_count(MotorMoveAxis);
						     currentPosition = currentPosition%(pAxis->PluseNumPerCycle*3);
						     axis_pulse_count_write(MotorMoveAxis,currentPosition);
						     disc_MovePosition = p_ExcuteAction->Postiontion * (pAxis->PluseNumPerCycle*3)/3600;
						     if (disc_MovePosition<currentPosition)
									  pluse = pAxis->PluseNumPerCycle*3+disc_MovePosition - currentPosition;
								 else
									  pluse = disc_MovePosition - currentPosition;
							   /*if ((p_ExcuteAction->Postiontion)*5/200<disc_Position) // 计算旋转角度 精确到0.1
								 {
									  pluse = (ENCODEPLUSEPERCYCLE-disc_Position)*100+p_ExcuteAction->Postiontion*ENCODEPLUSEPERCYCLE/360;
								 }
								 else
								 {
									  pluse = p_ExcuteAction->Postiontion*ENCODEPLUSEPERCYCLE/360-disc_Position*100;
								 }*/
								 
								 //pluse = pluse*pAxis->PluseNumPerCycle/(ENCODEPLUSEPERCYCLE*100);
								 p_ExcuteAction->ControlMode = Liner_Nes_Pre_NoOrgSL;
								 p_ExcuteAction->StartMode= Start_Motor_IntDisable_HighSpeed;
								 axis_rmv_write(MotorMoveAxis,pluse);
								 axis_Move(MotorMoveAxis,p_ExcuteAction);
							   break;
            case CHANGESTATUS:
							   devStatus.openLidstatus.doorhole = p_ExcuteAction->doorhole;
						     devStatus.openLidstatus.hole = p_ExcuteAction->hole;
						     devStatus.openLidstatus.action = p_ExcuteAction->devStatus&0xf;
						     devStatus.openLidstatus.state = p_ExcuteAction->devStatus>>4;
							break;
						case WRITECAPSTATUS:
						  	writeCapStatus = ((uint16_t)p_ExcuteAction->hole<<8) + p_ExcuteAction->doorhole;
						    currentCapStatus = writeCapStatus;
						    saveCurrentCapStatus(writeCapStatus);
							  break;
						default:
								      ;
				}
			  
				return 1;
     }			
		 else
		 {
			  if (WAIT == MotorMoveStatus)
				{
            return 0;					
				}
			  else if (CHANGESTATUS == MotorMoveStatus )
			  {
				    excuteStatus = changeStep();
					  return excuteStatus;
			  }
				else if (ENCODE_POSION_READ == MotorMoveStatus)
				{
					  status = osMessageQueueGet(encodeQSendMsgQ,&positionRcvMsg,0U,0U);
					  if (osOK == status) 
						{
					      calcEncodePosition();
							  excuteStatus = changeStep();
								return excuteStatus;
            }		
            return 1;						
				}
				else if (LOOSE == MotorMoveStatus || TIED ==  MotorMoveStatus)
				{
					  //io = MOVE;
					  flags = osEventFlagsWait(period10msEvt_id, 0x00000001U, osFlagsWaitAny,0x1U);
            if (flags == 0x00000001U)		
               moveTime ++;							
					  if (!(MOVE) && moveTime>600)
						{
							  excuteStatus = changeStep();
								return excuteStatus;
						}
					  return 1;
				}
				else
				{
			      motorExtStatus[MotorMoveAxis]=axis_read_outstatus(MotorMoveAxis);
			      if (!(motorExtStatus[MotorMoveAxis] & 0x8))  // 运动 停止
				    {
					        p_ExcuteAction->ExcuteStatus = 2; 
							    if (MOVE_ORG == MotorMoveStatus)
									{
										  axis_pulse_count_rst(MotorMoveAxis);											
									}
                  excuteStatus = changeStep();
									return excuteStatus;
									/*if (1 == p_MotorAction->RepeatFlag)  // 有重复动作
                  {
                        if (motorActionStep<p_MotorAction->RepeatEnd-1)
                        {
                            motorActionStep++;
                        }  
                        else
                        {
                            motorActionStep = p_MotorAction->RepeatStart-1;
                            for (i=motorActionStep;i<p_MotorAction->RepeatEnd;i++)
                            {
                                p_MotorAction->Action[i].ExcuteStatus = 0;
                            }
                        }  
                        return 1; 
                    }   // if (1 == MotorActionptr->RepeatFlag)
                    else  // 无重复动作
                    {
                        if (motorActionStep<p_MotorAction->Step-1) // 不是最后一节
                        {
                    
                            motorActionStep++;
                            return 1;
                        }
                        else
                        {
                             return 0;  // 运行结束
                        }
                    }*/
				    }
				    else
				    {
				        return 1;	
				    }
			  }
		 }
}






/****************************************************************************
  File name:      motor.C
  Author: Wangyong      Version: 1.0        Date: 2030-04-14 
* 名称:  void MotorControlThread (void *argument)
* 功能:  主线程 根据队列消息控制电机运行,完成开关盖动作              
* 调用者:  kernal            
* 调用      
* 入口参数:*argument
* 出口参数:无
****************************************************************************/

pcd4641_dev_t MotorChip;

void MotorControlThread (void *argument) 
{
    uint8_t TxData[3] = {"Ack"};
	  uint16_t i;
		osStatus_t Status;
		CAN_Start();    // 开启CAN 
		HAL_UART_Receive_IT(&huart3, (uint8_t *)&ustart3RdChar, 1); // 开Ustart3 中断 
	  HAL_UART_Receive_IT(&huart4, (uint8_t *)&uart4RdChar, 1); // 开Ustart4 中断 
	  //HAL_UART_Transmit(&huart4,TxData,8,10);
	  W25QXX_Init();  // 读电机参数
	  W25QXX_Read(saveMotorPara.buf,0,sizeof(motor_Para_t)*8+1);
		uart3Rcv_rd = 0;
		canEcvCnt = 0;
		canRcvPackCnt = 0;
	  if (saveMotorPara.DetalPara.flag!=1)
		{
       for (i=0;i<8;i++)
			 {
				  saveMotorPara.DetalPara.para[i].LowSpeed = 60;
				  saveMotorPara.DetalPara.para[i].HighSpeed = 300;
			 }
			 W25QXX_Write(saveMotorPara.buf,0,sizeof(motor_Para_t)*8+1);			
		}
		
		W25QXX_Read(saveDiscAnglePara.buf,4096,sizeof(DiscAngle_Save_t));
		
	  pcd4641_init(&MotorChip,&saveMotorPara);
		read_EncodePosition();
		
		SETALLMODE(); //CentrifugeTubeCapMotor M0 M1 M2 000 
		
//		currentCapStatus = getCurrentcapStatus();
		//CLRALLMODE();
    //CLRM0();
		//CLRSTART();
		//startCentrifugeTubeCapMotor();

	  //axis_SearchOrg(0,0);
    /*axis_stop(1);
		axis_rmv_write(1,100000);
		pcd4641_write_command_regs(1,0x44,NULL,0);
	  pcd4641_write_command_regs(1,0X15,NULL,0);
		axis_stop(1);
    axis_pulse_count_rst(6);
		k = axis_read_pulse_count(6);
		axis_rmv_write(6,100);
		osDelay(1000);
		k = axis_read_pulse_count(6);*/
		//W25QXX_Erase_Sector(2);
		//W25QXX_Erase_Sector(3);
		

		
		motorHasAction = 0;
		
		memset(&devStatus,0,sizeof(devStatus));
		devStatus.openLidstatus.action = 0;
		
		//CreatRstAction();
		//motorHasAction = 1;
    while (1) 
		{
		  //TODO 添加时基 5ms  
			if (motorHasAction)
					 motorHasAction = Excute_Motor_Action();
			
			  Status = osSemaphoreAcquire(canRcvID,1U);
			  if (osOK == Status) // 接收到Can 数据
			  {
					 unPackCanMsg();
					 //CAN_SendData(0x100,(uint8_t *)"CAN RCV",7);
					 canRcv_rd++;
					 canRcv_rd%=canBufLength;
				}
				
				Status = osSemaphoreAcquire(uart3RcvID,1U);
			  if (osOK == Status) // 接收到Pc数据
			  {
					 unPackUsart3Msg();
					 uart3Rcv_rd++;
					 uart3Rcv_rd%=uartMsgBufLength;
					 HAL_UART_Transmit(&huart3,TxData,3,1); // send Ack
				}
				
				osDelay(1);
			
		/*
		SETH(Status_Led_GPIO_Port,Status_Led_Pin);
		osDelay(1000);
		//CLRL(Status_Led_GPIO_Port,Status_Led_Pin);
		//osDelay(1000);         		// suspend thread
		CAN_SendData(0x600,TxData,8);*/
    }
}

MotorControl.h

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : aPPmain.h
  * @brief          : Header for main.c file.
  *                   This file contains the common defines of the application.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MOTORCONTROL_H
#define __MOTORCONTROL_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "cmsis_os2.h" 
#include "sys_stru.h"


/* Private includes ----------------------------------------------------------*/
#include "can.h"

#define CanPackDataLength    1024
#define MaxActionStep        100

/* USER CODE BEGIN Includes */

typedef struct
{
	uint32_t packstdID;
	uint32_t packLength;
	uint16_t packNum;
} canMsgPackHead_t;

typedef struct
{
	uint8_t packdata[CanPackDataLength];
} canMsgPackData_t;

typedef struct
{
	canMsgPackHead_t Head;
	canMsgPackData_t Data;
} canRcv_Msg_t;


typedef struct
{
  Motor_ActionInfo_t Action[MaxActionStep];  
  uint8_t         Step;                      // 动作步骤数
	uint8_t   RepeatFlag;   // 0- 单次  1--重复 
  uint8_t   RepeatEnd;          
  uint8_t   RepeatStart;
} Motor_Action_t;


extern Motor_Action_t motorAction,*p_MotorAction;	
extern uint8_t actionCreateStep;
extern int32_t motorRstsStatus;
extern Motor_ActionInfo_t *pAction;
extern int8_t HasCentrifugeTube; 

extern void MotorControlThread (void *argument);                              // thread function
extern osThreadId_t MotorControl_Thread;                                      // thread id
extern int Init_MotorControlThreadThread (void);
extern motor_Save_t saveMotorPara;
extern DiscAngle_Save_t saveDiscAnglePara;

/* USER CODE END Includes */

/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */

/* USER CODE END ET */

/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */

/* USER CODE END EC */

/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */

/* USER CODE END EM */

/* Exported functions prototypes ---------------------------------------------*/
//extern void app_main (void * arg);

/* USER CODE BEGIN EFP */

/* USER CODE END EFP */

/* Private defines -----------------------------------------------------------*/
/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

#ifdef __cplusplus
}
#endif

#endif /* __MAIN_H */


canSendThread.c

#include "cmsis_os2.h"                                        // CMSIS RTOS header file
#include "main.h" 
#include "Appmain.h"
#include "can.h"
 
void canSendThread (void *argument);                          // thread function
osThreadId_t canSend_ThreadId;                                      // thread id

uint64_t canSend_StackMemory[STACK_SIZE512] __attribute__((at(0x20028a00)));
uint32_t canSendCnt;

const osThreadAttr_t canSendthread_attr = {
  .priority = osPriorityNormal ,                            // 定义优先级
  .stack_mem = &canSend_StackMemory[0],
	.stack_size =sizeof(canSend_StackMemory)
};
 
int Init_canSendThread (void) {
 
  canSend_ThreadId = osThreadNew (canSendThread, NULL, &canSendthread_attr);
  if (!canSend_ThreadId) return(-1);
  
  return(0);
}
 
void canSendThread (void *argument) {
  canReplyMsg_t rcvMsg;
	osStatus_t status;
	canSendCnt = 0;
  while (1) {
    status = osMessageQueueGet(canQSendMsgQ,&rcvMsg,NULL,1u);
		if (osOK == status)
		{
			 CAN_SendData(0x91,(uint8_t *)&rcvMsg,rcvMsg.packNum*8);
			 canSendCnt ++;
		}
    osDelay(1);                                       
  }
}

CRC16_ModbusRTU.c

#include "cmsis_os2.h"    

const uint16_t polynom = 0xA001; 
uint16_t crc16_ModBusRtu(uint8_t *ptr, uint16_t len)
{	
    uint8_t i;	
    uint16_t crc = 0xffff; 	
    if (len == 0) 
    {		
        return 0xffff;	
    }	
    while (len--) 
    {		
        crc ^= *ptr;		
        for (i = 0; i<8; i++)		
        {			
            if (crc & 1) 
            {				
                crc >>= 1;				
                crc ^= polynom;			
            }			
            else
            {				
                crc >>= 1;			
            }		
            }		
            ptr++;	
    }	
    return (crc);
    
}

ResetAction.c

#include "cmsis_os2.h" 
#include "pcd4641.h"
#include "string.h"
#include "MotorControl.h"
#include "BaseAction.h"

extern uint16_t currentCapStatus;

void clampCentrifugeMotorMoveOutOrg()
{
	  // 初始化离心管 夹紧电机·
	  // 如果不在原点 表示有试管
			 pAction[actionCreateStep].ActionAxis = CLAMP_CENTRIFUGE_AXIS;
			 pAction[actionCreateStep].status = MOVE_PLUSE;
			 pAction[actionCreateStep].Postiontion = 75500;
			 pAction[actionCreateStep].ControlMode = Liner_Nes_Pre_NoOrgSL;
			 pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
		   actionCreateStep++;	
}

void clampPcrMotorMoveOutOrg()
{
	  // 初始化离心管 夹紧电机·
	  // 如果不在原点 表示有试管
			 pAction[actionCreateStep].ActionAxis = CLAMP_PCRTUBE_AXIS;
			 pAction[actionCreateStep].status = MOVE_PLUSE;
			 pAction[actionCreateStep].Postiontion = 75500;
			 pAction[actionCreateStep].ControlMode = Liner_Nes_Pre_NoOrgSL;
			 pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
		   actionCreateStep++;	
}


void rstCentrifugeTube()
{
	  int32_t pluse;
	  motor_Para_t *axisP;
	  HasCentrifugeTube = 0;
	  axisP = &saveMotorPara.DetalPara.para[0];
  	motorRstsStatus = axis_read_outstatus(CENTRIFUGE_Z_AXIS); // Z轴是否在ORG
		
    pluse = (-1) * (int32_t)axisP[CENTRIFUGE_Z_AXIS].LimitDistance*(int32_t)axisP[CENTRIFUGE_Z_AXIS].PluseNumPerCycle/
					       (int32_t) axisP[CENTRIFUGE_Z_AXIS].DistancePerCycle;
		z_CentrifugeTubeMotorMovePluse(pluse);  // 先运动到极限位	
	
	  if (motorRstsStatus & SORG)               // 电机在原点
		{
			  //z_CentrifugeTubeMotorMovePluse(-7500); // 移出原点位置
			  motorRstsStatus = axis_read_outstatus(CLAMP_CENTRIFUGE_AXIS);
			  if (!(motorRstsStatus & SORG))  // 表明夹爪上有离心管盖
        {
            // 归零
					  z_CentrifugeTubeMotorTurnZero();
					  //释放离心管
	          unFixCentrifuge();				
					  // 固定离心管
					  fixCentrifugeMotorMovePosition((int32_t)axisP[FIXED_CENTRIFUGE_AXIS].MoveDistace);
					  // 运动到旋紧位置
					  z_CentrifugeTubeMotorMovePosition((int32_t)axisP[CENTRIFUGE_Z_AXIS].MoveDistace);
					  // todo 旋紧离心管盖
					  tied_CentrifugeTubeCap();
 					
				}
				else
				{
	          clampCentrifugeMotorMoveOutOrg();				
				}
		}
	  else 
		{
        // 夹爪在零位 Z处于运动中或z已到位 但夹爪未夹紧 
			  // 夹爪不在零位 z已到位 但夹爪夹紧或运行到夹紧态 此时应松开夹爪
			  motorRstsStatus = axis_read_outstatus(CLAMP_CENTRIFUGE_AXIS);
			  if (!(motorRstsStatus & SORG))  // 表明夹爪上有离心管盖 且Z不在零位
        {
					// todo松离心管盖
          loose_CentrifugeTubeCap();
					// 归零			
					z_CentrifugeTubeMotorTurnZero();
					//释放离心管
	        unFixCentrifuge();				
					// 固定离心管
					fixCentrifugeMotorMovePosition((int32_t)axisP[FIXED_CENTRIFUGE_AXIS].MoveDistace);
					// Z运行到旋紧位
					z_CentrifugeTubeMotorMovePosition((int32_t)axisP[CENTRIFUGE_Z_AXIS].MoveDistace);
					// todo 旋紧离心管盖
          tied_CentrifugeTubeCap();					
			 }	
       else
       {
          clampCentrifugeMotorMoveOutOrg();
			 }				 
		}
		
		// 松开离心管夹爪 
		releaseCentrifugeTubeClamp();
		//Z 归零
		z_CentrifugeTubeMotorTurnZero();	
		
		//释放离心管
	  unFixCentrifuge();
		// 测试夹爪不在位情况
		//clampCentrifugeMotorMoveOutOrg();
		// 测试Postion 移动情况
		z_CentrifugeTubeMotorMovePosition((int32_t)axisP[CENTRIFUGE_Z_AXIS].MoveDistace);
		z_CentrifugeTubeMotorMovePosition(0);
}



void rstPcrTube()
{
	  motor_Para_t *axisP;
	  HasCentrifugeTube = 0;
	  axisP = &saveMotorPara.DetalPara.para[0];
	
	  z_PcrTubeMotorTurnZero();
	  motorRstsStatus = axis_read_outstatus(CLAMP_PCRTUBE_AXIS);
	  if (!(motorRstsStatus & SORG))  // 表明夹爪上有PCR管盖
    {
			 // 释放pcr管
			 unFixPcrTube();
			 // 固定pcr管
			 fixPcrTubeMotorMovePosition((int32_t)axisP[FIXED_PCRTUBE_AXIS].MoveDistace);
			 // z 运动到固定位 盖盖
			 z_PcrTubeMotorMovePosition((int32_t)axisP[PCR_Z_AXIS].MoveDistace);
			 // 松开夹爪
			 releasePcrTubeClamp();
			 // z 归零
			 z_PcrTubeMotorTurnZero();
    }	
		else
		{
			 // 复位夹爪
			 clampPcrMotorMoveOutOrg();
			 releasePcrTubeClamp();
		}
		// 释放Pcr管
		unFixPcrTube();
}

void rstDisc()
{
	 motor_Para_t *axisP;
	 axisP = &saveMotorPara.DetalPara.para[DISC_TURNING_AXIS];
	 motorRstsStatus = axis_read_outstatus(DISC_TURNING_AXIS);
	 if (motorRstsStatus & SORG)
   {
      discMotorMovePluse(axisP->PluseNumPerCycle*3/2);// 10度
			  
	 }			 
	 discMotorTunrZero();
	 discMotorMovePluse(axisP->PluseNumPerCycle*3/2);// 10度
	 discMotorTunrZero();
}

/****************************************************************************
  File name:      imotorControl.C
  Author: wangyong      Version: 1.0        Date: 2015-01-19
* 名称:CreatRstAction()
* 功能:复位动作
* 调用者:MotorControlThread
* 入口参数:无
* 出口参数:无
****************************************************************************/

void CreatRstAction()
{
    
	  rstActtionList();
	
	  //changeStatus(0,0,0x41); // 更新状态 
	  //axis_read_msts(1);  
	  // 复位离心管组电机
	  rstCentrifugeTube();
	  // 复位PCR
	  rstPcrTube();
	  //复位圆盘 
	  rstDisc();
	
	  changeStatus(0,0,0x10);
	
		motorAction.Step = actionCreateStep;
		//motorActionStep = 0;
}

void CreateRstActionWithCapStatus()
{
   uint8_t hole,doorhole;
	 //uint16_t roateAngle;
	 motor_Para_t *axisP;
	 uint8_t well;
	 axisP = &saveMotorPara.DetalPara.para[0];
	 rstActtionList();
   well = (currentCapStatus & 0xff00)>>8;	
	 doorhole = currentCapStatus &0xff;
	 if (well >0 && well <=16) // 有盖子在夹爪上
	 {
	    if (doorhole!=0) //圆盘已转出  此时 盖子在夹爪上 且已归零
      {
          // 释放Pcr管
		      unFixPcrTube();
				  //释放离心管
	        unFixCentrifuge();
				  //复位圆盘 
	        rstDisc();
				  // 管子旋转到位
				  if (hole%2 == 0)
			    {
				      hole = well/2;
				      disRotation(saveDiscAnglePara.AnglePara.pcrTubeAngle[hole-1]);
			     }
			     else
			     {
				      hole = (well-1)/2+1;
						  disRotation(saveDiscAnglePara.AnglePara.centrifugeTubeAngle[hole-1]);
			     }
					 SaveCapStatus(hole,0);
        }				
        if (well %2!=0) // 离心管在夹爪上
        {                    
				    if (doorhole==0) //圆盘未转出 有可能处于松盖的状态 
            {
				        // todo松离心管盖             
      			    loose_CentrifugeTubeCap();
					  }
				    // 归零
					  z_CentrifugeTubeMotorTurnZero();
					  //释放离心管
	          unFixCentrifuge();				
					  // 固定离心管
					  fixCentrifugeMotorMovePosition((int32_t)axisP[FIXED_CENTRIFUGE_AXIS].MoveDistace);
					  // 运动到旋紧位置
					  z_CentrifugeTubeMotorMovePosition((int32_t)axisP[CENTRIFUGE_Z_AXIS].MoveDistace);
					  // todo 旋紧离心管盖
					  tied_CentrifugeTubeCap();
						SaveCapStatus(0,0);
				    // 松开离心管夹爪 
	        	releaseCentrifugeTubeClamp();
				    // 归零
					  z_CentrifugeTubeMotorTurnZero();
				    //释放离心管
	          unFixCentrifuge();
				    // 复位pcr夹爪
						motorRstsStatus = axis_read_outstatus(CLAMP_PCRTUBE_AXIS);
						if (motorRstsStatus & SORG)
			          clampPcrMotorMoveOutOrg();
			      releasePcrTubeClamp();
				    // 释放pcr管
			      unFixPcrTube();
				    // z Pcr 归零
			      z_PcrTubeMotorTurnZero();
				
			    }	
          else
          {
            // z 归零
			      z_PcrTubeMotorTurnZero();
				    // 释放pcr管
			      unFixPcrTube();
			      // 固定pcr管
			      fixPcrTubeMotorMovePosition((int32_t)axisP[FIXED_PCRTUBE_AXIS].MoveDistace);
			      // z 运动到固定位 盖盖
			      z_PcrTubeMotorMovePosition((int32_t)axisP[PCR_Z_AXIS].MoveDistace);
			      // 松开夹爪
			      releasePcrTubeClamp();
						SaveCapStatus(0,0);
			      // z 归零
			      z_PcrTubeMotorTurnZero();
				    // 释放pcr管
			      unFixPcrTube();
				    // 复位离心管夹爪
						motorRstsStatus = axis_read_outstatus(CLAMP_CENTRIFUGE_AXIS);
						if (motorRstsStatus & SORG)
				        clampCentrifugeMotorMoveOutOrg();
				    releaseCentrifugeTubeClamp();
		        //Z 离心管归零
		        z_CentrifugeTubeMotorTurnZero();
				    //释放离心管
	          unFixCentrifuge();
        }				
	 }
	 else
	 {
	      // 复位离心管夹爪
		    motorRstsStatus = axis_read_outstatus(CLAMP_CENTRIFUGE_AXIS);
		    if (motorRstsStatus & SORG)
				    clampCentrifugeMotorMoveOutOrg();
				releaseCentrifugeTubeClamp();
		    //Z 离心管归零
		    z_CentrifugeTubeMotorTurnZero();	
        // 复位pcr夹爪
				motorRstsStatus = axis_read_outstatus(CLAMP_PCRTUBE_AXIS);
				if (motorRstsStatus & SORG)
			      clampPcrMotorMoveOutOrg();
			  releasePcrTubeClamp();
        // z 归零
			  z_PcrTubeMotorTurnZero();		        	
        //释放离心管
	      unFixCentrifuge();
        // 释放pcr管
			  unFixPcrTube();		 
	 }
	  //复位圆盘 
	  rstDisc();
	  changeStatus(0,0,0x10);
    SaveCapStatus(0,0);
    motorAction.Step = actionCreateStep;	 
}




BaseAction.c

#include "cmsis_os2.h" 
#include "pcd4641.h"
#include "string.h"
#include "MotorControl.h"
#include "Gpio.h"
#include <stdlib.h>

void z_CentrifugeTubeMotorMovePluse(int32_t pluse);
void Z_PcrTubeMotorMovePluse(int32_t pluse);
void rstActtionList(void);

void z_CentrifugeTubeMotorTurnZero()
{
	  int32_t pluse;
	  motor_Para_t *axisP;
	  axisP = &saveMotorPara.DetalPara.para[CENTRIFUGE_Z_AXIS];
	  // 由于 Z 轴搜寻原点向下 但只有上限位 为统一搜寻方向 搜寻原点 先向上到极限位 
	  pluse = (-1) * (int32_t)axisP->LimitDistance*(int32_t)axisP->PluseNumPerCycle/
					       (int32_t) axisP->DistancePerCycle;
		z_CentrifugeTubeMotorMovePluse(pluse);  // 先运动到极限位	
	
	  pAction[actionCreateStep].ActionAxis = CENTRIFUGE_Z_AXIS ;
		pAction[actionCreateStep].status = MOVE_ORG;
		pAction[actionCreateStep].ControlMode = Liner_Nes_Zero_Return;
		pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
		actionCreateStep++;
}

void z_CentrifugeTubeMotorMovePluse(int32_t pluse)
{
	  pAction[actionCreateStep].ActionAxis = CENTRIFUGE_Z_AXIS;     
	  pAction[actionCreateStep].status = MOVE_PLUSE;
	  pAction[actionCreateStep].Postiontion = abs(pluse);
	  if (pluse>=0)
	    	pAction[actionCreateStep].ControlMode = Liner_Nes_Pre_NoOrgSL;
		else
			  pAction[actionCreateStep].ControlMode = Liner_Pos_Pre_NoOrgSL;
	  pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
	  actionCreateStep++;
}

void z_CentrifugeTubeMotorMovePosition(int32_t position)
{
	  pAction[actionCreateStep].ActionAxis = CENTRIFUGE_Z_AXIS;     
	  pAction[actionCreateStep].status = MOVE_POSITION;
	  pAction[actionCreateStep].Postiontion = position;
	  actionCreateStep++;
}

void releaseCentrifugeTubeClamp()
{
	  pAction[actionCreateStep].ActionAxis = CLAMP_CENTRIFUGE_AXIS;
	  pAction[actionCreateStep].status = MOVE_ORG;
	  pAction[actionCreateStep].ControlMode = Liner_Pos_Zero_Return;
	  pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
	  actionCreateStep++;	
}



void centrifugeTubeClampMotorMovePosition(int32_t position)
{
	  pAction[actionCreateStep].ActionAxis = CLAMP_CENTRIFUGE_AXIS;
	  pAction[actionCreateStep].status = MOVE_POSITION;
	  pAction[actionCreateStep].Postiontion = position;
	  pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
	  actionCreateStep++;	
}

void fixCentrifugeMotorMovePlus(int32_t pluse)
{
	  pAction[actionCreateStep].ActionAxis = FIXED_CENTRIFUGE_AXIS;
	  pAction[actionCreateStep].status = MOVE_PLUSE;
	  pAction[actionCreateStep].Postiontion = abs(pluse);
	  if (pluse>=0)
	      pAction[actionCreateStep].ControlMode = Liner_Pos_Pre_NoOrgSL;
		else
			 pAction[actionCreateStep].ControlMode = Liner_Nes_Pre_NoOrgSL;
	  pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
	  actionCreateStep++;	
}

void fixCentrifugeMotorMovePosition(int32_t position)
{
	  
	  pAction[actionCreateStep].ActionAxis = FIXED_CENTRIFUGE_AXIS;
	  pAction[actionCreateStep].status = MOVE_POSITION;
	  pAction[actionCreateStep].Postiontion = position;
	  pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
	  actionCreateStep++;	
}

void unFixCentrifuge()
{
    pAction[actionCreateStep].ActionAxis = FIXED_CENTRIFUGE_AXIS ;
		pAction[actionCreateStep].status = MOVE_ORG;
		pAction[actionCreateStep].ControlMode = Liner_Pos_Zero_Return;
		pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
		actionCreateStep++;	  	
}

void fixPcrTubeMotorMovePosition(int32_t position)
{
	  
	  pAction[actionCreateStep].ActionAxis = FIXED_PCRTUBE_AXIS;
	  pAction[actionCreateStep].status = MOVE_POSITION;
	  pAction[actionCreateStep].Postiontion = position;
	  pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
	  actionCreateStep++;	
}


void unFixPcrTube()
{
    pAction[actionCreateStep].ActionAxis = FIXED_PCRTUBE_AXIS ;
		pAction[actionCreateStep].status = MOVE_ORG;
		pAction[actionCreateStep].ControlMode = Liner_Pos_Zero_Return;
		pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
		actionCreateStep++;	  	

}

void z_PcrTubeMotorTurnZero()
{
	  int32_t pluse;
	  motor_Para_t *axisP;
	  axisP = &saveMotorPara.DetalPara.para[PCR_Z_AXIS];
	  // 由于 Z 轴搜寻原点向下 但只有上限位 为统一搜寻方向 搜寻原点 先向上到极限位 
	  pluse = (-1) * (int32_t)axisP->LimitDistance*(int32_t)axisP->PluseNumPerCycle/
					       (int32_t) axisP->DistancePerCycle;
		Z_PcrTubeMotorMovePluse(pluse);  // 先运动到极限位	
	
	  pAction[actionCreateStep].ActionAxis = PCR_Z_AXIS ;
		pAction[actionCreateStep].status = MOVE_ORG;
		pAction[actionCreateStep].ControlMode = Liner_Nes_Zero_Return;
		pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
		actionCreateStep++;
}

void Z_PcrTubeMotorMovePluse(int32_t pluse)
{
	  pAction[actionCreateStep].ActionAxis = PCR_Z_AXIS;     
	  pAction[actionCreateStep].status = MOVE_PLUSE;
	  pAction[actionCreateStep].Postiontion = abs(pluse);
	  if (pluse>=0)
	    	pAction[actionCreateStep].ControlMode = Liner_Nes_Pre_NoOrgSL;
		else
			  pAction[actionCreateStep].ControlMode = Liner_Pos_Pre_NoOrgSL;
	  pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
	  actionCreateStep++;
}

void z_PcrTubeMotorMovePosition(int32_t position)
{
	 	
	  pAction[actionCreateStep].ActionAxis = PCR_Z_AXIS;     
	  pAction[actionCreateStep].status = MOVE_POSITION;
	  pAction[actionCreateStep].Postiontion = position;
	  actionCreateStep++;
}

void releasePcrTubeClamp()
{
	  pAction[actionCreateStep].ActionAxis = CLAMP_PCRTUBE_AXIS;
	  pAction[actionCreateStep].status = MOVE_ORG;
	  pAction[actionCreateStep].ControlMode = Liner_Pos_Zero_Return;
	  pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
	  actionCreateStep++;	
}

void pcrTubeClampMotorMovePlus(int32_t pluse)
{
	  pAction[actionCreateStep].ActionAxis = CLAMP_PCRTUBE_AXIS;
	  pAction[actionCreateStep].status = MOVE_PLUSE;
	  pAction[actionCreateStep].Postiontion = abs(pluse);
	  if (pluse>=0)
	      pAction[actionCreateStep].ControlMode = Liner_Pos_Pre_NoOrgSL;
		else
			 pAction[actionCreateStep].ControlMode = Liner_Nes_Pre_NoOrgSL;
	  pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
	  actionCreateStep++;	
}

void pcrTubeClampMotorMovePosition(int32_t position)
{
	  pAction[actionCreateStep].ActionAxis = CLAMP_PCRTUBE_AXIS;
	  pAction[actionCreateStep].status = MOVE_POSITION;
	  pAction[actionCreateStep].Postiontion = position;
	  pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
	  actionCreateStep++;	
}

void tied_CentrifugeTubeCap()
{
	  pAction[actionCreateStep].ActionAxis = CENTRIFUGE_CAP;
	  pAction[actionCreateStep].status = TIED;
	  actionCreateStep++;
}

void loose_CentrifugeTubeCap()
{
	  pAction[actionCreateStep].ActionAxis = CENTRIFUGE_CAP;
	  pAction[actionCreateStep].status = LOOSE;
	  actionCreateStep++;
}

void disRotation(int32_t angle) 
{
	  /*pAction[actionCreateStep].ActionAxis = DISC_TURNING_AXIS;
	  pAction[actionCreateStep].status = ENCODE_POSION_READ;
	  actionCreateStep++;*/
	
	  pAction[actionCreateStep].ActionAxis = DISC_TURNING_AXIS;
	  pAction[actionCreateStep].status = DISC_ROTATION;
	  pAction[actionCreateStep].Postiontion = angle;
	  pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
	  actionCreateStep++;
	
}

void createMoveAxisTestModeAction(uint8_t axis,uint32_t position)
{
	   
	  rstActtionList();
	  pAction[actionCreateStep].ActionAxis = axis;     
	  pAction[actionCreateStep].status = MOVE_POSITION;
	  pAction[actionCreateStep].Postiontion = position;
	  actionCreateStep++;
	
	  motorAction.Step = actionCreateStep;
}

void discMotorTunrZero()
{
    //rstActtionList();
	  pAction[actionCreateStep].ActionAxis = DISC_TURNING_AXIS;
	  pAction[actionCreateStep].status = MOVE_ORG;
	  pAction[actionCreateStep].ControlMode = Liner_Pos_Zero_Return;
	  pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
	  actionCreateStep++;	
	
	  //motorAction.Step = actionCreateStep;
}

void rstActtionList()
{
	  memset(&motorAction,0,sizeof(Motor_Action_t));
	  pAction = &motorAction.Action[0];
	  actionCreateStep = 0;
}


void discMotorMovePluse(int32_t pluse)
{
	  pAction[actionCreateStep].ActionAxis = DISC_TURNING_AXIS;
	  pAction[actionCreateStep].status = MOVE_PLUSE;
	  pAction[actionCreateStep].Postiontion = abs(pluse);
	  if (pluse>=0)
	      pAction[actionCreateStep].ControlMode = Liner_Nes_Pre_NoOrgSL;
		else
			 pAction[actionCreateStep].ControlMode = Liner_Pos_Pre_NoOrgSL;
	  pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
	  actionCreateStep++;	
}


void startCentrifugeTubeCapMotor()
{
	  SETSTART();
	  osDelay(1);
		CLRSTART();
	  osDelay(1);
		SETSTART();
}

void changeStatus(int8_t hole,int8_t doorHole,int8_t devStatus)
{
	  pAction[actionCreateStep].ActionAxis = 0;
	  pAction[actionCreateStep].status = CHANGESTATUS;
	  pAction[actionCreateStep].hole = hole;
    pAction[actionCreateStep].doorhole = doorHole;
  	pAction[actionCreateStep].devStatus = devStatus;
	  //pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
	  actionCreateStep++;
}

void SaveCapStatus(int8_t hole,int8_t doorHole)
{
	  pAction[actionCreateStep].ActionAxis = 0;
	  pAction[actionCreateStep].status = WRITECAPSTATUS;
	  pAction[actionCreateStep].hole = hole;
    pAction[actionCreateStep].doorhole = doorHole;
  	//pAction[actionCreateStep].devStatus = devStatus;
	  //pAction[actionCreateStep].StartMode= Start_Motor_IntDisable_HighSpeed;
	  actionCreateStep++;
}


BaseAction.h

#ifndef __BASEACTION_H
#define __BASEACTION_H

#include "cmsis_os2.h" 
#include "sys_stru.h"




extern void releaseCentrifugeTubeClamp(void);
extern void z_CentrifugeTubeMotorTurnZero(void);
extern void z_CentrifugeTubeMotorMovePluse(int32_t pluse);
extern void unFixCentrifugeMovePlus(void);
extern void z_CentrifugeTubeMotorMovePosition(int32_t position);
extern void fixCentrifugeMotorMovePlus(int32_t pluse);
extern void fixCentrifugeMotorMovePosition(int32_t position);
extern void unFixCentrifuge(void);
extern void centrifugeTubeClampMotorMovePosition(int32_t position);

extern void unFixPcrTube(void);
extern void z_PcrTubeMotorTurnZero(void);
extern void z_PcrTubeMotorMovePosition(int32_t position);
extern void fixPcrTubeMotorMovePosition(int32_t position);
extern void pcrTubeClampMotorMovePosition(int32_t position);
extern void pcrTubeClampMotorMovePlus(int32_t position);
extern void releasePcrTubeClamp(void);

extern void tied_CentrifugeTubeCap(void);
extern void loose_CentrifugeTubeCap(void);

extern void createMoveAxisTestModeAction(uint8_t axis,uint32_t position);
extern void rstActtionList(void);
extern void discMotorTunrZero(void);
extern void discMotorMovePluse(int32_t pluse);
extern void disRotation(int32_t angle);
extern void startCentrifugeTubeCapMotor(void);
extern void changeStatus(int8_t hole,int8_t doorHole,int8_t devStatus);
extern void SaveCapStatus(int8_t hole,int8_t doorHole);
#endif

CentrifugeTubeAction.c

#include "cmsis_os2.h" 
#include "pcd4641.h"
#include "string.h"
#include "MotorControl.h"
#include "BaseAction.h"

void createTiedCentrifugeAction(uint8_t well,uint8_t nextWell)
{
     motor_Para_t *axisP;
	   uint16_t roateAngle;
	   uint8_t hole;
	   rstActtionList();
	   //changeStatus(0,0,0x43);
	
	   axisP = &saveMotorPara.DetalPara.para[0];
	   // TODO 圆盘旋转到紧盖位置
	   if (well<=Max_Hole && well !=Omit_Well)
	      disRotation(saveDiscAnglePara.AnglePara.centrifugeTubeAngle[well-1]);
	   // 固定离心管
	   fixCentrifugeMotorMovePosition((int32_t)axisP[FIXED_CENTRIFUGE_AXIS].MoveDistace);
	   // Z 轴运动到位
	   z_CentrifugeTubeMotorMovePosition((int32_t)axisP[CENTRIFUGE_Z_AXIS].MoveDistace);
	   // 拧盖
	   tied_CentrifugeTubeCap();
	   // 夹爪张开
		 SaveCapStatus(0,0);
	   releaseCentrifugeTubeClamp();
	   // Z归零 此时夹爪张开状态
	   //z_CentrifugeTubeMotorTurnZero();
	   z_CentrifugeTubeMotorMovePosition(0);
	   // 松开离心管
	   unFixCentrifuge();
		 
		 if (nextWell!=Omit_Well)
		     nextWell = nextWell/2+1;
		 if (nextWell<=Max_Hole && nextWell !=Omit_Well)
		 {
	       disRotation(saveDiscAnglePara.AnglePara.centrifugeTubeAngle[nextWell-1]);
			 
			  // 固定离心管
	       fixCentrifugeMotorMovePosition((int32_t)axisP[FIXED_CENTRIFUGE_AXIS].MoveDistace);
	       // z轴运动到位
	       z_CentrifugeTubeMotorMovePosition((int32_t)axisP[CENTRIFUGE_Z_AXIS].MoveDistace);
	       // 夹离心管
			   SaveCapStatus((nextWell-1)*2+1,0);
	       centrifugeTubeClampMotorMovePosition((int32_t)axisP[CLAMP_CENTRIFUGE_AXIS].MoveDistace);		   
	       // 松盖
	       loose_CentrifugeTubeCap();
	       // Z 归零 此时 夹爪有管盖
	       z_CentrifugeTubeMotorMovePosition(0);
	       // 松开离心管
			   SaveCapStatus((nextWell-1)*2+1,(nextWell-1)*2+1);
	       unFixCentrifuge();		   
			   // TODO 圆盘旋转到加液位置
			   roateAngle = (nextWell-1)*450 + saveDiscAnglePara.AnglePara.discCentrifugeAngle;
		     roateAngle %=3600;
	       disRotation(roateAngle);

		     hole = (nextWell-1)*2+1;
		     changeStatus(hole,hole,0x20);
		 }
		 else
		 {
		     roateAngle = (well-1)*450 + saveDiscAnglePara.AnglePara.discCentrifugeAngle;
		     roateAngle %=3600;
	       disRotation(roateAngle);

		     hole = (well-1)*2+1;
			   changeStatus(0,hole,0x10);
	   }
	   motorAction.Step = actionCreateStep;
	   
}

void createLoosedCentrifugeAction(uint8_t well,uint8_t stopWell)
{
	   motor_Para_t *axisP;
	   uint8_t hole;
	   uint16_t roateAngle;
	   rstActtionList();
	   axisP = &saveMotorPara.DetalPara.para[0];
	
	   //changeStatus(0,0,0x42);
	   if (well<=Max_Hole && well !=Omit_Well)
	      disRotation(saveDiscAnglePara.AnglePara.centrifugeTubeAngle[well-1]);
	   
	   // 固定离心管
	   fixCentrifugeMotorMovePosition((int32_t)axisP[FIXED_CENTRIFUGE_AXIS].MoveDistace);
	   // z轴运动到位
	   z_CentrifugeTubeMotorMovePosition((int32_t)axisP[CENTRIFUGE_Z_AXIS].MoveDistace);
	   // 夹离心管
		 SaveCapStatus((well-1)*2+1,0);
	   centrifugeTubeClampMotorMovePosition((int32_t)axisP[CLAMP_CENTRIFUGE_AXIS].MoveDistace);
	   // 松盖
	   loose_CentrifugeTubeCap();
	   // Z 归零 此时 夹爪有管盖
	   z_CentrifugeTubeMotorMovePosition(0);
	   // 松开离心管
		 SaveCapStatus((well-1)*2+1,(well-1)*2+1);
	   unFixCentrifuge();
	   // TODO 圆盘旋转到加液位置
		 roateAngle = (well-1)*450+ saveDiscAnglePara.AnglePara.discCentrifugeAngle;
		 roateAngle %=3600;
	   disRotation(roateAngle);

		 hole = (well-1)*2+1;
		 changeStatus(hole,hole,0x20);
	   motorAction.Step = actionCreateStep;
}

CentrifugeTubeAction.c

#ifndef __CENTRIFUGETUBEACTION_H
#define __CENTRIFUGETUBEACTION_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "cmsis_os2.h" 
extern void createTiedCentrifugeAction(uint8_t well,uint8_t StopWell);
extern void createLoosedCentrifugeAction(uint8_t well,uint8_t stopWell);
#ifdef __cplusplus
}
#endif


#endif


pcrTubeAction.c

#include "cmsis_os2.h" 
#include "pcd4641.h"
#include "string.h"
#include "MotorControl.h"
#include "BaseAction.h"

void createClosedPcrTubeAction(uint8_t well,uint8_t nextWell)
{
     motor_Para_t *axisP;
	   uint16_t  roateAngle;
	   uint8_t hole;
	   rstActtionList();
	   //changeStatus(0,0,0x43);
	   axisP = &saveMotorPara.DetalPara.para[0];
	   // TODO 圆盘旋转到紧盖位置
	   if (well<=Max_Hole && well !=Omit_Well)
	      disRotation(saveDiscAnglePara.AnglePara.pcrTubeAngle[well-1]);
	   // 固定Pcr管
	   fixPcrTubeMotorMovePosition((int32_t)axisP[FIXED_PCRTUBE_AXIS].MoveDistace);
	   // Z 轴运动到位
	   z_PcrTubeMotorMovePosition((int32_t)axisP[PCR_Z_AXIS].MoveDistace);
	   // 夹爪张开
	   releasePcrTubeClamp();
		 SaveCapStatus(0,0);
	   // Z pcr归零 
	   z_PcrTubeMotorTurnZero();
	   // 释放Pcr管
	   unFixPcrTube();
	   nextWell /=2;
		 if (nextWell<=Max_Hole && nextWell !=Omit_Well)
		 {
	      disRotation(saveDiscAnglePara.AnglePara.pcrTubeAngle[nextWell-1]);
			  // 固定Pcr管
	      fixPcrTubeMotorMovePosition((int32_t)axisP[FIXED_PCRTUBE_AXIS].MoveDistace);
	      // z轴运动到位
	      z_PcrTubeMotorMovePosition((int32_t)axisP[PCR_Z_AXIS].MoveDistace);
	      // 夹爪抓紧
			  SaveCapStatus(nextWell*2,0);
        pcrTubeClampMotorMovePosition((int32_t)axisP[CLAMP_PCRTUBE_AXIS].MoveDistace);
	      // Z pcr归零 
	      z_PcrTubeMotorTurnZero();
	      // 释放离心管
			  SaveCapStatus(nextWell*2,nextWell*2);
	      unFixPcrTube();
	      // TODO 圆盘旋转到加液位置
			  roateAngle = (nextWell-1)*450 + saveDiscAnglePara.AnglePara.discPcrAngle;
		    roateAngle %=3600;
	      disRotation(roateAngle);
			  hole =(nextWell*2);
			  changeStatus(hole,hole,0x20);
		 }
		 else
		 {
	      roateAngle = (well-1)*450 + saveDiscAnglePara.AnglePara.discPcrAngle;
		    roateAngle %=3600;
	      disRotation(roateAngle); 
			  hole = well *2;
			  changeStatus(0,hole,0x10);
		 }
	   motorAction.Step = actionCreateStep;
}

void createOpendPcrTubeAction(uint8_t well,uint8_t stopWell)
{
	   motor_Para_t *axisP;
	   uint8_t hole;
	   uint16_t  roateAngle;
	   rstActtionList();
	   //changeStatus(0,0,0x42);
	   axisP = &saveMotorPara.DetalPara.para[0];
	  
	   if (well<=Max_Hole && well !=Omit_Well)
	      disRotation(saveDiscAnglePara.AnglePara.pcrTubeAngle[well-1]);
	
	   // 固定Pcr管
	   fixPcrTubeMotorMovePosition((int32_t)axisP[FIXED_PCRTUBE_AXIS].MoveDistace);
	   // z轴运动到位
	   z_PcrTubeMotorMovePosition((int32_t)axisP[PCR_Z_AXIS].MoveDistace);
	   // 夹爪抓紧
		 SaveCapStatus(well*2,0);
     pcrTubeClampMotorMovePosition((int32_t)axisP[CLAMP_PCRTUBE_AXIS].MoveDistace);
	   // Z pcr归零 
	   z_PcrTubeMotorTurnZero();
	   // 释放离心管
		 SaveCapStatus(well*2,well*2);
	   unFixPcrTube();
	   // TODO 圆盘旋转到加液位置
		 roateAngle = (well-1)*450 + saveDiscAnglePara.AnglePara.discPcrAngle;
		 //roateAngle = roateAngle - 900 -saveDiscAnglePara.AnglePara.centrifugeTubeAngle[0] - saveDiscAnglePara.AnglePara.pcrTubeAngle[0];
		 roateAngle %=3600;
	   disRotation(roateAngle);
		 
		 hole = well*2; 
		 
	   changeStatus(hole,hole,0x20);
		 
	   motorAction.Step = actionCreateStep;
}

pcrTubeActoin.h

#ifndef __PCRTUBEACTION_H
#define __PCRTUBEACTION_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "cmsis_os2.h" 
extern void createClosedPcrTubeAction(uint8_t well,uint8_t stopWell);
extern void createOpendPcrTubeAction(uint8_t well,uint8_t stopWell);
#ifdef __cplusplus
}
#endif


#endif

disMotorAction.c

#include "cmsis_os2.h" 
#include "pcd4641.h"
#include "string.h"
#include "MotorControl.h"
#include "BaseAction.h"
#include "AppMain.h"

extern DevStatus_t devStatus;

void rstDiscMotorAction()
{
     //motor_Para_t *axisP;
	   uint32_t axis_Status;
	   rstActtionList();
	   
	   axis_Status = axis_read_outstatus(DISC_TURNING_AXIS);
	   if (axis_Status & SORG)
     {
        discMotorMovePluse(15200);
			  
		 }			 
	   discMotorTunrZero();
		 discMotorMovePluse(15200);
		 discMotorTunrZero();
	   motorAction.Step = actionCreateStep;
	   
}

void discMotorMove(uint8_t well)
{
    uint8_t hole;
	  uint16_t roateAngle;
	  rstActtionList();
    //changeStatus(0,0,0x44);
	  SaveCapStatus(devStatus.openLidstatus.hole,well);
	  if (well == 0)
	  {
			 disRotation(0);
		}
		else
		{
			 if (well%2 == 0)
			 {
				  hole = well/2;
				  roateAngle = (hole-1)*450 +saveDiscAnglePara.AnglePara.discPcrAngle;
				  roateAngle %=3600;
				  disRotation(roateAngle);
			 }
			 else
			 {
				  hole = (well-1)/2+1;
				  roateAngle = (hole-1)*450 +saveDiscAnglePara.AnglePara.discCentrifugeAngle;
				  //roateAngle = roateAngle - saveDiscAnglePara.AnglePara.centrifugeTubeAngle[0] - saveDiscAnglePara.AnglePara.pcrTubeAngle[0];
				  roateAngle %=3600;
				  disRotation(roateAngle);
			 }
		}
		changeStatus(devStatus.openLidstatus.hole,well,0x10);
    motorAction.Step = actionCreateStep;	
}



Delay.c

#include "Delay.h"
#include "os_tick.h"

void Delay_Us(uint32_t u32Us)
{
	uint32_t u32Last = SysTick->VAL;
	uint32_t u32Cnt = 0;
	uint32_t u32Period = OS_Tick_GetInterval();
	u32Us *= (SystemCoreClock / 1000000);
	while(1)
	{
		uint32_t u32Now = SysTick->VAL;
		if(u32Now != u32Last)
		{
			if(u32Now < u32Last)
				u32Cnt += (u32Last - u32Now);//SYSTICK是递减的计数器就可以.
			else
				u32Cnt += (u32Period - u32Now + u32Last);
			if(u32Cnt >= u32Us)
				break; //时间超过/等于要延迟的时间,则退出.
			u32Last = u32Now;
		}
	}
}

Delay.h

#ifndef __SW_DELAY_H__
#define __SW_DELAY_H__

#include "stm32f4xx.h"
#include "cmsis_os2.h" 

#ifdef __cplusplus
 extern "C" {
#endif

extern void Delay_Us(uint32_t u32Us);

#define delay_us(us)			Delay_Us(us)
#define delay_ms(us)			Delay_Us(us*1000)

#ifdef __cplusplus
}
#endif

#endif

pcd4641.c

/****************************************************************************
  File name:      motor.C
  Author: Wangyong      Version: 1.0        Date: 2020-04-14 
  电机控制芯片PCD4641 
****************************************************************************/

#include "pcd4641.h"
#include "spi.h"
#include "delay.h"
#include "usart.h"
#include "Gpio.h"
#include "stm32f4xx_hal_gpio.h"
#include <stdarg.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

static p_pcd4641_dev_t p_pcd4641_dev;

uint8_t        outPutMode[Max_Axis];   // 输出参数 写入OutPut mode 寄存器 0x11-------- 

void axis_SearchOrg(uint8_t axis_n,uint8_t dir);
void axis_Move(uint8_t axis_n,Motor_ActionInfo_t *pAction);
uint32_t axis_read_rsts(uint8_t axis_n);
void pcd4641_write_command_regs(uint8_t axis_n,uint8_t commd,uint8_t *regs,uint8_t reg_count);
uint32_t axis_read_outstatus(uint8_t axis_n);
void axis_pulse_count_rst(uint8_t axis_n);

const uint16_t distancePercycle[Max_Axis] = {100,100,100,100,100,254,254,100};
const uint16_t MoveLogic[Max_Axis] = {POSTIVE_LOGIC,NEGTIVE_LOGIC,NEGTIVE_LOGIC,NEGTIVE_LOGIC,POSTIVE_LOGIC,NEGTIVE_LOGIC,NEGTIVE_LOGIC,NEGTIVE_LOGIC};

static void pcd4641_gpio_init(void)
{
	/*GPIO_InitTypeDef GPIO_Initure;
	__HAL_RCC_GPIOE_CLK_ENABLE();           //开启GPIOB时钟
	__HAL_RCC_GPIOG_CLK_ENABLE();

	GPIO_Initure.Pin=GPIO_PIN_4;
	GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
	GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
	GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
	HAL_GPIO_Init(GPIOE,&GPIO_Initure);
	
	GPIO_Initure.Pin=GPIO_PIN_10|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_6;              
	GPIO_Initure.Mode=GPIO_MODE_INPUT;     
	GPIO_Initure.Pull=GPIO_PULLUP;
	HAL_GPIO_Init(GPIOG,&GPIO_Initure);
	
	GPIO_Initure.Pin=GPIO_PIN_3;              
	GPIO_Initure.Mode=GPIO_MODE_IT_FALLING;     //下降沿触发
	GPIO_Initure.Pull=GPIO_PULLUP;
	HAL_GPIO_Init(GPIOE,&GPIO_Initure);
	
  HAL_NVIC_SetPriority(EXTI3_IRQn,2,0);       //抢占优先级为2,子优先级为0
  HAL_NVIC_EnableIRQ(EXTI3_IRQn);             //使能中断线0
	SPI4_Init();*/
}

/****************************************************************************
  File name:      pcd4641.C
  Author: Wangyong      Version: 1.0        Date: 2030-04-14 
* 名称:  pcd4641_read_command(uint8_t axis_n,uint8_t commd,uint8_t *rev_regs)
* 功能:  读寄存器   3Byte         
* 调用者:             
* 调用      
* 入口参数:uint8_t axis_n,    轴
            uint8_t commd,     命令
            uint8_t *regs,     数据地址 
   
* 出口参数:无
****************************************************************************/


void pcd4641_read_command(uint8_t axis_n,uint8_t commd,uint8_t *rev_regs)
{
	uint8_t i=0;
	static axis_sel_code_t axis_sel_code;
	memset((void *)&axis_sel_code,0,sizeof(axis_sel_code_t));
	axis_sel_code.area.axis = 1<<(axis_n%4);
	axis_sel_code.area.type = General_Purpose_Read;
	axis_sel_code.area.devcie = axis_n/4;
	
	PCD4641_CS_LOW();
	delay_us(100);
	SPI4_ReadWriteByte(axis_sel_code.code);
	delay_us(5);
	SPI4_ReadWriteByte(commd);
	for(i=0;i<3;i++)
	{
		delay_us(5);
		rev_regs[i] = SPI4_ReadWriteByte(0xff);
	}
	PCD4641_CS_HIGH();
}

/****************************************************************************
  File name:      pcd4641.C
  Author: Wangyong      Version: 1.0        Date: 2030-04-14 
* 名称:  void pcd4641_write_command_regs(uint8_t axis_n,uint8_t commd,uint8_t *regs,uint8_t reg_count)
* 功能:  写寄存器            
* 调用者:             
* 调用      
* 入口参数:uint8_t axis_n,    轴
            uint8_t commd,     命令
            uint8_t *regs,     数据地址
            uint8_t reg_count  数据个数
* 出口参数:无
****************************************************************************/

void pcd4641_write_command_regs(uint8_t axis_n,uint8_t commd,uint8_t *regs,uint8_t reg_count)
{
	int i=0;
	axis_sel_code_t axis_sel_code;
	axis_sel_code.area.axis = 1<<(axis_n%4);
	axis_sel_code.area.type = General_Purpose_Write;
	axis_sel_code.area.devcie = axis_n/4;
	
	PCD4641_CS_LOW();
	delay_us(100);
	SPI4_ReadWriteByte(axis_sel_code.code);
	delay_us(5);
	SPI4_ReadWriteByte(commd);	
	for(i=0;i<reg_count;i++)
	{
		delay_us(5);
		SPI4_ReadWriteByte(regs[i]);
		
	}
	PCD4641_CS_HIGH();
}

//读取芯片信息,测试
void pcd4641_read_info(uint8_t axis_n,uint8_t *regs)
{
	pcd4641_read_command(axis_n,EvenData,regs);
}


/****************************************************************************
  File name:      pcd4641.C
  Author: Wangyong      Version: 1.0        Date: 2030-04-14 
* 名称:  axis_initiate(uint8_t axis_n)
* 功能:  电机轴控制参数初始化,设定OutputMode 倍率 速度 加速度       
* 调用者:            
* 调用      
* 入口参数:uint8_t axis_n,    轴         
* 出口参数:无
****************************************************************************/

void axis_initiate(uint8_t axis_n)
{
	unsigned int Access_Time;
	unsigned int Ramp_Down_Buf;
	unsigned int Hight_Speed,Low_Speed;
	unsigned int speed_cal_buf;
	unsigned int access_cal_buf;
	p_control_para_t p_control_para = &(p_pcd4641_dev->control_para[axis_n]);
	uint8_t regs[3];
        
		if (!p_control_para->Roate_logic)
		{
	      pcd4641_write_command_regs(axis_n,NegLoc_ExtendMon,NULL,0);               // 写OutPutMode 模式寄存器 
		}
		else
		{
			  pcd4641_write_command_regs(axis_n,PosLoc_ExtendMon,NULL,0);               // 写OutPutMode 模式寄存器 
		}
			pcd4641_write_command_regs(axis_n,EvenData,p_control_para->Renv.regs,3);	// 设置运行环境参数 
		if (p_control_para->Mul>0)
    {
        p_control_para->MulReg= Motor_clk/8192/p_control_para->Mul;
    }
    else
    {
        p_control_para->Mul=BaseMul;
        p_control_para->MulReg= Motor_clk/8192/p_control_para->Mul;       
    }
		regs[0] = (p_control_para->MulReg)%256;
		regs[1] = (p_control_para->MulReg)/256;
		pcd4641_write_command_regs(axis_n,Manager_Reg,regs,2);

    Hight_Speed = p_control_para->HightSpeed;
    Low_Speed = p_control_para->LowSpeed;
    
    speed_cal_buf = Low_Speed*p_control_para->PluseNumPerCycle/MotorBaseCalSpeed;    
    p_control_para->LowSpeedReg = speed_cal_buf/(p_control_para->Mul);
		
		regs[0] = (p_control_para->LowSpeedReg)%256;
		regs[1] = (p_control_para->LowSpeedReg)/256;
		pcd4641_write_command_regs(axis_n,Low_Speed_Reg,regs,2);


    speed_cal_buf = Hight_Speed*p_control_para->PluseNumPerCycle/MotorBaseCalSpeed;    
    p_control_para->HighSpeedReg = speed_cal_buf/(p_control_para->Mul);
		
		regs[0] = (p_control_para->HighSpeedReg)%256;
		regs[1] = (p_control_para->HighSpeedReg)/256;
		pcd4641_write_command_regs(axis_n,High_Speed_Reg,regs,2);
		

    Access_Time = p_control_para->Accesstime;
    if (p_control_para->HighSpeedReg!=p_control_para->LowSpeedReg)
        access_cal_buf = (Access_Time)*(Motor_clk/1000)/(abs((int)(p_control_para->HighSpeedReg-p_control_para->LowSpeedReg)))/2;
    else
        access_cal_buf = 0;
    p_control_para->Lineeracc = access_cal_buf;
		regs[0] = (p_control_para->Lineeracc)%256;
		regs[1] = (p_control_para->Lineeracc)/256;
		pcd4641_write_command_regs(axis_n,Accel_Reg,regs,2);
		
     
    Ramp_Down_Buf = abs((int)(p_control_para->HighSpeedReg*p_control_para->HighSpeedReg
                        -p_control_para->LowSpeedReg*p_control_para->LowSpeedReg));
 
    Ramp_Down_Buf = Ramp_Down_Buf*access_cal_buf;
    Ramp_Down_Buf = Ramp_Down_Buf/p_control_para->MulReg/16384;
    
    p_control_para->RampDown = Ramp_Down_Buf;
		regs[0] = (p_control_para->RampDown)%256;
		regs[1] = (p_control_para->RampDown)/256;
		pcd4641_write_command_regs(axis_n,RapmDown_Reg,regs,2);
}

/****************************************************************************
  File name:      pcd4641.C
  Author: Wangyong      Version: 1.0        Date: 2030-04-14 
* 名称:  axis_SearchOrg(uint8_t axis_n,uint8_t dir)
* 功能:  电机查找原点            
* 调用者:            
* 调用      
* 入口参数:uint8_t axis_n,    轴
            uint8_t dir        旋转方向
* 出口参数:无
****************************************************************************/

void axis_SearchOrg(uint8_t axis_n,uint8_t dir)
{
	 if (dir)
			 pcd4641_write_command_regs(axis_n,Liner_Pos_Zero_Return ,NULL,0);//顺时针查找原点
	 else
       pcd4641_write_command_regs(axis_n,Liner_Nes_Zero_Return,NULL,0);//高速 变速
   pcd4641_write_command_regs(axis_n,Start_Motor_IntDisable_HighSpeed,NULL,0);//运行 
}

/****************************************************************************
  File name:      pcd4641.C
  Author: Wangyong      Version: 1.0        Date: 2030-04-14 
* 名称:  axis_stop(uint8_t axis_n)
* 功能:  电机停止           
* 调用者:            
* 调用      
* 入口参数:uint8_t axis_n,    轴
            
* 出口参数:无
****************************************************************************/
void axis_stop(uint8_t axis_n)
{
		pcd4641_write_command_regs(axis_n,Stop_Immediate_IntDisable,NULL,0);
}

/****************************************************************************
  File name:      pcd4641.C
  Author: Wangyong      Version: 1.0        Date: 2030-04-14 
* 名称:  axis_stop_dec(uint8_t axis_n)
* 功能:  电机减速停止           
* 调用者:            
* 调用      
* 入口参数:uint8_t axis_n,    轴
          
* 出口参数:无
****************************************************************************/

void axis_stop_dec(uint8_t axis_n)
{
		pcd4641_write_command_regs(axis_n,Stop_Deceleration_IntDisable,NULL,0);
}

/****************************************************************************
  File name:      pcd4641.C
  Author: Wangyong      Version: 1.0        Date: 2030-04-14 
* 名称:  axis_read_msts(uint8_t axis_n)
* 功能:  电机主要状态读取          
* 调用者:            
* 调用      
* 入口参数:uint8_t axis_n,    轴
          
* 出口参数:返回状态
  bit 0~7:ISTP ISDP ISTA BUSY PLSZ SDP FUP FDWN
  BUSY 轴运行
  SDP  过加减速点
  FUP  加速中
  FDWN 减速中
****************************************************************************/

uint8_t axis_read_msts(uint8_t axis_n)
{
	uint8_t msts = 0;
	axis_sel_code_t axis_sel_code;
	axis_sel_code.area.axis = 1<<(axis_n%4);
	axis_sel_code.area.type = General_Purpose_Read_Main;
	axis_sel_code.area.devcie = axis_n/4;
	
	PCD4641_CS_LOW();
	delay_us(100);
	SPI4_ReadWriteByte(axis_sel_code.code);
	delay_us(5);
	msts = SPI4_ReadWriteByte(0xff);
	PCD4641_CS_HIGH();
	
	return msts;
}

/****************************************************************************
  File name:      pcd4641.C
  Author: Wangyong      Version: 1.0        Date: 2030-04-14 
* 名称:  axis_pulse_count_rst(uint8_t axis_n)
* 功能:  脉冲计数器清零         
* 调用者:            
* 调用      
* 入口参数:uint8_t axis_n,    轴
            
* 出口参数:无
****************************************************************************/

void axis_pulse_count_rst(uint8_t axis_n)
{
	uint8_t regs[3]={0,0,0};
	pcd4641_write_command_regs(axis_n,PulseCount,regs,3);
}

void axis_pulse_count_write(uint8_t axis_n,uint32_t count)
{
	uint8_t regs[3]={0,0,0};
	regs[0] = (uint8_t)count;
	regs[1] = (uint8_t)(count>>8);
	regs[2] = (uint8_t)(count>>16);
	pcd4641_write_command_regs(axis_n,PulseCount,regs,3);
}

/****************************************************************************
  File name:      pcd4641.C
  Author: Wangyong      Version: 1.0        Date: 2030-04-14 
* 名称:  axis_rmv_write(uint8_t axis_n,uint32_t count)
* 功能:  电机运行脉冲个数        
* 调用者:            
* 调用      
* 入口参数:uint8_t axis_n,    轴
            
* 出口参数:无
****************************************************************************/

void axis_rmv_write(uint8_t axis_n,uint32_t count)
{
	uint8_t regs[3]={0,0,0};
	regs[0] = (uint8_t)count;
	regs[1] = (uint8_t)(count>>8);
	regs[2] = (uint8_t)(count>>16);
	pcd4641_write_command_regs(axis_n,Counter_Reg,regs,3);
}


/****************************************************************************
  File name:      pcd4641.C
  Author: Wangyong      Version: 1.0        Date: 2030-04-14 
* 名称:  axis_rmv_write(uint8_t axis_n,uint32_t count)
* 功能:  当前电机位置       
* 调用者:            
* 调用      
* 入口参数:uint8_t axis_n,    轴
            
* 出口参数:int32 位置值
****************************************************************************/

int32_t axis_read_pulse_count(uint8_t axis_n)
{
	uint8_t rev_regs[3]={0,0,0};
	uint32_t count=0;
	pcd4641_read_command(axis_n,PulseCount,rev_regs);
	
	count = (((uint32_t)(rev_regs[2]))<<16) + (((uint32_t)(rev_regs[1]))<<8) + rev_regs[0];
	if (count>0x7ffff)
		count = count - 0x1000000; // 24 bit 补码
	
	return (int32_t)count;
}

/****************************************************************************
  File name:      pcd4641.C
  Author: Wangyong      Version: 1.0        Date: 2030-04-14 
* 名称:  uint32_t axis_read_rsts(uint8_t axis_n)
* 功能:  读取外部状态        
* 调用者:            
* 调用      
* 入口参数:uint8_t axis_n,    轴
            
* 出口参数:int32 bit[7:0] msts bit[15:8]-rsts[7:0] bit[23:16]-rsts[15:8]
****************************************************************************/

uint32_t axis_read_rsts(uint8_t axis_n)
{
	uint8_t rev_regs[3]={0,0,0};
	uint32_t sta=0;
	pcd4641_read_command(axis_n,RSTS,rev_regs);
	sta = (((uint32_t)(rev_regs[2]))<<16) + (((uint32_t)(rev_regs[1]))<<8) + rev_regs[0];
	return sta;
}


/****************************************************************************
  File name:      pcd4641.C
  Author: Wangyong      Version: 1.0        Date: 2030-04-14 
* 名称:  uint32_t axis_read_rsts(uint8_t axis_n)
* 功能:  读取外部状态        
* 调用者:            
* 调用      
* 入口参数:uint8_t axis_n,    轴
            
* 出口参数:int32 bit[7:0] msts bit[15:8]-rsts[7:0] bit[23:16]-rsts[15:8]
****************************************************************************/

uint32_t axis_read_outstatus(uint8_t axis_n)
{
	uint8_t rev_regs[3]={0,0,0};
	uint32_t sta=0;
	pcd4641_read_command(axis_n,ALL_STATUS,rev_regs);
	sta = (((uint32_t)(rev_regs[2]))<<16) + (((uint32_t)(rev_regs[1]))<<8) + rev_regs[0];
	return sta;
}

/****************************************************************************
  File name:      pcd4641.C
  Author: Wangyong      Version: 1.0        Date: 2030-04-14 
* 名称:  axis_Move(uint8_t axis_n,Motor_ActionInfo_t *pAction)
* 功能:  电机运行        
* 调用者:            
* 调用      
* 入口参数:uint8_t axis_n,    轴
            Motor_ActionInfo_t *pAction
* 出口参数:无
****************************************************************************/

void axis_Move(uint8_t axis_n,Motor_ActionInfo_t *pAction)
{
	  //pcd4641_write_command_regs(1,0x44,NULL,0);
	  pcd4641_write_command_regs(axis_n,pAction->ControlMode,NULL,0);
	  pcd4641_write_command_regs(axis_n,pAction->StartMode,NULL,0);
	  
	  //pcd4641_write_command_regs(1,0X15,NULL,0);
}


/****************************************************************************
  File name:      pcd4641.C
  Author: Wangyong      Version: 1.0        Date: 2030-04-14 
* 名称:  axis_Move(uint8_t axis_n,Motor_ActionInfo_t *pAction)
* 功能:  pcd4641 各轴初始化       
* 调用者:            
* 调用      
* 入口参数:p_pcd4641_dev_t pdev,    驱动对象
            motor_Save_t *p_Para     初始化参数
* 出口参数:无
****************************************************************************/

uint8_t pcd4641_init(p_pcd4641_dev_t pdev,motor_Save_t *p_Para)
{
	renv_t renv_buff;
	int8_t i;
	motor_Para_t *p;
	
	p_pcd4641_dev = pdev;

  for (i=0;i<Max_Axis;i++)
	{
      p = &p_Para->DetalPara.para[i];
		  pdev->control_para[i].Mul=20; 						 //放大倍数
      pdev->control_para[i].MulReg=0; 				   //放大倍数寄存器
      pdev->control_para[i].HighSpeedReg=0;     //最大速度寄存器
      pdev->control_para[i].LowSpeedReg=0;      //最低速度寄存器     
	    pdev->control_para[i].Lineeracc=0;      	 //线性
	    pdev->control_para[i].RampDown=0;       	 //降速点位置
	    pdev->control_para[i].Accesstime=200;     //加减速时间 ms
	    pdev->control_para[i].Renv.regs[0]=0x7b;
	    pdev->control_para[i].Renv.regs[1]=2;
	    pdev->control_para[i].Renv.regs[2]=0;
		  pdev->control_para[i].Roate_logic = MoveLogic[i];
		  pdev->control_para[i].PluseNumPerCycle = 25600;
		  pdev->control_para[i].DistancePerCycle = distancePercycle[i];
		
		  pdev->control_para[i].HightSpeed=p->HighSpeed;     //最大转速
	    pdev->control_para[i].LowSpeed=p->LowSpeed;        //最小转速
		  //pdev->control_para[i].Accesstime=p->AssessTime;     //加减速时间 ms
	
	    //pcd4641_gpio_init();
	    axis_initiate(i);
		  delay_us(500);
	}
	pcd4641_read_info(4,renv_buff.regs);
	return 1;
}

/****************************** 以下接口预留 ******************************/

void axis_set_mul(uint8_t axis_n,uint16_t mul)
{  
	uint8_t regs[2]={0,0};
	uint16_t Mul_Value;
	p_control_para_t p_control_para = &(p_pcd4641_dev->control_para[axis_n]);
	Mul_Value = mul;
	
	p_control_para->MulReg= Motor_clk/8192/Mul_Value;
	p_control_para->Mul = Mul_Value;

	regs[0] = (p_control_para->MulReg)/256;
	regs[1] = (p_control_para->MulReg)%256;
	pcd4641_write_command_regs(axis_n,Manager_Reg,regs,2);
}


void axis_set_speed(uint8_t axis_n,uint32_t hspeed,uint32_t lspeed)
{
	uint32_t speed_cal_buf;
	uint32_t access_cal_buf;
	uint8_t regs[2]={0,0};

	p_control_para_t p_control_para = &(p_pcd4641_dev->control_para[axis_n]);
    
	p_control_para->HightSpeed = hspeed;
	p_control_para->LowSpeed = lspeed;
	
	speed_cal_buf = lspeed*MotorSpeedBasePulse/MotorBaseCalSpeed;
	
	p_control_para->LowSpeedReg = speed_cal_buf/(p_control_para->Mul);
	
	regs[0] = (p_control_para->LowSpeedReg)/256;
	regs[1] = (p_control_para->LowSpeedReg)%256;
	pcd4641_write_command_regs(axis_n,Low_Speed_Reg,regs,2);

	
	speed_cal_buf = hspeed*MotorSpeedBasePulse/MotorBaseCalSpeed;
	speed_cal_buf /= p_control_para->Mul;
	
	regs[0] = (p_control_para->HighSpeedReg)/256;
	regs[1] = (p_control_para->HighSpeedReg)%256;
	pcd4641_write_command_regs(axis_n,High_Speed_Reg,regs,2);
}

void axis_set_access(uint8_t axis_n,uint32_t access_time)
{  
    uint32_t access_cal_buf;
    uint8_t regs[2]={0,0};
		
		p_control_para_t p_control_para = &(p_pcd4641_dev->control_para[axis_n]);
		
    p_control_para->Accesstime = access_time;
    
    if (p_control_para->HighSpeedReg!=p_control_para->LowSpeedReg)
        access_cal_buf = (access_time)*(Motor_clk/1000)/(abs((int)(p_control_para->HighSpeedReg-p_control_para->LowSpeedReg)))/2;
    else
        access_cal_buf = 0;
    
    p_control_para->Lineeracc = access_cal_buf;   
		regs[0] = access_cal_buf/256;
    regs[1]= access_cal_buf%256;
		pcd4641_write_command_regs(axis_n,Accel_Reg,regs,2);
}

void axis_run(uint8_t axis_n,uint8_t dir,uint32_t loc,uint32_t hspeed,uint32_t lspeed)
{
	static uint32_t state = 0;
    

	state = axis_read_msts(axis_n); //读取主状态
	state = axis_read_rsts(axis_n); //读取外部状态


	axis_rmv_write(axis_n,loc); //运行脉冲数
	axis_set_speed(axis_n,hspeed,lspeed); //设置运行速度
	
	if(dir)
	{
		if(state & (1ul<<2)) //说明在原点
		{
			pcd4641_write_command_regs(axis_n,Liner_Nes_Pre_NoOrgSL,NULL,0);//往右
		}
		else
		{
			pcd4641_write_command_regs(axis_n,Liner_Nes_Pre_OrgSL,NULL,0);//往右
		}
		//Motor_Control_Ptr->WR_Command =Start_Motor_IntDisable_LowSpeedCon ; //低速 常速
		
	//	pcd4641_write_command_regs(AXIS_X,Start_Motor_IntDisable_LowSpeedCon,NULL,0);//低速 常速
		pcd4641_write_command_regs(axis_n,Start_Motor_IntDisable_HighSpeed,NULL,0);//高速 变速
	}
	else
	{
		pcd4641_write_command_regs(axis_n,Liner_Pos_Pre_OrgSL,NULL,0);//往左
		pcd4641_write_command_regs(axis_n,Start_Motor_IntEnable_HighSpeed,NULL,0);//高速 变速
		//Motor_Control_Ptr->WR_Command =Start_Motor_IntEnable_LowSpeedCon ;//低速 常速
	}
}





void EXTI3_IRQHandler(void)
{
	if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_3) != RESET)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3);
  }
}

pcd4641.h

#ifndef __PCD4641_H
#define __PCD4641_H
#include "cmsis_os2.h" 
#include "sys_stru.h"

#ifdef __cplusplus
 extern "C" {
#endif

/*-------------------------------------------------------------------*/
/*                   Motor Control Start Command                     */
/*-------------------------------------------------------------------*/
#define Start_Motor_IntEnable_LowSpeedCon      0x30    // 常速驱动  中断开 STOP:以FL启动  RUNING:立即变为FL     
#define Start_Motor_IntEnable_HighSpeed        0x35    // 变速驱动  中断开 STOP:以FH启动  RUNING:加速至FH    
#define Start_Motor_IntDisable_HighSpeed       0x15    // 变速驱动  中断关 STOP:以FH启动  RUNING:加速至FH  		
#define Start_Motor_IntDisable_LowSpeed        0x10    // 常速驱动  中断关 STOP:以FL启动  RUNING:立即变为FL
#define Start_Motor_IntDisable_HighSpeedCon    0x11    // 常速驱动  中断关 STOP:以FH启动  RUNING:立即变为FH  


#define Stop_Immediate_IntDisable              0x08    // 立即停止  中断关     
#define Stop_Immediate_IntEnable               0x28    // 立即停止  中断开     
#define Stop_Deceleration_IntDisable           0x1D    // 减速停止  中断关     
#define Stop_Deceleration_IntEnable            0x3D    // 减速停止  中断开     

/*-------------------------------------------------------------------*/
/*                 Motor Control Mode Command                     */
/*-------------------------------------------------------------------*/
#define Liner_Pos_Zero_Return             0x43         // 线性逆时针驱动,搜寻原点
#define Liner_Nes_Zero_Return             0x4b         // 线性顺时针驱动,搜寻原点
#define Scurve_Pos_Zero_Return            0x63         // 余弦逆时针驱动,搜寻原点
#define Scurve_Nes_Zero_Return            0x6b         // 余弦顺时针驱动,搜寻原点
#define Liner_Pos_ReturnNoOrg             0x42         // 线性逆时针驱动
#define Liner_Nes_ReturnNoOrg             0x4a         // 线性顺时针驱动
#define Scurve_Pos_Return                 0x62         // 余弦逆时针驱动
#define Scurve_Nes_Return                 0x6a         // 余弦顺时针驱动
#define Liner_Pos_Pre_NoOrgSL             0x44         //线性正方向忽略原点减速
#define Liner_Nes_Pre_NoOrgSL             0x4c		     //线性负方向忽略原点减速
#define Liner_Pos_Pre_OrgSL               0x45         //线性正方向原点减速
#define Liner_Nes_Pre_OrgSL               0x4d		     //线性负方向原点减速
#define Scurve_Pos_Pre_NoOrgSL            0x64		     //曲线S型正方向忽略原点减速
#define Scurve_Nes_Pre_NoOrgSL            0x6c		     //曲线S型负方向忽略原点减速	

#define ORG_Enable                        0x01
#define SL_Enable                         0x02
#define ORG_Disable                       0xfe
#define SL_Disable                        0xfd


/*-------------------------------------------------------------------*/
/*                 Motor Register Selection Command                    */
/*-------------------------------------------------------------------*/

#define Counter_Reg                       0x80
#define Low_Speed_Reg                     0x81
#define High_Speed_Reg                    0x82
#define Accel_Reg                         0x83
#define Manager_Reg                       0x84
#define RapmDown_Reg                      0x85
#define IdlePulse_Reg                     0x86
#define StatusRead                        0x87
#define EvenData                          0x87
#define PulseCount                        0x88
#define RSTS                              0x89
#define ALL_STATUS                        0x10

/*-------------------------------------------------------------------*/
/*                 Motor Control output mode Command                    */
/*-------------------------------------------------------------------*/
#define PosLoc_NormalMon                  0xd1 //标准正脉冲输出模式
#define NegLoc_NormalMon                  0xd0 //标准负脉冲输出模式
#define PosLoc_ExtendMon                  0xf1 //扩展正脉冲输出模式
#define NegLoc_ExtendMon                  0xf0 //扩展负脉冲输出模式

/*-------------------------------------------------------------------*/
/*                Serial I/F Access type                   */
/*-------------------------------------------------------------------*/
#define General_Purpose_Write 0x00   			//0-24bit
#define General_Purpose_Read  0x01   			//24bit
#define General_Purpose_Read_Port  0x02   //8bit
#define General_Purpose_Read_Main  0x03		//8bit

#define BaseMul                  50
#define MotorBaseStep            25600
#define MotorSpeedBasePulse      MotorBaseStep/BaseMul
#define MotorBaseCalSpeed        60
#define Motor_clk                4096000





typedef union
{
	struct
	{
		uint8_t renv_pmd:1; 
		uint8_t renv_46md:1;
		uint8_t renv_dcsp:1;
		uint8_t renv_aspd:1;
		uint8_t renv_spds:1;
		uint8_t renv_elds:1;
		uint8_t renv_ords:1;
		uint8_t renv_orrs:1;
		uint8_t renv_pstp:1;
		uint8_t renv_prev:1;
		uint8_t renv_mskn:1;
		uint8_t renv_iopm:1;
		uint8_t renv_ipm1:1;
		uint8_t renv_ipm2:1;
		uint8_t renv_ipm3:1;
		uint8_t renv_ipm4:1;
		uint8_t reserve; 
	}renv_area;
	uint8_t regs[3];
}renv_t,*p_renv_t;

typedef struct
{
		 unsigned int Mul; 						//放大倍数
		 unsigned int MulReg; 				//放大倍数寄存器
		 unsigned int HighSpeedReg;   // 最大速度寄存器
		 unsigned int LowSpeedReg;    // 最低速度寄存器
		 unsigned int HightSpeed;     // 最大转速
		 unsigned int LowSpeed;       // 最小转速
		 unsigned int Lineeracc;      //线性
		 unsigned int RampDown;       //降速点位置
		 unsigned int Accesstime;     //加减速时间 ms
		 renv_t				Renv;						//运行环境配置参数
	   uint8_t  Roate_logic;           // 旋转逻辑
	   uint32_t PluseNumPerCycle;      // 细分数
	   uint16_t DistancePerCycle;      // 一圈运动距离
}control_para_t,*p_control_para_t;

typedef union
{
	struct
	{
		uint8_t axis:4;
		uint8_t type:2;
		uint8_t devcie:2;
	}area;
	
	uint8_t code;
}axis_sel_code_t,*p_axis_sel_code_t;



typedef struct
{
	control_para_t control_para[Max_Axis];
}pcd4641_dev_t,*p_pcd4641_dev_t;

extern  p_pcd4641_dev_t p_pcd4641_dev;

extern uint8_t pcd4641_init(p_pcd4641_dev_t dev,motor_Save_t *p_Para);
extern int32_t axis_read_pulse_count(uint8_t axis_n);
extern void axis_run(uint8_t axis_n,uint8_t dir,uint32_t loc,uint32_t hspeed,uint32_t lspeed);
extern void axis_SearchOrg(uint8_t axis_n,uint8_t dir);
extern void axis_stop(uint8_t axis_n);
extern void axis_stop_dec(uint8_t axis_n);
extern void axis_Move(uint8_t axis_n,Motor_ActionInfo_t *pAction);
extern uint32_t axis_read_rsts(uint8_t axis_n);
extern void axis_rmv_write(uint8_t axis_n,uint32_t count);
extern uint8_t axis_read_msts(uint8_t axis_n);
extern void pcd4641_write_command_regs(uint8_t axis_n,uint8_t commd,uint8_t *regs,uint8_t reg_count);
extern uint32_t axis_read_outstatus(uint8_t axis_n);
extern void axis_pulse_count_rst(uint8_t axis_n);
extern void axis_pulse_count_write(uint8_t axis_n,uint32_t count);

#ifdef __cplusplus
}
#endif

#endif

w25qxx.c

#include "w25qxx.h"
#include "spi.h"
#include "delay.h"
#include "usart.h"
#include "stm32f4xx_hal_gpio.h"
#include "sys.h"
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F429开发板
//W25QXX驱动代码	   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2016/1/16
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved									  
// 	

uint16_t W25QXX_TYPE=W25Q16;	//默认是W25Q256

uint8_t W25QXX_BUFFER[4096] __attribute__((at(0xc0011200)));	

//4Kbytes为一个Sector
//16个扇区为1个Block
//W25Q256
//容量为32M字节,共有512个Block,8192个Sector 
													 
//初始化SPI FLASH的IO口
void W25QXX_Init(void)
{ 
    uint8_t temp;   
    //__HAL_RCC_GPIOF_CLK_ENABLE();           //使能GPIOF时钟
    
    //PF6
    /*GPIO_Initure.Pin=GPIO_PIN_6;            //PF6
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_FAST;     //快速         
    HAL_GPIO_Init(GPIOF,&GPIO_Initure);     //初始化*/
    
	W25QXX_CS=1;			                //SPI FLASH不选中
	//SPI5_Init();		   			        //初始化SPI
	SPI5_SetSpeed(SPI_BAUDRATEPRESCALER_2); //设置为45M时钟,高速模式
	W25QXX_TYPE=W25QXX_ReadID();	        //读取FLASH ID.
    if(W25QXX_TYPE==W25Q256)                //SPI FLASH为W25Q256
    {
        temp=W25QXX_ReadSR(3);              //读取状态寄存器3,判断地址模式
        if((temp&0X01)==0)			        //如果不是4字节地址模式,则进入4字节地址模式
		{
			W25QXX_CS=0; 			        //选中
			SPI5_ReadWriteByte(W25X_Enable4ByteAddr);//发送进入4字节地址模式指令   
			W25QXX_CS=1;       		        //取消片选   
		}
    }
}  

//读取W25QXX的状态寄存器,W25QXX一共有3个状态寄存器
//状态寄存器1:
//BIT7  6   5   4   3   2   1   0
//SPR   RV  TB BP2 BP1 BP0 WEL BUSY
//SPR:默认0,状态寄存器保护位,配合WP使用
//TB,BP2,BP1,BP0:FLASH区域写保护设置
//WEL:写使能锁定
//BUSY:忙标记位(1,忙;0,空闲)
//默认:0x00
//状态寄存器2:
//BIT7  6   5   4   3   2   1   0
//SUS   CMP LB3 LB2 LB1 (R) QE  SRP1
//状态寄存器3:
//BIT7      6    5    4   3   2   1   0
//HOLD/RST  DRV1 DRV0 (R) (R) WPS ADP ADS
//regno:状态寄存器号,范:1~3
//返回值:状态寄存器值
uint8_t W25QXX_ReadSR(uint8_t regno)   
{  
	uint8_t byte=0,command=0; 
    switch(regno)
    {
        case 1:
            command=W25X_ReadStatusReg1;    //读状态寄存器1指令
            break;
        case 2:
            command=W25X_ReadStatusReg2;    //读状态寄存器2指令
            break;
        case 3:
            command=W25X_ReadStatusReg3;    //读状态寄存器3指令
            break;
        default:
            command=W25X_ReadStatusReg1;    
            break;
    }    
	W25QXX_CS=0;                            //使能器件   
	SPI5_ReadWriteByte(command);            //发送读取状态寄存器命令    
	byte=SPI5_ReadWriteByte(0Xff);          //读取一个字节  
	W25QXX_CS=1;                            //取消片选     
	return byte;   
} 
//写W25QXX状态寄存器
void W25QXX_Write_SR(uint8_t regno,uint8_t sr)   
{   
    uint8_t command=0;
    switch(regno)
    {
        case 1:
            command=W25X_WriteStatusReg1;    //写状态寄存器1指令
            break;
        case 2:
            command=W25X_WriteStatusReg2;    //写状态寄存器2指令
            break;
        case 3:
            command=W25X_WriteStatusReg3;    //写状态寄存器3指令
            break;
        default:
            command=W25X_WriteStatusReg1;    
            break;
    }   
	W25QXX_CS=0;                            //使能器件   
	SPI5_ReadWriteByte(command);            //发送写取状态寄存器命令    
	SPI5_ReadWriteByte(sr);                 //写入一个字节  
	W25QXX_CS=1;                            //取消片选     	      
}   
//W25QXX写使能	
//将WEL置位   
void W25QXX_Write_Enable(void)   
{
	W25QXX_CS=0;                            //使能器件   
    SPI5_ReadWriteByte(W25X_WriteEnable);   //发送写使能  
	W25QXX_CS=1;                            //取消片选     	      
} 
//W25QXX写禁止	
//将WEL清零  
void W25QXX_Write_Disable(void)   
{  
	W25QXX_CS=0;                            //使能器件   
    SPI5_ReadWriteByte(W25X_WriteDisable);  //发送写禁止指令    
	W25QXX_CS=1;                            //取消片选     	      
} 

//读取芯片ID
//返回值如下:				   
//0XEF13,表示芯片型号为W25Q80  
//0XEF14,表示芯片型号为W25Q16    
//0XEF15,表示芯片型号为W25Q32  
//0XEF16,表示芯片型号为W25Q64 
//0XEF17,表示芯片型号为W25Q128 	  
//0XEF18,表示芯片型号为W25Q256
uint16_t W25QXX_ReadID(void)
{
	uint16_t Temp = 0;	  
	W25QXX_CS=0;				    
	SPI5_ReadWriteByte(0x90);//发送读取ID命令	    
	SPI5_ReadWriteByte(0x00); 	    
	SPI5_ReadWriteByte(0x00); 	    
	SPI5_ReadWriteByte(0x00); 	 			   
	Temp|=SPI5_ReadWriteByte(0xFF)<<8;  
	Temp|=SPI5_ReadWriteByte(0xFF);	 
	W25QXX_CS=1;				    
	return Temp;
}   		    
//读取SPI FLASH  
//在指定地址开始读取指定长度的数据
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(24bit)
//NumByteToRead:要读取的字节数(最大65535)
void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)   
{ 
 	uint16_t i;   										    
	W25QXX_CS=0;                            //使能器件   
    SPI5_ReadWriteByte(W25X_ReadData);      //发送读取命令  
    if(W25QXX_TYPE==W25Q256)                //如果是W25Q256的话地址为4字节的,要发送最高8位
    {
        SPI5_ReadWriteByte((uint8_t)((ReadAddr)>>24));    
    }
    SPI5_ReadWriteByte((uint8_t)((ReadAddr)>>16));   //发送24bit地址    
    SPI5_ReadWriteByte((uint8_t)((ReadAddr)>>8));   
    SPI5_ReadWriteByte((uint8_t)ReadAddr);   
    for(i=0;i<NumByteToRead;i++)
	{ 
        pBuffer[i]=SPI5_ReadWriteByte(0XFF);    //循环读数  
    }
	W25QXX_CS=1;  				    	      
}  
//SPI在一页(0~65535)内写入少于256个字节的数据
//在指定地址开始写入最大256字节的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!	 
void W25QXX_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
 	uint16_t i;  
    W25QXX_Write_Enable();                  //SET WEL 
	W25QXX_CS=0;                            //使能器件   
    SPI5_ReadWriteByte(W25X_PageProgram);   //发送写页命令   
    if(W25QXX_TYPE==W25Q256)                //如果是W25Q256的话地址为4字节的,要发送最高8位
    {
        SPI5_ReadWriteByte((uint8_t)((WriteAddr)>>24)); 
    }
    SPI5_ReadWriteByte((uint8_t)((WriteAddr)>>16)); //发送24bit地址    
    SPI5_ReadWriteByte((uint8_t)((WriteAddr)>>8));   
    SPI5_ReadWriteByte((uint8_t)WriteAddr);   
    for(i=0;i<NumByteToWrite;i++)SPI5_ReadWriteByte(pBuffer[i]);//循环写数  
	W25QXX_CS=1;                            //取消片选 
	W25QXX_Wait_Busy();					   //等待写入结束
} 
//无检验写SPI FLASH 
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能 
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   
{ 			 		 
	uint16_t pageremain;	   
	pageremain=256-WriteAddr%256; //单页剩余的字节数		 	    
	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
	while(1)
	{	   
		W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
		if(NumByteToWrite==pageremain)break;//写入结束了
	 	else //NumByteToWrite>pageremain
		{
			pBuffer+=pageremain;
			WriteAddr+=pageremain;	

			NumByteToWrite-=pageremain;			  //减去已经写入了的字节数
			if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
			else pageremain=NumByteToWrite; 	  //不够256个字节了
		}
	};	    
} 
//写SPI FLASH  
//在指定地址开始写入指定长度的数据
//该函数带擦除操作!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)						
//NumByteToWrite:要写入的字节数(最大65535)   
	 
void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   
{ 
	uint32_t secpos;
	uint16_t secoff;
	uint16_t secremain;	   
 	uint16_t i;    
	uint8_t * W25QXX_BUF;	  
   	W25QXX_BUF=W25QXX_BUFFER;	     
 	secpos=WriteAddr/4096;//扇区地址  
	secoff=WriteAddr%4096;//在扇区内的偏移
	secremain=4096-secoff;//扇区剩余空间大小   
 	//printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//测试用
 	if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节
	while(1) 
	{	
		W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容
		for(i=0;i<secremain;i++)//校验数据
		{
			if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除  	  
		}
		if(i<secremain)//需要擦除
		{
			W25QXX_Erase_Sector(secpos);//擦除这个扇区
			for(i=0;i<secremain;i++)	   //复制
			{
				W25QXX_BUF[i+secoff]=pBuffer[i];	  
			}
			W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区  

		}else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间. 				   
		if(NumByteToWrite==secremain)break;//写入结束了
		else//写入未结束
		{
			secpos++;//扇区地址增1
			secoff=0;//偏移位置为0 	 

		   	pBuffer+=secremain;  //指针偏移
			WriteAddr+=secremain;//写地址偏移	   
		   	NumByteToWrite-=secremain;				//字节数递减
			if(NumByteToWrite>4096)secremain=4096;	//下一个扇区还是写不完
			else secremain=NumByteToWrite;			//下一个扇区可以写完了
		}	 
	};	 
}
//擦除整个芯片		  
//等待时间超长...
void W25QXX_Erase_Chip(void)   
{                                   
    W25QXX_Write_Enable();                  //SET WEL 
    W25QXX_Wait_Busy();   
  	W25QXX_CS=0;                            //使能器件   
    SPI5_ReadWriteByte(W25X_ChipErase);        //发送片擦除命令  
	W25QXX_CS=1;                            //取消片选     	      
	W25QXX_Wait_Busy();   				   //等待芯片擦除结束
}   
//擦除一个扇区
//Dst_Addr:扇区地址 根据实际容量设置
//擦除一个扇区的最少时间:150ms
void W25QXX_Erase_Sector(uint32_t Dst_Addr)   
{  
	//监视falsh擦除情况,测试用   
 	//printf("fe:%x\r\n",Dst_Addr);	  
 	Dst_Addr*=4096;
    W25QXX_Write_Enable();                  //SET WEL 	 
    W25QXX_Wait_Busy();   
  	W25QXX_CS=0;                            //使能器件   
    SPI5_ReadWriteByte(W25X_SectorErase);   //发送扇区擦除指令 
    if(W25QXX_TYPE==W25Q256)                //如果是W25Q256的话地址为4字节的,要发送最高8位
    {
        SPI5_ReadWriteByte((uint8_t)((Dst_Addr)>>24)); 
    }
    SPI5_ReadWriteByte((uint8_t)((Dst_Addr)>>16));  //发送24bit地址    
    SPI5_ReadWriteByte((uint8_t)((Dst_Addr)>>8));   
    SPI5_ReadWriteByte((uint8_t)Dst_Addr);  
	W25QXX_CS=1;                            //取消片选     	      
    W25QXX_Wait_Busy();   				    //等待擦除完成
}  
//等待空闲
void W25QXX_Wait_Busy(void)   
{   
	while((W25QXX_ReadSR(1)&0x01)==0x01);   // 等待BUSY位清空
}  
//进入掉电模式
void W25QXX_PowerDown(void)   
{ 
  	W25QXX_CS=0;                            //使能器件   
    SPI5_ReadWriteByte(W25X_PowerDown);     //发送掉电命令  
	W25QXX_CS=1;                            //取消片选     	      
    delay_us(3);                            //等待TPD  
}   
//唤醒
void W25QXX_WAKEUP(void)   
{  
  	W25QXX_CS=0;                                //使能器件   
    SPI5_ReadWriteByte(W25X_ReleasePowerDown);  //  send W25X_PowerDown command 0xAB    
	W25QXX_CS=1;                                //取消片选     	      
    delay_us(3);                                //等待TRES1
}   

w25qxx.h

#ifndef __W25QXX_H
#define __W25QXX_H
#include "cmsis_os2.h"
//#include "sys.h"
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F429开发板
//W25QXX驱动代码	   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2016/1/16
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved									  
// 	

//W25X系列/Q系列芯片列表	   
//W25Q80  ID  0XEF13
//W25Q16  ID  0XEF14
//W25Q32  ID  0XEF15
//W25Q64  ID  0XEF16	
//W25Q128 ID  0XEF17	
//W25Q256 ID  0XEF18
#define W25Q80 	0XEF13 	
#define W25Q16 	0XEF14
#define W25Q32 	0XEF15
#define W25Q64 	0XEF16
#define W25Q128	0XEF17
#define W25Q256 0XEF18

extern uint16_t W25QXX_TYPE;					//定义W25QXX芯片型号		   

#define	W25QXX_CS 		PFout(6)  		//W25QXX的片选信号

// 
//指令表
#define W25X_WriteEnable		0x06 
#define W25X_WriteDisable		0x04 
#define W25X_ReadStatusReg1		0x05 
#define W25X_ReadStatusReg2		0x35 
#define W25X_ReadStatusReg3		0x15 
#define W25X_WriteStatusReg1    0x01 
#define W25X_WriteStatusReg2    0x31 
#define W25X_WriteStatusReg3    0x11 
#define W25X_ReadData			0x03 
#define W25X_FastReadData		0x0B 
#define W25X_FastReadDual		0x3B 
#define W25X_PageProgram		0x02 
#define W25X_BlockErase			0xD8 
#define W25X_SectorErase		0x20 
#define W25X_ChipErase			0xC7 
#define W25X_PowerDown			0xB9 
#define W25X_ReleasePowerDown	0xAB 
#define W25X_DeviceID			0xAB 
#define W25X_ManufactDeviceID	0x90 
#define W25X_JedecDeviceID		0x9F 
#define W25X_Enable4ByteAddr    0xB7
#define W25X_Exit4ByteAddr      0xE9

extern void W25QXX_Init(void);
extern uint16_t  W25QXX_ReadID(void);  	    		//读取FLASH ID
extern uint8_t W25QXX_ReadSR(uint8_t regno);             //读取状态寄存器 
extern void W25QXX_4ByteAddr_Enable(void);     //使能4字节地址模式
extern void W25QXX_Write_SR(uint8_t regno,uint8_t sr);   //写状态寄存器
extern void W25QXX_Write_Enable(void);  		//写使能 
extern void W25QXX_Write_Disable(void);		//写保护
extern void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
extern void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead);   //读取flash
extern void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//写入flash
extern void W25QXX_Erase_Chip(void);    	  	//整片擦除
extern void W25QXX_Erase_Sector(uint32_t Dst_Addr);	//扇区擦除
extern void W25QXX_Wait_Busy(void);           	//等待空闲
extern void W25QXX_PowerDown(void);        	//进入掉电模式
extern void W25QXX_WAKEUP(void);				//唤醒

#endif

RAM_INFO.txt
RAM 说明

内部RAM 0x20000000 size 0x30000

  1. os 使用 0x20028000 ~ 0x2002ffff 32k 统一设置为 8字节对齐
    静态分配 各线程 stack_mem, message data_mem

使用情况
0x20028000 ~ 0x20007ff size 2k 电机控制线程 stack
0x20028800 ~ 0x20009ff size 512 app启动线程 stack
0x20028a00 ~ 0x2000bff size 512 Can发送进程 stack

//0x20007000~0x20077ff size 2k Can Send messageQeue
0x20008000~0x20079ff size 512 Encode SenMessageQeue

以上地址 IAP 根据 iap 调整

  1. 全局,栈,堆 使用 0x2008000 ~ 0x202ffff 160k

0xc0013200 size 2k Can Send messageQeue

外部SRAM 0xc000000

stm32f4xx_it.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    stm32f4xx_it.c
  * @brief   Interrupt Service Routines.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */

/* USER CODE END TD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
 
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/* External variables --------------------------------------------------------*/
extern CAN_HandleTypeDef hcan1;
extern UART_HandleTypeDef huart4;
extern UART_HandleTypeDef huart1;
extern UART_HandleTypeDef huart3;
/* USER CODE BEGIN EV */
extern uint8_t ustart3RdChar;
extern uint8_t uart4RdChar;
/* USER CODE END EV */

/******************************************************************************/
/*           Cortex-M4 Processor Interruption and Exception Handlers          */ 
/******************************************************************************/
/**
  * @brief This function handles Non maskable interrupt.
  */
void NMI_Handler(void)
{
  /* USER CODE BEGIN NonMaskableInt_IRQn 0 */

  /* USER CODE END NonMaskableInt_IRQn 0 */
  /* USER CODE BEGIN NonMaskableInt_IRQn 1 */

  /* USER CODE END NonMaskableInt_IRQn 1 */
}

/**
  * @brief This function handles Hard fault interrupt.
  */
void HardFault_Handler(void)
{
  /* USER CODE BEGIN HardFault_IRQn 0 */

  /* USER CODE END HardFault_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_HardFault_IRQn 0 */
    /* USER CODE END W1_HardFault_IRQn 0 */
  }
}

/**
  * @brief This function handles Memory management fault.
  */
void MemManage_Handler(void)
{
  /* USER CODE BEGIN MemoryManagement_IRQn 0 */

  /* USER CODE END MemoryManagement_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
    /* USER CODE END W1_MemoryManagement_IRQn 0 */
  }
}

/**
  * @brief This function handles Pre-fetch fault, memory access fault.
  */
void BusFault_Handler(void)
{
  /* USER CODE BEGIN BusFault_IRQn 0 */

  /* USER CODE END BusFault_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_BusFault_IRQn 0 */
    /* USER CODE END W1_BusFault_IRQn 0 */
  }
}

/**
  * @brief This function handles Undefined instruction or illegal state.
  */
void UsageFault_Handler(void)
{
  /* USER CODE BEGIN UsageFault_IRQn 0 */

  /* USER CODE END UsageFault_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_UsageFault_IRQn 0 */
    /* USER CODE END W1_UsageFault_IRQn 0 */
  }
}

/**
  * @brief This function handles Debug monitor.
  */
void DebugMon_Handler(void)
{
  /* USER CODE BEGIN DebugMonitor_IRQn 0 */

  /* USER CODE END DebugMonitor_IRQn 0 */
  /* USER CODE BEGIN DebugMonitor_IRQn 1 */

  /* USER CODE END DebugMonitor_IRQn 1 */
}

/******************************************************************************/
/* STM32F4xx Peripheral Interrupt Handlers                                    */
/* Add here the Interrupt Handlers for the used peripherals.                  */
/* For the available peripheral interrupt handler names,                      */
/* please refer to the startup file (startup_stm32f4xx.s).                    */
/******************************************************************************/

/**
  * @brief This function handles CAN1 RX0 interrupts.
  */
void CAN1_RX0_IRQHandler(void)
{
  /* USER CODE BEGIN CAN1_RX0_IRQn 0 */

  /* USER CODE END CAN1_RX0_IRQn 0 */
  HAL_CAN_IRQHandler(&hcan1);
  /* USER CODE BEGIN CAN1_RX0_IRQn 1 */

  /* USER CODE END CAN1_RX0_IRQn 1 */
}

/**
  * @brief This function handles USART1 global interrupt.
  */
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

/**
  * @brief This function handles USART3 global interrupt.
  */
void USART3_IRQHandler(void)
{
  /* USER CODE BEGIN USART3_IRQn 0 */
  /*if(__HAL_UART_GET_FLAG( &huart3, UART_FLAG_RXNE ) != RESET)
	{	
		HAL_UART_Receive(&huart3, (uint8_t *)&ustart3RdChar, 1, 100);
		HAL_UART_Transmit(&huart3, &ustart3RdChar, 1,10);
	}*/
	//HAL_UART_Transmit(&huart3, &ustart3RdChar, 1,10);
  /* USER CODE END USART3_IRQn 0 */
  HAL_UART_IRQHandler(&huart3);
  /* USER CODE BEGIN USART3_IRQn 1 */
  HAL_UART_Receive_IT(&huart3, (uint8_t *)&ustart3RdChar, 1);
  /* USER CODE END USART3_IRQn 1 */
}

/**
  * @brief This function handles UART4 global interrupt.
  */
void UART4_IRQHandler(void)
{
  /* USER CODE BEGIN UART4_IRQn 0 */

  /* USER CODE END UART4_IRQn 0 */
  HAL_UART_IRQHandler(&huart4);
  /* USER CODE BEGIN UART4_IRQn 1 */
  HAL_UART_Receive_IT(&huart4, (uint8_t *)&uart4RdChar, 1);
  /* USER CODE END UART4_IRQn 1 */
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "can.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"
#include "fmc.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
  #include "RTE_Components.h"             
  #ifdef RTE_Compiler_EventRecorder
    #include "EventRecorder.h"            
  #endif    
  #include "cmsis_os2.h"
#include "Appmain.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */


uint32_t HAL_GetTick (void) {
 static uint32_t ticks = 0U;
 uint32_t i;

 if (osKernelGetState () == osKernelRunning) {
   return ((uint32_t)osKernelGetTickCount ());
 } 
 /* If Kernel is not running wait approximately 1 ms then increment and return auxiliary tick counter value */
 for (i = (SystemCoreClock >> 14U); i > 0U; i--) { __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); }
 return ++ticks; }

 
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_FMC_Init();
  MX_CAN1_Init();
  MX_SPI4_Init();
  MX_USART1_UART_Init();
  MX_USART3_UART_Init();
  MX_UART4_Init();
  MX_SPI5_Init();
  /* USER CODE BEGIN 2 */
	// 初始化外设 开中断
	MX_SDRAM_InitEx();
	

	#ifdef RTE_Compiler_EventRecorder
    EventRecorderInitialize(EventRecordAll, 1);
  #endif    
  SystemCoreClockUpdate();
  osKernelInitialize();                 // Initialize CMSIS-RTOS
  //osThreadNew(app_main, NULL, NULL);    // Create application main thread
	Init_appMainThreadThread();
  osKernelStart(); 
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage 
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 360;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Activate the Over-Drive mode 
  */
  if (HAL_PWREx_EnableOverDrive() != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

gpio.c

/**
  ******************************************************************************
  * File Name          : gpio.c
  * Description        : This file provides code for the configuration
  *                      of all used GPIO pins.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "gpio.h"
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/*----------------------------------------------------------------------------*/
/* Configure GPIO                                                             */
/*----------------------------------------------------------------------------*/
/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/** Configure pins as 
        * Analog 
        * Input 
        * Output
        * EVENT_OUT
        * EXTI
     PB5   ------> CAN2_RX
     PB6   ------> CAN2_TX
*/
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOE_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOG_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOI_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(SPI_FLASH_CS_GPIO_Port, SPI_FLASH_CS_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, Run_Led_Pin|Status_Led_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOI, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 
                          |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);

  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = SPI_INT_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(SPI_INT_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = SPI_CS_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(SPI_CS_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = SPI_FLASH_CS_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(SPI_FLASH_CS_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : PAPin PAPin PAPin PAPin */
  GPIO_InitStruct.Pin = ID0_Pin|ID1_Pin|ID2_Pin|ID3_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PBPin PBPin */
  GPIO_InitStruct.Pin = Run_Led_Pin|Status_Led_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pins : PH6 PH7 PH8 PH9 
                           PH12 PH13 PH14 PH15 */
  GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9 
                          |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);

  /*Configure GPIO pins : PGPin PGPin PGPin PGPin */
  GPIO_InitStruct.Pin = W_BUSY_Pin|Z_BUSY_Pin|X_BUSY_Pin|Y_BUSY_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

  /*Configure GPIO pins : PI0 PI1 PI2 PI3 
                           PI4 PI5 PI6 PI7 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 
                          |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);

  /*Configure GPIO pins : PB5 PB6 */
  GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF9_CAN2;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}

/* USER CODE BEGIN 2 */

/* USER CODE END 2 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

gpio.h

/**
  ******************************************************************************
  * File Name          : gpio.h
  * Description        : This file contains all the functions prototypes for 
  *                      the gpio  
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __gpio_H
#define __gpio_H
#ifdef __cplusplus
 extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* USER CODE BEGIN Private defines */


#define	SETH(p,i)		 p->BSRR=i	 //输出为高电平		
#define CLRL(p,i)		 p->BSRR=i<<16U	 //输出低电平
#define digitalToggle(p,i) p->ODR ^=i //输出反转状态
#define INPUT(p,i)   (p->IDR & i)

#define PCD4641_CS_HIGH()    SETH(SPI_CS_GPIO_Port,SPI_CS_Pin)
#define PCD4641_CS_LOW()     CLRL(SPI_CS_GPIO_Port,SPI_CS_Pin)

/*#define BOARD_ID   HAL_GPIO_ReadPin(ID3_GPIO_Port,ID3_Pin)<<3   \
                   + HAL_GPIO_ReadPin(ID2_GPIO_Port,ID2_Pin)<<2 \
									 + HAL_GPIO_ReadPin(ID1_GPIO_Port,ID1_Pin)<<1 \
									 + HAL_GPIO_ReadPin(ID0_GPIO_Port,ID0_Pin)*/

#define BOARD_ID   (ID3_GPIO_Port->IDR & (ID3_Pin|ID2_Pin|ID1_Pin|ID0_Pin))>>4
#define DEVICE_ID   0x9

#define MOVE   (GPIOH->IDR & GPIO_PIN_6)
#define READY   (GPIOH->IDR & GPIO_PIN_7)
#define TLC     (GPIOH->IDR & GPIO_PIN_6) 
#define MOTORALARM (GPIOH->IDR & GPIO_PIN_9) 


#define SETSTART()     SETH(GPIOI,GPIO_PIN_0)
#define CLRSTART()     CLRL(GPIOI,GPIO_PIN_0)
#define CLRALLMODE()   CLRL(GPIOI,(GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3))
#define SETALLMODE()   SETH(GPIOI,(GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3))
#define SETM0()     SETH(GPIOI,GPIO_PIN_1)
#define SETM1()     SETH(GPIOI,GPIO_PIN_2)
#define CLRM0()     CLRL(GPIOI,GPIO_PIN_1)
/* USER CODE END Private defines */

void MX_GPIO_Init(void);

/* USER CODE BEGIN Prototypes */

/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif
#endif /*__ pinoutConfig_H */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

fmc.c

/**
  ******************************************************************************
  * File Name          : FMC.c
  * Description        : This file provides code for the configuration
  *                      of the FMC peripheral.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "fmc.h"

/* USER CODE BEGIN 0 */
//向SDRAM发送命令
//bankx:0,向BANK5上面的SDRAM发送指令
//      1,向BANK6上面的SDRAM发送指令
//cmd:指令(0,正常模式/1,时钟配置使能/2,预充电所有存储区/3,自动刷新/4,加载模式寄存器/5,自刷新/6,掉电)
//refresh:自刷新次数
//regval:模式寄存器的定义
//返回值:0,正常;1,失败.
uint8_t SDRAM_Send_Cmd(uint8_t bankx,uint8_t cmd,uint8_t refresh,uint16_t regval)
{
    uint32_t target_bank=0;
    FMC_SDRAM_CommandTypeDef Command;
    
    if(bankx==0) target_bank=FMC_SDRAM_CMD_TARGET_BANK1;       
    else if(bankx==1) target_bank=FMC_SDRAM_CMD_TARGET_BANK2;   
    Command.CommandMode=cmd;                //命令
    Command.CommandTarget=target_bank;      //目标SDRAM存储区域
    Command.AutoRefreshNumber=refresh;      //自刷新次数
    Command.ModeRegisterDefinition=regval;  //要写入模式寄存器的值
    if(HAL_SDRAM_SendCommand(&hsdram1,&Command,0X1000)==HAL_OK) //向SDRAM发送命令
    {
        return 0;  
    }
    else return 1;    
}


//发送SDRAM初始化序列
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram)
{
    uint32_t temp=0;
    //SDRAM控制器初始化完成以后还需要按照如下顺序初始化SDRAM
    SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_CLK_ENABLE,1,0); //时钟配置使能
    HAL_Delay(1);                                  //至少延时200us
    SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_PALL,1,0);       //对所有存储区预充电
    SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_AUTOREFRESH_MODE,8,0);//设置自刷新次数 
    //配置模式寄存器,SDRAM的bit0~bit2为指定突发访问的长度,
	  //bit3为指定突发访问的类型,bit4~bit6为CAS值,bit7和bit8为运行模式
	  //bit9为指定的写突发模式,bit10和bit11位保留位
  	temp=(uint32_t)SDRAM_MODEREG_BURST_LENGTH_1          |	//设置突发长度:1(可以是1/2/4/8)
              SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |	//设置突发类型:连续(可以是连续/交错)
              SDRAM_MODEREG_CAS_LATENCY_3           |	//设置CAS值:3(可以是2/3)
              SDRAM_MODEREG_OPERATING_MODE_STANDARD |   //设置操作模式:0,标准模式
              SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;     //设置突发写模式:1,单点访问
    SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_LOAD_MODE,1,temp);   //设置SDRAM的模式寄存器
}

void MX_SDRAM_InitEx(void)
{
	 SDRAM_Initialization_Sequence(&hsdram1);
	//刷新频率计数器(以SDCLK频率计数),计算方法:
	//COUNT=SDRAM刷新周期/行数-20=SDRAM刷新周期(us)*SDCLK频率(Mhz)/行数
    //我们使用的SDRAM刷新周期为64ms,SDCLK=180/2=90Mhz,行数为8192(2^13).
	//所以,COUNT=64*1000*90/8192-20=683
	HAL_SDRAM_ProgramRefreshRate(&hsdram1,683);//设置刷新频率
}

/* USER CODE END 0 */

SDRAM_HandleTypeDef hsdram1;

/* FMC initialization function */
void MX_FMC_Init(void)
{
  FMC_SDRAM_TimingTypeDef SdramTiming = {0};

  /** Perform the SDRAM1 memory initialization sequence
  */
  hsdram1.Instance = FMC_SDRAM_DEVICE;
  /* hsdram1.Init */
  hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
  hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
  hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
  hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
  hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
  hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
  hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
  hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
  hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
  hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1;
  /* SdramTiming */
  SdramTiming.LoadToActiveDelay = 2;
  SdramTiming.ExitSelfRefreshDelay = 8;
  SdramTiming.SelfRefreshTime = 6;
  SdramTiming.RowCycleDelay = 6;
  SdramTiming.WriteRecoveryTime = 2;
  SdramTiming.RPDelay = 2;
  SdramTiming.RCDDelay = 6;

  if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
  {
    Error_Handler( );
  }

}

static uint32_t FMC_Initialized = 0;

static void HAL_FMC_MspInit(void){
  /* USER CODE BEGIN FMC_MspInit 0 */

  /* USER CODE END FMC_MspInit 0 */
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if (FMC_Initialized) {
    return;
  }
  FMC_Initialized = 1;

  /* Peripheral clock enable */
  __HAL_RCC_FMC_CLK_ENABLE();
  
  /** FMC GPIO Configuration  
  PF0   ------> FMC_A0
  PF1   ------> FMC_A1
  PF2   ------> FMC_A2
  PF3   ------> FMC_A3
  PF4   ------> FMC_A4
  PF5   ------> FMC_A5
  PC0   ------> FMC_SDNWE
  PC2   ------> FMC_SDNE0
  PC3   ------> FMC_SDCKE0
  PF11   ------> FMC_SDNRAS
  PF12   ------> FMC_A6
  PF13   ------> FMC_A7
  PF14   ------> FMC_A8
  PF15   ------> FMC_A9
  PG0   ------> FMC_A10
  PG1   ------> FMC_A11
  PE7   ------> FMC_D4
  PE8   ------> FMC_D5
  PE9   ------> FMC_D6
  PE10   ------> FMC_D7
  PE11   ------> FMC_D8
  PE12   ------> FMC_D9
  PE13   ------> FMC_D10
  PE14   ------> FMC_D11
  PE15   ------> FMC_D12
  PD8   ------> FMC_D13
  PD9   ------> FMC_D14
  PD10   ------> FMC_D15
  PD14   ------> FMC_D0
  PD15   ------> FMC_D1
  PG2   ------> FMC_A12
  PG4   ------> FMC_BA0
  PG5   ------> FMC_BA1
  PG8   ------> FMC_SDCLK
  PD0   ------> FMC_D2
  PD1   ------> FMC_D3
  PG15   ------> FMC_SDNCAS
  PE0   ------> FMC_NBL0
  PE1   ------> FMC_NBL1
  */
  /* GPIO_InitStruct */
  GPIO_InitStruct.Pin = A0_Pin|A1_Pin|GPIO_PIN_2|GPIO_PIN_3 
                          |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_11|GPIO_PIN_12 
                          |GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;

  HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

  /* GPIO_InitStruct */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_2|GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;

  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /* GPIO_InitStruct */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4 
                          |GPIO_PIN_5|GPIO_PIN_8|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;

  HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

  /* GPIO_InitStruct */
  GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10 
                          |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14 
                          |GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;

  HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

  /* GPIO_InitStruct */
  GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_14 
                          |GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;

  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

  /* USER CODE BEGIN FMC_MspInit 1 */

  /* USER CODE END FMC_MspInit 1 */
}

void HAL_SDRAM_MspInit(SDRAM_HandleTypeDef* sdramHandle){
  /* USER CODE BEGIN SDRAM_MspInit 0 */

  /* USER CODE END SDRAM_MspInit 0 */
  HAL_FMC_MspInit();
  /* USER CODE BEGIN SDRAM_MspInit 1 */

  /* USER CODE END SDRAM_MspInit 1 */
}

static uint32_t FMC_DeInitialized = 0;

static void HAL_FMC_MspDeInit(void){
  /* USER CODE BEGIN FMC_MspDeInit 0 */

  /* USER CODE END FMC_MspDeInit 0 */
  if (FMC_DeInitialized) {
    return;
  }
  FMC_DeInitialized = 1;
  /* Peripheral clock enable */
  __HAL_RCC_FMC_CLK_DISABLE();
  
  /** FMC GPIO Configuration  
  PF0   ------> FMC_A0
  PF1   ------> FMC_A1
  PF2   ------> FMC_A2
  PF3   ------> FMC_A3
  PF4   ------> FMC_A4
  PF5   ------> FMC_A5
  PC0   ------> FMC_SDNWE
  PC2   ------> FMC_SDNE0
  PC3   ------> FMC_SDCKE0
  PF11   ------> FMC_SDNRAS
  PF12   ------> FMC_A6
  PF13   ------> FMC_A7
  PF14   ------> FMC_A8
  PF15   ------> FMC_A9
  PG0   ------> FMC_A10
  PG1   ------> FMC_A11
  PE7   ------> FMC_D4
  PE8   ------> FMC_D5
  PE9   ------> FMC_D6
  PE10   ------> FMC_D7
  PE11   ------> FMC_D8
  PE12   ------> FMC_D9
  PE13   ------> FMC_D10
  PE14   ------> FMC_D11
  PE15   ------> FMC_D12
  PD8   ------> FMC_D13
  PD9   ------> FMC_D14
  PD10   ------> FMC_D15
  PD14   ------> FMC_D0
  PD15   ------> FMC_D1
  PG2   ------> FMC_A12
  PG4   ------> FMC_BA0
  PG5   ------> FMC_BA1
  PG8   ------> FMC_SDCLK
  PD0   ------> FMC_D2
  PD1   ------> FMC_D3
  PG15   ------> FMC_SDNCAS
  PE0   ------> FMC_NBL0
  PE1   ------> FMC_NBL1
  */

  HAL_GPIO_DeInit(GPIOF, A0_Pin|A1_Pin|GPIO_PIN_2|GPIO_PIN_3 
                          |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_11|GPIO_PIN_12 
                          |GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15);

  HAL_GPIO_DeInit(GPIOC, GPIO_PIN_0|GPIO_PIN_2|GPIO_PIN_3);

  HAL_GPIO_DeInit(GPIOG, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4 
                          |GPIO_PIN_5|GPIO_PIN_8|GPIO_PIN_15);

  HAL_GPIO_DeInit(GPIOE, GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10 
                          |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14 
                          |GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1);

  HAL_GPIO_DeInit(GPIOD, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_14 
                          |GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1);

  /* USER CODE BEGIN FMC_MspDeInit 1 */

  /* USER CODE END FMC_MspDeInit 1 */
}

void HAL_SDRAM_MspDeInit(SDRAM_HandleTypeDef* sdramHandle){
  /* USER CODE BEGIN SDRAM_MspDeInit 0 */

  /* USER CODE END SDRAM_MspDeInit 0 */
  HAL_FMC_MspDeInit();
  /* USER CODE BEGIN SDRAM_MspDeInit 1 */

  /* USER CODE END SDRAM_MspDeInit 1 */
}
/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

fmc.h

/**
  ******************************************************************************
  * File Name          : FMC.h
  * Description        : This file provides code for the configuration
  *                      of the FMC peripheral.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __FMC_H
#define __FMC_H
#ifdef __cplusplus
 extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */
//SDRAM配置参数
#define SDRAM_MODEREG_BURST_LENGTH_1             ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2             ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4             ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8             ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL      ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED     ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2              ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3              ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD    ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE     ((uint16_t)0x0200)
/* USER CODE END Includes */

extern SDRAM_HandleTypeDef hsdram1;

/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

void MX_FMC_Init(void);
void HAL_SDRAM_MspInit(SDRAM_HandleTypeDef* hsdram);
void HAL_SDRAM_MspDeInit(SDRAM_HandleTypeDef* hsdram);

/* USER CODE BEGIN Prototypes */
void MX_SDRAM_InitEx(void);
/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif
#endif /*__FMC_H */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

``
usart.c

```c
/**
  ******************************************************************************
  * File Name          : USART.c
  * Description        : This file provides code for the configuration
  *                      of the USART instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */
#include "Appmain.h"

uartPack uart3_RcvData __attribute__((at(0xc0000900))); // 接受数据缓冲区 
uartPack uart3_MsgRcvBuf[uartMsgBufLength] __attribute__((at(0xc0001200))); // usart3 消息缓冲区 	
uint8_t ustart3RdChar;
uint16_t uart3_Rd_Point=0;
uint8_t uart3_RcvHead = 0;
uint16_t count=0;
uint8_t uart3_BufWr =0;

uint8_t uart4RdChar;
Message_t uart4RcvMsg;
uint8_t uart4_Rd_point = 0;

// 串口回调函数 


void HAL_UART_RxCpltCallback(UART_HandleTypeDef* uartHandle)
{
	if (uartHandle->Instance == USART3)
	{
		    count++;
		    if (ustart3RdChar == '{')
				{
					  uart3_Rd_Point = 1;
					  uart3_RcvHead = 0;
					  //uart3_RcvData.packdata[0] = ustart3RdChar;
				}
				else if (ustart3RdChar == '|' && uart3_RcvHead ==0)
				{
				    uart3_Rd_Point=2;
            //uart3_RcvData[1] = ustart3RdChar;	
            uart3_RcvHead = 1;					
				}
				else
				{
					  if (uart3_RcvHead)
            {
                if (uart3_Rd_Point<(uartBufLength-2))
								{
							      uart3_RcvData.packdata[uart3_Rd_Point-2] = ustart3RdChar;
									  if (ustart3RdChar == '}')
										{
											 if (uart3_RcvData.packdata[uart3_Rd_Point-3] == '|')
											 {
										    	 uart3_RcvData.dataLength = uart3_Rd_Point;
												   uart3_MsgRcvBuf[uart3_BufWr] = uart3_RcvData;
												   uart3_BufWr++;
												   uart3_BufWr%=uartMsgBufLength;
												   osSemaphoreRelease(uart3RcvID);
												 
											 }
											 else
											 {
												   uart3_Rd_Point = 0;
									         uart3_RcvHead = 0;
											 }
										}
										else
										{
											uart3_Rd_Point++;
										}
								}
								else
								{
									 uart3_Rd_Point = 0;
									 uart3_RcvHead = 0;
								}
						}							
				}

	}
	else if (uartHandle->Instance == UART4)
	{
		   uart4RcvMsg.buf[uart4_Rd_point] = uart4RdChar;
		   uart4_Rd_point++;
		   if (uart4_Rd_point>sizeof(uart4RcvMsg.buf)-1)
			 {
				  uart4_Rd_point = 0;   
			 }
			 if (uart4RdChar == 0x0d)
			 {
				   uart4RcvMsg.Length = uart4_Rd_point-1;
				   osMessageQueuePut(encodeQSendMsgQ,&uart4RcvMsg,0u,0u);
				   uart4_Rd_point = 0;
			 }
	}
	
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *uartHandle)
{
	  if (uartHandle->Instance == USART3)
		{
			  uint32_t isrflags   = READ_REG(uartHandle->Instance->SR);//清错误都要先读SR
			  if((__HAL_UART_GET_FLAG(uartHandle, UART_FLAG_PE))!=RESET)
        {
            READ_REG(uartHandle->Instance->DR);//PE清标志
            __HAL_UART_CLEAR_FLAG(uartHandle, UART_FLAG_PE);//清标志
        }
        if((__HAL_UART_GET_FLAG(uartHandle, UART_FLAG_FE))!=RESET)
        {
            READ_REG(uartHandle->Instance->DR);
            __HAL_UART_CLEAR_FLAG(uartHandle, UART_FLAG_FE);
        }
        
        if((__HAL_UART_GET_FLAG(uartHandle, UART_FLAG_NE))!=RESET)
        {
            READ_REG(uartHandle->Instance->DR);//NE清标志,第二步读DR
            __HAL_UART_CLEAR_FLAG(uartHandle, UART_FLAG_NE);
        }        
        
        if((__HAL_UART_GET_FLAG(uartHandle, UART_FLAG_ORE))!=RESET)
        {
            READ_REG(uartHandle->Instance->CR1);//ORE清标志,第二步读CR
            __HAL_UART_CLEAR_FLAG(uartHandle, UART_FLAG_ORE);
        }
			
			   uartHandle->RxState = HAL_UART_STATE_READY;
				 uart3_Rd_Point = 0;
				 uart3_RcvHead = 0;
         
		}
		else
		{
			
		}
}

/* USER CODE END 0 */

UART_HandleTypeDef huart4;
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart3;

/* UART4 init function */
void MX_UART4_Init(void)
{

  huart4.Instance = UART4;
  huart4.Init.BaudRate = 19200;
  huart4.Init.WordLength = UART_WORDLENGTH_8B;
  huart4.Init.StopBits = UART_STOPBITS_1;
  huart4.Init.Parity = UART_PARITY_NONE;
  huart4.Init.Mode = UART_MODE_TX_RX;
  huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart4.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart4) != HAL_OK)
  {
    Error_Handler();
  }

}
/* USART1 init function */

void MX_USART1_UART_Init(void)
{

  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }

}
/* USART3 init function */

void MX_USART3_UART_Init(void)
{

  huart3.Instance = USART3;
  huart3.Init.BaudRate = 38400;
  huart3.Init.WordLength = UART_WORDLENGTH_8B;
  huart3.Init.StopBits = UART_STOPBITS_1;
  huart3.Init.Parity = UART_PARITY_NONE;
  huart3.Init.Mode = UART_MODE_TX_RX;
  huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart3.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart3) != HAL_OK)
  {
    Error_Handler();
  }

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==UART4)
  {
  /* USER CODE BEGIN UART4_MspInit 0 */

  /* USER CODE END UART4_MspInit 0 */
    /* UART4 clock enable */
    __HAL_RCC_UART4_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**UART4 GPIO Configuration    
    PA0/WKUP     ------> UART4_TX
    PA1     ------> UART4_RX 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* UART4 interrupt Init */
    HAL_NVIC_SetPriority(UART4_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(UART4_IRQn);
  /* USER CODE BEGIN UART4_MspInit 1 */

  /* USER CODE END UART4_MspInit 1 */
  }
  else if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration    
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 1, 1);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */

  /* USER CODE END USART1_MspInit 1 */
  }
  else if(uartHandle->Instance==USART3)
  {
  /* USER CODE BEGIN USART3_MspInit 0 */

  /* USER CODE END USART3_MspInit 0 */
    /* USART3 clock enable */
    __HAL_RCC_USART3_CLK_ENABLE();
  
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**USART3 GPIO Configuration    
    PB10     ------> USART3_TX
    PB11     ------> USART3_RX 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* USART3 interrupt Init */
    HAL_NVIC_SetPriority(USART3_IRQn, 1, 0);
    HAL_NVIC_EnableIRQ(USART3_IRQn);
  /* USER CODE BEGIN USART3_MspInit 1 */
    //__HAL_UART_ENABLE_IT(uartHandle,UART_IT_RXNE); 
		
  /* USER CODE END USART3_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==UART4)
  {
  /* USER CODE BEGIN UART4_MspDeInit 0 */

  /* USER CODE END UART4_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_UART4_CLK_DISABLE();
  
    /**UART4 GPIO Configuration    
    PA0/WKUP     ------> UART4_TX
    PA1     ------> UART4_RX 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0|GPIO_PIN_1);

    /* UART4 interrupt Deinit */
    HAL_NVIC_DisableIRQ(UART4_IRQn);
  /* USER CODE BEGIN UART4_MspDeInit 1 */

  /* USER CODE END UART4_MspDeInit 1 */
  }
  else if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */

  /* USER CODE END USART1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();
  
    /**USART1 GPIO Configuration    
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

    /* USART1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspDeInit 1 */

  /* USER CODE END USART1_MspDeInit 1 */
  }
  else if(uartHandle->Instance==USART3)
  {
  /* USER CODE BEGIN USART3_MspDeInit 0 */

  /* USER CODE END USART3_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART3_CLK_DISABLE();
  
    /**USART3 GPIO Configuration    
    PB10     ------> USART3_TX
    PB11     ------> USART3_RX 
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_11);

    /* USART3 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART3_IRQn);
  /* USER CODE BEGIN USART3_MspDeInit 1 */

  /* USER CODE END USART3_MspDeInit 1 */
  }
} 

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

usart.h

/**
  ******************************************************************************
  * File Name          : USART.h
  * Description        : This file provides code for the configuration
  *                      of the USART instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __usart_H
#define __usart_H
#ifdef __cplusplus
 extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */
#include "cmsis_os2.h" 

#define uartBufLength    2046
#define uartMsgBufLength   6
/* USER CODE END Includes */

extern UART_HandleTypeDef huart4;
extern UART_HandleTypeDef huart1;
extern UART_HandleTypeDef huart3;

/* USER CODE BEGIN Private defines */
extern uint8_t ustart3RdChar;
extern uint8_t uart4RdChar;
/* USER CODE END Private defines */

void MX_UART4_Init(void);
void MX_USART1_UART_Init(void);
void MX_USART3_UART_Init(void);

/* USER CODE BEGIN Prototypes */
typedef struct
{
		 uint16_t dataLength; 						
	   uint8_t  packdata[uartBufLength];

}uartPack;

extern osSemaphoreId_t uart3RcvID;
extern uartPack uart3_MsgRcvBuf[uartMsgBufLength];
//extern uint8_t W25QXX_BUFFER[4096];
/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif
#endif /*__ usart_H */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

spi.c

/**
  ******************************************************************************
  * File Name          : SPI.c
  * Description        : This file provides code for the configuration
  *                      of the SPI instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "spi.h"

/* USER CODE BEGIN 0 */

void SPI5_SetSpeed(uint8_t SPI_BaudRatePrescaler)
{
    assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判断有效性
    __HAL_SPI_DISABLE(&hspi5);            //关闭SPI
    hspi5.Instance->CR1&=0XFFC7;          //位3-5清零,用来设置波特率
    hspi5.Instance->CR1|=SPI_BaudRatePrescaler;//设置SPI速度
    __HAL_SPI_ENABLE(&hspi5);             //使能SPI
    
}

//SPI5 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
uint8_t SPI5_ReadWriteByte(uint8_t TxData)
{
    uint8_t Rxdata;
    HAL_SPI_TransmitReceive(&hspi5,&TxData,&Rxdata,1, 1000);       
 	return Rxdata;          		    //返回收到的数据		
}


uint8_t SPI4_ReadWriteByte(uint8_t TxData)
{
    uint8_t Rxdata;
    HAL_SPI_TransmitReceive(&hspi4,&TxData,&Rxdata,1, 1000);       
 	return Rxdata;          		    //返回收到的数据		
}
/* USER CODE END 0 */

SPI_HandleTypeDef hspi4;
SPI_HandleTypeDef hspi5;

/* SPI4 init function */
void MX_SPI4_Init(void)
{

  hspi4.Instance = SPI4;
  hspi4.Init.Mode = SPI_MODE_MASTER;
  hspi4.Init.Direction = SPI_DIRECTION_2LINES;
  hspi4.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi4.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi4.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi4.Init.NSS = SPI_NSS_SOFT;
  hspi4.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
  hspi4.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi4.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi4.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi4.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi4) != HAL_OK)
  {
    Error_Handler();
  }

}
/* SPI5 init function */
void MX_SPI5_Init(void)
{

  hspi5.Instance = SPI5;
  hspi5.Init.Mode = SPI_MODE_MASTER;
  hspi5.Init.Direction = SPI_DIRECTION_2LINES;
  hspi5.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi5.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi5.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi5.Init.NSS = SPI_NSS_SOFT;
  hspi5.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi5.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi5.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi5.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi5.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi5) != HAL_OK)
  {
    Error_Handler();
  }

}

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(spiHandle->Instance==SPI4)
  {
  /* USER CODE BEGIN SPI4_MspInit 0 */

  /* USER CODE END SPI4_MspInit 0 */
    /* SPI4 clock enable */
    __HAL_RCC_SPI4_CLK_ENABLE();
  
    __HAL_RCC_GPIOE_CLK_ENABLE();
    /**SPI4 GPIO Configuration    
    PE2     ------> SPI4_SCK
    PE5     ------> SPI4_MISO
    PE6     ------> SPI4_MOSI 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_5|GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI4;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

  /* USER CODE BEGIN SPI4_MspInit 1 */

  /* USER CODE END SPI4_MspInit 1 */
  }
  else if(spiHandle->Instance==SPI5)
  {
  /* USER CODE BEGIN SPI5_MspInit 0 */

  /* USER CODE END SPI5_MspInit 0 */
    /* SPI5 clock enable */
    __HAL_RCC_SPI5_CLK_ENABLE();
  
    __HAL_RCC_GPIOF_CLK_ENABLE();
    /**SPI5 GPIO Configuration    
    PF7     ------> SPI5_SCK
    PF8     ------> SPI5_MISO
    PF9     ------> SPI5_MOSI 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI5;
    HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

  /* USER CODE BEGIN SPI5_MspInit 1 */

  /* USER CODE END SPI5_MspInit 1 */
  }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{

  if(spiHandle->Instance==SPI4)
  {
  /* USER CODE BEGIN SPI4_MspDeInit 0 */

  /* USER CODE END SPI4_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI4_CLK_DISABLE();
  
    /**SPI4 GPIO Configuration    
    PE2     ------> SPI4_SCK
    PE5     ------> SPI4_MISO
    PE6     ------> SPI4_MOSI 
    */
    HAL_GPIO_DeInit(GPIOE, GPIO_PIN_2|GPIO_PIN_5|GPIO_PIN_6);

  /* USER CODE BEGIN SPI4_MspDeInit 1 */

  /* USER CODE END SPI4_MspDeInit 1 */
  }
  else if(spiHandle->Instance==SPI5)
  {
  /* USER CODE BEGIN SPI5_MspDeInit 0 */

  /* USER CODE END SPI5_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI5_CLK_DISABLE();
  
    /**SPI5 GPIO Configuration    
    PF7     ------> SPI5_SCK
    PF8     ------> SPI5_MISO
    PF9     ------> SPI5_MOSI 
    */
    HAL_GPIO_DeInit(GPIOF, GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9);

  /* USER CODE BEGIN SPI5_MspDeInit 1 */

  /* USER CODE END SPI5_MspDeInit 1 */
  }
} 

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

spi.h

/**
  ******************************************************************************
  * File Name          : SPI.h
  * Description        : This file provides code for the configuration
  *                      of the SPI instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __spi_H
#define __spi_H
#ifdef __cplusplus
 extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

extern SPI_HandleTypeDef hspi4;
extern SPI_HandleTypeDef hspi5;

/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

void MX_SPI4_Init(void);
void MX_SPI5_Init(void);

/* USER CODE BEGIN Prototypes */
extern uint8_t SPI4_ReadWriteByte(uint8_t TxData);
extern uint8_t SPI5_ReadWriteByte(uint8_t TxData);
extern void SPI5_SetSpeed(uint8_t SPI_BaudRatePrescaler);
/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif
#endif /*__ spi_H */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

can.c

/**
  ******************************************************************************
  * File Name          : CAN.c
  * Description        : This file provides code for the configuration
  *                      of the CAN instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "can.h"

/* USER CODE BEGIN 0 */


#include "delay.h"
#include "gpio.h"
CAN_TxHeaderTypeDef     canTxMessage;      //发送消息头
CAN_RxHeaderTypeDef     canRxMessage;      //接收消息头

canPack canRcvData[canBufLength] __attribute__((at(0xc0000400))); // Can 数据缓冲区 
uint8_t  canRcv_Wr = 0;

 void CANFilterConfig_Scale32_IdMask_StandardIdOnly(void);

/****************************************************************************
  File name:      CAN.C
  Author: Wangyong      Version: 1.0        Date: 2020-04-14 
* 名称:  HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
* 功能:  CAN接收回调
* 调用者: MotorControlThread            
* 调用      
* 入口参数:CAN_HandleTypeDef *hcan
						
* 出口参数:无
****************************************************************************/

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)  
{
		uint8_t  rdData[8];
	  uint8_t  i;
		HAL_StatusTypeDef	HAL_RetVal;
		if(hcan ==&hcan1)
		{	  
				HAL_RetVal=HAL_CAN_GetRxMessage(&hcan1,  CAN_RX_FIFO0, &canRxMessage,  rdData);  
				if ( HAL_OK==HAL_RetVal)  
				{  
    					    for (i=0;i<8;i++)   
                  canRcvData[canRcv_Wr].packdata[i] = rdData[i];		
              osSemaphoreRelease(canRcvID);					
					    canRcv_Wr++;
					    canRcv_Wr%=canBufLength;
				}
			}
}

HAL_StatusTypeDef sendTxMessage(uint8_t *pData,uint8_t offset)
{
    uint32_t txMailBox;
	  uint8_t  FreeTxmailBox=0;
	  
	  HAL_StatusTypeDef	HAL_RetVal;
	  FreeTxmailBox=HAL_CAN_GetTxMailboxesFreeLevel(&hcan1);	
    while(3!=FreeTxmailBox) // 等待CAN TX MAILBOX 空闲
    {									
				osDelay(1); // CAN 故障 始终占据 线程休眠 释放总线 
			  FreeTxmailBox=HAL_CAN_GetTxMailboxesFreeLevel(&hcan1);
		}	
		HAL_RetVal =  HAL_CAN_AddTxMessage(&hcan1,&canTxMessage,pData+offset,&txMailBox);
		Delay_Us(200);
		return HAL_RetVal;
}

/****************************************************************************
  File name:      CAN.C
  Author: Wangyong      Version: 1.0        Date: 2020-04-14 
* 名称:  CAN_SendData(uint16_t ID,uint8_t *pData,uint16_t Len)
* 功能:  CAN发送数据帧
* 调用者: MotorControlThread            
* 调用      
* 入口参数:
            uint16_t ID                  帧Id号
            uint8_t *pData               数据指针
            uint16_t Len                 数据长度						
* 出口参数:0 成功 2 失败
****************************************************************************/

uint8_t CAN_SendData(uint16_t ID,uint8_t *pData,uint16_t Len)  
{  
	//HAL_StatusTypeDef	HAL_RetVal;
	//uint8_t  FreeTxNum=0;
	uint8_t tryTime;
	uint16_t SendTimes,SendCNT=0;
	//uint32_t    CAN_TX_MAILBOX;
	SendTimes=Len/8+(Len%8?1:0);
	
	//FreeTxNum=HAL_CAN_GetTxMailboxesFreeLevel(&hcan1);
	
	canTxMessage.RTR = CAN_RTR_DATA;
  canTxMessage.IDE = CAN_ID_STD;            
  canTxMessage.StdId= ID;
  canTxMessage.TransmitGlobalTime = DISABLE;
  canTxMessage.DLC = 8;
	
	while(SendTimes--)
   {		
        if(0==SendTimes)
        {			
				    if(Len%8)				
				    canTxMessage.DLC=Len%8;		
				}		
        tryTime = 0;   
        while (HAL_OK!=	sendTxMessage(pData,SendCNT) && tryTime<5) tryTime++;	
        osDelay(1);				
	      SendCNT+=8;	
	 }
   return 0;
}

/****************************************************************************
  File name:      CAN.C
  Author: Wangyong      Version: 1.0        Date: 2020-04-14 
* 名称:  CAN_Start
* 功能:  CAN发送数据帧
* 调用者: MotorControlThread            
* 调用      
* 入口参数:无					
* 出口参数:0 成功 2 失败
****************************************************************************/

uint8_t CAN_Start(void)
{
	  /*CAN_FilterTypeDef  CAN1_FilerConf;
	  CAN1_FilerConf.FilterIdHigh=0X0000;     //32位ID
    CAN1_FilerConf.FilterIdLow=0X0000;
    CAN1_FilerConf.FilterMaskIdHigh=0X0000; //32位MASK
    CAN1_FilerConf.FilterMaskIdLow=0X0000;  
    CAN1_FilerConf.FilterFIFOAssignment=CAN_FILTER_FIFO0;//过滤器0关联到FIFO0
    CAN1_FilerConf.FilterBank=0;          //过滤器0
    CAN1_FilerConf.FilterMode=CAN_FILTERMODE_IDMASK;
    CAN1_FilerConf.FilterScale=CAN_FILTERSCALE_32BIT;
    CAN1_FilerConf.FilterActivation=ENABLE; //激活滤波器0
    CAN1_FilerConf.SlaveStartFilterBank=14;
	
    if(HAL_CAN_ConfigFilter(&hcan1,&CAN1_FilerConf)!=HAL_OK) return 2;//滤波器初始化*/
	  CANFilterConfig_Scale32_IdMask_StandardIdOnly();
	  // 启动 CAN
	  HAL_CAN_Start(&hcan1);
	  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
    return 0;
}

/****************************************************************************
  File name:      CAN.C
  Author: Wangyong      Version: 1.0        Date: 2020-04-14 
* 名称:  CANFilterConfig_Scale32_IdMask_StandardIdOnly(void) 
* 功能:  标准帧32位掩码配置 CAN1
* 调用者: MotorControlThread            
* 调用      
* 入口参数:无					
* 出口参数:无
****************************************************************************/

 void CANFilterConfig_Scale32_IdMask_StandardIdOnly(void)  
{  
  CAN_FilterTypeDef   sFilterConfig;  
  /*uint16_t StdIdArray[10] ={0x7e0,0x7e1,0x7e2,0x7e3,0x7e4,  
                                0x7e5,0x7e6,0x7e7,0x7e8,0x7e9}; //定义一组标准CAN ID  */
  //uint16_t      mask,num,tmp,i;  
  uint16_t  StdId = (DEVICE_ID<<4)|BOARD_ID;  
  sFilterConfig.FilterBank = 0;               //使用过滤器0  
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;     //配置为掩码模式  
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;    //设置为32位宽  
  //sFilterConfig.FilterIdHigh =(StdIdArray[0]<<5);       //使用StdIdArray[0]作为验证码 
  //sFilterConfig.FilterIdLow =0;	
  sFilterConfig.FilterIdHigh =((int32_t)StdId<<21&0xffff0000)>>16;
	sFilterConfig.FilterIdLow =((int32_t)StdId<<21)|CAN_ID_STD|CAN_RTR_DATA;  
    
  /*mask =0x7ff;                      //下面开始计算屏蔽码  
  num =sizeof(StdIdArray)/sizeof(StdIdArray[0]);  
  for(i =0; i<num; i++)      //屏蔽码位StdIdArray[]数组中所有成员的同或结果  
  {  
    tmp =StdIdArray[i] ^ (~StdIdArray[0]);  //所有数组成员与第0个成员进行同或操作  
    mask &=tmp;  
  }  
  sFilterConfig.FilterMaskIdHigh =(mask<<5);  
  sFilterConfig.FilterMaskIdLow =0|0x02;        //只接收数据帧  */
	
	sFilterConfig.FilterMaskIdHigh =0xffff;  
  sFilterConfig.FilterMaskIdLow =0xffff;        
    
  sFilterConfig.FilterFIFOAssignment = 0;       //设置通过的数据帧进入到FIFO0中  
  sFilterConfig.FilterActivation = ENABLE;  
  sFilterConfig.SlaveStartFilterBank = 14;  
    
  if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)  
  {  
    Error_Handler();  
  }  
} 

/****************************************************************************
  File name:      CAN.C
  Author: Wangyong      Version: 1.0        Date: 2020-04-14 
* 名称:  CANFilterConfig_Scale16_IdList(void) 
* 功能:  标准帧16位列表配置 CAN1
* 调用者: MotorControlThread            
* 调用      
* 入口参数:无					
* 出口参数:无
****************************************************************************/

static void CANFilterConfig_Scale16_IdList(void)  
{  
  CAN_FilterTypeDef  sFilterConfig;   
    
  sFilterConfig.FilterBank = 0;               //使用过滤器0  
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;     //设为列表模式  
  sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;    //位宽设置为16位  
  sFilterConfig.FilterIdHigh = BOARD_ID<<5;  //4个标准CAN ID分别放入到4个存储中  
  sFilterConfig.FilterIdLow = (BOARD_ID|0x1)<<5;  
  sFilterConfig.FilterMaskIdHigh = (BOARD_ID|0x2)<<5;  
  sFilterConfig.FilterMaskIdLow = (BOARD_ID|0x3)<<5;  
  sFilterConfig.FilterFIFOAssignment = 0;           //接收到的报文放入到FIFO0中  
  sFilterConfig.FilterActivation = ENABLE;  
  sFilterConfig.SlaveStartFilterBank = 14;  
    
  if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)  
  {  
    Error_Handler();  
  }  
} 

/* USER CODE END 0 */

CAN_HandleTypeDef hcan1;

/* CAN1 init function */
void MX_CAN1_Init(void)
{

  hcan1.Instance = CAN1;
  hcan1.Init.Prescaler = 6;
  hcan1.Init.Mode = CAN_MODE_NORMAL;
  hcan1.Init.SyncJumpWidth = CAN_SJW_3TQ;
  hcan1.Init.TimeSeg1 = CAN_BS1_11TQ;
  hcan1.Init.TimeSeg2 = CAN_BS2_3TQ;
  hcan1.Init.TimeTriggeredMode = DISABLE;
  hcan1.Init.AutoBusOff = ENABLE;
  hcan1.Init.AutoWakeUp = DISABLE;
  hcan1.Init.AutoRetransmission = ENABLE;
  hcan1.Init.ReceiveFifoLocked = DISABLE;
  hcan1.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan1) != HAL_OK)
  {
    Error_Handler();
  }

}

void HAL_CAN_MspInit(CAN_HandleTypeDef* canHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(canHandle->Instance==CAN1)
  {
  /* USER CODE BEGIN CAN1_MspInit 0 */

  /* USER CODE END CAN1_MspInit 0 */
    /* CAN1 clock enable */
    __HAL_RCC_CAN1_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**CAN1 GPIO Configuration    
    PA11     ------> CAN1_RX
    PA12     ------> CAN1_TX 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* CAN1 interrupt Init */
    HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
  /* USER CODE BEGIN CAN1_MspInit 1 */

  /* USER CODE END CAN1_MspInit 1 */
  }
}

void HAL_CAN_MspDeInit(CAN_HandleTypeDef* canHandle)
{

  if(canHandle->Instance==CAN1)
  {
  /* USER CODE BEGIN CAN1_MspDeInit 0 */

  /* USER CODE END CAN1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_CAN1_CLK_DISABLE();
  
    /**CAN1 GPIO Configuration    
    PA11     ------> CAN1_RX
    PA12     ------> CAN1_TX 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);

    /* CAN1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn);
  /* USER CODE BEGIN CAN1_MspDeInit 1 */

  /* USER CODE END CAN1_MspDeInit 1 */
  }
} 

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

can.h

/**
  ******************************************************************************
  * File Name          : CAN.h
  * Description        : This file provides code for the configuration
  *                      of the CAN instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __can_H
#define __can_H
#ifdef __cplusplus
 extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */
#include "cmsis_os2.h" 

#define canBufLength  32

typedef struct
{
		 CAN_RxHeaderTypeDef packHead; 						
	   uint8_t packdata[8];

}canPack;

extern CAN_HandleTypeDef hcan1;
extern CAN_TxHeaderTypeDef     canTxMessage;      //发送消息头
extern CAN_RxHeaderTypeDef     canRxMessage;      //接收消息头
extern osSemaphoreId_t canRcvID;

/* USER CODE END Includes */

extern CAN_HandleTypeDef hcan1;

/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

void MX_CAN1_Init(void);

/* USER CODE BEGIN Prototypes */

extern uint8_t CAN_Start(void);
extern uint8_t CAN_SendData(uint16_t ID,uint8_t *pData,uint16_t Len);
extern canPack canRcvData[canBufLength]; // Can 数据缓冲区 
/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif
#endif /*__ can_H */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值