单片机读取引脚_单片机编程读取引脚值 - CSDN
精华内容
参与话题
  • 51单片机引脚和读端口测试总结

    千次阅读 2019-01-30 13:29:44
    51的P0 - P3都是准双向I/O端口,作为输入端口时需要先将其置1,然后再读取引脚状态。 这里抛开汇编,单纯讲下C51编程时的哪种情况是读引脚、哪种情况是读端口,以及读引脚前为什么要置1,以防止大家出错。 1.读...

    51的P0 - P3都是准双向I/O端口,作为输入端口时需要先将其置1,然后再读取引脚状态。

    这里抛开汇编,单纯讲下C51编程时的哪种情况是读引脚、哪种情况是读端口,以及读引脚前为什么要置1,以防止大家出错。


    1.读引脚:(下面是测试代码)

    #include <reg51.h>
    
    sbit LED =  P0^0;    //外加上拉电阻
    sbit f = P0^1;
    
    void main()
    {
    	while(1)
            {
    	        if(f == 0)    //如果P0.1是低电平的话就让LED亮
    	        {
    		    LED = 0;
    	        }
            }
    }

    单片机通电复位后,P1口的锁存器Q端都为1,对应的MOS管不导通,P1口在上拉电阻作用下全是高电平,所以LED不亮,用导线将P0.1口拉低,LED瞬间点亮;

    说明 if(f == 0)判断的P0.1引脚的状态即读引脚,LED是否点亮受P0.1引脚状态影响。

    51单片机通电复位后直接读引脚是没问题的。

    但大家可能发现:先将P0.0置0,然后用导线将它拉高,单片机也可以读出此引脚是高电平,这种做法很危险!

    将P0.0置0后,对应的MOS管导通,VCC和GND间通过这个MOS管连接,由于电流较大以及MOS管的电阻作用使得P0.0引脚被拉高(通过万用表可以测出这个高电平较正常情况下低一些,单片机的其他端口的电平状态可能也不正常了),但这会缩短单片机寿命,因此读引脚前一定要向该引脚写一!然后读取引脚电平。(可以说,先写1 就是为了避免这种情况)

    2.读端口:(下面是测试代码)

    #include <reg51.h>
    
    sbit LED =  P0^0;
    
    void delay()
    {
    	unsigned char i = 255;
    	while(--i);
    }
    
    void main()
    {
    	//先将P0.0引脚用导线拉低
    	delay();
    	LED = ~LED;    //LED低电平亮
    	//拔出导线,将P0.0接到LED负极上
    }

    P0.0开始被拉低了,那么对其取反之后,P0.0应该为1,LED应该不亮,但实际是LED亮了,因为这里

    不是读引脚而是读端口(锁存器):单片机上电后P0口全是1,其内部的锁存器输出端Q也为1,虽然P0.0引脚被

    拉低了,但是其锁存器Q端仍为1不变,对1取反后再赋值给P0.0口,点亮了LED。

    可以总结下:

    1. 51单片机里对某一个I/O口进行读--改--写(例如上面的取反后写回)操作时,读取的是与之对应的锁存器的输出,而不

    是实际物理引脚的电平;其他非读--改--写(例如上面的f == 0)指令读取的是引脚电平。

    2. 读引脚电平时一定要先向该端口写1,然后再读取引脚电平!

     

     

     

     

    展开全文
  • 要搞清这个问题,就要明白p0口的内部结构...一般来说,读取P0的数据,都是读引脚,目的是获取与P0相连的外部电路的状态。而读端口是在执行下述语句时由CPU自行完成的: inc P0;给p0加1 执行这个语句时 ,采用“读...

    要搞清这个问题,就要明白p0口的内部结构。P0口是由锁存器经两个驱动场效应管和外部引脚相连的。


    读引脚的意思就是直接读P0外部引脚的电位,而读端口(锁存器)读的是内部与数据总线链接的锁存器的电位。


    两者不同。一般来说,读取P0的数据,都是读引脚,目的是获取与P0相连的外部电路的状态。而读端口是在执行下述语句时由CPU自行完成的:
    inc P0;给p0加1   

    执行这个语句时 ,采用“读-改-写”的过程,先读取p0的端口数据,再加1,然后送到p0锁存器里。注意这个端口数据跟p0的引脚状态不一样,比如你事先给p0写进69H,p0里数据就是69H,而引脚上的状态因为你没有执行MOV A,p0之类的指令,它是不会进到p0的锁存器里去的。由此可见,所谓的读端口,不是读取p0的状态,而是在执行inc之类的指令时由CPU自行完成的。


    读引脚就是读取p0口状态了。读引脚时要注意:先要给p0写FFH,使它的场效应管T2和地断开。


    因为p0口的场效应管T2一端接地,一端与外部引脚相连,由P0的锁存器控制,当给锁存器写1时,它和地断开,写0时和地相连,所以写零时读到的总是低电平。


    试想你现在要读P0引脚,按理说P0与外部电路相连,外部电路的是什么状态,就应该读到什么,但如果p0口的场效应管T2一端接地的话,它会把p0口电位拉低,你读到的总是低电平0,所以要先给p0写FFH,把p0的场效应管T2和地断开,再读数时就是真实状态了。当外部电路断开,再读时读到的就是p0端口(锁存器)的真实状态了。

    实际上不光是P0口,所有口都需要区分的。


    这里问题的关键是:你想读到什么?是你事先通过指令写入口锁存器中的数,还是由外部电路决定的口线的高低电平。因为这两个数有可能是不一样的。


    IO口的输出锁存器是通过控制一个晶体管是否对地导通连接到口的对外引脚上的,该晶体管的C极通过上拉电阻接Vcc(当然P0口的上拉电阻需要外部加上,其它口内部已经有大约40K的弱上拉)。
    于是会出现这样一种情况,例如你向某条口线写了1,锁存器的值是就是1,当然此时对应的晶体管截止,由于有上拉电阻,所以口线应该也是1(高电平),但如果你的口线是控制一个外部npn晶体管的通断,上拉电阻就相当于那个晶体管的基极电阻,于是它会导通。向口写0则口线会变低(<0.3V),它会截止,这都很正常。


    问题是,当口锁存器输出1时,由于外部晶体管BE结导通,电压只有0.7V(也就是口线或者说口的引脚的电压只有0.7V),此时你读入锁存器时得到的是1,但读引脚时会得到0(至少要大于2.4V才算高电平)。例如你想改变该控制信号的状态,通常是先读入,取反,然后再写出,此时必须是读入锁存器才能实现正确的操作!如果是读引脚,本来输出的是1,读入的(引脚)却是0,取反后得1,状态是不会改变的!

    展开全文
  • 51单片机读端口与读引脚

    千次阅读 2015-03-04 10:24:03
    (1)引脚的结构图清楚吗?   以上是P0口一位的结构。以上结构说明:读引脚之前一定要对端口先置1,使mosfet V2截止,以免信号被拉低而读错,这一点很容易理解。 (2)什么指令读端口?什么指令读引脚?...

    原文网址:http://blog.sina.com.cn/s/blog_3e8a48bf0100cm2g.html

    (1)引脚的结构图清楚吗?

     51单片机读端口与读引脚彻底研究(个人浅见)

    以上是P0口一位的结构。以上结构说明:读引脚之前一定要对端口先置1,使mosfet V2截止,以免信号被拉低而读错,这一点很容易理解。

    (2)什么指令读端口?什么指令读引脚?

    一般的教科书上都会强调:读端口的指令为端口内容取反这样的“读-修改-写”指令。而读引脚之前,先置1,然后用Mov A,Px之类的指令即可。 以下是从web(http://www.dzsc.com/dzbbs/20061112/200765184756359377.html)上搜集的资料:

    资料称: 这样的指令才有 Read-Modify-Write 功效

    ANL (logical AND, e.G., ANL P1,A)
    ORL (logical OR, e.g., ORL P2,A)
    XRL (logical EX-OR, e.g., XRL P3,A)
    JBC (jump if bit = 1 and clear bit, e.g., JBC P1.1, LABEL)
    CPL (complement bit, e.g., CPL P3.0)
    INC (increment, e.g., INC P2)
    DEC (decrement, e.g., DEC P2)
    DJNZ (decrement and jump if not zero, e.g., DJNZ P3, LABEL)
    MOV PX.Y,C(move carry bit to bit Y of
     PORT X)
    CLR PX.Y(clear bit Y of
     PORT X)
    SETB PX.Y(set bit Y of
     PORT X)

    (3)有没有读端口的指令(而不修改端口)?

    可以说,没有直接的读端口的指令。无论之前是否置1,以下指令

    MOV A, P1
    MOV 20H, P1
    MOV R0, P1
    MOV @R0, P1

    读的都是引脚,尽管不一定读准确。

    要想知道端口内容,可以采用的方法是(以下代码来源于网络):

    51端口锁存器是能读取!!仿真机才会用到
    READ_PORT_P1_REG2ACC:
         CLR A ; MOV A, #0FFH
         CPL A

         JB P1.0, L_11 ; $+11 ; pin 为“1”时,锁存器肯定为“1”
           JBC P1.0, L_06; $+ 6 ; 用JBC
     TEST 锁存器, 为“1”时,跳    
              JBC ACC.0, L_05; $ + 5 ; == clr acc.0   / sjmp L_05
                                     ;  用2周期/3bytes, 代替 3周期/4bytes
    L_06:       SETB P1.0       ; 恢复 锁存器 为“1”
    L_05:
    L_11:

         JB P1.1, $+11  
         JBC P1.1, $+ 6
             JBC ACC.1, $ + 5
           SETB P1.1

         JB P1.2, $+11
         JBC P1.2, $+ 6
             JBC ACC.2, $ + 5
           SETB P1.2

         JB P1.3, $+11
         JBC P1.3, $+ 6
             JBC ACC.3, $ + 5
           SETB P1.3

         JB P1.4, $+11
         JBC P1.4, $+ 6
             JBC ACC.4, $ + 5
           SETB P1.4

         JB P1.5, $+11
         JBC P1.5, $+ 6
             JBC ACC.5, $ + 5
           SETB P1.5

         JB P1.6, $+11
         JBC P1.6, $+ 6
             JBC ACC.6, $ + 5
           SETB P1.6

         JB P1.7, $+11
         JBC P1.7, $+ 6
             JBC ACC.7, $ + 5
           SETB P1.7

    展开全文
  • 51单片机读取引脚值原理

    千次阅读 2017-12-04 14:46:01
    对于51单片机来说,很多同学知道要读取某一个引脚的信息,需要先对这一位写1,却不知道如果不写1会出现什么情况
    因为51单片机I/O口内部结构的限制,在读取外部引脚状态的时候,需要向端口写1.51单片机复位后,不需要进行此操作也可以进行读取外部引脚的操作。因此,在按键的端口没有复用的情况下,可以省略此步骤。而对于其它一些真正双向I/O口的单片机来说,将引脚设置成输入状态,是必不可少的一个步骤。
    下面的程序代码初始化引脚为输入。
    void KeyInit(void)
    {
        io_key_1 = 1 ;
        io_key_2 = 1 ;
        io_key_3 = 1 ;
        io_key_4 = 1 ;            
    }
    根据按键硬件连接定义按键键值
    #define KEY_VALUE_1              0x0e
    #define KEY_VALUE_2              0x0d
    #define KEY_VALUE_3                0x0b
    #define KEY_VALUE_4                0x07
    #define KEY_NULL                    0x0f
    下面我们来编写按键的硬件驱动程序。
    根据第一章所描述的按键检测原理,我们可以很容易的得出如下的代码:
    static uint8 KeyScan(void)
    {
        if(io_key_1 == 0)return KEY_VALUE_1 ;
        if(io_key_2 == 0)return KEY_VALUE_2 ;
        if(io_key_3 == 0)return KEY_VALUE_3 ;
        if(io_key_4 == 0)return KEY_VALUE_4 ;
        return KEY_NULL ;
    }
    其中io_key_1等是我们按键端口的定义,如下所示:
    sbit io_key_1 = P3^0 ;
    sbit io_key_2 = P3^1 ;
    sbit io_key_3 = P3^2 ;
    sbit io_key_4 = P3^3 ;

    KeyScan()
    作为底层按键的驱动程序,为上层按键扫描提供一个接口,这样我们编写的上层按键扫描函数可以几乎不用修改就可以拿到我们的其它程序中去使用,使得程序复用性大大提高。同时,通过有意识的将与底层硬件连接紧密的程序和与硬件无关的代码分开写,使得程序结构层次清晰,可移植性也更好。对于单片机类的程序而言,能够做到函数级别的代码重用已经足够了。
    在编写我们的上层按键扫描函数之前,需要先完成一些宏定义。
    //
    定义长按键的TICK,以及连_发间隔的TICK
    #define KEY_LONG_PERIOD        100
    #define KEY_CONTINUE_PERIOD    25

    //
    定义按键返回值状态(按下,长按,_,释放)
    #define KEY_DOWN                0x80
    #define KEY_LONG                    0x40
    #define KEY_CONTINUE            0x20
    #define KEY_UP                  0x10

    //
    定义按键状态
    #define KEY_STATE_INIT            0
    #define KEY_STATE_WOBBLE            1
    #define KEY_STATE_PRESS            2
    #define KEY_STATE_LONG            3
    #define KEY_STATE_CONTINUE      4
    #define KEY_STATE_RELEASE        5

    接着我们开始编写完整的上层按键扫描函数,按键的短按,长按,连按,释放等等状态的判断均是在此函数中完成。对照状态流程转移图,然后再看下面的函数代码,可以更容易的去理解函数的执行流程。完整的函数代码如下:

    void GetKey(uint8 *pKeyValue)
    {
        static uint8 s_u8KeyState =KEY_STATE_INIT ;
        static uint8 s_u8KeyTimeCount = 0 ;
        static uint8 s_u8LastKey = KEY_NULL;  //
    保存按键释放时候的键值
        uint8 KeyTemp = KEY_NULL ;

        KeyTemp = KeyScan() ;        //
    获取键值

        switch(s_u8KeyState)
        {
            case KEY_STATE_INIT :
                    {
                        if(KEY_NULL !=(KeyTemp))
                        {
                            s_u8KeyState =KEY_STATE_WOBBLE ;
                        }
                    }
            break ;

            case KEY_STATE_WOBBLE :      //
    消抖
                    {
                        s_u8KeyState =KEY_STATE_PRESS ;    
                    }
            break ;

            case KEY_STATE_PRESS :
                    {
                        if(KEY_NULL !=(KeyTemp))
                        {
                            s_u8LastKey =KeyTemp ; //
    保存键值,以便在释放按键状态返回键值
                            KeyTemp |=KEY_DOWN ;  //
    按键按下
                            s_u8KeyState =KEY_STATE_LONG ;
                        }
                        else
                        {
                            s_u8KeyState =KEY_STATE_INIT ;
                        }
                    }
            break ;

            case KEY_STATE_LONG :
                    {
                        if(KEY_NULL !=(KeyTemp))
                        {
                           if(++s_u8KeyTimeCount > KEY_LONG_PERIOD)
                            {
                               s_u8KeyTimeCount = 0 ;
                                KeyTemp |= KEY_LONG ;  //
    长按键事件发生
                                s_u8KeyState= KEY_STATE_CONTINUE ;
                            }
                        }
                        else
                        {
                            s_u8KeyState =KEY_STATE_RELEASE ;
                        }
                    }
            break ;

            case KEY_STATE_CONTINUE :
                    {
                        if(KEY_NULL !=(KeyTemp))
                        {
                           if(++s_u8KeyTimeCount > KEY_CONTINUE_PERIOD)
                            {
                               s_u8KeyTimeCount = 0 ;
                                KeyTemp |=KEY_CONTINUE ;
                            }
                        }
                        else
                        {
                            s_u8KeyState = KEY_STATE_RELEASE;
                        }
                    }
            break ;

            case KEY_STATE_RELEASE :
                    {
                        s_u8LastKey |= KEY_UP;
                        KeyTemp = s_u8LastKey;
                        s_u8KeyState = KEY_STATE_INIT;
                    }
            break ;

            default : break ;
        }
        *pKeyValue = KeyTemp ; //
    返回键值    
    }
    关于这个函数内部的细节我并不打算花过多笔墨去讲解。对照着按键状态流程转移图,然后去看程序代码,你会发现其实思路非常清晰。最能让人理解透彻的,莫非就是将整个程序自己看懂,然后想象为什么这个地方要这样写,抱着思考的态度去阅读程序,你会发现自己的程序水平会慢慢的提高。所以我更希望的是你能够认认真真的看完,然后思考。也许你会收获更多。
    不管怎么样,这样的一个程序已经完成了本章开始时候要求的功能:按下,长按,连按,释放。事实上,如果掌握了这种基于状态转移的思想,你会发现要求实现其它按键功能,譬如,多键按下,功能键等等,亦相当简单,在下一章,我们就去实现它。
    在主程序中我编写了这样的一段代码,来演示我实现的按键功能。
    void main(void)
    {    
        uint8 KeyValue = KEY_NULL;
        uint8 temp = 0 ;
          LED_CS11 = 1 ; //流水灯输出允许
        LED_SEG = 0 ;
        LED_DIG = 0 ;
        Timer0Init() ;
        KeyInit() ;
        EA = 1 ;
        while(1)
        {
            Timer0MainLoop() ;
            KeyMainLoop(&KeyValue) ;
            
            if(KeyValue == (KEY_VALUE_1 |KEY_DOWN)) P0 = ~1 ;
            if(KeyValue == (KEY_VALUE_1 |KEY_LONG)) P0 = ~2 ;
            if(KeyValue == (KEY_VALUE_1 |KEY_CONTINUE)) { P0 ^= 0xf0;}
            if(KeyValue == (KEY_VALUE_1 |KEY_UP)) P0 = 0xa5 ;
        }

    }
        按住第一个键,可以清晰的看到P0口所接的LED的状态的变化。当按键按下时候,第一个LED灯亮,等待2 S后第二个LED亮,第一个熄灭,表示长按事件发生。再过500 ms 第5~8个LED闪烁,表示连按事件发生。当释放按键时候,P0口所接的LED的状态为:
    灭亮灭亮亮灭亮灭,这也正是P0 = 0xa5这条语句的功能。
    展开全文
  • 详解51系列单片机引脚及功能

    千次阅读 2020-01-02 09:50:48
    51系列单片机有各种封装形式,这里以40引脚双列直插DIP形式的封装来进行介绍,如图1.1所示。其中正电源和地线两根,外置石英振荡器的时钟线两根,4组8位共32个I/O口,中断口线与P3口线复用。 图1.1 8051双列直插式...
  • 本文主要介绍怎么通过遥控接收机的信号控制单片机的IO口。试验器材: 天地飞WFT09II 9通道2.4G遥控器+接收机 STC15F104W单片机 这里接收机输出的是频率为50hz,周期为2ms的pwm波形,通过单片机外部中断口接收pwm...
  • 本篇文章主要介绍如何使用PIC单片机从DHT11读取湿度和温度,并将其显示在LCD显示屏上。在这个例子中,我们使用的单片机型号是PIC16F628A。 所需的内容 要完成此项目,您需要以下内容: ● 使用安装有Microchip ...
  •  前几天帮一个朋友处理一些电路,正好解决了自己以前经常遇到的一个问题:传感器检测信号传送给单片机,如何改变单片机引脚电平信号,使之可在程序中直接读取,进而实现对外部环境的检测。 以前的思路: (1)最初...
  • 1,首先一个小圆坑或小标记指示第1引脚,然后逆时针数下去直到最后一个引脚第40引脚,典型51单片机有40个引脚(或管脚) 4组8个I/O口引脚,加8个特殊引脚,共40个。 2,40个引脚按其功能分为三类: (1)I/O端口...
  • 我看了一些资料,感觉是内部使用电压比较器(施密特触发器)进行判断的,是这样吗,怎么查看这个阈值?那么是否可以通过修改阈值来修改高低电平的辨识值,单片机提供这个功能吗?
  • 51单片机DS18B20温度读取

    千次阅读 2019-08-07 15:22:18
    本文是武汉市海联天下物联网有限公司技术团队内部学习笔记,将详细讲解DS18B20温度显示以及51单片机如何利用单总线与DS18B20通信,DS18B20重要时序掌握。——技术部 张傲 现象描述 使用DS18B20测量温度,并在数码管...
  • 二、单片机读取ID卡(产生载波)

    千次阅读 2018-10-02 10:58:15
    1、程序代码
  • 1 准备工作 硬件设备:JY61模块、STC89C52开发板一个。 ...提取码:zryo。下载并进行安装。 2 硬件连接 ...注意:TX-RX(第p10管脚)、RX-TX(第P11管脚)GND-GND、VCC-5V,前面为JY61,后边是STC89C52板子上的
  • 要解答这个问题,我们先考虑一种情况,假如我们要对P0.1引脚输出(赋值)为1,那么单片机内部是如何工作的? 我们知道,引脚属于IO设备,单片机内部CPU是通过地址总线,数据总线,控制总线对其进行赋值的,也就是说...
  • 二、软件部分
  • 基于单片机通用引脚的软件UART设计

    千次阅读 2015-05-26 10:19:00
    基于单片机通用引脚的软件UART设计 标签:ST 意法半导体 单片机 UART ST论坛转载 引言 随着单片机应用技术的不断深入,由单片机构成的多机系统取得了长足的发展,多个单片机之间以串口进行数据传输,构成复杂...
  • 单片机的基准电压一般为3.3V,如果外部信号超过了AD测量范围,可以采用电阻分压的方法,但是要注意阻抗匹配问题。... 因此对于使用单片机读取外部信号电压,外接分压电阻必须选用较小的电阻,或者在对功耗有要...
  • title: 【STM32Cube-21】使用ADC读取电压值 tags: STM32CubeMX ADC categories: STM32...本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的ADC外设,读取DAC输出引脚的电压值。 1. 准备工作 硬件准备 ...
  • 目录51单片机引脚图电源引脚时钟引脚控制引脚可编程输入/输出引脚P0P1P2P3 51单片机引脚图 电源引脚 VCC(40)脚:电源输入,常压5V GND(20脚):接地线 时钟引脚 XTAL1(19脚):片内振荡电路的输入端 XTAL2(18脚)...
  • 在之前我们已经能够让一个灯不停地闪烁了,此时大家应该大概了解了引脚能够接受数据信息再控制设备; 实际上,在学习跟高级的程序之前,这些知识是不够的。我们理论知识远远不够!  下面,我会结合操作给大家讲...
1 2 3 4 5 ... 20
收藏数 8,179
精华内容 3,271
关键字:

单片机读取引脚