正在开发一个433无线通信的东西,发射端输入数字,使用曼彻斯特编码,通过无线发送模块,发送到接收端的显示板上,现在就是无法接收数据,弄了好久了,是什么原因,各位大佬帮忙看看
发送端代码如下
// 添加配对模式标志
uint8_t pairing_mode = 0;
//S14正常模式发送数字
void S14_SendNumber(void)
{
uint8_t data[3] = {0};
// 配对模式下发送配对码
if(pairing_mode) {
// 将显示的三位数转换为配对码
uint16_t pairing_code = display_num[0] * 100 +
display_num[1] * 10 +
display_num[2];
printf("pairing_code=%d",pairing_code);
current_id = (0x123 & 0x3FF) << 10 | (pairing_code & 0x3FF);
printf("current_id=0x%04X\n",current_id);
uint32_t frame_24bit = ((uint32_t)current_id << 4) | 0xB;
printf("发送的24位: 0x%06lX\n", (unsigned long)frame_24bit);
// 打印二进制(24位,左补零)
printf("二进制: ");
for (int i = 23; i >= 0; i--) {
printf("%d", (frame_24bit >> i) & 1);
}
printf("\n");
EV1527_send_frame(0xB);
pairing_mode = 0; // 退出配对模式
S11_clean();
// 显示配对成功提示
TM1650_DisplayOne(1, 0x73); // P
TM1650_DisplayOne(2, 0x5E); // d
TM1650_DisplayOne(3, 0x00);
TM1650_DisplayOne(4, 0x00);
delay_us(100); // 显示1秒
S11_clean(); // 再次清空显示
}
// 正常模式发送数字
else {
// 确保有3位数字,不足则补0
uint8_t send_data[3] = {0};
int start_index = 3 - current_digits;
for (int i = 0; i < current_digits; i++) {
send_data[start_index + i] = display_num[i];
}
printf("Send Data: [%d, %d, %d]\n", send_data[0], send_data[1], send_data[2]);
// 发送三位数(分三帧发送)
for (int i = 0; i < 3; i++) {
// 打印要发送的24位数据
uint32_t frame = ((uint32_t)current_id << 4) | (send_data[i] & 0x0F);
printf("发送24位数据[%d]: 0x%06lX, 二进制: ", i, (unsigned long)frame);
for(int j = 23; j >= 0; j--) {
printf("%d", (frame >> j) & 1);
}
printf("\n");
Radio_Send(&send_data[i], 1); // 每次发送一位
}
}
}
// S15_configure进入配对模式
void S15_configure(void)
{
pairing_mode = 1; // 进入配对模式
current_digits = 0; // 重置输入计数器
// 显示配对提示
TM1650_DisplayOne(1, 0x73); // P
TM1650_DisplayOne(2, 0x39); // C
TM1650_DisplayOne(3, 0x00);
TM1650_DisplayOne(4, 0x00);
}
// 硬件配置
// 预设ID编码
uint32_t current_id = EV1527_ID_CODE; // 初始为预设ID
void Radio_init(void)
{
GPIO_InitTypeDef GPIO_InitStructeru;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_InitStructeru.GPIO_Pin = EV1527_TX_PIN;
GPIO_InitStructeru.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructeru.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructeru.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructeru.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(EV1527_TX_PORT, &GPIO_InitStructeru);
GPIO_ResetBits(EV1527_TX_PORT, EV1527_TX_PIN);
printf("Software Radio Initialized\n");
}
// 发送同步码
void send_sync(void) {
GPIO_SetBits(EV1527_TX_PORT, EV1527_TX_PIN);
delay_us(450);
GPIO_ResetBits(EV1527_TX_PORT, EV1527_TX_PIN);
delay_us(14000);
}
// 发送单个数据
void send_bit(uint8_t bit_value) {
if(bit_value) { // 发送'1'
GPIO_SetBits(EV1527_TX_PORT, EV1527_TX_PIN);
delay_us(1300);
GPIO_ResetBits(EV1527_TX_PORT, EV1527_TX_PIN);
delay_us(450);
} else { // 发送'0'
GPIO_SetBits(EV1527_TX_PORT, EV1527_TX_PIN);
delay_us(450);
GPIO_ResetBits(EV1527_TX_PORT, EV1527_TX_PIN);
delay_us(1300);
}
}
// 发送完整数据
void EV1527_send_frame(uint8_t key_data) {
send_sync();
// 发送20位ID(高位在前)bit19~bit0
for(int8_t i = 19; i >= 0; i--) {
send_bit((current_id >> i) & 0x01);
}
// 发送4位按键数据(高位在前)bit3~bit0
for(int8_t i = 3; i >= 0; i--) {
send_bit((key_data >> i) & 0x01);
}
//GPIO_SetBits(EV1527_TX_PORT, EV1527_TX_PIN);
GPIO_ResetBits(EV1527_TX_PORT, EV1527_TX_PIN);
}
void Radio_Send(uint8_t *data, uint8_t len) {
for(uint8_t i = 0; i < len; i++) {
// 确保数据在0-9范围内
uint8_t key_value = data[i] & 0x0F;
EV1527_send_frame(key_value);
delay_ms(13); // 帧间隔
}
}
接收端代码如下
// 硬件配置
// 示波器测量
// 同步头容差
// 定义数据解码状态枚举
typedef enum {
START,
LEAD_CODE_H,
LEAD_CODE_L,
HIGH_BIT,
LOW_BIT,
COMPARE,
} Decode_State_t;
// 全局变量和缓冲区
volatile uint32_t Bit_Count = 0; // 接收数据位计数
volatile uint32_t Received_Data = 0; // 接收到的数据
volatile Decode_State_t RF_Decode_State = START; // 数据解码状态
volatile uint8_t Frame_Ready = 0; // 帧接收完成标志
uint32_t stored_pairing_id = 0; // 存储配对成功的ID
uint8_t collected_digits[3] = {0}; // 收集的数字(百、十、个)
uint8_t digit_count = 0; // 已收集的数字个数
uint32_t last_time = 0; // 上次脉冲时间
uint8_t bit_val = 0; // 收集的值
static uint32_t last_received_id = 0;
static uint8_t last_received_key = 0xB; // 配对模式的按键值
uint32_t H_duration=0; //高电平脉冲宽度
uint32_t L_duration=0; //低电平脉冲宽度
// 初始化接收
void RF_RX_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
// 使能时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
// 配置DO引脚为输入
GPIO_InitStruct.GPIO_Pin = DATA_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DATA_PORT, &GPIO_InitStruct);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource15);
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line = EXTI_Line15;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;//触发 CPU 的中断处理流程
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //双边沿触发
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
// 配置中断优先级
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = EXTI4_15_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority =0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
// 初始化定时器
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseInitTypeDef TIM_InitStruct;
TIM_InitStruct.TIM_Prescaler = (SystemCoreClock / 1000000) - 1; // 1MHz频率
TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_InitStruct.TIM_Period = 0xFFFF;
TIM_TimeBaseInit(TIM3, &TIM_InitStruct);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);//中断使能
// 配置中断优先级
NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority =2;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
TIM_Cmd(TIM3, ENABLE);
}
// 定时器溢出计数(扩展为 64 位时间戳)
volatile uint32_t overflow_count = 0;
// 定时器中断服务函数
void TIM3_IRQHandler(void) {
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {
overflow_count++;
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
// 获取当前时间戳(单位:微秒)
uint64_t micros(void) {
uint32_t cnt = TIM_GetCounter(TIM3);
return ((uint64_t)overflow_count << 16) | cnt;
}
//接收到的数据
void print_received_data(uint32_t data, uint32_t bit_count) {
char bin_str[25] = {0};
for (int i = 0; i < 24; i++) {
uint32_t mask = 1UL << (23 - i);
bin_str[i] = (data & mask) ? '1' : '0';
}
printf("Bit[%d]: %s\n", bit_count, bin_str);
}
// 轮询接收函数
void Poll_RF_Receiver(uint16_t current_state) {
uint32_t current_time = micros();
uint32_t duration = current_time - last_time;
last_time = current_time;
switch (RF_Decode_State) {
case START:
if (current_state == 1) {
RF_Decode_State = LEAD_CODE_H;
}
break;
case LEAD_CODE_H:
if (current_state == 0) {
if (duration >= (LEAD_CODE_HIGH_US * TOLERANCE_MIN) && duration <= (LEAD_CODE_HIGH_US * TOLERANCE_MAX)) {
//printf("Dur3=%d\n",duration);
RF_Decode_State = LEAD_CODE_L;
} else {
RF_Decode_State = START;
}
}
break;
case LEAD_CODE_L:
if (current_state == 1) {
if (duration >= (LEAD_CODE_LOW_US * TOLERANCE_MIN) && duration <= (LEAD_CODE_LOW_US * TOLERANCE_MAX)) {
printf("Dur4=%d\n",duration);
Received_Data = 0;
Bit_Count = 0;
RF_Decode_State = HIGH_BIT;
} else {
RF_Decode_State = START;
}
}
break;
case HIGH_BIT:
if (current_state == 0) {
printf("Dur5=%d\n",duration);
H_duration = duration;
RF_Decode_State = LOW_BIT;
}
break;
case LOW_BIT:
if (current_state == 1) {
printf("Dur6=%d\n",duration);
L_duration = duration;
RF_Decode_State = COMPARE;
}
break;
case COMPARE:
if ( H_duration>L_duration ) {
bit_val = 1;
} else if ( H_duration<L_duration ) {
bit_val = 0;
} else {
RF_Decode_State = START;
printf("error\n");
break;
}
// 数据位移
//Received_Data = (Received_Data >> 1) | (bit_val << 23);
Received_Data = (Received_Data << 1) | bit_val;
Bit_Count++;
if (Bit_Count >= 24) {
Frame_Ready = 1;
RF_Decode_State = START;
print_received_data(Received_Data, 24);
} else {
RF_Decode_State = HIGH_BIT;
}
break;
}
}
void EXTI4_15_IRQHandler(void) {
if (EXTI_GetITStatus(EXTI_Line15) != RESET) {
uint8_t current = GPIO_ReadInputDataBit(DATA_PORT, DATA_PIN);
Poll_RF_Receiver(current);
EXTI_ClearITPendingBit(EXTI_Line15); // 清除中断标志
}
}
void Process_Received_Frame(void) {
if (!Frame_Ready) return;
// 直接提取20位ID和4位按键
uint32_t received_id = (Received_Data >> 4) & 0xFFFFF;
uint8_t received_key = Received_Data & 0x0B;
// 防止重复帧干扰
if (received_id == last_received_id && received_key == last_received_key) {
Frame_Ready = 0;
return;
}
last_received_id = received_id;
last_received_key = received_key;
// 配对模式处理
if (received_key == 0xB) {
// 预期的配对ID
uint32_t expected_id = ((0x123UL & 0x3FF) << 10) |
(((uint32_t)pairing_code[0] * 100 +
(uint32_t)pairing_code[1] * 10 +
(uint32_t)pairing_code[2]) & 0x3FF);
//uint32_t expected_id = (0x123UL & 0x3FF) << 10 | (pairing_code & 0x3FF);
// 判断 received_id 是否等于期望值
if (received_id == expected_id) {
stored_pairing_id = received_id;
sys_state = STATE_CONNECTED;
printf("Pairing_OK ID:0x%05lX, Code:%d%d%d\n",
(unsigned long)(received_id & 0xFFFFF),
pairing_code[0], pairing_code[1], pairing_code[2]);
}else {
printf("ID不匹配,期望ID: 0x%05lX : 实际ID: 0x%05lX\n",
(unsigned long)expected_id,
(unsigned long)(received_id & 0xFFFFF));
}
}
// 正常模式
else if (sys_state == STATE_CONNECTED && received_id == stored_pairing_id) {
if (received_key <= 9) {
if (digit_count < 3) {
collected_digits[digit_count] = received_key;
digit_count++;
// 构造要显示的三个数字
uint8_t display_digits[3];
for (int i = 0; i < 3; i++) {
display_digits[i] = (i < digit_count) ? collected_digits[i] : 10; // 10 表示空白或横杠
}
UpdateDisplay(display_digits[0], display_digits[1], display_digits[2]);
if (digit_count == 3) {
printf("received_OK: %d%d%d\n",
collected_digits[0], collected_digits[1], collected_digits[2]);
digit_count = 0;
}
}
}
}
Frame_Ready = 0;
}
// 检查无线数据
uint8_t CheckRadio(void) {
if (Frame_Ready) {
Process_Received_Frame();
return 1; // 有新数据
}
return 0; // 无新数据
}
接收端部分日志如下
Bit[24]: 000000010000000000010000
Dur4=14538
Dur5=1429
Dur6=1362
Dur5=89
Dur6=590
Dur5=50
Dur6=4036
Dur5=102
Dur6=748
Dur5=184
Dur6=122
Dur5=30
Dur6=66
Dur5=39
Dur6=5665
Dur5=111
Dur6=888
Dur5=57
Dur6=4119
Dur5=201
Dur6=-59762
Dur5=133
Dur6=74
Dur5=54
Dur6=228
Dur5=227
Dur6=199
Dur5=116
Dur6=6745
Dur5=60
Dur6=9796
Dur5=36
Dur6=1248
Dur5=68
Dur6=199
Dur5=39
Dur6=570
Dur5=112
Dur6=90
Dur5=56
Dur6=2193
Dur5=64
Dur6=536
Dur5=169
Dur6=3389
Dur5=214
Dur6=399
Dur5=55
Dur6=57
Bit[24]: 100010000010100000100000
Dur4=14427
Dur5=1099
Dur6=1054
Dur5=74
Dur6=19220
Dur5=7874
Dur6=902
Dur5=68
Dur6=53
Dur5=353
Dur6=38
Dur5=1963
Dur6=324
Dur5=92
Dur6=1575
Dur5=212
Dur6=783
Dur5=1201
Dur6=365
Dur5=422
Dur6=3541
Dur5=276
Dur6=1681
Dur5=92
Dur6=36
Dur5=165
Dur6=5070
Dur5=61
Dur6=62
Dur5=361
Dur6=2132
Dur5=187
Dur6=54
Dur5=93
Dur6=86
Dur5=59
Dur6=1543
Dur5=1384
Dur6=39
Dur5=273
Dur6=46
Dur5=130
Dur6=169
Dur5=196
Dur6=1479
Dur5=126
Dur6=-58834
Dur5=1412
Dur6=884
Bit[24]: 101111001001000110110001
Dur4=13825
Dur5=1244
Dur6=1128
Dur5=39
Dur6=-57005
Dur5=222
Dur6=9101
Dur5=93
Dur6=1279
Dur5=55
Dur6=181
Dur5=60
Dur6=43
Dur5=121
Dur6=70
Dur5=202
Dur6=691
Dur5=103
Dur6=799
Dur5=49
Dur6=61
Dur5=42
Dur6=60
Dur5=935
Dur6=1170
Dur5=152
Dur6=931
Dur5=91
Dur6=956
Dur5=184
Dur6=1069
Dur5=47
Dur6=3539
Dur5=173
Dur6=99
Dur5=151
Dur6=70
Dur5=140
Dur6=40
Dur5=98
Dur6=521
Dur5=34
Dur6=119
Dur5=44
Dur6=148
Dur5=63
Dur6=64
Dur5=206
Dur6=688
Bit[24]: 100001100000000011100000
发送端日志如下
KEY_MAP=14
key_scan=14
Send Data: [2, 3, 6]
发送24位数据[0]: 0xAAAAA2, 二进制: 101010101010101010100010
发送24位数据[1]: 0xAAAAA3, 二进制: 101010101010101010100011
发送24位数据[2]: 0xAAAAA6, 二进制: 101010101010101010100110
为何发送的数据和接收的数据不一致?
并且发送端,每次是发送3位数据的,而接收端只能接收到一位数据
逻辑分析仪中,发射端的波形和接收端的波形是一致的
我曾经遇到过类似的问题,433无线收发无法收到准确数据,主要可能是由以下几方面原因导致的:
从你的情况来看,发送端能正常发送数据,逻辑分析仪也显示发射端和接收端的波形一致,但接收数据不准确且只能收到一位,可能是同步和时序匹配出现了问题。发送端发送‘1’时高电平1300微秒、低电平450微秒,发送‘0’时高电平450微秒、低电平1300微秒,而接收端判断‘1’和‘0’是通过比较高低电平持续时间,这种判断方式对时序精度要求很高。另外,接收端日志中出现了负数的持续时间,这可能是定时器溢出或时间计算错误导致的,会干扰对高低电平的判断,进而影响数据接收的准确性。同时,发送端分三帧发送三位数字,接收端需要正确识别这三帧并按顺序收集,但目前可能存在帧识别或顺序错乱的问题,导致只能收到一位数据。
以下是两种解决方案:
COMPARE
状态处理部分修改判断条件。Radio_Send
函数中添加同步标识的发送,同时在接收端的Process_Received_Frame
函数中添加对同步标识的识别和处理。最优方案是优化时序判断机制。因为从问题表现来看,接收端对高低电平的判断不准确是导致数据接收异常的主要原因,而时序判断机制的优化能直接针对这一核心问题。通过设置合理的阈值范围,能有效减少时间波动和异常值对判断的影响,提高数据接收的准确性。相比增加帧同步标识,这种方案不需要对发送的数据结构进行大的改动,实现起来更简单直接,能更快地解决当前接收不到准确数据的问题。而且解决了时序判断的根本问题后,再处理帧的识别和数字收集会更加顺利。
请楼主采纳,如果按照上述方案操作后还有问题,请继续留言。
谢谢您的解答,我现在换了一个方式,使用定时器中断
void RF_RX_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
// 配置DO引脚为输入
GPIO_InitStruct.GPIO_Pin = DATA_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DATA_PORT, &GPIO_InitStruct);
// 初始化定时器
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseInitTypeDef TIM_InitStruct;
TIM_InitStruct.TIM_Prescaler = 47;
TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_InitStruct.TIM_Period = 99;
TIM_TimeBaseInit(TIM3, &TIM_InitStruct);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);//中断使能
// 配置中断优先级
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority =0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
TIM_Cmd(TIM3, ENABLE);
}
自动重载值设置为100.就是100us中断一次,然后判断在每个电平脉宽之间中断了多少次就可以了。现在已经成功接收到完整的数据
现在换了一个方式,使用定时器中断
void RF_RX_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
// 配置DO引脚为输入
GPIO_InitStruct.GPIO_Pin = DATA_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DATA_PORT, &GPIO_InitStruct);
// 初始化定时器
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseInitTypeDef TIM_InitStruct;
TIM_InitStruct.TIM_Prescaler = 47;
TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_InitStruct.TIM_Period = 99;
TIM_TimeBaseInit(TIM3, &TIM_InitStruct);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);//中断使能
// 配置中断优先级
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority =0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
TIM_Cmd(TIM3, ENABLE);
}
自动重载值设置为100.就是100us中断一次,然后判断在每个电平脉宽之间中断了多少次就可以了。现在已经成功接收到完整的数据
麻烦您调整一下排版,支持 markdown 语法
– 博客园团队 3个月前