前几天在群里看到有人咨询stm32串口总线空闲检测的问题,之前也一直没用过该特性,后来看了下手册学习了一下,编辑了一些代码进行测试发现一个小问题,uart源文件代码如下:
- #include "uart.h"
- uint8_t buffer[100];
- __IO uint32_t cnt = 0,idle_detect = 0;
- void uart_init (uint32_t baud)
- {
- USART_InitTypeDef USART_InitStructure;
- GPIO_InitTypeDef GPIO_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
- RCC_AHBPeriphClockCmd(USARTx_GPIO_CLK, ENABLE);
- USARTx_CLK_ENABLE();
- GPIO_PinAFConfig(USARTx_GPIO_PORT, USARTx_TX_SOURCE, USARTx_TX_AF);
- GPIO_PinAFConfig(USARTx_GPIO_PORT, USARTx_RX_SOURCE, USARTx_RX_AF);
- GPIO_InitStructure.GPIO_Pin = USARTx_TX_PIN| USARTx_RX_PIN;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_3;
- GPIO_Init(USARTx_GPIO_PORT, &GPIO_InitStructure);
- USART_InitStructure.USART_BaudRate = baud ;
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;
- USART_InitStructure.USART_StopBits = USART_StopBits_1;
- USART_InitStructure.USART_Parity = USART_Parity_No;
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
- USART_Init(USARTx, &USART_InitStructure);
- USART_ITConfig(USARTx,USART_IT_RXNE,ENABLE);
- USART_ITConfig(USARTx,USART_IT_PE,ENABLE);
- USART_ITConfig(USARTx,USART_IT_ERR,ENABLE);
- USART_ITConfig(USARTx,USART_IT_IDLE,ENABLE);
-
- NVIC_InitStructure.NVIC_IRQChannel = USARTx_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPriority=0;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- USART_Cmd(USARTx, ENABLE);
- }
- int fputc(int ch, FILE *f)
- {
- USART_SendData(USARTx,(uint8_t)ch);
- while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE) != SET);
- return ch;
- }
- void USARTx_IRQHandler(void)
- {
- uint8_t temp = 0;
-
- if(USART_GetFlagStatus(USARTx,USART_FLAG_ORE) != RESET)
- {
- temp = USART_ReceiveData(USARTx);
- (void)temp;
- USART_ClearFlag(USARTx,USART_FLAG_ORE);
- }
- if(USART_GetFlagStatus(USARTx,USART_FLAG_NE) != RESET)
- {
- USART_ClearFlag(USARTx,USART_FLAG_NE);
- }
- if(USART_GetFlagStatus(USARTx,USART_FLAG_FE) != RESET)
- {
- USART_ClearFlag(USARTx,USART_FLAG_FE);
- }
- if(USART_GetFlagStatus(USARTx,USART_FLAG_PE) != RESET)
- {
- USART_ClearFlag(USARTx,USART_FLAG_PE);
- }
-
- if(USART_GetITStatus(USARTx, USART_IT_RXNE) != RESET)
- {
- buffer[cnt++]=USART_ReceiveData(USARTx);
- if(cnt >= 100)
- {
- cnt = 0;
- }
- USART_ClearITPendingBit(USARTx, USART_IT_RXNE);
- }
- if(USART_GetITStatus(USARTx, USART_IT_IDLE) != RESET)
- {
- USART_ClearITPendingBit(USARTx, USART_IT_IDLE);
- idle_detect = 1;
- cnt = cnt;
- }
- return;
- }
复制代码 主函数中的测试代码如下:
- #include "uart.h"
- extern __IO uint32_t idle_detect,cnt;
- extern uint8_t buffer[100];
- int main (void)
- {
- uint8_t i = 0;
- uart_init(115200);
- while(1)
- {
- if(1 == idle_detect && cnt > 0)
- {
- idle_detect = 0;
-
- printf("\r\ncnt:%X,ctx:",cnt);
- for(i = 0; i < cnt; i++)
- {
- printf("%02X ",buffer[i]);
- }
- cnt = 0;
- }
- }
- }
复制代码 运行该代码时结果如下
它输出的cnt值一直为1,但数据内容是正确的,而把cnt的判断放在if条件语句的里面就不会出问题,如下:
- #include "uart.h"
- extern __IO uint32_t idle_detect,cnt;
- extern uint8_t buffer[100];
- int main (void)
- {
- uint8_t i = 0;
- uart_init(115200);
- while(1)
- {
- if(1 == idle_detect)
- {
- idle_detect = 0;
-
- if(cnt == 0)
- continue;
- printf("\r\ncnt:%X,ctx:",cnt);
- for(i = 0; i < cnt; i++)
- {
- printf("%02X ",buffer[i]);
- }
- cnt = 0;
- }
- }
- }
复制代码 运行结果如下:
此时输出的cnt的值是正确的,有人知道会是什么问题导致的吗?
|
我觉得RXNE和IDLE LINE这两个中断的发生时间需要测试一下。
这两个的发生时间我理解的可能不正确。若有错误请指正。
在我的理解里,RXNE是接受buffer里面有数据准备被DR读取的时候产生的。数据手册里面的描述是Received Data Ready to be Read.或者Read data register not empty.
而idle line是硬件检测到的空闲间隔。当出现idle line的时候RXNE一定发生。【The IDLE bit will not be set again until the RXNE bit has been set itself 】
在我的测试中是在HAL中进行的,使用中断idle line来实现不定常接收。就出现了每一个字节都接受,反而idle line没有什么效果。
所以你的第一段代码中cnt一直是1.你第二个出现正确的结果,个人猜测是因为你用了
这样其实如果你跟踪程序的话,会发现你的idle line第一次出现是的确是cnt==0或者==1.
- printf("\r\ncnt:%X,ctx:",cnt);
- for(i = 0; i < cnt; i++)
- {
- printf("%02X ",buffer);
- }
你的这段代码可以看出cnt早printf时和printf之后明显改变了。你过你把cnt赋值给另一个数你就每次只能打印出一个数。所以第二段代码其实也没有解决你的真实问题。不信你拿50个左右的字符试一试。然后printf用另一个更快的端口输出。或者直接在内存调试。
推荐的方法是DMA+IDLE探测。不开启RXNE