搜索
bottom↓
回复: 54

LGT端口输入寄存器PINA/B/C/D 正确使用方法 【重要,与AVR不同】

  [复制链接]

出0入0汤圆

发表于 2012-6-7 11:02:15 | 显示全部楼层 |阅读模式
在另一个帖子讨论到,重新开个帖子方便需要的人
---------------------------------------------------------------------------------------

手册资料:
考虑到软件能够及时获得端口信号的变化, PINA/B/C/D输入为异步设计,直接反应端口的状态。但这样的做法也同时带来了一些信号同步的问题。建议用户在直接使用端口状态进行程序流程控制时,采用必要的软件滤波算法。 同时也避免直接使用PINA/B/C/D寄存器的值进行程序流程控制,而是首先使用IN指令将其读到内部寄存器,然后使用寄存器的值作后续处理。下面将给出建议的使用端口作为程序流程控制的代码

汇编代码实例
Label:
in r16, PINA
; Skip if PINA[1] is clear, avoid to use sbic directly
sbrc r16, 1
; Skip if PINA[1] is set, avoid to use sbis directly
sbrs r16,1
…..
C语言代码实例
volatile unsigned char pv; /*volatile is necessary to disable optimize on ‘pv’ */
/* wait until PINA[1] is set */
do {
pv = PINA;
} while ((pv&0x2) != 0x02); /* avoid to use while(PINA&0x2) */



手册中提到的这个问题其实很严重,如果没有按照手册中代码写,你的程序很可能运行着就自动复位或者跑飞了。 详细原因手册没有提及。简单原因就是LGT sbic 和 sbis指令针对PINA/B/C/D这几个寄存器操作有局限性。 只有当PIN脚的电平确定,不会变化时才可以用。其它内部IO,由于电平在一个指令周期内确定,因此不受影响。

因此我们在AVR中常用的,比如说检测一个按键 if(!(PINA & 1<<PA0)){xxx} 这样的代码在LGT中就不可以使用了。需要这样:
  1. volatile unsigned char tempPina;
  2. tempPina = PINA;
  3. if(!(PINA & 1<<PA0)){xxx}
复制代码
那个变量必须加volatile限定,不然编译器会自动忽略这个变量,直接使用sbic指令了。

但是这样写法大大降低了效率,查看反汇编会发现,多了两条指令。总共需要4条指令。 4个时钟周期,如果是AVR的话,一条sbic需要2个时钟周期,这样LGT的速度就没AVR快了。
  1.         {
  2.                 volatile unsigned char tempPina;
  3.                 tempPina = PINA;
  4.   9e:        80 b1               in        r24, 0x00        ; 0
  5.   a0:        89 83               std        Y+1, r24        ; 0x01
  6.                  if(!(tempPina & 1<<PA0))
  7.   a2:        89 81               ldd        r24, Y+1        ; 0x01
  8.   a4:        80 fd               sbrc        r24, 0
  9.   a6:        fb cf               rjmp        .-10             ; 0x9e <main+0xa>
复制代码
那如何改进呢。 这里提供一个方法,把PINA重新定义一下。其它端口同理。
  1. inline unsigned char LGT_PINA()
  2. {
  3.         register unsigned char temp;
  4.         temp=PINA;
  5.         asm volatile ("" : "+r"(temp));
  6.         return temp;        
  7. }
  8. #undef PINA
  9. #define PINA LGT_PINA()
复制代码
这样代码可以写的和以前AVR一样:
if(!(PINA & 1<<PA0)){xxx}

看一下反汇编效果:
  1. inline unsigned char LGT_PINA()
  2. {
  3.         register unsigned char temp;
  4.         temp=PINA;
  5.   94:        80 b1               in        r24, 0x00        ; 0

  6. int main(void)
  7. {
  8.         while(1)
  9.         {
  10.                  if(!(PINA & 1<<PA0))
  11.   96:        80 fd               sbrc        r24, 0
  12.   98:        fd cf               rjmp        .-6              ; 0x94 <main>
  13.                  {
  14.                          asm("nop");
  15.   9a:        00 00               nop
  16.   9c:        fb cf               rjmp        .-10             ; 0x94 <main>
复制代码
这样就是两条指令了。 一个 in,一个sbrc 达到跟直接写汇编一样的效果。




阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出1070入962汤圆

发表于 2012-6-7 11:05:09 | 显示全部楼层
标记一下,很重要

出0入0汤圆

发表于 2012-6-7 11:05:12 | 显示全部楼层
楼主好细心,学习了!

出0入0汤圆

发表于 2012-6-7 11:07:49 | 显示全部楼层
多谢波仔。这个绝对要MARK。

出0入0汤圆

发表于 2012-6-7 11:10:51 | 显示全部楼层
谢谢波仔的老爸。

出0入0汤圆

发表于 2012-6-7 11:12:16 | 显示全部楼层
这个用法太绝了!嵌入汇编......速度优化了。

出0入0汤圆

发表于 2012-6-7 11:21:37 | 显示全部楼层
谢谢的分享,  还有之前内存指针的帖子 建议版主置顶

出0入0汤圆

发表于 2012-6-7 12:07:48 | 显示全部楼层
要标记

出0入0汤圆

发表于 2012-6-7 12:18:05 | 显示全部楼层
必须顶。今早试过了,对比效果非常明显。
如果直接判定IO,当IO口加1MHZ的方波信号,会频繁复位
用了lz程序,测试到6MHZ都没问题。而且编译效率很好

出0入0汤圆

发表于 2012-6-7 13:25:38 | 显示全部楼层
楼主够细心的。

折腾LGT的人越多,资料也越完善

出0入147汤圆

发表于 2012-6-7 13:40:38 | 显示全部楼层
怪不得前两天调试的时候,将优化等级调为s后,一运行到按键扫描处就死机,后面只有加了volatile后解决,原来是这个原因。

出0入169汤圆

发表于 2012-6-7 13:46:26 | 显示全部楼层
重要内容。

出0入0汤圆

发表于 2012-6-7 14:01:30 | 显示全部楼层
logicgreen 发表于 2012-6-7 11:10
谢谢波仔的老爸。

为何谢他老爸?

出390入22汤圆

发表于 2012-6-7 14:14:07 | 显示全部楼层
这个要标记一下

出0入0汤圆

发表于 2012-6-7 14:57:08 | 显示全部楼层
本帖最后由 logicgreen 于 2012-6-7 15:20 编辑
plc_avr 发表于 2012-6-7 14:01
为何谢他老爸?


我错了,谢谢波仔。

出0入0汤圆

发表于 2012-6-7 15:05:34 | 显示全部楼层
哈哈,简单的逻辑推理

出0入0汤圆

发表于 2012-6-7 15:13:18 | 显示全部楼层
logicgreen 发表于 2012-6-7 14:57
波仔应该照片的那个小孩,LZ主应该就是波仔老爸,不对么?


你不知道乱说要打PP的!

出0入618汤圆

发表于 2012-6-7 15:16:04 | 显示全部楼层
logicgreen 发表于 2012-6-7 14:57
波仔应该照片的那个小孩,LZ主应该就是波仔老爸,不对么?

1.楼主叫波仔
2.照片是个美女

出0入0汤圆

 楼主| 发表于 2012-6-7 15:38:55 | 显示全部楼层
logicgreen 发表于 2012-6-7 14:57
我错了,谢谢波仔。

哈哈,照片是我女儿。去年刚生的。

出0入0汤圆

发表于 2012-6-7 15:48:10 | 显示全部楼层
学习学习了,多谢

出0入8汤圆

发表于 2012-6-7 15:54:17 | 显示全部楼层
曾经受此困扰,一直查不到原因,谢谢您提供的资料

出0入0汤圆

发表于 2012-6-7 21:01:22 | 显示全部楼层
关注一下

出0入0汤圆

发表于 2012-6-7 21:54:08 | 显示全部楼层
高手如云呀

出0入0汤圆

发表于 2012-6-7 22:10:15 | 显示全部楼层
又学了壹招~~~谢谢分享~~~

出0入0汤圆

发表于 2012-6-7 22:13:58 | 显示全部楼层
重要标记,现在关注下后续Ic的adc输入阻抗

出0入10汤圆

发表于 2012-6-7 23:16:39 | 显示全部楼层
这个重要

出0入0汤圆

发表于 2012-6-8 09:25:47 | 显示全部楼层
ADC输入应该内置一个采样保持,以降低输入阻抗。

出0入0汤圆

发表于 2012-6-8 09:42:52 | 显示全部楼层
zhiwei 发表于 2012-6-8 09:25
ADC输入应该内置一个采样保持,以降低输入阻抗。

不是吧,我还想要输入阻抗∞呢,你还要降低?

出0入0汤圆

发表于 2012-6-8 09:44:30 | 显示全部楼层
学习学习

出0入0汤圆

发表于 2012-6-8 10:59:09 | 显示全部楼层
呵呵。说错了,增大IC输入阻抗,减小对为外部阻抗要求。

出0入618汤圆

发表于 2012-6-8 11:21:30 | 显示全部楼层
zhiwei 发表于 2012-6-8 09:25
ADC输入应该内置一个采样保持,以降低输入阻抗。

一般来说SAR ADC必须有采样保持的,而且现在猜测LGT就是为了提高转换速度,把采样保持电容加大了才导致输入阻抗下降。
比较理想的做法是采样保持前面加个buffer,这又牵涉精度和成本问题了……

出0入0汤圆

发表于 2012-6-8 11:37:10 | 显示全部楼层
支持波仔,难怪之前按键检测不对,都扔一边了!

出0入0汤圆

发表于 2012-6-8 15:21:02 | 显示全部楼层
学习学习

出0入0汤圆

发表于 2012-6-8 16:26:18 | 显示全部楼层
波仔在小波没出生时就是这个名字了~~

波仔这篇写得非常不错,有很高的指导意义!

出0入0汤圆

发表于 2012-6-14 01:37:44 | 显示全部楼层
logicgreen 发表于 2012-6-7 11:10
谢谢波仔的老爸。

请问一下这个现象以后的版本中会不会得到改进么?

出0入0汤圆

发表于 2012-6-14 11:17:10 | 显示全部楼层
zhuisuoji 发表于 2012-6-14 01:37
请问一下这个现象以后的版本中会不会得到改进么?

以后的会改进。

出0入42汤圆

发表于 2012-6-14 14:14:28 | 显示全部楼层
mark ...   

出0入0汤圆

发表于 2012-6-14 15:52:20 | 显示全部楼层
我用IAR编译出现下面的错误,请问如何解决呢?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2012-6-14 16:40:01 | 显示全部楼层
标记一下

出0入0汤圆

发表于 2012-6-29 08:11:58 | 显示全部楼层
初学,看看

出0入0汤圆

 楼主| 发表于 2012-6-29 12:47:51 | 显示全部楼层
oste_ 发表于 2012-6-14 15:52
我用IAR编译出现下面的错误,请问如何解决呢?

这个我没用过IAR,不清楚IAR的内嵌汇编如何写

出0入0汤圆

发表于 2012-6-29 17:11:02 | 显示全部楼层
这个问题值得注意,谨慎使用SBIC,SBIS检测IO状态。

出0入0汤圆

发表于 2012-7-2 13:03:40 | 显示全部楼层
编译过度优化或强行优化是很讨厌的问题,可能给编程带来极大的困扰和麻烦,甚至隐患。

出0入0汤圆

发表于 2012-9-9 14:31:05 | 显示全部楼层
mark!!!!!!!!!!!!!!!!!!!!!!!!!!!!

出0入0汤圆

发表于 2012-9-13 12:08:00 | 显示全部楼层
强顶楼主

出0入0汤圆

发表于 2012-9-15 21:12:30 | 显示全部楼层
顶楼主

出0入0汤圆

发表于 2012-9-17 21:06:10 | 显示全部楼层
等待问题的解决

出0入0汤圆

发表于 2012-10-9 09:16:33 | 显示全部楼层
楼主能否说下PIN的输出用法,我用简单的一个“PORTC^=(1<<x)”命令对C端口操作,发现PC0能正常反转,C端口的其他端口都不能反转,郁闷了几天,现在还不知道怎么回事?注x=0,1,2,3
求答,谢谢!

出0入0汤圆

发表于 2012-11-4 13:20:40 | 显示全部楼层
inline unsigned char LGT_PINA()
{
        register unsigned char temp;
        temp=PINA;
        asm volatile ("" : "+r"(temp));
        return temp;        
}
#undef PINA
#define PINA LGT_PINA()   这种方法,有时候能识别,有时候不能识别啊。

出0入4汤圆

发表于 2012-11-8 23:39:19 | 显示全部楼层
分析的很有条理,学习了。谢谢

出0入0汤圆

发表于 2012-11-11 20:00:15 | 显示全部楼层
不错,学习了

出0入0汤圆

发表于 2012-12-8 17:45:54 | 显示全部楼层
准备使用LGT,顶。

出0入0汤圆

发表于 2012-12-10 15:47:00 | 显示全部楼层
谢谢,学习!!!

出0入0汤圆

发表于 2012-12-11 19:49:47 | 显示全部楼层
一个函数的跳转不会增加指令执行的时间吗?

出0入76汤圆

发表于 2013-5-11 12:58:53 | 显示全部楼层
zhonggp 发表于 2012-12-11 19:49
一个函数的跳转不会增加指令执行的时间吗?

使用的是内联函数...
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-24 17:45

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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