本帖最后由 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 ;
}
编译下载,对摇杆进行不同方向的操作,看串口输出:
这样我们的摇杆就能正常控制了,里游戏移植又近了一步了。
|