前提:对应USART的接收部分,前面的初始化代码就不贴了,和原子的一样,注意一点,串口中断的配置只开启了USART_IT_RXNE
(1) 当使用发送字节函数时需要等待数据发送完成,或是数据已经由DR转移到移位寄存器了,再发送下一个数据;(注意:这里没有使用发送中断的方法)关于这点的总结:1 如果你不加while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)!=SET)语句的话,会造成什么现象。你的数据也能发出去但是会丢失很多数据,原因是你可能将数据放入DR的速度远远快于串口向外发送的速度,也就是说你放入第一个数据到DR,硬件自动将这个数据转到移位寄存器,然后发送,它还没发完呢,你可能已经向DR写了N个数据了,那么当串口发完你第一个数据时,才来DR读数据到移位寄存器,你想中间可能丢了N-1个数据了。2 检测什么时候向DR寄存器写入数据到底使用USART_GetFlagStatus(USART1,USART_FLAG_TXE)还是USART_GetFlagStatus(USART1,USART_FLAG_TC)呢,看手册: 1. 通过在USART_CR1寄存器上置位UE位来激活USART 2. 编程USART_CR1的M位来定义字长。 3. 在USART_CR2中编程停止位的位数。 4. 如果采用多缓冲器通信,配置USART_CR3中的DMA使能位(DMAT)。按多缓冲器通信中的描述配置DMA寄存器。 5. 利用USART_BRR寄存器选择要求的波特率。 6. 设置USART_CR1中的TE位,发送一个空闲帧作为第一次数据发送。 7. 把要发送的数据写进USART_DR寄存器(此动作清除TXE位)。在只有一个缓冲器的情况下,对每个待发送的数据重复步骤7。 8. 在USART_DR寄存器中写入最后一个数据字后,要等待TC=1,它表示最后一个数据帧的传输结束。当需要关闭USART或需要进入停机模式之前,需要确认传输结束,避免破坏 最后一次传输。很清楚了吧,使用USART_GetFlagStatus(USART1,USART_FLAG_TXE)就可以,这样效率更高一些,中间少等了串口发的N个bit的时间。实测功能完全正常,但是如果你发完最后一个数据要停掉USART的功能情况下就必须等待USART_GetFlagStatus(USART1, USART_FLAG_TC)了,因为不这样最后一个数据可能会丢失。(2) 当使能了串口接收中断RXENIE时,溢出中断是不会自己开启的,但是溢出标志位是可以置位的;(3) 调试硬件USART时,通过调试窗口,当进入接收中断时看不到RXNE置位, 原因是:当我们调出窗口时,对于MDK来说就是已经读取了DR寄存器,相当于将RXNE位给清零了,所以我们看不到RXNE置位,(4) 串口的接收部分的实验总结: a) 网上有人认为stm32的串口部分存在一些bug。例如:很多网友认为说只要我们开启了接收中断USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);那么溢出中断USART_IT_ORE就也会默认开启的,但是通过USART_GetITStatus(USART1,USART_IT_ORE)函数又得不到溢出中断的置位标记,而只能通过USART_GetFlagStatus(USART1,USART_FLAG_ORE)函数来判断是否发生了溢出,所以说这是个bug;首先:我认为这样理解是错误的。原因:1 根据库文件stm32f10x_usart.c V3.5.0中的串口中断配置函数void USART_ITConfig(USART_TypeDef* USARTx, uint16_tUSART_IT, FunctionalState NewState)/** * @brief Enables or disables the specified USART interrupts. * @param USARTx: Select the USART or the UART peripheral. * This parameter can be one of the following values: * USART1, USART2, USART3, UART4 or UART5. * @param USART_IT: specifies the USART interrupt sources to be enabled ordisabled. * This parameter can be one of the following values: * @arg USART_IT_CTS: CTS changeinterrupt (not available for UART4 and UART5) * @arg USART_IT_LBD: LIN Breakdetection interrupt * @arg USART_IT_TXE: Transmit DataRegister empty interrupt * @arg USART_IT_TC: Transmissioncomplete interrupt * @arg USART_IT_RXNE: Receive Data register not empty interrupt * @arg USART_IT_IDLE: Idle line detection interrupt * @arg USART_IT_PE: Parity Errorinterrupt * @arg USART_IT_ERR: Error interrupt(Frame error, noise error,overrun error) * @param NewState: new state of the specified USARTx interrupts. * This parameter can be: ENABLE or DISABLE. * @retval None */ 上面的红 {MOD}部分可知:如果你想使用溢出中断,必须配置USART_IT_ERR中断才可以使用USART_GetITStatus(USART1,USART_IT_ORE)函数来检测溢出中断;但是你在前面的初始化配置中只是打开了USART_ITConfig(USART1, USART_IT_RXNE, ENABLE)接收中断,试问你怎样通过USART_GetITStatus(USART1,USART_IT_ORE)来检测到溢出中断。(结论:如果只配置USART_IT_RXNE中断使能,USART_IT_ORE溢出中断仍然是不会触发的) 另外,在接收过程中如果发生了溢出我们是可以通过USART_GetFlagStatus(USART1,USART_FLAG_ORE)函数来检测看是否发生了溢出错误。根据是数据手册的:当RXNE仍然是’1’的时候,当前被接收在移位寄存器中的数据,需要传送至RDR寄存器时,硬件将该位置位。如果USART_CR1中的RXNEIE为’1’的话,则产生中断。可知该位可以是由硬件置位的;所以你能使用USART_GetFlagStatus(USART1,USART_FLAG_ORE)函数来检测。注意对“如果USART_CR1中的RXNEIE为’1’的话,则产生中断。”的理解,你开启了USART_IT_RXNE中断,那么RXNEIE肯定是为 1 的,也就是说在前面一句的基础上,发生溢出会产生中断,但是你都没使能溢出中断,它怎么触发中断,所以你用USART_GetITStatus(USART1, USART_IT_ORE)检测到溢出中断才怪了。 下面是我自己的调试代码:(1) 正常的中断处理函数 void USART1_IRQHandler(void) { my_printf("USART1->SR= %#x
",USART1->SR); 这句是用来解决JLINK调试中看不到RXNE置位用的 if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET) 如果是接收中断 { //注意使用的是USART_GetFlagStatus()函数,进入接收中断后,加个检测看是否发生了溢出错误if(USART_GetFlagStatus(USART1,USART_FLAG_ORE)!=SET) { //接收中断的读DR就是清中断,我这里是读完直接发出去,这样你在终端上可以直接看到自己的输入,交互性更好一些 my_putc(USART_ReceiveData(USART1) ); flag= 1; } else { //如果溢出了,就清一下, USART_GetITStatus(USART1,USART_IT_RXNE); USART_ReceiveData(USART1); if(flag> 0) //这里是个打印次数的控制变量,防止不停地发 { flag--; my_puts("Receiveoverflow!
"); } } }} 这里注意:如果溢出了,就按照手册的要求清ORE位,由软件序列将其清零(先读USART_SR,然后读USART_CR)。 即USART_GetITStatus(USART1, USART_IT_RXNE); USART_ReceiveData(USART1);这两句 另外注意:结合ORE置位的要求是 “当RXNE仍然是’1’的时候”,怎样理解呢,你既然要溢出,肯定是你上一次接受到的数据还没有从DR读走,又来了一个数据,所以肯定会先进入接收中断(覆盖上一个数据),接着你又检测ORE,这时ORE肯定置位了,就执行else分支,提示溢出。其次,注意书册上清ORE的方法,USART_GetITStatus(USART1,USART_IT_RXNE); USART_ReceiveData(USART1);这两句很有意思,这两句不仅清了ORE的置位,还把RXNE的置位也给清了,因为读DR可以请RXNE位。 (2) 下面是模拟产生接收溢出的代码:voidUSART1_IRQHandler(void) {my_printf("USART1->SR= %#x
",USART1->SR); 这句是用来解决JLINK调试中看不到RXNE置位用的 if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) 如果是接收中断 { //注意使用的是USART_GetFlagStatus()函数,进入接收中断后,加个检测看是否发生了溢出错误if(USART_GetFlagStatus(USART1,USART_FLAG_ORE)!=SET) { //注意这里我什么也没做,就是没有读DR,那么此时程序会不停地进入接收中断进行处理 //假如我们接收到一个数据,此时就开始不停地触发接收中断,因为中断出发了,你没有处理啊。 //但是此时还没有发生溢出错误,因为此时就收到一个数据,如果又来了一个数据,就要进入下面的else //因为这里的if不成立了,此时已经发生了溢出错误。 flag = 1; } else { //如果溢出了,就清一下,如果你不清,这时的中断还是接受中断USART_IT_RXNE,切记此时溢出中断你都没有打开 USART_GetITStatus(USART1,USART_IT_RXNE);//这里只要求读SR寄存器,所以参数随便整,无所谓; USART_ReceiveData(USART1); if(flag > 0) //这里是个打印次数的控制变量,防止不停地发 { flag--; my_puts("Receiveoverflow!
"); //发生溢出错误 } } }} (3)下面是模拟接受溢出现象的错误的写法void USART1_IRQHandler(void) { my_printf("USART1->SR =%#x
",USART1->SR); 这句是用来解决JLINK调试中看不到RXNE置位用的 if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET) 如果是接收中断 { //注意使用的是USART_GetITStatus()函数, if(USART_GetITStatus(USART1, USART_IT_ORE) != SET) { //注意这里我什么也没做,就是没有读DR,那么此时程序会不停地进入接收中断进行处理 //分析一下,这种情况下不管你接收到几个数据都不会进入else了,因为if判断永远成立。因为你溢出中断压根就没有开启 flag = 1; } else { //如果溢出了,就清一下, USART_GetITStatus(USART1,USART_IT_RXNE); USART_ReceiveData(USART1); if(flag> 0) //这里是个打印次数的控制变量,防止不停地发 { flag--; my_puts("Receiveoverflow!
"); } } }}
一周热门 更多>