用cube移植PS2手柄–HAL库[通俗易懂]

用cube移植PS2手柄–HAL库[通俗易懂]用cube移植PS2手柄–HAL库STM32F4PS2手柄移植HAL库,利用Cube进行设置请按以下步骤进行配置GPIOD0inputD1outputD2outputD3output详见下图然后配置工程文件生成格式生成MDK文件并用keil打开下载下面链接的文件并开始移植将文件内的delay.csys.cps2.cmisc.c进…

大家好,又见面了,我是你们的朋友全栈君。

用cube移植PS2手柄–HAL库

STM32F4 PS2手柄移植HAL库,利用Cube进行设置

请按以下步骤进行

选择芯片
时钟配置
在这里插入图片描述
在这里插入图片描述
配置GPIO

D0 input
D1 output
D2 output
D3 output

详见下图
在这里插入图片描述
然后配置工程文件生成格式
在这里插入图片描述
在这里插入图片描述
生成MDK文件并用keil打开
下载下面链接的文件并开始移植

将文件内的delay.c sys.c ps2.c misc.c 进行移植
移植过程如下:

1.将delay.c sys.c ps2.c misc.c 四个文件放置在cube生成的MDK-ARM文件夹内; 2…将delay.h sys.h ps2.h misc.h 四个文件放置在cube生成的Inc文件夹
3. 在keil里面填入这几个.c文件
在这里插入图片描述
4.编译即可通过
在这里插入图片描述
code:

// ps2.c
#include "stm32f4xx_hal.h"
#include "misc.h"
#include "ps2.h"
#include "gpio.h"

#define DELAY_TIME  delay_us(5); 

volatile int PS2_LX,PS2_LY,PS2_RX,PS2_RY,PS2_KEY;     //
uint16_t Handkey;
uint8_t Comd[2]={ 
   0x01,0x42};	//开始命令。请求数据
uint8_t Data[9]={ 
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};//数据存储数组
uint16_t MASK[]={ 
   
    PSB_SELECT,
    PSB_L3,
    PSB_R3 ,
    PSB_START,
    PSB_PAD_UP,
    PSB_PAD_RIGHT,
    PSB_PAD_DOWN,
    PSB_PAD_LEFT,
    PSB_L2,
    PSB_R2,
    PSB_L1,
    PSB_R1 ,
    PSB_GREEN,
    PSB_RED,
    PSB_BLUE,
    PSB_PINK
	};	//按键值与按键明

	
	//向手柄发送命令
void PS2_Cmd(uint8_t CMD)
{ 
   
	volatile uint16_t ref=0x01;
	Data[1] = 0;
	for(ref=0x01;ref<0x0100;ref<<=1)
	{ 
   
		if(ref&CMD)
		{ 
   
			DO_H;                   //输出一位控制位
		}
		else DO_L;

		CLK_H;                        //时钟拉高
		DELAY_TIME;
		CLK_L;
		DELAY_TIME;
		CLK_H;
		if(DI)
			Data[1] = ref|Data[1];
	}
	delay_us(16);
}

//判断是否为红灯模式 0x41=模拟绿灯 0x73=模拟红灯
//返回值;0,红灯模式
// 其他,其他模式
uint8_t PS2_RedLight(void)
{ 
   
	CS_L;
	PS2_Cmd(Comd[0]);  //开始命令
	PS2_Cmd(Comd[1]);  //请求数据
	CS_H;
	if( Data[1] == 0X73)   return 0 ;
	else return 1;

}

//读取手柄数据
void PS2_ReadData(void)
{ 
   
	volatile uint8_t byte=0;
	volatile uint16_t ref=0x01;
	CS_L;
	PS2_Cmd(Comd[0]);  //开始命令
	PS2_Cmd(Comd[1]);  //请求数据
	for(byte=2;byte<9;byte++)          //开始接受数据
	{ 
   
		for(ref=0x01;ref<0x100;ref<<=1)
		{ 
   
			CLK_H;
			DELAY_TIME;
			CLK_L;
			DELAY_TIME;
			CLK_H;
		      if(DI)
		      Data[byte] = ref|Data[byte];
		}
        delay_us(16);
	}
	CS_H;
}

//对读出来的PS2的数据进行处理 只处理了按键部分 默认数据是红灯模式 只有一个按键按下时
//按下为0, 未按下为1
uint8_t PS2_DataKey()
{ 
   
	uint8_t index;

	PS2_ClearData();
	PS2_ReadData();

	Handkey=(Data[4]<<8)|Data[3];     //这是16个按键 按下为0, 未按下为1
	for(index=0;index<16;index++)
	{ 
   	    
		if((Handkey&(1<<(MASK[index]-1)))==0)
		return index+1;
	}
	return 0;          //没有任何按键按下
}

//得到一个摇杆的模拟量 范围0~256
uint8_t PS2_AnologData(uint8_t button)
{ 
   
	return Data[button];
}

//清除数据缓冲区
void PS2_ClearData()
{ 
   
	uint8_t a;
	for(a=0;a<9;a++)
		Data[a]=0x00;
}

//void delay_init(uint8_t SYSCLK)
//{ 
   
// SysTick->CTRL&=0xfffffffb;//bit2清空,选择外部时钟 HCLK/8
// fac_us=SYSCLK/8;
//}

//void delay_us(uint32_t nus)
//{ 
// uint32_t temp; 
// SysTick->LOAD=nus*fac_us; //时间加载 
// SysTick->VAL=0x00; //清空计数器
// SysTick->CTRL=0x01 ; //开始倒数 
// do
// { 
   
// temp=SysTick->CTRL;
// }
// while(temp&0x01&&!(temp&(1<<16)));//等待时间到达 
// SysTick->CTRL=0x00; //关闭计数器
// SysTick->VAL =0X00; //清空计数器 
//}

//short poll
void PS2_ShortPoll(void)
{ 
   
	CS_L;
	delay_us(16);
	PS2_Cmd(0x01);  
	PS2_Cmd(0x42);  
	PS2_Cmd(0X00);
	PS2_Cmd(0x00);
	PS2_Cmd(0x00);
	CS_H;
	delay_us(16);	
}

//进入设置
void PS2_EnterConfing(void)
{ 
   
    CS_L;
	delay_us(16);
	PS2_Cmd(0x01);  
	PS2_Cmd(0x43);  
	PS2_Cmd(0X00);
	PS2_Cmd(0x01);
	PS2_Cmd(0x00);
	PS2_Cmd(0X00);
	PS2_Cmd(0X00);
	PS2_Cmd(0X00);
	PS2_Cmd(0X00);
	CS_H;
	delay_us(16);
}

//发送模式设置
void PS2_TurnOnAnalogMode(void)
{ 
   
	CS_L;
	PS2_Cmd(0x01);  
	PS2_Cmd(0x44);  
	PS2_Cmd(0X00);
	PS2_Cmd(0x01); //analog=0x01;digital=0x00 软件设置发送模式
	PS2_Cmd(0x03); //Ox03锁存设置,即不可通过按键“MODE”设置模式。
				   //0xEE不锁存软件设置,可通过按键“MODE”设置模式。
	PS2_Cmd(0X00);
	PS2_Cmd(0X00);
	PS2_Cmd(0X00);
	PS2_Cmd(0X00);
	CS_H;
	delay_us(16);
}

//振动设置
void PS2_VibrationMode(void)
{ 
   
	CS_L;
	delay_us(16);
	PS2_Cmd(0x01);  
	PS2_Cmd(0x4D);  
	PS2_Cmd(0X00);
	PS2_Cmd(0x00);
	PS2_Cmd(0X01);
	CS_H;
	delay_us(16);	
}


//完成并保存配置
void PS2_ExitConfing(void)
{ 
   
  CS_L;
	delay_us(16);
	PS2_Cmd(0x01);  
	PS2_Cmd(0x43);  
	PS2_Cmd(0X00);
	PS2_Cmd(0x00);
	PS2_Cmd(0x5A);
	PS2_Cmd(0x5A);
	PS2_Cmd(0x5A);
	PS2_Cmd(0x5A);
	PS2_Cmd(0x5A);
	CS_H;
	delay_us(16);
}

//手柄配置初始化
void PS2_SetInit(void)
{ 
   
	PS2_ShortPoll();
	PS2_ShortPoll();
	PS2_ShortPoll();
	PS2_EnterConfing();		//进入配置模式
	PS2_TurnOnAnalogMode();	//“红绿灯”配置模式,并选择是否保存
	//PS2_VibrationMode(); //开启震动模式
	PS2_ExitConfing();		//完成并保存配置
}

/****************************************************** Function: void PS2_Vibration(u8 motor1, u8 motor2) Description: 手柄震动函数, Calls: void PS2_Cmd(u8 CMD); Input: motor1:右侧小震动电机 0x00关,其他开 motor2:左侧大震动电机 0x40~0xFF 电机开,值越大 震动越大 ******************************************************/
void PS2_Vibration(uint8_t motor1, uint8_t motor2)
{ 
   
	CS_L;
	delay_us(16);
    PS2_Cmd(0x01);  //开始命令
	PS2_Cmd(0x42);  //请求数据
	PS2_Cmd(0X00);
	PS2_Cmd(motor1);
	PS2_Cmd(motor2);
	PS2_Cmd(0X00);
	PS2_Cmd(0X00);
	PS2_Cmd(0X00);
	PS2_Cmd(0X00);
	CS_H;
	delay_us(16);  
}

//读取手柄信息
void PS2_Receive (void)
{ 
   
		PS2_LX=PS2_AnologData(PSS_LX);
		PS2_LY=PS2_AnologData(PSS_LY);
		PS2_RX=PS2_AnologData(PSS_RX);
		PS2_RY=PS2_AnologData(PSS_RY);
		PS2_KEY=PS2_DataKey();
}
// ps2.h
#ifndef __PS2_H__
#define __PS2_H__

#include "stm32f4xx_hal.h"
#include "sys.h"

#define DI PDin(0)

#define DO_H PDout(1)=1
#define DO_L PDout(1)=0

#define CS_H PDout(2)=1 
#define CS_L PDout(2)=0

#define CLK_H PDout(3)=1 
#define CLK_L PDout(3)=0 


//These are our button constants
#define PSB_SELECT      1
#define PSB_L3          2
#define PSB_R3          3
#define PSB_START       4
#define PSB_PAD_UP      5
#define PSB_PAD_RIGHT   6
#define PSB_PAD_DOWN    7
#define PSB_PAD_LEFT    8
#define PSB_L2         9
#define PSB_R2          10
#define PSB_L1          11
#define PSB_R1          12
#define PSB_GREEN       13
#define PSB_RED         14
#define PSB_BLUE        15
#define PSB_PINK        16
#define PSB_TRIANGLE    13
#define PSB_CIRCLE      14
#define PSB_CROSS       15
#define PSB_SQUARE      26

//These are stick values
#define PSS_RX 5                //右摇杆X轴数据
#define PSS_RY 6
#define PSS_LX 7
#define PSS_LY 8

extern uint8_t Data[9];
extern uint16_t MASK[16];
extern uint16_t Handkey;

void PS2_Init(void);
uint8_t PS2_RedLight(void);//判断是否为红灯模式
void PS2_ReadData(void);
void PS2_Cmd(uint8_t CMD);		  //
uint8_t PS2_DataKey(void);		  //键值读取
uint8_t PS2_AnologData(uint8_t button); //得到一个摇杆的模拟量
void PS2_ClearData(void);	  //清除数据缓冲区
void delay_init(uint8_t SYSCLK);
void delay_us(uint32_t nus);

void PS2_ShortPoll(void);//short poll
void PS2_EnterConfing(void);//进入设置
void PS2_TurnOnAnalogMode(void);//保存并完成设置
void PS2_VibrationMode(void);
void PS2_ExitConfing(void);//保存并完成设置
void PS2_SetInit(void);//手柄设置初始化
void PS2_Vibration(uint8_t motor1 ,uint8_t motor2);

#endif
;
// sys.c
#include "sys.h"  
// 

//********************************************************************************
//修改说明
//无
// 


//THUMB指令不支持汇编内联
//采用如下方法实现执行汇编指令WFI 
__asm void WFI_SET(void)
{ 
   
	WFI;		  
}
//关闭所有中断(但是不包括fault和NMI中断)
__asm void INTX_DISABLE(void)
{ 
   
	CPSID   I
	BX      LR	  
}
//开启所有中断
__asm void INTX_ENABLE(void)
{ 
   
	CPSIE   I
	BX      LR  
}
//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(uint32_t	addr) 
{ 
   
	MSR MSP, r0 			//set Main Stack value
	BX r14
}
// ps2.h
#ifndef __SYS_H
#define __SYS_H	 
#include "stm32f4xx.h" 
#include "delay.h"
#include "ps2.h"
#define SYSTEM_SUPPORT_OS		0		//定义系统文件夹是否支持UCOS
extern volatile int PS2_LX,PS2_LY,PS2_RX,PS2_RY,PS2_KEY;

//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).M4同M3类似,只是寄存器地址变了.
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414 
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814 
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14 
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014 

#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 
// 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //输出 
#define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //输入

#define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  //输出 
#define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  //输入

//以下为汇编函数
void WFI_SET(void);		//执行WFI指令
void INTX_DISABLE(void);//关闭所有中断
void INTX_ENABLE(void);	//开启所有中断
void MSR_MSP(uint32_t addr);	//设置堆栈地址 
#include <string.h> 
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#endif
// misc.c
#include "stm32f4xx_hal.h"
#include "misc.h"

/* Cortex M3 Delay functions */

static __IO uint32_t TimingDelay = 0;

void Delay(__IO uint32_t nTime)
{ 
   
    TimingDelay = nTime;

    while(TimingDelay != 0);
}

void TimingDelay_Decrement(void)
{ 
   
    if (TimingDelay != 0x00) { 
   
        TimingDelay--;
    }
}

/* STM32F10x TIM helper functions */

TIM_Direction TIM_ReadDirection(TIM_TypeDef* TIMx)
{ 
   
    return (TIMx->CR1 & TIM_CR1_DIR);
}

void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
{ 
   
  /* Check the parameters */
  assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
  if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
  { 
   
    SysTick->CTRL |= SysTick_CLKSource_HCLK;
  }
  else
  { 
   
    SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
  }

}

// misc.h
#ifndef __STM32F10X_MISC_H__
#define __STM32F10X_MISC_H__

#include "stm32f4xx_hal.h"

/* Cortex M3 bit banding macros */

#define BITBAND_SRAM_REF   0x20000000
#define BITBAND_SRAM_BASE  0x22000000
#define BITBAND_SRAM(ptr,n) ((volatile uint32_t*)((BITBAND_SRAM_BASE + \
                                (((uint32_t)ptr)-BITBAND_SRAM_REF)*32 + (n*4))))
#define BITBAND_PERI_REF   0x40000000
#define BITBAND_PERI_BASE  0x42000000
#define BITBAND_PERI(ptr,n) ((volatile uint32_t*)((BITBAND_PERI_BASE + \
                                (((uint32_t)ptr)-BITBAND_PERI_REF)*32 + (n*4))))
          
#define SysTick_CLKSource_HCLK_Div8    ((uint32_t)0xFFFFFFFB)
#define SysTick_CLKSource_HCLK         ((uint32_t)0x00000004)

/* Cortex M3 Delay functions */
void TimingDelay_Decrement(void);
void Delay(__IO uint32_t nTime);
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);

/* STM32F10x GPIO helper functions */

#define GPIO_ToggleBit(port, pin) GPIO_WriteBit(port, pin, \
                            (BitAction) (1-GPIO_ReadOutputDataBit(port, pin)))

/* STM32F10x TIM helper functions */

typedef enum { 
   UP = 0, DOWN = 1} TIM_Direction;

TIM_Direction TIM_ReadDirection(TIM_TypeDef* TIMx);

#endif

// delay.c
#include "delay.h"
#include "misc.h"
#include "sys.h"
// 
//如果使用OS,则包括下面的头文件(以ucos为例)即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h"					//支持OS时,使用 
#endif

// 

static uint8_t  fac_us=0;							//us延时倍乘数 
static uint16_t fac_ms=0;							//ms延时倍乘数,在os下,代表每个节拍的ms数
	
#if SYSTEM_SUPPORT_OS							//如果SYSTEM_SUPPORT_OS定义了,说明要支持OS了(不限于UCOS).

#ifdef 	OS_CRITICAL_METHOD						//OS_CRITICAL_METHOD定义了,说明要支持UCOSII 
#define delay_osrunning		OSRunning			//OS是否运行标记,0,不运行;1,在运行
#define delay_ostickspersec	OS_TICKS_PER_SEC	//OS时钟节拍,即每秒调度次数
#define delay_osintnesting 	OSIntNesting		//中断嵌套级别,即中断嵌套次数
#endif

//支持UCOSIII
#ifdef 	CPU_CFG_CRITICAL_METHOD					//CPU_CFG_CRITICAL_METHOD定义了,说明要支持UCOSIII 
#define delay_osrunning		OSRunning			//OS是否运行标记,0,不运行;1,在运行
#define delay_ostickspersec	OSCfg_TickRate_Hz	//OS时钟节拍,即每秒调度次数
#define delay_osintnesting 	OSIntNestingCtr		//中断嵌套级别,即中断嵌套次数
#endif


//us级延时时,关闭任务调度(防止打断us级延迟)
void delay_osschedlock(void)
{ 
   
#ifdef CPU_CFG_CRITICAL_METHOD   			//使用UCOSIII
	OS_ERR err; 
	OSSchedLock(&err);						//UCOSIII的方式,禁止调度,防止打断us延时
#else										//否则UCOSII
	OSSchedLock();							//UCOSII的方式,禁止调度,防止打断us延时
#endif
}

//us级延时时,恢复任务调度
void delay_osschedunlock(void)
{ 
   	
#ifdef CPU_CFG_CRITICAL_METHOD   			//使用UCOSIII
	OS_ERR err; 
	OSSchedUnlock(&err);					//UCOSIII的方式,恢复调度
#else										//否则UCOSII
	OSSchedUnlock();						//UCOSII的方式,恢复调度
#endif
}

//调用OS自带的延时函数延时
//ticks:延时的节拍数
void delay_ostimedly(u32 ticks)
{ 
   
#ifdef CPU_CFG_CRITICAL_METHOD
	OS_ERR err; 
	OSTimeDly(ticks,OS_OPT_TIME_PERIODIC,&err);//UCOSIII延时采用周期模式
#else
	OSTimeDly(ticks);						//UCOSII延时
#endif 
}
 
//systick中断服务函数,使用OS时用到
void SysTick_Handler(void)
{ 
   	
	if(delay_osrunning==1)					//OS开始跑了,才执行正常的调度处理
	{ 
   
		OSIntEnter();						//进入中断
		OSTimeTick();       				//调用ucos的时钟服务程序 
		OSIntExit();       	 				//触发任务切换软中断
	}
}
#endif
			   
//初始化延迟函数
//当使用OS的时候,此函数会初始化OS的时钟节拍
//SYSTICK的时钟固定为AHB时钟的1/8
//SYSCLK:系统时钟频率
void delay_init(uint8_t SYSCLK)
{ 
   
#if SYSTEM_SUPPORT_OS 						//如果需要支持OS.
	u32 reload;
#endif
 	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); 
	fac_us=SYSCLK/8;						//不论是否使用OS,fac_us都需要使用
#if SYSTEM_SUPPORT_OS 						//如果需要支持OS.
	reload=SYSCLK/8;						//每秒钟的计数次数 单位为M 
	reload*=1000000/delay_ostickspersec;	//根据delay_ostickspersec设定溢出时间
											//reload为24位寄存器,最大值:16777216,在168M下,约合0.7989s左右 
	fac_ms=1000/delay_ostickspersec;		//代表OS可以延时的最少单位 
	SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;   	//开启SYSTICK中断
	SysTick->LOAD=reload; 					//每1/delay_ostickspersec秒中断一次 
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; 	//开启SYSTICK 
#else
	fac_ms=(uint16_t)fac_us*1000;				//非OS下,代表每个ms需要的systick时钟数 
#endif
}								    

#if SYSTEM_SUPPORT_OS 						//如果需要支持OS.
//延时nus
//nus:要延时的us数. 
//nus:0~204522252(最大值即2^32/fac_us@fac_us=21) 
void delay_us(u32 nus)
{ 
   		
	u32 ticks;
	u32 told,tnow,tcnt=0;
	u32 reload=SysTick->LOAD;				//LOAD的值 
	ticks=nus*fac_us; 						//需要的节拍数 
	delay_osschedlock();					//阻止OS调度,防止打断us延时
	told=SysTick->VAL;        				//刚进入时的计数器值
	while(1)
	{ 
   
		tnow=SysTick->VAL;	
		if(tnow!=told)
		{ 
   	    
			if(tnow<told)tcnt+=told-tnow;	//这里注意一下SYSTICK是一个递减的计数器就可以了.
			else tcnt+=reload-tnow+told;	    
			told=tnow;
			if(tcnt>=ticks)break;			//时间超过/等于要延迟的时间,则退出.
		}  
	};
	delay_osschedunlock();					//恢复OS调度 
}  
//延时nms
//nms:要延时的ms数
//nms:0~65535
void delay_ms(u16 nms)
{ 
   	
	if(delay_osrunning&&delay_osintnesting==0)//如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度) 
	{ 
   		 
		if(nms>=fac_ms)						//延时的时间大于OS的最少时间周期 
		{ 
    
   			delay_ostimedly(nms/fac_ms);	//OS延时
		}
		nms%=fac_ms;						//OS已经无法提供这么小的延时了,采用普通方式延时 
	}
	delay_us((u32)(nms*1000));				//普通方式延时
}
#else  //不用ucos时
//延时nus
//nus为要延时的us数. 
//注意:nus的值,不要大于798915us(最大值即2^24/fac_us@fac_us=21)
void delay_us(uint32_t nus)
{ 
   		
	uint32_t temp;	    	 
	SysTick->LOAD=nus*fac_us; 				//时间加载 
	SysTick->VAL=0x00;        				//清空计数器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 
	do
	{ 
   
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));	//等待时间到达 
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
	SysTick->VAL =0X00;       				//清空计数器 
}
//延时nms
//注意nms的范围
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK单位为Hz,nms单位为ms
//对168M条件下,nms<=798ms 
void delay_xms(uint16_t nms)
{ 
   	 		  	  
	uint32_t temp;		   
	SysTick->LOAD=(uint32_t)nms*fac_ms;			//时间加载(SysTick->LOAD为24bit)
	SysTick->VAL =0x00;           			//清空计数器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;          //开始倒数 
	do
	{ 
   
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));	//等待时间到达 
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;       //关闭计数器
	SysTick->VAL =0X00;     		  		//清空计数器 
} 
//延时nms 
//nms:0~65535
void delay_ms(uint16_t nms)
{ 
   	 	 
	uint8_t repeat=nms/540;						//这里用540,是考虑到某些客户可能超频使用,
											//比如超频到248M的时候,delay_xms最大只能延时541ms左右了
	uint16_t remain=nms%540;
	while(repeat)
	{ 
   
		delay_xms(540);
		repeat--;
	}
	if(remain)delay_xms(remain);
} 
#endif

// delay.h
#ifndef __DELAY_H
#define __DELAY_H 		
#include "misc.h"
// 
void delay_init(uint8_t SYSCLK);
void delay_ms(uint16_t nms);
void delay_us(uint32_t nus);

#endif

// main.c
/* USER CODE BEGIN Header */
/** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * <h2><center>&copy; Copyright (c) 2019 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 "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "ps2.h"
#include "sys.h"
#include "delay.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 */
/* 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();
  /* USER CODE BEGIN 2 */
	delay_init(168);
	PS2_SetInit();
	delay_ms(500);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	
	
  while (1)
  { 
   
    /* USER CODE END WHILE */
		   	PS2_LX=PS2_AnologData(PSS_LX);    
			PS2_LY=PS2_AnologData(PSS_LY);
			PS2_RX=PS2_AnologData(PSS_RX);
			PS2_RY=PS2_AnologData(PSS_RY);
			PS2_KEY=PS2_DataKey();	
			printf("PS2_LX:%d ",PS2_LX);
			printf("PS2_LY:%d ",PS2_LY);
		  printf("PS2_RX:%d ",PS2_RX);
			printf("PS2_RY:%d ",PS2_RY);
			printf("PS2_KEY:%d \r\n",PS2_KEY);
			delay_ms(100);
    /* 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 = 4;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != 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****/

如何使用摇杆和按键就需要读者自己去探索了
博主所使用的摇杆是控制麦克拉姆轮底片运动
下次会更新ps2手柄控制麦克拉姆轮的底盘代码

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/133475.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 微信小程序带参数跳转页面(小程序跳转第三方网页)

    //wxml&lt;textwx:for="{{titles}}"wx:key="{{index}}"bindtap=’changeClassify’data-id="{{index}}"&gt;{{item.name}}&lt;/text&gt;//jsfunctionchangeClassify(e){//letid=e.currentTarget.da…

  • Vue生命周期钩子(三)「建议收藏」

    Vue生命周期钩子(三)「建议收藏」Vue生命周期图Vue中共有11个生命周期函数,本文只说明8个生命周期钩子beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好data和methods属性created:实例已经在内存中创建完毕,此时 data 和 methods 已经创建完毕,此时还没有开始编译模板beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中…

  • 一、智能车舵机控制

    一、智能车舵机控制前言:本文章主要是近期有关舵机知识的总结,将分别从舵机的控制原理,控制流程和代码实现流程几个方面作简要介绍,由于时间紧急,难免有疏漏错误之处,欢迎留言指正,QQ:2046890259一、多级的控制原理:我们本次智能车使用的舵机是通过PWM进行控制。而PWM几个重要的参数就是最大值,最小值和占空比。其中占空比决定了舵机的旋转角度,如下图所示:不同的占空比控制不同的角度。而我们的目的就是通过…

  • 关于博客背景_好看的博客背景图

    关于博客背景_好看的博客背景图目前从事nuclear工程设计工作,基本与编程无关行业。但因为读研期间主要从事编程开发相关研究,所以有所涉猎,主要为C++、ZIGbee、RFID、STM32相关工作,但是基础知识较为欠缺。想通过博客的方式督促自身的学习。博客内容主要集中在机器学习和软件编程相关,虽然之前有过嵌入式、单片机的软硬件设计经验,但是相对学习成本高昂,不适合现在业余自学,所以目前专注于计算机软件编程知识。与君共勉,2

    2022年10月10日
  • Bootstrap FileInput中文API整理[通俗易懂]

    Bootstrap FileInput中文API整理[通俗易懂]BootstrapFileInput中文API整理这段时间做项目用到bootstrapfileinput插件上传文件,在用的过程中,网上能查到的api都不是很全,所以想着整理一份比较详细的文档,方便自己今后使用,也希望能给大家带来帮助,如有错误,希望大家积极指正。一、    引入文件&lt;linkhref="../css/bootstrap.min.css"rel="style…

  • Vagrant系列(二)—-Vagrant的配置文件Vagrantfile详解

    Vagrant系列(二)—-Vagrant的配置文件Vagrantfile详解

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号