华大HC32F4A0/F460串口裸机驱动

使用了DMA以及中断,测试比较简单,代码是F460上面用的,今天试了F4A0也可以直接用,需要提前初始化DMA,INT,以及IO复用功能;

/*************************************************************************************************************
 * 文件名:			uart.c
 * 功能:			HC32F4A0 UART通讯支持
 * 作者:			cp1300@139.com
 * 创建时间:		2021-11-19
 * 最后修改时间:	2021-11-19
 * 详细:			2021-09-12:修复设置串口传输位数bug,正常要设置CR1 BIT12位为0
*************************************************************************************************************/
#include "hc32f4a0_system.h"
#include "uart.h"
#include "typedef.h"

//串口中断接收函数
#if !UART_DMA_EN
__inline static void UARTx_IRQHandler(UART_CH_Type ch);				//串口中断处理
static void UART1_RX_IRQHandler(void) {UARTx_IRQHandler(UART_CH1);}	//串口1接收中断服务程序
static void UART2_RX_IRQHandler(void) {UARTx_IRQHandler(UART_CH2);}	//串口2接收中断服务程序
static void UART3_RX_IRQHandler(void) {UARTx_IRQHandler(UART_CH3);}	//串口3接收中断服务程序
static void UART4_RX_IRQHandler(void) {UARTx_IRQHandler(UART_CH4);}	//串口4接收中断服务程序


//中断函数集合	
static const void *scg_pUartIrqHandle[UART_ChMax] = 
{(const void *)UART1_RX_IRQHandler, 	(const void *)UART2_RX_IRQHandler, 	(const void *)UART3_RX_IRQHandler,  (const void *)UART4_RX_IRQHandler};

//串口中断所占用的中断线
static const IRQn_Type scg_UartIrqType[UART_ChMax] = 
{SYS_IRQ_UART1_RX_NUM, 	SYS_IRQ_UART2_RX_NUM, 	SYS_IRQ_UART3_RX_NUM, 	SYS_IRQ_UART4_RX_NUM};	
	
//串口中断源
static const INT_SOURCE_TYPE scg_UartIntSourceType[UART_ChMax] = 
{SYS_INT_USART1_RI, 	SYS_INT_USART2_RI, 	SYS_INT_USART3_RI, 	SYS_INT_USART4_RI};		
#endif //UART_DMA_EN

//时钟使能	
static const SYS_DEV_CLOCK scg_UARTx_DeviceClockEnable[UART_ChMax] 	= 
{DEV_USART1, 	DEV_USART2, 	DEV_USART3, 	DEV_USART4};	
//串口基址	
static const u32 scg_UARTx_Base[UART_ChMax] = {UART1_BASE, UART2_BASE, UART3_BASE, UART4_BASE};	

//DAM通道设置
#if UART_DMA_EN
#include "dma.h"
static const DMAx_CH_TYPE scg_UART_RxDMAChannel[4] = {DMA2_CH1, DMA2_CH2, DMA2_CH3,DMA2_CH4};	//接收通道
static const u32 scg_UART_RX_DR_ADDR[4] = {UART1_BASE + 0x04 + 2, UART2_BASE + 0x04 + 2, UART3_BASE + 0x04 + 2, UART4_BASE + 0x04 + 2};	//UART接收寄存器地址
static const u32 scg_UART_TX_DR_ADDR[4] = {UART1_BASE + 0x04 + 0, UART2_BASE + 0x04 + 0, UART3_BASE + 0x04 + 0, UART4_BASE + 0x04 + 0};	//UART发送寄存器地址
static const INT_SOURCE_TYPE scg_UART_Rx_DMA_Trigger[4] = {SYS_INT_USART1_RI, SYS_INT_USART2_RI, SYS_INT_USART3_RI, SYS_INT_USART4_RI};	//UART接收DMA触发源
static const INT_SOURCE_TYPE scg_UART_Tx_DMA_Trigger[4] = {SYS_INT_USART1_TI, SYS_INT_USART2_TI, SYS_INT_USART3_TI, SYS_INT_USART4_TI};	//UART发送DMA触发源
#endif	//UART_DMA_EN



//相关UART状态结构
typedef struct
{
	bool		isNewDataFlag;	//接收到新数据
	bool		isBuffFull;		//接收Buff满
	bool		isIntRx;		//是否开启中断接收
	u8 			*RxBuff;		//接收Buff指针
	u16			RxBuffSize;		//接收缓冲区大小,一帧数据大小
	u16 		UartRxCnt;		//接收数据计数器
	u8			TempData;		//用于接收溢出后读取数据寄存器,清除读取数据标志
} UartRx_TypeDef;
static UartRx_TypeDef sg_UartRx[UART_ChMax];

/*************************************************************************************************************************
*函数        	:	bool UARTx_Config(UART_CH_Type ch,UART_Config_TypeDef * cfg)
*功能        	:	串口配置
*参数        	:	ch:串口号;cfg:配置结构体
*返回        	:	TRUE:配置成功; FALSE: 配置失败
*依赖			: 	底层宏定义
*作者       	:	cp1300@139.com
*时间     		:	2021-11-19
*最后修改时间	:	2021-11-19
*说明        	:	配置前最好确保数据已经发送完成,没有数据正在发送
*************************************************************************************************************************/
bool UARTx_Config(UART_CH_Type ch,UART_Config_TypeDef * cfg)
{
	u32 temp;
	UART_TypeDef *UARTx;
	
	if(ch > (UART_ChMax - 1)) return FALSE;							//端口号超出范围
	UARTx = (UART_TypeDef *) scg_UARTx_Base[ch];					//获取设备基址
	
	temp = UARTx->CR1;
	//奇偶校验
	switch(cfg->OddEvenVerify)	
	{
		case UART_ODD:	//奇校验
		{
			temp |= BIT10;	//开启校验
			temp |= BIT9;	//奇校验
		}break;
		case UART_EVEN:	//偶校验
		{
			temp |= BIT10;	//开启校验
			temp &= ~BIT9;	//偶校验
		}break;
		default://无校验
		{
			temp &= ~BIT10;	//关闭校验
		}break;	
	}
	//数据长度
	if(cfg->DataBitWidth == UART_DATA_8BIT)	//数据位长度设置8bit
	{
		temp &= ~BIT12;
	}
	else
	{
		temp |= BIT12;
	}
	UARTx->CR1 = temp;
	
	//停止位
	temp = UARTx->CR2;
	if(cfg->StopBitWidth != UART_STOP_1BIT)	//不止1个停止位
	{
		temp |= BIT13;	//2个停止位
	}
	else
	{
		temp &= ~BIT13;	//1个停止位
	}
	UARTx->CR2 = temp;

	return TRUE;
}



/*************************************************************************************************************************
* 函数			:	void UARTx_SetBaudRate(UART_CH_Type ch,u32 baud)
* 功能			:	串口波特率设置
* 参数			:	ch:通道选择,baud:波特率,如9600,115200等等
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	cp1300@139.com
* 时间			:	2021-11-19
* 最后修改时间 	: 	2021-11-19
* 说明			: 	注意 DIV_Integer[7:0]只能 在 TE=0&RE=0(发送 /接收 禁止 )时设定
					DIV_Fraction[6:0]只能 在 TE=0&RE=0(发送 /接收 禁止 )时设定, 而且仅在 FBME=1时设定值 有效
*************************************************************************************************************************/
bool UARTx_SetBaudRate(UART_CH_Type ch,u32 baud)
{
	u8 Integer;
	u8 Fraction;
	UART_TypeDef *UARTx;
	float ftemp;
	u32 temp;	//PCLK频率
	
	if(ch > (UART_ChMax - 1)) return FALSE;			//端口号超出范围
	UARTx = (UART_TypeDef *) scg_UARTx_Base[ch];	//获取设备基址
	temp = SYS_GetPCLK1Speed();						//获取PCLK1时钟速度
	
	ftemp = (double)temp/(8*baud);
	if(ftemp < 1 || ftemp >= 256) return FALSE;		//时钟范围错误
	Integer = ftemp;	//整数分频
	
	//计算实际的波特率,由于整数分频存在误差,最终波特率只会偏大,不会偏小
	temp /= 8;
	temp /= Integer;
	//计算需要的波特率与实际波特率比值
	ftemp = baud;	//用目标波特率除以实际波特率,得到偏差比值,这个比值只会小于1,并且会接近1
	ftemp /= temp;	//得到了比值乘以256 - 128 就是最终的小数补偿值
	ftemp *= 256.0f;
	ftemp -= 128.0f;
	
	Integer -= 1;		//实际整数分频-1
	//小数分频计算
	if(ftemp < 1)
	{
		ftemp = 0;
		UARTx->CR1 &= ~BIT29;	//FBME=0关闭小数波特率功能
	}
	else
	{
		UARTx->CR1 |= BIT29;	//FBME=1使能小数波特率功能
	}
	Fraction = ftemp;			//计算得到最终的小数分频
	
	temp = Integer;
	temp <<= 8;
	temp |= Fraction&0x7F;
	
	UARTx->PR = 0;				//预分频寄存器为0
	UARTx->BRR = temp;

	return TRUE;
}


/*************************************************************************************************************************
* 函数			:	bool UARTx_Init(UART_CH_Type ch,u32 Speed,bool isEnableRx)
* 功能			:	串口初始化
* 参数			:	ch:通道选择,0->usart1,Speed:串口速度,isEnableRx:是否使能接收
* 返回			:	TRUE:成功,FALSE:失败
* 依赖			:	底层宏定义
* 作者			:	cp1300@139.com
* 时间			:	2021-11-19
* 最后修改时间 	: 	2021-06-23
* 说明			: 	
*************************************************************************************************************************/
bool UARTx_Init(UART_CH_Type ch,u32 Speed,bool isEnableRx)
{
	UART_Config_TypeDef cfg;
	UART_TypeDef *UARTx;

	if(ch > (UART_ChMax - 1)) return FALSE;							//端口号超出范围
	UARTx = (UART_TypeDef *) scg_UARTx_Base[ch];					//获取设备基址
	
	SYS_DeviceClockEnable(scg_UARTx_DeviceClockEnable[ch], TRUE);		//外设时钟使能或关闭控制

	UARTx->CR1 = 0xFFFFFFF3ul;
    UARTx->CR1 = 0x80000000ul;
	
	UARTx->CR1 = 0;													//控制器寄存器复位
	UARTx->CR2 = 0;
	UARTx->CR3 = 0;
	
	UARTx->CR1 |= BIT31;	//检测方式为RX下降沿
	//UARTx->CR1 |= BIT30;	//使能数字滤波
	UARTx->CR1 |= BIT20|BIT19|BIT17|BIT16;	//清除各种标志
	UARTx->CR1 |= BIT15;	//过采样为8位

	//配置
	cfg.DataBitWidth = UART_DATA_8BIT;								//数据宽度8
	cfg.OddEvenVerify = UART_VERIFY_NULL;							//无奇偶校验
	cfg.StopBitWidth = UART_STOP_1BIT;								//1个停止位
	if(UARTx_SetBaudRate(ch, Speed) == FALSE) return FALSE;			//设置波特率
	if(UARTx_Config(ch, &cfg) == FALSE) return FALSE;				//设置串口数据格式
	sg_UartRx[ch].isIntRx = FALSE;									//没有开启中断接收

	//IO初始化
	
	//使能了接收
	if(isEnableRx)
	{
#if(UART_DMA_EN)
		UARTx->CR1 |= BIT2;	//接收使能
#else //中断方式		
		UARTx->CR1 |= BIT5;	//接收中断使能
		INTC_RegisterIRQHandler(scg_UartIrqType[ch], scg_UartIntSourceType[ch], (void (*)(void))scg_pUartIrqHandle[ch]);//注册中断服务程序
		NVIC_ClearPendingIRQ(scg_UartIrqType[ch]);
		NVIC_SetPriority(scg_UartIrqType[ch], UART_INT_PRIO);
		NVIC_EnableIRQ(scg_UartIrqType[ch]);
		
		UARTx->CR1 |= BIT2;	//接收使能
#endif //UART_DMA_EN
		
		sg_UartRx[ch].isIntRx = TRUE;											//开启了接收
	}
	//发送使能
	UARTx->CR1 |= BIT3;

	return TRUE;
}


/*************************************************************************************************************************
* 函数			:	void UARTx_SendByte(UART_CH_Type ch,u8 data)
* 功能			:	UART单字节发送
* 参数			:	ch:通道号,dataL:要发送的数据
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	cp1300@139.com
* 时间			:	2021-11-19
* 最后修改时间 	: 	2021-11-19
* 说明			: 	单字节发送不要使用DMA,浪费
					2021-07-28:解决不能while空循环,V6编译器会优化掉问题,后面加个nop即可;
*************************************************************************************************************************/
void UARTx_SendByte(UART_CH_Type ch,u8 data)
{
	UART_TypeDef *UARTx;
	
	if(ch > (UART_ChMax - 1)) return;						//端口号超出范围
	UARTx = (UART_TypeDef *) scg_UARTx_Base[ch];			//获取设备基址
	while((UARTx->SR & BIT7)==0) nop;						//等待TX发送寄存器为空
 	UARTx->DR = data;										//发送数据-写到带发送寄存器,并不会等待数据发送完成
}




/*************************************************************************************************************************
* 函数			:	void UARTx_SendData(UART_CH_Type ch,u8 *tx_buff,u16 byte_number)
* 功能			:	UART数据发送函数
* 参数			:	ch:通道号,tx_buff:发送缓冲区,byte_number:需要发送的字节
* 返回			:	无
* 依赖			:	void UART_SendByte(u8 ch,u8 data)
* 作者			:	cp1300@139.com
* 时间			:	2021-11-19
* 最后修改时间 	: 	2021-11-19
* 说明			: 	
*************************************************************************************************************************/
void UARTx_SendData(UART_CH_Type ch,u8 *pTxBuff,u16 DataLen)
{
	u16 i;
#if(UART_DMA_EN) //使能DMA发送	
	int dma_ch;
	UART_TypeDef *UARTx;
	bool isNotDMA = FALSE;
#endif 
	
	if(ch > (UART_ChMax - 1)) return;						//端口号超出范围
	
#if(UART_DMA_EN) //使能DMA发送
	UARTx = (UART_TypeDef *) scg_UARTx_Base[ch];			//获取设备基址

	
	dma_ch = DMA_GetIdleChannel();//获取一个DMA空闲通道(用完后需要释放)
	//uart_printf("dma_ch=%d\r\n", dma_ch);
	if(dma_ch < 0)	//DMA获取失败,直接用字节发送
	{
		isNotDMA = TRUE;
	}
	else //DMA发送
	{
		if(DataLen < UART_DMA_TX_MIN) 
		{
			isNotDMA = TRUE;
		}
		else //DMA发送
		{
			while((UARTx->SR & BIT7)==0);							//等待TX发送寄存器为空
			DMA_MemoryToPeripheralConfig((DMAx_CH_TYPE) dma_ch, (u32)&pTxBuff[1], scg_UART_TX_DR_ADDR[ch], DMA_SIZE_8BIT,  DataLen-1, scg_UART_Tx_DMA_Trigger[ch], TRUE);//DMA存储器到外设传输配置
			UARTx_SendByte(ch, pTxBuff[0]);							//初始化DMA后不会被触发发送,只有先发送一条数据,让发送寄存器空从无效变为有效,之后就会触发DMA发送
			if(DMA_WaitMemComplete((DMAx_CH_TYPE) dma_ch, (u32)DataLen*2) == FALSE)		//等待存储器DMA传输完成
			{
				u16 cnt = DMA_GetCompleteResidualCnt((DMAx_CH_TYPE) dma_ch);
				DEBUG("dma_ch=%d 发送超时 cnt=%d\r\n",dma_ch, cnt);
				DMA_StopTrans((DMAx_CH_TYPE) dma_ch);								//传输超时,强制关闭 DMA 传输
			}
			DMA_ReleaseChannel(dma_ch);//释放当前使用的通道
		}	
	}
	
	if(isNotDMA)	//不需要用DMA发送
	{
		for(i = 0;i < DataLen;i++)							//循环发送,直至发送完毕
		{
			UARTx_SendByte(ch, pTxBuff[i]);
		}
	}
	
	
#else 	
	
	for(i = 0;i < DataLen;i++)							//循环发送,直至发送完毕
	{
	 	UARTx_SendByte(ch, pTxBuff[i]);
	}

#endif //UART_DMA_EN

#if (!UART_TX_TO_FIFI)	//要求等待数据发送完成
	UARTx_WaitSendComplete(ch);				//等待数据发送完成-从串口发送完成
#endif //UART_TX_TO_FIFI		
}


/*************************************************************************************************************************
* 函数			:	void UARTx_WaitSendComplete(UART_CH_Type ch)
* 功能			:	等待数据发送完成-从串口发送完成
* 参数			:	ch:通道号
* 返回			:	无
* 依赖			:	无
* 作者			:	cp1300@139.com
* 时间			:	2021-11-19
* 最后修改时间 	: 	2021-11-19
* 说明			:
*************************************************************************************************************************/
void UARTx_WaitSendComplete(UART_CH_Type ch)
{
	UART_TypeDef *UARTx;
	
	if(ch > (UART_ChMax - 1)) return;						//端口号超出范围
	UARTx = (UART_TypeDef *) scg_UARTx_Base[ch];			//获取设备基址
	while((UARTx->SR & BIT6) == 0)							//等待发送完成
	{
		SYS_DelayMS(1);
	}
}


/*************************************************************************************************************************
* 函数			:	void UARTx_SendString(UART_CH_Type ch,char *pString)
* 功能			:	UART发送字符串
* 参数			:	ch:通道号
					pString:字符串指针
* 返回			:	无
* 依赖			:	void UART_SendByte(u8 ch,u8 data)
* 作者			:	cp1300@139.com
* 时间			:	2021-11-19
* 最后修改时间 	: 	2021-11-19
* 说明			: 	
*************************************************************************************************************************/
#include "string.h"
void UARTx_SendString(UART_CH_Type ch,char *pString)
{	
	if(ch > (UART_ChMax - 1)) return;					//端口号超出范围
	
	UARTx_SendData(ch, (u8 *)pString, strlen(pString));
}


/*************************************************************************************************************************
* 函数			:	bool UARTx_GetNewDataFlag(UART_CH_Type ch)
* 功能			:	获取串口新数据标志
* 参数			:	ch:通道选择
* 返回			:	TRUE:成功,FALSE:失败
* 依赖			:	底层宏定义
* 作者			:	cp1300@139.com
* 时间			:	2021-11-19
* 最后修改时间 	: 	2021-11-19
* 说明			: 	用于判断是否有新的数据,会清除掉新数据标志的
*************************************************************************************************************************/
bool UARTx_GetNewDataFlag(UART_CH_Type ch)
{
	UART_TypeDef *UARTx;
	
	if(ch > (UART_ChMax - 1)) return FALSE;						//端口号超出范围
	UARTx = (UART_TypeDef *) scg_UARTx_Base[ch];				//获取设备基址

	if(sg_UartRx[ch].isIntRx == TRUE)							//开启了中断接收
	{
		if(sg_UartRx[ch].isNewDataFlag == TRUE) 				//有新数据
		{
		 	sg_UartRx[ch].isNewDataFlag = FALSE;				//清除标志
			return TRUE;										//返回有新数据
		}
	}
	else														//没开启中断接收
	{
	 	if((UARTx->SR & BIT5) == 0)							//接收FIFO不为空
		{
			return TRUE;
		}
	}
	return FALSE;
}


/*************************************************************************************************************************
* 函数			:	bool UARTx_GetRxBuffFullFlag(UART_CH_Type ch)
* 功能			:	获取串口接收缓冲区满标志
* 参数			:	ch:通道选择
* 返回			:	TRUE:成功,FALSE:失败
* 依赖			:	底层宏定义
* 作者			:	cp1300@139.com
* 时间			:	2021-11-19
* 最后修改时间 	: 	2021-11-19
* 说明			: 	用于判断接收缓冲区是否满,会清除标志
*************************************************************************************************************************/
bool UARTx_GetRxBuffFullFlag(UART_CH_Type ch)
{
	if(ch > (UART_ChMax - 1)) return FALSE;					//端口号超出范围

	if(sg_UartRx[ch].isBuffFull == TRUE)			//缓冲区已满
	{
	 	sg_UartRx[ch].isBuffFull = FALSE;			//清除满标志
		return TRUE;
	}
	return FALSE;
}


/*************************************************************************************************************************
* 函数			:	u8 UARTx_GetNewData(UART_CH_Type ch)
* 功能			:	获取串口新数据
* 参数			:	ch:通道选择
* 返回			:	收到的数据
* 依赖			:	底层宏定义
* 作者			:	cp1300@139.com
* 时间			:	2021-11-19
* 最后修改时间 	: 	2021-11-19
* 说明			: 	用于接收一个字节数据
*************************************************************************************************************************/
u8 UARTx_GetNewData(UART_CH_Type ch)
{
	UART_TypeDef *UARTx;
	
	if(ch > (UART_ChMax - 1)) return FALSE;						//端口号超出范围
	UARTx = (UART_TypeDef *) scg_UARTx_Base[ch];				//获取设备基址

	return UARTx->DR >> 16;										//返回数据
}


/*************************************************************************************************************************
* 函数			:	void UARTx_SetRxBuff(UART_CH_Type ch,u8 *RxBuff,u16 RxBuffSize)
* 功能			:	设置串口接收缓冲区
* 参数			:	ch:通道选择,RxBuffSize:缓冲区大小,RxBuff:缓冲区指针
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	cp1300@139.com
* 时间			:	2021-11-19
* 最后修改时间 	: 	2021-11-19
* 说明			: 	一定要设置,否则开启中断接收时可能会异常
*************************************************************************************************************************/
void UARTx_SetRxBuff(UART_CH_Type ch,u8 *RxBuff,u16 RxBuffSize)
{
	#ifdef _UCOS_II_
		OS_CPU_SR  cpu_sr;
	#endif	//_UCOS_II_
		
		if(ch > UART_ChMax - 1)						//判断端口是否超出范围
			return;
		
	#if UART_DMA_EN
		DMA_PeripheralToMemoryConfig(scg_UART_RxDMAChannel[ch], (u32)RxBuff, scg_UART_RX_DR_ADDR[ch], DMA_SIZE_8BIT, RxBuffSize, scg_UART_Rx_DMA_Trigger[ch], TRUE);	//DMA外设到存储器传输配置
	#endif //UART_DMA_EN
		
	#ifdef _UCOS_II_
		OS_ENTER_CRITICAL();
	#endif	//_UCOS_II_
		sg_UartRx[ch].RxBuffSize = RxBuffSize; 		//设置缓冲区大小
		sg_UartRx[ch].RxBuff = RxBuff;					//设置缓冲区指针
	#if !UART_DMA_EN		
		sg_UartRx[ch].UartRxCnt = 0;					//计数器清零
	#endif //!UART_DMA_EN
	#ifdef _UCOS_II_
		OS_EXIT_CRITICAL();
	#endif	//_UCOS_II_	
}





/*************************************************************************************************************************
* 函数			:	u32 UARTx_GetRxCnt(UART_CH_Type ch)
* 功能			:	获取串口接收数据计数器
* 参数			:	ch:通道选择
* 返回			:	接收到的数据数量
* 依赖			:	底层宏定义
* 作者			:	cp1300@139.com
* 时间			:	2021-11-19
* 最后修改时间 	: 	2021-11-19
* 说明			: 	无
*************************************************************************************************************************/
u32 UARTx_GetRxCnt(UART_CH_Type ch)
{	
	if(ch > (UART_ChMax - 1)) return 0;					//端口号超出范围
	
#if UART_DMA_EN
	return  sg_UartRx[ch].RxBuffSize - DMA_GetCompleteResidualCnt(scg_UART_RxDMAChannel[ch]);
#else
	return sg_UartRx[ch].UartRxCnt;			//返回计数值	
#endif //UART_DMA_EN
}


/*************************************************************************************************************************
* 函数			:	void UARTx_ClearRxCnt(UART_CH_Type ch)
* 功能			:	清除串口接收数据计数器
* 参数			:	ch:通道选择
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	cp1300@139.com
* 时间			:	2021-11-19
* 最后修改时间 	: 	2021-11-19
* 说明			: 	无
*************************************************************************************************************************/
void UARTx_ClearRxCnt(UART_CH_Type ch)
{
#if UART_DMA_EN	
	UART_TypeDef *UARTx;
#endif //UART_DMA_EN
	
	if(ch > (UART_ChMax - 1)) return;							//端口号超出范围
	
#if UART_DMA_EN
	UARTx = (UART_TypeDef *) scg_UARTx_Base[ch];					//获取设备基址
	DMA_StartTrans(scg_UART_RxDMAChannel[ch],  scg_UART_RX_DR_ADDR[ch], (u32)sg_UartRx[ch].RxBuff, sg_UartRx[ch].RxBuffSize);	
	UARTx->CR1 |= 0x1B << 16;						//清除中断标志
	{
		u8 temp = UARTx->DR>>16;					//取出读到的数据
		temp = temp;
	}
	
#else
	sg_UartRx[ch].UartRxCnt = 0;				//计数器清零
#endif //UART_DMA_EN
}


#if !UART_DMA_EN
//用于串口中断中读取数据
__inline static void UARTx_ReadRxData(UART_CH_Type ch, UART_TypeDef *UARTx)
{
    //while(UARTx->SR & BIT5) 																				//接收FIFO中有数据,循环读取
    {
        if((sg_UartRx[ch].RxBuffSize) > 0 && (sg_UartRx[ch].UartRxCnt < sg_UartRx[ch].RxBuffSize))			//接收缓冲区大于0,并且没有满
        {
            (sg_UartRx[ch].RxBuff)[(sg_UartRx[ch].UartRxCnt) ++] = UARTx->DR>>16; 							//将数据存放到缓冲区
            if(sg_UartRx[ch].UartRxCnt == sg_UartRx[ch].RxBuffSize) 										//缓冲区已满
            {
                 //sg_UartRx[ch].UartRxCnt = 0;																//接收计数器清零
                  sg_UartRx[ch].isBuffFull = TRUE;															//缓冲区已满标志
            }	
			
        }
        else //缓冲区满了,清除接收到的数据
        {
            sg_UartRx[ch].TempData = UARTx->DR>>16;
        }
    }	
	//UARTx_SendByte(ch, sg_UartRx[ch].TempData);					//调试,将收到的数据发送出去
}

//串口中断处理
__inline static void UARTx_IRQHandler(UART_CH_Type ch)
{
	UART_TypeDef *UARTx;
	
	UARTx = (UART_TypeDef *) scg_UARTx_Base[ch];				//获取设备基址
	
	if(UARTx->SR & BIT5)										//FIFO收到指定数据的数据了
	{
		UARTx_ReadRxData(ch, UARTx);
	}

	UARTx->CR1 |= BIT17|BIT16|BIT19|BIT20;						//清除中断
}

#endif //UART_DMA_EN

/*************************************************************************************************************
 * 文件名:			uart.h
 * 功能:			HC32F4A0 UART通讯支持
 * 作者:			cp1300@139.com
 * 创建时间:		2021-11-19
 * 最后修改时间:	2021-11-19
 * 详细:			
*************************************************************************************************************/
#ifndef _UART_H_  
#define _UART_H_
#include "hc32f4a0_system.h"

/***********************配置相关************************/
#define UART_TX_TO_FIFI	1							//1:数据发送到发送FIFO则认为发送完成; 0:数据从移位寄存器发送完成则认为发送完成
#define UART_ChMax		4							//串口通道数量
#define UART_DMA_EN		1							//释放使能DMA
#define UART_INT_PRIO	SYS_INT_UART_RX_PRO			//中断优先级
#define UART_DMA_TX_MIN	63							//使用DMA发送最少的数据,少于这个值不调用DMA,数据太少,使用DMA效率不高,但是至少3个字节以上
/*********************************************************/



//串口选择,串口0开始,到串口10
typedef enum
{
	UART_CH1	=		0,	//UART1
	UART_CH2	=		1,	//UART2
	UART_CH3	=		2,	//UART3
	UART_CH4	=		3,	//UART4
	UART_CH5	=		4,	//UART5
	UART_CH6	=		5,	//UART6
	UART_CH7	=		6,	//UART7
	UART_CH8	=		7,	//UART8
	UART_CH9	=		8,	//UART9
	UART_CH10	=		9,	//UART10
}UART_CH_Type;


//UART配置相关结构定义
typedef struct
{
	u8 OddEvenVerify;	//奇偶校验,奇,偶,无
	u8 StopBitWidth;	//停止位位宽1,2
	u8 DataBitWidth;	//数据位宽度8,9
} UART_Config_TypeDef;


//奇偶校验
#define UART_VERIFY_NULL	0	//无校验
#define UART_ODD			1	//奇校验
#define UART_EVEN			2	//偶校验
//停止位
#define UART_STOP_1BIT		0	//一个停止位
#define UART_STOP_2BIT		1	//2个停止位
//数据位数
#define UART_DATA_8BIT		0	//8位数据长度
#define UART_DATA_9BIT		1	//8位数据长度

//相关API
bool UARTx_Init(UART_CH_Type ch,u32 Speed, bool isEnableRx);		//串口初始化
void UARTx_SendByte(UART_CH_Type ch,u8 data);						//UART单字节发送
void UARTx_SendData(UART_CH_Type ch,u8 *pTxBuff,u16 DataLen);		//UART数据发送函数
void UARTx_WaitSendComplete(UART_CH_Type ch);						//等待数据发送完成-从串口发送完成
void UARTx_SendString(UART_CH_Type ch,char *pString);				//UART发送字符串
bool UARTx_GetNewDataFlag(UART_CH_Type ch);							//获取串口新数据标志
bool UARTx_GetRxBuffFullFlag(UART_CH_Type ch);						//获取串口接收缓冲区满标志
u8 	 UARTx_GetNewData(UART_CH_Type ch);								//获取串口新数据
void UARTx_SetRxBuff(UART_CH_Type ch,u8 *RxBuff,u16 RxBuffSize);	//设置串口接收缓冲区
void UARTx_ClearRxInt(UART_CH_Type ch);								//清除串口接收中断标志
u32  UARTx_GetRxCnt(UART_CH_Type ch);								//获取串口接收数据计数器
void UARTx_ClearRxCnt(UART_CH_Type ch);								//清除串口接收数据计数器

#endif //_UART_H_




//UART========================================================================================================
#define UART1_BASE               (0x4001CC00UL)      //寄存器基址
#define UART2_BASE               (0x4001D000UL)      //寄存器基址
#define UART3_BASE               (0x4001D400UL)      //寄存器基址
#define UART4_BASE               (0x4001D800UL)      //寄存器基址
#define UART5_BASE               (0x4001DC00UL)      //寄存器基址
#define UART6_BASE               (0x40020C00UL)      //寄存器基址
#define UART7_BASE               (0x40021000UL)      //寄存器基址
#define UART8_BASE               (0x40021400UL)      //寄存器基址
#define UART9_BASE               (0x40021800UL)      //寄存器基址
#define UART10_BASE              (0x40021C00UL)      //寄存器基址


typedef struct
{
	vu32 SR;			//状态寄存器
	vu32 DR;			//数据寄存器
	vu32 BRR;			//波特率寄存器
	vu32 CR1;			//控制寄存器1
	vu32 CR2;			//控制寄存器2
	vu32 CR3;			//控制寄存器3
	vu32 PR;			//预分配寄存器
	vu32 LBMC;			//LIN波特率测量计数寄存器
}UART_TypeDef;


#define UART1                       ((UART_TypeDef *) UART1_BASE)
#define UART2                       ((UART_TypeDef *) UART2_BASE)
#define UART3                       ((UART_TypeDef *) UART3_BASE)
#define UART4                       ((UART_TypeDef *) UART4_BASE)
#define UART5                       ((UART_TypeDef *) UART5_BASE)
#define UART6                       ((UART_TypeDef *) UART6_BASE)
#define UART7                       ((UART_TypeDef *) UART7_BASE)
#define UART8                       ((UART_TypeDef *) UART8_BASE)
#define UART9                       ((UART_TypeDef *) UART9_BASE)
#define UART10                      ((UART_TypeDef *) UART10_BASE)

//测试

n(void)
{
	u32 i = 0;

	SYS_GPIOx_OneInit(GPIOE, 6, OUT_PP, GPIO_DRV_0);
	LED = 0;
	
	UARTx_Init(UART_PRINTF_CH, 256000, TRUE);
	SYS_GPIOx_SetAF(GPIOE, 1, 32);
	SYS_GPIOx_SetAF(GPIOE, 0, 33);

	uart_printf("hello world!\r\n");
	while (1)
	{
		LED = !LED;
		delay_ms();
		uart_printf("%u\r\n", i++);
	}
}

 

版权声明:本文为CSDN博主「cp1300」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cp1300/article/details/121431121

生成海报
点赞 0

cp1300

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

HC32F460外部中断的使用

本次主要是使用按键触发外部中断,打印按下的按键,同时操作led灯。 外部中断操作流程参考《HC32F460系列的中断控制器INTC Rev1.1.pdf》中的使用方法。 1. 首先是介绍硬件电路的接法 1.1 按

HC32F460 读取热电偶温度

使用背景 首先感谢华大半导体产商的辛苦努力 ,发布了一款高性价比的MCU-HC32F460 系列,它是基于 ARM Cortex-M4 32-bit RISC CPU,最高工作频率200MHz 的高性

rt_thread hc32f460开发四:pwm驱动移植

RT-Thread 驱动开发简介 RT-Thread驱动开发最开始应该是要阅读官方的文档,理解驱动的运行原理和使用方法。PWM部分的文档在这里https://www.rt-thread.org/document/site/#/rt