单片机引脚读写操作

自己总结下单片机引脚的用法。 

使用单片机时肯定会用到单片机的IO引脚。以51单片机P1口为例。内部结构如图所示 

 
当单片机进行写操作时,引脚锁存器(D触发器)CLK端接收有效电平,然后内部总线上需要写的数据就会通过D触发器传输到Q'。当写1时Q'为0,使MOSFET截止,因此外部引脚电平为1.当写0时Q'为1,MOSFET饱和导通,此时引脚可以看成接地,所以引脚为0。
 
如果对单片机IO口进行读操作。由图可以看出读操作包括读寄存器和读引脚。以前知道有这两种区别,但是从来没仔细区分过。从图中可以看出读寄存器时读寄存器上的三态缓冲器打开,Q端的值直接传到了内部总线上,而下面的读引脚三台缓冲器是高阻态,读引脚时则相反。
 
汇编语言中对读寄存器和读引脚做了一定的区别,但说实话我在看汇编代码时还是区分不清两者的区别。现在大家对单片机编程应该大部分采用的都是C语言,在我看来,C语言中已经极大的淡化了读寄存器还是读引脚的区别。
 
有些人说a=P1是读引脚(a是某个字符变量),P1=P1|0x00是读寄存器(可能是认为这里P1进行了一次逻辑运算,只有寄存器中的值才能进行逻辑运算),但我在用C语言时感觉用P1=P1|0x00也是读的引脚。也有些人说看经过编译器编译后的汇编代码才能分辩出两者的区别,不知道这里大家怎么看读引脚和读寄存器?
 
在读引脚时需要先向引脚锁存器中写1。因为如果引脚寄存器中是0的话会导通MOSFET,使外部端口一直是低电平,即使外面接的是高电平在读引脚的时候也读的是0。以前知道需要这样做,但读引脚的时候一直没写过1,发现读的也对,现在我觉得这样写不符合规范。
 
一般来说单片机在上电复位后默认引脚寄存器的值是1,这样一来关断了MOSFET,而我们在使用单片机的时候如果这个引脚作为输入,也不会让它变成一会儿输出一会儿输入,使得能够准确的读出外部端口的值。现在我在写程序时如果端口做为输入引脚,我会在初始化里对其写一次1。当然,以后就不用写了,因为写了一次1后没有其他的写操作,引脚锁存器中会一直保持这个值不变。当然,如果某个单片机引脚同时作为输出和输入引脚复用时,则必须在输出完成后变成输入前先向其写1,再读引脚的值。
 
大家有什么看法欢迎提出。
   
网友1:可以在Keil中看P1和对应的引脚的值,以此来确定是读寄存器还是读引脚。
 
网友2:(1) 几乎可以肯定的是, "读引脚"与"读寄存器"的区别似乎是不恰当的, 实际上, 我们操作的只有寄存器, 永远都是寄存器. 引脚不过是 io resigter 的一个部分. (2) 另一点几乎可以肯定的是, 使用高级语言或者使用汇编语言, 读寄存器与操作何种语言应该无关. (3) 可能你遇到过一些隐约提及的含糊说法, 大意是读 io, 有可能会带来错误. 是的, 这个错误, 不仅仅是说, 会在指定的 pin 脚上, 读到错误的值, 而且甚至会影响到, 似乎与指定pin脚完全没有关系的, 其他的 pin 脚的值. 其原因就是所谓 "Read-modify-write操作"机制. 一般中文工程师世界中, 我们直译为"读修改写操作". 这个操作的深层内涵是, 明明只想操作 PINA, 为什么该 io register 中包含的其他 7 个pin, 在 32-bit mcu 中, 是其他 31个pin, 都被牵涉到这个操作中, 甚至被错误改写. 比方说, 瞬时的io错误就可能导致这个错误的改写. 现在我们考虑另一个例子, 很多工程师, 习惯于做 pin 的 toggle. 而一个立即的 toggle 的过程, 可能带来时序上的错误, 想想看, 明明 toggle 事件还没有发生, 代码就读回上个 PIN 值, 并强行将这个你不想要的 pin 值又重新写回 io register. -- 那么如何解决这个 read io register 固有的"rmw现象". 一般而言, 我们有几个不同的办法: (a) 我们可以定义一个 back register, 对我们意图保持的数据进行 back, 除了"备份寄存器"的名称外, 或者你也可以称其为"影子 register". (b) 另一个办法, 则可能让人嗔目结舌, 就是很多 mcu 的制作商, 体贴到承认这个现象是工程师常犯的错误, 故提供一个新的 reigster 来替你备份.microchip 就是这么做的, LAT 而不是 IO register. 新晋工程师习惯等效这两个 reigster是不可靠的. 因为回复有1000字的限制, 我仅仅提供我的看法在这里, 另外我的一份 blog 上, 也略有谈及. 有兴趣可以看看: http://www.eeskill.com/group/topic/id/1451
 
网友3:首先同意楼上关于C和汇编对此没有区别等的说法。其次认为这种误解通常是工程师太过“软件”而对于物理世界和芯片内部硬件模块如何工作的理解太过艰难,于是就只有按照部分原厂好心给出的建议的表面文字来理解,带来的奇怪现象了。其实,从这个简单的IO口电路看,写时钟过后读锁存器就与此时钟前的读该线脚相同了,因为线脚状态已经被写入锁存器并保持到下次更改之前。所以注意时序就好了,也因此如果知道背景里这样的操作,很多时候读锁存器和读线脚获得效果是相同的。而我能看到的一个出错可能是:当程序向IO输出(写)操作之后,IO设置变为输入,当它从外界获取一个新的电位,而内部并未进行过写(输出)操作因而锁存器没有更新,此时读锁存器和读IO线脚自然是可以不同的。不过要完整说明这个说法,还要看扩大的IO电路,要包括IO的“转向”控制,更清楚(如果有的话)。 

我见过若干这样的“太过软件”的工程师,或者学生。对于他们来说,程序里的语句是在一种情况下学的,而实际测量(例如示波器)或者实际情况的想象能力,是完全另外的事情,即使二者有联系,也仅仅是:“我这样的语句就会那样的效果”而已。两个世界是脱离的。

网友4:读的是寄存器而不是引脚,我想再粗糙的数字系统,都会先将信号稳定锁存后才读,而且在总线**问的也是GPIO寄存器地址,如果是直接读引脚,万一有干扰或者信号在变化怎么办,半导体厂商不会想不到这个问题的。许这只是个端口电路的大概图式,而不是全部。

网友5:其实都一样,只不过“读”之前要先写1,输出就不用管!

网友6:版主這個現象是8051 I/O的特有性能,大部分MCU 的GPIO都須設定I/O mode 且8051output mode 在Hi lever時高端的FET處於弱輸出也因此8051 GPIO可做wire and並連使用,當使用其他mcu時請小心port 燒毀。

网友7:很有用,解开了我长久以来对于输入输出用法的迷茫。

永不止步步 发表于09-19 10:44 浏览65535次
分享到:

已有0条评论

暂时还没有回复哟,快来抢沙发吧

添加一条新评论

只有登录用户才能评论,请先登录注册哦!

话题作者

永不止步步
金币:67410个|学分:308117个
立即注册
畅学电子网,带你进入电子开发学习世界
专业电子工程技术学习交流社区,加入畅学一起充电加油吧!

x

畅学电子网订阅号