51单片机使用笔记


51单片机使用笔记

前言

学习51时踩的一些坑和经验,系统的参考代码可见[JulyCub/51-CodeLibary (github.com)]

正文

  1. P1,P2口可以输出更大的电压(推挽输出),能到5v,一般的只到3.3

  2. 六角开关分方向,可以试试拿万用表测,只有两对脚有控制功能

  3. 数码管写入

    .dp g f e d c b a
    从左往右写二进制,左边高位,然后翻译成16进制。
    翻译16进制,可以每四位一翻译,然后接起来
    例如
    0101 1001
      5    B
  4. 数码管

    ​ 段选—选择哪一个led管亮

    ​ 位选—选择哪一个数字亮

  5. 运算符

    https://www.runoob.com/cprogramming/c-operators.html
    注意看“左移<<”“右移>>”“按位取反~”
  6. 使用二进制操作(移位,取反,取模等)数学方法,可以取得比for这种函数更快的运行速度,避免奇奇怪怪的误差

    例如

    P0 = 0x01 << i++
    i = i%8

    这个代码实现了p0的值从0000 0001到0000 0010到…到1000 0000的位移变换

  7. 按键消抖

    “按键按下时会有短暂抖动,不是直接拉到低电平。而单片机运算速度非常快,所以要消抖”

    方法

    1. 检测是否按下按键
    2. 等待抖动现象消失(经验值是延迟10ms)
    3. 再次检测是否按下
    	此时,抖动现象已经消失,电平稳定,是真实值
    4. 松手检测(看需求)

    示例

    while (1)
    {
    	if (P20 == 0)
    	{
    		delay.ms(10);
    		if (P20 == 0)//确实是按下了
    		{
    			......//要执行的按键响应程序
    			while (P20 ==0);//死循环,等待松手
    		}
    	}
    }
  8. proreus的按键旁边有一个红色的标志,按一下可以使按键一直被按下

  9. 外部中断

    INT0,INT1

    中断函数号(中断优先级),越小,优先级越高。当同时触发时,先处理优先级高的,处理完再处理剩下的

    写法

    void 函数名() interrupt 中断号

    中断有效条件

    1. 中断源有中断请求(这个中断请求可以是下降沿,也可以是低电平,取决于设置外部中断的触发方式(比如说IT0=0))
    2. 此时对应中断的允许位为一(允许那个中断来打扰cpu)参见(https://baike.baidu.com/item/ie/8411164)
    
    3. cpu开启了中断(EA=1)(cpu愿意被中断打扰)
    位序号 D0 D1 D2 D3 D4
    说明 外部中断0 定时/计数0 外部中断1 定时/计数1 串行口中断
    位符号(写程序时直接引用) EX0 ET0 EX1 ET1 ES

    中断采集下降沿上升沿比较好,因为发生时间短,更加准确快速。

  10. C51初始化的时候,io口全部置高,寄存器全部清零,sp堆栈指针为0x07

  11. sbit 和 define 在设置变量引脚对应关系上的区别

    sbit就是定义一个标志位,也叫位变量,比如一个8位的寄存器就可以看作八个位变量。
    #define就是替代或者替换的意思,
    主要就是用一个好记的名字替换一句不好记或者很长的鸟语啦。
    所以你的#define key1 P3^0说不通,P3^0不是寄存器而是指向性质的,
    如果你用#include<AT89X52.H>之类的话你可以#define key1 P3_0
  12. 0.96屏幕的长度是128x64位

  13. keil中’a’表示传递a的ascii码,””才是字符串。

  14. 在include中,<>表示直接在标准库里面查找库,’’表示优先在当前目录查找

  15. 计时器

    https://blog.csdn.net/a514371309/article/details/73432842

    上面那篇文章有个写的很好的地方

    计数器溢出后,THx与TLx都归0。并将特殊功能区中对应的溢出标志位TFx写为1
    这也就是如何实现溢出中断的

    TLx与THx之间256进制。即当TLx计到256个脉冲时,TLx归0同时THx进1。这也称为方式1。在方式1时,最多计65536个脉冲产生溢出。在主频为11.0592M时,每计一个脉冲为1.085us,所以溢出一次的时间为1.085usx65536=71.1ms。

    溢出时,将会触发溢出中断,软件就可以运行中断服务函数,通过计算有多少次溢出,就可以实现计时(在中断服务函数中使用static变量来计数)

  16. 定时器是统计内部时钟,计数器是统计外部信号源

  17. 定时器工作方式

    16位软件重装–溢出以后跳转执行中断服务,在中断服务函数里面手动设置两个寄存器的初值

    8位自动重装–在低八位溢出后,硬件自动将高八位的值赋给低八位,非常非常精确(主要是少了软件赋值这步,快一点点)

  18. 中断服务

    https://blog.csdn.net/zhibudefeng/article/details/7165319
  19. 推挽输出

    例如 p0m0=0xff就是p0的推挽输出

  20. 可移位寻址–可以直接写寄存器那个位的名字

    不可移位寻址–只能一次为整个寄存器赋值

  21. 在keil里面

    #ifndef x//先测试x是否被宏定义过
    #define x//如果没有宏定义下面就宏定义x并编译下面的语句
    ...
    #endif//如果已经定义了则编译#endif后面的语句
    ...

    这样可以避免出现重复定义,条件指示符#ifndef 的最主要目的是防止头文件的重复包含和编译

    x的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h –> #ifndef _STDIO_H_

  22. intrins.h 万能库,要是有语法报错就带上,只有好处没有坏处

  23. BCD码,有些外设芯片不用十六进制的地址编码,用的是bcd码,比如31就是0x31

  24. 在通信中有上升沿采集数据,和下降沿采集数据,依据芯片手册决定

    image-20220117093117324

    这里箭头所在的边缘就是读数据的时刻,此处注意主机接收的数据在主机发出最后一个写数据位的时钟的下降沿被发出

  25. 引脚名字上面的横线表示取非

    image-20220117094251963

    表示“低电平为真(有效)”

  26. 根据不同芯片,数据有先发低位(LSB)和先发高位(HSB)之分,先发低位较多,==具体参照芯片手册==

  27. 一个char乘以255和乘以0xff在keil里面好像是不一样的要注意类型,char 最好就乘16进制的


  目录