AT32F415 USART1、2、3,DMA 用结构体统一配置收发

AT32F415 USART1、2、3,DMA收发

1、串口1,2,3的收发原理都是一样的, 所以配置上都可以一起来,不同的地方再用指针引用。
2、程序基本流程串口配置,DMA配置,接收时用空闲中断,发送时用发送中断来关闭DMA.
(打开DMA后,串口的收发完成中断会对接到DMA的传输完成中断)
3、串口缓存和DMA缓存用两个独立,防止接收时有冲突。
4、接收时看空闲中断信号,有信号说明接收完了,把数据拿出来,DMA读数清零来重新接收,状态改为接收完成
5、发送时要手动开启DMA传输,传输完成后会产生串口中断,有中断后就关闭DMA

配置

串口配置
//串口编号
typedef enum {
	serial=0,
	Bluetooth,
	IrDA,
	serialCount,
}serialNum_e;
//统一缓冲格式:状态,收发大小,收发缓冲区大小
#define USART_MAX_BUFFER_SIZE 512
typedef struct usartRT {
	uint8_t status;
	uint16_t rxBufferSize;
	uint16_t txBufferSize;
	uint8_t txBuffer[USART_MAX_BUFFER_SIZE];
	uint8_t rxBuffer[USART_MAX_BUFFER_SIZE];
}usartPacket_s;
//统一串口接口:串口编号,串口的DMA通道,串口收发缓冲,DMA收发缓冲
typedef struct serialHandle {
	USART_Type* USARTx;
	DMA_Channel_Type* rxChannel;
	DMA_Channel_Type* txChannel;
	usartPacket_s packet;
	usartPacket_s DMApacket;
}SerialHandle_s;
//串口接口初始化配置
SerialHandle_s serialHandle[serialCount] = {
	[serial] = {//主要调试串口
		.USARTx = USART1,
		.rxChannel = DMA1_Channel5,
		.txChannel = DMA1_Channel4,
		},
	[Bluetooth] = {//串口2接到蓝牙模块
		.USARTx = USART2,
		.rxChannel = DMA1_Channel6,
		.txChannel = DMA1_Channel7,
		},
	[IrDA] = {//串口3接到红外收发模块
		.USARTx = USART3,
		.rxChannel = DMA1_Channel3,
		.txChannel = DMA1_Channel2,
		},
};
//串口初始化配置:串口接口,波特率,字节长度,停止位,校验位,收发模式,流控
//DMA配置
//开空闲中断,用来接收
//开发送中断,用来发送
//开启串口
void Serial_Setup(SerialHandle_s* serialx, uint32_t baudrate, uint16_t Wordlength, 
uint16_t Stopbits, uint16_t Parity, uint16_t Mode, uint16_t HardwareFlowControl)
{
	USART_Reset(serialx->USARTx);
	USART_InitType USARTx_InitStructure;
	USARTx_InitStructure.USART_BaudRate = baudrate;
	USARTx_InitStructure.USART_WordLength = Wordlength;
	USARTx_InitStructure.USART_StopBits = Stopbits;
	USARTx_InitStructure.USART_Parity = Parity;
	USARTx_InitStructure.USART_Mode = Mode;
	USARTx_InitStructure.USART_HardwareFlowControl = HardwareFlowControl;
	USART_Init(serialx->USARTx, &USARTx_InitStructure);
	USART_DMA_SETUP(serialx);
	USART_INTConfig(serialx->USARTx, USART_INT_IDLEF, ENABLE);
	USART_INTConfig(serialx->USARTx, USART_INT_TRAC, ENABLE);
	USART_Cmd(serialx->USARTx, ENABLE);
}
DMA配置
//DMA通道配置: 通道,发送的地址,设备地址,缓冲地址,缓冲大小,传送方向
void USART_DMA_INIT(DMA_Channel_Type* DMAchannelx,  uint32_t periphAddr, 
uint32_t bufferAddr, uint16_t bufferSize, uint32_t Direction)
{
	DMA_InitType DMA_InitStructure;
	DMA_Reset(DMAchannelx);
	DMA_DefaultInitParaConfig(&DMA_InitStructure);
	DMA_InitStructure.DMA_PeripheralBaseAddr = periphAddr;
	DMA_InitStructure.DMA_MemoryBaseAddr = bufferAddr;
	DMA_InitStructure.DMA_Direction = Direction;
	DMA_InitStructure.DMA_BufferSize = bufferSize;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PERIPHERALINC_DISABLE;
	DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_ENABLE;
	DMA_InitStructure.DMA_PeripheralDataWidth = DMA_PERIPHERALDATAWIDTH_BYTE;
	DMA_InitStructure.DMA_MemoryDataWidth = DMA_MEMORYDATAWIDTH_BYTE;
	DMA_InitStructure.DMA_Mode = DMA_MODE_NORMAL;
	DMA_InitStructure.DMA_Priority = DMA_PRIORITY_LOW;
	DMA_InitStructure.DMA_MTOM = DMA_MEMTOMEM_DISABLE;
	DMA_Init(DMAchannelx, &DMA_InitStructure);
}
//用人话重定义传送方向
/*memory to periph */
#define UART_TX DMA_DIR_PERIPHERALDST
/*periph to memory*/
#define UART_RX DMA_DIR_PERIPHERALSRC
//DMA初始化:发送通道,接收通道,开启通道,开启串口通道请求
void USART_DMA_SETUP(SerialHandle_s* serialx)
{
	USART_DMA_INIT(serialx->txChannel, (uint32_t) &(serialx->USARTx->DT), (uint32_t)(serialx->DMApacket.txBuffer), USART_MAX_BUFFER_SIZE, UART_TX);
	USART_DMA_INIT(serialx->rxChannel, (uint32_t) &(serialx->USARTx->DT), (uint32_t)(serialx->DMApacket.rxBuffer), USART_MAX_BUFFER_SIZE, UART_RX);
	//DMA_ChannelEnable(serialx->txChannel, ENABLE);
	DMA_ChannelEnable(serialx->rxChannel, ENABLE);
	/* Enable USARTx DMA Rx and TX request */
	USART_DMACmd(serialx->USARTx, USART_DMAReq_Rx, ENABLE);
	USART_DMACmd(serialx->USARTx, USART_DMAReq_Tx, ENABLE);
}
串口中断处理
// 缓冲准状态
typedef enum {
	rxDone=1,
	txDone=1<<1,
	rxBusy=1<<2,
	txBusy=1<<3,
}SerialStatus_e;

void Serial_IRQHandler(SerialHandle_s* serialx)
{
	uint16_t bufferCount = 0;
	//接收处理
	if (USART_GetITStatus(serialx->USARTx, USART_INT_IDLEF))
	{
		USART_ClearITPendingBit(serialx->USARTx, USART_INT_IDLEF);
		(void)(serialx->USARTx->DT);//读一次接收寄存器来清除接收中断
		DMA_ChannelEnable(serialx->rxChannel, DISABLE);//关闭通道
		serialx->DMApacket.status |= rxDone;//缓冲状态:接收完成
		bufferCount = DMA_GetCurrDataCounter(serialx->rxChannel);//缓冲计数
		serialx->DMApacket.rxBufferSize = USART_MAX_BUFFER_SIZE - bufferCount;//缓冲数
		serialx->packet.rxBufferSize = 0;//
		memcpy(serialx->packet.rxBuffer, serialx->DMApacket.rxBuffer, serialx->DMApacket.rxBufferSize);//复制DMA缓冲到USART缓冲
		//重新准备接收
		DMA_SetCurrDataCounter(serialx->rxChannel, USART_MAX_BUFFER_SIZE);
		DMA_ChannelEnable(serialx->rxChannel, ENABLE);
		USART_DMACmd(serialx->USARTx, USART_DMAReq_Rx, ENABLE);
	}
	//发送处理
	if (USART_GetITStatus(serialx->USARTx, USART_INT_TRAC))
	{
		USART_ClearITPendingBit(serialx->USARTx, USART_INT_TRAC);
		DMA_ChannelEnable(serialx->txChannel, DISABLE);
		serialx->DMApacket.status |= txDone;
		serialx->DMApacket.status &= (~txBusy);
		serialx->DMApacket.txBufferSize = 0;
	}
}

void USART1_IRQHandler(void)
{
	Serial_IRQHandler(&serialHandle[serial]);
}
void USART2_IRQHandler(void)
{
	Serial_IRQHandler(&serialHandle[Bluetooth]);
}
void USART3_IRQHandler(void)
{
	Serial_IRQHandler(&serialHandle[IrDA]);
}

数据收发

发送数据
//把数据写入到发送缓存里
//常量指针能避免修改指针指向的数据
void Serial_putc(SerialHandle_s* serialx, const char b)
{
	serialx->packet.txBuffer[serialx->packet.txBufferSize] = b;
	serialx->packet.txBufferSize++;
}
void Serial_puts(SerialHandle_s* serialx, const char* b)
{
	while (*b)
	{
		serialx->packet.txBuffer[serialx->packet.txBufferSize] = *b;
		serialx->packet.txBufferSize++;	
		b++;
		if (serialx->packet.txBufferSize == USART_MAX_BUFFER_SIZE) Serial_flush(serialx);
	}
}
//把缓存里的数据发送出去
void dmaChannelFlush(SerialHandle_s* serialx)
{
	if (!serialx->packet.txBufferSize)return;
	/*wait for transmition complete*/
	uint16_t tryCount = 0;
	//delay_ms(10);
	while (serialx->DMApacket.status & txBusy)
	{
		if (tryCount++ > SystemCoreClock/10000)return;
	}
	/*close dma channel and USART_DMAReq_Tx*/
	DMA_ChannelEnable(serialx->txChannel, DISABLE);
	USART_DMACmd(serialx->USARTx, USART_DMAReq_Tx, DISABLE);

	/*copy data from packet.txBuffer to DMApacket.txBuffer*/
	memcpy(serialx->DMApacket.txBuffer, serialx->packet.txBuffer, serialx->packet.txBufferSize);
	serialx->DMApacket.txBufferSize = serialx->packet.txBufferSize;
	/*reset packet.txBufferSize to 0*/
	serialx->packet.txBufferSize = 0;
	/*reset dma current data counter to DMApacket.txBufferSize*/
	DMA_SetCurrDataCounter(serialx->txChannel, serialx->DMApacket.txBufferSize);
	/*reopen USART_DMAReq_Tx*/
	USART_DMACmd(serialx->USARTx, USART_DMAReq_Tx, ENABLE);
	/*reopen dma channel*/
	DMA_ChannelEnable(serialx->txChannel, ENABLE);
	/*tx busy*/
	serialx->DMApacket.status |= txBusy;
}
void Serial_flush(SerialHandle_s* serialx)
{
	dmaChannelFlush(serialx);
}
接收数据
uint16_t IsSerialRxHasData(SerialHandle_s* serialx)
{
	if (serialx->DMApacket.status & rxDone)
	{
		return serialx->DMApacket.rxBufferSize;
	}
	else
		return 0;
}
/*
*Input: SerialHandle
*output: 1 byte of read
*/
const char Serial_getc(SerialHandle_s* serialx)
{
	return serialx->packet.rxBuffer[serialx->packet.rxBufferSize++];
}
/*
Input: SerialHandle,  rxBuffer pointer, bytesOfread pointer
ouput: pointer of rxBuffer
*/
const char* Serial_gets(SerialHandle_s* serialx)
{
	return (serialx->packet.rxBuffer);
}
/*
Input: SerialHandle,  rxBuffer pointer, bytesOfread pointer, bytes to read
ouput: pointer of rxBuffer
*/
const char Serial_get(SerialHandle_s* serialx, uint16_t byteIndex)
{
	if (byteIndex >= USART_MAX_BUFFER_SIZE) return 0;
	return serialx->packet.rxBuffer[byteIndex-1];
}
//清空接收缓冲
void Serial_Pruge(SerialHandle_s* serialx)
{
	serialx->DMApacket.status &= ~rxDone;
	serialx->DMApacket.rxBufferSize = 0;
	memset(serialx->packet.rxBuffer, 0, USART_MAX_BUFFER_SIZE);
}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值