*本次的笔记将详细介绍 ML307C-DC-CN 模组 所使用的 OpenCPU SDK 开发包,包括其目录结构、核心组件。在此基础上,我们将重点讲解如何基于该 SDK 创建一个全新的项目工程,从 函数入口开始,逐步编写和集成您的业务逻辑代码,最终实现一个完整的、可烧录运行的嵌入式应用程序。*

1、SDK包


在这里插入图片描述

注意:解压时尽量不要加中文,如果名字太长,也可以适当缩短
本相关文件均存放在SDK文件夹中,文件包含:

  1. 项目根目录:ML307C-DC-CN_OPENCPU_SDK
    这是整个SDK项目的顶层文件夹,包含了所有源代码、配置文件和构建脚本。

  2. 核心开发区域
    custom 文件夹
    这是您进行二次开发的核心区域。所有您自己编写的业务逻辑代码都应放在此处。
    custom_main: 这是官方为您预设的一个“空工程”模板,供您参考和修改。

    inc: 存放您自定义的头文件(.h),例如 my_app.h。
    src: 存放您自定义的源文件(.c),例如 my_app.c。

    custom_main.c: 这是程序的入口点。
    int cm_opencpu_entry(void *param) 函数是模组启动后首先执行的函数。您需 要在这里编写您的主循环或初始化代码。

  3. 辅助与参考资源
    docs 文件夹
    包含项目的 API 文档 和说明文件。可以在这里查阅各个函数的用法和参数说明。

    examples 文件夹
    这是 官方提供的示例程序。它展示了如何使用 SDK 中的各种功能,如:
    使用 UART 串口
    通过 MQTT 协议连接云平台
    配置和使用 LwM2M 协议
    进行 HTTP 请求
    读写文件系统
    等等

    💡 建议:在开始开发前,务必先阅读 examples 中的代码,了解基本的编程模式和 API 调用方法。

    include 文件夹
    存放 SDK 提供的公共头文件,例如 cm_i2c.h, cm_os.h, cm_uart.h 等。这些头文件定义了模组提供的各种外设接口和操作系统服务。

    kernel 文件夹
    存放操作系统的内核代码和底层驱动。普通开发者通常不需要修改此部分。

  4. 构建与输出
    out 文件夹
    这是 固件输出文件夹。当您成功编译项目后,生成的最终固件文件会存放在此目录下。这个文件就是您需要烧录到模组中的程序。

    prebuild 文件夹
    可能存放预编译的库文件或中间文件,由构建系统自动生成。

    test 文件夹
    这是为 ML307C-DC 模组专门准备的测试 Demo。

    third-party 文件夹
    存放第三方开源库,如 libcurl、mbedtls 等。

    tools 文件夹
    存放各种辅助工具,如烧录工具、打包脚本等。

  5. 项目管理文件
    README.md: 项目的说明文档,通常包含项目简介、快速入门指南、依赖项等。
    SConstruct / scons: 构建脚本,用于自动化编译整个项目。



二、创建自己的工程


基于custom创建用户工程
1.可见custom是一个空的工程,通过上节的 编译下载和运行第一个程序 咱知道咱是在custom里面写自己的程序;
sys_package是这边自己增加的文件,后期将会把封装的功能放到里面,然后提供接口使用文档供用户使用;
咱后面写自己的程序的时候需要把.c文件放到src文件夹里面(这是硬性规定); .h文件可以随意。
2.custom_main.c 里面的 int cm_opencpu_entry(char * param) 函数是程序的main函数, 程序从这个函数里面开始执行
在这里插入图片描述

3.在src文件夹新建自己需要的.c和.h文件

三、USB例程


USB功能是将USB例化成串口使用,连接电脑设备管理器会出现2个ASR Modem Device 其中一个为USB例化串口,可进行本demo中的回显测试
注意该USB存在一特性:需先以某波特率发任意字节给模组,进行波特率适配,模组才能通过USB往外输出数据

static osThreadId_t CM_USB_DEMO_MAIN_TASKHANDLE = NULL;    // USB DEMO测试线程
static osMessageQueueId_t CM_USB_DEMO_QUEUE_HANDLE = NULL; // USB 队列用于接收USB数据

作用:
CM_USB_DEMO_MAIN_TASKHANDLE:用于存储USB主任务的线程ID。
CM_USB_DEMO_QUEUE_HANDLE:用于存储消息队列的句柄,用于接收USB数据。
USB接收数据回调函数

static void cm_usb_demo_recv_callback(void *data, int32_t len)
{
    if (len <= 0) // 如果无数据 则返回
    {
        return;
    }
    cm_usb_demo_data_t *usb_recv_data = cm_malloc(sizeof(cm_usb_demo_data_t));
    if (usb_recv_data == NULL)
    {
        return;
    }
    usb_recv_data->event = CM_USB_DEMO_EVENT_RECV;
    memcpy(usb_recv_data->data, data, len);
    usb_recv_data->datalen = len;
    if (osOK != osMessageQueuePut(CM_USB_DEMO_QUEUE_HANDLE, &usb_recv_data, 0, 0))   //timeout一定要为0  不能在回调中做阻塞操作
    {
        cm_free(usb_recv_data);
        return;
    } 
}

作用:当USB接收到数据时被调用,将数据封装后放入消息队列。
使用方法:
通过 cm_usb2com_register_recv_cb() 注册此回调函数。
回调中分配内存保存数据,然后通过 osMessageQueuePut() 将数据放入队列。
USB插拔事件回调函数

static void cm_usb_demo_event_callback(int32_t event)
{
    cm_usb_demo_data_t *usb_recv_data = cm_malloc(sizeof(cm_usb_demo_data_t));
    if (usb_recv_data == NULL)
    {
        return;
    }
    usb_recv_data->event = event;
    if (osOK != osMessageQueuePut(CM_USB_DEMO_QUEUE_HANDLE, &usb_recv_data, 0, 0))
    {
        cm_free(usb_recv_data);
        return;
    }
    
    return;
}

作用:当USB设备插入或拔出时被调用,将事件放入消息队列。
使用方法:
通过 cm_usb2com_register_status_cb() 注册此回调函数。
USB主线程

static void cm_usb_demo_main(void)
{
    while (1)
    {
        cm_usb_demo_data_t *usb_data = {0};
        if (osOK == osMessageQueueGet(CM_USB_DEMO_QUEUE_HANDLE, &usb_data, NULL, osWaitForever))
        {
            switch (usb_data->event)
            {
            case CM_USB_DEMO_EVENT_RECV:
                //注意该打印函数只能打印最多108字节 超过字节不打印 而非数据接收有问题
                cm_log_printf(0,"CM_USB_DEMO_EVENT_RECV:%s,%d", usb_data->data, usb_data->datalen);
                cm_usb2com_send_data(usb_data->data,usb_data->datalen);  //实现回显 
                break;
            case CM_USB_DEMO_EVENT_INSERT:
                cm_log_printf(0,"CM_USB_DEMO_EVENT_INSERT");
                break;
            case CM_USB_DEMO_EVENT_REMOVE:
                cm_log_printf(0,"CM_USB_DEMO_EVENT_REMOVE");
                break;

            default:
                break;
            }
            cm_free(usb_data);
            usb_data = NULL;
        }
    }
}

作用:处理来自消息队列的数据,包括回显接收的数据和打印插拔事件。
使用方法:
在 cm_opencpu_entry() 中创建此线程。
通过 osMessageQueueGet() 从队列中获取数据并处理。
USB接口测试启动函数

int cm_opencpu_entry(void *arg)
{
    (void)arg;
    cm_usb2com_register_recv_cb(cm_usb_demo_recv_callback);    //数据接收回调
    cm_usb2com_register_status_cb(cm_usb_demo_event_callback); //USB插拔检测事件回调

    /*创建USB数据接收队列*/
    if (CM_USB_DEMO_MAIN_TASKHANDLE == NULL)
    {
        CM_USB_DEMO_QUEUE_HANDLE = osMessageQueueNew(20, sizeof(cm_usb_demo_data_t *), NULL); // 创建消息队列 用于接收USB回调中的数据
        if (CM_USB_DEMO_QUEUE_HANDLE == NULL)
        {
            cm_log_printf(0,"CM_DEMO_USB_QUEUE_HANDLE is NULL");
        }
    }

    /*创建USB数据接收/发送处理线程*/
    osThreadAttr_t usb_demo_main_task_attr = {0};
    usb_demo_main_task_attr.name = "usb_demo_main_task";
    usb_demo_main_task_attr.stack_size = 4 * 1024;
    usb_demo_main_task_attr.priority = osPriorityNormal;

    if (CM_USB_DEMO_MAIN_TASKHANDLE == NULL)
    {
        CM_USB_DEMO_MAIN_TASKHANDLE = osThreadNew((osThreadFunc_t)cm_usb_demo_main, 0, &usb_demo_main_task_attr);
        if (CM_USB_DEMO_MAIN_TASKHANDLE == NULL)
        {
            cm_log_printf(0,"CM_USB_DEMO_MAIN_TASKHANDLE is NULL");
        }
    }

    return 0;
}

作用:初始化USB功能,注册回调函数,创建消息队列和处理线程。
使用方法:
作为程序入口点,在系统启动时被调用。
注册USB数据接收和状态回调函数。
创建消息队列和主线程来处理USB事件。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐