打印
[IDE]

【RISC-V MCU CH32V103测评】+摇杆驱动程序

[复制链接]
506|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 qjp1988113 于 2020-11-30 09:52 编辑

今天我们来调试一下摇杆,想以前打街机时,摇杆可是很爽的存在。估计也就80,90小时候会玩这玩意,00后的估计都很少见。
不废话了。摇杆其实就是2个电位器加一个按键的集合体。我这有现成的摇杆模块,引出5个引脚:GND VCC VRX(x方向判断) VRY(y方向判断) SW(Z方向判断)。
X,Y方向输出电位器对应的ADC值,Z方向仅0或1与按键类似。
好,我们开始程序搭建:
引脚定义:
ADCCH1-->PB0          (joy_y)
ADCCH2-->PB1          (joy_x)
GPIO_intput-->PB3     (joy_z)

joy.h:(我们之前调试过2路ADC,此时正好派上用处了)
#ifndef JOY_H_
#define JOY_H_

#include "adc_timtrig.h"
//定义判断的按键值
#define UP         0
#define DOWN       1
#define LEFT       2
#define RIGHT      3
#define LEFT_UP    4
#define LEFT_DOWN  5
#define RIGHT_UP   6
#define RIGHT_DONW 7
#define ENTER      8
#define UNKNOW_KEY 99

//Z-->PB3
#define JOY_Z_Value    GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3)

extern u16  JOY_X, JOY_Y, JOY_Z ;

void JOY_GPIO_Init(void);
void GET_KEY_Basedata(void);
uint8_t GET_KEY_VALUE(int x, int y, int z);


#endif /* JOY_H_ */
joy.c:
/*
* joy.c
*
*  Created on: Nov 27, 2020
*      Author: Administrator
*/

#include "joy.h"
#include "debug.h"


//保存转换计算后的电压值
float ADC_VOL_VALUE[2];
//最终值
u16  JOY_X, JOY_Y, JOY_Z ;

//GPIO初始化,主要是Z PB3
void JOY_GPIO_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //内部上拉

    GPIO_Init(GPIOB, &GPIO_InitStructure);

}

//获取摇杆X,Y对应的ADC值   Z输入状态0或1
//X-->PB0   Y-->PB1 Z-->PB3(按键仅0或1)
void GET_KEY_Basedata(void)
{
    //3.3V位AD转换的参考电压值,STM32的AD转换为12bit,所以2^12=4096
   //故当输入参考电压为3.3V时,AD转换的结果为4096
   //取12bit数值
    Get_Adc_Average(1);
    //printf("X is :%d ,Y is :%d ",ADC_DATA[0],ADC_DATA[1]);
    ADC_VOL_VALUE[0]= (float)(ADC_DATA[0] & 0xFFF) * 3.3 / 4096 ;
    ADC_VOL_VALUE[1]= (float)(ADC_DATA[0] & 0xFFF) * 3.3 / 4096 ;
    //printf("x:%.2fv   y:%.2fv\n", ADC_VOL_VALUE[0], ADC_VOL_VALUE[1]);
    //只取高8位有效数据
    JOY_X = ADC_DATA[0]>>4;
    JOY_Y = ADC_DATA[1]>>4;
    JOY_Z = JOY_Z_Value;

}

//获取摇杆键值
uint8_t GET_KEY_VALUE(int x, int y, int z)
{
    if((0 == x) && (y > 100 && y < 255))
        return RIGHT;//TEST
    else if((255 == x) && (y > 0 && y < 255))
        return LEFT ;//TEST
    else if((x > 0 && x < 255) && (255 == y))
        return DOWN ;//TEST
    else if((x > 0 && x < 255) && (0 == y))
        return UP ;//TEST
    else if((0 == x) && (255 == y))
        return RIGHT_DONW ;//
    else if((255 == x) && (255 == y))
        return LEFT_DOWN ;
    else if((0 == x) && (0 == y))
        return RIGHT_UP ;
    else if((255 == x) && (0 == y))
        return LEFT_UP ;//
    else if(x > 0 && y > 0 && 0 == z)
        return ENTER ;

    return UNKNOW_KEY ;
}
ADC相关的文件:
ADC.H
/*
* adc_timtrig.h
*
*  Created on: Nov 21, 2020
*      Author: Administrator
*/

#ifndef ADC_TIMTRIG_H_
#define ADC_TIMTRIG_H_

#include "ch32v10x.h"

//PB0-->ADC_IN8
//PB1-->ADC_IN9
extern u16 tmpadcbuf[2];
extern u16 ADC_DATA[2];

void ADC_Function_Init(void);
void TIM1_PWM_In( u16 arr, u16 psc, u16 ccp );
u16* GetADC(void);
u16* Get_Adc_Average(u8 times);

#endif /* ADC_TIMTRIG_H_ */
ADC.C
/*
* adc_timtrig.c
*
*  Created on: Nov 21, 2020
*      Author: Administrator
*/

#include "adc_timtrig.h"
#include "debug.h"


u16 tmpadcbuf[2]={0};
u16 ADC_DATA[2]={0};
/*******************************************************************************
* Function Name  : ADC_Function_Init
* Description    : Initializes ADC collection.
* Input          : None
* Return         : None
*******************************************************************************/
void ADC_Function_Init(void)
{
    ADC_InitTypeDef ADC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE );
    RCC_ADCCLKConfig(RCC_PCLK2_Div8);
    //PB0-->AD_IN8
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    //PB1-->AD_IN9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    ADC_DeInit(ADC1);
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigInjecConv_T1_CC4;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 2;
    ADC_Init(ADC1, &ADC_InitStructure);

    ADC_InjectedSequencerLengthConfig(ADC1, 2);
    ADC_InjectedChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_239Cycles5);
    ADC_InjectedChannelConfig(ADC1, ADC_Channel_9, 2, ADC_SampleTime_239Cycles5);

    ADC_DiscModeChannelCountConfig( ADC1, 1);
    ADC_InjectedDiscModeCmd(ADC1 , ENABLE);
    ADC_ExternalTrigInjectedConvCmd(ADC1, ENABLE);
    ADC_Cmd(ADC1, ENABLE);

    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));
}

/*******************************************************************************
* Function Name  : TIM1_PWM_In
* Description    : Initializes TIM1 PWM output.
* Input          : arr: the period value.
*                  psc: the prescaler value.
*                                    ccp: the pulse value.
* Return         : None
*******************************************************************************/
void TIM1_PWM_In( u16 arr, u16 psc, u16 ccp )
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;

    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE );

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init( GPIOA, &GPIO_InitStructure);

    TIM_TimeBaseInitStructure.TIM_Period = arr;
    TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit( TIM1, &TIM_TimeBaseInitStructure);

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = ccp;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OC4Init( TIM1, &TIM_OCInitStructure );

    TIM_CtrlPWMOutputs(TIM1, ENABLE );
    TIM_OC4PreloadConfig( TIM1, TIM_OCPreload_Disable );
    TIM_ARRPreloadConfig( TIM1, ENABLE );
    TIM_SelectOutputTrigger( TIM1, TIM_TRGOSource_Update );
    TIM_Cmd( TIM1, ENABLE );
}


u16* GetADC(void)
{

    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));
    ADC_ClearFlag( ADC1, ADC_FLAG_EOC);
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_JEOC ));
    ADC_ClearFlag( ADC1, ADC_FLAG_JEOC);

    tmpadcbuf[0]=ADC1->IDATAR1;
    tmpadcbuf[1]=ADC1->IDATAR2;

    return tmpadcbuf;
}

u16* Get_Adc_Average(u8 times)
{
    u32 temp_val[2]={0,0};
    u8 t;
    for(t=0;t<times;t++)
    {
        GetADC();
        temp_val[0]+=tmpadcbuf[0];
        temp_val[1]+=tmpadcbuf[1];
        Delay_Ms(5);
    }
    ADC_DATA[0]=temp_val[0]/times;
    ADC_DATA[1]=temp_val[1]/times;

    return ADC_DATA;
}
在main.c初始化JOY相关引脚:
 ADC_Function_Init();
TIM1_PWM_In( 1000, 48000-1, 500 );
JOY_GPIO_Init();
在while里面查询。判断键值方向,并串口打印出:
 GET_KEY_Basedata();
        key_value = GET_KEY_VALUE(JOY_X, JOY_Y, JOY_Z);
        printf("x:%d   y:%d  z:%d\n", JOY_X,JOY_Y,JOY_Z);

        switch(key_value)
        {
            case UP :
                printf("UP\n");
                break ;

            case DOWN :
                printf("DOWN\n");
                break ;

            case LEFT :
                printf("LEFT\n");
                break ;

            case RIGHT  :
                printf("RIGHT\n");
                break ;

            case LEFT_UP:
                printf("LEFT_UP\n");
                break ;

            case LEFT_DOWN:
                printf("LEFT_DOWN\n");
                break ;

            case RIGHT_UP:
                printf("RIGHT_UP\n");
                break ;

            case RIGHT_DONW :
                printf("RIGHT_DONW\n");
                break ;

            case ENTER :
                printf("ENTER\n");
                break ;

            default:
                break ;
        }
编译下载,对摇杆进行不同方向的操作,看串口输出:
这样我们的摇杆就能正常控制了,里游戏移植又近了一步了。





使用特权

评论回复

相关帖子

沙发
w494143467| | 2020-11-30 15:14 | 只看该作者
大学玩小车的时候用的就是摇杆控制小车。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

111

主题

627

帖子

2

粉丝