例程1. LKB -- 慕司板IAP15

LKB是LED、KEY、Buzzer的首字母缩写,代表LED、按键、蜂鸣器的操作,都属于基本的IO(GPIO)操作。
慕司板(IAP15)板载一个用户LED(蓝色光)、10个独立按键、1个无源蜂鸣器,电路如下:
例程1. LKB -- 慕司板IAP15_第1张图片

与单片机的对应关系如下图:
例程1. LKB -- 慕司板IAP15_第2张图片

先说说GPIO(通用IO口):
贴片44个引脚的IAP15L2K61S2有42个GPIO口(P0、P1、P2、P3、P4、P5.4、P5.5),除了VCC和GND,都是可用的GPIO口。芯片手册中明确指出STC15系列单片机的I/O口有4种工作类型,通过PxM1和PxM0(x:0~5)设置:

复位后默认IO为准双向口模式,如欲设定P25(对应慕司板的蜂鸣器)为推挽输出:

P2M1 &= 0xdf;   //1101 1111,第5位清0
P2M0 |= 0x20;   //0010 0000,第5位置1

LED不用多说,对应引脚等于0即可点亮,1熄灭。

无源蜂鸣器使用一个S8050的NPN晶体管,工作在截止区或饱和区而不是三极管的放大区,仅起开关作用,10K的下拉电阻确保晶体管可以稳定关断。实验表明,设置为推挽输出才能响(同理,把蜂鸣器换成继电器等,也要设置为推挽),初始化代码(lkb.c)如下:

****************************************
*设置蜂鸣器端口为推挽输出
****************************************/
void LKB_Init()
{
 P2M1 &= 0xdf; //P25清0:1101 1111 
 P2M0 |= 0x20; //P25置1:0010 0000
}

蜂鸣器有频率和鸣响时间两个参数,于是又有了Buzzer_Func()函数(lkb.c中):

/**************************************** *无源蜂鸣器频率、时间控制函数 *Freq:蜂鸣器频率 *time: 蜂鸣器响的时间:ms ****************************************/
void Buzzer_Func(unsigned int Freq,unsigned int time)
{
    unsigned int i;
    for(i=0;i<time*Freq/500;i++)
    {
        BEEP=~BEEP;
        Delay_us(500000L/Freq); //最低500000L/65536=7.6Hz约8Hz 最高500 000Hz
    }
    BEEP=0;             //关闭蜂鸣器
}

至于按键,考虑到每个按键的独立性以及可能作为其它用途,十个按键均为独立按键,参考了正点原子的代码:

/***************************************** *按键扫描函数(参考自正点原子按键程序) *mode: *0 不支持连按 *1 支持连按 *****************************************/
void Key_Scan(unsigned char mode)
{
    static unsigned char key_up=1;//按键按松开标志
    if(mode)    key_up=1;  //支持连按 

    if(key_up && (KEY1==0 || KEY2==0 || KEY3==0 || KEY4==0 || KEY5==0
                ||KEY6==0 || KEY7==0 || KEY8==0 || KEY9==0 || KEY10==0) )   //有按键按下
    {
            Delay_ms(10); 
            key_up=0;
            if(KEY1==0)      Key_Num = 1;
            else if(KEY2==0) Key_Num = 2;
            else if(KEY3==0) Key_Num = 3;
            else if(KEY4==0) Key_Num = 4;
            else if(KEY5==0) Key_Num = 5;
            else if(KEY6==0) Key_Num = 6;
            else if(KEY7==0) Key_Num = 7;
            else if(KEY8==0) Key_Num = 8;
            else if(KEY9==0) Key_Num = 9;
            else if(KEY10==0) Key_Num = 10;
            else Key_Num=0;
    }
    else if( (KEY1==1) && (KEY2==1) && (KEY3==1) && (KEY4==1) && (KEY5==1)
           &&(KEY6==1) && (KEY7==1) && (KEY8==1) && (KEY9==1) && (KEY10==1))    // 无按键按下
    {
        key_up=1; 
        Key_Num=0;       
    }
    else Key_Num=0; 
}

Key_Num是全局变量,在lkb.c中定义,在config0.h中作了声明:

extern unsigned char Key_Num;

当然,按键程序千千万,需要实现什么功能要自己会改,如常说的点动(按住不松手就输出,一松手就停止输出,类似上面程序中的连按模式)、互锁(各个按键是互斥的,如电风扇的1档和2档不能同时按下)、自锁(按一下就连续运转),具体介绍如下:

  • 点动,用英文字母M代表(如遥控器工作方式为M4,代表点动方式,有ABCD
    4个按键),即手按遥控器的每一个键,相应继电器接通,松开遥控器按键,相应继电器断开,一次只有一路继电器是接通的。例如一路直流开关,用一键遥控器控制。一直按着遥控器按键,则继电器一直接通,松开按键,继电器断开。

  • 互锁,用英文字母L代表,手按遥控器第一个键,相应继电器接通,再按另一个按键,相应继电器接通,之前接通的那路继电器则断开,它具有唯一关系,每次只有按的那一路继电器接通,之前接通的会断开。例如二路直流互锁遥控开关,用二键遥控器控制(A、B两键)。按A键时,A对应的继电器会接通,按B键时,B键对应的继电器会接通,A键对应的断开。

  • 自锁,用英文字母T代表,同一个键控制一路,按一次开,再按一次关,可独立控制,可同时有多个通断。像家里有的灯具遥控开关,基本上都是使用自锁功能。如四路直流自锁开关,用桃木四键遥控器控制(ABCD四键),按A时,A对应的继电器接通,再按一下A时,A对应的继电器断开,其它按键亦然。可逐次按下ABCD四键,则四路继电器都接通。

回到程序来,main.c中我们实现按键的点动方式?按下一个按键,蜂鸣器响一声(300ms),然后反转蓝光LED的状态:

void main()
{
    Delay_us(10);
    LKB_Init();

    while(1)
    {
        Key_Scan(0);    //可以试试为1时按下的情况
        if(Key_Num) 
        {
            Buzzer_Func(Key_Num*500,300);
            LED1 = ~LED1;  //位取反
        }
    }
}

按下F7编译,设置好仿真:

按下Ctrl+F5进入仿真,按下F5全速运行,这时按下十个按键可以听到十种不同频率的声音,并能看到LED的状态反转。

由于蜂鸣器和按键扫描函数均使用了Delay,单片机空跑,比较浪费时间,下一节我们将用定时器改造我们的代码,使单片机的效率大大提高。

后面例程的学习也类似,看示例代码,比照芯片手册相应章节的寄存器定义,看懂驱动程序,运行程序,自己可以试着修改一下。这样,用不了多长时间,一款单片机就能学会的。

原作于 2014年10月
CSDN发表于2016年4月
weifengdq

你可能感兴趣的:(单片机,led,按键,蜂鸣器,IAP15L2K61)