STM32
直播中

山中老虎

8年用户 921经验值
擅长:制造/封装
私信 关注
[问答]

如何利用STM32F4 PS2手柄去移植HAL库呢

如何利用STM32F4 PS2手柄去移植HAL库呢?如何利用Cube对其进行设置呢?

回帖(2)

于敏

2021-11-30 15:14:59
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控制功能
//具体实现思想,参考<>第五章(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
拉姆轮的底盘代码
举报

李叱镡

2021-11-30 15:15:08
//
//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
#include
#include
#include
#include
#include


#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                         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
  *
  *

© Copyright (c) 2019 STMicroelectronics.
  * All rights reserved.


  *
  * 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 rn",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 %drn", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */


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


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

更多回帖

发帖
×
20
完善资料,
赚取积分