K210_kendryte IDE_UART_查询法
本实验基于kendryte standalone SDK实现K210的C语言裸机开发。采用非中断的方式实现了串口的收发功能。
一、实验环境
1、软件环境:
macOS 11.4
kendryte IDE
Kendryte Standalone SDK
2、硬件环境
SIPEED M1 AI MODULE
二、功能构思
实现简单的串口输出字符串信息。采用查询方式实现串口实时接收上位机的信息,并实时回传至串口输出。
三、代码实现
1、FPIOA引脚绑定
想实现串口功能首先要定义好串口的硬件接口。由于K210支持可编程IO所以第一步根据电路设计配置好RX于TX。这里参考M1 AI MOUDLE的Datasheet使用ISP_RX与ISP_TX引脚。分别对应芯片上的IO4、IO5。
在kendryte IDE中使用FPIOA configure进行IO4、IO5引脚的绑定。如图所示。
绑定好后在fpioa-config.c中会生成如下代码段,这里我额外根据电路板上的LED绑定了三个GPIO。
#include <fpioa.h>
#include "fpioa-config.h"
int ide_config_fpioa() {
int ret = 0;
ret += fpioa_set_function(12, FUNC_GPIO0);
ret += fpioa_set_function(13, FUNC_GPIO1);
ret += fpioa_set_function(14, FUNC_GPIO2);
ret += fpioa_set_function(4, FUNC_UART1_RX);
ret += fpioa_set_function(5, FUNC_UART1_TX);
return ret;
}
2、初始化外设
(1)初始化GPIO
初始化通用GPIO(LED用)gpio_init()函数为SDK提供函数,主要用来使能GPIO的时钟。gpio_set_drive_mode()用来设置gpio的工作模式(输入、输出)gpio_set_pin()用来设置引脚的电平状态。详细用法如下所示。
函数原型
void gpio_set_drive_mode(uint8_t pin, gpio_drive_mode_t mode)
参数
参数名称 | 描述 | 输入输出 |
---|---|---|
pin | GPIO管脚 | 输入 |
mode | GPIO驱动模式 | 输入 |
mode成员:
成员名称 | 描述 |
---|---|
GPIO_DM_INPUT | 输入 |
GPIO_DM_INPUT_PULL_DOWN | 输入下拉 |
GPIO_DM_INPUT_PULL_UP | 输入上拉 |
GPIO_DM_OUTPUT | 输出 |
函数原型
void gpio_set_pin(uint8_t pin, gpio_pin_value_t value)
参数
参数名称 | 描述 | 输入输出 |
---|---|---|
pin | GPIO管脚 | 输入 |
value | GPIO值 | 输入 |
value成员:
成员名称 | 描述 |
---|---|
GPIO_PV_LOW | 低 |
GPIO_PV_HIGH | 高 |
整体GPIO初始化子程序:
void GPIO_init(void) {
gpio_init(); // enable the gpio clock
gpio_set_drive_mode(0, GPIO_DM_OUTPUT);
gpio_set_drive_mode(1, GPIO_DM_OUTPUT);
gpio_set_drive_mode(2, GPIO_DM_OUTPUT);
gpio_set_pin(0, GPIO_PV_HIGH);
gpio_set_pin(1, GPIO_PV_HIGH);
gpio_set_pin(2, GPIO_PV_HIGH);
}
(2)初始化串口
初始化串口时应初始化串口号、串口工作方式、波特率、数据位宽、停止位、校验位。分别用SDK中的以下函数实现。
函数原型
void uart_init(uart_device_number_t channel)
参数
参数名称 | 描述 | 输入输出 |
---|---|---|
channel | UART号 | 输入 |
uart号:
成员名称 | 描述 |
---|---|
UART_DEVICE_1 | UART 1 |
UART_DEVICE_2 | UART 2 |
UART_DEVICE_3 | UART 3 |
函数原型
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_BITWIDTH_5BIT | 5比特 |
UART_BITWIDTH_6BIT | 6比特 |
UART_BITWIDTH_7BIT | 7比特 |
UART_BITWIDTH_8BIT | 8比特 |
停止位宽:
成员名称 | 描述 |
---|---|
UART_STOP_1 | 1 个停止位 |
UART_STOP_1_5 | 1.5 个停止位 |
UART_STOP_2 | 2 个停止位 |
校验位:
成员名称 | 描述 |
---|---|
UART_PARITY_NONE | 无校验位 |
UART_PARITY_ODD | 奇校验 |
UART_PARITY_EVEN | 偶校验 |
函数原型
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结构体说明 | 输入 |
工作方式:
成员名称 | 描述 |
---|---|
UART_NORMAL | 普通UART |
UART_IRDA | 红外 |
UART_RS485_FULL_DUPLEX | 全双工RS485 |
UART_RS485_HALF_DUPLEX | 半双工RS485 |
整体串口初始化子程序:
void UART_init(void) {
uart_init(UART_DEVICE_1); // enable the uart device clock
uart_set_work_mode(UART_DEVICE_1, UART_NORMAL);
uart_configure(UART_DEVICE_1, 115200, UART_BITWIDTH_8BIT, UART_STOP_1,
UART_PARITY_NONE);
}
3、串口功能实现
(1)发送功能
在SDK中提供了很多串口发送的函数可以使用,包含了中断发送、发送、dma发送等函数。这里使用最简单的非中断发送函数实现简单的发送效果。函数如下。
函数原型
int uart_send_data(uart_device_number_t channel, const char *buffer, size_t buf_len)
参数
参数名称 | 描述 | 输入输出 |
---|---|---|
channel | UART 编号 | 输入 |
buffer | 待发送数据 | 输入 |
buf_len | 待发送数据的长度 | 输入 |
返回值
已发送数据的长度。
发送子程序:
void uart_send(char *tx_buffer) {
uart_send_data(UART_DEVICE_1, tx_buffer, strlen(tx_buffer));
//*tx_buffer = '1';
// uart_send_data(UART_DEVICE_1, tx_buffer, strlen(tx_buffer));
}
(2)接收功能
在SDK中同样提供了很多接收函数,包括了查询式接收、中断式接收、dma接收等函数。这里使用最简单的查询式接收来接收上位机发送的信息。所谓查询式就是CPU要一直反复的查询串口接收相关的寄存器状态,当发生了接收事件时将数据接收到相关寄存器中。其间如果CPU存在其他任务则无法第一时间接收串口数据。函数如下。
函数原型
int uart_receive_data(uart_device_number_t channel, char *buffer, size_t buf_len);
参数
参数名称 | 描述 | 输入输出 |
---|---|---|
channel | UART 编号 | 输入 |
buffer | 接收数据 | 输出 |
buf_len | 接收数据的长度 | 输入 |
返回值
已接收到的数据长度。
注意,我们可以根据接收函数的返回值来判断CPU是否完成了接收任务,从而完成之后的程序功能。
4、整体代码
#include <gpio.h>
#include <sleep.h>
#include <string.h>
#include <uart.h>
char *string = {"hello world!\n"};
char rx_buffer;
void GPIO_init(void);
void UART_init(void);
void uart_send(char *tx_buffer);
int main(void) {
GPIO_init();
UART_init();
msleep(5000);
uart_send(string);
while (1) {
if (uart_receive_data(UART_DEVICE_1, &rx_buffer, 1)) {
uart_send(&rx_buffer);
}
}
}
void GPIO_init(void) {
gpio_init(); // enable the gpio clock
gpio_set_drive_mode(0, GPIO_DM_OUTPUT);
gpio_set_drive_mode(1, GPIO_DM_OUTPUT);
gpio_set_drive_mode(2, GPIO_DM_OUTPUT);
gpio_set_pin(0, GPIO_PV_HIGH);
gpio_set_pin(1, GPIO_PV_HIGH);
gpio_set_pin(2, GPIO_PV_HIGH);
}
void UART_init(void) {
uart_init(UART_DEVICE_1); // enable the uart device clock
uart_set_work_mode(UART_DEVICE_1, UART_NORMAL);
uart_configure(UART_DEVICE_1, 115200, UART_BITWIDTH_8BIT, UART_STOP_1,
UART_PARITY_NONE);
}
void uart_send(char *tx_buffer) {
uart_send_data(UART_DEVICE_1, tx_buffer, strlen(tx_buffer));
//*tx_buffer = '1';
// uart_send_data(UART_DEVICE_1, tx_buffer, strlen(tx_buffer));
}
四、实验效果
编译以上代码,并通过k-flash下载到k210中。将串口调试助手设置为和程序中一致的参数。实验现象为:通电后5s 可以看到发送的hello world!信息。表示发送子程序成功!使用键盘输入信息发送至k210。k210能够同时将输入的信息发送到串口调试助手中,表示接收程序成功!