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

server/2024/12/22 20:24:14/

前言:

        上一篇文章已经把如何配置和安装开发环境介绍了一下,开发环境准备完毕之后就可以进行具体的项目开发了,这个款芯片的外设接口很多,我个人觉得用的最多的还是串口,这篇文章就介绍一下串口的开发流程,如果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            1024static 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 numberva_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,		// 波特率为96000,   //配置为普通串口模式,若要配置为低功耗模式可改为10,   //环形缓存区大小按照默认配置8k0,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.ppmy.cn/server/152312.html

相关文章

智能电商:API接口如何驱动自动化与智能化转型

在当今这个数字化时代&#xff0c;电商行业正以前所未有的速度发展&#xff0c;而智能电商作为电商领域的重要发展方向&#xff0c;其自动化与智能化转型已成为行业关注的焦点。API&#xff08;应用程序编程接口&#xff09;接口作为电商平台与外部系统或服务进行交互的桥梁&am…

AG32 IDE 开发环境搭建

一、准备工作 需要的PC环境&#xff1a;64位系统&#xff0c;Win8.1/Win10/Win11 &#xff08;注&#xff1a;不支持Win7&#xff09; 初次使用时&#xff0c;请按照以下几个步骤来搭建环境&#xff1a; 下载安装软件和SDK&#xff1a;安装VSCODE&#xff08;开发中的IDE&am…

配置TypeScript:tsconfig.json详解

今天我们要深入了解 TypeScript 中最核心的配置文件——tsconfig.json。如果你已经开始写 TypeScript 代码&#xff0c;那么你可能已经接触过这个文件。它是 TypeScript 项目中必不可少的一部分&#xff0c;负责控制 TypeScript 编译器的行为。 但如果你对它还不太熟悉&#x…

如何处理对象的创建和销毁?

概念 处理对象的创建和销毁是软件开发中的核心问题&#xff0c;尤其是在确保资源管理、性能优化和代码清晰性方面。以下是一些常用的方法和设计模式&#xff0c;用于有效管理对象的创建和销毁。 方法 构造函数和析构函数 在C等语言中&#xff0c;使用构造函数和析构函数是最…

不同协议下的接口测试方案设计

什么是多协议接口测试&#xff1f; 多协议接口测试是指在不同协议&#xff08;如HTTP、HTTPS、TCP/IP、SOAP、REST等&#xff09;下进行的接口测试。这类测试的主要目标是确保不同协议间的组件可以顺畅地进行通信&#xff0c;从而提高系统的整体可用性和稳定性。接口测试不仅可…

敏感词过滤

敏感词过滤通常是指在文本中检测并替换或删除不适宜的内容。基于DFA&#xff08;Deterministic Finite Automaton&#xff0c;确定性有限自动机&#xff09;算法的敏感词过滤是一种高效的方法。DFA算法通过构建一个状态机来匹配敏感词&#xff0c;其核心思想是将每个敏感词转换…

怎样衡量电阻负载的好坏

电阻负载的好坏通常通过以下几种方法来衡量&#xff1a; 1. 测量电阻值&#xff1a;最直接的方法是使用万用表来测量电阻负载的电阻值。将万用表设置在适当的电阻档位&#xff0c;然后将测试笔连接到电阻负载的两个引脚上。如果电阻负载是好的&#xff0c;那么万用表应该显示一…

ES6中的map和set

Set ES6 提供了新的数据结构 Set。它类似于数组&#xff0c;但是成员的值都是唯一的&#xff0c;没有重复的值。 Set本身是一个构造函数&#xff0c;用来生成 Set 数据结构。 以下代码 const s new Set();[2, 3, 5, 4, 5, 2, 2].forEach(x > s.add(x));for (let i of s…