C51基础知识

一、基础知识&点亮LED灯

 1 byte(字节)=8 bit(位)

 编码表,使用编码表程序会放在程序存储器中,也可以指定内存位置,不用编码表的话会放在RAM里,RAM内存是有限的

二、流水灯、蜂鸣器继电器

有一个用来控制流水灯的循环函数(之后补),流水灯:循环左移

锁存器

 OE:Output Enable,上面的——代表低电平有效

 LE:锁存器的所存端

 Z:高阻态,介于高电平和低电平之间的状态

 DB1-DB8接在P1口上,点灯的时候,给DIOLA一个高电平,让锁存器保持在直通状态,D是什么Q就是什么,但是DB1-DB8同时也和AD转换芯片接在一起了,在用AD转换的时候就需要用锁存器锁住转换出的值以便控制led灯

三、数码管的显示原理

数码管显示原理

 U1控制段选,U2控制位选

复位电路

 晶振

四、数码管的动态显示&中断

 TCON

 

 

中断三条代码没对上

C52中中断请求由TCON的IT0控制

原因是低电平触发是默认的,单片机上电后都是低电平,中断请求可以不用写

如果是跳变沿触发,就需要设置IT0,就和中断条件对应上了

中断函数(不需要声明)

 无返回值   函数名 interrupt  中断序号

定时器

 

 

 

 

TH0和TL0里如何存放数据? 为什么除以256?

方式一是16位定时器,所以一共可以放2^16也就是65536个数,最终对应65ms

我们想要的50MS在加上一个多少就能等于65536,也就是65536和50000的差值,这个值就是我们说的初值。也就是说定时器里存放的是初值

除以256是因为2^8=256,低8位满一次高8位加1,那么高8位装多少,低8位就满了几次,算法就是用差值除一下256取其整数,剩下的,就是还剩了小于256次数的就放在低8位,就是差值 的余数。如果我要放一个超过256的数,肯定是超过先放高八位,把剩下的部分放在低八位中了,TH0=(65536-50000)/256就是把TL0中放不下的部分放在TH0中,再把剩下的部分放在TH0中。

假设我们要50ms进行一次中断,TH0=(65536-50000)/256

                                                    TL0=(65536-50000)%256

 

 为什么再装初值?

 如果只装一次初值的话,当定时器记满清零后,初值就为零了,为了保证时间还是我们想要的,所以需要再装初值。

如果想要1s怎么办呢?

main函数里有一个变量tt,让tt自加1,在主程序检测tt是否为20,当tt=20的时候,定时器走一次50ms,这样就是1s了

 

中断函数后的using

现象:流水灯在工作,中断里的数码管很久才动一下

这是为什么呢?

在延时函数里的时候就已经到了中断的时间了,错过了进入中断的时间

中断从TR0=0开始记两秒,很有可能程序还在delay中的时候aa已经到了40,

假设从中断开始计时到delay,aa刚好是20,到if会多出if之前两条程序的时间,从第一次到if开始就不是正确的时间,后面我再走20个中断也是从岔开的时间开始走,那么在走完delay来到if判断的时候必然进不去数码管的程序,只有在恰好等于40的时候才会走数码管的程序

所以不将if判断放在主函数内,delay会有影响,放到终端函数里,到时间直接走数码管程序

中断:如果到了两秒,数码管就显示对应的数,不到就执行主函数里的流水灯

 

 

 

五、独立键盘&矩阵键盘

独立键盘

 键盘是有抖动的,按下一次大概有20us,当按下的时候,由于抖动,在这个时间内,num已经++好几次了,此时按键是一直按着的,所以num会一直在这个if里++,等松手来到else以后,num其实已经不止++一次了。所以为了避免抖动,在松手之前,让程序一直在while里循环,这样可以保证num只++一次

为了避免按下松开时的抖动,需用延时函数进行消抖

 矩阵键盘

原理没写,可能需要理解一下

再加一嘴,到第九讲的时候郭天祥说按下检测没写,可以从这直接跳到第九讲看完,不然后面可能会忘了。

为什么判断两遍?

六、AD/DA的工作原理

1.DA

 D7=1时,D7后面所有电阻为2R,与D7上的电阻均分电流,所以I7=I/2,而I6又以同样的方式均分I7,所以I6=I7/2=I/4,后面所有电流同理

 

 

 

 时序图:

网格部分代表无所谓,两个箭头包起来的部分表示有效数据

什么是数字量,什么是模拟量?

数字量是脉冲,只有01两种,模拟量是电流电压

DA灯由暗到亮,在由暗到亮思路,定时器内P0由0++到0xff;再由0xff--到0

2. AD

是I7+I6的和和VIN比吗?还是一位一位的比呢 

 

 

 先转换CS=0,WR给一个低脉冲(1->0->1)

 在读数据,CS=0,RD也给一个低脉冲(1->0->1)

郭天祥代码思路:首先看AD0804这个芯片,把转换完的数据通过DB口传到锁存器,这个锁存器正好还和LED连着,如下图

为什么要初始化P0?

因为锁存器D0-D7是和P0口连着的

 

为什么是0x7f?

要进行AD转换,首先要片选,设置SCAD的值,CSAD是和D7连在一起的,将SCAD设置为低电平

 

作业2:AD转换完后的数据换成二进制在数码管前三位显示

段选的值就是转换后的数据,那转化后的数据怎么获取呢?锁存器的值怎么给P0呢?

init(){
       P0=0x7f;//CSAD置零
 }

strat(){
    wr=1;
    wr=0;
    wr=1;//wr一个低脉冲开始转换
}

void main(){
        init(); 
        while(1){
            strat();
            delay(5);
            rd=0;//开始读
            delay(20);
            rd=1;
            delay(20);
            temp=P0;//例程里都没有设置LED灯,我觉得是因为LED直接和锁存器连着,那数码管也是直接和 
                      锁存器连着的啊,那也不用选吗,先暂且接受一下P0的数据吧
            wela=1;
            P0=0x1f;//前三个数码管
            wela=0;
            dula=1;
            P0=temp;
            dula=0;
}
}

作业3:AD的值读回来送给DA

DA和AD的CS与52的接口不是同一个位置,DA是P3.2,AD是在锁存器上,需要设置P0口来将CS置零。

init(){
       P0=0x7f;//CSAD置零
 }

strat(){
    wr=1;
    wr=0;
    wr=1;//wr一个低脉冲开始转换
}

void main(){
        init(); 
        while(1){
            strat();
            delay(5);
            rd=0;//开始读
            delay(20);
            rd=1;
            delay(20);
            temp=P0;
            scda=0;
            wr=0;
            P0=temp;
            while(1);
}
            

七、串口通讯原理

 举例:P0口发送八位数据

 八位收起以后记为一个字节

异步通信:

 

 

同步通信(了解) 

 

 

 

 奇偶校验

 

 

 

 

单片机接收信号程序

法一(查询法):单片机接收到数据以后,TI会置位,查询TI是否置位,手动给TI清零(郭天祥是这                          么说的,但是接收用什么TI啊,不应该是用RI吗,气死我了,后面他代码里写的也                          是RI,破案了,就是RI)这种方法主要利用下图所讲的原理

                    (1)确定T1的工作方式:串口通讯的话TMOD要选择工作方式2(8位自动重装定时/                                  计数器)

                        为什么是0x20?

                          高四位是T1,高四位的M0,M1选择10的方式 0010 0000

                    (2)计算T1的初值,装载TH1,TL1,波特率前面算过了,9600Bd对应的TH1=0xfd;

                            TH1是常数寄存器

                    (3)确定串行口控制,将SM0,SM1的工作方式为方式一01,也就是十位异步收发                               器

                    (4)根据上图原理,首先得将REN置一

                    (5)启动定时器,TR1=1;

                    (6)说下原理,当RI=1的时候,像CPU请求中断,我们查询的就是RI是不是等于                                   1,请求中断后,需手动清零,当RI=0的时候,就将接收到的数据装入SBUF                                   里,并用P1接收了SBUF的值

#include <reg52.h>
void main(){
TMOD=0x20;
TH1=0xfd;
TL1=0xfd;
SM0=0;
SM1=1;
REN=1;
TR1=1;
while(1){
  if(RI==1){
      RI=0;
      p1=SBUF;
}
}
}

                            为什么用P1接收SBUF?

                            去看芯片原理图,流水灯接的是DB0-7,在52上对应P1口,

                            数码管接的是D0-7,在52上是P1口

法二(中断法):TI置位后会像单片机申请中断,利用中断函数自动置位

                   (1)确定T1的工作方式:串口通讯的话TMOD要选择工作方式2(8位自动重装定时/                                  计数器)

                    (2)计算T1的初值,装载TH1,TL1,波特率前面算过了,9600Bd对应的TH1=0xfd;

                            TH1是常数寄存器

                    (3)确定串行口控制,将SM0,SM1的工作方式为方式一01,也就是十位异步收发                               器

                    (4)得将REN置一

                    (5)打开总中断和串口中断

                    (6)启动定时器,TR1=1;

                    (7)写一个中断函数,让RI=0,SBUF里有数据,让P1接收数据

#include <reg52.h>
void main(){
TMOD=0x20;
TH1=0xfd;
TL1=0xfd;
SM0=0;
SM1=1;
REN=1;
TR1=1;
EA=1;
ES=1;//串口中断
while(1);
}
}
void serial() interrupt 1 {
       RI=0;
      p1=SBUF;
}

发送数据程序

#include <reg52.h>
uint8_t flag,a;
void main(){
TMOD=0x20;
TH1=0xfd;
TL1=0xfd;
SM0=0;
SM1=1;
REN=1;
TR1=1;
EA=1;
ES=1;//串口中断
while(1){
     if(flag==1){
         flag=0;
         ES=0;
         SBUF=a;
         while(!TI);//郭天祥说判断是否发完,只要发了不就是1了吗,这行代码有必要吗
         TI=0;
         ES=1;
}
}
}
}
void serial() interrupt 1 {
      RI=0;
      SBUF=a;
      flag=1;
}

 while(!TI);如果不写ES=0呢,直接写TI=0能不能达到同样的效果?

液晶没看,我之后的板子用不到,就没看,之后有时间在补吧,这个笔记里还有我未解决的疑问,也要等到后面有空在解答了,或者谁帮我解答一下

九、IIC

 

先传最高位

 

 地址:7位地址位+1位方向位

 

 

 不管应不应答,主机要从从机接收数据了

 

 

 需要延时函数

 

 

 

移位操作:

左移时,最低位补零,最高位一如PSW的CY位;PSW:状态寄存器   CY位:溢出位

右移时,最低位移除,最高位补零

 起始位,设备地址,写入的地址,数据,stop

 起始位,设备地址,数据,stop

随即地址读需要虚拟写入,因为先要告诉它哪个内部寄存器是你想要读取的

为什么需要虚拟写入?

因为不仅要指定读取的从机设备,还要告诉从机是从哪个位置开始读的,所以要把位置写入到从机

起始位,从机地址,读取的位置地址,在一个开始,从这个开始主机要从写变为读,所以再一个从机地址,后面是所要读取的数据

#include<reg52.h>
typedef unsigned char  uint8_t
typedef unsigned int  uint32_t
sbit SDA=P2^0;
sbit SCL=P2^1;
uint8_t i=0,temp;

void Mydelay(int k){//about 5us
    for(i=0;i++;i<k){
       for(j=0;j++00;j<200) 
}
}
void IICStrat(){
    SDA=1;
    Mydelay(50);
    SCL=1;
    Mydelay(50);
    SCL=0;
}
void IICStop(){
    SDA=0;
    Mydelay(50);
    SCL=1;
    Mydelay(50);
    SDA=1;
}
void IICRespond(){
    //如何确定第九个时钟让ACK=1
    //ACK这个变量就是数据线上的,ACK=1就是SDA=1
    SCL=1;
    Mydelay(50);
    while((SDA=1)&&(i<250))i++;//郭天祥的经验,i到250差不多就是第九个时钟
    SCL=0;
    Mydelay(50);
}
void  init(){//初始化,总线状态可以任意定义,但是一般定义为1,方便后续操作
    SCL=1;
    SDA=1;
}
void write_byte(uint8_t data){
    //如何完成一位一位的送数据的操作呢?
    //将要传输的数据一位一位的左移送到PSW寄存器里的CY中
    SCL=0;
    Mydelay(50);
    temp=data;
    for(i=0;i<8;i++){
    temp=temp<<1;
    SAD=CY;//error:CY=temp;传数据的话要放到SDA上
    SCL=1;
    Mydelay(50);
    //别忘了把SCL再置零
    SCL=0; 
    Mydelay(50);
}
    SDA=1//释放总线
    Mydelay(50);
}
int read_byte(){
    uint8_t temp,data;
    SCl=0;
    Mydelay(50);
    for(i=0;i<8;i++){
    SCL=1;
    Mydelay(50);
    SDA=1;
    temp=SDA;
    data=(data<<1)|temp;
    SCL=0;
    Mydelay(50);
}
    return data;
}
void write_add(uint8_t address,uint8_t data){
    //写地址
    //start、从机地址、ACK=1、写入的地址、ACK=1、写入的数据、ACK=0、stop
    IICStrat();
    write_byte(0xa0);
    respond();
    write_byte(address);
    respond();
    write_byte(data);
    respond();
    IICStop();
}
void write_add(uint8_t address){
    //读数据(随机读)
    //start、从机地址、ACK=1、写入的地址、ACK=1、写入的数据、ACK=0、stop
    uint8_t data;
    IICStrat();
    write_byte(0xa0);
    respond();
    write_byte(address);
    respond();
    write_byte(0xa1);
    respond();
    data=read_byte();
    IICStop();
    return data;
}
//void random_read(){
//}
void mian(){
    init();
    write_add(23,0xaa);
    
    Mydelay(100);
    P1=read_add(23);;
    while(1);
}

第十讲 用定时器创建流水灯

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值