搜索
bottom↓
回复: 26

难道我记错了?至少4次 asm(“nop”)才能读出准确的PIN数据, 不是说一次就够了吗?

[复制链接]
头像被屏蔽

出0入0汤圆

发表于 2008-6-3 21:32:42 | 显示全部楼层 |阅读模式
注: 本贴的答案,请看【16楼】 machao 的测试

---------------------------

我用GCC编写一段测试代码,我记得输出改为输入时一个时钟是需要延时的。

但实际测试时,发现至少加入四句  asm("nop") 才能正常。

那位可以说出原因及解决的方法? 谢谢。

注:我是使用 WINAVR 060421版本,及AVR STUDIO 4.13 SP2 版本。 M16芯片,工作了1M 内部RC。




//PA0,PA1输入 无上拉电阻, 预期读出的均是0
DDRA&=0b11111100;
PORTA&=0b11111100;
asm("nop");
asm("nop");
asm("nop");
asm("nop");
if ((PINA&0b00000011) != 0x00) red_led();

//PA0,PA1输入 有上拉电阻, 预期读出的均是1
DDRA&=0b11111100;
PORTA|=0b00000011;
asm("nop");
asm("nop");
asm("nop");
asm("nop");
if ((PINA&0b00000011) != 0x03) red_led();

//PA0输出1, PA1输入无上拉电阻所以缺省是0,PA1预期读入是1
DDRA|=0b0000001;
PORTA|=0b00000001;

DDRA&=0b11111101;
PORTA&=0b11111101;

asm("nop");
asm("nop");
asm("nop");
asm("nop");

if ((PINA&0b00000010) != 0x02) red_led();

出0入10汤圆

发表于 2008-6-3 21:36:37 | 显示全部楼层
输出改为输入几个nop还是不够的 要可靠还要多些

出0入10汤圆

发表于 2008-6-3 22:01:17 | 显示全部楼层
to 站长
输出改为输入有一个稳定的过程 和管子的导通及关断时间有关系 还有电平也要有一个稳定时间

出0入0汤圆

发表于 2008-6-3 23:54:40 | 显示全部楼层
不明白LZ做何测试.

但理解有误:正确的理解是PINA上的电平变化,需要经过1-2个CLK后才能反映到CPU的内部,换句话讲,CPU读到的PINA电平,是2个(实际是1.5个)CLK之前的电平值.
头像被屏蔽

出0入0汤圆

 楼主| 发表于 2008-6-4 01:05:07 | 显示全部楼层
不过我真的是测出3个nop也不行的,需要4个才行。

开始没有留意这个问题,仿真的时候(JTAG连接硬件)可以正常通过的。但在硬件上独立运行就有问题。

出50入0汤圆

发表于 2008-6-4 01:30:13 | 显示全部楼层
我的按键扫描程序,4*4的矩阵键盘:
//按键检测,返回值为0xff表示无效按键
uchar key (void)
{
   uchar key_x,key_y;

   keyline_PORT=0x0f;               //置为高4位输出0,低4位上拉输入
   keyline_DDR=0xf0;
   nop;nop;                         //2个nop即可
   
   key_x=keyline_PIN;
   if ((key_x&0x0f)!=0x0f)
    {
          delay_ms (10);                 //延时10MS
          
          key_x=keyline_PIN;
          if ((key_x&0x0f)!=0x0f)
            key_x&=0x0f;                //保存低4位有效值
          else
            return 0xff;
          
          keyline_PORT=0xf0;            //置为高4位上拉输入,低4位输出0
           keyline_DDR=0x0f;
           nop;nop;                           //2个nop即可
          
          key_y=keyline_PIN;
          if ((key_y&0xf0)!=0xf0)
           {
             key_y&=0xf0;                //保存高4位有效值
             return (pgm_read_byte (key_value+(key_x|key_y)-0x77));
           }
          else
            return 0xff;
        }
   else
     return 0xff;
}
头像被屏蔽

出0入0汤圆

 楼主| 发表于 2008-6-4 03:13:42 | 显示全部楼层
见鬼了。刚才将四句nop删除只余下一句,工作起来仍好像很可靠 :(

但之前调试时却有问题。(注:使用全新的M16-16AU,用弹性测试座更换芯片测试)。

出0入0汤圆

发表于 2008-6-4 06:19:20 | 显示全部楼层
从什么时候,阿莫也搞起技术了?
头像被屏蔽

出0入0汤圆

 楼主| 发表于 2008-6-4 08:07:54 | 显示全部楼层
呵呵,我正在编写拆机AVR芯片的检测程序:

本来是交给技术人员编写的,但看了几个版本后,觉得心里没有底。

求人不如求已。自己动手 :)


(原文件名:SNAG-0014.jpg)

出0入0汤圆

发表于 2008-6-4 08:15:44 | 显示全部楼层
延迟是I/O脚上的电容所致。时间由电容量和驱动方的内阻决定,不能说死几个nop()就行了的。
比如一种简易触摸开关的做法就是:在I/O口上拉MΩ级电阻,处理器先用'L'驱动一下然后改成输入,从恢复'H'的延迟时间判断该点有没被触摸。

出0入0汤圆

发表于 2008-6-4 09:06:48 | 显示全部楼层
IO检测程序里还可以再写 void 函数???还没这样写过。

出0入0汤圆

发表于 2008-6-4 09:18:30 | 显示全部楼层
长知识了

出0入0汤圆

发表于 2008-6-4 13:10:35 | 显示全部楼层
莫老板居然还有时间写代码.

出0入0汤圆

发表于 2008-6-4 16:06:42 | 显示全部楼层
函数嵌套定义,是gcc的c扩展功能(c++扩展没有)。不过,一般应当尽量避免使用编译器扩展功能,否则移植性差。

出0入0汤圆

发表于 2008-6-4 18:07:58 | 显示全部楼层
确实有这个问题。。。

出0入12汤圆

发表于 2008-6-4 18:49:45 | 显示全部楼层
绝缘好,泻放不出去。

出0入0汤圆

发表于 2008-6-4 21:00:13 | 显示全部楼层
明白阿莫做什么了,我做了点测试,提供你参考.

环境:CVAVR,AVR-51板,M16,内部RC1M,和外部晶体12M.

代码1:
#include <mega16.h>

// Declare your global variables here

void main(void)
{
    PORTA=0x00;
    DDRA=0xff;              //PORTA输出0
   
    PORTB=0xff;
    DDRB=0xff;              //portb控制LED指示
   
    DDRA &= 0b11111100;
    PORTA |= 0b00000011;    //PA0,PA1转输入,上拉有效
   
    #asm("nop");
    //#asm("nop");
    //#asm("nop");
    //#asm("nop");

    if ((PINA & 0b00000011) != 0x03) PORTB = 0X00;
   
    while (1)
    {
    };
}
结果:内部RC1M时需要1个nop, 外部晶体12M时需要3个nop
==============================================================
代码2:

#include <mega16.h>

// Declare your global variables here

void main(void)
{
    PORTA=0x00;
    DDRA=0xff;              //PORTA输出0
   
    PORTB=0xff;
    DDRB=0xff;              //portb控制LED指示
   
    PORTA |= 0b00000011;    //PA0,PA1输入,上拉有效
    DDRA &= 0b11111100;

    if ((PINA & 0b00000011) != 0x03) PORTB = 0X00;
   
    while (1)
    {
    };
}

结果:注意代码2仅仅是将PA的设置顺序换了一下(按手册上的推荐介绍转换设置次序),不管是内部1M还是外部12M,一个nop也不要(当然,DDRA &= 0b11111100本身相当3个nop).
                 ;      24     PORTA |= 0b00000011;    //PA0,PA1输入,上拉有效
000061 b3eb              IN   R30,0x1B
000062 60e3              ORI  R30,LOW(0x3)
000063 bbeb              OUT  0x1B,R30                     <======此处改变PA1,PA0,输出高电平了.
                 ;      25     DDRA &= 0b11111100;
000064 b3ea              IN   R30,0x1A
000065 7fec              ANDI R30,LOW(0xFC)
000066 bbea              OUT  0x1A,R30                     <======此处PA1,PA0变成输入
=============================================================================================
测试过程中,所有硬件外围不变,也不动,环境一样.只是改程序,改熔丝位设置系统时钟类型,下执行代码.
看过手册,找不到确切的说明,提供参考.


另外,I/O设置成高阻输入,读PIN口的值是不稳定的,因为空间的电磁干扰会改变PIN的值.因此我认为采用上面的方法检测PIN口的是低电平或高电平要商榷.

建议:对于要测试I/O输入的话,在相应的I/O口对地接一个200K电阻.测试程序如下:

输入0的测试:
void main(void)
{
    PORTA=0xff;
    DDRA=0xff;              //PORTA输出1
   
    PORTB=0xff;
    DDRB=0xff;              //portb控制LED指示
   
    PORTA = 0b11111100;    //PA0,PA1输出0,转输入时,上拉无效
    DDRA &= 0b11111100;    //转输入
   
    //#asm("nop");
    //#asm("nop");
    //#asm("nop");
    //#asm("nop");

    if ((PINA & 0b00000011) == 0x00) PORTB = 0X00; // OK!
   
    while (1)
    {
    };
}


输入1的测试:
id main(void)
{
    PORTA=0x00;
    DDRA=0xff;              //PORTA输出0
   
    PORTB=0xff;
    DDRB=0xff;              //portb控制LED指示
   
    PORTA |= 0b00000011;    //PA0,PA1输出1,转输入时,上拉有效
    DDRA &= 0b11111100;     // 转输入
   
    //#asm("nop");
    //#asm("nop");
    //#asm("nop");
    //#asm("nop");

    if ((PINA & 0b00000011) == 0x03) PORTB = 0X00;  //OK
   
    while (1)
    {
    };
}

为了保险,可以增加几个nop.上面的测试我做过简单的验证了.见笑.
头像被屏蔽

出0入0汤圆

 楼主| 发表于 2008-6-5 01:27:51 | 显示全部楼层
哈,谢谢马老师的测试。本贴能置COOL了。

出0入0汤圆

发表于 2008-6-5 08:07:39 | 显示全部楼层
这个测试用nop比较麻烦,只要输出后立即while,达到所需输出即可.

出0入0汤圆

发表于 2008-6-13 01:03:08 | 显示全部楼层
学习

出0入0汤圆

发表于 2009-5-6 16:28:13 | 显示全部楼层
只有学习的份了。

出0入0汤圆

发表于 2009-5-6 16:55:37 | 显示全部楼层
也就是做矩阵键盘扫描时在行输出后列输入脚要反复读2次以上吧

出0入0汤圆

发表于 2009-5-6 18:58:42 | 显示全部楼层
学习了;老帖有味道啊!!呵呵!

出0入0汤圆

发表于 2009-5-6 23:41:40 | 显示全部楼层
hehe,只有看帖的份,长知识了

出10入8汤圆

发表于 2009-5-7 10:31:38 | 显示全部楼层
MARK

出0入0汤圆

发表于 2009-5-7 12:22:15 | 显示全部楼层
是不是说这这样设置不好:
    DDRA &= 0b11111100;
    PORTA |= 0b00000011;

改成:
    DDRA &= 0b11111100;
    PORTA |= 0b00000011

就一点问题也没有,一个NOP都不需要,对吧?

出0入85汤圆

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

本版积分规则

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

GMT+8, 2024-5-6 10:25

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

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