本帖最后由 wzt19910506 于 2013-5-2 08:28 编辑
author:wzt 2013.04.28 以前写stm32串口的程序只是简单的要么用查询要么用中断的方法来进行一些简单的发送接收。最近又用到usart,按照之前的思路进行了同样的配置,发现一个现象就是程序会一直自动的进入中断程序从而我在main函数中写到其他程序根本就没有机会运行。然后网上又对照了别人的程序代码进行配置结果依然一样。当然硬件问题我已经排除过了,所以为了解决不得又重新深入看数据手册。才发现我参考的代码本身就是误导人的。下面我贴出自己的代码然后一点点分析: //名称:USART_Config //功能:对串口1进行初始化,数据位8位,停止位1位,无奇偶校验位 //入口参数:波特率设定值 //出口参数:无 voidUSART_Config(u16 Baud_Rate) { USART_InitTypeDef USART_InitStructure; GPIO_InitTypeDef GPIO_InitStructure2; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);//使能USART1的时钟。USART1为APB2 USART1,3为APB1 GPIO_StructInit(&GPIO_InitStructure2); GPIO_InitStructure2.GPIO_Pin=GPIO_Pin_9; GPIO_InitStructure2.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure2.GPIO_Mode=GPIO_Mode_AF_PP; //TX引脚配置为复用输出 GPIO_Init(GPIOA,&GPIO_InitStructure2); GPIO_InitStructure2.GPIO_Pin=GPIO_Pin_10; GPIO_InitStructure2.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure2.GPIO_Mode=GPIO_Mode_IN_FLOATING; //RX引脚配置为浮空输入 GPIO_Init(GPIOA,&GPIO_InitStructure2); USART_StructInit(&USART_InitStructure); USART_InitStructure.USART_BaudRate=Baud_Rate; //波特率设定 USART_InitStructure.USART_WordLength=USART_WordLength_8b; //8位数据位 USART_InitStructure.USART_StopBits=USART_StopBits_1; //1位停止位 USART_InitStructure.USART_Parity=USART_Parity_No; //无奇偶校验 USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//无硬件流控制 USART_InitStructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx; //发送和接收双向模式 USART_Init(USART1,&USART_InitStructure); USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //打开接收中断 USART_ITConfig(USART1,USART_IT_TC,ENABLE); //打开发送完成中断 USART_Cmd(USART1,ENABLE); //使能串口1 USART1_NVIC_Config(); //配置USART1中断 } //名称:USART1_NVIC_Config //功能:串口1中断分组,配置优先级 //进出参数:无 static voidUSART1_NVIC_Config() { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //优先级组设置为2(可以是0——4) /*****************串口1中断配置******************/ NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn; //外部中断0 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; //抢占1 NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; //子优先级0 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); } 先看下红色部分USART_Init(USART1,&USART_InitStructure);这个函数, USART_InitStructure这个参数是个结构体类型的指针,这个结构体内有六个参数可以按照上面的配置就行,想更改波特率停止位,奇偶校验位等等都通过它来初始化,上面的注释写的已经很清楚啦,其他更详细的其他参数就要参考库函数的参考手册啦。 然而导致程序不断进入中断的问题关键是上面蓝色那句:USART_ITConfig(USART1,USART_IT_TC,ENABLE); 这一句是我修改过的,而原来是这样写的USART_ITConfig(USART1,USART_IT_TXE,ENABLE);关键就是两个函数参数不一样:一个用到USART_IT_TC,一个用到USART_IT_TXE。为什么产生这种现象在我们再看一下中断函数后再进行分析: void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE)!= RESET) //处理接收到的数据 { USART_ClearITPendingBit(USART1,USART_IT_RXNE); } if (USART_GetITStatus(USART1, USART_IT_TXE)!= RESET) //发送中断 { USART_ClearITPendingBit(USART1,USART_IT_TXE); USART_ITConfig(USART1, USART_IT_TXE, DISABLE); USART_ITConfig(USART1, USART_IT_TC, ENABLE); } if (USART_GetITStatus(USART1, USART_IT_TC)!= RESET) //发送完成 { USART_ClearITPendingBit(USART1,USART_IT_TC); USART_ITConfig(USART1, USART_IT_TC,DISABLE); } } 看到紫色的部分代码是我在网上查到资料时别人写的,后来我自己的代码都给删掉啦,因为在上面USART_Config函数中只打开啦USART_IT_TC和USART_IT_RENE中断,没有打开USART_IT_TXE中断,所以在中断处理函数中也就不需要这部分紫色的代码。另外紫色字体的代码还有一个错误USART_ClearITPendingBit(USART1,USART_IT_TXE);为什么说它错,因为这个USART_IT_TXE标志位根本就不支持软件清除,只能通过对USART_DR寄存器的写操作由硬件清除。我之前一直进入中断也就是打开了USART_IT_TXE的中断使能,然后进入中断却试图使用软件清除以至于不起作用,还是不断的进入中断函数中去。 USART一共有十个中断源,如下列表: USART_FLAG_CTS: CTS Change flag (not available for UART4 andUART5) USART_FLAG_LBD: LIN Break detection flag USART_FLAG_TXE: Transmit data register empty flag USART_FLAG_TC: Transmission Complete flag USART_FLAG_RXNE: Receive data register not empty flag USART_FLAG_IDLE: Idle Linedetection flag USART_FLAG_ORE: OverRun Error flag USART_FLAG_NE: Noise Error flag USART_FLAG_FE: Framing Error flag USART_FLAG_PE: Parity Error flag 而中间可以使用软件清除的只有橘黄色的四个。而对于一般作为串口使用的我们一般只用到两个就够啦:USART_FLAG_TC(串口数据发送完中断,这个发送完指的是一帧的数据发送完,按我的配置也就是八个数据位一个停止位发送完),USART_IT_RXNE(串口接收数据中断)。而很多人在配置的时候使用的却是USART_FLAG_TXE,这个数据手册写的也很清楚,指的是发送寄存器空中断,并不是发送完成中断,要是打开这个中断的话只要发送的数据从发送寄存器移出就会进入中断,所以我们在不发送数据的时候一定要记得把这个中断关闭要不然就会像我最初的一样不断进入中断函数中去。 那是不是这个USART_IT_TXE就没什么用处了呢,其实不是,这个在连续发送数据的时候打开这个中断判断发送数据寄存器是否为空而能够更迅速的做出反应把数据写入发送寄存器,但是一定要在不发送的时候把它给关闭。 还有在USART发送数据之前都需要进行读取TC标志位,等待上一次发送完毕自动置1后才进行本次数据的发送。TC标志位初始值为1,一般不需要手动清零。先查询状态寄存器SR然后再写DR寄存器TC的值会自动清零,DR寄存器中的值发送完毕后TC标志位又会自动置1。 while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); USART_SendData(USART1,0x01);
|