3.3 串口通讯
一、实验目的
本节课主要学习K210的串口通讯。
二、实验准备
1.实验元件
Type-C接口和CH340串口芯片
2.元件特性
Tpye-C接口连接到串口芯片,具有供电和串口传输数据的功能,下载程序也是通过串口传输数据的功能把固件传输到K210芯片上的。
Type-C接口是目前主流的数据传输连接接口,市面上很多智能手机也是使用Type-C接口给手机充电和传输数据。Type-C接口是可以正反插的,不用担心反向拿反而插不进的问题。
CH340串口芯片是一个USB总线的转接芯片,可以实现USB转串口。具有全速USB设备接口,硬件全双工串口,内置收发缓冲区,支持通讯波特率为50bps~2Mbps,兼容USBV2.0等特点。
3.硬件连接
Tpye-C接口连接K210的IO4和IO5接口,其中IO4为K210芯片的接收引脚,IO5为K210芯片的发送引脚。
4.SDK中对应API功能
对应的头文件 uart.h
通用UART 为UART1、UART2 和UART3,支持异步通信(RS232 和RS485 和IRDA,通信速率可达到5Mbps。UART 支持CTS 和RTS 信号的硬件管理以及软件流控(XON 和XOFF)。3 个接口均可被DMA 访问或者CPU 直接访问。每次传输数据为8字节,支持异步时钟,可单独配置数据时钟,实现全双工模式,保证两个时钟域中数据同步。
uart默认为RS232模式,也可以配置为软件可编程式RS485模式。
用THRE 中断模式来提升串口性能。当THRE 模式和FIFO 模式被选择之后,如果FIFO 中少于阈值便触发THRE 中断。
为用户提供以下接口:
• uart_init:初始化uart
• uart_config (0.6.0 后不再支持,请使用uart_configure)
• uart_configure:配置串口的波特率等
• uart_send_data:通过串口发送数据
• uart_send_data_dma:通过dma通道发送数据
• uart_send_data_dma_irq:UART通过DMA发送数据,并注册DMA接收完成中断函数,仅单次中断
• uart_receive_data:读取串口数据
• uart_receive_data_dma:串口通过dma接收数据
• uart_receive_data_dma_irq:UART通过DMA接收数据,并注册DMA接收完成中断函数,仅单次中断
• uart_irq_register:注册串口中断函数
• uart_irq_deregister:注销串口中断
• uart_set_work_mode:设置uart工作模式。有四种模式:普通uart、红外、RS485全双工、RS485半双工。
• uart_set_rede_polarity:设置RS485 re de 管脚有效时的极性。
• uart_set_rede_enable:使能 re de管脚,主要用在rs485全双工模式,re和de必须手动控制。单双工模式不用调用该函数,单双工时硬件会自动设置re de。
• uart_set_tat:配置re de互相的时间间隔,这个与外部的485模块有关。
• uart_set_det:设置de 有效无效转换时数据的时间延时。
• uart_debug_init:配置调试串口。系统默认使用UART3做为调试串口,调用该函数用户可以自定义使用哪个uart做为调试串口,如果使用UART1或UART2需要使用fpioa设置管脚。因此调试脚不局限于fpioa4、5
• uart_handle_data_dma:UART通过DMA传输数据
高速通用异步收发传输器(UARTHS)对应的头文件uarths.h
高速UART为UARTHS(UART0),通讯速率可达到5Mbps,8字节发送和接收FIFO,可编程式THRE中断,不支持硬件流控制或者其他调制解调器控制信号,或同步串行数据转换器。系统的printf调试函数默认就是调用UARTHS串口来实现发送数据的。
为用户提供以下接口
• uarths_init:初始化UARTHS,系统默认波特率为115200 8bit 1 位停止位无检验位。因为uarths 时钟源为PLL0,在设置PLL0 后需要重新调用该函数设置波特率,否则会打印乱码。
• uarths_config:设置UARTHS的参数。默认8bit数据,无校验位。
• uarths_receive_data:通过UARTHS读取数据。
• uarths_send_data:通过UART发送数据。
• uarths_set_irq:设置UARTHS中断回调函数。
• uarths_get_interrupt_mode:获取UARTHS的中断类型。接收、发送或接收发送同时中断。
• uarths_set_interrupt_cnt:设置UARTHS中断时的FIFO深度。 当中断类型为UARTHS_SEND_RECEIVE,发送接收FIFO中断深度均为cnt;
三、实验原理
串口通讯是指外设和计算机间,通过数据信号线、地线等,按位(bit)进行传输数据(发送和接收)的一种通讯方式,一个字符一个字符地传输,每个字符一位一位地传输,并且传输一个字符时,总是以“起始位”开始,以“停止位”结束,字符之间没有固定的时间间隔要求,但是数据是低位在前,高位在后,然后接上奇偶检验位。
序号 | 名称 | 备注 |
1 | 起始位 | 表示传输字符的开始,逻辑"0"的信号。 |
2 | 数据位 | 数据位的个数可以是5、6、7、8等,构成一个字符 从最低位开始传送,靠时钟定位 |
3 | 奇偶校验位 | 数据位加上这一位后,使得"1"的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性 |
4 | 停止位 | 一个字符数据的结束标志,可以是1位、1.5位、2位的高电平 |
串口支持全双工通讯,也就是使用一根线发送数据的同时,用另一根线接收数据。串口通讯最重要的参数是波特率、数据位、停止位和奇偶校验,对于两个通讯的端口,这些参数是必须设置为相同的。
四、实验过程
1.首先根据上面的硬件连接引脚图,K210的硬件引脚和软件功能使用的是FPIOA映射关系。
这里要注意的是程序里操作的都是软件引脚,所以需要先把硬件引脚映射成软件GPIO功能,操作的时候直接操作软件GPIO即可。
2.然后是初始化串口,这里我们选择的是串口3,设置波特率为115200,串口数据宽度为8位,停止位为1位,不使用奇偶校验。
3.开机的时候发送“hello yahboom!”,提示已经开机完成。
4.然后循环等待串口数据,如果接收到串口数据,再通过串口把接收到的数据发送出去。
5.编译调试,烧录运行
把本课程资料中的gpiohs_rgb复制到SDK中的src目录下,然后进入build目录,运行以下命令编译。
cmake .. -DPROJ=uart -G "MinGW Makefiles"
make
编译完成后,在build文件夹下会生成uart.bin文件。
使用type-C数据线连接电脑与K210开发板,打开kflash,选择对应的设备,再将程序固件烧录到K210开发板上。
五、实验现象
烧录完成固件后,系统会弹出一个终端界面,如果没有弹出终端界面的可以打开串口助手显示调试内容。
打开电脑的串口助手,选择对应的K210开发板对应的串口号,波特率设置为115200,然后点击打开串口助手。注意还需要设置一下串口助手的DTR和RTS。在串口助手底部此时的4.DTR和7.RTS默认是红色的,点击4.DTR和7.RTS,都设置为绿色,然后按一下K210开发板的复位键。
从串口助手,可以接收到hello yahboom!的欢迎语,然后在底部输入要发送的字符,然后点击发送,K210会把接收到的数据发送回来在串口助手上显示。
六、实验总结
1.uart总共有三个,分别是UART1,UART2和UART3。
2.uart默认使用RS232模式,可以另外配置成可编程式RS485模式。
3.uart的引脚如果映射到其他硬件引脚上,需要连接其他串口芯片如CH340上才可以显示数据。
附:API
对应的头文件 uart.h
初始化uart。
void uart_init(uart_device_number_t channel)
参数名称 | 描述 | 输入输出 |
channel | UART号 | 输入 |
无。
设置UART相关参数。该函数已废弃,替代函数为uart_configure。
设置UART相关参数。
void uart_configure(uart_device_number_t channel, uint32_t baud_rate, uart_bitwidth_t data_width, uart_stopbit_t stopbit, uart_parity_t parity)
参数名称 | 描述 | 输入输出 |
channel | UART 编号 | 输入 |
baud_rate | 波特率 | 输入 |
data_width | 数据位 (5-8) | 输入 |
stopbit | 停止位 | 输入 |
parity | 校验位 | 输入 |
无。
通过UART发送数据。
int uart_send_data(uart_device_number_t channel, const char *buffer, size_t buf_len)
参数名称 | 描述 | 输入输出 |
channel | UART 编号 | 输入 |
buffer | 待发送数据 | 输入 |
buf_len | 待发送数据的长度 | 输入 |
已发送数据的长度。
UART通过DMA发送数据。数据全部发送完毕后返回。
void uart_send_data_dma(uart_device_number_t uart_channel, dmac_channel_number_t dmac_channel, const uint8_t *buffer, size_t buf_len)
参数名称 | 描述 | 输入输出 |
uart_channel | UART 编号 | 输入 |
dmac_channel | DMA通道 | 输入 |
buffer | 待发送数据 | 输入 |
buf_len | 待发送数据的长度 | 输入 |
无。
UART通过DMA发送数据,并设置DMA发送完成中断函数,仅单次中断。
void uart_send_data_dma_irq(uart_device_number_t uart_channel, dmac_channel_number_t dmac_channel,
const uint8_t *buffer, size_t buf_len, plic_irq_callback_t uart_callback,
void *ctx, uint32_t priority)
参数名称 | 描述 | 输入输出 |
uart_channel | UART 编号 | 输入 |
dmac_channel | DMA通道 | 输入 |
buffer | 待发送数据 | 输入 |
buf_len | 待发送数据的长度 | 输入 |
uart_callback | DMA中断回调 | 输入 |
ctx | 中断函数参数 | 输入 |
priority | 中断优先级 | 输入 |
无。
通过UART读取数据。
int uart_receive_data(uart_device_number_t channel, char *buffer, size_t buf_len);
参数名称 | 描述 | 输入输出 |
channel | UART 编号 | 输入 |
buffer | 接收数据 | 输出 |
buf_len | 接收数据的长度 | 输入 |
已接收到的数据长度。
UART通过DMA接收数据。
void uart_receive_data_dma(uart_device_number_t uart_channel, dmac_channel_number_t dmac_channel, uint8_t *buffer, size_t buf_len)
参数名称 | 描述 | 输入输出 |
uart_channel | UART 编号 | 输入 |
dmac_channel | DMA通道 | 输入 |
buffer | 接收数据 | 输出 |
buf_len | 接收数据的长度 | 输入 |
无。
UART通过DMA接收数据,并注册DMA接收完成中断函数,仅单次中断。
void uart_receive_data_dma_irq(uart_device_number_t uart_channel, dmac_channel_number_t dmac_channel,
uint8_t *buffer, size_t buf_len, plic_irq_callback_t uart_callback,
void *ctx, uint32_t priority)
参数名称 | 描述 | 输入输出 |
uart_channel | UART 编号 | 输入 |
dmac_channel | DMA通道 | 输入 |
buffer | 接收数据 | 输出 |
buf_len | 接收数据的长度 | 输入 |
uart_callback | DMA中断回调 | 输入 |
ctx | 中断函数参数 | 输入 |
priority | 中断优先级 | 输入 |
无。
注册UART中断函数。
void uart_irq_register(uart_device_number_t channel, uart_interrupt_mode_t interrupt_mode, plic_irq_callback_t uart_callback, void *ctx, uint32_t priority)
参数名称 | 描述 | 输入输出 |
channel | UART 编号 | 输入 |
interrupt_mode | 中断类型 | 输入 |
uart_callback | 中断回调 | 输入 |
ctx | 中断函数参数 | 输入 |
priority | 中断优先级 | 输入 |
无。
注销UART中断函数。
void uart_irq_deregister(uart_device_number_t channel, uart_interrupt_mode_t interrupt_mode)
参数名称 | 描述 | 输入输出 |
channel | UART 编号 | 输入 |
interrupt_mode | 中断类型 | 输入 |
无。
设置uart工作模式。有四种模式:普通uart、红外、RS485全双工、RS485半双工。
void uart_set_work_mode(uart_device_number_t uart_channel, uart_work_mode_t work_mode)
参数名称 | 描述 | 输入输出 |
channel | UART 编号 | 输入 |
work_mode | 工作模式,详细见uart_work_mode_t结构体说明 | 输入 |
无。
设置RS485 re de 管脚有效时的极性。
void uart_set_rede_polarity(uart_device_number_t uart_channel, uart_rs485_rede_t rede, uart_polarity_t polarity)
参数名称 | 描述 | 输入输出 |
uart_channel | UART 编号 | 输入 |
rede | re 或de 管脚 | 输入 |
polarity | 有效时极性 | 输入 |
无。
使能 re de管脚,主要用在rs485全双工模式,re和de必须手动控制。单双工模式不用调用该函数,单双工时硬件会自动设置re de。
void uart_set_rede_enable(uart_device_number_t uart_channel, uart_rs485_rede_t rede, bool enable)
参数名称 | 描述 | 输入输出 |
uart_channel | UART 编号 | 输入 |
rede | re 或de 管脚 | 输入 |
enable | 是否有效 | 输入 |
无。
配置re de互相的时间间隔,这个与外部的485模块有关。
void uart_set_tat(uart_device_number_t uart_channel, uart_tat_mode_t tat_mode, size_t time)
参数名称 | 描述 | 输入输出 |
uart_channel | UART 编号 | 输入 |
tat_mode | 转换模式re到de或de到re | 输入 |
time | 时间(纳秒) | 输入 |
无。
设置de 有效无效转换时数据的时间延时。
void uart_set_det(uart_device_number_t uart_channel, uart_det_mode_t det_mode, size_t time)
参数名称 | 描述 | 输入输出 |
uart_channel | UART 编号 | 输入 |
det_mode | 转换模式,de无效转有效或有效转无效 | 输入 |
time | 时间(纳秒) | 输入 |
无。
配置调试串口。系统默认使用UART3做为调试串口,调用该函数用户可以自定义使用哪个uart做为调试串口,如果使用UART1或UART2需要使用fpioa设置管脚。因此调试脚不局限于fpioa4、5。
void uart_debug_init(uart_device_number_t uart_channel)
参数名称 | 描述 | 输入输出 |
uart_channel | UART 编号,-1则默认使用上次设置的UART | 输入 |
无。
UART通过DMA传输数据。
void uart_handle_data_dma(uart_device_number_t uart_channel ,uart_data_t data, plic_interrupt_t *cb)
参数名称 | 描述 | 输入输出 |
uart_channel | UART 编号 | 输入 |
data | UART数据相关的参数,详见i2c_data_t说明 | 输入 |
cb | dma中断回调函数,如果设置为NULL则为阻塞模式,直至传输完毕后退出函数 | 输入 |
无
相关数据类型、数据结构定义如下:
uart_device_number_t:UART 编号。
uart_bitwidth_t:UART 数据位宽。
uart_stopbits_t:UART 停止位。
uart_parity_t:UART 校验位。
uart_interrupt_mode_t:UART中断类型,接收或发送。
uart_send_trigger_t:发送中断或DMA触发FIFO深度。
uart_receive_trigger_t:接收中断或DMA触发FIFO深度。
uart_data_t:使用dma传输时数据相关的参数。
uart_interrupt_mode_t:传输模式,发送或接收。
uart_work_mode_t:UART工作模式。
uart_rs485_rede_t:选择re de管脚。
uart_polarity_t:de re极性。
uart_tat_mode_t:de re转换选择。
uart_det_mode_t:de 有效无效选择。
UART编号。
typedef enum _uart_device_number
{
UART_DEVICE_1,
UART_DEVICE_2,
UART_DEVICE_3,
UART_DEVICE_MAX,
} uart_device_number_t;
成员名称 | 描述 |
UART_DEVICE_1 | UART 1 |
UART_DEVICE_2 | UART 2 |
UART_DEVICE_3 | UART 3 |
UART数据位宽。
typedef enum _uart_bitwidth
{
UART_BITWIDTH_5BIT = 0,
UART_BITWIDTH_6BIT,
UART_BITWIDTH_7BIT,
UART_BITWIDTH_8BIT,
} uart_bitwidth_t;
成员名称 | 描述 |
UART_BITWIDTH_5BIT | 5比特 |
UART_BITWIDTH_6BIT | 6比特 |
UART_BITWIDTH_7BIT | 7比特 |
UART_BITWIDTH_8BIT | 8比特 |
UART 停止位。
typedef enum _uart_stopbits
{
UART_STOP_1,
UART_STOP_1_5,
UART_STOP_2
} uart_stopbits_t;
成员名称 | 描述 |
UART_STOP_1 | 1 个停止位 |
UART_STOP_1_5 | 1.5 个停止位 |
UART_STOP_2 | 2 个停止位 |
UART 校验位。
typedef enum _uart_parity
{
UART_PARITY_NONE,
UART_PARITY_ODD,
UART_PARITY_EVEN
} uart_parity_t;
成员名称 | 描述 |
UART_PARITY_NONE | 无校验位 |
UART_PARITY_ODD | 奇校验 |
UART_PARITY_EVEN | 偶校验 |
UART中断类型,接收或发送。
typedef enum _uart_interrupt_mode
{
UART_SEND = 1,
UART_RECEIVE = 2,
} uart_interrupt_mode_t;
成员名称 | 描述 |
UART_SEND | UART 发送 |
UART_RECEIVE | UART 接收 |
发送中断或DMA触发FIFO深度。当FIFO中的数据小于等于该值时触发中断或DMA传输。FIFO的深度为16字节。
typedef enum _uart_send_trigger
{
UART_SEND_FIFO_0,
UART_SEND_FIFO_2,
UART_SEND_FIFO_4,
UART_SEND_FIFO_8,
} uart_send_trigger_t;
成员名称 | 描述 |
UART_SEND_FIFO_0 | FIFO为空 |
UART_SEND_FIFO_2 | FIFO剩余2字节 |
UART_SEND_FIFO_4 | FIFO剩余4字节 |
UART_SEND_FIFO_8 | FIFO剩余8字节 |
接收中断或DMA触发FIFO深度。当FIFO中的数据大于等于该值时触发中断或DMA传输。FIFO的深度为16字节。
typedef enum _uart_receive_trigger
{
UART_RECEIVE_FIFO_1,
UART_RECEIVE_FIFO_4,
UART_RECEIVE_FIFO_8,
UART_RECEIVE_FIFO_14,
} uart_receive_trigger_t;
成员名称 | 描述 |
UART_RECEIVE_FIFO_1 | FIFO剩余1字节 |
UART_RECEIVE_FIFO_4 | FIFO剩余2字节 |
UART_RECEIVE_FIFO_8 | FIFO剩余4字节 |
UART_RECEIVE_FIFO_14 | FIFO剩余8字节 |
使用dma传输时数据相关的参数。
typedef struct _uart_data_t
{
dmac_channel_number_t tx_channel;
dmac_channel_number_t rx_channel;
uint32_t *tx_buf;
size_t tx_len;
uint32_t *rx_buf;
size_t rx_len;
uart_interrupt_mode_t transfer_mode;
} uart_data_t;
成员名称 | 描述 |
tx_channel | 发送时使用的DMA通道号 |
rx_channel | 接收时使用的DMA通道号 |
tx_buf | 发送的数据 |
tx_len | 发送数据的长度 |
rx_buf | 接收的数据 |
rx_len | 接收数据长度 |
transfer_mode | 传输模式,发送或接收 |
UART数据传输模式。
typedef enum _uart_interrupt_mode
{
UART_SEND = 1,
UART_RECEIVE = 2,
} uart_interrupt_mode_t;
成员名称 | 描述 |
UART_SEND | 发送 |
UART_RECEIVE | 接收 |
UART工作模式。
typedef enum _uart_work_mode
{
UART_NORMAL,
UART_IRDA,
UART_RS485_FULL_DUPLEX,
UART_RS485_HALF_DUPLEX,
} uart_work_mode_t;
成员名称 | 描述 |
UART_NORMAL | 普通UART |
UART_IRDA | 红外 |
UART_RS485_FULL_DUPLEX | 全双工RS485 |
UART_RS485_HALF_DUPLEX | 半双工RS485 |
RS485 re de管脚。
typedef enum _uart_rs485_rede
{
UART_RS485_DE,
UART_RS485_RE,
UART_RS485_REDE,
} uart_rs485_rede_t;
成员名称 | 描述 |
UART_RS485_DE | 选择de管脚 |
UART_RS485_RE | 选择re管脚 |
UART_RS485_REDE | 同时选择de re管脚 |
re de 有效时的极性。
typedef enum _uart_polarity
{
UART_LOW,
UART_HIGH,
} uart_polarity_t;
成员名称 | 描述 |
UART_LOW | 低电平 |
UART_HIGH | 高电平 |
re de转换的模式。
typedef enum _uart_tat_mode
{
UART_DE_TO_RE,
UART_RE_TO_DE,
UART_TAT_ALL,
} uart_tat_mode_t;
成员名称 | 描述 |
UART_DE_TO_RE | de 有效转 re有效 |
UART_RE_TO_DE | re 有效转 de有效 |
UART_TAT_ALL | de转re re转de |
de 有效无效选择。
typedef enum _uart_det_mode
{
UART_DE_ASSERTION,
UART_DE_DE_ASSERTION,
UART_DE_ALL,
} uart_det_mode_t;
成员名称 | 描述 |
UART_DE_ASSERTION | de 有效 |
UART_DE_DE_ASSERTION | de 无效 |
UART_DE_ALL | de 有效 无效 |
对应的头文件 uarths.h
初始化UARTHS,系统默认波特率为115200 8bit 1位停止位 无检验位。因为uarths时钟源为PLL0,在设置PLL0后需要重新调用该函数设置波特率,否则会打印乱码。
void uarths_init(void)
无。
无。
设置UARTHS的参数。默认8bit数据,无校验位。
void uarths_config(uint32_t baud_rate, uarths_stopbit_t stopbit)
参数名称 | 描述 | 输入输出 |
baud_rate | 波特率 | 输入 |
stopbit | 停止位 | 输入 |
无。
通过UARTHS读取数据。
size_t uarths_receive_data(uint8_t *buf, size_t buf_len)
参数名称 | 描述 | 输入输出 |
buf | 接收数据 | 输出 |
buf_len | 接收数据的长度 | 输入 |
已接收到的数据长度。
通过UART发送数据。
size_t uarths_send_data(const uint8_t *buf, size_t buf_len)
参数名称 | 描述 | 输入输出 |
buf | 待发送数据 | 输入 |
buf_len | 待发送数据的长度 | 输入 |
已发送数据的长度。
设置UARTHS中断回调函数。
void uarths_set_irq(uarths_interrupt_mode_t interrupt_mode, plic_irq_callback_t uarths_callback, void *ctx, uint32_t priority)
参数名称 | 描述 | 输入输出 |
interrupt_mode | 中断类型 | 输入 |
uarths_callback | 中断回调函数 | 输入 |
ctx | 回调函数的参数 | 输入 |
priority | 中断优先级 | 输入 |
无。
获取UARTHS的中断类型。接收、发送或接收发送同时中断。
uarths_interrupt_mode_t uarths_get_interrupt_mode(void)
无
当前中断的类型。
设置UARTHS中断时的FIFO深度。 当中断类型为UARTHS_SEND_RECEIVE,发送接收FIFO中断深度均为cnt;
void uarths_set_interrupt_cnt(uarths_interrupt_mode_t interrupt_mode, uint8_t cnt)
参数名称 | 描述 | 输入输出 |
interrupt_mode | 中断类型 | 输入 |
cnt | FIFO深度 | 输入 |
无。
/* 设置接收中断 中断FIFO深度为0,即接收到数据立即中断并读取接收到的数据。*/
int uarths_irq(void *ctx)
{
if(!uarths_receive_data((uint8_t *)&receive_char, 1))
printf("Uarths receive ERR!n");
return 0;
}
plic_init();
uarths_set_interrupt_cnt(UARTHS_RECEIVE , 0);
uarths_set_irq(UARTHS_RECEIVE ,uarths_irq, NULL, 4);
sysctl_enable_irq();
相关数据类型、数据结构定义如下:
uarths_interrupt_mode_t:中断类型。
uarths_stopbit_t:停止位。
UARTHS中断类型。
typedef enum _uarths_interrupt_mode
{
UARTHS_SEND = 1,
UARTHS_RECEIVE = 2,
UARTHS_SEND_RECEIVE = 3,
} uarths_interrupt_mode_t;
成员名称 | 描述 |
UARTHS_SEND | 发送中断 |
UARTHS_RECEIVE | 接收中断 |
UARTHS_SEND_RECEIVE | 发送接收中断 |
UARTHS停止位。
typedef enum _uarths_stopbit
{
UART_STOP_1,
UART_STOP_2
} uarths_stopbit_t;
成员名称 | 描述 |
UART_STOP_1 | 1位停止位 |
UART_STOP_2 | 2位停止位 |