rtthread studio与正点原子apollo[5]--UART设备
前言
本文介绍RT-Thread中UART设备的使用,主要介绍UART的接收中断和DMA接收。
一、UART设备简介
UART(Universal Asynchronous Receiver/Transmitter)通用异步收发传输器,UART 作为异步串口通信协议的一种,工作原理是将传输数据的每个字符一位接一位地传输。是在应用程序开发过程中使用频率最高的数据总线。
串口通信的协议如下图所示:
串口线无数据传输时为空闲状态,串口线电平为高,当有数据传输时,电平由高变低,起始位占一个串口时钟,接着传递数据位,数据位长度可自定义,通常为8个位,校验位自定义,然后是停止位,数据传输完毕,串口线电平再次变为高电平即空闲状态。
串口通信的核心是配置串行数据格式及串口通信波特率即时钟。
二、RT-Thread使用UART设备
1.访问串口设备
RT-Thread中访问串口及相关API的介绍参考官方文档
UART设备
串口使用的主要步骤:
(1)定义串口设备并查找设备
#define SAMPLE_UART_NAME "uart2" /* 串口设备名称 */
static rt_device_t serial; /* 串口设备句柄 */
/* 查找串口设备 */
serial = rt_device_find(SAMPLE_UART_NAME);
(2)控制串口设备
/* 初始化配置参数 */
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
/* 修改串口配置参数 */
config.baud_rate = BAUD_RATE_9600; //修改波特率为 9600
config.data_bits = DATA_BITS_8; //数据位 8
config.stop_bits = STOP_BITS_1; //停止位 1
config.bufsz = 128; //修改缓冲区 buff size 为 128
config.parity = PARITY_NONE; //无奇偶校验位
/* 控制串口设备。通过控制接口传入命令控制字,与控制参数 */
rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);
(3)打开串口
/* 以中断接收及轮询发送模式打开串口设备 */
rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
/* 以 DMA 接收及轮询发送模式打开串口设备 */
rt_device_open(serial, RT_DEVICE_FLAG_DMA_RX);
(4)发送及接收数据
- 发送数据
char str[] = "hello RT-Thread!\r\n";
/* 发送字符串 */
rt_device_write(serial, 0, str, (sizeof(str) - 1));
数据发送结束可以设置发送完成回调函数
rt_err_t rt_device_set_tx_complete(rt_device_t dev, rt_err_t (*tx_done)(rt_device_t dev,void *buffer));
- 接收数据
通常使用中断方式接收数据,首先设置接收回调函数
rt_err_t rt_device_set_rx_indicate(rt_device_t dev, rt_err_t (*rx_ind)(rt_device_t dev,rt_size_t size));
读取数据
rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size);
2.UART使用实例
在RT-Thread studio中创建工程,并进行后续配置:
(1)采用普通中断的配置
如果使用DMA则开启DMA模式并设置DMA缓冲区大小
(2)打开board.h文件,根据提示进行串口配置
第一步:在(1)中已完成
第二步:定义串口并制定串口引脚
第三步:根据实际需要开启DMA,按(1)中方式进行
第四步:如果开启了DMA功能,则board.h串口配置需要添加一行代码
串口功能的具体配置代码可以参考uart_config.h文件
(3)上述配置完成后即可开始编写功能代码:
普通中断模式通常使用信号量,尽量不要在中断回调函数中进行数据接收,而DMA方式通常采用邮箱或队列方式,也不要在中断回调函数中接收数据
普通中断接收数据的完整示例代码如下:
#include <rtthread.h>
#include <rtdevice.h>
#include "string.h"
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
static rt_device_t serial2;//串口设备句柄
static struct rt_semaphore s2rx_sem;//定义信号量
char uart2_rec_buf[100];
static rt_err_t uart2_rec_callback(rt_device_t dev, rt_size_t size)//中断接收回调函数
{
rt_sem_release(&s2rx_sem);//释放信号量
return RT_EOK;
}
int main(void)
{
char ch;
rt_uint8_t i=0;
rt_sem_init(&s2rx_sem, "serial2_rx_sem", 0, RT_IPC_FLAG_FIFO);//初始化信号量
serial2=rt_device_find("uart2");//查询串口设备
rt_device_open(serial2, RT_DEVICE_OFLAG_RDWR|RT_DEVICE_FLAG_INT_RX);
rt_device_set_rx_indicate(serial2, uart2_rec_callback);//打开串口设备
while (1)
{
if(rt_sem_take(&s2rx_sem,RT_WAITING_FOREVER)==RT_EOK)//等待信号量
{
rt_device_read(serial2, 0, &ch, 1);//读取串口数据
uart2_rec_buf[i++]=ch;
if(i>=2)
{
if(uart2_rec_buf[i-2]=='\r' && uart2_rec_buf[i-1]=='\n')
{
rt_device_write(serial2, 0, uart2_rec_buf, i);
i=0;
memset(uart2_rec_buf, 0, sizeof(uart2_rec_buf));
}
}
}
}
return RT_EOK;
}
DMA方式接收数据的完整示例:
#include <rtthread.h>
#include <rtdevice.h>
#define LED0_PIN GET_PIN(B, 1)
#define UART_NAME "uart2"//定义串口名
static rt_device_t serial2;//串口设备句柄
rt_thread_t serial_tid=RT_NULL;
struct rx_msg//定义接收消息结构体
{
rt_device_t dev;
rt_size_t size;
};
static rt_mq_t uart2_rx_mq;//定义队列
rt_err_t uart2_rx_ind(rt_device_t dev,rt_size_t size)//串口接收中断回调函数
{
rt_err_t ret;
struct rx_msg msg;
msg.dev=dev;
msg.size=size;
ret=rt_mq_send(uart2_rx_mq, &msg, sizeof(msg));//发送消息队列
if(ret==RT_EFULL)
{
rt_kprintf("message queue full!\r\n");
}
return ret;
}
void serial_thread_entry(void *parameter)
{
struct rx_msg msg;
rt_uint16_t rx_len;
char buf[128];
while(1)
{
rt_memset(&msg,0,sizeof(msg));
if(rt_mq_recv(uart2_rx_mq, &msg, sizeof(msg), RT_WAITING_FOREVER)==RT_EOK)//等待消息队列
{
rx_len=rt_device_read(msg.dev, 0, buf, msg.size);//读取串口数据
rt_device_write(serial2, 0, buf, rx_len);
}
}
}
void uart_dma_sample(void)
{
char str[]="hello RT-Thread!\r\n";
uart2_rx_mq=rt_mq_create("uart_mq", 128, 8, RT_IPC_FLAG_FIFO);
serial2=rt_device_find(UART_NAME);
rt_device_open(serial2, RT_DEVICE_FLAG_DMA_RX);
rt_device_set_rx_indicate(serial2, uart2_rx_ind);
rt_device_write(serial2,0,str,(sizeof(str)-1));
serial_tid=rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
rt_thread_startup(serial_tid);
}
int main(void)
{
uart_dma_sample();
return RT_EOK;
}
总结
本文介绍了RT-Thread中UART设备的使用,分别介绍了普通中断方式接收和DMA方式接收。