STM32串口一直进中断解决方法(转帖)

STM32串口的问题(转帖)

今天在使用USART模块,遇到了一些问题并解决了,于是发贴共享。

问题描述:

在使用USART做串口通讯时,我只把接收中断打开,并设置抢占优先级为最低一个级别,而接收中断上一个优先级处理事情比较多,可能占用了2ms时间。当我使用9600波特率往下位机发送数据,速度非常快,就是一直按回车发!问题就出来,不到1分钟时间,通讯没有反应了。USART配置代码如下:

void uart_config(void)

{

USART_InitTypeDef USART_InitStructure;

USART_InitStructure.USART_BaudRate = UART_GetBaud(BaudRate);

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_InitStructure.USART_Clock = USART_Clock_Disable;

USART_InitStructure.USART_CPOL = USART_CPOL_Low;

USART_InitStructure.USART_CPHA = USART_CPHA_2Edge;

USART_InitStructure.USART_LastBit = USART_LastBit_Enable;

/* Configure USART1 */

USART_Init(USART1, &USART_InitStructure);

/* Enable USART1 receive interrupt */

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

/* Enable the USART1 */

USART_Cmd(USART1, ENABLE);

}

分析问题:

1.为什么没有通讯了?

通过仿真器仿真,发现程序一直进入接收中断中,由于我没有使用中断发送,于是程序就死在了接收中断,也就没有数据发送到电脑上来。接收中断代码如下:

void UART_Receive(void)

{

//正在处理上一条通讯,接收到数据不处理

if(bRecieveOK)

{

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)

USART_ClearITPendingBit(USART1, USART_IT_RXNE);

return;//processing receive data,don’t receive again

}

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)

{

if(MoudBusExpir == 0)

{

ucRcePtr = 0;

MoudBusExpir = 20;//50ms

}

else

MoudBusExpir = 20;

/* Read one byte from the receive data register */

ucRS485Buff[ucRcePtr++] = USART_ReceiveData(USART1);

/* Clear the USART1 Receive interrupt */

USART_ClearITPendingBit(USART1, USART_IT_RXNE);

}

2.为什么会一直跑到接收中断?

断点之后发现(USART_GetITStatus(USART1, USART_IT_RXNE)==RESET的,也就是说没有数据接收到也进了中断,而且在USART配置中我也只打开了接收中断!没有数据送过来应该是不可能进入中断的!

3.响应了什么中断?

我想通过函数(USART_GetITStatus()把所有中断状态都读出来,但失败了,USART_IT_XXX所有中断状态都是RESET!也就是说没有中断也进入到这个中断服务程序来了!?

4.找资料

STM32F10x微控制器参考手册(2009年12月第10版)P541发现如下说明:

也就是说只要接收中断打开,即RXNEIE设置为1,那么ORE中断也自动打开了。

可是USART_GetITStatus(USART1, USART_IT_ORE )== RESET!!!!

找到USART_GetITStatus(USART1, USART_IT_RXNE)函数,发现只有当USART_IT_ERR中断使能时,才能读到ORE中断。

在这里要指出这个BUG:产生ORE中断了,但使用USART_GetITStatus()函数却无法读到这个中断被SET起来!

5.把ORE中断标志位清除

既然找到了是什么中断,那么把相应的中断标志位清除,就应该可以了吧?

USART_ClearITPendingBit(USART1, USART_IT_ORE);

但是,结果是没有任何效果!清除之后,马上读ORE中断状态,USART_GetITStatus(USART1, USART_IT_ORE)==RESET.程序仍然跑死在接收中断。再使用另一个函数USART_GetFlagStatus(USART1, USART_FLAG_ORE) = SET,原来ORE标志位还没有清除。

6.问题解决

为什么清除不掉?头疼了,再找找资料,有发现,在P523页如下图:

接收中断程序改为:

void UART_Receive(void)

{

if (USART_GetFlagStatus(USART1, USART_FLAG_ORE) != RESET)//注意!不能使用if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)来判断

{

USART_ReceiveData(USART1);

}

//正在处理上一条通讯,接收到数据不处理

if(bRecieveOK)

{

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)

USART_ClearITPendingBit(USART1, USART_IT_RXNE);

return;//processing receive data,don’t receive again

}

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)

{

if(MoudBusExpir == 0)

{

ucRcePtr = 0;

MoudBusExpir = 20;//50ms

}

else

MoudBusExpir = 20;

/* Read one byte from the receive data register */

ucRS485Buff[ucRcePtr++] = USART_ReceiveData(USART1);

/* Clear the USART1 Receive interrupt */

USART_ClearITPendingBit(USART1, USART_IT_RXNE);

}

总结:

注意问题:1.USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);使能了接收中断,那么ORE中断也同时被开启了。

2.ORE中断只能使用USART_GetFlagStatus(USART1, USART_FLAG_ORE) 读到(没有使能USART_IT_ERR中断时)

BUG建议:1.在STM32库中,能不能修改USART_GetITStatus()函数对USART_IT_ORE中断的处理?也就是我只要打开了接收中断,那么有ORE中断时,我也能使用USART_GetITStatus(USART1,USART_IT_ORE)读到.

以上是网上查到的资料,stm32一直进中断,中断程序中有清中断标志!!!

一直进中断的原因很简单USART设置成了半双工模式USART_HalfDuplexCmd(USART1,ENABLE); //半双工模式

只要屏蔽该语句就好啦!亲自试验成功,至于为什么还不太清除。。。。

转自:http://hi.baidu.com/tylhot/blog/item/9fe6d0eddcdab836fcfa3c60.html

Source Insight tab的一些相关设置备忘(转)

问题:在Source Insight 里面编辑的程序,到别的编辑器中,原本整整齐齐的格式,变成乱七八糟,反之亦然解决办法:TAB符用四个SPACE(空格)代替 在很多大公司的编码规范中一般建议不使用TAB符,全部用四个SPACE(空格)代替,另外由于有些代码并不是自己编写,难免存在TAB符,所以需要进行替换。- source insight中显示TAB符: 
Options->Document Options 将 Visible tabs 打勾- source insight中将输入的TAB符转换为空格:  
1. Options->Document Options 将 Expand Tabs 打勾
2. TAB符宽度设置, 在TAB width中填入期望数值,一般为4个空格,即填4- source insight中将已有的TAB符转换为空格:
选择需要替换的文件,Edit – Special Edit – Tabs to Spaces  ultraedit的TAB都设为4个字符宽度  1.Advanced->Configuration 左栏Editor->Word wrap/Tab setting 右栏/Use spaces in   place of Tabs   /Indent Space 设为4 VC的TAB都设为4个字符宽度  Tools ->options->Tabs->Tab size, Indent size 设置4;单选insert Spaces 引用地址:http://blog.chinaunix.net/uid-20379123-id-1956579.html 1. SMART TAB的用法. 解决自动缩进. 

    新开一个PROJECT后,点Options->Document Options,弹出对话框后先在左上角选好要用的Document Type,主要就是设C Source File和C++ Source File,选好后点右边中间的Auto Indent调整缩进。单选里一定要点Smart,右边有两个复选框Indent Open Brace和Indent Close Brace,具体效果是如何的可以看SIS的HELP。 

    勾选Auto Indent和SMART的效果: 在C程序里, 如果遇到行末没有分号的语句,如IF, WHILE, SWITCH等, 写到该行末按回车,则新行自动相对上一行缩进四列. 

    勾掉indent Open Brace和Indent Close Brace的效果: 继上一段,在相对缩进行里, 如果输入”{“或”}”, 则自动和上一行列对齐。 

2.TAB键=4个SPACE 

    写代码时候很头痛的问题是在SIS界面里,即使设置好了Tab Width=4,按四个空格所显示的缩进,和按TAB键的缩进位置是不同的,后者要更靠里面三个字符的位置,但在左下角看到的Col=5都是一样的。这样的代码在SIS里看了不对齐,到PB里看了却是对齐的。而SIS里面看着对其的代码,在PB里面会差三格。现在发现Options-> Document Options里面的右下角Editing Options栏里,把Expand tabs 勾起来,然后确定。OK,现在TAB键的缩进和四个空格的缩进在SIS里面看起来就对齐咯! 引用地址:http://www.cnblogs.com/wucg/archive/2012/08/29/2662119.html

[转]Source Insight 3.5中文注释间有空格的一种处理方法

step1:
 options->style properties ​
 comment  
 …   
 comment To Do 
 里面的font->font name设置为“宋体”或其它中文字体就可以了!


 step2:
 options -> preferences -> syntax formatting 标签下  
 special comment styles不勾选此项;



 转自:http://fcy007.blog.163.com/blog/static/62180200811319565311/

win7旗舰版原版镜像文件下载、安装方法

Windows7 简体中文旗舰版 (MSDN官方发布正式版原版镜像)下载 


Windows 7 简体中文旗舰版官方原版( 32位 ) 
电驴下载32位 windows7 旗舰版原版镜像文件 
下载链接:[url= cn_windows_7_ultimate_x86_dvd_x15-65907.iso (2.43 GB) ]32位windows7旗舰版原版镜像文件[/url] 
Windows 7 简体中文旗舰版官方原版( 64位 ) 
电驴下载64位windows7旗舰版原版镜像文件 
下载链接:[url= cn_windows_7_ultimate_x64_dvd_x15-66043.iso (3.11 GB) ]64位windows7旗舰版原版镜像文件[/url] 

Windows7 安装方法①(安装完后是单系统) 



该Windows 7硬盘安装方法大全介绍了Windows 7下安装高版本的Windows 7,Vista下硬盘安装Windows 7,xp下硬盘安装Windows7等方法! 

一、windows 7系统下全新安装高版Windows7: 
1、下载windows7 7600 ISO镜像(RC或RTM),用虚拟光驱拷贝至非C盘(如D:\7600)  
2、开机按F8——修复系统——选择最后一项命令修复——在命令框输入“D:\7600\sources\setup.exe“(不带引号)  
3、进入安装界面、选择custom安装  
4、选择安装语言、格式化C盘  
5、OK了,装好后是一个纯系统(非双系统)。 


二、如果有vista安装盘的话,方法也很简单: 
1、下载windows7 7600 ISO镜像(RC或RTM),用虚拟光驱拷贝至非C盘(如D:\7600)  
2、BIOS中选择光驱启动,进入vista安装界面  
3、选择左下角修复计算机(自动搜索系统,提示加载驱动或关闭,选择关闭进入修复选项)  
4、选择最后一项命令修复,在命令框输入“D:\7600\sources\setup.exe“(不带引号),开始安装  
5、选择安装语言、格式化C盘 (即使C盘原本没有系统此法也可行) 

三、XP系统下全新安装windows 7: 
1、下载windows 7 7600ISO镜像(RC或RTM),用虚拟光驱拷贝至非C盘(如D:\7600)  
2、把D:\7600目录下的bootmgr和boot目录(其实只要里面的boot.sdi和bcd文件)拷贝到c盘根目录下,并在C盘根目录下建个sources文件夹。(XP下不需要取得管理员权限)  
3、把D:\7600\sources下的boot.win复制到C盘刚建的sources文件夹  
4、用管理员身份运行cmd,然后输入c:\boot\bootsect.exe/nt60 c: 提示successful(即成功了!)  
5、关闭cmd窗口重启计算机,自动进入安装界面,选择安装语言,同时选择适合自己的时间和货币显示种类及键盘和输入方式  
6、出现“开始安装界面”,(要注意了,不点击“现在安装”)点左下角“修复计算机”(repair mycomputer),进入”系统恢复选择”,选择最后一项”命令提示符”(commandprompt),进入DOS窗口  
7、输入“D:\7600\sources\setup.exe“(不带引号),开始安装  
8、选择安装语言、格式化C盘,就OK了  


四、vista系统下全新安装windows7(实践证明XP用此种方法也更加方便): 
1、下载windows 7 7600ISO镜像(RC或RTM),用虚拟光驱拷贝至非C盘(如D:\7600)  
2、复制D:\7600文件夹中的Boot、EFI、sources文件夹和bootmgr至C盘根目录下  
3、复制D:\7600\boot下Bootsect.exe至C盘根目录下  

第2部需取得管理员权限 
4、管理员身份运行cmd,输入c:\bootsect.exe/nt60 c:并回车(最好复制,中间有空格)  
5、重启系统自动进入安装界面,点左下角的修复计算机repair my computer)  
6、选择最后一项命令提示符,进入DOS窗口,输入D:\7600\sources\setup.exe进入安装界面  
7、选择安装语言、格式化C盘,就OK了

此文转至:http://bbs.pcbeta.com/viewthread-695496-1-1.html

记之备用。

[转]键盘的报告描述符的理解

本文摘自:http://bbs.ednchina.com/BLOG_ARTICLE_158362.HTM

二,键盘的报告描述符的理解

       在参考别人的例程实现了键盘跑起来的时候,你这时候应该会想问的是,为什么描述符要这样写呢?

       好的,我当初也有同样的疑问,那下面来简单说说键盘的报告描述符的含义。其它的描述符含义很明显,这里就不作详细讲解。

      报告描述符是HID类设备最重要的描述符,其实它相当于一个大的设备属性表,在主机端会有一个叫做Parser的东西,对在枚举阶段接收到的报告描述符进行解释,以完成对该HID设备的属性的了解。

      由于电脑圈圈前辈已经对这部分有过较详细的讲解了,我这只作为补充,供各位参考。

键盘的报告描述符:

const uint8 KeyBoardReportDescriptor[63] =

{

    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)

    0x09, 0x06,                    // USAGE (Keyboard)

    0xa1, 0x01,                    // COLLECTION (Application)

    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)

//(1)

    0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)

    0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)

    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)

    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)

    0x75, 0x01,                    //   REPORT_SIZE (1)

    0x95, 0x08,                    //   REPORT_COUNT (8)

    0x81, 0x02,                    //   INPUT (Data,Var,Abs)

//(2)

    0x95, 0x01,                    //   REPORT_COUNT (1)

    0x75, 0x08,                    //   REPORT_SIZE (8)

    0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)

//(3)

    0x95, 0x05,                    //   REPORT_COUNT (5)

    0x75, 0x01,                    //   REPORT_SIZE (1)

    0x05, 0x08,                    //   USAGE_PAGE (LEDs)

    0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock)

    0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)

    0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)

//(4)

    0x95, 0x01,                    //   REPORT_COUNT (1)

    0x75, 0x03,                    //   REPORT_SIZE (3)

    0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)

//(5)

    0x95, 0x06,                    //   REPORT_COUNT (6)

    0x75, 0x08,                    //   REPORT_SIZE (8)

    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)

    0x25, 0xFF,                    //   LOGICAL_MAXIMUM (255)

    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)

    0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))

    0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)

    0x81, 0x00,                    //   INPUT (Data,Ary,Abs)

    0xc0,                              //  END_COLLECTION

};  

       在这为了容易表达,把上面键盘的报告描述符除开头与尾分成五部分

(1)这部分实际上为键盘的八个控制键,包括:左/右CTL,在/右ALT,在/右SHIFT,左/右WIN键盘,所以其范围为如下所示(HID Usage Tables.pdf从54页开始,展示了所有的keyborad page)   

1>

    0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)

    0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)

2>

       八个键一个键对应于一个位所以:

    0x75, 0x01,                    //   REPORT_SIZE (1)

    0x95, 0x08,                    //   REPORT_COUNT (8)

report size单位为bit,report count为8,所以1*8共占用一个字节;

3>由于按键的值要么为1(按下),要么为0(松开),所以逻辑最大值为1,最小值为0

    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)

    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)

4>由于按键为输入(对主机来说),所以为INPUT,并且为数据(Data),变量(var),绝对值(Abs)

    0x81, 0x02,                    //   INPUT (Data,Var,Abs)

(2)这部分由于键盘数据的八个字节的第二个字节是保留的(第一个字节就是上面所描述的控制键部分),所以

    0x95, 0x01,                    //   REPORT_COUNT (1)

    0x75, 0x08,                    //   REPORT_SIZE (8)

    0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)

1bit*8 = 1 byte ,前且为常量。

(3)该部分LED输出,即如键盘上的大小灯,数字锁定灯等,只用了五个,所以report count为5.

(4)由于(3)部分只用了5个bits,但发送肯定是一字节一字节地发送,所以要把不用的3个bits也要凑起来,但其又是没有实际意义的,所以定义为常量。

    0x95, 0x01,                    //   REPORT_COUNT (1)

    0x75, 0x03,                    //   REPORT_SIZE (3)

    0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)

(5)这部分主要就是六个字节的键盘键值了(一个字节表示一个键),所以一次最多可以发送六个键值,即六个按键按下(当然有没有效,操作系统说了算,一般三个键同时按下系统就报错),所以这一整个报告描述符,包括一组输入的键,一组输出的LED。键一共有八个字节,即一起发送要发八个字节的数据,第1个字节是八个控制键,第2个字节是保留,第三至第八个字节为普通按键键值,没有固定位置,只需要往上填上HID Usage Tables上的键值系统即会确认为该键按下。输出的LED只有一个字节,一个位对应一个LED灯,只使用了五个位。

    0x95, 0x06,                    //   REPORT_COUNT (6)

    0x75, 0x08,                    //   REPORT_SIZE (8)

    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)

    0x25, 0xFF,                    //   LOGICAL_MAXIMUM (255)

    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)

    0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))

    0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)

    0x81, 0x00,                    //   INPUT (Data,Ary,Abs)

report size为8bits,有6个,所以刚好是六个字节。

其它的跟上面介绍一样的意思,不再多说。

简单解释后,我们来看看上一篇博文里附带的例程中的键值发送部分:

   case 0:

    break;

   case 1:

    break;

   case 2:input_buf[2] =   0x53;//NUM LOCK

    break;

   case 3:input_buf[3] =   0x58;//回车

    break;

   case 4:input_buf[4] =   0x59;//1 (以下均为小键盘数字,需按下NUM LOCK)

    break;

   case 5:input_buf[5] =   0x5a;//2

    break;

   case 6:input_buf[6] =   0x5b;//3

    break;

   case 7:input_buf[7] =   0x5c;//4

    break;

   case 8:input_buf[2] =   0x5d;//5

    break;

   case 9:input_buf[3] =   0x5e;//6

    break;

   case 10:input_buf[4] =  0x5f;//7

    break;

   case 11:input_buf[5]=   0x60;//8

    break;

   case 12:input_buf[6] =  0x61;//9

    break;

   case 13:input_buf[7] =  0x55;//*

    break;

   case 14:input_buf[2] =  0x56;//-

    break;

   case 15:input_buf[3] =  0x53;//NUM LOCK

    break;

   default: 

    break;

其中,input_buf为八个字节大小的数组,发送时直接发送这个数组即可完成键值传送。input_buf[0]没用上,记得是一位对一个控制键即可,自己根据情况加上。

input_buf[1]为保留字节,所以不使用。其余的,从input_buf[2]-input_buf[7]可以直接给键值,而且不限位置,所以一个101键的标准键盘可以使用这六个字节全部表达完毕,确实是很巧妙的写法,不得不佩服制定协议的前辈们。

好了,报告描述符的介绍就说到这,鼠标的也是同样的分析方法。另外在电脑圈圈的例程里,还有HID英文协议里,USB之人性化介面装置的报告描述元(1)(2)(3)三篇(林锡宽)这些文章也很详细讲解了报告描述符,建议在看这篇博文前,先把刚刚提到的这几篇文章,例程,英文协议的相关部分过目理解一遍后再看,才可起到辅助的作用。