K210_kendryte IDE_UART_中断法

  • Post author:
  • Post category:其他




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中的以下函数实现。

特别要初始化串口中断相关配置信息

。uart_irq_register()函数实现了串口中断回调函数的注册。K210不同于stm32等mcu,官方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_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 中断优先级 输入

interrupt_mode:

成员名称 描述
UART_SEND UART 发送
UART_RECEIVE UART 接收

priority:

Each individual interrupt can have its own priority selected among 7 possible levels ( 1 is the lowest priority and 7 the highest priority).



函数原型
void uart_set_receive_trigger(uart_device_number_t channel, uart_receive_trigger_t trigger);


参数
参数名称 描述 输入输出
channel UART 编号 输入
trigger FIFO触发阈值 输入

trigger:

成员名称 描述
UART_RECEIVE_FIFO_1 FIFO 1字节
UART_RECEIVE_FIFO_4 FIFO 2字节
UART_RECEIVE_FIFO_8 FIFO 4字节
UART_RECEIVE_FIFO_14 FIFO 8字节

整体串口初始化子程序:

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);
  uart_irq_register(UART_DEVICE_1, UART_RECEIVE, uart1_receive_callback, NULL,1);  // priority 1~7 1 is the lowest
  uart_set_receive_trigger(UART_DEVICE_1, UART_RECEIVE_FIFO_1);
}



(3)初始化中断

K210要实现串口中断需要配置外部中断、以及使能总中断。分别使用plic_init()函数以及sysctl_enable_irq()函数。



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)接收功能

这里使用中断的方式来接收上位机的信息。中断方式不同于查询方式,不需要一直占用CPU,仅仅在触发中断后CPU才进入中断函数,处理中断操作,其余时间CPU可处理其他任务。因此中断可大大提升整体程序的效率。uart1_receive_callback(void *ctx)为本次使用的回调函数。在该函数中处理接收信息。

Created with Raphaël 2.2.0 开始 是否触发中断? 保存断点 中断回调函数 返回断点 主程序 yes no
int uart1_receive_callback(void *ctx) {
  while (uart_receive_data(UART_DEVICE_1, &rx_buffer, 1)) {
    uart_send(&rx_buffer);
  }
  return 0;
}



4、整体代码

#include <gpio.h>
#include <plic.h>
#include <sleep.h>
#include <stdio.h>
#include <string.h>
#include <sysctl.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 uart1_receive_callback(void *ctx);  // uart1 receive callback function
int main(void) {
  plic_init();  //初始化外部中断
  GPIO_init();
  UART_init();
  sysctl_enable_irq();  //使能中断
  msleep(5000);
  uart_send(string);
  while (1) {
    gpio_set_pin(0, GPIO_PV_LOW);
    gpio_set_pin(1, GPIO_PV_LOW);
    gpio_set_pin(2, GPIO_PV_LOW);
    msleep(1000);
    gpio_set_pin(0, GPIO_PV_HIGH);
    gpio_set_pin(1, GPIO_PV_HIGH);
    gpio_set_pin(2, GPIO_PV_HIGH);
    msleep(1000);
  }
}

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);
  uart_irq_register(UART_DEVICE_1, UART_RECEIVE, uart1_receive_callback, NULL,
                    1);  // priority 1~7 1 is the lowest
  uart_set_receive_trigger(UART_DEVICE_1, UART_RECEIVE_FIFO_1);
}

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));
}

int uart1_receive_callback(void *ctx) {
  while (uart_receive_data(UART_DEVICE_1, &rx_buffer, 1)) {
    uart_send(&rx_buffer);
  }
  return 0;
}



四、实验效果

编译以上代码,并通过k-flash下载到k210中。将串口调试助手设置为和程序中一致的参数。实验现象为:通电后5s 可以看到发送的hello world!信息。表示发送子程序成功!板上的3个LED开始持续闪烁。使用键盘输入信息发送至k210。k210能够同时将输入的信息发送到串口调试助手中,表示接收程序成功!在没有发送信息时3个LED可以一直保持闪烁状态。说明在没有产生接收中断时CPU可一直处理主函数任务。

在这里插入图片描述



版权声明:本文为weixin_44874976原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。