基于STM32F407 ADC双通道 PS2游戏机摇杆ADC采集
基于STM32F407 ADC双通道 PS2游戏机摇杆ADC采集
- 一、PS2游戏机摇杆概述
- 1.1PS2游戏机摇杆概述
- 1.2PS2游戏机摇杆图解
- 二、硬件连接分析
- 三、代码实现
- 3.1 ADC代码
- 3.1 定时器
- 3.2 主函数
- 四、实验效果分析
一、PS2游戏机摇杆概述
1.1PS2游戏机摇杆概述
摇杆一般在航模中的无人机、电玩、遥控车、云台等设备上应用广泛,很多带有屏幕的设备也经常使用摇杆作为菜单选择的输入控制。
PS2游戏双轴摇杆传感器模块由采用原装优质金属PS2摇杆电位器制作,具有2轴(X,Y)模拟输出,1路(Z)按钮数字输出。
原理:摇杆为一个双向十字的10K电阻器。模块使用5V供电,原始状态下X、Y读出电压约为2.5V,当摇杆往某个方向推动,输出的相应轴电压值增加或减小,大值5V,小值0V。
1、工作电压:5V
2、输出电压范围:0~5V
3、接口:两路模拟信号代表X、Y偏移量,一路数字信号SW代表Z轴是否按下
1.2PS2游戏机摇杆图解
(1)SW:标识符为摇杆按下时触发,引脚电平为高低电平变化,但是我通过万用表进行测量时,没有电平变化,且引脚电平是不通过的,不知道是不是买的这个模块有问题,在编程过程中其实也不难,加个中断即可。(2)VRY:输出Y轴电压变化范围:0~3.3V 或 0~5V ;电压范围取决于+5V标识的连接方式
(3)VRX:输出Y轴电压变化范围:0~3.3V 或 0~5V;电压范围取决于+5V标识的连接方式
(4)GND:接电源地即可
(5)+5V:这个是接电压的,虽然写着+5V,但是也可以接3.3V(如果接3.3V, X轴与Y轴的电压变化范围:0~3.3V),由于STM32F407 ADC的参考电压为3.3V,所以此引脚接3.3V
X、Y转电压增量变化如图
二、硬件连接分析
由于X、Y轴输出的是电压可变的量,且有两个ADC需要同时进行采集,故将采用ADC的双通道进行设计,通过查找手册,确定使用ADC1 通道2及通道3
由于需要进行快速的响应采集速度,故使用DMA的方式进行转换的方式,通过查找手册知道ADC1与DMA的关系为
三、代码实现
3.1 ADC代码
adc.c
#include "adc.h"//用于存储PA2 PA3的ADC值
__IO uint16_t aADCDualConvertedValue[2];/*************************************
硬件说明
PA2 -- ADC123_IN2
PA3 -- ADC123_IN3选用ADC1*************************************/void ADC_PA2_PA3_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;ADC_CommonInitTypeDef ADC_CommonInitStructure;ADC_InitTypeDef ADC_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC1时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3; //引脚2 3GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; //模拟模式GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //浮空GPIO_Init(GPIOA, &GPIO_InitStructure);复位ADC寄存器RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE); //reset adcRCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE); //end reset adcADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; //独立模式ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //这是混合ADC才使用的模式,这里由于是独立模式,选择参数ADC_DMAAccessMode_DisabledADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz ADC_CommonInit(&ADC_CommonInitStructure);//初始化ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; //12位模式ADC_InitStructure.ADC_ScanConvMode = ENABLE; //扫描模式 多通道采集需要ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转换ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止触发检测,使用软件触发
// ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_CC1; //禁止硬件触发,些值可以不用填写ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐 ADC_InitStructure.ADC_NbrOfConversion = 2;//2个转换在规则序列中ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化// 配置 ADC 通道转换顺序和采样时间周期ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_15Cycles ); //ADC1,ADC通道,480个周期,提高采样时间可以提高精确度 ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 2, ADC_SampleTime_28Cycles ); //ADC1,ADC通道,480个周期,提高采样时间可以提高精确度 // 使能 DMA 请求 after last transfer (Single-ADC mode)ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);//使能 ADC DMAADC_DMACmd(ADC1, ENABLE);//ADC_ExternalTrigConvCmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE);//开启AD转换器 }void DMA_Config(void)
{DMA_InitTypeDef DMA_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);DMA_InitStructure.DMA_Channel = DMA_Channel_0; //选择 DMA 通道,通道存在于流中0中DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR); //数据源在ADC1->DR中DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)aADCDualConvertedValue;//数据目的地在aADCDualConvertedValue数组DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//数据传输方向为外设到存储器DMA_InitStructure.DMA_BufferSize = 2; //与通道数设置一致DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设寄存器只有一个,地址不用递增DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 存储器地址固定DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 外设数据大小为半字,即两个字节DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord; // 存储器数据大小也为半字,跟外设数据大小相同DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循环传输模式DMA_InitStructure.DMA_Priority = DMA_Priority_High; // DMA 传输通道优先级为高,当使用一个 DMA 通道时,优先级设置不影响DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; // 禁止 DMA FIFO ,使用直连模式// FIFO 大小, FIFO 模式禁止时,这个不用配置DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;DMA_Init(DMA2_Stream0, &DMA_InitStructure);//使能 DMA 流DMA_Cmd(DMA2_Stream0, ENABLE);}
adc.h
#ifndef __ADC_H
#define __ADC_H#include "stm32f4xx.h"void ADC_PA2_PA3_Init(void);
void DMA_Config(void);#endif
3.1 定时器
在这里,我选择每隔1S采集ADC的值,如果在项目中需要快速采集,则减少定时器中断即可
tim.c
#include "tim.h"/*********************************************
功能说明:
TIM3 -- APB1 -- 16位定时器(65535)
TIM3时钟频率: APB1*2 = 42*2 = 84MHZ
**********************************************/void Tim3_Init(void)
{NVIC_InitTypeDef NVIC_InitStruct;TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;// 1、使能定时器时钟。RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);TIM_TimeBaseInitStruct.TIM_Prescaler = 8400-1; //8400分频 84000 000HZ/84000 = 10000HZTIM_TimeBaseInitStruct.TIM_Period = 10000-1; //计10000个数,用时1sTIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上计数TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //分频因子// 2、初始化定时器,配置ARR,PSC。TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct); NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn; //中断通道 ,在stm32f4xx.hNVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; //响应优先级NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //中断通道使能 // 3、启定时器中断,配置NVIC。NVIC_Init(&NVIC_InitStruct);// 4、设置 TIM3_DIER 允许更新中断TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);// 5、使能定时器。TIM_Cmd(TIM3, ENABLE);}
tim.h
#ifndef __TIM_H
#define __TIM_H#include "stm32f4xx.h"void Tim3_Init(void);#endif
3.2 主函数
#include "stm32f4xx.h"
#include "adc.h"
#include "delay.h"
#include "usart.h"
#include "tim.h"//用于存储PA2 PA3的ADC值
extern __IO uint16_t aADCDualConvertedValue[2];
unsigned int adcVal,adcVal01,adcVal02;
char msgstr[64];int main(void)
{//设置系统中断优先级分组2NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);Delay_Init();Usart1_Init(115200);ADC_PA2_PA3_Init();DMA_Config(); //1S产生一次中断,在中断获取ADC数据Tim3_Init();//开始 adc 转换,软件触发ADC_SoftwareStartConv(ADC1);while(1){delay_s(1);//延时200ms};return 0;
}// 6、编写中断服务函数。
void TIM3_IRQHandler(void)
{if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET){printf("While Run...\r\n");adcVal01= aADCDualConvertedValue[0]; adcVal02= aADCDualConvertedValue[1]; printf("X轴电压:%f, Y轴电压:%f\r\n", (adcVal01/4095.0)*3.3 , (adcVal02/4095.0)*3.3);sprintf(msgstr,"PA2 ch2=%d PA3 ch3=%d\r\n",adcVal01,adcVal02); printf(msgstr); printf("\r\n");}//清除中断线0标志位TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
四、实验效果分析
将程序下载到开发板后,打开串口,通过摇杆,即可改变不同的电压
单个的PS游戏摇杆就写到这里了。两个摇杆的话,写成四通道即可。源码链接:https://download.csdn.net/download/wwwqqq2014/85309506?spm=1001.2014.3001.5503
基于STM32F407 ADC双通道 PS2游戏机摇杆ADC采集相关推荐
- ADC模数转换器(基于STM32F407)
简介 Analog-to-digital converters(模拟数字转换器),我的STM32F407中内置3个ADC,每个 ADC 有 12 位.10 位.8 位和 6 位可选,ADC 具有独立模 ...
- 基于STM32F407使用ADC采集电压实验
核心板:STM32F407 实验目的:使用ADC采集电压值将其打印在串口助手上 目录 ADC简介 STM32F407 ADC通道对应的引脚 STM32F407中的数据寄存器 ADC 规则数据寄存器 ( ...
- STM32F103+NRF2401+游戏摇杆ADC双单片机通信遥控小车
STM32F103+NRF2401+游戏摇杆ADC双单片机通信遥控小车 文章目录 STM32F103+NRF2401+游戏摇杆ADC双单片机通信遥控小车 前言 一.实现的功能? 二.主要代码及模块讲解 ...
- STM32F4时钟触发ADC双通道采样DMA传输进行FFT+测频率+采样频率可变+显示波形(详细解读)...
此文转载自:https://blog.csdn.net/qq_45620831/article/details/110819495 写在前面的婆婆妈妈的话 本人大三,参加过数次电赛,来CSDN好久, ...
- STM32F4时钟触发ADC双通道采样DMA传输进行FFT+测频率+采样频率可变+显示波形(详细解读)
写在前面的婆婆妈妈的话(代码链接在最下方) 本人大三,参加过数次电赛,来CSDN好久, 每次都是在绝望中从这里找到了希望,每次都仿佛一个即将被怪兽打翻的小船突然被危险流浪者救起来.是众多前辈的智慧,让 ...
- 基于STM32F103C8T6的高速DMA传输多通道ADC数据
文章目录 前言 一.软件设计思路 二.代码 总结 前言 ADC在STM32系列单片机的使用中占用着很大的比例,常见的案例是通过ADC单次转换电压值,这种方式的缺陷在于转换效率不高.一般的单片机带有AD ...
- STM32 PS2游戏摇杆 测试
PS2游戏摇杆有3个输出口,按照手册应该是2个模拟输出(XY),1个数字输出(Z),因此用stm32的ADC进行测试. PS2 原理图: ADC配置: 代码: MX_ADC1_Init(); HAL_ ...
- ps2摇杆android图形编程,ROC-RK3308-CC开发实例总结--PS2 Joystick摇杆模块
本帖最后由 Demon 于 2019-4-8 17:58 编辑 最近本人又调试了一款比较有趣的传感器模块--PS2 Joystick摇杆模块.下面将本人的测试方法分享于大家,下文仅个人见解,若有不足 ...
- EC20模组使用MQTT库对接EMQX,基于STM32F407
一.说明 本lib库基于STM32F407编译,其他的cortexM4内核也支持,采用串口和EC20模组通信. 库包括两个文件:ec20_mqtt.h和ec20_mqtt.lib.使用时添加lib文件 ...
最新文章
- 大数据分布式集群搭建(9)
- Python入门100题 | 第080题
- Qomolangma实现篇(四):基本特性增强与多投事件系统
- java在画布上画出变量_急..JAVA 在画布上画拖动滚动条可扩大缩小的长方形
- 什么是document对象?如何获取文档对象上的元素?_dom对象
- ubuntu 14.04 LTS(64bit) Anaconda2 + Theano(1.0.2) + Keras安装
- 人本原理内涵_叶澜教育学原理课后答案资料配套题库考研真题精选课后习题章节题库...
- 牛客练习赛23: D. 托米的咒语(暴力)
- 2017年杭州java面试题_2017年Java面试题整理
- vue学习-处理边界-依赖注入
- Cadence学习笔记
- 数据科学、机器学习和数据挖掘的差异
- 《图解密码技术》笔记
- R:基于每股权益的量化分析 —— PEG估值法
- 爬取招聘信息并进行数据分析及可视化
- mac电脑键盘失灵怎么办
- dbpedia知识图谱java_中文通用百科知识图谱(CN-DBpedia)
- 2021年美国大学生数学建模竞赛(题目详细介绍)
- 8421码,5421码,2421码,余3码特点及转换
- pd_to_datetime将时间戳转换日期格式,日期不正确
热门文章
- Android激活设备管理器--一键锁屏
- 北京钢铁学校计算机99,首钢工学院
- AD18创建Class
- slam 基础 之概率基础
- Vans携手洛杉矶现代艺术博物馆推出联名系列;关晓彤代言艾莱依羽绒服 | 知消...
- Windows 10 系统自带搜索功能详解
- oracle创建app_profile,Oracle PUP(PRODUCT_USER_PROFILE)配置和使用
- 深入浅出CChart 每日一课——快乐高四第五十课 新石器时代,轻装上阵之EasyX窗口绘图
- vs提示出现“xxx.exe中已触发了一个断点”错误的解决办法
- 如何解决在加载、保存或覆盖项目文件时 Lumion 可能无法打开或显示错误的问题?