找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2947|回复: 8
收起左侧

关于用单片机+红外遥控长按短按设置定时器的问题

[复制链接]
回帖奖励 10 黑币 回复本帖可获得 10 黑币奖励! 每人限 1 次
ID:887218 发表于 2021-3-19 15:30 | 显示全部楼层 |阅读模式
本帖最后由 nyjm2021 于 2021-3-20 16:51 编辑

我用的是51单片机,想用NEC协议的红外遥控来设置定时器,这个阶段想要实现的功能是这样的:1.数码管前4位显示ds1302芯片设置的时间(已实现)。

2.长按遥控的电源键5s(编码为0x45),定时功能打开,这时数码管前两位显示小时,后两位显示分钟,初始值都为0.(已实现)
3.再按下遥控的电源键(小于5s),代表小时的前两位闪烁。(有问题)
4.再次按下遥控的电源键(小于5s),代表分钟的后两位闪烁。(有问题)
我用计算红外遥控的连发码数量来算电源键长按下的时间,连发码一个约108ms,5s需要达到46个连发码。
最开始按下电源键,达到46个连发码时可以打开定时器,小时和分钟都不闪烁,数码管上显示00:00。再按电源键可以让小时闪烁,再按可以让分钟闪烁。但如果打开定时器后,按下的时间比较长,一直没有松开,按理说闪烁的部分是不应该有变化的,但是实际上在20个连发码的时候,闪烁的小时或者分钟会自动交换一次,等到35个连发码时又会自动交换一次,等到46个连发码时定时器没有再次打开(小时或者分钟还会闪烁),等到50个连发码以上时定时器才会重新打开。
想问下有人知道这是什么原因导致的,怎样才能改掉这个问题吗?谢谢!感觉问题应该出在EX0_ISR()函数或者ir_process()函数:————————————————————————————————————————————————
解决方案:因为每次是在到20个连发码的时候出现这个问题,所以我后来在ir_process()函数中把短按的最长时间从小于46个连发码改到了小于15个连发码,虽然没有找到这个问题出现的原因,但也让这个问题不再出现了。


下面是我的单片机main.c文件代码:
  1. #include "reg52.h"        
  2. #include "ds1302.h"
  3. #include <intrins.h>                 //此文件中定义了单片机的一些特殊功能寄存器

  4. #define uint unsigned int          //对数据类型进行声明定义
  5. #define uchar unsigned char
  6. #define ulong unsigned long

  7. bit timer_on_flag,hour_flash,min_flash;   //定时器开启,时钟闪烁,分钟闪烁
  8.   
  9. uint hour,min;            

  10. sbit lsa = P2^4;          //数码管位选
  11. sbit lsb = P2^3;
  12. sbit lsc = P2^2;


  13. sbit IRIN = P3^2;   //红外遥控
  14. uint irtime;            //检测红外高电平持续时间
  15. bit irpro_ok,irok;
  16. uchar IRcord[4];         //储存数据码
  17. uchar irdata[33];         //1引导码 8位客户1 8位客户2 8位操作码 8位操作反码
  18. bit shortpress;   //红外遥控短按和长按
  19. uint long_press_time;   //红外遥控连发码数量

  20. uchar code duan[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

  21. uint flag1ms,flag5ms,flag100ms;

  22. uchar n4,n5,n6,n7;
  23. uchar n0,n1,n2,n3;
  24. bit dig_on;             //数码管打开

  25. void Ircordpro();
  26. void ir_process();
  27. /*------------------------------------------------------------------------------
  28.                           数码管位选、赋值、闪烁
  29. ------------------------------------------------------------------------------*/
  30. void flash_display(uchar seta,uchar setb,uchar setc,uchar num,bit check)                           //数码管闪烁
  31. {
  32.          static uchar flash = 0;
  33.         lsa = seta; lsb = setb; lsc = setc;
  34.         if(check)
  35.         {
  36.                 if(++flash>10) flash = 0;
  37.                 else if(flash<=4) P0 = duan[num];
  38.                 else if(flash>4) P0 = 0x00;
  39.          }else{
  40.                  P0 = duan[num];
  41.          }
  42. }

  43. /*------------------------------------------------------------------------------
  44.                                 数码管显示
  45. ------------------------------------------------------------------------------*/
  46. void display(){
  47.     static uchar i = 0;                  

  48.         if(dig_on)
  49.         {        
  50.                 switch(i)
  51.                 {                        
  52.                         case 0:        flash_display(1,1,1,n7,hour_flash);break;
  53.                         case 1:        flash_display(1,1,0,n6,hour_flash);break;
  54.                         case 2:        flash_display(1,0,1,n5,min_flash);break;
  55.                         case 3: flash_display(1,0,0,n4,min_flash);break;
  56.                         case 4: lsa = 0;lsb = 1;lsc = 1;P0 = duan[n3];break;
  57.                         case 5: lsa = 0;lsb = 1;lsc = 0;P0 = duan[n2];break;
  58.                         case 6: lsa = 0;lsb = 0;lsc = 1;P0 = duan[n1];break;
  59.                         case 7: lsa = 0;lsb = 0;lsc = 0;P0 = duan[n0];break;                        
  60.                 }
  61.                 i++;
  62.                 if(i>7)        i=0;
  63.         }
  64.         else
  65.         {
  66.                 P0 = 0x00;
  67.         }               
  68. }

  69. /*------------------------------------------------------------------------------
  70.                                 定时器1初始化
  71. ------------------------------------------------------------------------------*/
  72. void Timer1Init()
  73. {
  74.         TMOD &= 0x0F;                         //清0 T1的控制位
  75.         TMOD |= 0x10;                     //定时器1的工作方式为1
  76.         TH1 = (65536-921)/256;         //晶振频率为11.0592MHz,机器周期为12/11059200*1000000 = 1.08506944us,周期为1ms,N为1000/1.08506944 = 921.6
  77.         TL1 = (65536-921)%256;

  78.         EA = 1;                                     //打开总中断
  79.         ET1 = 1;                             //打开定时器1中断
  80.     TR1 = 1;                             //打开定时器1
  81. }

  82. /*------------------------------------------------------------------------------
  83.                              定时器1中断服务函数
  84. ------------------------------------------------------------------------------*/
  85. void timer1() interrupt 3
  86. {

  87.          TH1 = (65536-921)/256;
  88.         TL1 = (65536-921)%256;
  89.         flag1ms = 1;                                                   //定时器周期为1ms

  90.         P0 = 0x00;                                  //消抖
  91. }
  92. /*------------------------------------------------------------------------------
  93.                          (红外)定时器0初始化
  94. ------------------------------------------------------------------------------*/
  95. void Timer0Init()  //256*(1/11.0592MHz)*12 = 0.278ms
  96. {
  97.         TMOD &= 0xF0;  //清零T0的控制位
  98.         TMOD |= 0x02;  //定时器0工作方式2
  99.         TH0 = 0x00;           //高位初始化
  100.         TL0 = 0x00;           //低位初始化
  101.         ET0 = 1;           //定时器0中断
  102.         TR0 = 1;           //启动定时器
  103. }

  104. /*------------------------------------------------------------------------------
  105.                          (红外)外部中断0初始化
  106. ------------------------------------------------------------------------------*/
  107. void Int0Init()   //外部中断0初始化
  108. {
  109.         IT0 = 1;          //设置外部中断0为下降沿触发
  110.         EX0 = 1;          //启动外部中断0
  111.         EA = 1;                  //总中断允许
  112. }

  113. /*------------------------------------------------------------------------------
  114.                           (红外)定时器0中断服务函数
  115. ------------------------------------------------------------------------------*/

  116. void timer0() interrupt 1
  117. {
  118.         irtime++;         //检测脉宽,一次位278us
  119. }

  120. /*------------------------------------------------------------------------------
  121.                           (红外)外部中断0服务函数
  122. ------------------------------------------------------------------------------*/
  123. void EX0_ISR() interrupt 0
  124. {
  125.         static uchar i;                 //把33次高电平持续时间存入irdata
  126.         static bit startflag;         //开始存储脉宽标志位

  127.         if(startflag)                         //开始接收脉宽检测
  128.         {   
  129.                 if(irtime<63 && irtime>=45)   //判断是否引导码,低电平9ms+高电平4.5ms         
  130.                 {
  131.                         i = 0;                         //如果是存入irdata的第一位
  132.                         shortpress = 1;
  133.                         long_press_time = 0;
  134.                 }
  135.                 else if(irtime>33 && irtime <45)         //判断是否为连发码,低电平9ms+高电平2.25ms
  136.                 {
  137.                         shortpress = 0;
  138.                         long_press_time++;                          //计算连发码的数量
  139.                 }
  140.                 if(shortpress)
  141.                 {
  142.                         irdata[i] = irtime;
  143.                 }
  144.                 irtime = 0;                        //计数清零,下一个下降沿的时候再存入脉宽
  145.                 i++;                                //计算脉宽存入的次数
  146.                 if(i==33)                        //如果存入34次
  147.                 {
  148.                         irok = 1;                //脉宽检测完毕
  149.                         i = 0;                        //脉宽计数清零准备下次存入
  150.                 }         
  151.         }
  152.         else
  153.         {
  154.                 irtime = 0;                        //计数清零
  155.                 startflag = 1;                //开始处理
  156.         }
  157. }
  158. /*------------------------------------------------------------------------------
  159.                           (红外)码值处理函数
  160. ------------------------------------------------------------------------------*/
  161. void Ircordpro()  //提取33次脉宽进行数据解码
  162. {
  163.         uchar i, j, k,cord,value;            //k用于33次脉宽中的哪一位
  164.         k=1;                                            //从第一位开始,丢弃引导码脉宽
  165.         for(i=0;i<4;i++)                //处理4个字节
  166.         {
  167.                 for(j=1;j<=8;j++)       //处理1个字节8位
  168.                 {
  169.                         cord=irdata[k];        //把脉宽存入cord
  170.                         if(cord>5)      //脉宽大于11.0592的T0溢出率位约278us*5=1390那么判断为1
  171.                         {
  172.                                                         value=value|0x80;  //接收时先接收最低位
  173.                                                 }
  174.                         if(j<8)
  175.                         {
  176.                                 value>>=1;           //value位左移依次接收8位数据
  177.                         }
  178.                         k++;               //每执行一次脉宽数加一
  179.                 }
  180.                 IRcord[i]=value;           //每处理完一个字节把它放入ircord数组中
  181.                 value=0;                        //清零value方便下次存入数据
  182.         }
  183.         irpro_ok=1;  //接受完4个字节后irpro_ok置1表示红外解码完成
  184. }

  185. /*------------------------------------------------------------------------------
  186.                           (红外)功能实现函数
  187. ------------------------------------------------------------------------------*/

  188. void ir_process()
  189. {
  190.         if(irok)                         //如果红外信号接收完毕
  191.         {
  192.                 Ircordpro();        //对红外信号进行解码
  193.                 irok = 0;
  194.                 shortpress = 0;
  195.         }
  196.         if(irpro_ok)                   //如果对红外信号解码完毕
  197.         {
  198.                 if(IRcord[2]==0x45 )           //如果按键是45H
  199.                 {
  200.                         if(long_press_time >= 46)          //长按打开定时器
  201.                         {
  202.                                 timer_on_flag = 1;                 //打开定时器
  203.                                 hour = 0;
  204.                                 min = 0;
  205.                                 hour_flash = 0;                         //小时不闪烁
  206.                                 min_flash = 0;                         //分钟不闪烁
  207.                         }
  208.                         else if( (1<=long_press_time && long_press_time <46))           //短按对时间进行选择,设置超过20时会自动跳变
  209.                         {
  210.                                         if(timer_on_flag)                                   //如果定时器处于打开状态
  211.                                         {
  212.                                                 if(!min_flash && !hour_flash)          //小时分钟均不闪烁,让小时闪烁
  213.                                                 {
  214.                                                         hour_flash = 1;
  215.                                                         irpro_ok = 0;
  216.                                                 }
  217.                                                 else if(hour_flash && !min_flash)                                   //小时已经在闪烁,短按一下让分钟闪烁
  218.                                                 {
  219.                                                         hour_flash = 0;
  220.                                                         min_flash = 1;
  221.                                                         irpro_ok = 0;
  222.                                                 }
  223.                                                 else if(min_flash && !hour_flash)
  224.                                                 {
  225.                                                         hour_flash = 1;                           //小时没有闪烁,短按一下让小时闪烁,分钟不闪烁
  226.                                                         min_flash = 0;
  227.                                                         irpro_ok = 0;
  228.                                                 }
  229.                                        
  230.                                         }
  231.                         }
  232.                 }         
  233.         }  
  234.                
  235. }
  236. /*------------------------------------------------------------------------------
  237.                           数码管显示内容设置函数
  238. ------------------------------------------------------------------------------*/
  239. void calculate_num()
  240. {        
  241.         
  242.         n3 = long_press_time / 10;
  243.         n2 = long_press_time % 10;
  244.         n1 = IRcord[2]>>4;
  245.         n0 = IRcord[2]&0x0F;
  246.         
  247.         if(timer_on_flag)                    //定时器打开,数码管显示定时的倒计时
  248.         {
  249.                 n7 = hour / 10;
  250.                 n6 = hour % 10;
  251.                 n5 = min / 10;
  252.                 n4 = min % 10;
  253.         }else if(!timer_on_flag)          //定时器未开,数码管显示时钟芯片实时时间
  254.         {
  255.                 Ds1302ReadTime();
  256.                 n7 = TIME[2]/16;                //时
  257.                 n6 = TIME[2]&0x0f;

  258.             n5 = TIME[1]/16;                //分
  259.                 n4 = TIME[1]&0x0f;
  260.         }
  261. }

  262. /*------------------------------------------------------------------------------
  263.                                 主函数
  264. ------------------------------------------------------------------------------*/
  265. void main( )
  266. {        
  267.         dig_on = 1;

  268.         Timer0Init();
  269.         Timer1Init();

  270.     Ds1302Init();
  271.         Int0Init();

  272.         while(1)
  273.         {
  274.                   if(flag1ms)
  275.                 {
  276.                         flag1ms = 0;               
  277.                         display();             //数码管显示
  278.                         if(++flag5ms>=5)          //1ms * 5 = 5ms
  279.                         {
  280.                                 flag5ms = 0;
  281.                                 ir_process();      //红外控制
  282.                                 calculate_num();
  283.                         }
  284.                 }
  285.         }        
  286. }
复制代码

回复

使用道具 举报

ID:140489 发表于 2021-3-19 16:19 | 显示全部楼层
用遥控器就多用几个键来设置,,遥控器上那么多的按键不用作什么
回复

使用道具 举报

ID:887218 发表于 2021-3-19 18:37 | 显示全部楼层
lids 发表于 2021-3-19 16:19
用遥控器就多用几个键来设置,,遥控器上那么多的按键不用作什么

不好意思,我在做一个小项目,要求就是这样的,用一个遥控按键实现长按5s开启定时,短按切换小时和分钟闪烁
回复

使用道具 举报

ID:283908 发表于 2021-3-19 21:22 | 显示全部楼层
是否可以换个思路,再定义几个变量。

判断在一定时间段里。出现的0x45。

如第一个0X45存在IRcord—one[2]==0x45

后 108ms的0X45存在IRcord—two[2]==0x45

IRcord—two[2] 再后的0X45存在IRcord_three[2]==0x45

然后再分别处理IRcord_three[2]   IRcord—two[2]  IRcord—one[2]

      
回复

使用道具 举报

ID:275826 发表于 2021-3-20 14:30 | 显示全部楼层
楼主的程序中long_press_time未复位0;程序应该没有长按功能,只有短按功能
回复

使用道具 举报

ID:887218 发表于 2021-3-20 16:43 | 显示全部楼层
本帖最后由 nyjm2021 于 2021-3-20 16:54 编辑
tyrl800 发表于 2021-3-20 14:30
楼主的程序中long_press_time未复位0;程序应该没有长按功能,只有短按功能

长按功能是可以实现的。我这里的长按和短按更准确地说是判断读取到的是11.25ms的连发码还是13.5ms的引导码,long_press_time是在短按,也就是接收到引导码的时候复位0的。每一次有按键按下,最开始发送引导码,执行短按部分的程序,long_press_time归0,读取到的数据码存储在irdata[]中,按键持续按下,没有放开,读取到连发码,long_press_time自增,不存储新的数据。每一次读取到引导码或者连发码时,用Ircordpro()函数进行解码,并用ir_process()函数完成相应的功能。遥控按键放开,下一次又有按键按下时,再对引导码进行处理,long_press_time再次清零。
回复

使用道具 举报

ID:358564 发表于 2021-3-20 19:40 | 显示全部楼层
// =========================== key.c ======================
#include "reg51.h"

#define KEY_INPUT           P1.0    //  按键IO

#define KEY_STATE_0         0       //  按键状态
#define KEY_STATE_1         1
#define KEY_STATE_2         2
#define KEY_STATE_3         3

#define SINGLE_KEY_TIME     3       //  SINGLE_KEY_TIME*10MS = 30MS     判定单击的时间长度,软件消抖
#define KEY_INTERVAL        30      //  KEY_INTERVAL*10MS    = 300MS 判定双击的时间间隔
#define LONG_KEY_TIME       300     //  LONG_KEY_TIME*10MS   = 3S   判定长按的时间长度


#define N_KEY               0       //  no click
#define S_KEY               1       //  single click        单击
#define D_KEY               2       //  double click        双击
#define T_KEY               3       //  Triple click        三击
#define Q_KEY               4       //  Quadruple click     四击
#define L_KEY               10      //  long press          长按

// ----------------------------------- key_driver --------------------------
unsigned char key_driver(void)
{     
    static unsigned char key_state = 0;
    static unsigned int  key_time = 0;
    unsigned char key_press, key_return;

    key_return = N_KEY;                         //  清除 返回按键值

    key_press = key_input;                      //  读取当前键值

    switch (key_state)     
    {      
        case KEY_STATE_0:                       //  按键状态0:判断有无按键按下
            if (!key_press)                     //  有按键按下
            {
                key_time = 0;                   //  清零时间间隔计数
                key_state = KEY_STATE_1;        //  然后进入 按键状态1
            }        
            break;

        case KEY_STATE_1:                       //  按键状态1:软件消抖(确定按键是否有效,而不是误触)。按键有效的定义:按键持续按下超过设定的消抖时间。
            if (!key_press)                     
            {
                key_time++;                     //  一次10ms
                if(key_time>=SINGLE_KEY_TIME)   //  消抖时间为:SINGLE_KEY_TIME*10ms = 30ms;
                {
                    key_state = KEY_STATE_2;    //  如果按键时间超过 消抖时间,即判定为按下的按键有效。按键有效包括两种:单击或者长按,进入 按键状态2, 继续判定到底是那种有效按键
                }
            }         
            else key_state = KEY_STATE_0;       //  如果按键时间没有超过,判定为误触,按键无效,返回 按键状态0,继续等待按键
            break;

        case KEY_STATE_2:                       //  按键状态2:判定按键有效的种类:是单击,还是长按
            if(key_press)                       //  如果按键在 设定的长按时间 内释放,则判定为单击
            {
                 key_return = S_key;            //  返回 有效按键值:单击
                 key_state = KEY_STATE_0;       //  返回 按键状态0,继续等待按键
            }
            else
            {
                key_time++;                     

                if(key_time >= LONG_KEY_TIME)   //  如果按键时间超过 设定的长按时间(LONG_KEY_TIME*10ms=300*10ms=3000ms), 则判定为 长按
                {
                    key_return = L_KEY;         //  返回 有效键值值:长按
                    key_state = KEY_STATE_3;    //  去状态3,等待按键释放
                }
            }
            break;

      case KEY_STATE_3:                         //  等待按键释放
          if (key_press)
          {
              key_state = KEY_STATE_0;          //  按键释放后,进入 按键状态0 ,进行下一次按键的判定
          }        
          break;

        default:                                //  特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
            key_state = KEY_STATE_0;
            break;
    }

    return  key_return;                         //  返回 按键值
}

// ----------------------------------- key_read --------------------------------
void key_read(void)                             
{
    static unsigned char key_state1=0, key_time1=0;
    unsigned char key_return,key_temp;

    key_return = N_KEY;                         //  清零 返回按键值

    key_temp = key_driver();                    //  读取键值

    switch(key_state1)
    {         
        case KEY_STATE_0:                       //  按键状态0:等待有效按键(通过 key_driver 返回的有效按键值)
            if (key_temp == S_key )             //  如果是[单击],不马上返回单击按键值,先进入 按键状态1,判断是否有[双击]的可能
            {
                 key_time1 = 0;                 //  清零计时
                 key_state1 = KEY_STATE_1;
            }            
            else                                //  如果不是[单击],直接返回按键值。这里的按键值可能是:[长按],[无效按键]
            {
                 key_return = key_temp;         //  返回 按键值
            }
            break;

        case KEY_STATE_1:                       //  按键状态1:判定是否有[双击]
            if (key_temp == S_key)              //  有[单击]后,如果在 设定的时间间隔(KEY_INTERVAL*10ms=30*10ms=300ms) 内,再次有[单击],则为[双击],但是不马上返回 有效按键值为[双击],先进入 按键状态2,判断是否有[三击]
            {
                key_time1 = 0;                  //  清零 时间间隔
                key_state1 = KEY_STATE_2;       //  改变 按键状态值
            }
            else                                //  有[单击]后,如果在 设定的时间间隔(KEY_INTERVAL*10ms=30*10ms=300ms)内,没有[单击]出现,则判定为 [单击]
            {
                key_time1++;                    //  计数 时间间隔
                if(key_time1 >= KEY_INTERVAL)   //  超过 时间间隔
                 {
                    key_return = S_key;         //  返回 有效按键:[单击]
                    key_state1 = KEY_STATE_0;   //  返回 按键状态0,等待新的有效按键
                 }              
             }              
             break;

        case KEY_STATE_2:                       // 按键状态2:判定是否有[三击]
            if (key_temp == S_key)              // 有[双击]后,如果在 设定的时间间隔(KEY_INTERVAL*10ms=30*10ms=300ms) 内,再次有[单击],则为[三击],由于这里只扩展到[三击],所以马上返回 有效按键值为[三击]
            {
                key_time1 = 0;                  // 清零 时间间隔
                key_state1 = KEY_STATE_3;       // 改变 按键状态值
            }
            else                                // 有[双击]后,如果在 设定的时间间隔(KEY_INTERVAL*10ms=30*10ms=300ms)内,没有[单击],则判定为 [双击]
            {
                key_time1++;                    // 计数 时间间隔
                if(key_time1 >= KEY_INTERVAL)   // 超过 时间间隔
                 {
                      key_return = D_KEY;       // 返回 有效按键:[双击]
                      key_state1 = KEY_STATE_0; // 返回 按键状态0,等待新的有效按键
                 }
             }
             break;

        case KEY_STATE_3:                       // 按键状态3:等待按键释放
            if (key_temp == S_key)              // 有[三击]后,如果在 设定的时间间隔(KEY_INTERVAL*10ms=30*10ms=300ms) 内,再次有[单击],则为[四击],马上返回有效按键值为[四击],
            {
                 key_return = Q_key;            // 返回 有效按键:[四击]
                 key_state1 = KEY_STATE_0;      // 返回 按键状态0,等待新的有效按键
            }
            else                                
            {                                   // 有[三击]后,如果在 设定的时间间隔(KEY_INTERVAL*10ms=30*10ms=300ms)内,没有[单击],则判定为 [三击]                 
                key_time1++;                    // 计数 时间间隔
                if(key_time1 >= KEY_INTERVAL)   // 超过 时间间隔
                 {
                      key_return = T_KEY;       // 返回 有效按键:[三击]
                      key_state1 = KEY_STATE_0; // 返回 按键状态0,等待新的有效按键
                 }              
             }            
             break;

        default:                                //  特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
            key_state1 = KEY_STATE_0;
            break;
    }

    return = key_return;                        // 返回 按键值
}     
回复

使用道具 举报

ID:275826 发表于 2021-3-20 20:36 | 显示全部楼层
nyjm2021 发表于 2021-3-20 16:43
长按功能是可以实现的。我这里的长按和短按更准确地说是判断读取到的是11.25ms的连发码还是13.5ms的引导 ...

楼主程序每次都先执行短按,有长按再执行,没有区分开吧
回复

使用道具 举报

ID:729845 发表于 2022-5-1 12:31 | 显示全部楼层
获益匪浅
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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