这里出现该问题主要是我有时需要串口发送脚,切换为普通IO口中断来使用。
前篇提要
之前文章中有提过GD32串口发送丢失字节的问题,使用的轮询标志位,发送使用了while等待,造成了数据丢失,因为该单片机硬件自行处理了“发送缓冲区空标志”和“发送完成标志”;不需要程序去做多余的等待。
这里Geehy(极海)的32单片机用户手册上给出来的和GD32处理不一样。
上诉大概意思和发送的步骤如下:
-->当发送寄存器为空(数据寄存器(USART_DATA))=TXBEF=1时
-->数据写入USART_DATA寄存器,自动TXBEF=0
-->数据会自行移入 移位寄存器 中;(移入完成后,DATA为空,TXBEF=1,此时又可以写入数据了)
-->移位寄存器中有数据后,TX开始发送数据;(当发送完成,且TXBEF=1; 才会硬件置位发送完成标志TXCF=1)
最后一步可以说是,你发送一个数组,当最后一个字节发送完成时,就可以查询txcf标志,看发送完成没。
void USART_Init(USART_T* usart)
{
USART_Config_T usartConfig;
/* BaudRate is 9600 */
usartConfig.baudRate = 9600;
/* No interrupt */
usartConfig.interrupt = USART_INT_NONE;
/* Enable receive and transmit */
usartConfig.mode = USART_MODE_TX;//只使能了TX
/* Parity disable */
usartConfig.parity = USART_PARITY_NONE;
/* One stop bit */
usartConfig.stopBits = USART_STOP_BIT_1;
/* Word length is 8bit */
usartConfig.wordLength = USART_WORD_LEN_8B;
/* USART1 configuration */
USART_Config(USART1, &usartConfig);
/* Enable USART1 */
USART_Enable(USART1);
}
/**************************************************************************************
函数名称:USARTX_Send
功 能:发送一组数据
参 数:pary,待发送数组首地址
len,待发送数据长度
返 回 值:无
**************************************************************************************/
void USARTX_Send(USART_T* usart, char data)
{
/* Wait until end of transmission */
while(USART_ReadStatusFlag(usart, USART_FLAG_TXBE) == RESET){};//等待DATA数据寄存器为空TXBEF=1;
USART_TxData8(usart, data);//这里是将数据写入DATA数据寄存器 TXBEF=0
}
// 主函数
int main(void)
{
USART_Init(USART1);
while (1)
{
USART_COM_Init_TX();//切换为USART1_TX
for(i=0; i<6; i++)
USARTX_Send(USART1,send_card[i]);//发送一串数据
while(USART_ReadStatusFlag(USART1, USART_FLAG_TXC) == RESET);//这里是等待数据发送成,和TXBEF=1; 发送完成标志才会置1,TXCF=1
/*这里需要等待上面数组发送完成,才能切换,否则会丢失数据*/
USART_COM_Init_RX();//切换为普通IO口,下降沿中断
}
}
下面代码是通过中断来发送数据
void USART_Init(USART_T* usart)
{
USART_Config_T usartConfig;
/* BaudRate is 9600 */
usartConfig.baudRate = 9600;
/* No interrupt */
usartConfig.interrupt = USART_INT_TX;//发送缓冲区空中断, TXBEF 置位时,产生中断
/* Enable receive and transmit */
usartConfig.mode = USART_MODE_TX;//只使能了TX
/* Parity disable */
usartConfig.parity = USART_PARITY_NONE;
/* One stop bit */
usartConfig.stopBits = USART_STOP_BIT_1;
/* Word length is 8bit */
usartConfig.wordLength = USART_WORD_LEN_8B;
/* USART1 configuration */
USART_Config(USART1, &usartConfig);
/* Enable USART1 */
USART_Enable(USART1);
/* Enable USART1 transmitter IRQ request */
NVIC_EnableIRQRequest(USART1_TX_IRQn, 0x01);
}
/*!
* @brief USART1 transmitter interrupt service routine
*
* @param None
*
* @retval None
*/
uint8_t tx1DataPt = 0;
extern unsigned char send_card[6];
void USART1_TxIsr(void)
{
if(USART_ReadIntFlag(USART1, USART_INT_FLAG_TX) == SET)
{
if(tx1DataPt < 6)
{
USART_TxData8(USART1, send_card[tx1DataPt++]);
}
else
{
tx1DataPt=0;
/* Disable USART1 transmitter interrupt */
USART_DisableInterrupt(USART1, USART_INT_TX);
}
}
}
/*!
* @brief This function handles USART1 receiver exception
*
* @param None
*
* @retval None
*/
void USART1_TX_IRQHandler(void)
{
USART1_TxIsr();
}
// 主函数
extern uint8_t tx1DataPt;
int main(void)
{
USART_Init(USART1);
while (1)
{
USART_COM_Init_TX();//切换为USART1_TX
while(USART_ReadStatusFlag(USART1, USART_FLAG_TXC) == RESET);//这里是等待数据发送成,和TXBEF=1; 发送完成标志才会置1,TXCF=1
/*也可以使用下面代码替代上面的while循环*/
// while(txDataPt < 6);//6是数组的大小
/*这里需要等待上面数组发送完成,才能切换,否则会丢失数据*/
USART_COM_Init_RX();//切换为普通IO口,下降沿中断
}
}
以下是串口和普通IO口相互切换的代码
/*!
* @brief USART_COM_Init_RX, Initialize to a common I/O port
*
* @param None
*
* @retval None
*
* @note
*/
void USART_COM_Init_RX(void)
{
USART_Reset(USART1);//失能USART1
GPIO_Config_T gpioConfig;
gpioConfig.mode = GPIO_MODE_IN_PU;
gpioConfig.speed = GPIO_SPEED_10MHz;
gpioConfig.intEn = GPIO_EINT_ENABLE;
gpioConfig.pin = GPIO_PIN_5;
GPIO_Config(GPIOD, &gpioConfig);
GPIO_SetBit(GPIOD, GPIO_PIN_5);
EINT_Config(EINT_PORT_D, EINT_TRIGGER_FALLING);
NVIC_EnableIRQRequest(EINTD_IRQn, 0X0f);
}
/*!
* @brief Initialize to USART1
*
* @param None
*
* @retval None
*
* @note
*/
void USART_COM_Init_TX(void)
{
Disable_EINT_D();//将PD5的中断失能
USART_Init(USART1);
}