RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能端口时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能串口时钟
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);//端口映射到串口 GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
IO_Init。GPIO_Mode = GPIO_Mode_AF; //设置为复用模式 IO_Init。GPIO_OType = GPIO_OType_PP; IO_Init。GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; IO_Init。GPIO_PuPd = GPIO_PuPd_UP; IO_Init。GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &IO_Init);
UT_Init。USART_BaudRate = 9600; //波特率 UT_Init。USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件控制流 UT_Init。USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //发送接收 UT_Init。USART_Parity = USART_Parity_No; //无奇偶校验 UT_Init。USART_StopBits = USART_StopBits_1; //停止位1 UT_Init。USART_WordLength = USART_WordLength_8b; //数据位8 USART_Init(USART1, &UT_Init);
USART_Cmd(USART1, ENABLE); //串口使能
其中的位5:RXNE就是可以接收完成标志位,当数据接收完成时,RXNE会自动置1,我们可以通过读取该位的状态,来判断是否接收到数据,直接读取该位的方法是
u8 Receive_Data = 0;
Receive_Flag = USART1->SR & 1 << 5; //若接收到数据则标志位=1
上面的方法就是直接读取位5的值,接收完成则Receive_Flag=1。
其实我们更喜欢用一个函数来读取RXNE的状态:
USART_GetFlagStatus(USART1, USART_IT_RXNE)
该函数不仅可以读取RXNE的状态,还可以读取其他位的状态,若标志置1,该函数则会返回SET,即1。
我们可以看看该函数是如何实现的呢?
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG) { FlagStatus bitstatus = RESET; /* Check the parameters */ assert_param(IS_USART_ALL_PERIPH(USARTx)); assert_param(IS_USART_FLAG(USART_FLAG)); /* The CTS flag is not available for UART4 and UART5 */ if (USART_FLAG == USART_FLAG_CTS) { assert_param(IS_USART_1236_PERIPH(USARTx)); } if ((USARTx->SR & USART_FLAG) != (uint16_t)RESET) { bitstatus = SET; } else { bitstatus = RESET; } return bitstatus; }
可以看出该函数也是通过读取寄存器相应的位来返回相应的状态。
还有另一个函数和这个很相似:
USART_GetITStatus(USART1, USART_IT_RXNE);
这个函数也是读取RXNE的状态,不同的是当我们打开了串口中断,接收到数据时,这个函数才会返回1.
也就是说,无论串口中断是打开,接受完成后RXNE标志位都会置1,即USART_GetFlagStatus(USART1, USART_IT_RXNE)返回1,如果开启了中断,那么USART_GetFlagStatus(USART1, USART_IT_RXNE)和USART_GetITStatus(USART1, USART_IT_RXNE)都会置1。
当RXNE置1,即接收到数据后,我们要及时的读取接收到的数据,相应的函数是Receive_Data = USART_ReceiveData(USART1);
我们也可以直接读取USART1->DR寄存器,如Receive_Data = USART1->DR;
当读取完成后,RXNE将自动清零,如果没有读取数据,则需要软件清零,可以使用函数USART_ClearFlag(USART1,USART_IT_RXNE);来进行手动清零,或通过将状态寄存器位5-RXNE置为0:USART1->SR &= ~(1 << 5);这一点是很重要的。
将数据进行处理后,我们需要回复一些数据,我们可以通过函数USART_SendData(USART1,data);来向外发送数据,当然我们也可以像读取数据那样,将数据写入DR寄存器来实现 USART1->DR=data。其实我们更多的是通过重定向printf()函数来向外格式化输出数据,如printf("Receive Succsed: %d \r\n", Data);这个更方便一些。
那么我们怎么来实现电脑发送0x01来控制LED反转呢?
void USART1_Config() { GPIO_InitTypeDef IO_Init; USART_InitTypeDef UT_Init; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能端口时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能串口时钟 GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);//端口映射到串口 GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); IO_Init.GPIO_Mode = GPIO_Mode_AF; //设置为复用模式 IO_Init.GPIO_OType = GPIO_OType_PP; IO_Init.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; IO_Init.GPIO_PuPd = GPIO_PuPd_UP; IO_Init.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &IO_Init); UT_Init.USART_BaudRate = 9600; //波特率 UT_Init.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件控制流 UT_Init.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //发送接收 UT_Init.USART_Parity = USART_Parity_No; //无奇偶校验 UT_Init.USART_StopBits = USART_StopBits_1; //停止位1 UT_Init.USART_WordLength = USART_WordLength_8b; //数据位8 USART_Init(USART1, &UT_Init); USART_Cmd(USART1, ENABLE); //串口使能 }
主函数怎么写呢?其实很简单,就是对接收的数据进行一下判断就OK了,如果接收到的数据==0x01,那么LED=!LED,是不是很简单呢?
int main(void) { LED_Init(); delay_init(168); USART1_Config(); LED0_OFF; LED1_OFF; while(1) { u8 Receive_Data = 0; if(USART_GetITStatus(USART1, USART_IT_RXNE)) //若接收到数据 { Receive_Data = USART_ReceiveData(USART1); //读取数据后,RXNE标志位自动清零; printf("Receive Succsed: %2x \r\n", Receive_Data); if(Receive_Data == 0x01) LED0 = !LED0; // USART_ClearFlag(USART1,USART_IT_RXNE); //手动清零 } else { LED1 = !LED1; printf("Running....\r\n"); delay_ms(500); } } }
这里使用了串口发送“Running....”和LED1闪烁来指示程序正在运行,这种方法很常用,可以指示程序的运行状态。
本文章没有使用串口中断来进行控制,下一篇文章将会介绍如何使用串口中断来控制LED。
2017年4月16日21:58:46
欢迎大家关注我的个人博客 http://www.wangchaochao.top/
微信扫码关注我的公众号
不定期更新个人学习笔记和技术总结,欢迎大家互相学习交流!