创建串口设备结构体
typedef struct
{
USART_TypeDef *uart;
uint8_t *pTxBuf;
uint8_t *pRxBuf;
uint16_t usTxBufsize;
uint16_t usRxBufsize;
uint16_t usTxWrite;
uint16_t usTxRead;
uint16_t usTxCount;
uint16_t usRxWrite;
uint16_t usRxRead;
uint16_t usRxCount;
void (*SendBefor)(void);
void (*SendOver)(void);
void (*ReciveNew)(void);
}UART_T;
上述的接收缓冲区读写指针和发送缓冲区读写指针虽然是uint16_t的数据类型,但是在这里称之为指针,是因为其在队列中反应了数据读写时位置的变化。
static void UartVarInit(void)
{
g_tUart1.uart = USART1;
g_tUart1.pTxBuf = g_TxBuf1;
g_tUart1.pRxBuf = g_RxBuf1;
g_tUart1.usTxBufsize = UART1_TX_BUF_SIZE;
g_tUart1.usRxBufsize = UART1_RX_BUF_SIZE;
g_tUart1.usTxWrite = 0;
g_tUart1.usTxRead = 0;
g_tUart1.usRxWrite = 0;
g_tUart1.usRxRead = 0;
g_tUart1.usRxCount = 0;
g_tUart1.usTxCount = 0;
g_tUart1.SendBefor = 0;
g_tUart1.SendOver = 0;
g_tUart1.ReciveNew = 0;
}
上述的初始化过程将读写指针初始化为0,表明最开始缓冲区中没有数据,也就是处于队列的最底部。
下面是初始化串口的硬件部分
static void InitHardUart(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
USART_ClockInitTypeDef USART_ClockInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO | RCC_APB2Periph_USART1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = UART1_BAUD;
USART_InitStructure.USART_WordLength = UART1_WORD_LENGTH;
USART_InitStructure.USART_StopBits = UART1_STOP_BIT;
USART_InitStructure.USART_Parity = UART1_PARITY;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;
USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;
USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;
USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;
USART_ClockInit(USART1, &USART_ClockInitStructure);
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);
USART_ClearFlag(USART1, USART_FLAG_TC);
}
上述过程是程序化步骤,没有思维难点,接下来配置串口中断
static void ConfigUartNVIC(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
在发送数据的时候,采用UartSend();这个函数进行发送
具体的代码如下所示:
static void UartSend(UART_T *_pUart, uint8_t *_ucaBuf, uint16_t _usLen)
{
uint16_t i;
for(i = 0;i < _usLen;i++)
{
while(1)
{
__IO uint16_t usCount;
DISABLE_INT();
usCount = _pUart->usTxCount;
ENABLE_INT();
if(usCount < _pUart->usTxBufSize)
{
break;
}
}
_pUart->pTxBuf[_pUart->usTxWrite] = _ucaBuf[i];
DISABLE_INT();
if (++_pUart->usTxWrite >= _pUart->usTxBufSize)
{
_pUart->usTxWrite = 0;
}
_pUart->usTxCount++;
ENABLE_INT();
}
USART_ITConfig(_pUart->uart, USART_IT_TXE, ENABLE);
}
if(usCount < _pUart->usTxBufSize)
{
break;
}
通过上述的这句话保证每次写入缓冲区时都能保证等待发送的个数都小于缓冲区本身的大小,当等待发送的数据个数超过缓冲区本身的大小时,程序将陷入死循环。
_pUart->pTxBuf[_pUart->usTxWrite] = _ucaBuf[i]; 通过此条语句将要发送的数据送入缓冲区。
if (++_pUart->usTxWrite >= _pUart->usTxBufSize)
{
_pUart->usTxWrite = 0;
}
上述语句即表示如果当前的写指针已经移动到FIFO的顶端时,对指针进行复位。
同时在将要发送的数据存储到缓冲区之后,就可以通过触发中断发送数据
具体的发送中断的函数如下所示:
if (USART_GetITStatus(_pUart->uart, USART_IT_TXE) != RESET)
{
if(_pUart->usTxCount == 0)
{
USART_ITConfig(_pUart->uart, USART_IT_TXE, DISABLE);
USART_ITConfig(_pUart->uart, USART_IT_TC, ENABLE);
}
else
{
USART_SendData(_pUart->uart, _pUart->pTxBuf[_pUart->usTxRead]);
if (++_pUart->usTxRead >= _pUart->usTxBufSize)
{
_pUart->usTxRead = 0;
}
_pUart->usTxCount--;
}
}
else if (USART_GetITStatus(_pUart->uart, USART_IT_TC) != RESET)
{
if (_pUart->usTxCount == 0)
{
USART_ITConfig(_pUart->uart, USART_IT_TC, DISABLE);
}
else
{
USART_SendData(_pUart->uart, _pUart->pTxBuf[_pUart->usTxRead]);
if (++_pUart->usTxRead >= _pUart->usTxBufSize)
{
_pUart->usTxRead = 0;
}
_pUart->usTxCount--;
}
}
上述代码完成了一个完整的数据发送的过程
下面阐述关于接收数据的过程,接收数据通过触发中断接收数据。
中断处理函数如下:
if (USART_GetITStatus(_pUart->uart, USART_IT_RXNE) != RESET)
{
uint8_t ch;
ch = USART_ReceiveData(_pUart->uart);
_pUart->pRxBuf[_pUart->usRxWrite] = ch;
if (++_pUart->usRxWrite >= _pUart->usRxBufSize)
{
_pUart->usRxWrite = 0;
}
if (_pUart->usRxCount < _pUart->usRxBufSize)
{
_pUart->usRxCount++;
}
}
在接收中断里面读取到接收移位寄存器的值并将值存储到FIFO中,然后通过UartGetChar()函数读取缓冲区的值。
static uint8_t UartGetChar(UART_T *_pUart, uint8_t *_pByte)
{
uint16_t usCount;
DISABLE_INT();
usCount = _pUart->usRxCount;
ENABLE_INT();
if(usCount == 0)
{
return 0;
}
else
{
*_pByte = _pUart->pRxBuf[_pUart->usRxRead];
}
}
通过上述函数*_pByte便是从缓冲区读出的值
最后,再指出一点,再发送数据的时候,将要发送的数据送入缓冲区时,用的是发送写指针,在中断中将发送缓冲区中的数据填入发送数据寄存器中用的是发送读指针。
在中断接收时用的是接收写指针,读取程序中用的是接收读指针。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)