原文链接:https://www.cnblogs.com/zitech/p/5033851.html

实验使用如下所示的双轴按键摇杆控制器,来控制TFTLCD上显示的直线首先介绍一下双轴按键摇杆控制器。原理:十字摇杆为一个双向的10K电阻器,随着摇杆方向不同,抽头的阻值随着变化。本模块使用5V供电(在本实验中使用3.3V ),原始状态下X,Y读出电压为2.5V左右(本实验为1.65V),当随箭头方向按下,读出电压值随着增加,最大到5V (本实验最大为3.3V) ;箭头相反方向按下,读出电压值减少,最小为0V即模块特设二路模拟输出和一路数字输出接口,输出值分别对应(X,Y)双轴偏移量,其类型为模拟量;按键表示用户是否在ž轴上按下,类型其为数字开关量坐标标识符清晰简明,准确定位;用其可以轻松控制物体(如二自由度舵机云台)在二维空间运动。

实验目的:

在屏幕的中心区域显示一条射线,射线起点为屏幕中心(120160),射线方向与摇杆歪的方向相同,射线长度与歪的程度有关线路连接。:

PC1 - ADC1 channel_11;  PC0 - ADC1 channel_10; PC2 - SW;

实验准备:

如图1所示,实验中对摇杆两个模拟段输入的检测需要使用STM32的ADC功能;

2,在数据转换之后的移动数据时使用DMA,以将数据及时转移出ADC的寄存器;

我们先来看看主函数,在主函数中我们定义了浮点型数组float ADC_ConvertedValueLocal [2];用于保存转换计算后的电压值,还有在adc.c文件中定义的数组ADC_ConvertedValue [2] ;用来装转换后的数据。

的的#include <stdio.h>中中
的的#include “ stm32f10x.h ”
的的#include “ led.h ”
的的#include “ delay.h ”
的的#include “ key.h ”
的的#include “ timer.h ”
的#包括“ beep.h ”
#包括“ usart.h中”
的#include “ adc.h ”
的#include “ lcd.h用于”// ADC1转换的电压值通过MDA方式传到SRAM
外部 __IO uint16_t ADC_ConvertedValue [ 2 ];// 局部变量,用于保存转换计算后的电压值
float ADC_ConvertedValueLocal [ 2 ];    int main(void )
{ u8 x = 0 ; u8 lcd_id [ 12 ];            // 存放LCD ID字符串  SysTick_Init(); // 延时  初始化USART1_Int(9600 ); LCD_Init(); ADC1_Init(); POINT_COLOR = RED; 而(1 ){        如果(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_2)!= 1 ){ LCD_Clear(黄色); LCD_ShowString(20,100,200,100,16,“ 谢谢你! ” );    Delay_ms(2000 );    LCD_Clear(白色); }对于(x = 0 ; x < 2 ; x ++ ){ ADC_ConvertedValueLocal [x] =(float)ADC_ConvertedValue [x] / 4096 * 3.3 ; // 读取转换的AD值  LCD_ShowxNum(0,0 + X * 20,ADC_ConvertedValue [X],5,16,0 ); }
 LCD_DrawLine(124,158,165 - (50 * ADC_ConvertedValueLocal [ 1 ])+ 42,50 * ADC_ConvertedValueLocal [ 0 ] + 78 );
           Delay_ms(100 );    LCD_Fill(34,72,210,246 ,LGRAY); }
}

在主函数的而(1)循环之前,我进了三个初始化,分别是:

  USART1_Int(9600 ); LCD_Init(); ADC1_Init();

在这里第一个就不在介绍,不懂解的可以参考:http://www.ciast.net/post/2015119.html  。第二个在这里也不作为重点介绍,TFTLCD的介绍可以参见  http:/ /www.ciast.net/post/20151112.html  ,在这里我们会使用到lcd.c中定义的一些操作液晶屏的函数,如下所示:

// 清屏函数// 颜色:清要屏的
填充色空隙LCD_Clear(U16颜色);
// 在指定区域内填充单个颜色// (SX,SY),(例如,EY):填充矩形对角坐标,区域大小为:(前SX + 1)*(EY-SY + 1)   // 颜色:要
填充的颜色空隙LCD_Fill(U16 SX,SY U16,U16 EX,EY U16,U16颜色);
// 画线// x1,y1:起点坐标// x2,y2:终点坐标
void LCD_DrawLine(u16 x1,u16 y1,u16 x2,u16 y2);
// 显示数字,高位为0,还是显示// x,y:起点坐标// num:数值(0〜999999999);
// len:长度(即要显示的位数)//size:字体大小// mode:// [7]:0,不填充; 1,填充0.// [6:1]:保留// [0]:0,非叠加显示; 1,叠加显示。
空隙LCD_ShowxNum(U16的x,U16 Y,U32 NUM,U8 LEN,U8大小,U8模式);
// 显示字符串// x,y:起点坐标// 宽度,高度:区域大小  // 尺寸:字体大小// * p:字符串起始地址
void LCD_ShowString(u16 x,u16 y,u16 width,u16身高,u8大小,u8 * p)

这些功能将在一段时间(1)循环中使用我们现在着重要将的是ADC1_Init();这个初始化函数,我们找到这个函数的定义,内容如下:

/ * *函数名:ADC1_Init *描述:无*输入:无*输出:无*调用:外部调用* /
void ADC1_Init(void )
{ ADC1_GPIO_Config(); ADC1_Mode_Config();
}

这个函数由另外两个函数组成,分别是:

/ * *函数名:ADC1_GPIO_Config *描述:使能ADC1和DMA1的时钟,初始PC.00,PC.01和PC.02 *输入:无*输出:无*调用:内部调用* /
static  void ADC1_GPIO_Config(void );
/ * 函数名:ADC1_Mode_Config *描述:配置ADC1的工作模式为MDA模式*输入:无*输出:无*调用:内部调用* /
static  void ADC1_Mode_Config(void);

首先看的是第一个函数,即引脚定义:

/ * *函数名:ADC1_GPIO_Config *描述:使能ADC1和DMA1的时钟,初始化PC.01 *输入:无*输出:无*调用:内部调用* /
static  void ADC1_GPIO_Config(void )
{ GPIO_InitTypeDef GPIO_InitStructure;/ * 启用DMA 时钟* / RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);/ * 使能ADC1和GPIOC 时钟* / RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC,ENABLE);/ *将PC.01配置为模拟输入* / GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOC,&GPIO_InitStructure);                // PC1 PC0,输入时不用设置速率
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC,&GPIO_InitStructure);                // PC2设置按键功能
}

我将两个模拟输入设置为GPIO_Mode_AIN(模拟输入),将PC2按键功能键设置成上拉输入(摇杆的SW引脚已经被上拉)。下面是重点:

在ADC1_GPIO_Config(void )函数中,我们主要进行的是DMA和ADC1双通道的设置,下面我们对负责传输的DMA进行设置:

DMA_InitTypeDef DMA_InitStructure;/ * DMA通道1配置* / DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;     // ADC地址  DMA_InitStructure.DMA_MemoryBaseAddr =(u32)&ADC_ConvertedValue; // 内存地址  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 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_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;        // 循环传输  DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1,&DMA_InitStructure);/ * 启用DMA通道1 * / DMA_Cmd(DMA1_Channel1,ENABLE);

下面我们开始使用ADC1的通道10和通道11来转换接受到的虚拟信号:

ADC_InitTypeDef ADC_InitStructure;/ * ADC1配置* / ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;    // 独立ADC模式  ADC_InitStructure.ADC_ScanConvMode = ENABLE;      // 禁止扫描模式,扫描模式用于多通道采集  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;    // 开启连续转换模式,即不停地进行ADC转换  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;    // 不使用外部触发转换  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;     // 采集数据右对齐  ADC_InitStructure.ADC_NbrOfChannel = 2 ;         // 要转换的通道数目2  ADC_Init(ADC1,&ADC_InitStructure);/ * 配置ADC时钟,为PCLK2的8分频,即9Hz * / RCC_ADCCLKConfig(RCC_PCLK2_Div8); / * 配置ADC1的通道11为55. 5 个采样周期,序列为1 * /  ADC_RegularChannelConfig(ADC1,ADC_Channel_11,1 ,ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_10,2,ADC_SampleTime_55Cycles5); // ADC1; ADC1通道0;第2转换;采样时间为239.5周期
ADC_DMACmd(ADC1,ENABLE);      / * 启用ADC1 DMA * / ADC_Cmd(ADC1,ENABLE);          / * 启用ADC1 * / ADC_ResetCalibration(ADC1);       / * 复位校准寄存器* / while(ADC_GetResetCalibrationStatus(ADC1));     / * 等待校准寄存器复位完成* / ADC_StartCalibration(ADC1);       / * ADC校准* / while(ADC_GetCalibrationStatus(ADC1));      / * 等待校准完成* // * 由于没有采用外部触发,所以使用软件触发ADC转换* /  ADC_SoftwareStartConvCmd(ADC1,ENABLE);

我把整个ADC的设置分成了四个部分:

第一部分:主要是ADC的初始化参数配置函数,具体设置可以参考:http://www.ciast.net/post/20151226.html  ,在这里使用独立ADC模式模式,由于使用了双通道,所以ADC_ScanConvMode = ENABLE;即开启扫描模式,且ADC_NbrOfChannel = 2;

第二部分:主要是配置ADC时钟和规则通道设置这里由于ADC的频率不能大于12MHz的的,所以我们选择分频为PCLK2的8分频,即9HZ 规则通道的设置是每一个通道都要进行的,可以设置通道和扫描顺序以及扫描周期等,这也是ADC设置的重点,可以参考  http://www.ciast.net/post/20151226.html  。

第三部分:主要是使能DMA和ADC,以及复位校准;

第四部分:使用软件触发ADC转换,转换开始。

至此初始化函数介绍完毕,下面开始的同时(1)循环部分的介绍:

  而(1 ){         如果(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_2)!= 1 ){ LCD_Clear(黄色); LCD_ShowString(20,100,200,100,16,“ 谢谢你! ” );    Delay_ms(2000 );    LCD_Clear(白色); }对于(x = 0 ; x < 2 ; x ++ ){ ADC_ConvertedValueLocal [x] =(float)ADC_ConvertedValue [x] / 4096 * 3.3 ; // 读取转换的AD值  LCD_ShowxNum(0,0 + X * 20,ADC_ConvertedValue [X],5,16,0 ); }
 LCD_DrawLine(124,158,165 - (50 * ADC_ConvertedValueLocal [ 1 ])+ 42,50 * ADC_ConvertedValueLocal [ 0 ] + 78 );                          Delay_ms(100 );    LCD_Fill(34,72,210,246 ,LGRAY); }

其中的重点是FOR语句:

        对于(x = 0 ; x < 2 ; x ++ ){ ADC_ConvertedValueLocal [x] =(float)ADC_ConvertedValue [x] / 4096 * 3.3 ; // 读取转换的AD值  LCD_ShowxNum(0,0 + X * 20,ADC_ConvertedValue [X],5,16,0 ); }

在这个循环语句中,我们读取两个通道中的数据。其中ADC_ConvertedValue [X]为我们在一开始就定义的用户存数处理过的数据的数组,其中X取1和2为什么这个数组?可以接受到两个通道的数据呢其实在DMA中我们设置了数据的传输:

    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;     // ADC地址  DMA_InitStructure.DMA_MemoryBaseAddr =(u32)&ADC_ConvertedValue; // 内存地址  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

其中传输方向是从外设到内存,而内存地址,我们取得就是这个数组的首地址,这样转换过的数据自然就被传到了这个数组中。那么传输之前数据的处理又是怎么进行的呢?从下面的程序可以看到,我们在ADC设置时,使能了扫描和连续转换,且通道数目为2,那么在连续转换时,ADC就会按照下面ADC_RegularChannelConfig中设置的转换顺序进行连续的转换所有的通道(即转换完通道1后转换通道2)。每次转换完一个通道后,转换好的数据就会被DMA转走,从而回到了上面的步骤。

    ADC_InitStructure.ADC_ScanConvMode = ENABLE;      // 禁止扫描模式,扫描模式用于多通道采集  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;    // 开启连续转换模式,即不停地进行ADC转换  ADC_InitStructure.ADC_NbrOfChannel = 2 ;         // 要转换的通道数目2
------------------------------------------ ----------------------------------------------ADC_RegularChannelConfig(ADC1, ADC_Channel_11,1 ,ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_10,2,ADC_SampleTime_55Cycles5); // ADC1; ADC1通道0;第2转换;采样时间为239.5周期

下面的语句是FOR语句下面的,实现的是话射线功能,我们使用的屏是240×320的,图形具体尺寸见下图:

LCD_DrawLine(124,158,165 - (50 * ADC_ConvertedValueLocal [ 1 ])+ 42,50 * ADC_ConvertedValueLocal [ 0 ] + 78 );
Delay_ms(100 );
LCD_Fill(34,72,210,246,LGRAY);

中间一点是理论中心点(120160),但是由于摇杆的电压不是太稳定,出现了电压波动,所示实际中心点是(124159),中间的正方形是射线的边界。

还有最后的IF语句,设置的是按下是的操作,实现的是按下后在屏幕上刷黄色屏,出现一个字符串:

如果(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_2)!= 1 ){  LCD_Clear(黄色);  LCD_ShowString(20,100,200,100,16,“ 谢谢你!” );  Delay_ms(2000 );  LCD_Clear(白色);  }

现在整个实验就结束了。这个实验今天从早上7点多开始,我一直弄到下午4点半才成功,中间还百度了很多资料。

最终效果如下:

基于STM32控制的PS2摇柄模块—双轴按键摇杆控制器控制TFTLCD相关推荐

  1. Arduino提高篇12—双轴按键摇杆

    摇杆一般在航模.电玩.遥控车.云台等设备上应用广泛,很多带有屏幕的设备也经常使用摇杆作为菜单选择的输入控制.本篇介绍双轴按键摇杆的使用. 1. 双轴按键摇杆介绍 双轴按键摇杆主要由两个10K的电位器和 ...

  2. Arduino双轴按键摇杆

    双轴按键摇杆主要由两个10K的电位器和一个按键开关组成,两个电位器随着摇杆扭转角度分别输出X.Y轴上对应的电压值,在Z轴方向上按下摇杆可触发轻触按键.在配套机械结构的作用下,无外力扭动的摇杆初始状态下 ...

  3. 基于STM32的双轴XY摇杆传感器模块使用

    文章目录 前言 一.双轴XY摇杆传感器模块介绍 二.如何使用该模块 1.进行ADC转换 2.传输转换完成的数据(DMA) 3.串口打印 三.实现步骤 1.ADC初始化与配置参数 2.实现DMA传输 3 ...

  4. 最简单DIY基于STM32的远程控制电脑系统①(电容触摸+按键控制)

    STM32库函数开发系列文章目录 第一篇:STM32F103ZET6单片机双串口互发程序设计与实现 第二篇:最简单DIY基于STM32单片机的蓝牙智能小车设计方案 第三篇:最简单DIY基于STM32F ...

  5. 基于STM32单片机光学指纹识别模块(FPM10A)全教程(基于C语言)

    本文转载,其来源在参考中:1,稍加修改,因为近期使用到这个模块,故而加以整理! 1.平台 首先我使用的是 奋斗 STM32 开发板 MINI板 基于STM32单片机光学指纹识别模块(FPM10A)全教 ...

  6. K_A12_022 基于STM32等单片机驱动VL53L0X模块 串口与OLED0.96双显示

    K_A12_022 基于STM32等单片机驱动VL53L0X模块 串口与OLED0.96双显示 一.资源说明 二.基本参数 参数 引脚说明 三.驱动说明 UART对应程序: IIC对应程序: 四.部分 ...

  7. K_A14_001 基于STM32等单片机驱动MPU6050模块 串口与OLED0.96双显示

    K_A14_001 基于STM32等单片机驱动MPU6050模块 串口与OLED0.96双显示 一.资源说明 二.基本参数 参数 引脚说明 三.驱动说明 时序 对应程序: 四.部分代码说明 1.接线引 ...

  8. 六轴机械臂控制器 控制卡 软件 机械臂

    六轴机械臂控制器 控制卡 软件 机械臂27400624681113128教学实训设备

  9. K_A08_004 基于 STM32等单片机驱动MX1919模块按键控制直流电机正反转加减速启停

    目录 一.资源说明 二.基本参数 1.参数 2.引脚说明 三.驱动说明 1.MX1919模块驱动时序 2.对应程序: 3.PWM信号 四.部分代码说明 接线说明 1.STC89C52RC+MX1919 ...

  10. 基于stm32的正点原子Lora模块教程

    基于stm32的LoRa模块调试教程 初识LoRa 上手LoRa 程序编写 结果演示 再见LoRa 初识LoRa 简单来讲,LoRa就是一种低功耗远程无线通信技术.它是基于Semtech公司SX127 ...

最新文章

  1. Linux操作系统上lsof命令详解
  2. 郑州升达学院计算机考试,第35次全国计算机等级考试报名工作通知
  3. CserialPort类的简单用法
  4. LeapMotion使用入门
  5. VTK修炼之道4_Win32控制台项目
  6. ​搜出来的文本:从文本生成到搜索采样
  7. mysql 导入dbm文件_DBM数据导入到mysql数据库方法
  8. 【HDU - 5777】domino(贪心)
  9. 【HDU - 5886】Tower Defence(树的直径,思维,dp)
  10. Proactor 与 Reactor
  11. 杨玲 201771010133《面向对象程序设计(java)》第十六周学习总结
  12. Ionic3与Angular4新特性
  13. 基于Socket实现网络编程
  14. 【论文笔记】—低光图像增强—Zero-reference—ZeroDCE—2020-CVPR
  15. 安卓手机修改host
  16. 本周大新闻|传苹果MR明年Q1量产,五部委发布VR行业应用行动计划
  17. UG NX二次开发(C#)-装配-替换组件
  18. 第三篇 ME909s-821设备描述符分析
  19. 制作辣条视频教程+配方
  20. 单身的程序猿伤不起,在神棍节感慨下

热门文章

  1. 2016 PayPal商家账户界面 如何集成支付按钮
  2. IBM supervessel power云平台 之 crontab定时任务篇
  3. zmq xsub/xpub 实现消息订阅(一)
  4. android lint
  5. FYI | Neuro Workshop (Virtual)-Connectomics
  6. markdown格式转wiki格式(文件格式转换)
  7. python islower方法_(验证)Python中不同类型的islower()方法
  8. shell蚂蚁森林_和“蚂蚁森林”的融合
  9. win10无法复制文件到system32,提示需要权限操作
  10. JVM -运行时数据区 - 堆空间