完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
` 上一节我们和大家分享了基于AMetal平台LED灯控制,对于一个初学者的第一步学习都是从点灯开始,熟悉了基础的工程结构和点灯控制后将慢慢升级为通过通信端口与外界交互通信,通过通信端口的数据收发可以了解MCU执行的状态和输入命令控制。那么我们今天将进入到基于立功科技的AMetal平台的MM32 MCU的串口操作。 图1 LED工程 如上图所示,我操作了板载的4个LED闪烁,除了看到LED的操作,我们还可以看到 am_main()接口中的第 1 行代码调用了一个宏 AM_DBG_INFO(),其功能是通过调试串口向外部输出调试信息,用户可通过该接口在程序中向外部输出调试信息,代码中通过该接口向外部输出了字符串“Start up successful! ”,表示系统启动正常。 我们通过程序跳转发现其定义为: #define AM_DBG_INFO(...) (void) am_kprintf(__VA_ARGS__) 可见,调用该宏实际上调用的是接口 am_kprintf(),而 am_kprintf()接口的定义为: int am_kprintf (const char *fmt, ...) { int len; va_list args; if ((NULL == gpfunc_kputc) || (NULL == gpfunc_kputs)) { return 0; } va_start(args, fmt); len = am_vfprintf_do(gp_kout_file, gpfunc_kputc, gpfunc_kputs, fmt, args); va_end(args); return len; } 在上述的函数中, fmt 参数为格式化字符串,后续参数为不定参,需根据参数 fmt 的内容传入。该接口的使用方法与 printf()类似,用户可参考 printf()的使用方法来使用该函数。 在 AMetal 中,通常习惯于使用宏AM_DBG_INFO()来输出调试信息, am_kprintf()接口通常被替换为AM_DBG_INFO()。 AM_DBG_INFO()的功能是通过串口向外部输出调试信息,但可以发现,在使用该接口的过程中并没有串口相关信息的体现,这是因为在一个系统中,调试串口通常只有一个且一般不需要在程序运行的过程中更改,所以 AMetal 将指定串口的参数取消,改用一个用户配置文件来存放调试串口的相关信息。根据 AMetal 用户配置文件的命名规则,调试串口的相关信息可在 user_config 目录下的 am_hwconf_debug_uart.c 文件中找到。 为了方便了解程序从一上电开始执行了那些步骤,我们直接使用工程进入debug模式,可以发现在debug状态下,断点会指向main函数,如下图所示: 图2 调试状态窗口 我们根据上图可以看到,在系统启动时,我们定义了一些全局变量参数,通过宏定义的方式,可以选择对MCU相关外设进行初始化操作,以便全局调用,如NVIC GPIO CLK DMA RAM等相关功能,操作的函数有: 01 am_mm32l073_nvic_inst_init() /** 函数功能:中断实例初始化,初始化中断驱动 * 输入参数:无 * 返回值: AM_OK * 说明:在实例初始化中,初始化全局资源外设时,返回值为 int 类型,仅仅是一个初始化结果标志(int 类型)。 */ 02 am_mm32l073_clk_inst_init() /** 函数功能:CLK实例初始化,初始化系统时钟 * 输入参数:无 * 返回值:AM_OK * 说明:返回AM_OK表示时钟初始化成功,返回AM_ ERROR表示初始化失败 */ 03 am_mm32l073_gpio_inst_init() /** 函数功能:GPIO实例初始化 * 输入参数:无 * 返回值:AM_OK * 说明:GPIO平台初始化,初始化每一个引脚的回调处理函数及触发方式,包括GPIO的中断处理 */ 04 am_mm32l073_dma_inst_init() /** 函数功能:DMA实例初始化 * 输入参数:无 * 返回值:AM_OK * 说明:无 */ 05 am_nvram_inst_init() /** 函数功能:存储标准服务初始化 * 输入参数:无 * 返回值:AM_OK * 说明:初始化时,指定应用程序的存储段 */ 06 am_board_init() /** 函数功能:板级外设初始化 * 输入参数:无 * 返回值:AM_OK * 说明:此函数可以由用户添加,主要针对板级的外设初始化,如:systick、LED_GPIO、BEEP、KEY_GPIO等板载外设进行初始化操作,方便用户全局调用。 */ 每个外设驱动都提供了对应的驱动解初始化函数,以便应用不再使用某个外设时,释放掉相关资源。当应用不再使用该外设时,只需要调用一下该函数即可,如下所示:am_{dev_name}_deinit() 如: 中断NVIC的初始化函数: am_mm32l073_nvic_inst_init (void) 解初始化函数: am_mm32l073_nvic_inst_deinit (void) 用户调用即可,可以释放相关的资源。 AMetal 平台提供了 UART 初始化函数,可以直接调用初始化函数,在官方提供的例程中,默认提供配置是UART1。初始化UART1,调用该函数时需要定义一个 am_uart_handle_t 类型的变量,用于保存获取的 UART1服务句柄, UART1初始化程序如下: /** 函数功能:调试串口UART1实例初始化 * 输入参数:无 * 返回值:UART 标准服务句柄,若为 NULL,表明初始化失败 */ am_uart_handle_t am_debug_uart_inst_init (void) { am_uart_handle_t handle = NULL; handle = am_mm32l073_uart1_inst_init(); /* 调试初始化 */ am_debug_init(handle, __DEBUG_BAUDRATE); return handle; } /** rief UART1实例初始化,获取UART1句柄 */ am_uart_handle_t am_mm32l073_uart1_inst_init (void) { return am_mm32_uart_init(&__g_uart1_dev, &__g_uart1_devinfo); } 其中__g_uart1_dev(am_mm32_uart_dev_t) 定义的是串口设备结构体定义,&__g_uart1_devinfo定义的是UART1的设备信息初始化操作,主要包含UART1的外设的基础配置,包括时钟初始化、UART1参数设定、GPIO初始化等操作,用户如果需要修改波特率或配置中断等都在该结构体中修改。 官方提供了UART标准的接口函数,用户可以在amhw_mm32_uart.h中找,标准的接口函数列表如下:
在这里我们主要讲下面四个函数函数的输入参数,其他的函数用户可以在资料中了解。 01 UART 数据发送(查询模式)函数原型 int am_uart_poll_send (am_uart_handle_t handle,const uint8_t *p_txbuf, uint32_t nbytes)
02 UART 数据接收(查询模式)函数原型 int am_uart_poll_receive (am_uart_handle_t handle, uint8_t *p_rxbuf, uint32_t nbytes)
03 启动 UART 中断模式数据传输函数原型 int am_uart_tx_startup (am_uart_handle_t handle)
基于以上信息,启动 UART 中断模式数据传输程序为: am_uart_tx_startup(uart_handle) 04 设置 UART 回调函数详解 当发生错误时,调用回调函数,执行错误回调函数。 回调函数与普通函数一样,程序为: void uart_callback(void *p_arg) { AM_DBG_INFO(“UART ERROR! ”); } 设置 UART 回调函数函数原型为: static int __uart_callback_set (void * handle, int callback_type, void *pfn_callback, void *p_arg);
UART 通信时,由于查询模式会阻塞整个应用,因此在实际应用中几乎都使用中断模式。但在中断模式下,UART 每收到一个数据都会调用回调函数,如果将数据的处理放在回调函数中,很有可能因当前数据的处理还未结束而丢失下一个数据。 基于此,AMetal 提供了一组带缓冲区的 UART 通用接口,其实现是在UART 中断接收与应用程序之间,增加一个接收缓冲区。当串口收到数据时,将数据存放在缓冲区中,应用程序直接访问缓冲区即可。对于 UART 发送,虽然不存在丢失数据的问题,但为了便于开发应用程序,避免在 UART中断模式下的回调函数接口中一次发送单个数据,同样提供了带缓冲区的 UART 发送函数。当应用程序发送数据时,将发送数据存放在发送缓冲区中,串口在发送空闲时提取发送缓冲区中的数据进行发送。
上述简略的讲了一些常用的接口函数,大家有兴趣可以去ZLG官网详细了解更多函数功能,下面我们将以实际的操作来测试检验上述函数功能: 01 UART 查询方式收发示例 #include "ametal.h" #include "am_board.h" #include "am_vdebug.h" #include "am_mm32l073_inst_init.h" static const uint8_t __ch[ ] = {" STD-UART test in polling mode: "}; int am_main (void) { uint8_t uart1_buf[5]; // 数据缓冲区 am_uart_handle_t uart_handle; // 串口标准服务句柄 AM_DBG_INFO("Hello Mindmotion! "); uart_handle =am_mm32l073_uart1_inst_init (); // UART 初始化 am_uart_poll_send(uart_handle, __ch, sizeof(__ch)); while (1) { am_uart_poll_receive(uart_handle, uart1_buf,1); // 接收字符 am_uart_poll_send(uart_handle, uart1_buf,1); // 发送刚刚接收的字符 } } 测试结果: 图3 查询方式UART收发 02 UART 中断方式收发示例 #include "ametal.h" #include "am_board.h" #include "am_vdebug.h" #include "am_mm32l073_inst_init.h" #define BUF_SIZE 8 static int __g_recv_count = 0; static int __uart_recv_irq (void *p_arg, uint8_t dat) { uint8_t *p_buf = (uint8_t *)p_arg; p_buf[__g_recv_count++] = dat; return 0; } int am_main (void) { am_uart_handle_t uart1_handle; AM_DBG_INFO("Hello Mindmotion! "); uart1_handle =am_mm32l073_uart1_inst_init ();//获取串口 1 实例初始化句柄 uint8_t uart1_buf[BUF_SIZE]; am_uart_ioctl(uart1_handle,AM_UART_MODE_SET,(void*)AM_UART_MODE_INT); am_uart_callback_set( uart1_handle,AM_UART_CALLBACK_RXCHAR_PUT,__uart_recv_irq,(void *)uart1_buf); //设置接收回调函数 am_uart_tx_startup(uart1_handle); //启动发送 while (1) { if (__g_recv_count >= BUF_SIZE) { __g_recv_count = 0; am_uart_poll_send(uart1_handle, uart1_buf, BUF_SIZE);//发送接收到的内容 } } } 测试结果: 图4 中断方式UART收发 03 UART 环形缓冲示例 #include "ametal.h" #include "am_board.h" #include "am_vdebug.h" #include "am_uart_rngbuf.h" #include "am_mm32l073_inst_init.h" #define UART_RX_BUF_SIZE 128 /* 接收环形缓冲区大小,应该为 2^n */ #define UART_TX_BUF_SIZE 128 /* 发送环形缓冲区大小,应该为 2^n */ static uint8_t __uart_rxbuf[UART_RX_BUF_SIZE]; /* UART 接收环形缓冲区 */ static uint8_t __uart_txbuf[UART_TX_BUF_SIZE]; /* UART 发送环形缓冲区 */ static const uint8_t __ch[] = {"UART interrupt mode(Add ring buffer) test: "}; static am_uart_rngbuf_dev_t __g_uart_ringbuf_dev; /* 串口缓冲区设备 */ int am_main(void) { am_uart_handle_t uart1_handle; uint8_t uart1_buf[5]; /* 数据缓冲区 */ am_uart_rngbuf_handle_t handle=NULL; /* 串口环形缓冲区服务句柄 */ AM_DBG_INFO("Hello Mindmotion! "); uart1_handle =am_mm32l073_uart1_inst_init ();//获取串口 1 实例初始化句柄 handle = am_uart_rngbuf_init( &__g_uart_ringbuf_dev,uart1_handle, __uart_rxbuf,UART_RX_BUF_SIZE,__uart_txbuf,UART_TX_BUF_SIZE); am_uart_rngbuf_send(handle, __ch, sizeof(__ch)); while (1) { am_uart_rngbuf_receive(handle, uart1_buf,1);/* 从接收缓冲区取出一个数据到 buf */ am_uart_rngbuf_send(handle, uart1_buf,1); /* 将 buf 的一个数据放入环形缓冲区*/ } } 测试结果: |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
2249个成员聚集在这个小组
加入小组灵动微电子MM32全系列MCU产品应用手册,库函数和例程和选型表
11703 浏览 3 评论
【MM32 eMiniBoard试用连载】+基于OLED12864的GUI---U8G2
5930 浏览 1 评论
【MM32 eMiniBoard试用连载】移植RT-Thread至MM32L373PS
10965 浏览 0 评论
【MM32 eMiniBoard测评报告】+ 开箱 + 初探
4577 浏览 1 评论
灵动微课堂(第106讲) | MM32 USB功能学习笔记 —— WinUSB设备
4302 浏览 1 评论
[MM32软件] MM32F002使用内部flash存储数据怎么操作?
981浏览 1评论
806浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-27 21:48 , Processed in 0.605854 second(s), Total 67, Slave 49 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号