第十三章 UART实验
本章将介绍Kendryte K210的UART外设。通过本章的学习,读者将学习到UART的使用。 本章分为如下几个小节: 13.1 UART介绍 13.2 硬件设计 13.3 程序设计 13.4 运行验证
13.1 UART介绍 串口通信是一种设备间常用的串行通信方式,串口按位(bit)发送和接收字节。尽管比特字节(byte)的串行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。串口通信协议是指规定了数据包的内容,内容包含了起始位、主体数据、校验位及停止位,双方需要约定一致的数据包格式才能正常收发数据的有关规范。在串口通信中,常用的协议包括RS-232、RS-422和RS-485等。 随着科技的发展,RS-232在工业上还有广泛的使用,但是在商业技术上,已经慢慢的使用USB转串口取代了RS-232串口。我们只需要在电路中添加一个USB转串口芯片,就可以实现USB通信协议和标准UART串行通信协议的转换,而我们开发板上的USB转串口芯片是CH343P这个芯片。 下面我们来学习串口通信协议,这里主要学习串口通信的协议层。 串口通信的数据包由发送设备的TXD接口传输到接收设备的RXD接口。在串口通信的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据,其组成如图 13.1.1所示。 图13.1.1 串口通信协议数据帧格式 串口通信协议数据包组成可以分为波特率和数据帧格式两部分。 1. 波特率本章主要讲解的是串口异步通信,异步通信是不需要时钟信号的,但是这里需要我们约定好两个设备的波特率。波特率表示每秒钟传送的码元符号的个数,所以它决定了数据帧里面每一个位的时间长度。两个要通信的设备的波特率一定要设置相同,我们常见的波特率是4800、9600、115200等。 2. 数据帧格式数据帧格式需要我们提前约定好,串口通信的数据帧包括起始位、停止位、有效数据位以及校验位。 l 起始位和停止位 串口通信的一个数据帧是从起始位开始,直到停止位。数据帧中的起始位是由一个逻辑0 的数据位表示,而数据帧的停止位可以是 0.5、1、1.5或 2个逻辑1的数据位表示,只要双方约定一致即可。 l 有效数据位 数据帧的起始位之后,就接着是数据位,也称有效数据位,这就是我们真正需要的数据,有效数据位通常会被约定为5、6、7或者8个位长。有效数据位是低位(LSB)在前,高位(MSB)在后 l 校验位 校验位可以认为是一个特殊的数据位。校验位一般用来判断接收的数据位有无错误,检验方法有:奇检验、偶检验、0检验、1检验以及无检验。下面分别介绍一下: 奇校验是指有效数据为和校验位中“1”的个数为奇数,比如一个 8 位长的有效数据为:10101001,总共有 4 个“1”,为达到奇校验效果,校验位设置为“1”,最后传输的数据是8位的有效数据加上 1 位的校验位总共 9位。 偶校验与奇校验要求刚好相反,要求帧数据和校验位中“1”的个数为偶数,比如数据帧:11001010,此时数据帧“1”的个数为 4 个,所以偶校验位为“0”。 0 校验是指不管有效数据中的内容是什么,校验位总为“0”,1 校验是校验位总为“1”。 无校验是指数据帧中不包含校验位。 我们一般是使用无校验的情况。 3. Kendryte K210串口介绍Kendryte K210硬件上有3个UART控制器和1个UARTHS控制器,它们能够灵活地与外部设备进行全双工数据交换。 UART一共有3个,其特点如下所示: 1. 可编程收发波特率 2. 3个UART的发送FIFO以及接收FIFO共享1024*8bit RAM全双工异步通信 3. 支持输出信号波特率自动检测功能 4. 支持5、6、7、8位数据长度 5. 支持1、1.5、2、3、4位停止位长度 6. 支持奇偶校验位 7. 支持RS485协议 8. 支持IrDA协议 9. 支持DMA高速数据通信 10. 支持UART唤醒模式 11. 支持软件流控和硬件流控 UARTHS一共有1个,其特点如下所示: 1. 通讯速率可达5Mbps 2. 8字节接收和发送FIFO 3. 可编程中断模式 4. 不支持硬件流控或者其他调制解调控制信号,或异步串行数据转换器 本章实验只用到UART外设,UARTHS这里不详细介绍,感兴趣的自行了解学习。Kendryte K210官方SDK提供了多个操作UART的函数,这些函数介绍如下: 1, uart_init函数 该函数主要用于初始化UART外设,如下代码所示: void uart_init(uart_device_number_t channel) { sysctl_clock_enable(SYSCTL_CLOCK_UART1 + channel); sysctl_reset(SYSCTL_RESET_UART1 + channel); } /* uart_init 的UART功能编号 channel的配置参数 */ typedef enum _uart_device_number { UART_DEVICE_1, UART_DEVICE_2, UART_DEVICE_3, UART_DEVICE_MAX, } uart_device_number_t; 函数共有一个参数,用于选择UART的编号进行初始化,可以看到函数先使能外设时钟,然后重新复位。 2,uart_config函数 该函数用于UART的功能,该函数原型及参数描述如下所示: void uart_config(uart_device_number_t channel, uint32_t baud_rate, uart_bitwidth_t data_width, uart_stopbit_t stopbit, uart_parity_t parity); /* 数据位宽度配置参数 */ typedef enum _uart_bitwidth { UART_BITWIDTH_5BIT = 5, UART_BITWIDTH_6BIT, UART_BITWIDTH_7BIT, UART_BITWIDTH_8BIT, } uart_bitwidth_t; /* 停止位配置参数 */ typedef enum _uart_stopbit { UART_STOP_1, UART_STOP_1_5, UART_STOP_2 } uart_stopbit_t; /*奇偶校验位配置参数 */ typedef enum _uart_parity { UART_PARITY_NONE, UART_PARITY_ODD, UART_PARITY_EVEN } uart_parity_t; 函数用于设置对应串口号的波特率、数据宽度、停止位宽度、奇偶校验位,第一个参数用于选择串口号,第二个参数设置串口的波特率,后面三个参数用于设置数据格式,分别设置数据位宽度、停止位宽度和奇偶校验位。 3,uart_send_data函数 该函数用来发送数据,函数代码如下所示: int uart_send_data(uart_device_number_t channel, const char *buffer, size_t buf_len) { g_write_count = 0; while(g_write_count < buf_len) { uart_channel_putc(*buffer++, channel); g_write_count++; } return g_write_count; } 可以看到,函数共有三个参数,第一个参数用于设置发送数据的串口号,第二个参数是要发送的数据,第三个参数是设置发送数据的长度,函数会返回写入成功的字节数。 4,uart_receive_data函数 该函数用来发送数据,函数代码如下所示: int uart_receive_data(uart_device_number_t channel, char *buffer, size_t buf_len) { size_t i = 0; for(i = 0; i < buf_len; i++) { if(uart[channel]->LSR & 1) buffer = (char)(uart[channel]->RBR & 0xff); else break; } return i; } 函数共有三个参数,第一个参数用于设置接收数据的串口号,第二个参数是用于设置接收数据存放的内存地址,第三个参数是设置接收数据的长度,该函数接收一段数据后会返回收到数据的字节数,我们可以根据返回值确定字符串的大小,从而方便我们处理数据。 13.2 硬件设计 13.2.1 例程功能 1. Kendryte K210通过USB串口和上位机对话,Kendryte K210在收到上位机发过来的字符串后,会返回给上位机。同时每隔一定时间,通过USB串口输出一段信息到电脑。 13.2.2 硬件资源 1.USB接口 UARTHS_TX – IO5 UARTHS_RX – IO4 13.2.3 原理图 本章实验内容,主要讲解UART外设的使用,无需关注原理图。 13.3 程序设计 13.3.1 UART驱动代码介绍 UART源码包括两个文件:uart.c和uart.h(正点原子团队编写),我们先介绍uart.h文件的内容。 /*****************************HARDWARE-PIN*********************************/ /* 硬件IO口,与原理图对应 */ #define PIN_UART_USB_RX (4) #define PIN_UART_USB_TX (5) /*****************************SOFTWARE-GPIO********************************/ /* 软件GPIO口,与程序对应 */ #define UART_USB_NUM UART_DEVICE_3 /*****************************FUNC-GPIO************************************/ /* GPIO口的功能,绑定到硬件IO口 */ #define FUNC_UART_USB_RX (FUNC_UART1_RX + UART_USB_NUM * 2) #define FUNC_UART_USB_TX (FUNC_UART1_TX + UART_USB_NUM * 2) 这里是是硬件管脚和UART的串口号绑定,我们这里使用的是UART3。 /** * @param baudrate:波特率 * @retval 无 */ void usart_init(uint32_t baudrate) { fpioa_set_function(PIN_UART_USB_RX, FUNC_UART_USB_RX); fpioa_set_function(PIN_UART_USB_TX, FUNC_UART_USB_TX); /* 初始化串口号,设置波特率,8位数据格式,1个停止位,无奇偶校验位 */ uart_init(UART_USB_NUM); uart_configure(UART_USB_NUM, baudrate, UART_BITWIDTH_8BIT, UART_STOP_1, UART_PARITY_NONE); } 这个函数用于初始化我们UART,函数带有一个参数,用于设置波特率,串口号可以通过uart.h文件的宏定义修改,可以看到,我们先绑定硬件管脚的功能,然后初始化UART,再配置UART即可。 13.3.2 main.c代码 main.c中的代码如下所示: char recvbut[200]; int main(void) { uint16_t times = 0; uint8_t recvbut_len = 0; char *hello = {"正点原子K210 开发板\r\n"}; usart_init(115200); /* 初始化UART */ /* 开机发送正点原子K210 开发板 */ uart_send_data(UART_USB_NUM, hello, strlen(hello)); while (1) { /* 等待串口信息,并通过串口发送出去 */ recvbut_len = uart_receive_data(UART_USB_NUM, recvbut, 200); if (recvbut_len != 0) { uart_send_data(UART_USB_NUM, recvbut, recvbut_len); } else { if ((times % 30000) == 0) { uart_send_data(UART_USB_NUM, hello, strlen(hello)); times = 0; } times++; usleep(100); } } } 我们主要看到循环中的内容,先用定义的变量recvbut_len获取接收数据的长度,并将数据存放于recvbut,如果数据长度不为0(有数据),则通过串口发送收到的数据recvbut,否则,延时100us。系统每隔3秒打印输出一段信息。 13.4 运行验证 将DNK210开发板连接到电脑主机,通过VSCode将固件烧录到开发板中,我们打开“串口终端”,可以看到串口中断不断的打印数据,如下图所示: 图13.4.1 “串行终端”窗口打印输出 也可以通过串口调试助手来收发数据,我们用XCOM V2.7,该软件在光盘有提供,且无需安装,直接可以运行,但是需要你的电脑安装有.NET Framework 4.0(WIN自带了)或以上版本的环境才可以,该软件的详细介绍请看:http://www.openedv.com/posts/list/22994.htm 这个帖子。 接着我们打开XCOM V2.7,设置串口为开发板的USB转串口(CH343虚拟串口,得根据你自己的电脑选择,我的电脑是COM50,另外,请注意:波特率是115200)。XCOM的左下角提供发送新行这个选项,只要勾选了这个选项,每次发送数据后,XCOM都会自动多发一个回车换行(0X0D+0X0A)。设置好了发送新行,我们再在发送区输入你想要发送的文字,然后单击发送,可以看到输出信息,如图下图所示: 图13.4.2 串口助手 可以看到,我们发送的消息被发送回来了。大家可以试试,如果数据出现乱码,可能是串口助手编码方式不同导致的,这时我们需要重新设置XCOM的串口助手的编码方式,选择UTF-8编码,如下图所示: 图13.4.3 修改串口助手编码方式
|