畜牧定位器

news2024/11/15 5:06:17

qs100.c

#include "qs100.h"

// 内部调用函数:发送AT命令和处理返回响应
static void QS100_SendCmd(uint8_t *cmd);
static void QS100_HandleResp(void);

// 串口接收中断回调
void QS100_UartCallback(uint16_t size);

// 定义接收数据的缓冲区和长度
static uint8_t rxBuff[NB_BUFF_SIZE]; // 一次中断接收的数据,最大128
static uint16_t rxSize;
static uint8_t respBuff[NB_RESP_SIZE]; // 一次完整响应接收的数据,最大256
static uint16_t respSize;

// 初始化
void QS100_Init(void)
{
    // 1. 串口3初始化
    MX_USART3_UART_Init();

    // 2. 配置使用中断方式接收变长数据,打开中断使能
    HAL_UARTEx_ReceiveToIdle_IT(&huart3, rxBuff, NB_BUFF_SIZE);

    // 3. 发送指令进行配置
    // 3.1 重启
    debug_printfln("开始重启NB-IoT模块...");
    QS100_SendCmd("AT+RB\r\n");
    debug_printfln("重启NB-IoT模块完成!");

    // 3.2 设置回显AT指令
    QS100_SendCmd("ATE1\r\n");
}

void QS100_UartCallback(uint16_t size)
{
    rxSize = size;

    // 重新调用 ReceiveToIdle_IT,打开中断使能
    HAL_UARTEx_ReceiveToIdle_IT(&huart3, rxBuff, NB_BUFF_SIZE);
}

static void QS100_SendCmd(uint8_t *cmd)
{
    HAL_UART_Transmit(&huart3, cmd, strlen((char *)cmd), 2000);

    // 中断方式接收响应数据,处理响应
    QS100_HandleResp();
}

static void QS100_HandleResp(void)
{
    // 先清空要保存数据的数组
    memset(rxBuff, 0, NB_BUFF_SIZE);
    rxSize = 0;
    memset(respBuff, 0, NB_RESP_SIZE);
    respSize = 0;

    // 阻塞轮询,等待接收响应
    // 为了处理没有OK和ERROR的情况,增加一个计数值,减到0就退出循环
    uint8_t cnt = 2;
    do
    {
        // 引入超时
        uint32_t timeout = 0xffffff;
        while (rxSize == 0 && timeout--)
        {
        }

        // HAL_Delay(1);

        // 接收到数据,就将 rxBuff 中的内容拼接到 respBuff 中
        memcpy(&respBuff[respSize], rxBuff, rxSize);
        respSize += rxSize;

        // 清零size
        rxSize = 0;
    } while (strstr((char *)respBuff, "OK") == NULL && strstr((char *)respBuff, "ERROR") == NULL && --cnt);

    // 打印输出收到的响应
    debug_printfln("AT命令响应:\n%.*s", respSize, respBuff);
    printf("=======================================\n");
}

// 向 TCP 服务器发送数据
static CommonStatus QS100_GetIP(void);
static CommonStatus QS100_OpenSocket(uint16_t port, uint8_t *socketID);
static CommonStatus QS100_TCP_ConnectServer(uint8_t socketID, uint8_t serverIP[], uint16_t serverPort);
static CommonStatus QS100_TCP_SendDataToServer(uint8_t socketID, uint8_t sequence, uint8_t data[], uint16_t dataLen);

CommonStatus QS100_TCP_SendData(uint8_t serverIP[], uint16_t serverPort, uint8_t data[], uint16_t dataLen)
{
    // 1. 联网
    uint8_t cnt = 60;
    while (QS100_GetIP() == COMMON_ERROR && --cnt)
    {
        Utils_Delay_s(1); // 1s查询一次联网状态
    }
    if (cnt == 0)
    {
        return COMMON_ERROR;
    }

    // 2. 打开Socket(TCP协议)
    cnt = 20;
    uint8_t socketID = 0;
    while (QS100_OpenSocket(0, &socketID) == COMMON_ERROR && --cnt)
    {
        Utils_Delay_s(1); // 1s查询一次联网状态
    }
    if (cnt == 0)
    {
        return COMMON_ERROR;
    }

    // 3. 连接 TCP 服务器
    cnt = 10;
    while (QS100_TCP_ConnectServer(socketID, TCP_SERVER_IP, TCP_SERVER_PORT) == COMMON_ERROR && --cnt)
    {
        Utils_Delay_s(1); // 1s查询一次联网状态
    }
    if (cnt == 0)
    {
        return COMMON_ERROR;
    }

    // 4. 向 TCP 服务器发送数据
    cnt = 10;
    while (QS100_TCP_SendDataToServer(socketID, 5, data, dataLen) == COMMON_ERROR && --cnt)
    {
        Utils_Delay_s(1); // 1s查询一次联网状态
    }
    if (cnt == 0)
    {
        return COMMON_ERROR;
    }

    return COMMON_OK;
}

static CommonStatus QS100_GetIP(void)
{
    // QS100_SendCmd("AT+CGATT=1\r\n");

    // 发送指令
    QS100_SendCmd("AT+CGATT?\r\n");

    // 根据指令响应,判断是否联网
    if (strstr((char *)respBuff, "+CGATT:1"))
    {
        return COMMON_OK;
    }
    return COMMON_ERROR;
}
static CommonStatus QS100_OpenSocket(uint16_t port, uint8_t *socketID)
{
    // 拼接命令
    uint8_t tmpCmd[50] = {0};
    sprintf((char *)tmpCmd, "AT+NSOCR=STREAM,6,%d,0\r\n", port);

    // 发送命令
    QS100_SendCmd(tmpCmd);

    // 如果响应OK,解析出socket 编号
    if (strstr((char *)respBuff, "OK"))
    {
        sscanf((char *)respBuff, "%*[^:]:%hhu", socketID);
        return COMMON_OK;
    }
    return COMMON_ERROR;
}
static CommonStatus QS100_TCP_ConnectServer(uint8_t socketID, uint8_t serverIP[], uint16_t serverPort)
{
    // 拼接命令
    uint8_t tmpCmd[50] = {0};
    sprintf((char *)tmpCmd, "AT+NSOCO=%d,%s,%d\r\n", socketID, serverIP, serverPort);

    // 发送命令
    QS100_SendCmd(tmpCmd);

    if (strstr((char *)respBuff, "OK"))
    {
        return COMMON_OK;
    }
    return COMMON_ERROR;
}
static CommonStatus QS100_TCP_SendDataToServer(uint8_t socketID, uint8_t sequence, uint8_t data[], uint16_t dataLen)
{
    // 格式 AT+NSOSD=0,2,4444,0x200,1

    // 1. 将数据转换成16进制字符串
    uint8_t hexData[2 * dataLen + 1];
    for (uint8_t i = 0; i < dataLen; i++)
    {
        sprintf((char *)&hexData[i * 2], "%02X", data[i]);
    }

    // 2. 拼接命令
    uint8_t tmpCmd[512] = {0};
    sprintf((char *)tmpCmd, "AT+NSOSD=%d,%d,%s,0x200,%d\r\n", socketID, dataLen, hexData, sequence);

    // 3. 发送命令
    QS100_SendCmd(tmpCmd);

    if (strstr((char *)respBuff, "OK"))
    {
        // 4. 查询数据是否发送成功
        // 4.1 清空命令缓冲区
        memset((char *)tmpCmd, 0, strlen((char *)tmpCmd));

        // 4.2 拼接命令
        sprintf((char *)tmpCmd, "AT+SEQUENCE=%d,%d\r\n", socketID, sequence);

        do
        {
            Utils_Delay_s(1);

            // 4.3 每隔1s发送一次命令进行查询
            QS100_SendCmd(tmpCmd);
        } while ( respBuff[19] == '2' );

        // 4.4  如果状态为1,表示发送成功
        if (respBuff[19] == '1')
        {
            return COMMON_OK;   
        }
    }
    return COMMON_ERROR;
}

// 进入低功耗模式(PSM模式)
void QS100_EnterLowPower(void)
{
    debug_printfln("NB-IoT设备进入低功耗模式...");
    QS100_SendCmd("AT+FASTOFF=0\r\n");
}
// 退出低功耗模式(用NB_WKUP引脚唤醒)
void QS100_ExitLowPower(void)
{
    debug_printfln("NB-IoT设备从睡眠中唤醒...");

    HAL_GPIO_WritePin(NB_WKUP_GPIO_Port, NB_WKUP_Pin, GPIO_PIN_SET);
    Utils_Delay_ms(150);
    HAL_GPIO_WritePin(NB_WKUP_GPIO_Port, NB_WKUP_Pin, GPIO_PIN_RESET);
}

ds3553.c

/*
 * @Author: wushengran
 * @Date: 2024-11-05 16:07:52
 * @Description: 
 * 
 * Copyright (c) 2024 by atguigu, All Rights Reserved. 
 */
#include "ds3553.h"

// 初始化
void DS3553_Init(void)
{
    MX_I2C1_Init();
}

// 定义内部静态函数,读取某个寄存器的值(传入地址)
static uint8_t DS3553_ReadReg(uint8_t regAddr)
{
    // 定义变量保存读取的值
    uint8_t result = 0;

    // 1. CS拉低
    DS3553_CS_L;
    Utils_Delay_ms(4);

    // 2. 调库I2C读取从设备数据
    // 2.1 假写
    HAL_I2C_Master_Transmit(&hi2c1, DS3553_ADDR_W, &regAddr, 1, 2000);

    // 2.2 真读
    HAL_I2C_Master_Receive(&hi2c1, DS3553_ADDR_R, &result, 1, 2000);

    // 3. CS拉高
    DS3553_CS_H;
    Utils_Delay_ms(11);

    return result;
}

// 读取芯片ID
uint8_t DS3553_ReadID(void)
{
    return DS3553_ReadReg(DS3553_REG_CHIP_ID);
}

// 读取计步数值(24位)
uint32_t DS3553_ReadCNT(void)
{
    uint8_t buff[3] = {0};
    buff[0] = DS3553_ReadReg(DS3553_REG_STEP_CNT_L);
    buff[1] = DS3553_ReadReg(DS3553_REG_STEP_CNT_M);
    buff[2] = DS3553_ReadReg(DS3553_REG_STEP_CNT_H);
    
    return buff[0] + (buff[1] << 8) + (buff[2] << 16);
}

at6558r.c

/*
 * @Author: wushengran
 * @Date: 2024-11-04 15:59:07
 * @Description:
 *
 * Copyright (c) 2024 by atguigu, All Rights Reserved.
 */
#include "at6558r.h"

static void AT6558R_SendCmd(uint8_t *cmd);

// 定义接收GPS数据的缓冲区和长度
static uint8_t rxBuff[GPS_INFO_BUFF_SIZE];
static uint16_t rxSize;

// 初始化
void AT6558R_Init(void)
{
    // 1. 初始化串口2
    MX_USART2_UART_Init();

    // 2. 配置使用中断方式接收变长数据,打开中断使能
    HAL_UARTEx_ReceiveToIdle_IT(&huart2, rxBuff, GPS_INFO_BUFF_SIZE);

    // 3. 发送指令进行配置
    // 配置GPS工作模式
    debug_printfln("GPS定位模块配置:工作模式为 GPS + 北斗");
    AT6558R_SendCmd(GPS_MODE);

    // 设置定位更新频率
    debug_printfln("GPS定位模块配置:更新频率为 1Hz");
    AT6558R_SendCmd(GPS_UPDATE_FREQ);
}

// 发送命令函数,传入$和*之间的内容
static void AT6558R_SendCmd(uint8_t *cmd)
{
    // 计算校验和
    uint16_t cs = cmd[0];
    for (uint8_t i = 1; cmd[i] != '\0'; i++)
    {
        cs ^= cmd[i];
    }
    debug_printfln("cs = %X", cs);

    // 将cs拼接到完整命令中
    uint8_t tmpCmd[50] = {0};
    sprintf((char *)tmpCmd, "$%s*%X\r\n", cmd, cs);

    // 串口发送命令
    HAL_UART_Transmit(&huart2, tmpCmd, strlen((char *)tmpCmd), 2000);
    debug_printfln("tmpCmd = %s", tmpCmd);
}

void AT6558R_UartCallback(uint16_t size)
{
    // 获取接收到的数据长度
    rxSize = size;

    // 重新开启中断接收方式
    HAL_UARTEx_ReceiveToIdle_IT(&huart2, rxBuff, GPS_INFO_BUFF_SIZE);
}

// 读取GPS数据
void AT6558R_ReadData(uint8_t data[], uint16_t *dataLen)
{
    // 先清空要保存数据的数组
    memset(data, 0, strlen((char *)data));
    *dataLen = 0;

    // 根据rxSize,判断是否接收到数据
    if (rxSize == 0)
    {
        return;
    }

    // 将接收到的数据复制到data中
    if (strstr((char *)rxBuff, GPS_INFO_BEGIN) && strstr((char *)rxBuff, GPS_INFO_END))
    {
        memcpy(data, rxBuff, rxSize);
        *dataLen = rxSize;
    }

    // 清零size
    rxSize = 0;
}

// 进入低功耗模式,直接将 GPS_EN 拉低,断电
void AT6558R_EnterLowPower(void)
{
    debug_printfln("GPS 模块电源关闭...");
    HAL_GPIO_WritePin(GPS_EN_GPIO_Port, GPS_EN_Pin, GPIO_PIN_RESET);
}
// 退出低功耗模式
void AT6558R_ExitLowPower(void)
{
    debug_printfln("GPS 模块电源打开...");
    HAL_GPIO_WritePin(GPS_EN_GPIO_Port, GPS_EN_Pin, GPIO_PIN_SET);
}

communication.c

/*
 * @Author: wushengran
 * @Date: 2024-11-05 11:20:14
 * @Description:
 *
 * Copyright (c) 2024 by atguigu, All Rights Reserved.
 */
#include "communication.h"
#include "cJSON.h"

// 启动通讯模块
void Communication_Start(void)
{
    AT6558R_Init();
    QS100_Init();
    LoRa_Init();
}

// 接收GPS数据缓冲区
uint8_t gpsData[GPS_INFO_BUFF_SIZE];
uint16_t gpsDataLen;

// 接收 GPS 数据
void Communication_GetGpsInfo(UploadDataType *data)
{
    debug_printfln("读取 GPS 定位信息...");

    // 定义指针,指向 RMC 数据的位置
    char *rmcStart;

    // 轮询进行数据接收
    while (1)
    {
        // 接收GPS数据
        AT6558R_ReadData(gpsData, &gpsDataLen);

        if (gpsDataLen > 0)
        {
            // 有数据,找到 RMC 的起始位置
            // rmcStart = strstr((char *)gpsData, "$GNRMC");
            rmcStart = "$GNRMC,070822.000,A,4006.81888,N,11621.89413,E,0.81,359.02,020624,,,A,V*02";

            // 跳过不是A和V的所有字符,找到有效标记位
            uint8_t valid = 0;
            sscanf(rmcStart, "%*[^AV]%c", &valid);

            // 如果是A,就是有效数据,退出轮询进行数据包装
            if (valid == 'A')
            {
                debug_printfln("有效定位数据:\n%s", gpsData);
                break;
            }
            // 如果是V,无效数据,继续循环读取接收到的数据
            else
            {
                debug_printfln("无效定位数据:\n%s", gpsData);
            }
        }
    }

    // 解析 GPS 信息
    // 数据示例:$GNRMC,070822.000,A,4006.81888,N,11621.89413,E,0.81,359.02,020624,,,A,V*02

    // 定义保存时间和日期的字符串
    char time[7] = {0}; // 时分秒,格式 hhmmss
    char date[7] = {0}; // 日月年,格式 ddMMyy

    // 提取信息到对应变量中
    sscanf(rmcStart, "$GNRMC,%6c%*7c%lf,%c,%lf,%c,%lf,%*f,%6c",
           time,
           &data->lat, (char *)&data->latDir,
           &data->lon, (char *)&data->lonDir,
           &data->speed,
           date);

    // 合成dataTime,格式 yyyy-MM-dd hh:mm:ss
    sprintf((char *)data->dateTime, "20%c%c-%c%c-%c%c %c%c:%c%c:%c%c",
            date[4], date[5], date[2], date[3], date[0], date[1],
            time[0], time[1], time[2], time[3], time[4], time[5]);

    Utils_Time_UTC2Beijing(data->dateTime, data->dateTime);

    // 调整经纬度信息,保存成 xxx.xxx 形式,单位是度
    uint8_t lat_int = (uint8_t)(data->lat / 100); // 纬度的整数部分(单位度)
    data->lat = lat_int + (data->lat - lat_int * 100) / 60;
    uint8_t lon_int = (uint8_t)(data->lon / 100); // 经度的整数部分(单位度)
    data->lon = lon_int + (data->lon - lon_int * 100) / 60;
}

static void Communication_FormatDataToJson(UploadDataType *data);
static CommonStatus Communication_SendDataByNBIoT(UploadDataType *data);
static CommonStatus Communication_SendDataByLoRa(UploadDataType *data);

// 发送要上传的数据(通过NB-IoT 或 LoRa)
void Communication_SendData(UploadDataType *data)
{
    // 1. 将数据转换为JSON串
    Communication_FormatDataToJson(data);

    // 2. 通过NB-IoT发送
    CommonStatus sendStatus = Communication_SendDataByNBIoT(data);

    // 3. 如果发送失败,就再通过LoRa发送
    if (sendStatus == COMMON_ERROR)
    {
        debug_printfln("NB-IoT发送失败,将通过LoRa发送数据...");
        Communication_SendDataByLoRa(data);
    }
}

static void Communication_FormatDataToJson(UploadDataType *data)
{
    // 0. 将UID补充到数据中(16进制字符形式)
    sprintf((char *)data->uid, "%08X%08X%08X", HAL_GetUIDw2(), HAL_GetUIDw1(), HAL_GetUIDw0());

    // 1. 创建一个JSON对象
    cJSON *cjson = cJSON_CreateObject();

    // 2. 向JSON对象中逐个添加键值对
    cJSON_AddStringToObject(cjson, "uid", (char *)data->uid);
    cJSON_AddNumberToObject(cjson, "lon", data->lon);
    cJSON_AddStringToObject(cjson, "lonDir", (char *)data->lonDir);
    cJSON_AddNumberToObject(cjson, "lat", data->lat);
    cJSON_AddStringToObject(cjson, "latDir", (char *)data->latDir);
    cJSON_AddNumberToObject(cjson, "speed", data->speed);
    cJSON_AddStringToObject(cjson, "dateTime", (char *)data->dateTime);
    cJSON_AddNumberToObject(cjson, "stepNum", data->stepNum);

    // 3. 生成JSON字符串
    char *out = cJSON_PrintUnformatted(cjson);
    data->jsonLen = strlen(out);
    memcpy(data->json, out, data->jsonLen);

    // 4. 释放cJSON对象(堆空间)
    cJSON_Delete(cjson);

    printData(data);
}

// --- 以NB-IoT方式发送数据
static CommonStatus Communication_SendDataByNBIoT(UploadDataType *data)
{
    return QS100_TCP_SendData(TCP_SERVER_IP, TCP_SERVER_PORT, data->json, data->jsonLen);
}

// ---- 以LoRa方式发送数据
static CommonStatus Communication_SendDataByLoRa(UploadDataType *data)
{
    return (CommonStatus)LoRa_SendData(data->json, data->jsonLen);
}

// 打印输出要上传的数据
void printData(UploadDataType *data)
{
    printf("GPS 信息:\n");
    printf("  经度:%lf, 方向:%s\n", data->lon, data->lonDir);
    printf("  纬度:%lf, 方向:%s\n", data->lat, data->latDir);
    printf("  对地速度:%lf 节\n", data->speed);
    printf("  定位时间:%s\n", data->dateTime);

    printf("计步信息:\n");
    printf("  运动步数:%u\n", data->stepNum);

    printf("上传的数据:\n");
    printf("  数据长度:%d\n", data->jsonLen);
    printf("  数据:%.*s\n", data->jsonLen, data->json);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2240620.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数字图像处理(c++ opencv):图像复原与重建-常见的滤波方法--自适应滤波器

自适应局部降噪滤波器 自适应局部降噪滤波器&#xff08;Adaptive, Local Noise Reduction Filter&#xff09;原理步骤 步骤 &#xff08;1&#xff09;计算噪声图像的方差 &#xff1b; &#xff08;2&#xff09;计算滤波器窗口内像素的均值 和方差 &#xff1b; &…

websocket身份验证

websocket身份验证 前言 上一集我们就完成了websocket初始化的任务&#xff0c;那么我们完成这个内容之后就应该完成一个任务&#xff0c;当客户端与服务端连接成功之后&#xff0c;客户端应该主动发起一个身份认证的消息。 身份认证proto 我们看一眼proto文件的内容。 我…

鸿蒙HarmonyOS 地图不显示解决方案

基于地图的开发准备已完成的情况下&#xff0c;地图还不显式的问题 首先要获取设备uuid 获取设备uuid 安装DevEco Studio的路径下 有集成好的hdc工具 E:\install_tools\DevEco Studio\sdk\default\openharmony\toolchains 这个路径下打开cmd运行 进入“设置 > 关于手机…

Day44 | 动态规划 :状态机DP 买卖股票的最佳时机IV买卖股票的最佳时机III

Day44 | 动态规划 &#xff1a;状态机DP 买卖股票的最佳时机IV&&买卖股票的最佳时机III&&309.买卖股票的最佳时机含冷冻期 动态规划应该如何学习&#xff1f;-CSDN博客 本次题解参考自灵神的做法&#xff0c;大家也多多支持灵神的题解 买卖股票的最佳时机【…

PySpark——Python与大数据

一、Spark 与 PySpark Apache Spark 是用于大规模数据&#xff08; large-scala data &#xff09;处理的统一&#xff08; unified &#xff09;分析引擎。简单来说&#xff0c; Spark 是一款分布式的计算框架&#xff0c;用于调度成百上千的服务器集群&#xff0c;计算 TB 、…

<项目代码>YOLOv8 番茄识别<目标检测>

YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv8具有更高的…

MySQL技巧之跨服务器数据查询:基础篇-动态参数

MySQL技巧之跨服务器数据查询&#xff1a;基础篇-动态参数 上一篇已经描述&#xff1a;借用微软的SQL Server ODBC 即可实现MySQL跨服务器间的数据查询。 而且还介绍了如何获得一个在MS SQL Server 可以连接指定实例的MySQL数据库的连接名: MY_ODBC_MYSQL 以及用同样的方法&a…

三天精通一种算法之螺旋矩阵(设计思路),长度最小子数组(滑动窗口)

这题主要考察思维 我来一一解释这串代码 var generateMatrix function(n) { const matrix Array.from({ length: n }, () > Array(n).fill(0)); let top 0, bottom n - 1; let left 0, right n - 1; var num 1; while (num < n * n) { …

2024-11-13 Unity Addressables1——概述与导入

文章目录 1 概述1.1 介绍1.2 主要作用1.3 Addressables 与 AssetBundle 的区别 2 导入3 配置3.1 方法一3.2 方法二 1 概述 1.1 介绍 ​ Addressables 是可寻址资源管理系统。 ​ Unity 从 2018.2 版本开始&#xff0c;建议用于替代 AssetBundle 的高阶资源管理系统。在 Unit…

python爬虫实战案例——爬取A站视频,m3u8格式视频抓取(内含完整代码!)

1、任务目标 目标网站&#xff1a;A站视频&#xff08;https://www.acfun.cn/v/ac40795151&#xff09; 要求&#xff1a;抓取该网址下的视频&#xff0c;将其存入本地&#xff0c;视频如下&#xff1a; 2、网页分析 进入目标网站&#xff0c;打开开发者模式&#xff0c;我们发…

web实验3:虚拟主机基于不同端口、目录、IP、域名访问不同页面

创建配置文件&#xff1a; 创建那几个目录及文件&#xff0c;并且写内容&#xff1a; 为网卡ens160添加一个 IPv4 地址192.168.234.199/24: 再重新激活一下网卡ens160&#xff1a; 重启服务&#xff1a; 关闭防火墙、改宽松模式&#xff1a; 查看nginx端口监听情况&#xff1a;…

在tiktok开店,商家可以享受到多少显著的优势?

短视频带货正在蓬勃发展&#xff0c;因此&#xff0c;许多人开始利用自媒体平台进行商品销售。越来越多的商家选择在TikTok上开设店铺。那么&#xff0c;在TikTok上开店&#xff0c;商家可以享受到哪些显著的优势呢&#xff1f; 1. 庞大的用户基础 TikTok拥有海量的用户群体&…

【系统设计】理解带宽延迟积(BDP)、吞吐量、延时(RTT)与TCP发送窗口的关系:优化网络性能的关键

在设计和优化网络性能时&#xff0c;理解 带宽延迟积&#xff08;BDP&#xff09;、吞吐量、延时&#xff08;RTT&#xff09; 和 TCP发送窗口 之间的关系至关重要。这些概念相互影响&#xff0c;决定了网络连接的性能上限&#xff0c;尤其是在高带宽、高延迟的环境中&#xff…

Flutter:使用Future发送网络请求

pubspec.yaml配置http的SDK cupertino_icons: ^1.0.8 http: ^1.2.2请求数据的格式转换 // Map 转 json final chat {name: 张三,message: 吃饭了吗, }; final chatJson json.encode(chat); print(chatJson);// json转Map final newChat json.decode(chatJson); print(newCha…

IOT物联网低代码可视化大屏解决方案汇总

目录 参考来源云服务商阿里云物联网平台产品主页产品文档 开源项目DGIOT | 轻量级工业物联网开源平台项目特点项目地址开源许可 IoTGateway | 基于.NET6的跨平台工业物联网网关项目特点项目地址开源许可 IoTSharp | 基于.Net Core开源的物联网基础平台项目特点项目地址开源许可…

redis 原理篇 26 网络模型 Redis是单线程的吗?为什么使用单线程

都是学cs的&#xff0c;有人月薪几万&#xff0c;有人月薪几千&#xff0c;哎&#xff0c; 相信 边际效用&#xff0c; 也就是说&#xff0c; 随着技术提升的越来越多&#xff0c;薪资的提升比例会更大 一个月几万&#xff0c;那肯定是高级开发了&#xff0c; 一个月几千&…

前端中的 File 和 Blob两个对象到底有什么不同

JavaScript 在处理文件、二进制数据和数据转换时&#xff0c;提供了一系列的 API 和对象&#xff0c;比如 File、Blob、FileReader、ArrayBuffer、Base64、Object URL 和 DataURL。每个概念在不同场景中都有重要作用。下面的内容我们将会详细学习每个概念及其在实际应用中的用法…

【QT常用技术讲解】优化网络链接不上导致qt、qml界面卡顿的问题

前言 qt、qml项目经常会涉及访问MySQL数据库、网络服务器&#xff0c;并且界面打开时的初始化过程就会涉及到链接Mysql、网络服务器获取数据&#xff0c;如果网络不通&#xff0c;卡个几十秒&#xff0c;会让用户觉得非常的不爽&#xff0c;本文从技术调研的角度讲解解决此类问…

JS的学习与使用

JS的学习与使用 一 什么是Javascript&#xff1f; Javascript是一门跨平台&#xff0c;面向对象的脚本语言&#xff0c;是用来控制网页行为的&#xff0c;它能使网页可以交互 java与Javascript是完全不同的语言&#xff0c;不论是概念还是设计&#xff0c;但是基础语法类似 E…

WebRTC视频 03 - 视频采集类 VideoCaptureDS 上篇

WebRTC视频 01 - 视频采集整体架构 WebRTC视频 02 - 视频采集类 VideoCaptureModule [WebRTC视频 03 - 视频采集类 VideoCaptureDS 上篇]&#xff08;本文&#xff09; WebRTC视频 04 - 视频采集类 VideoCaptureDS 中篇 WebRTC视频 05 - 视频采集类 VideoCaptureDS 下篇 一、前…