项目名称:智能家居边缘网关项目

news2024/10/7 4:32:08

一,项目介绍

软件环境: C语言
硬件环境: STM32G030C8TX单片机开发板
开发工具: Linux平台GCC交叉编译环境以及ukeil

(1)边缘网关概念

  边缘网关是部署在网络边缘侧的网关,通过网络联接、协议转换等功能联接物理和数字世界,提供轻量化的联接管理、实时数据分析及应用管理功能。比较常见的就是智能家居中智能音箱(蓝牙网关)+路由器(wifi网关),工厂里的工业网关等。它们通常扮演着一个区域内中心网关的功能,即负责终端设备的网络连接,也负责各终端数据的采集以及远程控制。同时,又提供数据上云的功能。

  

(2)包含知识点

两大网联网场景:消费物联网、工业物联网两大场景全覆盖

边缘网关新概念:物联网边缘网关中边缘采集、边缘计算两大主流技术

基础综合运用:C、shell、Makefile、C++、QT、单片机、数据库等基础知识大融合

Linux开发技术点:进程间通信、多线程程序设计、文件操作、网络编程、应用协议

物联网主流通信技术:Json、Modbus、mqtt

各种调试工具学习:mqtt.fx、modbus slave、modbus poll、wireshark、网络调试、串口调试等

二,产品需求矩阵

上位机:搜索界面,设备信息显示和控制界面,监控界面 ,历史数据查询,边缘计算

网关:上报模块,公有云模块,搜索响应模块,数据存储模块,内置网页,各采集模块,视频流模块

设备端:stm32模块,modbus模块

三,全局点表

点表使用

真实物联网场景中,点表通过客户端界面(上位机或者web页面)编辑,生成json文件后下发给设备,设备解析使用。

四,modbus采集进程

 modbus采集模块实现了modbus工业设备的通信对接,向上通过modbusTCP协议采集单片机的数据,并刷新到共享内存,以便上报模块进程使用。向下接收来自上报模块的JSON控制指令,解析后,转换为标准的modbusTCP指令后通过网络发送给设备,实现设备的控制。

(1)主程序:

int main(int argc, char const *argv[])
{
    INIT_LIST_HEAD(&head);
    FILE *fd = fopen("./node.json", "r");
    if (fd == NULL)
    {
        perror("fopen err\n");
    }
    //定位文件末尾操作
    fseek(fd, 0, SEEK_END);
    //计算文件的大小
    int len = ftell(fd);
    //定位文件开头操作
    fseek(fd, 0, SEEK_SET);
    char *p = (char *)malloc(len + 1);
    fread(p, 1, len, fd);

    cJSON *root = NULL;
    //把传入的字符串转成cJSON的结构(反序列化)
    root = cJSON_Parse(p);
    if (root == NULL)
    {
        perror("err parse\n");
        //return -1;
    }
    //版本
    cJSON *item = cJSON_GetObjectItem(root, "version");
    printf("version =%s\n", item->valuestring);

    item = cJSON_GetObjectItem(root, "mb_dev");
    char *IP = cJSON_GetObjectItem(item, "addr")->valuestring;
    int pot = cJSON_GetObjectItem(item, "port")->valueint;
    printf("ip=%s port=%d\n", IP, pot); //解析端口和设备地址

    //解析modbus
    cJSON *ROO = cJSON_GetObjectItem(root, "modbus");
    cJSON *tem = cJSON_GetObjectItem(ROO, "data");
    int array_size = cJSON_GetArraySize(tem); //数组的大小
    cJSON *JS_tem = tem->child;               //子对象

    for (int i = 0; i < array_size; i++)
    {
        struct mb_node_list *arr = (struct mb_node_list *)malloc(sizeof(struct mb_node_list));
        printf("key=%d\n", cJSON_GetObjectItem(JS_tem, "key")->valueint);
        printf("name=%s\n", cJSON_GetObjectItem(JS_tem, "name")->valuestring);
        printf("addr=%d\n", cJSON_GetObjectItem(JS_tem, "addr")->valueint);
        printf("type=%d\n", cJSON_GetObjectItem(JS_tem, "type")->valueint);

        arr->node.key = cJSON_GetObjectItem(JS_tem, "key")->valueint;
        arr->node.addr = cJSON_GetObjectItem(JS_tem, "addr")->valueint;
        list_add(&arr->list, &head);
        JS_tem = JS_tem->next;
    }

    //1,创建实例
    //modbus_t *ctx = modbus_new_tcp(argv[1], atoi(argv[2]));
    modbus_t *ctx = modbus_new_tcp(IP, pot);
    //2,设置从机ID
    modbus_set_slave(ctx, 1);
    //3,和主机进行连接
    int slave = modbus_connect(ctx);
    if (slave != 0)
    {
        perror("connect err");
        return -1;
    }
    else
    {
        printf("连接成功!!!!\n");
    }

    //数据采集线程

    if (pthread_create(&tid, NULL, mythread, ctx) != 0)
    {
        perror("pthread_create err");
        return -1;
    }

    //指令控制
    if (pthread_create(&tid, NULL, controlthread, ctx) != 0)
    {
        perror("pthread_create_control err");
        return -1;
    }
    pthread_detach(tid);
    while (1)
        ;

    //6,释放Modbus实例
    modbus_free(ctx);
    //7,关闭套接字
    modbus_close(ctx);

    return 0;
}

(2)数据采集线程:

//数据采集线程
void *mythread(void *arg)
{

    uint16_t data[1024] = {};
    uint16_t data1[1024] = {};
    uint8_t dest[1024] = {};

    int ret = -1;
    ret = shm_init(&para, "shm_test", MAX_NODE_SIZE); //初始化
    if (ret < 0)
    {
        perror("shm_init err\n");
        //return -1;
    }
    //获取共享内存的地址并将其赋值给指针变量addr
    void *addr = shm_getaddr(&para);
    if (addr == NULL)
    {
        perror("shm_getaddr err\n");
        //return -1;
    }
    int *p = NULL;
    p = addr;
    printf("Address=%p\n", p);
    int *num = addr;
    struct std_node *add = (addr + sizeof(int));

    modbus_t *ctx = (modbus_t *)arg;

    while (1)
    {
        sleep(2);
        list_for_each(pos, &head)
        {
            tmp1 = list_entry(pos, struct mb_node_list, list);
            //温度
            if (tmp1->node.key == 101)
            {
                modbus_read_input_registers(ctx, tmp1->node.addr - 1, 2, data);
            }
            //湿度
            else if (tmp1->node.key == 102)
            {
                modbus_read_input_registers(ctx, tmp1->node.addr - 1, 2, data + 2);
            }

            //空调开关
            else if (tmp1->node.key == 103)
            {
                modbus_read_bits(ctx, tmp1->node.addr - 1, 2, dest);
                //printf("空调开关= %u  ", dest[0]);
            }
            //空调的温度,
            //读取保持寄存器(功能码 0x3)
            else if (tmp1->node.key == 104)
            {
                modbus_read_registers(ctx, tmp1->node.addr , 2, data1);
            }
            //风扇开关
            else if (tmp1->node.key == 105)
            {
                modbus_read_bits(ctx, tmp1->node.addr - 1, 2, dest + 2);
            }
            //风扇档位1档,2档,3档
            else if (tmp1->node.key == 106)
            {
                modbus_read_registers(ctx, tmp1->node.addr , 2, data1 + 2);
            }
            printf("温度寄存器= %u  湿度寄存器= %u\n", data[0], data[2]);
            printf("空调温度的监测= %u  风扇的档位=%u\n", data1[0], data1[2]);
            printf("空调开关的状态:=%u 风扇开关的状态:=%u\n", dest[0], dest[1]);
        }
/* 读取的方式
        modbus_read_input_registers(ctx, 0, 4, data);
        //读输入寄存器的值,可读取多个连续输入寄存器的值(对应功能码为0x04)
        //温度,湿度
        printf("温度寄存器= %u  湿度寄存器= %u\n", data[0], data[2]);
        //空调的温度,风扇档位1档,2档,3档
        //读取保持寄存器(功能码 0x3)
        modbus_read_registers(ctx, 0, 4, data1);
        printf("空调温度的监测= %u  风扇的档位=%u\n", data1[0], data1[2]);
        //空调开关和风扇开关
        //读取线圈或者离散量输出状态(功能码 0x1)
        modbus_read_bits(ctx, 0, 4, dest);
        printf("空调开关的状态:=%u 风扇开关的状态:=%u\n", dest[0], dest[1]);
*/

        for (int i = 0; i < *num; i++)
        {
            
            if (add[i].key == 101) //温度
            {
                add[i].new_val.f_val = modbus_get_float_dcba(data);
                printf("Temperature sensor=%f\n", add[i].new_val.f_val);
                if (add[i].new_val.f_val != 0)
                {
                    add[i].ret = 0;
                }
                else
                {
                    add[i].ret = -1;
                    printf("Temperature sensor err:=%d\n", add[i].ret);
                }
            }
            else if (add[i].key == 102) //湿度
            {
                add[i].new_val.f_val = modbus_get_float_dcba(data + 2);
                printf("Humidity sensor=%f\n", add[i].new_val.f_val);

                if (add[i].new_val.f_val != 0)
                {
                    add[i].ret = 0;
                }
                else
                {
                    add[i].ret = -1;
                    printf("Humidity sensor err:=%d\n", add[i].ret);
                }
            }
            else if (add[i].key == 103) //空调开关
            {
                add[i].new_val.b_val = dest[0];
                printf("air conditioning switch=%d\n", add[i].new_val.b_val);
                if (add[i].new_val.b_val != 0)
                {
                    add[i].ret = 0;
                }
                else
                {
                    add[i].ret = -1;
                    printf("air conditioning switch err:=%d\n", add[i].ret);
                }
            }
            else if (add[i].key == 104) //空调的温度
            {
                add[i].new_val.f_val = modbus_get_float_dcba(data1);
                printf("air conditioning temperature=%f\n", add[i].new_val.f_val);
                if (add[i].new_val.f_val != 0)
                {
                    add[i].ret = 0;
                }
                else
                {
                    add[i].ret = -1;
                    printf("air conditioning temperature err:=%d\n", add[i].ret);
                }
            }
            else if (add[i].key == 105) //风扇开关
            {
                add[i].new_val.b_val = dest[1];
                printf("Fan switch=%d\n", add[i].new_val.b_val);
                if (add[i].new_val.b_val != 0)
                {
                    add[i].ret = 0;
                }
                else
                {
                    add[i].ret = -1;
                    printf("Fan switch err:=%d\n", add[i].ret);
                }
            }
            else if (add[i].key == 106) ///风扇档位控制,1档,2档,3档
            {
                add[i].new_val.f_val = modbus_get_float_dcba(data1 + 2);
                printf("Fan switch control=%f\n", add[i].new_val.f_val);
                if (add[i].new_val.f_val != 0)
                {
                    add[i].ret = 0;
                }
                else
                {
                    add[i].ret = -1;
                    printf("Fan switch err:=%d\n", add[i].ret);
                }
            }
        }
        

        for (int i = 0; i < 6; i++)
        {
            if (add[i].key == 101)
            {
                printf("key=%d new_val=%f\n", add[i].key, add[i].new_val.f_val);
            }
            else if (add[i].key == 102)
            {
                printf("key=%d new_val=%f\n", add[i].key, add[i].new_val.f_val);
            }
            else if (add[i].key == 103)
            {
                printf("key=%d new_val=%d\n", add[i].key, add[i].new_val.b_val);
            }
            else if (add[i].key == 104)
            {
                printf("key=%d new_val=%f\n", add[i].key, add[i].new_val.f_val);
            }
            else if (add[i].key == 105)
            {
                printf("key=%d new_val=%d\n", add[i].key, add[i].new_val.b_val);
            }
            else if (add[i].key == 106)
            {
                printf("key=%d new_val=%f\n", add[i].key, add[i].new_val.f_val);
            }
        }

        sleep(1);
    }
    //free(tmp1);
   // tmp1 = NULL;

    shm_del(&para);
    pthread_exit(NULL);
}

(3)指令控制进程:

//指令控制
void *controlthread(void *arg)
{

    modbus_t *ctx = (modbus_t *)arg;
    struct msg msg;

    //反序列化
    msg.mtype = 1;
    while (1)
    {

        // u_int16_t buf[4] = {444};
        // u_int16_t buf1[4] = {1662};

        //modbus_write_registers(ctx,40000,2,buf);
        //modbus_write_registers(ctx,40002,2,buf1);

        //modbus_write_registers(ctx,40003,2,buf);
        //modbus_write_registers(ctx,40005,4,buf );
        //modbus_write_register(ctx,0, 12);
        //modbus_write_register(ctx,2, 12);

        if (msg_queue_recv("modbus", &msg, sizeof(msg), 1, 0) > 0)
        {
            cJSON *root = cJSON_Parse(msg.mdata);
            if (NULL == root)
            {
                printf("err parse\n");
                //return -1;
            }
            //cJSON *item;
            //item = cJSON_GetObjectItem(root, "data"); //解析对象
            //解析key的值
            cJSON *login_key = cJSON_GetObjectItem(root, "key");
            int identifying_Key = login_key->valueint;
            printf("key=%d\n", identifying_Key); //打印此时的key值
            //解析val的值
            login_key = cJSON_GetObjectItem(root, "val");
            int identifying_val = atoi(cJSON_GetObjectItem(root, "val")->valuestring);
            printf("val=%d\n", identifying_val);
            //遍历链表
            list_for_each(pos, &head)
            {
                tmp = list_entry(pos, struct mb_node_list, list);
                if (identifying_Key == tmp->node.key)
                {
                    if (identifying_Key == 103) //空调开关
                    {
                        modbus_write_bit(ctx, tmp->node.addr - 1, identifying_val);
                    }
                    else if (identifying_Key == 104) //空调温度控制
                    {
                        uint16_t buf[4];

                        modbus_set_float_dcba((float)atof(cJSON_GetObjectItem(root, "val")->valuestring), buf);

                        modbus_write_registers(ctx, tmp->node.addr, 2, buf);
                    }
                    else if (identifying_Key == 105) //风扇开关
                    {
                        modbus_write_bit(ctx, tmp->node.addr - 1, identifying_val);
                    }
                    else if (identifying_Key == 106) //风扇档位控制,1档,2档,3档
                    {
                        uint16_t buf[4];

                        modbus_set_float_dcba((float)atof(cJSON_GetObjectItem(root, "val")->valuestring), buf);

                        modbus_write_registers(ctx, tmp->node.addr, 2, buf);
                    }
                }
            }
        }
    }
    pthread_exit(NULL);
    pause();
}

五,STM32

●STM32采集模块
stm32采集模块实现了stm32设备的通信对接,向上通过串口协议采集单片机的数据,
并刷新到共享内存,以便上报模块进程使用。
向下接收来自上报模块的JSON控制指令,解析后,
转换为相应的控制指令后通过串口发送给设备,实现设备的控制。

●单片机设备模块
单片机模拟了智能家居系统的设备场景,分别实现了传感器数据采集上报、设备的远程控制等功能。
通过ADC采集光敏传感器,并按照上报协议通过串口发送给网关设备。
接收来自网关的控制指令,通过JSON反序列化后,进行相应的设备控制。
呼吸灯来表示设备运行状态,按键模拟墙壁开关同步模拟灯光控制。

(1)需求分析

  • 采集类传感器使用光敏度传感器。
  • 蓝LED模拟智能灯,可以采集到灯状态并可远程控制;五向按键作为灯控开关(家居本地控制)。
  • 绿色灯作为呼吸灯,1S闪烁一次,表示设备运行正常。
  • 蓝灯表示网络连接状态,如果连接wifi并成功连接服务器后,蓝灯常亮(wifi连接模式)。
  • 每隔2s采集一次传感器数据智能灯的状态电池电量信息,组包主动上报给网关。
  • 接收来自网关的控制指令,并对智能灯做相应的控制。

(2)技术点分析

  • GPIO
  • 串口通信
  • 串口中断
  • GPIO中断
  • 硬件定时器
  • ADC采集
  • 网络调试(wifi连接模式)

注意:这种方式很直观,发送前需要对发送的数据进行JSON的序列化动作。

  • 单片机的栈空间比较小,如果使用cJSON序列化时候,在串口调试助手发现输出不正常时,一般是栈空间不够了,此时可以考虑增大栈空间,可以直接从cubeMX直接进行调整。

 (3)Linux中采集和控制代码

主线程:    // 读取串口数据(数据采集)

int main(int argc, char const *argv[])
{
    fd = open("/dev/ttyUSB0", O_RDWR);
    if (fd < 0)
    {
        perror("open err");
        return -1;
    }
    else
        printf("open device success\n");

    serial_init(fd); //设置串口属性
    //创建线程
    pthread_t tid;
    if (pthread_create(&tid, NULL, my_pthread, NULL) != 0)
    {
        perror("pthread create err");
        return -1;
    }
    printf("this is father\n");

    char buf[1024] = {0}; //存放读串口数据
    static struct shm_param para;
    int ret = -1;
    // 创建共享内存
    ret = shm_init(&para, "shm_test", 1024);
    if (ret < 0)
    {
        return -1;
    }
    // 获取共享内存地址
    struct std_node *addr = shm_getaddr(&para);
    if (addr == NULL)
    {
        return -1;
    }

    while (1)
    {
        // 读取串口数据
        if (read(fd, buf, sizeof(buf)) < 0)
        {
            perror("read err");
            return -1;
        }
        printf("cj_buf=%s\n", buf);
        // 反序列化
        cJSON *root = cJSON_Parse(buf);
        if (NULL == root)
        {
            printf("parse err\n");
            return -1;
        }
        printf("*****反序列化*****\n");
        cJSON *data = NULL;
        cJSON *tmp = NULL;
        cJSON *item = NULL;
        data = cJSON_GetObjectItem(root, "data");
        int n = cJSON_GetArraySize(data);
        struct std_node buffer[n - 1];
        for (int i = 0; i < n; i++)
        {
            tmp = cJSON_GetArrayItem(data, i);
            item = cJSON_GetObjectItem(tmp, "key");
            buffer[i].key = item->valueint;
            printf("%s=%d\n", item->string, item->valueint);

            item = cJSON_GetObjectItem(tmp, "val");
            if (buffer[i].key == 301) //传感器
            {
                buffer[i].type = 3;
                buffer[i].dev_type = buffer[i].key / 100;
                buffer[i].old_val.f_val = item->valueint;
                buffer[i].new_val.f_val = item->valueint;
            }
            else if (buffer[i].key == 302) //电池
            {
                buffer[i].type = 2;
                buffer[i].dev_type = buffer[i].key / 100;
                buffer[i].old_val.i_val = item->valueint;
                buffer[i].new_val.i_val = item->valueint;
            }
            else if (buffer[i].key == 303) //灯状态
            {
                buffer[i].type = 2;
                buffer[i].dev_type = buffer[i].key / 100;
                buffer[i].old_val.i_val = item->valueint;
                buffer[i].new_val.i_val = item->valueint;
            }
            //打印查看采集的值
            printf("%s=%d\n", item->string, item->valueint);
            buffer[i].ret = 0;
        }

        cJSON_Delete(root);
    }
    pthread_join(tid, NULL);
    return 0;
}

线程://从消息队列中读cjson(控制指令通过串口发给单片机)

void *my_pthread(void *arg)
{
    printf("this is son\n");

    struct msgbuf r_buf;
    cJSON *r = cJSON_CreateObject();
    cJSON *d = cJSON_CreateArray();
    cJSON_AddItemToObject(r, "data", d);
    cJSON *i = cJSON_CreateObject();
    cJSON_AddItemToArray(d, i);
    cJSON_AddNumberToObject(i, "key", 303);
    cJSON_AddStringToObject(i, "name", "light");
    cJSON_AddStringToObject(i, "val", "1");
    char *q = cJSON_PrintUnformatted(r);
    r_buf.mtype = 1;
    strcpy(r_buf.mdata, q);
    msg_queue_send("stm32", &r_buf, sizeof(r_buf), 0);
    printf("r_buf=%s\n", r_buf.mdata);
    free(q);
    cJSON_Delete(r);

    while (1)
    {
        //从消息队列中读cjson
        struct msgbuf recv_buf;
        int t = msg_queue_recv("stm32", &recv_buf, sizeof(recv_buf), 0, 0);
        if (t < 0)
        {
            perror("msg recv err");
            return NULL;
        }
        printf("%s\n", recv_buf.mdata);
        // 反序列化
        cJSON *msg_root = cJSON_Parse(recv_buf.mdata);
        if (NULL == msg_root)
        {
            printf("parse err\n");
            return NULL;
        }
        int msg_key, msg_val;
        cJSON *msg_item = NULL;
        cJSON *msg_data = cJSON_GetObjectItem(msg_root, "data");
        int cout = cJSON_GetArraySize(msg_data);
        printf("*************\n");
        for (int i = 0; i < cout; i++)
        {
            cJSON *tmp = cJSON_GetArrayItem(msg_data, i);
            msg_item = cJSON_GetObjectItem(tmp, "key");
            msg_key = msg_item->valueint;
            printf("%s=%d\n", msg_item->string, msg_item->valueint);
            msg_item = cJSON_GetObjectItem(tmp, "name");
            printf("%s=%s\n", msg_item->string, msg_item->valuestring);
            msg_item = cJSON_GetObjectItem(tmp, "val");
            msg_val = atoi(msg_item->valuestring);
            printf("%s=%s\n", msg_item->string, msg_item->valuestring);
        }
        cJSON_Delete(msg_root);
        // 序列化
        if (msg_key == 303)
        {
            cJSON *root = cJSON_CreateObject();
            cJSON *data = cJSON_CreateArray();
            cJSON_AddItemToObject(root, "data", data);

            cJSON *item3 = cJSON_CreateObject();
            cJSON_AddItemToArray(data, item3);
            cJSON_AddNumberToObject(item3, "key", 303);
            cJSON_AddStringToObject(item3, "name", "light");
            cJSON_AddNumberToObject(item3, "val", msg_val);
            char *p = cJSON_PrintUnformatted(root);
            printf("ctronl_cjson=%s\n", p);
            //写串口
            if (write(fd, p, strlen(p)) < 0)
            {
                perror("write err");
                return NULL;
            }
            free(p);
            cJSON_Delete(root);
        }
    }
    pthread_exit(NULL);
}

(4)ukeil工程

main.c() LED灯五项按键中断, 串口接受控制指令,ADC采集

五项按键

//按键中断
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin==GPIO_PIN_8)
	{
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_1);
		while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8));//抬手检测
	}
}

串口接受控制指令

//每次达到上述条件后,会触发此中断,每次触发中断缓冲区数据就是完整一包数据
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart->Instance == USART1)
	{
//		printf("RxBuf is %s\n", RxBuf);
        //这里来解析命令,并做出相应的反应
//		char dev_name[32]={0};
		cJSON* recv_root=cJSON_Parse(RxBuf);
//		if(NULL==recv_root)
//		{
//			printf("parse err\n");
//		}
		
		cJSON*recv_data=cJSON_GetObjectItem(recv_root,"data");
		int count=cJSON_GetArraySize(recv_data);
		for(int i=0;i<count;i++)
		{
			cJSON*tmp=cJSON_GetArrayItem(recv_data,i);
//			printf("********zhongduan*******\n");
			cJSON* recv_item=NULL;
			recv_item=cJSON_GetObjectItem(tmp,"key");
//			printf("%s=%d\n", recv_item->string, recv_item->valueint);
			int key=recv_item->valueint;
			
//			recv_item=cJSON_GetObjectItem(tmp,"name");
//			printf("%s=%s\n", recv_item->string, recv_item->valuestring);
//			strcpy(dev_name,recv_item->valuestring);
			
			recv_item=cJSON_GetObjectItem(tmp,"val");
//			printf("%s=%d\n", recv_item->string, recv_item->valueint);
			int val=recv_item->valueint;
//			int val=atoi(recv_item->valueint);
			
			//控制灯
			if(key==303)
			{
				//开灯
				if(val==1)
				{
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
				}
				//关灯
				else if(val==0)
				{
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
				}
			}
			cJSON_Delete(recv_root);
		}
		
		memset(RxBuf,0,1024);
        
		//再次设置此中断
		HAL_UARTEx_ReceiveToIdle_IT(&huart1,RxBuf,1024);
	}
}

ADC采集 ,LED灯,呼吸灯

  /* USER CODE BEGIN WHILE */
  while (1)
  {
		//呼吸灯
		for(int i=995;i>=0;i--)
		{
			TIM3->CCR3=i;
			HAL_Delay(1);
		}
		for(int i=0;i<995;i++)
		{
			TIM3->CCR3=i;
			HAL_Delay(1);
		}
		
		
		//		启动adc开始转换
		HAL_ADC_Start(&hadc1);
		//		获取转换结果
		while(!(ADC1->ISR&(1<<2)));
		bat=HAL_ADC_GetValue(&hadc1);
		while(!(ADC1->ISR&(1<<3)));
		light=HAL_ADC_GetValue(&hadc1);
		//		停止转换
		HAL_ADC_Stop(&hadc1);
		
//		printf("bat=%d light=%d\n",bat,light);
//		HAL_Delay(10);
		
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==GPIO_PIN_SET)
		{
//			printf("led_off\n");
			led_val=0;
		}else
		{
//			printf("led_on\n");
			led_val=1;
		}
		//序列化封装为json格式
		cJSON* root=cJSON_CreateObject();
		cJSON* data=cJSON_CreateArray();
		cJSON_AddItemToObject(root,"data",data);
		cJSON* item=cJSON_CreateObject();
		
		cJSON_AddItemToArray(data,item);
		cJSON_AddNumberToObject(item,"key",301);
		cJSON_AddStringToObject(item,"name","sensor");
		cJSON_AddNumberToObject(item,"val",light);
		cJSON* item2=cJSON_CreateObject();
		
		cJSON_AddItemToArray(data,item2);
		cJSON_AddNumberToObject(item2,"key",302);
		cJSON_AddStringToObject(item2,"name","bat");
		cJSON_AddNumberToObject(item2,"val",bat);
		cJSON* item3=cJSON_CreateObject();
		
		cJSON_AddItemToArray(data,item3);
		cJSON_AddNumberToObject(item3,"key",303);
		cJSON_AddStringToObject(item3,"name","light");
		cJSON_AddNumberToObject(item3,"val",led_val);
		
		char *p = cJSON_PrintUnformatted(root);
		
		HAL_UART_Transmit(&huart1,p,strlen(p),1000);
//		printf("cjson=%s\n",p);
		
		free(p);
		cJSON_Delete(root);
		//lcd屏显示
		sprintf(lcd_sensor,"%d\n",light);
		sprintf(lcd_bat,"%d\n",bat);
		sprintf(lcd_led,"%d\n",led_val);
		Gui_DrawFont_GBK16(25,30,WHITE,RED,"sensor:");
		Gui_DrawFont_GBK16(80,30,WHITE,RED,lcd_sensor);
		Gui_DrawFont_GBK16(35,45,WHITE,RED,"bat:");
		Gui_DrawFont_GBK16(78,45,WHITE,RED,lcd_bat);
		Gui_DrawFont_GBK16(35,60,WHITE,RED,"LED:");
		Gui_DrawFont_GBK16(78,60,WHITE,RED,lcd_led);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

 相关知识:

1,JSON数据交换格式

2,内核链表

3,共享内存,消息队列

通信组件(!!!!!!!!!!)

以下组件依赖临时目录,必须提前创建(tmp目录是内存型目录,如果重启了系统会消失,所以每次重启后注意重新创建下)

mkdir /tmp/ipc/shmem -p
mkdir /tmp/ipc/msgqueue/peer -p

4,GIT

 总结:

  • 强化编程基础
  • 迅速拓展知识面,训练自己的学习能力
  • 了解企业开发流程,提前感受团队项目开发过程

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

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

相关文章

大语言模型的预训练[2]:GPT、GPT2、GPT3、GPT3.5、GPT4相关理论知识和模型实现、模型应用以及各个版本之间的区别详解

大语言模型的预训练[2]:GPT、GPT2、GPT3、GPT3.5、GPT4相关理论知识和模型实现、模型应用以及各个版本之间的区别详解 1.GPT 模型 1.1 GPT 模型简介 在自然语言处理问题中&#xff0c;可从互联网上下载大量无标注数据&#xff0c;而针对具体问题的有标注数据却非常少&#x…

原型设计用什么比较好?这4款值得体验

无论是UI还是UX设计师&#xff0c;工作中肯定少不了交互设计。在设计原型图时&#xff0c;一款好用的原型设计工具肯定是必不可少&#xff0c;本文就整理了4款为大家推荐&#xff0c;一起来看看吧 即时设计 即时设计是一款更适合国内UI或UX设计师和产品经理使用的原型设计工具…

如何使用Python三方库CCXT

数量技术宅团队在CSDN学院推出了量化投资系列课程 欢迎有兴趣系统学习量化投资的同学&#xff0c;点击下方链接报名&#xff1a; 量化投资速成营&#xff08;入门课程&#xff09; Python股票量化投资 Python期货量化投资 Python数字货币量化投资 C语言CTP期货交易系统开…

<数据结构>NO11.归并排序|递归|非递归|优化

文章目录 归并排序递归写法非递归写法修正方案1.归并一段拷贝一段修正方案2.修正区间 算法优化算法分析 归并排序的应用外排序和内排序 归并排序 递归写法 思路: 如果给出两个有序数组&#xff0c;我们很容易可以将它们合并为一个有序数组。因此当给出一个无序数组时&#xf…

如何解决循环引用的问题

本文已收录于专栏 《Java》 目录 概念说明发现问题解决问题分析问题具体解决注解说明代码实现效果展示 总结提升 概念说明 循环引用是指在对象之间存在相互引用的情况。具体来说&#xff0c;当一个对象A引用了另一个对象B&#xff0c;而对象B又引用了对象A&#xff0c;它们之间…

软件研发开发人员成本计算器

写了个简单的人员工资计算器&#xff0c;用最简单的人天数计算研发投入&#xff0c;其他费用计算稍后补充完善 软件研发成本计算 ——高级工程师中级工程师初级工程师平均日工资项目阶段高级工程师人天中级工程师人天初级工程师人天调研方案产品设计软件开发测试部署培训试运…

操作系统(王道)- 初识操作系统

一、什么是操作系统&#xff1f; 操作系统可以这么理解 操作系统的定义&#xff1a; 操作系统是整个计算机的硬件和软件的管理者&#xff01;&#xff01;&#xff01; 二、操作系统的功能和目标 作为计算机硬件和软件的管理者&#xff0c;操作系统做了什么&#xff1f; 操作系…

安达发|工业系统APS软件与MES软件有哪些区别?

MES 和 APS 有什么区别&#xff1f;MES 是一个制造执行系统&#xff0c;APS 是一个高级计划排程系统系统&#xff0c;两者是互补的关系&#xff0c;APS 和 MES 可以实现计划和车间执行的闭环管理模式。MES 和 APS 有什么区别&#xff1f; mes和aps的区别: MES 是智能化工厂…

【1++的Linux】之进程(一)

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的Linux】 文章目录 一&#xff0c;冯诺依曼与操作系统概念1.1 冯诺依曼体系结构1.2 操作系统 二&#xff0c;进程的基本概念 一&#xff0c;冯诺依曼与操作系统概念 1.1 冯诺依曼体系结构 如…

如何关闭网页版【知乎】等页面的登录弹窗(以谷歌浏览器为例)

如何关闭网页版【知乎】等页面的登录弹窗&#xff08;以谷歌浏览器为例&#xff09; 在不登陆知乎的情况下仍然可以正常浏览页面&#xff0c;可是每次打开新页面会重复出现弹窗要求用户登录。如何屏蔽掉这一弹窗呢? 在浏览器中把知乎网址设置为禁止使用javascript 在chrome的…

C#盯盘小工具,“监”

也是一个小工具&#xff0c;用来看大A股票和主要指数行情的。 如果你是一个上班族&#xff0c;同时你也是一颗小韭菜&#xff0c;a股在开市交易盘中时刻惦记着股票是涨了还是跌了&#xff0c;却不能时刻盯着手机看行情&#xff0c;也不能在电脑上开着同花顺来回切窗口&#xff…

4.CSS(一)

目录 一、CSS简介 二、CSS基础选择器 &#xff08;一&#xff09;标签选择器 &#xff08;二&#xff09;类选择器 类选择器-多类名 &#xff08;三&#xff09;id选择器 &#xff08;四&#xff09;通配符选择器 &#xff08;五&#xff09;总结 三、CSS字体属性 &…

Acwing.906 区间分组(贪心)

题目 给定N个闭区间[ai,bi]&#xff0c;请你将这些区间分成若千组&#xff0c;使得每组内部的区间两两之间(包括端点)没有交集&#xff0c;并使得组数尽可能小。 输出最小组数。 输入格式 第一行包含整数N&#xff0c;表示区间数。 接下来N行&#xff0c;每行包含两个整数ai…

【算法基础】2.2 字典树/前缀树 Trie

文章目录 知识点cpp结构体模板 模板例题835. Trie字符串统计❤️❤️❤️❤️❤️143. 最大异或对&#x1f62d;&#x1f62d;&#x1f62d;&#x1f62d;&#x1f62d;&#xff08;Trie树的应用&#xff09; 相关题目练习208. 实现 Trie (前缀树)1804. 实现 Trie &#xff08;…

轮转数组——左旋数组,右旋数组

题目链接&#xff1a;力扣 左旋转字符串&#xff1a;【1234567】—左旋3下—>【4567123】 反转区间为前n的子串【3214567】反转区间为n到末尾的子串【3217654】反转整个字符串【4567123】 右旋转字符串&#xff1a;【1234567】—右旋3下—>【5671234】 反转整个字符…

一图看懂 pandas 模块(1):提供高性能、易用的数据结构和数据分析工具,资料整理+笔记(大全)

本文由 大侠(AhcaoZhu)原创&#xff0c;转载请声明。 链接: https://blog.csdn.net/Ahcao2008 一图看懂 pandas 模块&#xff1a;提供高性能、易用的数据结构和数据分析工具&#xff0c;资料整理笔记&#xff08;大全&#xff09; &#x1f9ca;摘要&#x1f9ca;模块图&#x…

SAP-MM-物料版次

业务背景介绍 UF公司其产成品会根据客户需求进行细节上零件变更,每次都需新增物料主数据以及搭建新的BOM和对应的工艺路线进行数据处理(即对客户A0001的产成品从A0010到B0010的变化,但物料描述还是原来的描述) 新增物料编号进行库存管控是较为合理的需求,但是因UF销售业务员…

在LLM的支持下使游戏NPC具有记忆化的方法

问题 使用GPT这样的LLM去处理游戏中的NPC和玩家的对话是个很好的点子&#xff0c;那么如何处理记忆化的问题呢。 因为LLM的输入tokens是有限制的&#xff0c;所以伴随着问题的记忆context是有窗口大小限制的&#xff0c;将所有的记忆输入LLM并不现实。 所以这里看到了stanfo…

Damiler EDI 项目 Excel 方案开源介绍

准备下载和运行 Daimler EDI 到 Excel 使用 Excel 生成一系列 EDI 文档与 Daimler 通信。 下载工作流 下载示例文件 Daimler EDI & Excel 方案简介 本文将继续分享Daimler示例工作流&#xff1a;使用Excel端口和Email端口生成一系列文件&#xff0c;完成与Daimler的…

解锁编程世界的魔法密码:探索算法的奥秘与应用

一个程序员一生中可能会邂逅各种各样的算法&#xff0c;但总有那么几种&#xff0c;是作为一个程序员一定会遇见且大概率需要掌握的算法。今天就来聊聊这些十分重要的“必抓&#xff01;”算法吧~* 一&#xff1a;引言 算法是解决问题和优化程序性能的核心&#xff0c;它是一…