当前位置: 首页 > article >正文

ML307R 串口开发--OpenCPU应用程序开发学习笔记(2)

前言:

        上一篇文章已经把如何配置和安装开发环境介绍了一下,开发环境准备完毕之后就可以进行具体的项目开发了,这个款芯片的外设接口很多,我个人觉得用的最多的还是串口,这篇文章就介绍一下串口的开发流程,如果SDK开发环境还没配置好看上一篇文章。

ML307R SDK开发--OpenCPU应用程序开发学习笔记(1)_ml307r opencpu-CSDN博客

1:OpenCpu-ML307R串口介绍

                根据中移的官方资料可以了解到,关于串口一共有三个,两个串口,一个调试串口。

        想要学习一个全新的外设最快最简单的方法是看历程。OPenCpu中有很多历程

        常使用的外设历程基本都在这里,在此着重说明一下串口的历程也就是uart。

2:串口开发准备

        相比第一次接触这个OpenCpu的时候会有点小懵,我在哪里开发自己的程序,应该写在哪里,然后是写好程序后如何编译运行。在此我一一给出说明。

首先所有的用户程序开发均在这个里面。

src里面存放c文件,inc里面存放h文件。

        在src里面有个custom_main.c的文件,文件中有个cm_opencpu_entry()函数。这个函数就相当于传统c语言中的main函数,程序就在这里运行。

然后可以在src文件下创建想要的用户程序文件。

        我个人习惯是把.c、.h文件放在一起。

        创建完用户文件后就需要添加路径,不然编译的时候找不到库函数。

在这个文件夹里面有个SConscript文件里面设置对应的文件路劲的地方。

上面都有对应的注释,按照自己的需求添加在对应的位置即可。

3:串口开发流程

        这个串口开发流程我是根据示例程序总结的只代表我个人观点。

        在进行具体的程序开发之前我认为应该要对相关的API接口函数有个大致的了解。

        这个就是对用的接口函数,了解到相关的接口函数那就开始说开发流程。这个只是读取数据的,写数据同理。

1:配置串口参数,事件结构体

常见配置

事件结构体

2:  设置读取数据事件

3:复用使能引脚

这个要根据原理图来查看。        

使用的是串口0,对应的引脚就是17,18

4:注册串口接收数据事件

5:打开串口

6:使用线程来做uart接收任务

7:编写串口接收函数

8:编写回调函数

9:编写uart事件处理任务

上面这个不用完全自己会写,看得懂例子接口即可。

我也附上我的完整程序。


//串口示例头文件
#include "cm_uart.h"
#include "cm_iomux.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#include "cm_os.h"
#include "cm_mem.h"
#include "cm_common.h"
#include "cm_sys.h"
#include "cm_demo_uart.h"

#include "cm_sys.h"

#include "test.h"

typedef struct{
    int msg_type;
} uart_event_msg_t;


#define UART_BUF_LEN            1024

static int rx_rev_len = 0;
static char rx_rev_data[UART_BUF_LEN] = {0};//
static osThreadId_t OC_Uart_TaskHandle = NULL; //串口数据接收、解析任务Handle
static void* g_uart_sem = NULL;
static osMessageQueueId_t uart_event_queue = NULL;
static osThreadId_t uart_event_thread = NULL;

static void uart_event(void *arg)
{
    uart_event_msg_t msg = {0};

    while (1)
    {
        if (osMessageQueueGet(uart_event_queue, &msg, NULL, osWaitForever) == osOK)
        {
            //cm_log_printf(0, "uart event msg type = %d\n", msg.msg_type);
            if (CM_UART_EVENT_TYPE_RX_OVERFLOW & msg.msg_type)
            {
                cm_log_printf(0, "CM_UART_EVENT_TYPE_RX_OVERFLOW... ...");
            }
        }
    }
}


/* 用于测试串口事件,用户可参考 */
static int uart_event_create(void)
{
    if (uart_event_queue == NULL)
    {
        uart_event_queue = osMessageQueueNew(10, sizeof(uart_event_msg_t), NULL);
    }

    if (uart_event_thread == NULL)
    {
        osThreadAttr_t attr1 = {
            .name = "uart_event",
            .priority = UART_TASK_PRIORITY,
            .stack_size = 1024,
        };
        uart_event_thread = osThreadNew(uart_event, NULL, (const osThreadAttr_t*)&attr1);
    }

    return 0;
}


extern osEventFlagsId_t cmd_task_flag;

/* 回调函数中不可输出LOG、串口打印、执行复杂任务或消耗过多资源,
建议以信号量或消息队列形式控制其他线程执行任务 */
static void cm_uart_callback(void *param, uint32_t type)
{
    uart_event_msg_t msg = {0};
	//数据接收回调
    if (CM_UART_EVENT_TYPE_RX_ARRIVED & type)
    {
       /* 收到接收事件,触发其他线程执行读取数据 */
        if (g_uart_sem != NULL) {
            osSemaphoreRelease(g_uart_sem);
        }
    }
    //溢出回调
    if ((CM_UART_EVENT_TYPE_RX_OVERFLOW & type))
    {
        /* 收到溢出事件,触发其他线程处理事件 */
        msg.msg_type = type;
        
        if (uart_event_queue != NULL)//向队列发送数据
        {
            osMessageQueuePut(uart_event_queue, &msg, 0, 0);
        }
    }
}



/* 串口接收示例,平时使用信号量挂起,当收到接收事件后,释放信号量以触发读取任务 */
static void cm_uart_recv(void *param)
{
    int temp_len = 0;
    
    while (1)
    {
    	if (g_uart_sem != NULL)
        {
        	// 阻塞等待信号量,直到有数据到达或发生超时
            osSemaphoreAcquire(g_uart_sem, osWaitForever);//阻塞
        }
        //如果缓冲区没满,则尝试读取更多数据
        if (rx_rev_len < UART_BUF_LEN)
        {
         	memset((void*)rx_rev_data + rx_rev_len, 0, UART_BUF_LEN - rx_rev_len);	 
        	//读取数据
            temp_len = cm_uart_read(OPENCPU_MAIN_URAT, (void*)&rx_rev_data[rx_rev_len], UART_BUF_LEN - rx_rev_len, 1000);
			if(temp_len > 0)
			{
				rx_rev_len += temp_len;
			}
			
			 /* 每次接收到数据后立即打印 */
            //cm_demo_printf("Received data: %.*s", temp_len, &rx_rev_data[rx_rev_len - temp_len]);
        }

        /*数据处理*/
        if (strstr(rx_rev_data, "\r\n"))
        { 
           if (rx_rev_len != 0)
           {
               // 打印完整的接收到的数据信息
                cm_demo_printf("Full command received: %s", rx_rev_data);
				// 处理完数据后重置缓冲区
                memset(rx_rev_data, 0, sizeof(rx_rev_data));
                rx_rev_len = 0;
           } 
        }
    }
}

/* 从测试串口打印字符串 */
void cm_demo_printf(char *str, ...)
{
    char s[600] = {0}; //This needs to be large enough to store the string TODO Change magic number
    va_list args;
    int len;
    
    if ((str == NULL) || (strlen(str) == 0))
    {
        return;
    }

    va_start(args, str);
    len = vsnprintf((char*)s, 600, str, args);
    va_end(args);
    cm_uart_write(OPENCPU_MAIN_URAT, s, len, 1000);
}

void cm_uart(void)
{
    int32_t ret = -1;

    /* 配置参数 */
    cm_uart_cfg_t config = 
    {
        CM_UART_BYTE_SIZE_8,  			// 数据位长度为8位
        CM_UART_PARITY_NONE,			// 无校验位
        CM_UART_STOP_BIT_ONE, 			// 停止位为1位
        CM_UART_FLOW_CTRL_NONE, 		// 无流控制
        CM_UART_BAUDRATE_115200,		// 波特率为9600
        0,   //配置为普通串口模式,若要配置为低功耗模式可改为1
        0,   //环形缓存区大小按照默认配置8k
        0,
        0,
    };

    /* 设置串口数据接收事件参数 */
    cm_uart_event_t event = 
    {
   		//接收到新的数据,接收FIFO缓存溢出
        CM_UART_EVENT_TYPE_RX_ARRIVED|CM_UART_EVENT_TYPE_RX_OVERFLOW,   //注册需要上报的事件类型
        "uart0",                                                        //用户参数
        cm_uart_callback                                         //上报事件的回调函数
    };

   	cm_log_printf(0, "uart NUM = %d start", OPENCPU_MAIN_URAT);

    /* 配置引脚复用功能,使能UART TX和RX引脚 使能引脚*/
    cm_iomux_set_pin_func(OPENCPU_TEST_UARTTX_IOMUX);
    cm_iomux_set_pin_func(OPENCPU_TEST_UARTRX_IOMUX);

    /* 注册事件和回调函数 */
    ret = cm_uart_register_event(OPENCPU_MAIN_URAT, &event);
    //判断事件是否设置成功
    if (ret != RET_SUCCESS)
    {
        cm_log_printf(0, "uart register event err,ret=%d\n", ret);
        return;
    }
	//打开串口
    /* 开启指定的UART端口,并传递配置参数 */
    ret = cm_uart_open(OPENCPU_MAIN_URAT, &config);
    //判断事件是否设置成功
    if (ret != RET_SUCCESS)
    {
        cm_log_printf(0, "uart init err,ret=%d\n", ret);
        return;
    }
	
	// 打印日志信息,表示事件注册完成
    cm_log_printf(0, "cm_uart_register_event start... ...\n");

    /* 创建串口接收线程 */
    osThreadAttr_t uart_task_attr = {0};
    uart_task_attr.name = "uart_task";			// 线程名称
    uart_task_attr.stack_size = 2048;			// 线程堆栈大小
    uart_task_attr.priority= UART_TASK_PRIORITY;// 线程优先级
    
    // 如果信号量g_uart_sem为空,则创建一个新的二值信号量
    if (g_uart_sem == NULL)
    {
        g_uart_sem = osSemaphoreNew(1, 0, NULL);//创建二值信号量返回信号量ID
    }
	
	// 创建一个新线程来处理UART接收任务
    OC_Uart_TaskHandle = osThreadNew(cm_uart_recv, 0, &uart_task_attr);
	// 创建UART事件处理任务
    uart_event_create();
}




程序编写完毕后,记得在.h文件中声明,和c语言的程序开发流程基本一样。然后再cm_opencpu_entry();里面调用,这个样就可以了。那么怎么进行编译了。

上一篇文章安装的scons就是编译器,在终端打开,然后输入命令

scons custom=y

就会编译了。

编译成功会在out里面生成一个zpi固件程序,烧录到开发板里面即可。

然后运行测试。

测试成功,发送上面接收上面,并打印出来。


http://www.kler.cn/a/446431.html

相关文章:

  • 20241217使用M6000显卡在WIN10下跑whisper来识别中英文字幕
  • CLION中运行远程的GUI程序
  • 智能工厂的设计软件 三种处理单元(NPU/GPU/CPU)及其在深度学习框架中的作用 之5(腾讯云AI代码助手 之3)
  • CarWatchdog
  • CH340系列芯片驱动电路·CH340系列芯片驱动!!!
  • 电源芯片MPQ2179A(TI)
  • 通过edu 邮箱免费使用 Autodesk
  • QT:Widgets中的模型/视图架构
  • 【AI驱动的设计模式:类图的智能化解读】
  • [机器学习] 决策树
  • 关于VS项目中添加第三方库出现error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int 错误的解决方法
  • 【Visual Studio Code(VSCode)介绍】
  • 城市灾害应急管理集成系统——系统介绍
  • Centos7, 使用yum工具,出现 Could not resolve host: mirrorlist.centos.org
  • [react] <NavLink>自带激活属性
  • 项目29:简易谜语生成器 --- 《跟着小王学Python·新手》
  • 如何解决Elastic Job Lite任务分配到不健康实例问题?
  • Java 中 wait 和 sleep 的区别:从原理到实践全解析
  • lua dofile 传参数
  • GhostRace: Exploiting and Mitigating Speculative Race Conditions-记录
  • 基于 Python 将 PDF 转 Markdown 并拆解为 JSON,支持自定义标题处理
  • Odoo:免费开源ERP的AI技术赋能出海企业电子商务应用介绍
  • Python Turtle图形库基本命令详解
  • leetcode之hot100---160相交链表(C++)
  • MFC/C++学习系列之简单记录2——thread和Release
  • 【服务器】MyBatis是如何在java中使用并进行分页的?