单片机实验整理

代码搬运自其他博主,自己写的注释,持续更新中。。。。

原博主乐者zmh_算法编程题解析,web自动化,opencv-优快云博客


实验内容1️⃣:用AD转换显示电压值,DA转换实现呼吸灯

其中电压值的读取用到了PCF8591芯片

main.c


#include"dac.h"//用到的头文件声明
#include"i2c.h"
#include"timer0.h"

unsigned char dat=0;

void main(){
    timer0_init(); 
    while(1){        
        dat=PCF8591_Read();  //模数AD转换,是将模拟量转换为数字量,方便后续write写入,read和write函数的声明在i2c.c中
        PCF8591_Write(255);  //参考dac.h里的公式,给定最高电压为5V,单位为FACTOR=5/256,后面temp=FACTOR*dat就是实际电压值,由于是8位,8位2进制最大对应255,此时对应最大电压,实际电压=5/256*255近似5V即灯最亮
        delay(10000);  //延时,它的定义在dac.h中给出
        dat=PCF8591_Read();//继续执行读操作AD转换
        PCF8591_Write(200);//改变电压,呈现出一种灯逐渐变暗的现象
        delay(10000);
        dat=PCF8591_Read();
      PCF8591_Write(150);
        delay(10000);
        dat=PCF8591_Read();
        PCF8591_Write(100);
        delay(10000);
        dat=PCF8591_Read();
        PCF8591_Write(50);
        delay(10000);
        dat=PCF8591_Read();
        PCF8591_Write(0);//灯灭
        delay(10000);
        dat=PCF8591_Read();
        PCF8591_Write(50);//灯又开始重新慢慢亮起来
        delay(10000);
        dat=PCF8591_Read();
        PCF8591_Write(100);
        delay(10000);
        PCF8591_Write(150);
        delay(10000);
        dat=PCF8591_Read();
        PCF8591_Write(200);
        delay(10000);
        dat=PCF8591_Read();
        PCF8591_Write(255);
        delay(10000);
    }
}

void timer0() interrupt 1{   //这里设置了timer0中断目的是延时,这也是除了delay()函数外另一种延时方法
    TH0=0xdc;
    TL0=0x00;//设置定时器延时10ms,THTL确定方式:12*x/f=设置延时时间,f一般为12Mhz,然后因为是16位重载方式THTL=(65536-x)后化为16进制的值
    display(dat);  //display函数是控制数码管显示的函数,在Dac.c中声明,这里就是在数码管上显示dat即电压的值
}

timer0.c


#include"timer0.h"//头文件

void timer0_init(){//因为上面用了timer0来延时,所以要初始化timer0
    EA=1;//打开中断总开关
    ET0=1;//打开timer0这个分开关,允许T0中断
    TR0=1;//一旦用到了定时器的定时功能都要设置TR0=1以启动定时器
    TMOD=0x01;//设置定时器工作模式为1
    TH0=0xdc;//设置延时时间为10ms
    TL0=0x00;
}

timer0.h


#ifndef __TIMER0_H__//固定格式,但注意要把中间改成和头文件名一样的大写形式
#define __TIMER0_H__//固定格式,但注意要把中间改成和头文件名一样的大写形式

    #include <reg52.h>    //固定格式
    void timer0_init();    //声明timer0.c文件里用到的函数
    
#endif//固定格式

dac.c


#include"dac.h"//头文件声明
unsigned char code smgduan[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//共阳数码管对应的0-9这10个数字(数码管引脚图见下图)
unsigned char i;
unsigned char voltage[2];//这是定义voltage数组表示有两位,即【0】和【1】

void delay(unsigned int i){//定义delay()延时函数
    while(i--);//计算机做减法会占用比较多的时间,因此可以用来延时
}

void display(unsigned char dat){ //display()函数的声明       
    float temp = FACTOR * dat;//电压值
    if(dat == 255){//这里和下面是用两位数的voltage来量化电压voltage[1]voltage[0],目的是为了把电压值与数码管上显示的对应起来,以便数组voltage[1]voltage[0]能对应数码管里的0-9这10个数
        voltage[1]= 5;//5v
        voltage[0] = 0;
    }
    else{ //非5v
        voltage[1]= (unsigned char)temp;//获得电压值的整数部分
        voltage[0] = (unsigned char)((temp - voltage[1]) * 10);//获得电压值的小数部分
    }    
    for(i=0;i<2;i++)
    {//数码管有两位用来动态显示电压,所以是两种情况(数码管的动态显示的原理是以人眼看不到的极快速度快速切换)
        switch(i){//下面的P0是为了控制数码管内引脚,而P1是为了控制哪个数码管工作(一共是4个数码管)         
      case(0): 
        LSA=0;LSB=0;LSC=1;LSD=0; break; //数码管的引脚分配显示第一位,在Dac.h中可见LSA=P1^3,LSB=P1^2,LSC=P1^1,LSD=P1^0,这里是P1^1
      case(1): 
        LSA=0;LSB=1;LSC=0;LSD=0; break;  //数码管的引脚分配显示第二位,这里是P1^2   
        }
        if(i==1)//P1.2亮
            P0=smgduan[voltage[i]]&0x7f;//这里与的目的是让数码管引脚上的dp始终起作用,即小数部分
        else //P1^1亮
            P0=smgduan[voltage[i]];//显示整数部分    
      delay(100); //短暂延时      
        P0=0xFF;//这里是数码管的消隐,直接关闭数码管所有的位,其目的是避免数码管的鬼影,让下一次显示更清晰
  }      
}   

数码管引脚图:对应的二进制顺序为dp gfe dcba(dp是控制小数点)

dac.h


#ifndef __DAC_H__
#define __DAC_H__

    #define FACTOR 0.01953125 // 这里的FACTOR实际上=5 / 256,它是一个量化单位(用一个字节来量化表示5V的电压值,共为256个量化等级 )
    #include <reg52.h>
    void display(unsigned char dat);//声明dac.c中用到的diplay()函数
    void delay(unsigned int i);//声明dac.c中用到的delay()函数
    sbit LSA=P1^3; //声明P1^0-P1^3的引脚分配
    sbit LSB=P1^2; 
    sbit LSC=P1^1; 
    sbit LSD=P1^0;

#endif

i2c.c


#include"i2c.h"                                

void delay5us(void) //这里是定义延时函数,延时5us
{
    unsigned char a;
    for(a=1;a>0;a--);
}

void I2cStart()  //这是I2c的启动函数
{
    SDA=1;//根据起始信号图,起始时SDA=1,SCL=1
    SCL=1;
    delay5us();//然后延时接近5us
    SDA=0;//然后变为SDA=0,SCL=1
    delay5us();//然后又延时接近5us
    SCL=0;//保持SCL=0(SCL始终要保持为低电平)            
    delay5us();//延时5us保持接收        
}
void I2cStop()//这是I2c的终止函数  
{
    SDA=0;//根据终止信号图,起始时SDA=0,SCL=1
    SCL=1;
    delay5us();//然后延时接近5us
    SDA=1;//之后SDA=1
    delay5us();//延时5us保持接收            
}

unsigned char I2cReadByte()//这是I2C读取字节的函数
{
  unsigned char a=0,dat=0;
    SDA=1;          
    delay5us();//延时接近5us,是为了保证数据的完全传输(根据数据手册数据传输需要4us、4.7us)
    for(a=0;a<8;a++)//这里是接收8个字节
    {
        SCL=1; //SCL由0变1后发送数据
        delay5us();
        dat&l
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值