热度 18
2015-3-16 18:37
2628 次阅读|
0 个评论
串口通信应用设计 HED10W07SN模块有两个串口。厂家提供的参考实现中,串口0用于管理:AT指令、EM_WIFI程序下载、Boot Loader程序下载(超级终端);串口1可以用于AT指令解释也可以用于用户数据传输。 在我的封装实现中,为了避免冲突以及简化实现,也是因为初学避免引入bug,沿用厂家的配置方式:串口0用于管理,串口1仅用于用户数据传输。 帖子“开发环境”的附件中的工程“MyLearningProject_02”是串口封装和使用的例子。 封装好的串口接口函数在“MOD\include\modUart.h”中定义,实现代码在“MOD\source\modUartSimpleImpl.c”。 main.c是一个简单的应用例子,功能是在收到串口消息后,将消息回传并toggle LED。 注:串口消息的header格式为0x7e 0x7e length。 比如用串口精灵测试时,发送字符串“123”的方式为:用十六进制发送7e7e03313233 API使用方式: 在CreateUserTask()中初始化UART: modUartInit(1,115200); modUartSetRxCallback(myUartRxCallbackFunction); 第1句设置波特率,第2句设置回调函数。(回调函数的名称可以自己定义) 发送消息的例子: modUartSendPkt(1, 11, pWellcomeMsg); 第1个参数固定为1。(该API只支持UART1,不支持UART0) 第2个参数是分组长度,第3个参数是分组指针。 接收消息: 当底层代码收到完整的一个分组后,会调用用户定义的回调函数。 用户在回调函数编写自己的代码对收到的分组进行处理。例子: void myUartRxCallbackFunction(uint8 vUartNumber, uint8 vSize, uint8* vPacket){ //toggle led 0 modSetLedState(0,2); //send it back modUartSendPkt(1, vSize, vPacket); } 与接口实现方式相关的接口使用说明 1、串口接收回调函数是由单独的任务调用,不是在中断服务处理程序中调用,所以没有处理时限要求; 2、消息发送函数modUartSendPkt的实现采用同步发送方式,当分组数据全部向UART硬件发送完毕才返回;支持多线程; modUart API的实现简介 注:下文中HAL层代表厂家提供的底层代码(不论是否硬件相关),MOD层代表我写的模块化代码。 一、底层函数的实现方式 芯片中断调用串口ISR函数tls_uart_isr: * 接收侧:tls_uart_isr从接收寄存器读入数据,放入接收FIFO,然后调用回调函数rx_callback(rx_callback由tls_uart_rx_register设置)。 * 发送侧: tls_uart_isr调用tls_uart_tx_chars从发送FIFO取数据,写入发送寄存器,FIFO半空时调用tx_callback; 二、接收API实现方式 modUartRxCallback()是供tls_uart_isr调用的回调函数。 modUartRxCallback()将数据放进缓冲区,然后发送一个消息MSG_UART_RECEIVE_DATA到消息队列mUart1TaskQueuePtr,然后返回(ISR流程结束)。 启动一个专门的任务modUartDataProcTask处理UART收到的数据。 modUartDataProcTask一直在等待消息队列mUart1TaskQueuePtr的消息,收到消息后调用modUart1RxFramingRoutine()进行帧界定。 modUart1RxFramingRoutine()从接收FIFO中逐字节读入数据,判断帧头、长度,读入足够数目的数据后,调用用户定义的接收回调函数。 所以,用户定义的接收回调函数是在modUartDataProcTask的线程中处理的。 三、发送API实现方式 modUartSendPkt()先调用tls_uart_write发送header字节,然后调用tls_uart_tx_sync()发送分组body。 底层提供的tls_uart_tx_sync()本身实现同步发送机制。 四、tls_uart_tx_sync()的实现 厂家文档中推荐应用调用的串口消息发送函数是:异步发送函数tls_uart_tx()和同步发送函数tls_uart_tx_sync()。 1、tls_uart_tx() tls_uart_tx()将发送的分组数据全部写入到HAL层的发送缓冲区中,未写入的部分保留在串口的数据结构中,由tls_uart_tx_cb继续写入(tls_uart_tx_cb由tls_uart_isr调用)。 * 将发送数据指针和发送长度保存在uart_port -buff_ptr和uart_port - buf_len中。 * 然后调用tls_uart_write()将数据写入HAL层的发送缓冲区。 * 设置发送中断回调函数为tls_uart_tx_cb(tls_uart_tx_register(TLS_UART_1, tls_uart_tx_cb);) * 然后调用tls_uart_tx_chars_start()将缓冲区的若干数据实际发送到UART硬件。 tls_uart_tx_cb负责将uart_port -buff_ptr中未写入HAL层发送缓冲区的数据写入缓冲区。 可见:tls_uart_tx不是线程安全的。 2、tls_uart_tx_sync() tls_uart_tx_sync()调用异步发送函数tls_uart_tx()发送消息; 然后创建并等待信号port-tx_sem: err = tls_os_sem_create(port-tx_sem, 0); tls_uart_tx(buf, len); tls_os_sem_acquire(port-tx_sem, 0); tls_uart_tx_chars()在发送缓冲区空时,释放信号(tls_uart_tx_chars()由中服程序tls_uart_isr调用) if (uart_circ_empty(xmit)) { if(port-tx_sem) tls_os_sem_release(port-tx_sem); return; } tls_uart_tx_sync()收到信号后,返回。 tls_os_sem_delete(port-tx_sem); port-tx_sem = NULL; tls_uart_tx_chars()负责将发送缓冲区的数据写入UART硬件。 可见:tls_uart_tx_sync是线程安全的,但是效率低。 主索引 回教程首页 使用控件 控件设计 附件 参考链接