433 单引脚电平型程序

← 返回 MOC | ← 主页


发射端 — EV1527 编码发送(单向遥控/报警)

发射端通过翻转 DATA 引脚(PA4)输出 OOK 信号,使用 EV1527 协议:前导码 + 同步码 + 20位地址 + 4位数据。 delay_us 基于 8MHz 系统时钟手动 NOP 校准,时间单位 T ≈ 4µs。 发送前关中断(GIE=0),发送后恢复,防止时序被打断。

// ---- 引脚 & 地址定义 ----
#define DATAOUT_HIGH  PA4 = 1
#define DATAOUT_LOW   PA4 = 0
#define g_my_addr     0x12345   // 20位地址,按需修改
#define is_leaking    0x02      // 4位数据:漏水状态
#define duima         0x01      // 4位数据:配对码
 
typedef unsigned char  uint8_t;
typedef unsigned int   uint16_t;
typedef unsigned long  uint32_t;
 
// 延时(基于 8MHz,每循环约 1us)
void delay_us(uint16_t us) {
    uint16_t j;
    us = us * 3;
    for (j = 0; j < us; j++) {
        NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();
        NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();
        NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();
    }
}
 
// 前导码:10个脉冲,HIGH ~4us + LOW ~20us(AGC 锁定用)
void coding_preamble_1527(void) {
    uint8_t i;
    for (i = 0; i < 10; i++) {
        DATAOUT_HIGH; delay_us(4);
        DATAOUT_LOW;  delay_us(20);
    }
}
 
// 同步码:HIGH 4us + LOW 124us
void coding_syn_1527(void) {
    DATAOUT_HIGH; delay_us(4);
    DATAOUT_LOW;  delay_us(124);
}
 
// 逻辑0:HIGH 4us + LOW 12us
void coding_L_1527(void) {
    DATAOUT_HIGH; delay_us(4);
    DATAOUT_LOW;  delay_us(12);
}
 
// 逻辑1:HIGH 12us + LOW 4us
void coding_H_1527(void) {
    DATAOUT_HIGH; delay_us(12);
    DATAOUT_LOW;  delay_us(4);
}
 
// 发送一帧:前导码 + 同步码 + 20位地址 + 4位数据
// addr: 20位地址(≤0xFFFFF),data: 4位数据(≤0xF)
void coding_1527(uint32_t addr, uint8_t data) {
    uint8_t i, k;
    uint32_t j;
    if (addr > 0xFFFFF || data > 15) return;
 
    GIE = 0;
    coding_syn_1527();
    for (i = 0; i < 20; i++) {
        j = 0x80000 & addr;
        addr <<= 1;
        if (j) coding_H_1527(); else coding_L_1527();
    }
    for (i = 0; i < 4; i++) {
        k = 0x08 & data;
        data <<= 1;
        if (k) coding_H_1527(); else coding_L_1527();
    }
    DATAOUT_HIGH; delay_us(4);
    DATAOUT_LOW;
    GIE = 1;
}
 
// 使用示例:发送漏水报警(发3次保可靠性)
void send_alarm(void) {
    uint8_t i;
    for (i = 0; i < 3; i++) {
        coding_preamble_1527();
        coding_1527(g_my_addr, is_leaking);
    }
}

接收端 — EV1527 解码(TIM1 90us 中断采样)

接收端用 TIM1 产生 90us 定时中断,在 ISR 中采样 PB7 引脚电平,统计高/低脉宽计数, 按 EV1527 协议识别前导码→同步码→24位数据(20位地址+4位数据)。 解码成功后写入 rf_data[3],置 rf_data_ready = 1,主循环轮询读取。 TIM1 时钟源为 HIRC = 32MHz(非系统时钟),ARR = 2879 → 90us。

// ---- rf433.h ----
typedef unsigned char  uint8_t;
typedef unsigned int   uint16_t;
 
extern volatile uint8_t rf_data[3];      // 解码结果:[地址高][地址低][数据]
extern volatile uint8_t rf_data_ready;   // 1=有新数据,主循环读完后清零
 
void RF433_Init(void);   // 初始化 TIM1(90us 中断)
void RF433_ISR(void);    // 放在 TIM1 更新中断 ISR 里调用
 
// ---- rf433.c ----
__at(0x20) static unsigned char flag;
#define bit_rf_ok      (flag & 0x01)
#define bit_last_state (flag & 0x02)
#define bit_syn        (flag & 0x04)
#define SET_rf_ok()      (flag |= 0x01)
#define CLR_rf_ok()      (flag &= ~0x01)
#define SET_last_high()  (flag |= 0x02)
#define CLR_last_high()  (flag &= ~0x02)
#define SET_syn()        (flag |= 0x04)
#define CLR_syn()        (flag &= ~0x04)
 
__at(0x21) static unsigned char a_code1;
__at(0x22) static unsigned char a_code2;
__at(0x23) static unsigned char a_code3;
__at(0x24) static unsigned char hh_w;    // 高电平计数(单位:90us)
__at(0x25) static unsigned char ll_w;    // 低电平计数
__at(0x26) static unsigned char t_code1;
__at(0x27) static unsigned char t_code2;
__at(0x28) static unsigned char t_code3;
__at(0x29) static unsigned char ma_x;   // 当前解码位索引
__at(0x2A) static unsigned char pre_cnt;
#define PRE_CNT_MIN 5   // 至少5个前导码脉冲才接受同步码
 
static unsigned int s;
volatile unsigned char rf_data[3]    = {0};
volatile unsigned char rf_data_ready = 0;
 
void RF433_Init(void) {
    flag = 0; hh_w = 0; ll_w = 0;
    t_code1 = 0; t_code2 = 0; t_code3 = 0;
    ma_x = 0; s = 0; pre_cnt = 0;
 
    // TIM1: HIRC=32MHz, ARR=2879 → 90us 中断
    PCKEN  |= 0x02;           // 使能 TIM1 时钟
    CKOCON  = 0x20;
    TCKSRC  = 0x03;           // 时钟源 HIRC=32MHz
    TIM1CR1 = 0x84;           // 自动预装载,向上计数,暂不使能
    TIM1SR1 = 0;
    TIM1IER = 0x01;           // 使能更新中断
    T1UIE   = 1;
    TIM1ARRH = 0x0B;          // ARR = 2879 (0x0B3F)
    TIM1ARRL = 0x3F;
    TIM1CR1 = 0x85;           // 使能计数器
    GIE     = 1;
}
 
static void set_bit(unsigned char bit_idx) {
    unsigned char mask = (unsigned char)(0x80 >> (bit_idx & 0x07));
    if      (bit_idx < 8)  t_code1 |= mask;
    else if (bit_idx < 16) t_code2 |= (unsigned char)(0x80 >> ((bit_idx - 8)  & 0x07));
    else                   t_code3 |= (unsigned char)(0x80 >> ((bit_idx - 16) & 0x07));
}
 
static void save_code(void) {
    a_code1 = t_code1; a_code2 = t_code2; a_code3 = t_code3;
    SET_rf_ok(); CLR_syn(); s = 1000;
}
 
void RF433_ISR(void) {
    if (PB7 == 0) {
        ll_w++;
        CLR_last_high();
    } else {
        hh_w++;
        if (!(bit_last_state)) {
            // 上升沿:处理上一个低电平脉宽
            if ((hh_w >= 2 && hh_w <= 5) && (ll_w >= 15 && ll_w <= 25)) {
                // 前导码
                if (pre_cnt < 255) pre_cnt++;
            } else if ((pre_cnt >= PRE_CNT_MIN) &&
                       (hh_w >= 2 && hh_w <= 5) && (ll_w >= 80 && ll_w <= 165)) {
                // 同步码
                SET_syn(); pre_cnt = 0; ma_x = 0;
                t_code1 = 0; t_code2 = 0; t_code3 = 0;
            } else if ((bit_syn) && (ll_w >= 7 && ll_w <= 13)) {
                // 逻辑0
                ma_x++;
                if (ma_x > 23 && !bit_rf_ok) save_code();
            } else if ((bit_syn) && (ll_w >= 2 && ll_w <= 7)) {
                // 逻辑1
                if (ma_x <= 23) {
                    set_bit(ma_x);
                    if (ma_x == 23 && !bit_rf_ok) save_code();
                    ma_x++;
                }
            } else {
                // 干扰,重置
                pre_cnt = 0; ma_x = 0; CLR_syn();
                t_code1 = 0; t_code2 = 0; t_code3 = 0; ll_w = 0;
            }
            ll_w = 0; hh_w = 1;
        }
        SET_last_high();
    }
 
    if (bit_rf_ok) {
        s--;
        if (!s) CLR_rf_ok();
        rf_data[0] = a_code1;
        rf_data[1] = a_code2;
        rf_data[2] = a_code3;
        rf_data_ready = 1;
    }
    T1UIF = 1;  // 清中断标志(写1清零)
}
 
// ---- 主循环中读取示例 ----
// if (rf_data_ready) {
//     rf_data_ready = 0;
//     // rf_data[0..2] 即 24位解码结果(高位在前)
//     // 地址 = (rf_data[0]<<12) | (rf_data[1]<<4) | (rf_data[2]>>4)
//     // 数据 = rf_data[2] & 0x0F
// }