DMA模式的串口通信

之前试过了DMA的ADC,这次用DMA结合串口的收发。

初始化一些需要用到的参数

#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;
typedef struct serialHandle {
	USART_Type* USARTx;
	DMA_Channel_Type* rxChannel;//接收频道
	DMA_Channel_Type* txChannel;//发送频道
	usartPacket_s packet;
	usartPacket_s DMApacket;
}SerialHandle_s;
//以串口1为例
SerialHandle_s serialHandle[serialCount] = {
	[serial1] = {
		.USARTx = USART1,
		.rxChannel = DMA1_Channel5,
		.txChannel = DMA1_Channel4,
		.packet.rxBufferSize = 0,
		.DMApacket.rxBufferSize = 0,
	},
}

初始化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;	//数据宽度8位
	DMA_InitStructure.DMA_MemoryDataWidth = DMA_MEMORYDATAWIDTH_BYTE;			//数据宽度8位
	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);
}

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

初始化串口

void USART_ClkCmd(USART_Type* USARTx, FunctionalState NewState)
{
	if (USARTx == USART1)
	{
	RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_USART1, NewState);				//不同的串口硬件时钟不同,要注意
	}
}

void USART_NVIC_Cmd(USART_Type* USARTx, FunctionalState NewState)
{
	if (USARTx == USART1)
	{
		NVIC_Config(USART1_IRQn, 4, 1, NewState);
	}
}

void Usart_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_ClkCmd(serialx->USARTx, ENABLE);									//开启串口时钟
	USART_NVIC_Cmd(serialx->USARTx, ENABLE);								//串口中断
	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);												//设置DMA
	USART_INTConfig(serialx->USARTx, USART_INT_IDLEF, ENABLE);				//串口空闲中断开启
	USART_INTConfig(serialx->USARTx, USART_INT_TRAC, ENABLE);
	USART_Cmd(serialx->USARTx, ENABLE);										//串口使能
}

使用串口1发数据

char* myitoa(int num, char* str, int radix)
{ 
	char index[] = "0123456789ABCDEF";
	unsigned unum;
	int i = 0, j, k;

	if (radix == 10 && num < 0) 
	{
		unum = (unsigned)-num;
		str[i++] = '-';
	}
	else
		unum = (unsigned)num; 
	
	do
	{
		str[i++] = index[unum % (unsigned)radix];
		unum /= radix;
	} while (unum);
	str[i] = '\0';
	
	if (str[0] == '-')
		k = 1; 
	else
		k = 0;

	for (j = k; j <= (i - 1) / 2; j++)
	{
		char temp;
		temp = str[j];
		str[j] = str[i - 1 + k - j];
		str[i - 1 + k - j] = temp;
	}
	return str;
}
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 Serial_put(SerialHandle_s* serialx, const char* buffer, uint16_t lenght)
{
	if (lenght + serialx->packet.txBufferSize > USART_MAX_BUFFER_SIZE)
	{
		uint16_t txSize = 0;
		txSize = USART_MAX_BUFFER_SIZE - serialx->packet.txBufferSize;
		memcpy(&(serialx->packet.txBuffer[serialx->packet.txBufferSize]), buffer, txSize);
		serialx->packet.txBufferSize = USART_MAX_BUFFER_SIZE;
		Serial_flush(serialx);
		memcpy(&(serialx->packet.txBuffer[0]), &buffer[txSize], lenght - txSize);
		serialx->packet.txBufferSize = lenght - txSize;
	}
	else
	{
		while (lenght)
		{
			serialx->packet.txBuffer[serialx->packet.txBufferSize] = *buffer;
			serialx->packet.txBufferSize++;
			buffer++;
			lenght--;
		}
	}
}
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)
	{
		delay_us(10);
		// usartPrintf("userial busy!!\n");
		if (tryCount++ > SystemCoreClock / 1000000)
			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;

	/*IrDA modulate for usart3*/
	// if (serialx->USARTx == USART3) IrDA_Modulate_Cmd(ENABLE);
	/*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);
}
void uartPrintfloat(const char* format, ...)
{
	char str[30];
	char c = 0;
	char ch = 0;
	bool catchFloat = 0;
	union _floatHex
	{
		double _f;
		uint8_t _u8;
		int8_t _i8;
		uint16_t _u16;
		int16_t _i16;
		uint32_t _u32;
		int32_t _i32;
		uint64_t _u64;
		int64_t _i64;
		uint8_t hex[8];
	}ftmp;
	va_list ap;
	va_start(ap, format);
	char *p = 0;
	while ((c = *format))
	{
		switch (c)
		{
		case '%':
			ch = *++format;
			switch (ch)
			{
			case 'd':
			{
				if(catchFloat)
				{
					p = va_arg(ap, char[8]);
					memcpy(&ftmp.hex[4],p,4);
				}
				else
				{
					p = va_arg(ap, char[8]);
					memcpy(&ftmp.hex[0],p,8);
				}
				myitoa(ftmp._i64, str, 10);
				Serial_puts(&serialHandle[serial1], str);
				break;
			}
			case 'f':
				
				if (!catchFloat)
				{
					catchFloat = 1;
					/**FIXME 第一次遇到浮点数据时,前面有4个不明字节数据, 跳过它! */
					/**NOTE 不管什么类型都是8字节对齐的! */
					p = va_arg(ap, char[8]);
					memcpy(ftmp.hex,&p[4],4);
				}
				p = va_arg(ap, char[8]);
				memcpy(&ftmp.hex[4],p,4);

				// hexFloatTest(f);
				int32_t n;
				n = ftmp._f;
				myitoa(n, str, 10);
				Serial_puts(&serialHandle[serial1], str);
				Serial_putc(&serialHandle[serial1], '.');
				n = (ftmp._f - n) * 1000000;
				if (n < 0)
					n = (unsigned)-n;
				myitoa(n, str, 10);
				Serial_puts(&serialHandle[serial1], str);
				memcpy(ftmp.hex,&p[4],4);
				break;
			case '%':
				Serial_putc(&serialHandle[serial1], '%');
				break;
			default:
				Serial_putc(&serialHandle[serial1], '%');
				Serial_putc(&serialHandle[serial1], ch);
				break;
			}
			break;
		default:
			Serial_putc(&serialHandle[serial1], c);
			break;
		}
		format++;
	}
	va_end(ap);
	Serial_flush(&serialHandle[serial1]);
}
void usartPrintf(const char* format, ...)
{
	char str[30];
	char c = 0;
	char ch = 0;
	bool catchFloat = 0;
	va_list ap;
	va_start(ap, format);
	while ((c = *format))
	{
		switch (c)
		{
		case '%':
		{
			ch = *++format;

			switch (ch)
			{
			case 'b':
			{
				uint32_t n = va_arg(ap, int);
				myitoa(n, str, 2);
				Serial_puts(&serialHandle[serial1], str);
				break;
			}
			case 'c':
			{
				char c = va_arg(ap, int);
				Serial_putc(&serialHandle[serial1], c);
				break;
			}
			case 'd':
			{
				uint32_t n = va_arg(ap, int);
				myitoa(n, str, 10);
				Serial_puts(&serialHandle[serial1], str);
				break;
			}
			case 'x':
			{
				uint32_t n = va_arg(ap, int);
				myitoa(n, str, 16);
				Serial_puts(&serialHandle[serial1], str);
				break;
			}
			case 'f':
			{
				if (!catchFloat)
				{
					catchFloat = 1;
					/**FIXME 第一次遇到浮点数据时,前面有4个不明字节数据, 跳过它! */
					// int nn = va_arg(ap, char[4]);
					// Serial_puts(&serialHandle[serial1], "catchFloat:");
					// // hexFloatTest(*(double*)p);
					// myitoa(nn, str, 16);
					// Serial_puts(&serialHandle[serial1], str);
				}
				double f = va_arg(ap, double);
				hexFloatTest(f);
				int32_t n;
				n = f;
				myitoa(n, str, 10);
				Serial_puts(&serialHandle[serial1], str);
				Serial_putc(&serialHandle[serial1], '.');
				n = (f - n) * 1000000;
				if (n < 0)
					n = (unsigned)-n;
				myitoa(n, str, 10);
				Serial_puts(&serialHandle[serial1], str);
				break;
			}
			case 's':
			{
				char* p = va_arg(ap, char*);
				Serial_puts(&serialHandle[serial1], p);
				break;
			}
			case '%':
			{
				Serial_putc(&serialHandle[serial1], '%');
				break;
			}
			default:
			{
				/*Serial_puts(&serialHandle[serial1], "#error:format invalid: <%");*/
				Serial_putc(&serialHandle[serial1], '%');
				Serial_putc(&serialHandle[serial1], ch);
				/*Serial_puts(&serialHandle[serial1], ">#");*/

				break;
			}
			}
		}
		break;
		default:
			Serial_putc(&serialHandle[serial1], c);
			break;
		}
		format++;
	}
	va_end(ap);
	Serial_flush(&serialHandle[serial1]);
}

使用串口1接收数据

char Serial_getc(SerialHandle_s* serialx)
{
	return serialx->packet.rxBuffer[serialx->packet.rxBufferSize++];
}
/*
Input: SerialHandle,  rxBuffer pointer, bytesOfread pointer
ouput: pointer of rxBuffer
*/
char* Serial_gets(SerialHandle_s* serialx)
{
	return (char*)(serialx->packet.rxBuffer);
}
// serialHandle[serial].packet.rxBuffer
/*
Input: SerialHandle,  rxBuffer pointer, bytesOfread pointer, bytes to read
ouput: pointer of rxBuffer
*/
char Serial_get(SerialHandle_s* serialx, uint16_t byteIndex)
{
	if (byteIndex >= USART_MAX_BUFFER_SIZE)
		return 0;
	return serialx->packet.rxBuffer[byteIndex - 1];
}
uint16_t IsSerialRxHasData(SerialHandle_s* serialx)
{
	if (serialx->DMApacket.status & rxDone)
	{
		return serialx->packet.rxBufferSize;
	}
	else
		return 0;
}
/**清空串口接收缓存 */
void Serial_Pruge(SerialHandle_s* serialx)
{
	serialx->DMApacket.status &= ~rxDone;
	serialx->packet.rxBufferSize = 0;
	memset(serialx->packet.rxBuffer, 0, USART_MAX_BUFFER_SIZE);
}

中断处理

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;
		if (serialx->packet.rxBufferSize >= USART_MAX_BUFFER_SIZE)
			serialx->packet.rxBufferSize = 0;
		memcpy(&serialx->packet.rxBuffer[serialx->packet.rxBufferSize], serialx->DMApacket.rxBuffer, serialx->DMApacket.rxBufferSize);
		serialx->packet.rxBufferSize += serialx->DMApacket.rxBufferSize;

		DMA_SetCurrDataCounter(serialx->rxChannel, USART_MAX_BUFFER_SIZE);
		DMA_ChannelEnable(serialx->rxChannel, ENABLE);
		USART_DMACmd(serialx->USARTx, USART_DMAReq_Rx, ENABLE);
	}
	//DMA中断处理
	if (USART_GetITStatus(serialx->USARTx, USART_INT_TRAC))
	{
		USART_ClearITPendingBit(serialx->USARTx, USART_INT_TRAC);
		/*turn off IrDA moudulate of usart3*/
		// if (serialx->USARTx == USART3) IrDA_Modulate_Cmd(DISABLE);
		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]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值