加我模型论坛

 找回密码
 注册
搜索
热搜: 活动 交友 discuz
查看: 4311|回复: 3

我在PIC单片机开发中总结的经验教训-有关程序调试,采样,中断,指令,处理16位数据等问题

[复制链接]
发表于 2012-6-25 13:22:55 | 显示全部楼层 |阅读模式
本帖最后由 joyrus 于 2012-6-27 10:30 编辑

中断的使用注意事项:

1. 不是必须的情况下尽量不要使用中断处理,除非是实时性非常强的情况。例如要求延时不能超出几个微妙等。

2. 最好不要在中断中使用寄存器间接寻址,如改变FSR等操作,否则必须要对FSR做保护。而且用间接寻址会增加指令周期。经过本人的亲身经历教训证明如果在主程序中使用了FSR做间接寻址的操作,而忽略了在中断中对FSR保护,那么在中断对FSR操作就会造成无法预计的错误,比如毫不相干的寄存器内容莫名其妙的被改写了。这在使用单步或者自动单步等非全速运行测试的情况下可能不会出现,一旦真正在全速运行或者实际运行时就会随机出现!因为很可能主程序在进行间接寻址的过程中进入了中断!

解决的办法是进入中断后保护FSR,或者使用预先设定的立即数直接加数据缓冲区的首地址的直接寻址,例如:

movf     address,w        ;取寄存器address的数据
处理w的数据

movf     address+n,w    ;取寄存器address后n个寄存器的数据
处理w的数据

这个n可以是直接用数字,也可以是一个之前已经用EQU定义的一个数字。这样如果缓冲区数据比较多,会质疑程序代码会变得很长,但是实际上这是在中断程序中,所以一般处理的数据都不会很长可以一个个处理,而且这样执行的代码反而由于不需要对FSR进行操作而是实际运行的指令周期减少了,只是会增加程序空间的使用。

3. 不要在中断中进行复杂的操作,要保证不错过任何的中断,也就是在中断所消耗的指令周期一定要小于系统中最小的中断请求间隔时间。否则就不能使中断的实时性得到体现,那就根本需要使用中断了。

4. 在主程序中适时地要禁止中断,比如在对一个中断中要使用的16位的数据进行写操作的时候,就必须保证在写的整个过程中,不能相应需要使用到这个数据的中断请求,或者就暂时禁止所有中断。

为了对中断的延时影响降到最低,可以使用这个的方法,如果中断中需要使用L1,H1这一组16位数据。那么在中断中不要直接使用他们,而使用他们的影子寄存器(复制一个拷贝)TL1,TH1。这样就只要在L1和H1刚刚计算得到结果后立即保护L1,H1复制到TL1,TL2的过程即可,这个复制过程一般就几个指令周期。而L1和H1的计算过程就不许要保护,这个过程可能就比较长了。

5. 不要在中断中调用子程序。另一种情况(我还未尝试)?是否可以把子程序定义在中断代码空间内来调用?但绝对不要调用有嵌套的子程序!也不要在中断中在打开中断请求也就是说绝对不要在中断中把GIE置1。

6. 不要在中断中goto到中断外的代码。

对于中断就暂时先聊这些。
 楼主| 发表于 2012-6-25 14:10:47 | 显示全部楼层
本帖最后由 joyrus 于 2012-6-25 14:11 编辑

再说说指令容易忽视的问题。

我在我的第二个单片机开源项目——全比例模型遥控器摇杆位置采样程序

中使用了求16位数据补码的过程,问题就来了。

这是一个标准的求8位补码的指令,很简单
comf     number,f     ;求反
incf       number,f     ;加1

那么16位数据就要分别对高低两次求反并低位加1
comf     number,f         ;低位求反
comf     number+1,f     ;高位求反
incf       number,f         ;低位加1

这样就有问题了,低位加1后可能会出现低8位向高8位进位,修改如下:
comf     number,f         ;低位求反
comf     number+1,f     ;高位求反
incf       number,f         ;低位加1
skpnc                         ;是否有进位
incf       number+1,f    ;有进位高8位加1

问题解决了?实际执行后我发现了问题!问题很简单,incf虽然也是加法指令但是他实际上是不改变STATUS中进位标志C的!

这样16位数据求补码我就用addf来实现了。
comf     number,f         ;低位求反
comf     number+1,f     ;高位求反
movlw   0x01              ;w送1
addf     number,f         ;低位加W
skpnc                         ;是否有进位C=0无进位跳过下条指令
incf       number+1,f    ;有进位高8位加1

这样问题就解决了!
 楼主| 发表于 2012-6-26 12:08:46 | 显示全部楼层
说说有关采样的问题,在很多书籍中都提到过了。
比如:
1. 采样时间的问题,ADC使用的时钟周期不能小于1.6us。如果是4MHz晶振那就要2分频得到2us的采样时钟周期。

2. 在开始进入采样前也就是GO置1之前,必须保证被采样的那个通道已经提前被选择至少十几个微妙。这样就保证了采样电容有足够的时间充放电,保证采样数据的准确。比较好的方发是在取走采样数据后立即切换到下个需要采样的通道,这样就可以在处理完本通道的数据之后,立即采样下一个通道,而不必特地等待的时间。
 楼主| 发表于 2012-6-26 12:19:44 | 显示全部楼层
本帖最后由 joyrus 于 2012-6-26 12:22 编辑

再说说程序调试的问题:

1. 如果程序运行错误(绝对)不要怀疑单片机出了问题,如果使用现成的开发板,一般外围硬件也可以信赖。

2. 如果程序运行错误,比如明明执行了赋值的操作却在watch中看不到寄存器的值有变化,这很可能是没有选择到正确的Bank

3. 如果确定Bank无误,则在watch中去掉这个寄存器,再重新加入到watch中可能就ok了。

4. 如果还是不能正常工作,则关闭开发板的电源,再拔出PICKit3。重新插入PICKit3再打开开发板电源,再测试,一般问题就会解决。

5. 如果在非全速模式下程序运行正常而在全速运行中出现问题,则一般都是程序造成的。很可能是在某些部位的程序跳转或者使用了间接寻址,而没有充分的对所在程序或者内存空间的位置进行分析并妥善处理相关寄存器数据的等问题造成的。

6. 在调试中出现错误,也不要都认为是程序的问题,在修改程序时注意备份,以防止修改后反而出现了新的问题!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|JOYRUS.com

GMT+8, 2019-7-18 07:04 , Processed in 0.071939 second(s), 16 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表