概述
前言:发现STC板子上的按键不够用了,想着用导航键,但无奈在网上找了很久都没有任何一个字眼是关于STC学习板导航按键的使用和详细的代码。今天下午我帅帅的学长教会了我如何去使用导航键,为了更好的巩固和理解,特写博客一篇,希望能帮到有需要的人。
本篇博客构成:
目录
一、导航键原理介绍;
二、STC学习板结构简单介绍;
三、A/D转换的使用和中断的简单介绍;
四、详细代码解释;
一、导航键原理介绍:
先来看导航键的结构图:
1.首先可以看到左边有多个不同阻值的电阻,然后是分别是1、2、3、4、5、6共6个接口。
2.图片中间是一个开关,可以接到不同的接口上;
3.图片右上角KEY3是输出;
以上便是我们需要关注的,下面的K3、K2、K1就板子上的三个开关啦。这个不用管。
导航键如何确定被按下是哪个方向呢?哈哈相信聪明的你想到了,导航键的开关接到不同接口上由于总阻值不一样,所以加在这两点的电压肯定不同。比如当我向上按导航键,这个时候会有一个电压,假如0.5v吧,那么我们如何去拿到这个电压数据呢?刚刚说KEY3是输出,所以当然是从输出去接收啦。但这是模拟信号,需要转成数字才行。这个时候就需要用到我们的A/D转换啦,这个过程叫ADC,亦即模拟转数字。所以配置好端口和启动A/D转换器就好啦。
二、STC学习板结构简单介绍:
这张图标注了STC板子上每一个接口的名称,当你想用这个某个端口的时候就在这张图上面找对应的名字就好。
比如我们现在要用KEY3这个口,发现它对应的名称是P1.7,当我们要在代码里用它的时候,将引脚别名为P1^7就好,也就是声明你这个引脚是这个端口。你会发现前面还有一些字母是干嘛呢?比如ADC7,说明这个端口可以作为A/D转换的输入。如图:
不懂就多翻数据手册啊,要什么有什么!
三、A/D转换的使用:
强行插一张图:
核心原理就在我圈的红圈里面。这一部分会不停的比较转换得到的数字值,直到差值无限逼近0才会向结果寄存器输出精度很高的数字值。
1.IO口初始化:
设置推挽输出:
P0M0 = 0xFF;
P0口为什么这么设置,不用我说了吧?数码管显示数字都需要这样设置。
P2为什么是这样设置呢?由于数码管是共阴极的(咱们的板子),所以数码管点亮需要led_sel为1,所以P2M0 就是 0000 1000啦,也就是0x08呗。P2M1我就不说了吧,查看STC结构图都可以看懂,还有M0M1不同组合对应的工作模式。推挽是10。 因此设置P2.3为推挽只需为M0M1为10就好,其它口不适用,设置为高阻输入。详情看图:
2.为了测试方便,本人采用定时器来实现数码管的显示。这样子更好一些,每当定时器溢出就扫描一次数码管。
那么先来初始化我们的定时器吧。
查找数据手册,可以看到与定时器有关的寄存器如图:
我就简单说一下我们要用的寄存器吧,详情参考数据手册。
首先是TMOD,共有八位。结构如下:
可以看到有两个定时器T1和T0,GATE设置为1表示选择了其中哪个定时器,比如我最高位为1表示我用的是定时器1,这个时候定时器0的GATE必须设置为0。C/~T表示用作定时器还是计数器,为1用作计数器,为0用作定时器,M0M1则是工作模式选择。具体如图:
一般呢选用16位自动重装就好啦。因此TMOD就可以初始化为:TMOD &= 0xF0 (1111 0000)
说明一下为什么GATE为置为0,启动定时器有两种方法:一种是GATE为1且INTO脚为高 第二种是直接将TR0置为1。而我采用的是第二种,因此不用去管GATE的值了,只要TR0为1就能启动定时器,这里配置的定时器0,因为定时器1与1111相与是不变的。
为什么要这样与呢?寄存器一般都有一个初值的,详情看图:一般都是0。
接下来是AUXR辅助寄存器,这个主要用来控制定时器的速度的,一般采用12分频率。结构如下:
控制速度是B7、B6,我们只要关心这两个位置就好,很容易看出B7是控制定时器T0的,B6是控制定时器T1的,因此对应设置就好。对应的速度如下:(我采用的是定时器0,因此设置T0x12为0即可)
因此AUXR设置为:AUXR &=0x7F (0111 1111)最高位置0就好,因为任何数与0都是0。
ok接下来要给我们的定时器一个初始值,告诉它你要从哪里开始加。由于我们采用的时钟系统频率是11.0592HZ,大概推算一下就可以得到下面的式子:
TH0 = (65535 - 1000) >> 8; //高八位赋值
好了到这里定时器就配置好了,是不是很简单啊,只要设置好寄存器的状态就可以了。
那么就启动我们的定时器吧。
首先看到这个寄存器:
注意到可位寻址了嘛?什么意思呢?意思就是你可以单独位它的某一位进行设置。
比如图中的TR0就是启动寄存器,那么直接TR0=1就可以启动定时器。当然你也可以TCON |=xxxxxx。只要对应位置设置好就可以了。
下面是TCON中断控制寄存器每一位的解释:(知道你们懒)
因为要中断去扫描数码管,因此一定要记得开启允许定时器中断:ET0=1;(后面会详细讲到)
3.第三步是初始化我们的ADC啦。
如图是AD转换需要用到的寄存器:
首先配置好我们AD采集信息的输入口,那么要写入信息,就要用到与此相关的寄存器,也就是P1ASF。它有八个口可以作为输入。而我们是采集导航键的,刚刚说了导航键的输出对应的是P1.7口。因为P1ASF可设置为:P1ASF = 0x80(1000 0000)。如图:(B7-B0哪位为1就表示选用哪个端口作为数据输入源)
信息源有了,接下来是打开我们的AD转换器。
跟打开定时器类似,也要用到控制寄存器,也就是ADC_CONTR啦。先来看看它的结构:
各位表示的意思如下(知道大爷们懒)
注意红圈!!!!
所以这个ADC_CONTR可以设置为:ADC_CONTR = 0x87 (1000 0111) ADC_FLAG需要特别注意,一定要软件清0,否则就只能转换一次。ADC_STATR此处不需要设置,你可以手动开启。ADC_CONTR也是可为寻址的,因此可以单独设置某一位的值。
那么转换后的结果放在哪呢?寄存器呗!AD转换有用来存储结果的寄存器,称为结果寄存器。如图:
CLK_DIV我们只关心ADRJ就好了,因为它决定了我们的数据如何存储在上面的两个结果寄存器中。转换的结果有10位,不巧的是我们的寄存器只有八位,因为高八位和低二位如何放呢?高八位放在ADC_RES还是ADC_RESL呢?由ADRJ来决定。具体看图:
注意区分哦。
最后是允许中断。中断也有专门的寄存器,称为中断允许寄存器。不同的位表示不同的中断,如图:
看到ET0很眼熟吧,上面用了,没错咯它就是允许定时器0中断。
但中断有个老大,它要是不允许中断,谁有中断请求都是无效的,那就是EA,它叫CPU开放中断,EA为1的时候CPU才会接受来自不同地方的中断请求,也就是我们常说的总中断。然后再允许ADC中断就好了。也就是把EADC置为1。
好了!AD和定时器全初始化完成了。下面就该告诉它们,当中断请求发生的时候该干些什么了。
四、
首先是定时器,它要干的事情是去扫描数码管,这里给的建议就是:别把你的程序放在中断函数里面去。为什么呢?假如你菜写的代码效率又不高,一直在里面执行迟迟不能返回,就会一直中断在这里,其它中断请求来的了只能等着你执行完它才有机会被执行,是不是浪费了很多cpu资源还容易破坏周期。一个技巧就是改变标记位,你的程序最好放到main函数里面去,用一个if检测标记位是否发生改变就可以了。这样子中断请求很快就被处理完成,程序性能也大大提高。接下来是AD转换,当中断的时候已经完成了数据的转换了,这个时候你可以拿到这个值了。这个值称它为ADC_VALUE吧,导航键往不同的方向按下的时候会有一个不同的ADC_VALUE,你可以将这个ADC_VALUE显示到数码管上,分别记录下来。当ADC_VALUE值对应的时候,你可以对一个变量进行运算操作,加加减减你随意,把这个变量显示到数码管上就会看到当导航键向上按这个数字加一的效果了,向下按是减一。反正一句话就是判断当前ADC_VALUE属于哪个方向的,就能确定导航键往哪个方向按下了!
四、详细代码代码解释:
#include "stc15f2k60s2.h"
bit flag_1ms;
bit flag_adc;
unsigned int digit_pos;
unsigned int adc_value;
unsigned int digit_value;
void IO_Init();
void Timer0_Init();
void ADC_Init();
void func_1ms();
char digit[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void main()
{
IO_Init();//IO口初始化
Timer0_Init();//定时器初始化
ADC_Init();//ADC转换器初始化
EA = 1;//允许中断
flag_1ms = 0;
flag_adc = 0;
digit_pos = 4;
adc_value = 0;
digit_value = 0;
while(1)
{
if(flag_1ms)
{
flag_1ms = 0;
//扫描
func_1ms();
}
if(flag_adc)
{
flag_adc = 0;
adc_value = ((ADC_RES & 0x03) << 8) | ADC_RESL;
adc_value = adc_value >> 7;
if(adc_value == 5)
{
digit_value ++;
if(digit_value > 9999)
{
digit_value = 0;
}
}
if(adc_value == 2)
{
digit_value --;
if(digit_value < 0)
{
digit_value = 9999;
}
}
}
}
}
void IO_Init()
{
P0M0 = 0xFF;
//推挽输出
P0M1 = 0x00;
P2M0 |= 0x08;
//0000 1000
P2M1 &= 0xF7;
//1111 0111
}
void Timer0_Init()
{
TMOD &= 0xF0;
AUXR &= 0x7F;
//0111 1111
TH0 = (65535 - 1000) >> 8;
TL0 = (65535 - 1000) & 0xFF;
TR0 = 1;
ET0 = 1;
}
void ADC_Init()
{
P1ASF = 0x80;
ADC_CONTR = 0x87;
//1000 0111
CLK_DIV |= 0x20;
EADC = 1;
}
void func_1ms()
{
P0 = 0;
P2 = (P2 & 0xF0) | (digit_pos & 0x0F);
switch(digit_pos)
{
case 4: P0 = digit[digit_value/1000]; break;
case 5: P0 = digit[digit_value%1000/100]; break;
case 6: P0 = digit[digit_value%100/10]; break;
case 7: P0 = digit[digit_value%10]; break;
default: break;
}
digit_pos ++;
if(digit_pos == 8)
{
digit_pos = 4;
}
ADC_CONTR |= 0x08;
}
void Timer0_Handler() interrupt 1
{
flag_1ms = 1;
}
void ADC_Handler() interrupt 5
{
flag_adc = 1;
ADC_CONTR &= 0xEF;(1011 1111)
}
有不懂的加我QQ2528019027。博客写得一般,有错字地方还见谅,有错误也欢迎指出,本篇博客日后会继续完善。
补图:
数字跳动太快,消抖一下就好啦。以后再补哈哈哈哈。
最后
以上就是大意裙子为你收集整理的湖南大学STC学习板导航键的使用的全部内容,希望文章能够帮你解决湖南大学STC学习板导航键的使用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复