C51(STC89C52)


学习资料

b站江科大自化协51单片机入门教程笔记(1)

b站江科大自化协51单片机入门教程笔记(2)

51单片机89C516笔记(二)

STM32F1学习笔记(超详细35000字介绍)

基本思想

  • 单片机最小应用系统:单片机、晶振、复位电路、电源

  • 电源和Vcc引脚之间有滤波电容

  • LED:正极引脚长,负极引脚短,正极电源和LED之间有限流电阻,防止LED灯烧坏

  • CPU通过控制寄存器中的数值,在通过驱动器和IO端口相连从而控制外设,同时,也可以从IO端口获得外设的状态,送给寄存器

  • 在单片机中寄存器就是一段特殊的RAM存储器:

    • 寄存器可以存储和读取数据,

    • 每一个寄存器背后都连接了一根导线,控制着电路的连接方式

    • 可位寻址:可以单独赋值 不可位寻址:只能整体赋值

  • 单片机通电时所有IO口都是高电平

  • 单片机的高电平驱动能力弱,低电平驱动能力强

  • 注意寄存器高低位的方向:最左边是高位,最右边是低位

  • 寄存器8个为一组,如果直接操作某个寄存器,则需要同时给8个赋值,现在只想操作寄存器的某一位,打开头文件,找到对位寄存器的声明

  • 单片机IO口模式:弱上拉模式,即准双向口,即其既可以输出,又可以输入。弱上拉:输出1的驱动能力有限,输出零的驱动能力强,除此之外,还有其他模式

  • 无符号字符型为0~255的8位二进制数据,表示一个寄存器unsigned char

  • 单片机通过配置寄存器来控制内部线路的连接;开关拨到哪个位置就是靠寄存器控制的

    数码管

  • 数码管 一个单独的,分为共阴极和共阳极,要使其正常工作,共阴极接0,共阳极接1

  • 四位一体数码管静态显示:共阴极和共阳极作为位选,四个数码管公用一个段选

  • 动态显示:高频率扫描

  • 74LS138:38译码器,可以通过三个地址端控制八个数码管的位选

  • 在数码管的段选和输入间一般会有双向数据缓冲器,比如74HC245,其中DIR用于控制方向,既可以给数码管提供段选信号,又可以读取数码管的段选限号,可以用于提高数据的驱动能力

  • 动态显示数码管+模块化编程

    数码管扫描(输出扫描)原理:显示第1位→显示第2位→显示第3位→……,然后快速循环这个过程,最终实现所有数码管同时显示的效果

    W9_3@MBSTJ57_LZBBAF8Q_M.png

    其它.c文件想使用其中的代码时,只需要#include “XXX.h”文件即可

    main.c

    #include <REGX52.H>	// <>是在安装目录里找这个文件
    #include "Delay.h"	//包含Delay头文件  ""是在自己程序目录里寻找文件
    #include "Nixie.h"	//包含数码管头文件
    
    void main()
    {
        while(1)
        {
            Nixie(1,1);	//在数码管的第1位置显示1
            Nixie(2,2);	//在数码管的第2位置显示2
            Nixie(3,3);	//在数码管的第3位置显示3
            Nixie(4,4);	//在数码管的第4位置显示4
            Nixie(5,5);	//在数码管的第5位置显示5
            Nixie(6,6);	//在数码管的第6位置显示6
        }
    }
    

    把各个模块的代码放在不同的.c文件里

    Nixie.c

    #include <REGX52.H>
    #include "Delay.h"	//包含Delay头文件
    //数码管静态、动态显示,驱动方法:38译码器+双向数据缓冲器 数码管为共阴极
    //该段扫描方法:单片机直接扫描 硬件设备简单,但会耗费大量的单片机CPU时间
    //另一种扫描方法:专用驱动芯片:内部自带显存、扫描电路,单片机只需告诉它显示什么即可
    
    //数码管段码表
    unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
    
    //数码管显示子函数
    void Nixie(unsigned char Location,Number)
    {
        switch(Location)		//位码输出
        {
            case 1:P2_4=1;P2_3=1;P2_2=1;break;
            case 2:P2_4=1;P2_3=1;P2_2=0;break;
            case 3:P2_4=1;P2_3=0;P2_2=1;break;
            case 4:P2_4=1;P2_3=0;P2_2=0;break;
            case 5:P2_4=0;P2_3=1;P2_2=1;break;
            case 6:P2_4=0;P2_3=1;P2_2=0;break;
            case 7:P2_4=0;P2_3=0;P2_2=1;break;
            case 8:P2_4=0;P2_3=0;P2_2=0;break;
        }
        P0=NixieTable[Number];	//段码输出
        Delay(1);				//形成数字以后先延时,否则直接清零数码管会比较暗
        P0=0x00;				//段码清0,消影
    }
    //位选 段选 清零  位选 段选
    

    在.h文件里提供外部可调用函数的声明

    Nixie.h

     #ifndef __NIXIE_H__
     #define __NIXIE_H__
     
     void Nixie(unsigned char Location,Number);
     
     #endif
     
    

按键

63YO5J_F_H0WBPB_HBN0D7D.png

  • 轻触按键:在原理图中,若其公共端接低电平,按键松开,读寄存器,值为1;按下时读寄存器为0
  • 按键在按下时不其作用,在松手的一瞬间才起作用,消抖:按键按下时延时20ms,松手时也延时20ms
int main()
{
    while(1)
    {
        if(P3_1==0)
        {
            //如果P31是按下状态,那么延时20ms
            Delay(20);  
            //按下不操作,松手才操作;while(P3_1==0)检测松手,不能不加
            while(P3_1==0); 
            //松手以后,消除松手抖动
            Delay(20); 
             //可以操作了,然后取反
            P2_0=~P2_0;    
        }
            
    }
}
  • 矩阵按键

采用逐行或逐列的“扫描”,就可以读出任何位置按键的状态

矩阵键盘扫描(输入扫描)原理:读取第1行(列)→读取第2行(列) →读取第3行(列) → ……,然后快速循环这个过程,最终实现所有按键同时检测的效果

  • 检测矩阵按键状态,此处采用逐列扫描
#include <REGX52.H>
#include "Delay.h"

/**
  * @brief  矩阵键盘读取按键键码
  * @param  无
  * @retval KeyNumber 按下按键的键码值
            如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下时,返回0
  */
unsigned char MatrixKey()
{
    unsigned char KeyNumber=0;  //局部变量引用必须赋初始值
    
    P1=0xFF; 
    P1_3=0;   // 扫描第一列
    if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
    //在扫描第一列时,如果P1_7==0,那么此时是判断开关1的状态
    //由于是机械按键,加入延时函数消除抖动,然后判断是否松手;如果松手,继续消除抖动
    //返回值KeyNumber
    if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;}
    if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}	
    if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}	
    
    P1=0xFF;
    P1_2=0;   // 扫描第二列
    if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
    if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;}
    if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}	
    if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}	
    
    P1=0xFF;
    P1_1=0;   // 扫描第三列
    if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;}
    if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;}
    if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}	
    if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}	
    
    P1=0xFF;
    P1_0=0;   // 扫描第四列
    if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;}
    if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;}
    if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}	
    if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}	
    
    return KeyNumber;
}

定时器

  • 定时器属于单片机的内部资源

    • 用于计时系统,可实现软件计时
    • 替代长时间的Delay
  • 工作原理

K_V@_9_S0QB0_CIT1QME_@I.png

  • SYSclk:系统时钟,即晶振周期

中断系统

image.png

串口通信

  • 51单片机内部自带UART(Universal Asynchronous Receiver Transmitter,通用异步收发器),可实现单片机的串口通信。
  • TTL电平:+5V表示1,0V表示0,TTL:Transistor-Transistor Logic 晶体管-晶体管逻辑(电路);(单片机就是用的TTL)
  • 如果操作的是端口的寄存器,用的就是IO口;如果操作的是串口的寄存器,就通过IO口发送数据
  • 简单双向串口通信有两根通信线(发送端TXD和接收端RXD)

文章作者: Wgm
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Wgm !
  目录