FreeRTOS项目(2)摇杆按键检测

发布于:2025-09-09 ⋅ 阅读:(24) ⋅ 点赞:(0)

PS:最近一个多月以来一直在赶工作上的项目,最近才抽空把摇杆的文章补完。。。

        在上一章我们准备好了一个模板,一个骨架,今天我们在学习如何在FreeRTOS上读取摇杆的方位。

目录

模块简介

代码实现

ADC初始化

 ADC转换值获取

按键(Z轴)检测

main.c

执行效果


模块简介

下图为本人所使用的模块。

        如图所示,这个模块有五个引脚,分别是电源、GND、X轴、Y轴 和 Z轴(SW)。

        电源方面,虽然标注了5V,但是3.3V一般就能驱动,如果3.3V带不动的情况下再改接5V。

        模块X轴和Y轴采用的是ADC模拟量检测,而按下摇杆所触发Z轴的是数字量,即高低电平。我把按下摇杆作为确定键来使用。

代码实现

ADC初始化

        因为程序是通过RTOS调度运行的,所以在这里省去了中断的相关配置。其次为了使用灵活,通道转换顺序放在其他位置定义了。

void ADCx_Config(void)
{
	ADC_GPIO_APBxClock_FUN ( ADC_GPIO_CLK, ENABLE );
	ADC_APBxClock_FUN ( ADC_CLK, ENABLE );
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6); 
	
	GPIO_InitTypeDef GPIO_InitStructure;
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = ROCKERBAR_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	GPIO_Init(ADC_PORT, &GPIO_InitStructure);				

	ADC_InitTypeDef ADC_InitStructure;
	//独立模式
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	//扫描模式:关
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	//连续转换模式:关 
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	//右对齐
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	//转换通道数量:1个
	ADC_InitStructure.ADC_NbrOfChannel = 1;	
	//外部触发源:无,软件自动触发
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_Init(ADC1, &ADC_InitStructure);
	ADC_Cmd(ADC1, ENABLE);
	//初始化校准寄存器并等待初始化完成
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);
	//开启校准并等待校准完成
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1) == SET);
	
}

 ADC转换值获取

        基于上述的初始化操作,我们只需要控制ADC的转换通道就能实现任意通道的ADC值获取。因此,下面的函数实现了根据通道来单次转换ADC值的功能。

uint16_t adc_value;

uint16_t AD_GetValue(uint8_t ADC_Channel)
{
	//配置ADC的转换顺序和采样时间
	ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);
	//软件触发转换
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	//等待转换完成标志位置位并返回转换值
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
	return ADC_GetConversionValue(ADC1);
}

按键(Z轴)检测

        通过前面的ADC我们就能获取摇杆四个方向的输入,Z轴实际上就是按下按键,因此我们需要一个按键检测函数。

        首先是GPIO初始化。

void Key_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK|KEY2_GPIO_CLK,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN; 

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 
	
	GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = KEY2_GPIO_PIN; 
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 
	GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);	
}

        然后是按键检测函数。

uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{			
	if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON )  
	{	 
		while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);   
		return 	KEY_ON;	 
	}
	else
		return KEY_OFF;
}

        到这一步,外设的配置工作基本就完成了,接下来就是添加到实现逻辑里。

main.c

        首先在硬件初始化函数Hardware_Config()中加入ADC和按键的初始化。

        以下为摇杆检测任务。

        该任务的功能就是每1000ms(1s)检测一次摇杆操作,并将摇杆操作状态通过串口打印。四个方向和按下在同一时刻只能存在一种情况。

void RockerBar_Task(void * param)
{
    uint8_t confirm_flag = 0;
    while(1)
    {
        XValue = AD_GetValue(ADC_Value1);
        YValue = AD_GetValue(ADC_Value2);

        if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3) == 0)
		{
			confirm_flag = 1;
		}

        if(confirm_flag == 1)
        {
            printf("Confirm\r\n");
        }
        else if(((XValue >= 2000) && (XValue <= 2200)) && ((YValue >= 2000) && (YValue <= 2200)) && (confirm_flag == 0)
        {
            printf("No change in position\r\n");
        }
        else if(((XValue >= 0) && (XValue <= 10)) && ((YValue >= 2000) && (YValue <= 2200)))
        {
            printf("Left\r\n");
        }
        else if(((XValue >= 4000) && (XValue <= 4100)) && ((YValue >= 2000) && (YValue <= 2200)))
        {
            printf("Right\r\n");
        }
        else if(((XValue >= 2000) && (XValue <= 2200)) && ((YValue >= 4000) && (YValue <= 4100)))
		{
            printf("Front\r\n");
        }
		else if(((XValue >= 2000) && (XValue <= 2200)) && ((YValue >= 0) && (YValue <= 10)))
        {
            printf("Back\r\n");
        }
		vTaskDelay(1000);
    }
}

        上述判断值为本人实际测试过的值,由于范围较小所以偏一点就可能检测失败,建议检测区间增加200左右用起来更舒服。方向也可以根据自己的实际需求取修改,我这里的方向可能不准,只是为了验证功能。

        最后将摇杆任务加入任务创建函数。

static TaskHandle_t RockerBar_Handle = NULL;

void RockerBar_Task(void * param);

xTaskCreate((TaskFunction_t )RockerBar_Task, /* 任务入口函数 */
                        (const char*    )"RockerBar_Task",/* 任务名字 */
                        (uint16_t       )256,   /* 任务栈大小 */
                        (void*          )NULL,	/* 任务入口函数参数 */
                        (UBaseType_t    )2,	    /* 任务的优先级 */
                        (TaskHandle_t*  )&RockerBar_Handle);/* 任务控制块指针 */

        到这里为止,摇杆按键就配置完成啦。接下来让我们看靠实际效果。

执行效果

        效果非常完美!!

        在下一章,我们将OLED加入这个项目中,敬请期待!


网站公告

今日签到

点亮在社区的每一天
去签到