找回密码
 立即注册

QQ登录

只需一步,快速开始

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

求个手电 断电时长判断的单片机代码可以吗?

  [复制链接]
跳转到指定楼层
楼主
stc单片机.控制pwm占空比的代码?
现在没弄懂半按这个怎么判定!!!

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

使用道具 举报

沙发
ID:879348 发表于 2024-8-12 08:09 | 只看该作者
我做过电筒一段时间,这个需要硬件判断关机时间,STC做这种功能不是很方便,需要的硬件比较多
回复

使用道具 举报

板凳
ID:161164 发表于 2024-8-12 10:30 | 只看该作者
如果要测关机时间就要加电容电阻来检测掉电时间
上电时引脚输入模式,检测电容电平,
检测完后引脚转为输出模式对电容充电
电容并联一个电阻来让电容在关电时放电
回复

使用道具 举报

地板
ID:1130333 发表于 2024-8-13 09:59 | 只看该作者
wufa1986 发表于 2024-8-12 08:09
我做过电筒一段时间,这个需要硬件判断关机时间,STC做这种功能不是很方便,需要的硬件比较多

用哪个比较方便呢?
我见很多手电用的都是九齐或者应广
回复

使用道具 举报

5#
ID:1130333 发表于 2024-8-13 10:00 | 只看该作者
wufa1986 发表于 2024-8-12 08:09
我做过电筒一段时间,这个需要硬件判断关机时间,STC做这种功能不是很方便,需要的硬件比较多

可以提供一份代码给我吗?
谢谢
回复

使用道具 举报

6#
ID:1130333 发表于 2024-8-13 10:01 | 只看该作者
lkc8210 发表于 2024-8-12 10:30
如果要测关机时间就要加电容电阻来检测掉电时间
上电时引脚输入模式,检测电容电平,
检测完后引脚转为输 ...

能否提供一份代码?
我做的另一个手电是 要开机3秒才能判定是否eeprom保存
回复

使用道具 举报

7#
ID:161164 发表于 2024-8-13 11:30 | 只看该作者
vb2002 发表于 2024-8-13 10:01
能否提供一份代码?
我做的另一个手电是 要开机3秒才能判定是否eeprom保存
  1. sbit CAP = P3^2;
  2. u8 mode = 0;
  3. void main()
  4. {
  5.         mode = IapRead(EEPromAddr);
  6.         if(CAP)
  7.         {
  8.                 mode++;
  9.                 if(mode>=4)mode=0;
  10.                 IapProgram(EEPromAddr,mode);
  11.         }
  12.         P3M0 = 0x04; P3M1 = 0x00; //P32推挽输出对电容充电

  13.         switch (mode)
  14.         {
  15.                 case 0:
  16.                         break;
  17.                 case 1:
  18.                         break;
  19.                 case 2:
  20.                         break;
  21.                 case 3:
  22.                         break;
  23.                 default:
  24.                         break;
  25.         }
  26.     while (1)
  27.     {
  28.         }
  29. }
复制代码
回复

使用道具 举报

8#
ID:404160 发表于 2024-8-15 12:35 | 只看该作者
根据提供的描述,我们需要编写一段C51代码来实现以下功能:

按下开关开机,再次按下关机,这个过程中PWM亮度保持不变,即只读取EEPROM中的值。
如果在开机状态下,半按(断电时间小于500ms)则进入下一个状态,切换PWM的占空比,实现4个档位的循环切换。
如果关机时长大于3秒,则写入当前的PWM占空比到EEPROM;如果小于3秒,则写入新的EEPROM值。
如果关机后马上开机,不进行任何操作。
下面是一段简化的C51代码示例,用于实现上述功能。请注意,这只是一个基础示例,实际应用中可能需要根据具体的硬件和EEPROM库进行调整。

#include <reg51.h>

#define PWM_PIN P1 // 假设PWM控制引脚连接到P1端口
#define BUTTON_PIN P3_2 // 假设按钮连接到P3.2端口
#define EEPROM_ADDR 0x30 // 假设EEPROM写入地址

unsigned char pwm_duty = 10; // PWM占空比
unsigned char pwm_level = 0; // 当前PWM级别
unsigned char eeprom_value = 0; // 从EEPROM读取的值
bit is_power_on = 0; // 电源状态标志

void DelayMs(unsigned int ms) {
    // 延时函数,需要根据实际的晶振频率调整
    // 这里只是一个示例,具体实现需要根据硬件来编写
}

void SetPWM(unsigned char duty) {
    // 设置PWM占空比的函数
    // 这里只是一个示例,具体实现需要根据硬件来编写
}

void EEPROMWrite(unsigned char addr, unsigned char value) {
    // 写入EEPROM的函数
    // 这里只是一个示例,具体实现需要根据EEPROM库来编写
    EERDB = value; // 设置EEPROM数据寄存器
    EEMPE = 1;    // 允许EEPROM编程
    EENH = 0;     // 选择高8位地址
    EEL = 1;      // 选择低8位地址
    EEAR = addr;  // 设置EEPROM地址寄存器
    EEWE = 1;     // 写入使能
    EEWE = 0;     // 清除写入使能
}

unsigned char EEPROMRead(unsigned char addr) {
    // 从EEPROM读取的函数
    EEAR = addr; // 设置EEPROM地址寄存器
    EEN2 = 1;    // 启用EEPROM
    EEN1 = 1;
    EEN0 = 1;
    unsigned char value = EERDB; // 读取数据
    EEN2 = 0;
    EEN1 = 0;
    EEN0 = 0;
    return value;
}

void main() {
    SetPWM(eeprom_value); // 初始设置PWM为EEPROM中的值
    while(1) {
        if (!BUTTON_PIN) { // 检测按钮是否被按下
            DelayMs(20); // 消抖
            if (!BUTTON_PIN) {
                if (is_power_on) {
                    // 关机操作
                    unsigned int shutdown_time = 0;
                    while (!BUTTON_PIN) {
                        shutdown_time++;
                        if (shutdown_time > 3000) { // 大于3秒
                            EEPROMWrite(EEPROM_ADDR, pwm_duty);
                            break;
                        }
                    }
                    SetPWM(0); // 关闭PWM
                    is_power_on = 0;
                } else {
                    // 开机操作
                    is_power_on = 1;
                    SetPWM(pwm_duty); // 根据EEPROM设置PWM
                }
            }
        } else {
            if (is_power_on) {
                // 半按操作,切换PWM占空比
                DelayMs(500); // 等待500ms
                if (BUTTON_PIN) {
                    pwm_level++;
                    if (pwm_level > 3) {
                        pwm_level = 0;
                    }
                    pwm_duty = (pwm_duty + 20) % 101; // 增加20%,循环4个级别
                    SetPWM(pwm_duty);
                }
            }
        }
    }
}
回复

使用道具 举报

9#
ID:1130333 发表于 2024-8-16 13:06 | 只看该作者
飞云居士 发表于 2024-8-15 12:35
根据提供的描述,我们需要编写一段C51代码来实现以下功能:

按下开关开机,再次按下关机,这个过程中PWM ...

感觉这个像是ai写的.
而且里面提到的是3秒
回复

使用道具 举报

10#
ID:1110945 发表于 2024-8-16 16:41 | 只看该作者
本帖最后由 明日之星8 于 2024-8-16 17:38 编辑

加二极管和电池(比如2032电池),检测到无外接供电时单片机
就进入掉电模式,同时打开掉电唤醒定时器并计时。
比如STC8H1K08可以做到2微安,2032电池可以连续计时三到五年以上,
时间误差不到10%

有RTC功能的单片机(比如STC8H1K08T),外接32k晶振可以做到相对精确的计时。
回复

使用道具 举报

11#
ID:1130333 发表于 2024-8-18 00:43 | 只看该作者
明日之星8 发表于 2024-8-16 16:41
加二极管和电池(比如2032电池),检测到无外接供电时单片机
就进入掉电模式,同时打开掉电唤醒定时器并计时 ...

这个不符合实际情况啊
实际情况就是一个18650电池, 加一个灯珠,中间有个驱动.
再要去弄其他电池麻烦哦.
回复

使用道具 举报

12#
ID:401564 发表于 2024-8-19 13:03 | 只看该作者
首先,你要清楚你的要求是什么,在我的印象中,没有什么手电是对关机断电时长有要求的
按照正常的实际情况操作是这样的:
1,先看你18650是怎么接在电路上的,如果是焊线的,那就不需要用到EEPROM,直接保存到一个全局变量就可以了,如果涉及充电,这个变量就得有三个工作模式:1点灯,2充电,3关机
STC进入掉电模式,唤醒后全局变量的值是不会变的
2,如果电池是可以拿出来的那种,那就是每次按下按键,点灯模式切换后就把点灯模式保存到EEPROM,下次开机时,先读取EEPROM的模式,再进行点灯
但有一点要记得,STC的是"EEPROM"是FLASH,不是像24C01那种的,百度一下就知道了
回复

使用道具 举报

13#
ID:1130333 发表于 2024-8-20 10:42 | 只看该作者
Y_G_G 发表于 2024-8-19 13:03
首先,你要清楚你的要求是什么,在我的印象中,没有什么手电是对关机断电时长有要求的
按照正常的实际情况操 ...

手电开关有两种.
你说的那种是电子开关的.可以长期不断电.不设计eeprom也可以保存档位
我说的这个是机械开关,就是开关装在尾部,依靠断电通电来开关手电的
市面销售的开关逻辑是, 123档,现在我调到2档,关机,下次开机也是2档. 如果想换挡,就开机关机(时间低于500ms就换挡到3档) 如果超过500ms就还是2档

现在我能实现的就是,开机 2档,超过3秒就eeprom保存当前2档,,如果开机3秒内在关机开机.那就进行换挡.
虽然都能达到目的, 但是我这个有点麻烦,如果开机超过3秒后,需要换挡,必须重新关机开机,再关机开机换挡.

如果您感兴趣,发视频给您看看?

回复

使用道具 举报

14#
ID:401564 发表于 2024-8-20 12:01 | 只看该作者
vb2002 发表于 2024-8-20 10:42
手电开关有两种.
你说的那种是电子开关的.可以长期不断电.不设计eeprom也可以保存档位
我说的这个是机 ...

断电了,单片机就没有用了,就没有"断电时间"这个概念了
如果要有记忆功能,就只能是重新关机开机,再关机开机换挡
没有别的选择了,除非换开关种类
回复

使用道具 举报

15#
ID:384109 发表于 2024-8-20 13:05 | 只看该作者
感觉你这个想复杂了吧,跟普通手电操作一样,只不过增加一个标志而已
回复

使用道具 举报

16#
ID:161164 发表于 2024-8-20 14:22 | 只看该作者
vb2002 发表于 2024-8-20 10:42
手电开关有两种.
你说的那种是电子开关的.可以长期不断电.不设计eeprom也可以保存档位
我说的这个是机 ...

试了我的代码了吗?
回复

使用道具 举报

17#
ID:23640 发表于 2024-8-20 15:55 | 只看该作者
楼主可以在MCU供电脚串一个二极管,MCU供电加个几微法的大电容,加二极管的目的就是防止开关断开后电容给后级供电,只要满足电容只给MCU供电,即使外部电源断了,几微法的电容也可以维持几秒钟时间,这时候你就可以做些判断保存数据的动作
回复

使用道具 举报

18#
ID:1130333 发表于 2024-8-20 16:42 | 只看该作者
lkc8210 发表于 2024-8-20 14:22
试了我的代码了吗?

试了,试出来就是普通的eeprom读写switch里面的循环.
没有加电容实现不了那个半按..
回复

使用道具 举报

19#
ID:69038 发表于 2024-8-20 16:43 | 只看该作者
咋看都象是一个按键实现开机、关机、调亮度的功能。。。
回复

使用道具 举报

20#
ID:1130333 发表于 2024-8-20 16:45 | 只看该作者
人中狼 发表于 2024-8-20 13:05
感觉你这个想复杂了吧,跟普通手电操作一样,只不过增加一个标志而已

我能想通,但是代码搞不定.
标志位就是断电那个状态怎么读取出来.
之前有人发了一个帖子,,当时我还不懂啥意思,都已经断电了.为啥还要在断电的时候开启睡眠模式.
现在懂了.是让电容继续给单片机供电
回复

使用道具 举报

21#
ID:69038 发表于 2024-8-20 16:46 | 只看该作者
倒不如关机后短按开机、开机后短按切换亮度、长按关机。。。
回复

使用道具 举报

22#
ID:1130333 发表于 2024-8-20 16:51 | 只看该作者
yaosongjin 发表于 2024-8-20 15:55
楼主可以在MCU供电脚串一个二极管,MCU供电加个几微法的大电容,加二极管的目的就是防止开关断开后电容给后 ...

如果设置睡眠模式,是不是10uf可以坚持很久很久?
甚至都不用eeprom都行了?
就是这个断电判断不会弄
回复

使用道具 举报

23#
ID:161164 发表于 2024-8-20 17:13 | 只看该作者
vb2002 发表于 2024-8-20 16:42
试了,试出来就是普通的eeprom读写switch里面的循环.
没有加电容实现不了那个半按..

为啥不加电容?
回复

使用道具 举报

24#
ID:23640 发表于 2024-8-20 17:39 | 只看该作者
vb2002 发表于 2024-8-20 16:51
如果设置睡眠模式,是不是10uf可以坚持很久很久?
甚至都不用eeprom都行了?
就是这个断电判断不会弄

MCU第4脚用于判断开关状态。

5fee380a84e8dab4c9fc65f1daf0e8ca.png (60.68 KB, 下载次数: 8)

5fee380a84e8dab4c9fc65f1daf0e8ca.png
回复

使用道具 举报

25#
ID:23640 发表于 2024-8-20 17:42 | 只看该作者
图中MCU第4脚用于判断开关状态,开关断开4脚是低电平,开关接通4脚是高电平。
回复

使用道具 举报

26#
ID:1130333 发表于 2024-8-20 18:47 | 只看该作者
lkc8210 发表于 2024-8-20 17:13
为啥不加电容?


这个是我的代码, 现在可以变相换挡和保存的 ..电路图是这个,电容直接替换那个0.1uf吗?



  1. #include "stc8h.h"
  2. #include "intrins.h"
  3. #include "eeprom.h"
  4. #include <stdio.h>



  5. #define MAIN_Fosc 11059200UL
  6. #define BRT         (65536 - MAIN_Fosc / 115200 / 4)
  7. //#define EEPROMId           0x0E00

  8. typedef unsigned char u8;
  9. typedef unsigned int u16;


  10. u8 PWMData[] = {1,5,33,};//添加数组,设置需要的档位
  11. u16 delayTime = 3000;//这里修改需要的工作时间,单位(ms)


  12. u8 dat;
  13. u16 EEPROMId = 0020;
  14. u16 time;

  15. bit key_flag;

  16. void delayms(u16 ms);   
  17. void sys_init();
  18. void PWM_init(void);
  19. void Timer0_Init(void);


  20. void UartInit()
  21. {
  22.     SCON = 0x5a;
  23.     T2L = BRT;
  24.     T2H = BRT >> 8;
  25.     AUXR = 0x15;
  26. }

  27. u8 LEDControl()
  28. {       
  29.         u8 i;
  30.         u8 length = (sizeof(PWMData)/sizeof(PWMData[0]));
  31.                 delayms(20);
  32. //        u16 EEPROMId = 0XE00;                                //将指针指向第8扇区的第一个字节
  33. //        SetMode(CMD_READ);                                //设置为读取数据
  34.        
  35.         while(1)
  36.         {       
  37.                 dat = IapRead(EEPROMId + 1);                        //读取下一字节数据255
  38. //                printf("dat=%bu\r\n",dat);
  39. //                printf("id=%u\r\n",EEPROMId);               
  40.                 if(dat == 0XFF)                                        //下一字节字节未写入数据255
  41.                 {
  42.                         dat = IapRead(EEPROMId);                //读取当前字节数据
  43. //                        SetMode(CMD_PROGRAM);                        //写入数据
  44.                        
  45.                         for(i = 0; i < length-1; i++)
  46.                         {        if(dat == i)
  47.                                 {        IapProgram(EEPROMId+1,i+1);
  48.                                         return dat;
  49.                                 }
  50.                         }
  51. //                        dat=0;
  52.                         IapProgram(EEPROMId+1,0);
  53.                          
  54.                         return dat;                                        //返回当前字节数据
  55.                 }
  56.         else                                                        //下一字节不为空,指针加一,继续判断下一个字节
  57.                 {        EEPROMId++;
  58.                 }


  59.                 if(EEPROMId >= 0XFFD)                                //如果当前字节到达EEPROM末尾,擦除扇区所有数据
  60.                 {       
  61. //                        SetMode(CMD_ERASE);                        //扇区擦除
  62.                         IapErase(0x0000);                                //擦除扇区
  63.                         IapErase(0x0200);                                //擦除扇区       
  64.                         IapErase(0x0400);                                //擦除扇区       
  65.                         IapErase(0x0600);                                //擦除扇区       
  66.                         IapErase(0x0800);                                //擦除扇区       
  67.                         IapErase(0x0A00);                                //擦除扇区       
  68.                         IapErase(0x0C00);                                //擦除扇区       
  69.                         IapErase(0x0E00);                                //擦除扇区                               
  70.                         return 1;
  71.                 }
  72.         }
  73. }


  74. void main()
  75. {               

  76.         sys_init();  

  77.       UartInit();
  78.        
  79.     LEDControl();
  80.                      PWM_init();
  81.        
  82.                 PWMA_CCR1 = PWMData[dat] ;  

  83.           while(1)
  84.         {



  85.         }       
  86. }



  87. void sys_init(void)
  88. {
  89.         P_SW2=0x80;

  90.     P3M0 = 0x00; P3M1 = 0x00;       P1M0 = 0x00; P1M1 = 0x00;
  91.        
  92.   
  93.          Timer0_Init();
  94.        
  95.         IT0=1;EX0=1;
  96.         INTCLKO|=0x40;   //EX4=1; 允许INT4外部中断
  97. //        IP2H=0x00;               
  98.         IP2=0x10;

  99.        
  100.         EA=1;                        //打开总中断

  101. }


  102. //// 初始化PWM功能
  103. void PWM_init(void) {
  104.     PWMA_CCER1 = 0x00;                          // 写CCMRx前必须先清零CCERx关闭通道
  105.     PWMA_CCMR1 = 0x60;                          // 设置CC1为PWMA输出模式
  106.     PWMA_PS        = 0x00;                      //  
  107.     PWMA_CCER1 = 0x0c;                          // 使能CC4通道双极
  108.     PWMA_CCR1 = 0;                              // 初始化CCR4计数值为0
  109.     PWMA_ARR = 256;                           // 设置周期时间为12000个计数周期
  110.     PWMA_ENO = 0x02;                            // 使能PWM4P+N端口输出
  111.     PWMA_PSCR = 0;                              // PWM时钟预分频寄存器设置为0
  112.     PWMA_BKR = 0x80;                            // 使能主输出
  113.     PWMA_CR1 = 0x01;                            // 开始计时
  114.        
  115. }


  116. u8 TimeNum = 1;//这里是定时器中断时间,单位(ms)

  117. void Timer0_Isr(void) interrupt 1
  118. {        u8 Num = delayTime/TimeNum;//中断执行多少次到达工作时间
  119.         if(time < Num)
  120.         {        time++;
  121.         }else if(time == Num)        //到达要求的时间
  122.         {       
  123.                 IapProgram(EEPROMId+2,dat);
  124.                 time++;
  125.         }
  126. }

  127. void Timer0_Init(void)                //1毫秒@11.0592MHz
  128. {
  129.         AUXR |= 0x80;                        //定时器时钟1T模式
  130.         TMOD &= 0xF0;                        //设置定时器模式
  131.         TL0 = 0xCD;                                //设置定时初始值
  132.         TH0 = 0xD4;                                //设置定时初始值
  133.         TF0 = 0;                                //清除TF0标志
  134.         TR0 = 1;                                //定时器0开始计时
  135.         ET0 = 1;                                //使能定时器0中断
  136. }


  137. void INT4_Isr(void) interrupt 16
  138. {
  139. IAP_CONTR=0x60;                       
  140. }


  141. void INT0_Isr(void) interrupt 0
  142. {
  143.                   printf("dat=%bu\n",dat);
  144.                 printf("id=%u\n",EEPROMId);               
  145. }

  146. void delayms(u16 ms)
  147.         {u16 i;
  148.         do{
  149.                 i = MAIN_Fosc /10000;
  150.                 while(--i);
  151.         }                while(--ms);
  152. }
  153.        
复制代码



回复

使用道具 举报

27#
ID:1130333 发表于 2024-8-20 18:49 | 只看该作者
yaosongjin 发表于 2024-8-20 17:39
MCU第4脚用于判断开关状态。

主要是代码方面弄不好.
  1. #include "stc8h.h"
  2. #include "intrins.h"
  3. #include "eeprom.h"
  4. #include <stdio.h>



  5. #define MAIN_Fosc 11059200UL
  6. #define BRT         (65536 - MAIN_Fosc / 115200 / 4)
  7. //#define EEPROMId           0x0E00

  8. typedef unsigned char u8;
  9. typedef unsigned int u16;


  10. u8 PWMData[] = {1,5,33,};//添加数组,设置需要的档位
  11. u16 delayTime = 3000;//这里修改需要的工作时间,单位(ms)


  12. u8 dat;
  13. u16 EEPROMId = 0020;
  14. u16 time;

  15. bit key_flag;

  16. void delayms(u16 ms);   
  17. void sys_init();
  18. void PWM_init(void);
  19. void Timer0_Init(void);


  20. void UartInit()
  21. {
  22.     SCON = 0x5a;
  23.     T2L = BRT;
  24.     T2H = BRT >> 8;
  25.     AUXR = 0x15;
  26. }

  27. u8 LEDControl()
  28. {       
  29.         u8 i;
  30.         u8 length = (sizeof(PWMData)/sizeof(PWMData[0]));
  31.                 delayms(20);
  32. //        u16 EEPROMId = 0XE00;                                //将指针指向第8扇区的第一个字节
  33. //        SetMode(CMD_READ);                                //设置为读取数据
  34.        
  35.         while(1)
  36.         {       
  37.                 dat = IapRead(EEPROMId + 1);                        //读取下一字节数据255
  38. //                printf("dat=%bu\r\n",dat);
  39. //                printf("id=%u\r\n",EEPROMId);               
  40.                 if(dat == 0XFF)                                        //下一字节字节未写入数据255
  41.                 {
  42.                         dat = IapRead(EEPROMId);                //读取当前字节数据
  43. //                        SetMode(CMD_PROGRAM);                        //写入数据
  44.                        
  45.                         for(i = 0; i < length-1; i++)
  46.                         {        if(dat == i)
  47.                                 {        IapProgram(EEPROMId+1,i+1);
  48.                                         return dat;
  49.                                 }
  50.                         }
  51. //                        dat=0;
  52.                         IapProgram(EEPROMId+1,0);
  53.                          
  54.                         return dat;                                        //返回当前字节数据
  55.                 }
  56.         else                                                        //下一字节不为空,指针加一,继续判断下一个字节
  57.                 {        EEPROMId++;
  58.                 }


  59.                 if(EEPROMId >= 0XFFD)                                //如果当前字节到达EEPROM末尾,擦除扇区所有数据
  60.                 {       
  61. //                        SetMode(CMD_ERASE);                        //扇区擦除
  62.                         IapErase(0x0000);                                //擦除扇区
  63.                         IapErase(0x0200);                                //擦除扇区       
  64.                         IapErase(0x0400);                                //擦除扇区       
  65.                         IapErase(0x0600);                                //擦除扇区       
  66.                         IapErase(0x0800);                                //擦除扇区       
  67.                         IapErase(0x0A00);                                //擦除扇区       
  68.                         IapErase(0x0C00);                                //擦除扇区       
  69.                         IapErase(0x0E00);                                //擦除扇区                               
  70.                         return 1;
  71.                 }
  72.         }
  73. }


  74. void main()
  75. {               

  76.         sys_init();  

  77.       UartInit();
  78.        
  79.     LEDControl();
  80.                      PWM_init();
  81.        
  82.                 PWMA_CCR1 = PWMData[dat] ;  

  83.           while(1)
  84.         {



  85.         }       
  86. }



  87. void sys_init(void)
  88. {
  89.         P_SW2=0x80;

  90.     P3M0 = 0x00; P3M1 = 0x00;       P1M0 = 0x00; P1M1 = 0x00;
  91.        
  92.   
  93.          Timer0_Init();
  94.        
  95.         IT0=1;EX0=1;
  96.         INTCLKO|=0x40;   //EX4=1; 允许INT4外部中断
  97. //        IP2H=0x00;               
  98.         IP2=0x10;

  99.        
  100.         EA=1;                        //打开总中断

  101. }


  102. //// 初始化PWM功能
  103. void PWM_init(void) {
  104.     PWMA_CCER1 = 0x00;                          // 写CCMRx前必须先清零CCERx关闭通道
  105.     PWMA_CCMR1 = 0x60;                          // 设置CC1为PWMA输出模式
  106.     PWMA_PS        = 0x00;                      //  
  107.     PWMA_CCER1 = 0x0c;                          // 使能CC4通道双极
  108.     PWMA_CCR1 = 0;                              // 初始化CCR4计数值为0
  109.     PWMA_ARR = 256;                           // 设置周期时间为12000个计数周期
  110.     PWMA_ENO = 0x02;                            // 使能PWM4P+N端口输出
  111.     PWMA_PSCR = 0;                              // PWM时钟预分频寄存器设置为0
  112.     PWMA_BKR = 0x80;                            // 使能主输出
  113.     PWMA_CR1 = 0x01;                            // 开始计时
  114.        
  115. }


  116. u8 TimeNum = 1;//这里是定时器中断时间,单位(ms)

  117. void Timer0_Isr(void) interrupt 1
  118. {        u8 Num = delayTime/TimeNum;//中断执行多少次到达工作时间
  119.         if(time < Num)
  120.         {        time++;
  121.         }else if(time == Num)        //到达要求的时间
  122.         {       
  123.                 IapProgram(EEPROMId+2,dat);
  124.                 time++;
  125.         }
  126. }

  127. void Timer0_Init(void)                //1毫秒@11.0592MHz
  128. {
  129.         AUXR |= 0x80;                        //定时器时钟1T模式
  130.         TMOD &= 0xF0;                        //设置定时器模式
  131.         TL0 = 0xCD;                                //设置定时初始值
  132.         TH0 = 0xD4;                                //设置定时初始值
  133.         TF0 = 0;                                //清除TF0标志
  134.         TR0 = 1;                                //定时器0开始计时
  135.         ET0 = 1;                                //使能定时器0中断
  136. }


  137. void INT4_Isr(void) interrupt 16
  138. {
  139. IAP_CONTR=0x60;                       
  140. }


  141. void INT0_Isr(void) interrupt 0
  142. {
  143.                   printf("dat=%bu\n",dat);
  144.                 printf("id=%u\n",EEPROMId);               
  145. }

  146. void delayms(u16 ms)
  147.         {u16 i;
  148.         do{
  149.                 i = MAIN_Fosc /10000;
  150.                 while(--i);
  151.         }                while(--ms);
  152. }
  153.        
复制代码
回复

使用道具 举报

28#
ID:23640 发表于 2024-8-21 08:38 | 只看该作者
vb2002 发表于 2024-8-20 18:49
主要是代码方面弄不好.

你可能没搞清楚程序运行的逻辑,按照这个电路来操作的话:
1.上电后MCU复位进入工作状态
2.当按下电源开关后MCU开始记录4脚电平保持的时间
3.假如维持的低电平为500MS又变高了,就切换模式或者亮度之类的功能并且写入内存
4.假如维持的电平超过500MS说明是手电要关机,就不再做任何处理
5.如果要做双击的话,同样在按键处理这一块想办法
回复

使用道具 举报

29#
ID:161164 发表于 2024-8-21 11:11 | 只看该作者
vb2002 发表于 2024-8-20 18:47
这个是我的代码, 现在可以变相换挡和保存的 ..电路图是这个,电容直接替换那个0.1uf吗?

我的代码是检测P32脚电容的电平来判断掉电时间的
回复

使用道具 举报

30#
ID:1130333 发表于 2024-8-21 22:01 | 只看该作者
lkc8210 发表于 2024-8-21 11:11
我的代码是检测P32脚电容的电平来判断掉电时间的

按您的代码现在一直是亮度5,可以点亮
但是不能换挡. 能帮看看吗?  是我没有上真机实验吗? 我用的开发板弄的
  1. #include "stc8h.h"
  2. #include "intrins.h"
  3. #include "eeprom.h"
  4. #include <stdio.h>



  5. #define MAIN_Fosc 11059200UL
  6. #define BRT         (65536 - MAIN_Fosc / 115200 / 4)
  7. //#define EEPROMId           0x0E00

  8. typedef unsigned char u8;
  9. typedef unsigned int u16;


  10. //u8 PWMData[] = {1,5,33,};//添加数组,设置需要的档位
  11. //u16 delayTime = 1000;//这里修改需要的工作时间,单位(ms)


  12. u8 dat;
  13. //u16 EEPROMId = 0020;
  14. u16 EEPromAddr;
  15. u16 time;
  16. u8 mode = 0;
  17. sbit CAP = P3^2;
  18. // bit key_flag;


  19. void delayms(u16 ms);   
  20. void sys_init();
  21. void PWM_init(void);
  22. void Timer0_Init(void);


  23. void UartInit()
  24. {
  25.     SCON = 0x5a;
  26.     T2L = BRT;
  27.     T2H = BRT >> 8;
  28.     AUXR = 0x15;
  29. }

  30. //u8 LEDControl()
  31. //{       
  32. //        u8 i;
  33. //        u8 length = (sizeof(PWMData)/sizeof(PWMData[0]));
  34. //                delayms(20);
  35. ////        u16 EEPROMId = 0XE00;                                //将指针指向第8扇区的第一个字节
  36. ////        SetMode(CMD_READ);                                //设置为读取数据
  37. //       
  38. //        while(1)
  39. //        {       
  40. //                dat = IapRead(EEPROMId + 1);                        //读取下一字节数据255
  41. ////                printf("dat=%bu\r\n",dat);
  42. ////                printf("id=%u\r\n",EEPROMId);               
  43. //                if(dat == 0XFF)                                        //下一字节字节未写入数据255
  44. //                {
  45. //                        dat = IapRead(EEPROMId);                //读取当前字节数据
  46. ////                        SetMode(CMD_PROGRAM);                        //写入数据
  47. //                       
  48. //                        for(i = 0; i < length-1; i++)
  49. //                        {        if(dat == i)
  50. //                                {       
  51. //                                        IapProgram(EEPROMId+1,i+1);
  52. ////                                        IapRead(EEPROMId );
  53. //                                        return dat;
  54. //                                }
  55. //                        }
  56. ////                        dat=0;
  57. //                        IapProgram(EEPROMId+1,0);
  58. //                         
  59. //                        return dat;                                        //返回当前字节数据
  60. //                }
  61. //        else                                                        //下一字节不为空,指针加一,继续判断下一个字节
  62. //                {        EEPROMId++;
  63. //                }


  64. //                if(EEPROMId >= 0XFFD)                                //如果当前字节到达EEPROM末尾,擦除扇区所有数据
  65. //                {       
  66. ////                        SetMode(CMD_ERASE);                        //扇区擦除
  67. //                        IapErase(0x0000);                                //擦除扇区
  68. //                        IapErase(0x0200);                                //擦除扇区       
  69. //                        IapErase(0x0400);                                //擦除扇区       
  70. //                        IapErase(0x0600);                                //擦除扇区       
  71. //                        IapErase(0x0800);                                //擦除扇区       
  72. //                        IapErase(0x0A00);                                //擦除扇区       
  73. //                        IapErase(0x0C00);                                //擦除扇区       
  74. //                        IapErase(0x0E00);                                //擦除扇区                               
  75. //                        return 1;
  76. //                }
  77. //        }
  78. //}


  79. void main()
  80. {               

  81.         sys_init();  

  82.       UartInit();
  83.        
  84. //     LEDControl();
  85.                      PWM_init();
  86.        
  87. //                PWMA_CCR1 = PWMData[dat] ;  

  88.           mode = IapRead(EEPromAddr);
  89.         if(CAP)
  90.         {
  91.                 mode++;
  92.                 if(mode>=4)mode=0;
  93.                 IapProgram(EEPromAddr,mode);
  94.         }
  95.         P3M0 = 0x04; P3M1 = 0x00; //P32推挽输出对电容充电

  96.         switch (mode)
  97.         {
  98.                 case 0: PWMA_CCR1 = 2 ;  
  99.                         break;
  100.                 case 1: PWMA_CCR1 = 5 ;  
  101.                         break;
  102.                 case 2: PWMA_CCR1 = 12 ;  
  103.                         break;
  104.                 case 3: PWMA_CCR1 = 32 ;  
  105.                         break;
  106.                 default: PWMA_CCR1 = 112 ;  
  107.                         break;
  108.           }

  109.           while(1)
  110.         {
  111. //           PWMA_CCR1 = mode ;  


  112.         }       
  113. }



  114. void sys_init(void)
  115. {
  116.         P_SW2=0x80;

  117.     P3M0 = 0x00; P3M1 = 0x00;     
  118.         P1M0 = 0x00; P1M1 = 0x00;
  119.        
  120.   
  121.          Timer0_Init();
  122.        
  123.         IT0=1;EX0=1;
  124.         INTCLKO|=0x40;   //EX4=1; 允许INT4外部中断
  125. //        IP2H=0x00;               
  126.         IP2=0x10;

  127.        
  128.         EA=1;                        //打开总中断

  129. }


  130. //// 初始化PWM功能
  131. void PWM_init(void) {
  132.     PWMA_CCER1 = 0x00;                          // 写CCMRx前必须先清零CCERx关闭通道
  133.     PWMA_CCMR1 = 0x60;                          // 设置CC1为PWMA输出模式
  134.     PWMA_PS        = 0x00;                      //  
  135.     PWMA_CCER1 = 0x0c;                          // 使能CC4通道双极
  136.     PWMA_CCR1 = 0;                              // 初始化CCR4计数值为0
  137.     PWMA_ARR = 256;                           // 设置周期时间为12000个计数周期
  138.     PWMA_ENO = 0x02;                            // 使能PWM4P+N端口输出
  139.     PWMA_PSCR = 0;                              // PWM时钟预分频寄存器设置为0
  140.     PWMA_BKR = 0x80;                            // 使能主输出
  141.     PWMA_CR1 = 0x01;                            // 开始计时
  142.        
  143. }


  144. //u8 TimeNum = 1;//这里是定时器中断时间,单位(ms)

  145. //void Timer0_Isr(void) interrupt 1
  146. //{        u8 Num = delayTime/TimeNum;//中断执行多少次到达工作时间
  147. //        if(time < Num)
  148. //        {        time++;
  149. //        }else if(time == Num)        //到达要求的时间
  150. //        {       
  151. //                IapProgram(EEPROMId+2,dat);
  152. ////                IapRead(EEPROMId);
  153. //                time++;
  154. //        }
  155. //}

  156. void Timer0_Init(void)                //1毫秒@11.0592MHz
  157. {
  158.         AUXR |= 0x80;                        //定时器时钟1T模式
  159.         TMOD &= 0xF0;                        //设置定时器模式
  160.         TL0 = 0xCD;                                //设置定时初始值
  161.         TH0 = 0xD4;                                //设置定时初始值
  162.         TF0 = 0;                                //清除TF0标志
  163.         TR0 = 1;                                //定时器0开始计时
  164.         ET0 = 1;                                //使能定时器0中断
  165. }


  166. void INT4_Isr(void) interrupt 16
  167. {
  168. IAP_CONTR=0x60;                       
  169. }


  170. //void INT0_Isr(void) interrupt 0
  171. //{
  172. //                  printf("dat=%bu\n",mode);
  173. //                printf("id=%u\n",EEPromAddr);               
  174. //}

  175. void delayms(u16 ms)
  176.         {u16 i;
  177.         do{
  178.                 i = MAIN_Fosc /10000;
  179.                 while(--i);
  180.         }                while(--ms);
  181. }
  182.        
复制代码
回复

使用道具 举报

31#
ID:1130333 发表于 2024-8-21 22:51 | 只看该作者
yaosongjin 发表于 2024-8-21 08:38
你可能没搞清楚程序运行的逻辑,按照这个电路来操作的话:
1.上电后MCU复位进入工作状态
2.当按下电源 ...

就是代码不会弄呢
可以给个代码吗?
实现半按换挡
我这个麻烦死了
回复

使用道具 举报

32#
ID:23640 发表于 2024-8-22 08:42 | 只看该作者
vb2002 发表于 2024-8-21 22:51
就是代码不会弄呢
可以给个代码吗?
实现半按换挡

我没写过这种代码,但是有了具体思路不是很简单的事情吗?按键判断的代码本站也有很多的
回复

使用道具 举报

33#
ID:161164 发表于 2024-8-22 09:20 | 只看该作者
vb2002 发表于 2024-8-21 22:01
按您的代码现在一直是亮度5,可以点亮
但是不能换挡. 能帮看看吗?  是我没有上真机实验吗? 我用的开发板 ...

我那个只是示范,你还要加上之前的EEPRom循环读写的代码
回复

使用道具 举报

34#
ID:1130333 发表于 2024-8-22 23:12 | 只看该作者
lkc8210 发表于 2024-8-22 09:20
我那个只是示范,你还要加上之前的EEPRom循环读写的代码

哥,我好像有一点点懂了.
我一直纠结程序上的问题.
刚刚我试了一个很垃圾的手电.好像不是代码上的问题.
就是那个电容的问题.  我那个垃圾手电,我把电容用铅笔涂黑了(就是短路了)
现在不能换挡,一直是那个档位.
好像换挡取决于那个电容.. 电容的大小决定关机再开机多久时间换挡.
回复

使用道具 举报

35#
ID:1130333 发表于 2024-8-24 23:37 | 只看该作者
lkc8210 发表于 2024-8-21 11:11
我的代码是检测P32脚电容的电平来判断掉电时间的

您这个是不是电路上还有要求啊?
P32 我原本接的按键
回复

使用道具 举报

36#
ID:1130333 发表于 2024-8-24 23:41 | 只看该作者
lkc8210 发表于 2024-8-22 09:20
我那个只是示范,你还要加上之前的EEPRom循环读写的代码

您的代码我之前不能换挡是因为没有加 eeprom擦除
现在在写前面加一句                  IapErase(EEPROMId);
就好了
但是就一直换挡,关开一次就换一次档.不能保存当前档位
还有哪里需要纠正吗
回复

使用道具 举报

37#
ID:1130333 发表于 2024-8-25 10:20 | 只看该作者
lkc8210 发表于 2024-8-22 09:20
我那个只是示范,你还要加上之前的EEPRom循环读写的代码

弄好了.我在P32加了个电容到负极.
现在可以实现我说的那个功能了
超强
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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