0、引言
本系列博客仅作为本人学习K210单片机的学习记录,主要学习其内部资源使用,作为初学者难免有错误之处,如有发现还望指出。
硬件:Sipeed Maix Dock开发板(推荐官方KD233开发板)
软件:Kendryte IDE(基于VS Code 开发)
文档:
Kendryte IDE使用手册
Standalone SDK编程指南
芯片技术规格书
SDK:
Kendryte SDK
MaixPy/drive
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiclRnblN2XjlGcjAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL9EEVPFzZU90MRRVT3V1MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLwITN4EzNwATM3ATOwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
1、UART——interrupt
以下代码为官方代码库“kendryte_uart-interrupt-standalone”修改而成,实现的功能为将电脑发送的字符串,在中断回调函数中存入缓存v_buf中,字符串接收完成后,再将v_buf中的数据上传回电脑。管脚配置如下所示
main.c
#include <fpioa.h>
#include <gpio.h>
#include <stdio.h>
#include <string.h>
#include <sysctl.h>
#include <uart.h>
//UART_NUM位于uart.h中 ,用于定义所使用的串口号
//#define UART_NUM UART_DEVICE_3
uint32_t v_uart_num = UART_NUM;
//打印字符串,通过指针
void uart_print(const char const *str) {
uart_send_data(UART_NUM, str, strlen(str));
}
//发送中断回调函数(想不到用途)
int on_uart_send(void *ctx) {
uint8_t v_uart = *((uint32_t *)ctx) + 1 + 0x30;
//注销中断函数,保证该功能单次使用,否则会陷入局部死循环。
uart_irq_unregister(UART_NUM, UART_SEND);
uart_print("Send ok Uart\n"); //测试用
uart_send_data(UART_NUM, (char *)&v_uart, 1); //标准发送程序,位于uart.c
return 0;
}
int main() {
plic_init();//中断初始化
sysctl_enable_irq();//开启系统中断
uart_init(UART_NUM); //初始化配置串口。通道3
uart_configure(UART_NUM, 115200, 8, UART_STOP_1, UART_PARITY_NONE);
//接收中断或 DMA 触发 FIFO 深度,当 FIFO 中的数据大于等于该值时触发中断或 DMA传输。
uart_set_receive_trigger(UART_NUM, UART_RECEIVE_FIFO_8);
//串口中断配置(通道、接收中断、回调函数)
uart_irq_register(UART_NUM, UART_RECEIVE, on_uart_recv, NULL, 2);
//发送中断配置
// uart_set_send_trigger(UART_NUM, UART_SEND_FIFO_0);
//当发送事件产生,触发中断及回调函数(想不到用途)
// uart_irq_register(UART_NUM, UART_SEND, on_uart_send, &v_uart_num, 2);
//发送字符串
char *hel = {"hello world!\n"};
uart_send_data(UART_NUM, hel, strlen(hel));
while (1) {
if (uart_recv_ztj) //当字符串接收完成,uart_recv_ztj置高
{
uart_send_data(UART_NUM, v_buf, uart_recv_len);//将收到的数据发送回去
uart_recv_ztj = 0;//清除标志位
}
}
}
uart.h(其他部分与官方提供的库一致,后文不再赘述)
#define BUF_LEN 200//定义接收最大长度
#define UART_NUM UART_DEVICE_3//定义使用的通道
extern char v_buf[BUF_LEN];//将缓存配置位全局变量
extern char uart_recv_ztj; //接收数据状态机
extern int uart_recv_len; //实际接收到的数据长度
void on_uart_recv(void);//中断函数,需要在uart_irq_register中配置
uart.c(可根据自己实际的报文格式,对代码进行二次修改)
char v_buf[BUF_LEN]; //接收数据缓冲区
char uart_recv_ztj = 0; //接收状态机
int uart_recv_len = 0;//实际长度
//接收中断回调参数,处理接收数据
void on_uart_recv(void) {
size_t i = 0;
for (i = 0; i < BUF_LEN; i++) {
//以下两行为官方所采用判断是否接收完成的代码,不完全理解其含义
if (uart[UART_DEVICE_3]->LSR & 1)
v_buf[i] = (char)(uart[UART_DEVICE_3]->RBR & 0xff);
else {
uart_recv_ztj = 1; //接收完成
uart_recv_len = i; //将真实长度传递
break;//跳出循环
}
}
}
测试结果如下所示
详情请参考 《Standalone SDK编程指南》——通用异步收发传输器 (UART)部分
2、UART——DMA
使用串口接收触发中断,后调用DMA收数据,再将数据发出去,其他函数看了很久,没弄得明白,在此不表。
#include <fpioa.h>
#include <gpio.h>
#include <stdio.h>
#include <string.h>
#include <sysctl.h>
#include <uart.h>
//回调函数
void ztj() {
uart_receive_data_dma(UART_NUM, DMAC_CHANNEL1, v_buf, 10);//将数据通过DMA方式接收
uart_send_data_dma(UART_NUM, DMAC_CHANNEL0, v_buf, 10);
}
int main() {
dmac_init();
plic_init(); //中断初始化
sysctl_enable_irq(); //开启系统中断
gpio_init(); //初始化GPIO
gpio_set_drive_mode(0, GPIO_DM_OUTPUT); //将GPIO 0配置为输出模型
gpio_set_pin(0, GPIO_PV_HIGH); // GPIO 0 输出高
//初始化配置串口。通道3
uart_init(UART_NUM);
uart_configure(UART_NUM, 115200, 8, UART_STOP_1, UART_PARITY_NONE);
//接收中断或 DMA 触发 FIFO 深度,当 FIFO 中的数据大于等于该值时触发中断或
// DMA传输。
// uart_set_receive_trigger(UART_NUM, UART_RECEIVE_FIFO_8);
//串口中断配置(通道、接收中断、回调函数)
uart_irq_register(UART_NUM, UART_RECEIVE, ztj, NULL, 1);
//发送字符串
char *hel = {"hello world!\n"};
// uart_send_data(UART_NUM, hel, strlen(hel));
uart_send_data_dma(UART_NUM, DMAC_CHANNEL0, hel, strlen(hel));
while (1) {
gpio_set_pin(0, 1);
msleep(2000);
gpio_set_pin(0, 0);
msleep(2000);
}
}
3、双串口使用
FPIOA很大程度方便了硬件设计,将GPIO 34/35 配置为UART1 RX/TX,GPIO 4/5 配置为UART3 RX/TX。
关于两个串口的配置也相对简单,再库函数中修改为对应的串口信道即可,详情见代码。
程序流程:使用UART3中断来接收PC下发的字符串,接收完成后用UART1再发送回PC。
main.c
#include <fpioa.h>
#include <gpio.h>
#include <stdio.h>
#include <string.h>
#include <sysctl.h>
#include <uart.h>
int main() {
plic_init(); //中断初始化
sysctl_enable_irq(); //开启系统中断
gpio_init(); //初始化GPIO
gpio_set_drive_mode(0, GPIO_DM_OUTPUT); //将GPIO 0配置为输出模型
gpio_set_pin(0, GPIO_PV_HIGH); // GPIO 0 输出高
uart_init(UART_NUM); //初始化配置串口。通道3
uart_configure(UART_NUM, 115200, 8, UART_STOP_1, UART_PARITY_NONE);
uart_init(UART_DEVICE_1); //初始化配置串口。通道1
uart_configure(UART_DEVICE_1, 115200, 8, UART_STOP_1, UART_PARITY_NONE);
//接收中断或 DMA 触发 FIFO 深度,当 FIFO 中的数据大于等于该值时触发中断或
//DMA传输。 uart_set_receive_trigger(UART_NUM, UART_RECEIVE_FIFO_8);
//串口中断配置(通道、接收中断、回调函数)
uart_irq_register(UART_NUM, UART_RECEIVE, on_uart_recv, NULL, 2);
//发送中断配置
// uart_set_send_trigger(UART_NUM, UART_SEND_FIFO_0);
//当发送事件产生,触发中断及回调函数(想不到用途)
// uart_irq_register(UART_NUM, UART_SEND, on_uart_send, &v_uart_num, 2);
//发送字符串
char *hel = {"hello world!\n"};
uart_send_data(UART_NUM, hel, strlen(hel));
while (1) {
gpio_set_pin(0, 1);
msleep(2000);
gpio_set_pin(0, 0);
msleep(2000);
}
}
uart.c
//接收中断回调参数,处理接收数据
void on_uart_recv(void) {
size_t i = 0;
for (i = 0; i < BUF_LEN; i++) {
if (uart[UART_DEVICE_3]->LSR & 1)
v_buf[i] = (char)(uart[UART_DEVICE_3]->RBR & 0xff);
else {
uart_recv_ztj = 1; //接收完成
uart_recv_len = i; //将真实长度传递
//uart_send_data(UART_NUM, v_buf, uart_recv_len);
break;
}
}
if (uart_recv_ztj) //当字符串接收完成,uart_recv_ztj置高
{
// uart_send_data(UART_NUM, v_buf, uart_recv_len); //将收到的数据发送回去
uart_send_data_dma(UART_DEVICE_1, DMAC_CHANNEL0, v_buf, uart_recv_len);//使用DMA发送数据
uart_recv_ztj = 0; //清除标志位
}
}
测试结果
参考资料
《Kendryte IDE使用手册》
《Standalone SDK编程指南》
《芯片技术规格书》
K210学习记录(1)——GPIO与软件使用