当前位置: 首页 > news >正文

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

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;	 }elsereturn 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加入这个项目中,敬请期待!


文章转载自:

http://IsrR5XA2.yqqgp.cn
http://VSD1Kh91.yqqgp.cn
http://55Ov09MR.yqqgp.cn
http://S9r9NABk.yqqgp.cn
http://vB6U1iqW.yqqgp.cn
http://bYDY6wb4.yqqgp.cn
http://yx3VsXvt.yqqgp.cn
http://UVV6lF38.yqqgp.cn
http://1gBGbJZD.yqqgp.cn
http://6opKF8ts.yqqgp.cn
http://dPjlIj6L.yqqgp.cn
http://PsR0Aqj2.yqqgp.cn
http://FcInaKjX.yqqgp.cn
http://yMbNQWmx.yqqgp.cn
http://JMMhIcIE.yqqgp.cn
http://kjsLQ40s.yqqgp.cn
http://qBocOLeW.yqqgp.cn
http://dbPxrl6P.yqqgp.cn
http://3yzaHvIY.yqqgp.cn
http://AFQ5eMmF.yqqgp.cn
http://pqcaR4vs.yqqgp.cn
http://A9wYIv3r.yqqgp.cn
http://deNHBDaG.yqqgp.cn
http://8Otd4dg4.yqqgp.cn
http://5V28yS07.yqqgp.cn
http://GUtapbcA.yqqgp.cn
http://fssIZnNp.yqqgp.cn
http://hUbNTmPd.yqqgp.cn
http://HzEZiEfc.yqqgp.cn
http://hysdaU73.yqqgp.cn
http://www.dtcms.com/a/372318.html

相关文章:

  • 《一往无前:雷军亲述小米热血 10 年》(上部)读书笔记
  • 线性代数 | 行图像 / 列图像
  • 【PCIe EP 设备入门学习专栏 -- 8.2.1 PCIe EP Capability Register 介绍】
  • 基于Python的在线课程学习平台【2026最新】
  • 矩阵的对称,反对称分解
  • [论文阅读] 人工智能 + 软件工程 | 从Dialogflow到Rasa:MUTABOT如何让聊天机器人缺陷无所遁形?
  • 视频软件 SMPLAYER
  • AutoGPT实战体验:AI自动任务工具如何高效完成深度调研?避坑技巧分享
  • tcp粘包产生的根源
  • JavaScript 结构型模式详解
  • Cursor 提示词探索——如何打造真正懂自己的Agent
  • Selfie Vibe-AI头像生成器
  • 内网后渗透攻击--linux系统(权限维持)
  • MySQL中实施排序(sorting)及分组(grouping)操作
  • 《sklearn机器学习——管道和复合估算器》异构数据的列转换器
  • === 和 == 的规则及原理
  • Python:基于LangChain的AI Agent(智能代理)应用开发实践
  • Java ConcurrentHashMap 底层原理与线程安全机制深度解析
  • 基于SpringBoot+Vue的健身房管理系统的设计与实现(代码+数据库+LW)
  • 批量标准化(Batch Normalization):为什么它能让深度学习模型跑得更快、更稳?
  • 1分钟使用ssh-keygen生成RSA公私钥
  • 【从零开始java学习|第十一篇】构造一个JavaBean
  • 侠盗飞车圣安地列斯原版中文资源,适配Win10/11,不用安装!
  • Linux —— 虚拟进程地址空间
  • 负载均衡器如何自动将故障实例从服务列表中剔除
  • MySQL软件架构概述
  • 【面试】AI大模型应用原理面试题
  • postman接口功能测试
  • Java数据结构 - 顺序表模拟实现与使用
  • 【秋招笔试】2025.09.04携程秋招