找回密码
 立即注册
查看: 102|回复: 4

做红外感应开关,要如何避开红外干扰呢?

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2025-09-12 08:47:51
已绑定手机

6

主题

21

回帖

106

积分

注册会员

积分
106
发表于 2025-9-9 16:39:39 | 显示全部楼层 |阅读模式
用8G1K08A做的红外感应开关,用手机刘海出的红外感应头对着单片机的红外感应头时,灯会一直在闪烁要如何避开,有没有大佬解答一下要如何处理呢,



#include "reg51.h"
#include "intrins.h"

/*************        本地常量声明        **************/
#define ADC_START        (1<<6)        /* 自动清0 */
#define ADC_FLAG        (1<<5)        /* 软件清0 */

#define        ADC_SPEED        1                /* 0~15, ADC时钟 = SYSclk/2/(n+1) */
#define        RES_FMT                (1<<5)        /* ADC结果格式 0: 左对齐, ADC_RES: D9 D8 D7 D6 D5 D4 D3 D2, ADC_RESL: D1 D0 0  0  0  0  0  0 */
                                                        /*             1: 右对齐, ADC_RES: 0  0  0  0  0  0  D9 D8, ADC_RESL: D7 D6 D5 D4 D3 D2 D1 D0 */

#define CSSETUP                (1<<7)        /* 0~1,  ADC通道选择时间      0: 1个ADC时钟, 1: 2个ADC时钟,  默认0(默认1个ADC时钟) */
#define CSHOLD                (2<<5)        /* 0~3,  ADC通道选择保持时间  (n+1)个ADC时钟, 默认1(默认2个ADC时钟)                */
#define SMPDUTY                20                /* 10~31, ADC模拟信号采样时间  (n+1)个ADC时钟, 默认10(默认11个ADC时钟)                                */
                                                        /* ADC转换时间: 10位ADC固定为10个ADC时钟, 12位ADC固定为12个ADC时钟.                                 */
                                                       
#define MAIN_Fosc                22118400L        //定义主时钟

sfr     ADC_CONTR   =   0xbc;
sfr     ADC_RES     =   0xbd;
sfr     ADC_RESL    =   0xbe;
sfr     ADCCFG      =   0xde;

sfr     P_SW2   =   0xba;
#define ADCTIM  (*(unsigned char volatile xdata *)0xfea8)

sfr AUXR = 0x8E;
sfr INT_CLKO = 0x8F;
sfr P_SW1 = 0xa2;

sfr     CCON    =   0xd8;
sbit    CF      =   CCON^7;
sbit    CR      =   CCON^6;
sbit    CCF2    =   CCON^2;
sbit    CCF1    =   CCON^1;
sbit    CCF0    =   CCON^0;

sfr     CMOD    =   0xd9;
sfr     CL      =   0xe9;
sfr     CH      =   0xf9;
sfr     CCAPM0  =   0xda;
sfr     CCAP0L  =   0xea;
sfr     CCAP0H  =   0xfa;
sfr     PCA_PWM0 =  0xf2;
sfr     CCAPM1  =   0xdb;
sfr     CCAP1L  =   0xeb;
sfr     CCAP1H  =   0xfb;
sfr     PCA_PWM1 =  0xf3;
sfr     CCAPM2  =   0xdc;
sfr     CCAP2L  =   0xec;
sfr     CCAP2H  =   0xfc;
sfr     PCA_PWM2 =  0xf4;

sfr     P0M1    =   0x93;
sfr     P0M0    =   0x94;
sfr     P1M1    =   0x91;
sfr     P1M0    =   0x92;
sfr     P2M1    =   0x95;
sfr     P2M0    =   0x96;
sfr     P3M1    =   0xb1;
sfr     P3M0    =   0xb2;
sfr     P4M1    =   0xb3;
sfr     P4M0    =   0xb4;
sfr     P5M1    =   0xc9;
sfr     P5M0    =   0xca;

sfr P4   = 0xC0;
sfr P5   = 0xC8;
sfr P6   = 0xE8;
sfr P7   = 0xF8;

sbit    IR_OUT    =   P5^4;
sbit    IR_IN           =   P5^5;

typedef     unsigned char   u8;
typedef     unsigned int    u16;
typedef     unsigned long   u32;

#define         PCA0                        0
#define         PCA1                        1
#define         PCA2                        2

unsigned int ambient_light = 0;   // 环境光基准值
unsigned int ir_received        = 0;

#define EMIT_DURATION 20    // 发射持续时间(ms)
#define STOP_DURATION 10    // 停止持续时间(ms)
unsigned int emit_phase_samples = 0;  // 发射阶段采样值
unsigned int stop_phase_samples = 0;  // 停止阶段采样值
unsigned int net_ir_signal = 0;       // 净反射信号强度
bit emission_state = 0;               // 发射状态: 0=停止, 1=发射
unsigned int timer0_count = 0;        // 定时器0计数

void UpdatePcaPwm(u8 PCA_id, u16 pwm_value)
{
        if(PCA_id == PCA0)
        {
                PCA_PWM0 = (PCA_PWM0 & ~0x32) | (u8)((pwm_value & 0x0300) >> 4) | (u8)((pwm_value & 0x0400) >> 9);
                CCAP0H = (u8)pwm_value;
        }
        else if(PCA_id == PCA1)
        {
                PCA_PWM1 = (PCA_PWM1 & ~0x32) | (u8)((pwm_value & 0x0300) >> 4) | (u8)((pwm_value & 0x0400) >> 9);
                CCAP1H = (u8)pwm_value;
        }
        else if(PCA_id == PCA2)
        {
                PCA_PWM2 = (PCA_PWM2 & ~0x32) | (u8)((pwm_value & 0x0300) >> 4) | (u8)((pwm_value & 0x0400) >> 9);
                CCAP2H = (u8)pwm_value;
        }
}

void Timer0_Init(void)                //1毫秒@22.1184MHz
{
        //定时器0
        TMOD = 0x00;                                //模式0
        TL0  = 0xcd;                                 //[TH0,TL0]=65536-22.1184M*1000/12*1(1MS)
        TH0  = 0xf8;
        TR0  = 1;                                    //启动定时器
        ET0  = 1;                                    //使能定时器中断
        EA  = 1;
}

void TM0_Isr() interrupt 1        //1ms
{
        timer0_count++;
       
        // 控制发射时序: 发射20ms, 停止10ms
        if(emission_state)
        {
                if(timer0_count >= EMIT_DURATION)
                {
                        emission_state = 0;
                        timer0_count = 0;
                        IR_OUT = 0; // 停止发射
                }
        }
        else
        {
                if(timer0_count >= STOP_DURATION)
                {
                        emission_state = 1;
                        timer0_count = 0;
                        IR_OUT = 1; // 开始发射
                }
        }
}

void Timer1_Init(void)
{
        AUXR &= 0xBF;                        //定时器时钟12T模式
        TMOD &= 0x0F;                        //设置定时器模式
        TL1 = 0xE8;                                //设置定时初始值
        TH1 = 0xFF;                                //设置定时初始值
        TF1 = 0;                                //清除TF1标志
        TR1 = 1;                                //定时器1开始计时
        ET1 = 1;                                //使能定时器1中断
}

void Timer1_Isr(void) interrupt 3
{
        // 不再使用Timer1控制发射,改为由Timer0控制
}

// 初始化ADC
void ADC_Init(void)
{
    P5M0 &= ~0x20; P5M1 |= 0x20; // P5.5设为高阻输入

    ADC_CONTR = 0x80 + 0;        //ADC on + channel
        ADCCFG = RES_FMT + ADC_SPEED;
        P_SW2 |=  0x80;        //访问XSFR
        ADCTIM = CSSETUP + CSHOLD + SMPDUTY;
}

u16        Get_ADC10bitResult(u8 channel)
{
        ADC_RES = 0;
        ADC_RESL = 0;
        ADC_CONTR = 0x80 | ADC_START | channel;
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        while((ADC_CONTR & ADC_FLAG) == 0)        ;        //等待ADC结束
        ADC_CONTR &= ~ADC_FLAG;
        #if ((RES_FMT & (1<<5)) != 0)
                return        ((u16)ADC_RES * 256 + (u16)ADC_RESL);        //右对齐
        #else
                return        ((u16)ADC_RES * 4 + (u16)(ADC_RESL >> 6));        //左对齐
        #endif
}

#define                SUM_LENGTH        16        /* 平均值采样次数 最大值16 */

/***********************************
查询方式做一次ADC, chn为通道号, chn=0~3通道对应P3.0~P3.3, 4通道-->P5.4, 5通道-->P5.5, 15通道为内部1.19V基准电压做输入的ADC值.
***********************************/
unsigned int        ADC_convert(u8 chn)
{
        u16        j;
        u8        k;                //平均值滤波时使用

        Get_ADC10bitResult(chn);                //参数i=0~11,15,查询方式做一次ADC, 切换通道后第一次转换结果丢弃. 避免采样电容的残存电压影响.
        Get_ADC10bitResult(chn);                //参数i=0~11,15,查询方式做一次ADC, 切换通道后第二次转换结果丢弃. 避免采样电容的残存电压影响.
        for(k=0, j=0; k<SUM_LENGTH; k++)       
                j += Get_ADC10bitResult(chn);        // 采样累加和   参数0~15,查询方式做一次ADC, 返回值就是结果
        j = j / SUM_LENGTH;                // 求平均
       
        return j;
}

// 在全局变量中定义滤波系数和滤波后的值
#define ALPHA 0.2f  // 滤波系数 (0 < ALPHA < 1)。值越小越平滑,但响应也越慢。
unsigned int filtered_ir_value = 0;

void main()
{
        P0M0 = 0x00;
        P0M1 = 0x00;
        P1M0 = 0x00;
        P1M1 = 0x00;
        P2M0 = 0x00;
        P2M1 = 0x00;
        P3M0 = 0xe0;
        P3M1 = 0x00;
        P4M0 = 0x00;
        P4M1 = 0x00;
        P5M0 = 0x00;
        P5M1 = 0x00;
       
    P3M0 |= 0x08; P3M1 &= ~0x08; //P3.3推挽模式
        P3M0 |= 0x04; P3M1 &= ~0x04; //P3.2推挽模式

    P_SW1 = 0x00; //ECI/P1.2, CCP0/P1.1, CCP1/P1.0, CCP2/P3.7
       
        CCON = 0x00;
        CMOD = 0x08; //PCA 时钟为系统时钟
        CL = 0x00;
        CH = 0x00;

        //-- 10 位 PWM--       
        CCAPM0 = 0x02;          //PCA 模块 0 为 PWM 工作模式
        PCA_PWM0 = 0xc0; //PCA 模块 0 输出 10 位 PWM
        CCAP0L = 0;
        CCAP0H = 0;
       
        CCAPM1 = 0x02;          //PCA 模块 1 为 PWM 工作模式
        PCA_PWM1 = 0xc0; //PCA 模块 1 输出 10 位 PWM
        CCAP1L = 0;
        CCAP1H = 0;
        CR = 1; //启动 PCA 计时器
       
        //定时器
        Timer0_Init();
        Timer1_Init();

        UpdatePcaPwm(PCA1,1023);
        UpdatePcaPwm(PCA0,1023);
       
        ADC_Init();
       
        ambient_light = ADC_convert(5);
       
    while (1)
        {
                // 同步采样策略
                if(emission_state && timer0_count > EMIT_DURATION/2)
                {
                        // 在发射阶段后期采样 (包含自身发射的反射信号 + 环境光)
                        emit_phase_samples = ADC_convert(5);
                }
                else if(!emission_state && timer0_count > STOP_DURATION/2)
                {
                        // 在停止发射阶段采样 (主要是环境光)
                        stop_phase_samples = ADC_convert(5);
                       
                        // 计算净反射信号强度
                        if(emit_phase_samples > stop_phase_samples)
                        {
                                net_ir_signal = emit_phase_samples - stop_phase_samples;
                        }
                        else
                        {
                                net_ir_signal = 0;
                        }
                       
                        // 使用净反射信号进行滤波
                        filtered_ir_value = (unsigned int)((1 - ALPHA) * filtered_ir_value + ALPHA * net_ir_signal);
                       
                        // 环境光补偿:使用停止阶段的采样值作为环境光基准
                        ambient_light = stop_phase_samples;
                       
                        // 手势检测:基于净反射信号
                        if(net_ir_signal > 83) // 阈值可能需要调整
                        {
                                UpdatePcaPwm(PCA1,0);
                                UpdatePcaPwm(PCA0,0);
                        }
                        else
                        {
                                UpdatePcaPwm(PCA1,1023);
                                UpdatePcaPwm(PCA0,1023);
                        }
                }
        }       
}





回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:560
  • 最近打卡:2025-09-16 05:09:25
已绑定手机

86

主题

6122

回帖

1万

积分

超级版主

积分
11330
发表于 2025-9-9 20:16:58 | 显示全部楼层
红外感应开关程序供参考:
15系列单片机主时钟频率11.0592MHz(8G系列需要移植),用38KHz接收头,感应距离>100mm,认假率过高调大Protect,拒真率过高调小Protect
  1. #include <STC15F2K60S2.H>
  2. #include <intrins.h>
  3. #define                RXD                P30
  4. #define                TXD                P31
  5. #define                IRIN        P32
  6. #define                IROUT        P33
  7. #define                OUT                P34
  8. #define                Pluse        20        //Pluse number
  9. #define                Protect        2        //Protect level:1~7
  10. /*----------------------------延时10us@STC-Y5@11.0592MHz----------------------------*/
  11. void Delay_10us(void)
  12. {
  13.         unsigned char i;
  14.         _nop_();
  15.         i=25;
  16.         while(--i);
  17. }
  18. /*----------------------------延时x10us----------------------------*/
  19. void Delay_x10us(unsigned char x)
  20. {
  21.         while(x--)
  22.                 Delay_10us();
  23. }
  24. /*----------------------------延时10ms@STC-Y5@11.0592MHz----------------------------*/
  25. void Delay_10ms(void)
  26. {
  27.         unsigned char i,j;
  28.         i=108;
  29.         j=145;
  30.         do
  31.         {
  32.                 while(--j);
  33.         }while(--i);
  34. }
  35. /*----------------------------延时x10ms----------------------------*/
  36. void Delay_x10ms(unsigned char x)
  37. {
  38.         while(x--)
  39.                 Delay_10ms();
  40. }
  41. void PWM_Delay(void)
  42. {
  43.         unsigned char i;
  44.         _nop_();
  45.         _nop_();
  46.         i=20;
  47.         while(--i);
  48. }
  49. void PWM(void)
  50. {
  51.         unsigned char i;
  52.         for(i=0;i<Pluse;i++)
  53.         {
  54.                 IROUT=0;
  55.                 PWM_Delay();
  56.                 IROUT=1;
  57.                 PWM_Delay();
  58.                 IROUT=1;
  59.                 PWM_Delay();
  60.         }
  61. }
  62. void Init(void)
  63. {
  64.         
  65. }
  66. void main(void)
  67. {
  68.         bit flag;
  69.         unsigned char i,a,b;
  70.         Init();
  71.         while(1)
  72.         {
  73.                 a=0x00;
  74.                 b=0x00;
  75.                 for(i=0;i<Protect;i++)
  76.                 {
  77.                         flag=0;
  78.                         PWM();
  79.                         if(!IRIN)
  80.                                 flag=1;
  81.                         else
  82.                                 flag=0;
  83.                         Delay_x10us(50);        //Do not adjust
  84.                         if(IRIN&&flag)
  85.                                 a|=0x01<<i;
  86.                         b|=0x01<<i;
  87.                         Delay_x10ms(5);        //Minium:40ms
  88.                 }
  89.                 if(a==b)
  90.                         OUT=0;
  91.                 else
  92.                         OUT=1;
  93.         }
  94. }
复制代码


回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2025-09-12 08:47:51
已绑定手机

6

主题

21

回帖

106

积分

注册会员

积分
106
发表于 2025-9-9 20:50:06 | 显示全部楼层
Debu*** 发表于 2025-9-9 20:16
红外感应开关程序供参考:
15系列单片机主时钟频率11.0592MHz(8G系列需要移植),用38KHz接收头,感应距离 ...

感谢你的回答,但是用我用的是红外对管,不是38KHZ的接收头,所以我用了ADC采集接收头的数据对比,我用的是STC8G1K08A,没有PWM,只有PCA,用PCA的PWM好像不能这么准确调到38KHZ,只能用定时器去定到38KHZ
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:495
  • 最近打卡:2025-09-16 15:37:51

9

主题

423

回帖

3025

积分

论坛元老

积分
3025
发表于 2025-9-9 21:33:48 | 显示全部楼层
应该是做反射式感应开关吧? 简单的直接利用ADC采样光敏管接收到电平值做门限判断,确实很容易受到外部干扰.

想要抑制干扰,一是选择红外对管的波长,避开常见红外遥控器用的波长值,配合专用滤色片.这是最经济的办法.

如果无法避开遥控波长,就要靠其他方法抑制干扰,
可以使用监视环境干扰的方法.忽略掉遥控信号,利用遥控器发射间隙来识别自己的有效信号.
也可以采用远离38khz脉冲调制,接收前端增加窄带滤波器选频,然后检波成直流再做门限判断.电路比较复杂.



回复

使用道具 举报 送花

  • 打卡等级:常住居民I
  • 打卡总天数:67
  • 最近打卡:2025-09-17 07:07:04
已绑定手机

7

主题

52

回帖

707

积分

高级会员

积分
707
发表于 2 小时前 来自手机 | 显示全部楼层
不是必须的38khz,你只要提高模拟量采集速度,在瞬时,能打开红外管采集,关闭红外进行采集。多采集几次。打开红外有信号,关闭红外就没有信号,就是感应到了。如果关闭红外还是有信号,说明是外接的红外在干扰。外部红外不可控,也可以在关闭红外的时候采集一次,这个作为浮动基准,然后再和打开红外采集的数做对比,打开红外有遮挡,肯定还会有数据变化,就认为是有遮挡。速度尽可能快的采集adc就行。
回复

使用道具 举报 送花

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

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-9-17 09:27 , Processed in 0.211929 second(s), 73 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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