打印
[其他ST产品]

【正点原子K210连载】第十三章 UART实验《DNK210使用指南-SDK版》

[复制链接]
466|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主

第十三章 UART实验

本章将介绍Kendryte K210的UART外设。通过本章的学习,读者将学习到UART的使用。
本章分为如下几个小节:
13.1 UART介绍
13.2 硬件设计
13.3 程序设计
13.4 运行验证


13.1 UART介绍
串口通信是一种设备间常用的串行通信方式,串口按位(bit)发送和接收字节。尽管比特字节byte)的串行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。串口通信协议是指规定了数据包的内容,内容包含了起始位、主体数据、校验位及停止位,双方需要约定一致的数据包格式才能正常收发数据的有关规范。在串口通信中,常用的协议包括RS-232RS-422RS-485
随着科技的发展,RS-232在工业上还有广泛的使用,但是在商业技术上,已经慢慢的使用USB转串口取代了RS-232串口。我们只需要在电路中添加一个USB转串口芯片,就可以实现USB通信协议和标准UART串行通信协议的转换,而我们开发板上的USB转串口芯片是CH343P这个芯片。
下面我们来学习串口通信协议,这里主要学习串口通信的协议层。
串口通信的数据包由发送设备的TXD接口传输到接收设备的RXD接口。在串口通信的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据,其组成如图 13.1.1所示。
图13.1.1 串口通信协议数据帧格式
串口通信协议数据包组成可以分为波特率和数据帧格式两部分。
1. 波特率
本章主要讲解的是串口异步通信,异步通信是不需要时钟信号的,但是这里需要我们约定好两个设备的波特率。波特率表示每秒钟传送的码元符号的个数,所以它决定了数据帧里面每一个位的时间长度。两个要通信的设备的波特率一定要设置相同,我们常见的波特率是48009600115200等。
2. 数据帧格式
数据帧格式需要我们提前约定好,串口通信的数据帧包括起始位、停止位、有效数据位以及校验位。
l 起始位和停止位
串口通信的一个数据帧是从起始位开始,直到停止位。数据帧中的起始位是由一个逻辑0 的数据位表示,而数据帧的停止位可以是 0.511.52个逻辑1的数据位表示,只要双方约定一致即可。
l 有效数据位
数据帧的起始位之后,就接着是数据位,也称有效数据位,这就是我们真正需要的数据,有效数据位通常会被约定为567或者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硬件上有3UART控制器和1UARTHS控制器,它们能够灵活地与外部设备进行全双工数据交换。
UART一共有3个,其特点如下所示:
1. 可编程收发波特率
2. 3UART的发送FIFO以及接收FIFO共享1024*8bit RAM全双工异步通信
3. 支持输出信号波特率自动检测功能
4. 支持5678位数据长度
5. 支持11.5234位停止位长度
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的编号进行初始化,可以看到函数先使能外设时钟,然后重新复位。
2uart_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;
函数用于设置对应串口号的波特率、数据宽度、停止位宽度、奇偶校验位,第一个参数用于选择串口号,第二个参数设置串口的波特率,后面三个参数用于设置数据格式,分别设置数据位宽度、停止位宽度和奇偶校验位。
3uart_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;
}
可以看到,函数共有三个参数,第一个参数用于设置发送数据的串口号,第二个参数是要发送的数据,第三个参数是设置发送数据的长度,函数会返回写入成功的字节数。
4uart_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.cuart.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。
/**
* @brief   初始化USART
* @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 修改串口助手编码方式

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

93

主题

94

帖子

2

粉丝