用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)
blank

相关推荐

  • Android 低功耗蓝牙开发

    Android 低功耗蓝牙开发初识低功耗蓝牙Android4.3(APILevel18)开始引入BluetoothLowEnergy(BLE,低功耗蓝牙)的核心功能并提供了相应的API,应用程序通过这些API扫描蓝牙设备、查询services、读写设备的characteristics(属性特征)等操作。AndroidBLE使用的蓝牙协议是GATT协议,有关该协议的详细内容可以参见蓝牙官方文…

  • 图片加载失败的正确处理[通俗易懂]

    图片加载失败的正确处理[通俗易懂]<imgsrc=”http://imgsrc.baidu.com/forum/pic/item/fd1f4134970a304e16d3176ad3c8a786c8175ca8.jpg”/>对于这样一段代码来讲,如果该图片加载成功,那么界面上会显示图片,如果由于一些原因导致图片加载失败,会出现这样的图标。在正常的项目中,标签的src是后端返回的路径,如果图片加载不出来,显示上…

  • php avc,什么是AVC编码?简述H.264概念和发展

    php avc,什么是AVC编码?简述H.264概念和发展频编解码技术有两套标准,国际电联(ITU-T)的标准H.261、H.263、H.263+等;还有ISO的MPEG标准Mpeg1、Mpeg2、Mpeg4等等。H.264/AVC是两大组织集合H.263+和Mpeg4的优点联合推出的最新标准,最具价值的部分无疑是更高的数据压缩比。在同等的图像质量条件下,H.264的数据压缩比能比H.263高2倍,比MPEG-4高1.5倍。以下我们简单介绍H.264的…

  • 深圳有哪些不错的互联网公司_深圳好公司推荐

    深圳有哪些不错的互联网公司_深圳好公司推荐深圳作为一个一线城市,改革开放已经40余年了,即使如此,栈长觉得深圳现在也还是一个非常年轻的城市,不断吸引着大批外省务工人员。深圳不仅是一个包容度很高的城市,也是一个互联网公司扎堆的城市,今天栈

  • python 入门学习—模块导入三种方式及中文凝视

    python 入门学习—模块导入三种方式及中文凝视

  • GB28181协议_gb28181版本

    GB28181协议_gb28181版本国家为了规范安防行业的设备平台互联互通,在2012年出台了GB/T-28181的第一版标准:这个版本我13年在工作中开发IPC设备使用过,当时觉得协议对流媒体的规范还是比较好(H.264+G711封装成PS流,再经过RTP协议进行实时传输),但是控制方面有很多不足,相对于当前流行的ONVIF协议在控制信令上还是有很多不足。去公安…

    2022年10月21日

发表回复

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

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