STM32F103实现对设备在线通信出错进行处理

针对STM32F103CB UCOSII实时操作系统实现当检测设备在先后,向在线设备发送多帧数据完成后再向下一在线设备发送多帧数据,依次类推。如果设备在线,但是设备接收数据失败,导致发送不成功的情况进行处理,跳过通信失败的设备。对数据发送到一半导致的通信出错进行处理,重试3次不成功后跳过当前设备,继续向下一在线设备发送数据。具体的代码实现如下:
1.定义信号量

OS_EVENT *I2C_Receive_Complete_Sem;// 定义I2C接收数据完成信号量
OS_EVENT *I2C_Send_Wait_Sem;// 定义I2C发送数据等待信号量
OS_EVENT *DeviceQueue;//消息队列指针
void *DeviceQueueEntries[16];//消息队列存储地址,最大支持16个消息

2.检测设备是否在线

//设备是否在线检测任务
void TaskCheckDevices(void *pdata) {
    OS_CPU_SR cpu_sr = 0; // CUP状态寄存器
    while (1) {
        for (int deviceIndex = 0; deviceIndex < sizeof(slave_addresses) / sizeof(slave_addresses[0]); deviceIndex++) {
            uint8_t deviceAddress = slave_addresses[deviceIndex];

            OS_ENTER_CRITICAL(); // 进入临界区,禁止中断
            int isOnline = I2C_CheckDevice(I2C1, deviceAddress);
            OS_EXIT_CRITICAL(); // 退出临界区,允许中断

            if (isOnline) {
                OSQPost(DeviceQueue, (void*)(uintptr_t)deviceAddress);
            }
            else {
                printf(" Device 0x%02X is offline, skipping...\r\n", deviceAddress);
            }
        }
        OSTimeDlyHMSM(0, 0, 10, 0); // 每10秒检查一次
    }
}

3.发送数据

void TaskSend(void *pdata) {
    OS_CPU_SR cpu_sr;
    uintptr_t msg;
    u8 err;
    while (1) {
        msg = (uintptr_t)OSQPend(DeviceQueue, 0, &err); // 等待设备地址从队列中获取
        if (err == OS_ERR_NONE) {
            uint8_t deviceAddress = (uint8_t)msg;
            int deviceIndex = -1;
            //查找设备在数组中的索引
            for (int i = 0; i < sizeof(slave_addresses)/sizeof(slave_addresses[0]); i++) {
                if (slave_addresses[i]==deviceAddress) {
                    deviceIndex = i;
                    break;
                }
            }
            //检查从机地址
            if (deviceIndex == -1) {
                printf(" TaskSend: Device address not found in slave_addresses array.\n");
                continue;
            }

            // 检查设备状态
            if (device_status[deviceIndex]) {
                printf(" TaskSend: Device 0x%02X is marked as unavailable, skipping...\n", deviceAddress);
                continue;
            }

            OSSemPend(I2C_Send_Wait_Sem, 0, &err); // 等待设备数据发送完毕
            if (err == OS_ERR_NONE) {
                responseAddress = deviceAddress;
                handle_tx_chmc_data(); // 处理发送数据准备工作
                for (frameIndex = 0; frameIndex < sizeof(buffers)/sizeof(buffers[0]); frameIndex++) {
                    int retryCount = 0;
                    bool send_success = false;
                    while (retryCount < MAX_RETRY_COUNT &&!send_success) {
                        OS_ENTER_CRITICAL(); // 开启临界区  
                        send_success = i2c_master_send_buffer_data(responseAddress, buffers[frameIndex], bufferSizes[frameIndex]);
                        printf(" ||Send %s command<====================>0x%02X \n", commandsNames[frameIndex], responseAddress);
                        OS_EXIT_CRITICAL(); // 结束临界区
                        // 检查特定错误码,设备在线发送数据出错时
                        if ((send_success == false && I2CErrorCode == 5) || (send_success == false && I2CErrorCode == 6)){
                            printf(" TaskSend:Device 0x%02X send data failed \r\n",deviceAddress);
                            device_status[deviceIndex]=false;
                            break;
                        }
                        
                        if (!send_success) {
                            retryCount++;
                            OSTimeDlyHMSM(0, 0, 0, 500); // 等待500ms后重试
                            // 检测设备状态
                            OS_ENTER_CRITICAL();
                            int isOnline = I2C_CheckDevice(I2C1, deviceAddress);
                            OS_EXIT_CRITICAL();
                            if (!isOnline) {
                                printf(" TaskSend: Device 0x%02X is offline during retry, marking as unavailable.\n", deviceAddress);
                                device_status[deviceIndex]=false; // 标记设备为不可用
                                break; // 跳过该设备
                            }
                        }
                    }

                    if (!send_success) {
                        printf(" TaskSend: Failed to send data to device 0x%02X after %d retries, marking as unavailable.\n", deviceAddress, MAX_RETRY_COUNT);
                        device_status[deviceIndex]=false; // 标记设备为不可用
                        break; // 跳过该设备
                    }

                    OSSemPost(I2C_Receive_Complete_Sem); // 授权接收任务
                    OSTimeDlyHMSM(0, 0, 0, 50);
                    OSSemPost(I2C_Send_Wait_Sem); // 释放发送权限
                }
            }
        } else {
            printf(" TaskSend: Error during queue pend.\n");
        }
    }
}
针对您的问题,以下是stm32f103c8t6 SPI双机通信的步骤: 一、SPI主机配置 1. 配置SPI口为主机模式,设置SPI口的工作模式、数据大小、时钟极性、时钟相位等参数。 2. 使能SPI口,等待SPI口空闲。 二、SPI从机配置 1. 配置SPI口为从机模式,设置SPI口的工作模式、数据大小、时钟极性、时钟相位等参数。 2. 使能SPI口,等待SPI口空闲。 三、双机通信 1. 轮询+中断(低速):主机发送数据,从机接收数据,主机等待从机接收完成中断,从机接收完成后发送中断信号,主机接收中断信号后读取数据。 2. 轮询+DMA(低速):主机发送数据,从机接收数据,主机等待DMA传输完成,从机接收完成后发送DMA传输完成信号,主机接收信号后读取数据。 3. DMA+DMA(高速):主机发送数据,从机接收数据,主机使用DMA传输数据,从机使用DMA接收数据,传输完成后从机发送DMA传输完成信号,主机接收信号后读取数据。 4. 开启CRC校验(自选):在数据传输过程中,可以开启CRC校验,以保证数据传输的正确性。 四、遇到的问题 1. 高速使用时,程序卡死,或者数据出错(已解决):可能是由于时钟极性、时钟相位等参数设置不正确导致的,需要重新设置参数。 2. 数据莫名其妙乱码,主机发送正常,接收乱码等:可能是由于数据大小设置不正确导致的,需要重新设置数据大小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九点两刻

你的支持是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值