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