6.3 - UART串口数据发送之中断

news/2025/2/25 7:03:07

文章目录

  • 1 实验任务
  • 2 系统框图
  • 3 软件设计

1 实验任务

本实验使用中断方式实现UART串口数据的连续发送。

2 系统框图

参见6.1。

3 软件设计

注意事项:

  1. 系统上电、程序下载后,此时TX FIFO虽然为空,但是并不会触发空中断;空中断的触发前提是FIFO中的最后一个数据被读出(这个地方调试了好久,明明使能了空中断,但是程序下载后死活都收不到中断;尝试在main函数中加入一些打印信息,反而能触发空中断,思来想去并结合文档关于空中断状态位的描述,发现必须先写入数据);
  2. 对于XUartPs_Send函数
    • (1) 禁用发送相关中断(TXFULL和TXEMPTY)
    • (2) 使用XUartPs_SendBuffer函数向TX FIFO中写入数据
    • (3) XUartPs_SendBuffer会使能TXEMPTY中断,但是有个前提,必须使能了RX FIFO相关中断(RXFULL、RXEMPTY或RXOVR)(这个地方同样调试了好久,至今仍未明白原因)
    • (4) 返回实际写入的个数
  3. 有个小技巧,在程序下载后,假设上一次数据已发送完毕,SendComplete置1,并将每一轮的首次数据发送放在while循环中,这样TxBuffer中的数据才能一轮一轮的循环发送起来(刚开始把首次数据发送放在while循环外边,在第一轮的最后一次数据发送完毕并触发空中断后,SendComplete置1,然后就没有然后了…)。
/************************** Include Files ***********************************/
#include "xparameters.h"
#include "xuartps.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "stdio.h"
#include "sleep.h"

/************************** Constant Definitions ****************************/
#define UART_DEVICE_ID		XPAR_XUARTPS_0_DEVICE_ID
#define INTC_DEVICE_ID		XPAR_SCUGIC_SINGLE_DEVICE_ID
#define UART_INTR_ID		XPAR_XUARTPS_1_INTR

#define BUFFER_SIZE 		256  // 发送缓冲区大小
#define FIFO_TRIGGER_LEVEL  32   // FIFO触发阈值
#define RECV_TIMEOUT        4    // 接收超时时间(单位:波特率时钟周期)

/************************** Function Prototypes *****************************/
s32  UartPsInit(XUartPs *UartPsInstPtr, XUartPsFormat* UartFormatPtr);
s32  SetupInterruptSystem(XScuGic *IntcInstPtr, XUartPs *UartPsInstPtr);
void UartIntrHandler(void *CallBackRef);

/************************** Variable Definitions ****************************/
XUartPs UartInst;
XScuGic IntcInst;

u8 TxBuffer[BUFFER_SIZE] = { 0 };  // 接收缓冲区

int RxDataLength = 0;  // 接收到的数据长度

XUartPsFormat UartFormat = {
		XUARTPS_DFT_BAUDRATE,     // 115200
		XUARTPS_FORMAT_8_BITS,
		XUARTPS_FORMAT_NO_PARITY,
		XUARTPS_FORMAT_1_STOP_BIT
};

// 发送状态
u32 TotalBytesSent;  // 已发送的字节数
int SendComplete;    // 发送完成标志
/************************** Function Implementation *************************/

int main()
{
	//
	s32 Status;
	u32 BytesSent;
	//
    for (int i = 0; i < BUFFER_SIZE; i++) {
    	TxBuffer[i] = (u8)i;  // 填充从 0 开始的递增数
    }
	// 初始化UART
	Status = UartPsInit(&UartInst, &UartFormat);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	// 设置中断系统
	Status = SetupInterruptSystem(&IntcInst, &UartInst);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	// 主循环
	SendComplete = 1;
	while(1)
	{
		if (SendComplete == 1) {
			TotalBytesSent = 0;
			SendComplete = 0;
			sleep(3);
		    // 启动第一次发送
		    BytesSent = XUartPs_Send(&UartInst, TxBuffer, BUFFER_SIZE);
		    TotalBytesSent += BytesSent;
		}
	}
	//
	return 0;
}

s32 UartPsInit(XUartPs *UartInstPtr, XUartPsFormat* UartFormatPtr)
{
	//
	s32 Status;
	XUartPs_Config *UartConfigPtr;
	// 查找UART配置
	UartConfigPtr = XUartPs_LookupConfig(UART_DEVICE_ID);
	if(NULL == UartConfigPtr)
	{
		return XST_FAILURE;
	}
	// 初始化UART
	Status = XUartPs_CfgInitialize(UartInstPtr, UartConfigPtr, UartConfigPtr->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	// 设置UART数据格式
	XUartPs_SetDataFormat(UartInstPtr, UartFormatPtr);
	// 设置UART操作模式
	XUartPs_SetOperMode(UartInstPtr, XUARTPS_OPER_MODE_NORMAL);
	// 设置接收FIFO触发阈值
	XUartPs_SetFifoThreshold(UartInstPtr, FIFO_TRIGGER_LEVEL);
	// 设置接收超时
	XUartPs_SetRecvTimeout(UartInstPtr, RECV_TIMEOUT);
	// 设置中断掩码,使能发送FIFO空中断
	XUartPs_SetInterruptMask(UartInstPtr, XUARTPS_IXR_RXOVR | XUARTPS_IXR_TXEMPTY);
	//
	return XST_SUCCESS;
}

s32 SetupInterruptSystem(XScuGic *IntcInstPtr, XUartPs *UartInstPtr)
{
	//
	s32 Status;
	XScuGic_Config *IntcConfigPtr;
	// 初始化中断控制器GIC
	IntcConfigPtr = XScuGic_LookupConfig(INTC_DEVICE_ID);
	if (NULL == IntcConfigPtr)
	{
		return XST_FAILURE;
	}

	Status = XScuGic_CfgInitialize(IntcInstPtr, IntcConfigPtr, IntcConfigPtr->CpuBaseAddress);
	if (Status != XST_SUCCESS)
	{
		return XST_FAILURE;
	}
	// 注册异常处理程序
	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, IntcInstPtr);
	Xil_ExceptionEnable();
	// 连接UART中断处理程序
	XScuGic_Connect(IntcInstPtr, UART_INTR_ID, (Xil_InterruptHandler)UartIntrHandler, (void *)UartInstPtr);
	// 使能UART中断
	XScuGic_Enable(IntcInstPtr, UART_INTR_ID);
	//
	return XST_SUCCESS;
}

void UartIntrHandler(void *CallBackRef)
{
	//
	XUartPs* UartInstPtr = (XUartPs*)CallBackRef;
	u32 IsrStatus;
	// 读取中断状态
	IsrStatus = XUartPs_ReadReg(UartInstPtr->Config.BaseAddress, XUARTPS_IMR_OFFSET);
	IsrStatus &= XUartPs_ReadReg(UartInstPtr->Config.BaseAddress, XUARTPS_ISR_OFFSET);
	// 处理发送FIFO空中断
	if ((IsrStatus & (u32)XUARTPS_IXR_TXEMPTY) != (u32)0) {
		XUartPs_WriteReg(UartInstPtr->Config.BaseAddress, XUARTPS_ISR_OFFSET, XUARTPS_IXR_TXEMPTY);
		if (TotalBytesSent < BUFFER_SIZE) {
			// 继续发送剩余的数据
			u32 BytesSent = XUartPs_Send(UartInstPtr, &TxBuffer[TotalBytesSent], BUFFER_SIZE - TotalBytesSent);
			TotalBytesSent += BytesSent;
		}
		else {
			// 所有数据已发送完毕
			SendComplete = 1;
//			xil_printf("Config file sent successfully in polled mode!\n");
		}
	}
	//
	return;
}

http://www.niftyadmin.cn/n/5865132.html

相关文章

【高速公路——Tarjan】

题目 BFS暴力代码 60p #include <bits/stdc.h> using namespace std;const int N 1010; const int M 10010; int g[N][N]; int n, m; int h[N], e[M], ne[M], idx;void add(int a, int b) // 添加一条边a->b {e[idx] b, ne[idx] h[a], h[a] idx ; }void bfs(i…

vue2版本elementUI的table分页实现多选逻辑

1. 需求 我们需要在表格页上实现多选要求&#xff0c;该表格支持分页逻辑。 2. 认识属性 表格属性 参数说明类型可选值默认值data显示的数据array——row-key行数据的 Key&#xff0c;用来优化 Table 的渲染&#xff1b;在使用 reserve-selection 功能与显示树形数据时&…

UE5 Gameplay框架及继承关系详解

文章目录 前言一、核心类及其继承关系二、核心类的职责与协作2.1 Actor & Pawn2.2 Controller2.3 GameMode & GameState2.4 PlayerState2.5 HUD & UI 三、协作流程示例总结 前言 Unreal Engine 5&#xff08;UE5&#xff09;的 Gameplay 框架 是一个高度模块化的系…

OpenCV计算摄影学(1)图像修复(Inpainting)的函数inpaint()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 使用图像中选定区域的邻域来恢复该选定区域。 cv::inpaint 函数是 OpenCV 中用于图像修复&#xff08;Inpainting&#xff09;的一个重要函数。它…

Kafka面试题----Kafka是如何保证顺序消费的

在 Kafka 中&#xff0c;默认情况下消息是按分区进行顺序存储和读取的&#xff0c;但全局顺序消费&#xff08;即所有分区的消息按顺序消费&#xff09;较难实现。下面分别介绍 Kafka 按分区顺序消费以及实现全局顺序消费的相关内容。 按分区顺序消费 Kafka 本身可以保证单个…

机器人“战场”:创新、落地与未来

从1999年的机器管家&#xff0c;2001年的机器人小孩大卫&#xff0c;到2015年拥有自我意识的“查派”&#xff0c;在科幻电影里&#xff0c;人们赋予了对机器人的各种形象和想象。2018年&#xff0c;尽管只是实验室的试验品&#xff0c;但波士顿动力机器狗Spot的视频还是在国内…

python 判断 字符串在字典列表中

在Python中&#xff0c;如果你想判断一个字符串是否存在于一个字典列表中&#xff0c;你可以通过遍历这个列表并检查每个字典是否包含你想要找的字符串键来实现。这里有几种方法可以做到这一点&#xff1a; 方法1&#xff1a;使用any()函数 你可以使用any()函数和字典的get方法…

【MySQL】第九弹---掌握SQL关键操作:更新、删除、插入与聚合分析的秘诀

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【MySQL】 目录 1 Update 2 Delete 2.1 删除数据 2.2 截断表 3 插入查询结果 4 聚合函数 5 group by子句的使用 1 Update 语法…