找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6018|回复: 3
打印 上一主题 下一主题
收起左侧

求助 一个按键来实现调光和开关灯

[复制链接]
跳转到指定楼层
楼主
本帖最后由 lids 于 2017-2-27 15:24 编辑

这个程序现在可以实现调光和开关灯,但是要3个按键;我准备用一个按键来实现调光和开关灯,想了好久都搞不定,请高手们帮忙写一下,谢谢。
/*************************************/
#include <reg52.h>
unsigned char pwm_led_val = 0;//LED占空比值 0-50 0最亮,pwm_led_val值越大,调光的速度越慢
unsigned char pwm_t;//周期
unsigned char num;
bit flag;
sbit key_s2 = P3^0;         //减键
sbit key_s3 = P3^1;         //加键
sbit key_s4 = P3^2;         //开关键
void delay(unsigned int z)//毫秒级延时
{
        unsigned int x,y;
        for(x = z; x > 0; x--)
                for(y = 114; y > 0 ; y--);
}        

//定时器0中断
void timer0() interrupt 1
{
        pwm_t++;
        if(pwm_t == 100)
        {
                pwm_t = 0; P1 = 0xff;
        }
        if(pwm_led_val == pwm_t)
                P1 = 0;                                         
}
void main()
{
        TMOD |= 0x02;//8位自动重装模式
        TH0 = 240;
        TL0 = 240;//11.0592M晶振下占空比最大比值是50,输出1150HZ
        TR0 = 1;//启动定时器0
        ET0 = 1;//允许定时器0中断
        EA        = 1;//总中断允许
        while(1)
        {
                if(flag==0)
                {
               
                if(key_s2 == 0)         //S2按下LED变暗
                {
                        delay(5);
                        if(key_s2 == 0)
                        {
                                if(pwm_led_val < 100)
                                {
                                        pwm_led_val++;
                                }
                        //        while(!key_s2);
                        }
                }
                if(key_s3 == 0)        //S3按键LED变亮
                {
                        delay(5);
                        if(key_s3 == 0)
                        {
                                if(pwm_led_val > 0)
                                {
                                        pwm_led_val--;
                                }
                        //        while(!key_s3);
                        }
                  }
                }
               
                else{
                                P1 = 0xff;
                        }        
                        

               
                       
/*开关灯程序,按1次灯亮,再按1次灯灭,如此循环*/                           
                         if(num==0)                           
              {
               if(key_s4==0)
               {
                 delay(5);
                   if(key_s4==0)
                   {   
                                       num++;
                       flag=~flag;
                       TR0=0;
                       while(!key_s4);
                    }
                }
               }


              if(num==1)
              {
               if(key_s4==0)
               {
                 delay(5);
                 if(key_s4==0)
                 {  
                                    num=0;
                    flag=~flag;
                    TR0=1;
                    while(!key_s4);
                  }
                }
               }        
                                
        }
}

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:146949 发表于 2017-2-27 23:24 | 只看该作者
本帖最后由 wosiyabo 于 2017-3-1 16:30 编辑


//项目:单按键手电控制开关机和调灯光暗模式
//单片机型号:STC15F104W  供电5V 内部晶振选12.00MHz
#include "reg51.h"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
uint zkb;
sfr P3M0        =   0xB2;   //0000,0000 端口3模式寄存器0
sfr P3M1        =   0xB1;   //0000,0000 端口3模式寄存器1
sfr   AUXR      = 0x8E;               //辅助寄存器
sfr IAP_DATA    =   0xC2;           //IAP数据寄存器
sfr IAP_ADDRH   =   0xC3;           //IAP地址寄存器高字节
sfr IAP_ADDRL   =   0xC4;           //IAP地址寄存器低字节
sfr IAP_CMD     =   0xC5;           //IAP命令寄存器
sfr IAP_TRIG    =   0xC6;           //IAP命令触发寄存器
sfr IAP_CONTR   =   0xC7;           //IAP控制寄存器
#define CMD_IDLE    0               //空闲模式
#define CMD_READ    1               //IAP字节读命令
#define CMD_PROGRAM 2               //IAP字节编程命令
#define CMD_ERASE   3               //IAP扇区擦除命令
#define ENABLE_IAP  0x82            //if SYSCLK<20MHz

sbit        P32 = P3^2;  //按键
sbit        P33 = P3^3;  //输出电源控制
sbit        P34 = P3^4;         //PWM输出 781Hz 10/255 分辩率

void Delayms(uint ms) //1mS@12.000MHz
{
   unsigned char i, j;
   while(ms--)
   {i = 12;
                j = 169;
                do
                {
                        while (--j);
                } while (--i);
   }
}
void IapIdle()//关闭IAP
{
    IAP_CONTR = 0;                  //关闭IAP功能
    IAP_CMD = 0;                    //清除命令寄存器
    IAP_TRIG = 0;                   //清除触发寄存器
    IAP_ADDRH = 0x80;               //将地址设置到非IAP区域
    IAP_ADDRL = 0;
}
uchar IapReadByte(uint addr)//从ISP/IAP/EEPROM区域读取一字节
{
    uchar dat;                       //数据缓冲区
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_READ;             //设置IAP命令
    IAP_ADDRL = addr;               //设置IAP低地址
    IAP_ADDRH = addr >> 8;          //设置IAP高地址
    IAP_TRIG = 0x5a;                //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                //写触发命令(0xa5)
    _nop_();                        //等待ISP/IAP/EEPROM操作完成
    dat = IAP_DATA;                 //读ISP/IAP/EEPROM数据
    IapIdle();                      //关闭IAP功能
    return dat;                     //返回
}
void IapProgramByte(uint addr, uchar dat)//写一字节数据到ISP/IAP/EEPROM区域
{
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_PROGRAM;          //设置IAP命令
    IAP_ADDRL = addr;               //设置IAP低地址
    IAP_ADDRH = addr >> 8;          //设置IAP高地址
    IAP_DATA = dat;                 //写ISP/IAP/EEPROM数据
    IAP_TRIG = 0x5a;                //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                //写触发命令(0xa5)
    _nop_();                        //等待ISP/IAP/EEPROM操作完成
    IapIdle();
}
void IapEraseSector(uint addr)//扇区擦除
{
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_ERASE;            //设置IAP命令
    IAP_ADDRL = addr;               //设置IAP低地址
    IAP_ADDRH = addr >> 8;          //设置IAP高地址
    IAP_TRIG = 0x5a;                //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                //写触发命令(0xa5)
    _nop_();                        //等待ISP/IAP/EEPROM操作完成
    IapIdle();
}
void Timer0Init(void)                //5微秒@12.000MHz
{
        AUXR |= 0x80;                //定时器时钟1T模式
        TMOD &= 0xF0;                //设置定时器模式
        TL0 = 0xC4;                //设置定时初值
        TH0 = 0xFF;                //设置定时初值
        TF0 = 0;                //清除TF0标志
        TR0 = 1;                //定时器0开始计时
}
void main()
{
          bit b;
    uchar  num,key_num=0;
    P3M0 = 0x18;//P3M0置1时为强上拉输出  【7:0】 0001 1000   P34和P33为高
    P3M1 = 0x00;
          zkb=IapReadByte(0x0001);
    P33=1;
    Timer0Init();
    ET0 = 1;         //使能定时器0中断
    EA = 1;               
                P32=1;
                while(!P32)
                {
     Delayms(100);// 防止开机长按进入调光模式
    }
                if(zkb==255)b=1;//记录上一次是否最大,如果是最大,那么长按进入调暗
    while (1)
    {
                                if(!P32)
                                                {
                                                        Delayms(10);   // 开关防抖动
                                                        if(!P32)
                                                                {
                                                                        while(!P32 && b==0) //以b=0作为判断上一次是调暗
                                                                                                {
                                                                                                        key_num++;
                                                                                                        Delayms(10);
                                                                                                        if(key_num>60)//实际测试要2秒才进入调光模式
                               {
                                                                                                                                   key_num=30;
                                   zkb+=10;    //因为试过加1次和加5次都不明显,加10次比较好辩认有没有工作
                                                                                                                                   if(zkb>254)//限制最大值
                                                                                                                                                 {
                                                                                                                                                          zkb=0;
                                                                                                                                                          Delayms(20);        //调到最大时闪一下提示                                                 
                                        zkb=255;
                                                                                                                                                          Delayms(20);       
                                     }
                               }                               
                                                                                                }
                                                                        while(!P32 && b==1) //以b=1作为判断上一次是调光
                                                                                                {
                                                                                                        key_num++;
                                                                                                        Delayms(10);
                                                                                                        if(key_num>60)
                               {
                                                                                                                                   key_num=30;
                                   zkb-=10;
                                                                                                                                   if(zkb<10)//限制最小值
                                                                                                                                                 {
                                                                                                                                                          zkb=0;
                                                                                                                                                          Delayms(20);                //调到最小时闪一下提示                                                                 
                                        zkb=10;
                                                                                                                                                          Delayms(20);         
                                     }                                                                                                                                               
                               }                                                                                                       
                                                                                                }               
                                                                                                b=~b; //反转做标记,记录调光或者是调暗
                                                                                                if(key_num<30) //短按小于1秒时进入保存数据和关机
                                                                                                            {
                                                                                                                                 
                                                                                                                                 num = zkb;  ////这里是数据交换放在num内,因为写EEPROM时zkb的值会瞬间变为FF一下子
                                                                                                                                 zkb=0;    //防止关机闪强光
                                                                                                                                 IapEraseSector(0x0001); // 清除EEPROM
                                                                                                                                 IapProgramByte(0x0001, num); // 写入EEPROM
                                 P33=0; //关机
                              }
                        key_num=0;//清计时,下一次如果是短按则关机
                                                                 }
                                                         }                                         
                                }               
}
void tm0_isr() interrupt 1 using 1
{
        static uchar i;  /*中断次数计数器变量*/
        TL0 = 0xC4;                //设置定时初值
        TH0 = 0xFF;                //设置定时初值       
        i++;
         if(i<=zkb)P34=1;   //判断zkb的值选择是否输出高电平
      else P34=0;     //否则输出低电平
}

评分

参与人数 1黑币 +80 收起 理由
admin + 80 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

板凳
ID:74758 发表于 2017-2-28 11:02 | 只看该作者
按键用短按跟长按的方式来区分开来就可以了。。比如短按是变亮/变暗,长按开关机这样
回复

使用道具 举报

地板
ID:167121 发表于 2017-2-28 14:21 | 只看该作者
一个按键轮询下去就好了:
第一次按:微亮
第二次按:中亮
第三次按:高亮
第四次按:灭
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表