单片机学习笔记 —— 导航按键

  在ADC模数转换的基础上,我们可以设计一个导航按键案例,通过将模拟电压转化为数字电压,根据数字电压值进行相应的处理。

一、导航按键电路

电流图

说明:左边有6个电阻,加起来700Ω,当按下/松开/拨动导航按键时,A/D转换输入的模拟电压有0、100、200、300、400、500、700六种组合。



二、A/D转换目标

实现效果:程序主要是对ADC进行操作,并将寄存器相应位取出分别用8位二极管和数码管显示。第一位数码管显示8位转换结果中前三位值,最后两位数码管显示后五位值。数码管下方的发光二极管与数码管对应显示。

程序运行效果说明
在数码管最高位(命名Seg0)显示转换结果高三位,点亮对应的发光二极管L7—L5。
数码管后两位(命名Seg6-Seg7)显示转换结果低五位,点亮对应的发光二极管L4—L0。
误差来源:电阻的工艺使得电阻会有一定的误差,导致实际数值有一点误差
解决办法:我们在做导航按键的判断时,都只是取高三位的值,也就是数码管Seg0的值。

数码管及二极管显示

操作seg0seg6-seg7参考值 (实际值)
无操作731(0-31)
按下KEY3000(0-31)
向右106(0-31)
向下212(0-31)
向里317(0-31)
向左422(0-31)
向右525(0-31)


三、程序实现

变量定义:定义引脚别名,AD值相关变量和数码管显示相关的量。

#include <STC15F2K60S2.H>
#include <intrins.h>              //_cror_(); 

#define uint unsigned int
#define ulint unsigned long
#define uchar unsigned char
#define ADC_FLAG 0x10

/*---------引脚别名---------*/
sbit sbtSel0 = P2 ^ 0;
sbit sbtSel1 = P2 ^ 1;
sbit sbtSel2 = P2 ^ 2;  //位选
sbit sbtLedSel = P2 ^ 3;

/*---------变量定义---------*/
uint uiSampleNum = 0;  //采样次数
ulint uiAdSum = 0;     //AD值累加和
uint uiAdDate8 = 0;   //AD值八位数据
uint uiAdHigh3 = 0;   //AD值高3位
uint uiAdLow5 = 0;    //AD值低5位
uchar ucSegState;     //数码管扫描状态
//段选
char arrSegSelect[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};
//位选
uchar arrDigSelect[] = {0x00, 0x06, 0x07};

初始化函数:设置推挽输出、中断和AD转换控制寄存器

// 初始化单片机SYS
void InitSYS()
{
    P0M1 = 0x00;
    P0M0 = 0xff;
    P2M1 = 0x00;
    P2M0 = 0x0E;
    ucSegState = 0;

    TMOD = 0x00;        //中断设置
    EA = 1; 
    TH0 = ( 65535 - 1000 ) / 256; 
    TL0 = ( 65535 - 1000 ) % 256;
    ET0 = 1;            //打开定时器
    TR0 = 1;            //启动定时器
}

//初始化ADC
void InitADC()
{
    P1ASF = 0x80;  //选择P1.7作为A/D使用=>可以检测到KEY3按下后的低电平
    ADC_RES = 0;//清零ADC寄存器
    ADC_CONTR = 0X8F;   //打开power 540周期转换一次 选择P1.7作为A/D输入来用   
    CLK_DIV = 0X00;         //ADRJ = 0  ADC_RES存放高8位结果
    EADC = 1;               //允许ADC中断
    PADC = 1;               //ADC中断优先级为1//ADCÖжÏÓÅÏȼ¶Îª1
}

处理子函数:控制数码管显示、ADC的数据采集和处理

void Divide3and5()		//分离AD转换结果的高3位
{
    uiAdHigh3 = uiAdDate8 & 0xE0;         //将8位转换结果的低5位清零
    uiAdHigh3 = _cror_( uiAdHigh3, 5 );      //循环右移5位
    uiAdLow5 = uiAdDate8 & 0x1F;          //将8位转换结果高5位清零
}

说明:_cror_循环右移函数,包含在头文件<intrins.h> 中:
_crol_(var, n):将var循环左移n位
_cror_(var, n):将var循环右移n位

// 定时器T0中断
void T0_Process() interrupt 1
{
    ucSegState++;
    if( ucSegState == 4 )
        ucSegState = 0;
    P0 = 0x00;
    switch( ucSegState )
    {
        case 0:
            sbtLedSel = 0;              //选择数码管亮
            P2 = arrDigSelect[ucSegState];
            P0 = arrSegSelect[uiAdHigh3];   //显示高三位对应的十进制
            break;
        case 1:
            sbtLedSel = 0;
            P2 = arrDigSelect[ucSegState];
            P0 = arrSegSelect[uiAdLow5 / 10]; //显示低5位对应的十进制的十位
            break;
        case 2:
            sbtLedSel = 0;
            P2 = arrDigSelect[ucSegState];
            P0 = arrSegSelect[uiAdLow5 % 10]; //显示低5位对应的十进制的个位
            break;
        case 3:
            sbtLedSel = 1;	// 发光二极管亮
            P0 = uiAdDate8;
            break;
    }
}

// ADC中断处理
void ADC_Process() interrupt 5
{
    IE = 0x00;                // 关闭中断
    ADC_CONTR &= ~0X10;       // ADC_FLAG清零
    uiSampleNum++;
    if( uiSampleNum > 1000 )          //采集数据1000次后
    {
        uiAdDate8 = ( uiAdSum + 500 ) / 1000; //四舍五入
        Divide3and5();               //分离高3位AD值
        uiSampleNum = 0;
        uiAdSum = 0;
    }
    uiAdSum += ADC_RES;
    ADC_CONTR |= 0X08;       // 将ADC_START置位
    IE = 0xa2;               //重新打开中断
}

主函数:初始化+死循环

void main()
{
    InitSYS();
    InitADC();
    while( 1 ) ;
}

将持续烧写到实验板中,当我们拨动导航按键时,数码管第一位显示不同的数字,最后两位显示30/31(存在工艺误差),由于选择P1.7作为A/D输入来用,所以当按下KEY3时,数码管显示0 00



完结 cheers! ??

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数码管是一种常见的数字显示器件,可以用于显示各种数字、字母等字符。在单片机应用中,数码管通常用于显示计数器、计时器、温度、湿度等实时数据。 数码管的种类有很多,包括共阳数码管、共阴数码管、共阳共阴混合数码管等。其中,共阳数码管是最常见的一种,也是本文所涉及的数码管类型。 单片机控制数码管的原理是通过对数码管的各个管脚进行控制,使其显示相应的数字或字符。数码管的控制方式有两种,即静态显示和动态显示。 静态显示是指将要显示的数字或字符的每一位分别输出到数码管的每个管脚上,然后使其保持不变,从而实现显示效果。静态显示的缺点是需要使用大量的I/O口,且不能灵活地改变显示内容。 动态显示是指将要显示的数字或字符的每一位依次输出到数码管的每个管脚上,并在短时间内快速切换下一个数字或字符,从而形成连续的显示效果。动态显示的优点是可以使用较少的I/O口,且可以灵活地改变显示内容。 以下是一个简单的动态显示数码管的实现示例: 1. 定义数码管的引脚 ```c #define DIG_PORT P2 // 数码管位选端口 #define DIG_COM 0x00 // 数码管位选端口初始值 #define LED_PORT P0 // 数码管段选端口 ``` 2. 定义数码管显示的数字或字符 ```c unsigned char code ledChar[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f }; ``` 3. 实现数码管动态显示函数 ```c void display(unsigned char i) { unsigned char j, k; for (j = 0; j < 8; j++) { DIG_PORT = DIG_COM | (1 << j); // 选择数码管位(从左到右) for (k = 0; k < 100; k++); // 延时,视情况可调整 LED_PORT = ledChar[i]; // 显示数码管上的数字或字符 } } ``` 4. 调用数码管动态显示函数 ```c int main() { unsigned char i = 0; while (1) { display(i % 10); // 显示数字 i 的个位数 i++; } return 0; } ``` 以上就是一个简单的数码管动态显示的实现示例。需要注意的是,数码管的控制方式和具体实现方法可能因不同的硬件平台和编程语言而有所不同。因此,在具体应用中需要根据实际情况进行适当的调整和修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值