实验5 IIC通讯与AD/接DA接口

简介:

1.利用单片机控制PCF8591AD转换,控制AD0AD1电位器,在数码光上显示DA转换的值。

2.利用单片机控制PCF8591DA转换,让发光二极管D1由暗到亮变化,整个过程时间差不多2s左右,再由亮到暗变化,循环变化。

 

以下代码将12实验合并成一个实验。

Lab6.1

#include<reg51.h>

#include <I2C.H>

 

#define  PCF8591 0x90    //PCF8591 地址

#define uchar unsigned char

#define uint unsigned int

#define ulong unsigned long

 

 

 

//=========全局变量区============================================

unsignedchar AD_CHANNEL;

unsignedint  D[5];

        

sbit high=P2^4;

sbit mid=P2^3;

sbit low=P2^2;

uint code NumTable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//数字的编码

 

 

//=========全局变量区结束========================================

 

 

 

 

//=========函数区============================================

/*******************************************************************

    延时

*******************************************************************/

void delay_1ms(uint x){

    uint i=x;

    uint j;

    for(;i>0;--i){

       for(j=110;j>0;--j);

    }

}

/*******************************************************************

    在数码管上显示对应的值

参数说明:

  Num 要显示的数字

  withDot 是否带点,如果要带点的话,那么传入0x80。不带点,传入0

 

*******************************************************************/

void display(uchar Num,uchar withDot)

{

 

    P0=NumTable[Num]|withDot;

    delay_1ms(1);

    P0=0;      //送完段选信号后,进行消影的处理

}

 

/*******************************************************************

    控制数码管显示,并分解计数值

*******************************************************************/

void DisplayNumByOrder(uint left,uint right){

       low=0; mid=0; high=0;  display(left%10000/1000,0);         //left

        low=1; mid=0; high=0;  display(left%1000/100,0);               

        low=0; mid=1; high=0;  display(left%100/10,0x80);

       low=1; mid=1; high=0;  display(left%10,0);

                                             //right

       low=0; mid=0; high=1;  display(right%10000/1000,0);

       low=1; mid=0; high=1;  display(right%1000/100,0);

       low=0; mid=1; high=1;  display(right%100/10,0x80);

       low=1; mid=1; high=1;  display(right%10,0);

}

 

/*******************************************************************

DAC 变换转化函数              

*******************************************************************/

bit DACconversion(unsignedchar sla,unsignedchar c,  unsignedchar Val)

{

   Start_I2c();              //启动总线

   SendByte(sla);            //发送器件地址

   if(ack==0)return(0);

   SendByte(c);              //发送控制字节

   if(ack==0)return(0);

   SendByte(Val);            //发送DAC的数值 

   if(ack==0)return(0);

   Stop_I2c();               //结束总线

   return(1);

}

 

/*******************************************************************

ADC发送字节[命令]数据函数              

*******************************************************************/

bit ISendByte(unsignedchar sla,unsignedchar c)

{

   Start_I2c();              //启动总线

   SendByte(sla);            //发送器件地址

   if(ack==0)return(0);

   SendByte(c);              //发送数据

   if(ack==0)return(0);

   Stop_I2c();               //结束总线

   return(1);

}

 

/*******************************************************************

ADC读字节数据函数              

*******************************************************************/

unsignedchar IRcvByte(unsignedchar sla)

{  unsignedchar c;

 

   Start_I2c();          //启动总线

   SendByte(sla+1);      //发送器件地址

   if(ack==0)return(0);

   c=RcvByte();          //读取数据0

 

   Ack_I2c(1);           //发送非就答位

   Stop_I2c();           //结束总线

   return(c);

}

 

//******************************************************************/

main()

{ 

     while(1)

     {

       /********以下AD-DA处理*************/ 

       //因为PCF8591读取的是前一个时刻AD转换的值,所以读取的值在第5个时钟才是正常的值,相当于

       //swith经历了一轮case 0~4后,程序里面读取到的AD转换的值才是正常的。

       switch(AD_CHANNEL)    // A/D信道,通过这个函数,4个信道的数值都能读到

       {

            case0: ISendByte(PCF8591,0x41);

                   D[0]=IRcvByte(PCF8591)*2;  //ADC0 模数转换1  放大2倍显示

                   break; 

        

            case1: ISendByte(PCF8591,0x42);

                   D[1]=IRcvByte(PCF8591)*2;  //ADC1  模数转换2

                   break; 

 

            case2: ISendByte(PCF8591,0x43);

                   D[2]=IRcvByte(PCF8591)*2;  //ADC2  模数转换3

                   break; 

 

            case3: ISendByte(PCF8591,0x40);

                   D[3]=IRcvByte(PCF8591)*2;  //ADC3   模数转换4

                   break; 

            case4: DACconversion(PCF8591,0x40, D[4]);//DAC  数模转换

               break;

       }

              D[4]=D[0];  //   把模拟输入采样的信号通过数模转换输出,最终改变灯泡亮度

       if(++AD_CHANNEL>4) AD_CHANNEL=0;

       DisplayNumByOrder(D[0],D[1]);//AD的值送到LED数码管显示

     } 

}

 

//=========函数结束区============================================

 

 

 

 

/*************************此部分为I2C总线的驱动程序*************************************/

I2c.c

#include<reg51.h>

#include <intrins.h>

#include <I2C.H>

 

#define  NOP()   _nop_()   /* 定义空指令 */

#define  _Nop()  _nop_()   /*定义空指令*/

 

 

sbit     SCL=P2^1;       //I2C  时钟

sbit     SDA=P2^0;       //I2C  数据

bit ack;                 /*应答标志位*/

  

 

/*******************************************************************

                     起动总线函数              

函数原型: void  Start_I2c(); 

功能:     启动I2C总线,即发送I2C起始条件. 

********************************************************************/

void Start_I2c()

{

  SDA=1;         /*发送起始条件的数据信号*/

  _Nop();

  SCL=1;

  _Nop();        /*起始条件建立时间大于4.7us,延时*/

  _Nop();

  _Nop();

  _Nop();

  _Nop();   

  SDA=0;         /*发送起始信号*/

  _Nop();        /* 起始条件锁定时间大于4μs*/

  _Nop();

  _Nop();

  _Nop();

  _Nop();      

  SCL=0;       /*钳住I2C总线,准备发送或接收数据 */

  _Nop();

  _Nop();

}

 

/*******************************************************************

                      结束总线函数              

函数原型: void  Stop_I2c(); 

功能:     结束I2C总线,即发送I2C结束条件. 

********************************************************************/

void Stop_I2c()

{

  SDA=0;      /*发送结束条件的数据信号*/

  _Nop();       /*发送结束条件的时钟信号*/

  SCL=1;      /*结束条件建立时间大于4μs*/

  _Nop();

  _Nop();

  _Nop();

  _Nop();

  _Nop();

  SDA=1;      /*发送I2C总线结束信号*/

  _Nop();

  _Nop();

  _Nop();

  _Nop();

}

 

/*******************************************************************

                 字节数据发送函数              

函数原型: void  SendByte(UCHAR c);

功能:     将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对

          此状态位进行操作.(不应答或非应答都使ack=0)    

           发送数据正常,ack=1; ack=0表示被控器无应答或损坏。

********************************************************************/

void  SendByte(unsignedchar  c)

{

 unsignedchar  BitCnt;

 

 for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8*/

    {

     if((c<<BitCnt)&0x80)SDA=1;   /*判断发送位*/

       else  SDA=0;               

     _Nop();

     SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/

      _Nop();

      _Nop();             /*保证时钟高电平周期大于4μs*/

      _Nop();

      _Nop();

      _Nop();        

     SCL=0;

    }

   

    _Nop();

    _Nop();

    SDA=1;                /*8位发送完后释放数据线,准备接收应答位*/

    _Nop();

    _Nop();  

    SCL=1;

    _Nop();

    _Nop();

    _Nop();

    if(SDA==1)ack=0;    

       else ack=1;        /*判断是否接收到应答信号*/

    SCL=0;

    _Nop();

    _Nop();

}

 

/*******************************************************************

                 字节数据接收函数              

函数原型: UCHAR  RcvByte();

功能:        用来接收从器件传来的数据,并判断总线错误(不发应答信号)

          发完后请用应答函数应答从机。 

********************************************************************/   

unsignedchar   RcvByte()

{

  unsignedchar  retc;

  unsignedchar  BitCnt;

 

  retc=0;

  SDA=1;                     /*置数据线为输入方式*/

  for(BitCnt=0;BitCnt<8;BitCnt++)

      {

        _Nop();          

        SCL=0;                  /*置时钟线为低,准备接收数据位*/

        _Nop();

        _Nop();                 /*时钟低电平周期大于4.7μs*/

        _Nop();

        _Nop();

        _Nop();

        SCL=1;                  /*置时钟线为高使数据线上数据有效*/

        _Nop();

        _Nop();

        retc=retc<<1;

        if(SDA==1)retc=retc+1;  /*读数据位,接收的数据位放入retc */

        _Nop();

        _Nop();

      }

  SCL=0;   

  _Nop();

  _Nop();

  return(retc);

}

 

/********************************************************************

                     应答子函数

函数原型:  void Ack_I2c(bit a);

功能:      主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)

********************************************************************/

void Ack_I2c(bit a)

{

 

  if(a==0)SDA=0;              /*在此发出应答或非应答信号 */

  else SDA=1;

  _Nop();

  _Nop();

  _Nop();     

  SCL=1;

  _Nop();

  _Nop();                    /*时钟低电平周期大于4μs*/

  _Nop();

  _Nop();

  _Nop(); 

  SCL=0;                     /*清时钟线,钳住I2C总线以便继续接收*/

  _Nop();

  _Nop();   

}

 

 

 

 

I2c.h

clip_image002

本文转自陈哈哈博客园博客,原文链接http://www.cnblogs.com/kissazi2/p/3174446.html如需转载请自行联系原作者


kissazi2

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
4天前
|
存储 关系型数据库 分布式数据库
PostgreSQL 18 发布,快来 PolarDB 尝鲜!
PostgreSQL 18 发布,PolarDB for PostgreSQL 全面兼容。新版本支持异步I/O、UUIDv7、虚拟生成列、逻辑复制增强及OAuth认证,显著提升性能与安全。PolarDB-PG 18 支持存算分离架构,融合海量弹性存储与极致计算性能,搭配丰富插件生态,为企业提供高效、稳定、灵活的云数据库解决方案,助力企业数字化转型如虎添翼!
|
15天前
|
弹性计算 关系型数据库 微服务
基于 Docker 与 Kubernetes(K3s)的微服务:阿里云生产环境扩容实践
在微服务架构中,如何实现“稳定扩容”与“成本可控”是企业面临的核心挑战。本文结合 Python FastAPI 微服务实战,详解如何基于阿里云基础设施,利用 Docker 封装服务、K3s 实现容器编排,构建生产级微服务架构。内容涵盖容器构建、集群部署、自动扩缩容、可观测性等关键环节,适配阿里云资源特性与服务生态,助力企业打造低成本、高可靠、易扩展的微服务解决方案。
1312 5
|
2天前
|
监控 JavaScript Java
基于大模型技术的反欺诈知识问答系统
随着互联网与金融科技发展,网络欺诈频发,构建高效反欺诈平台成为迫切需求。本文基于Java、Vue.js、Spring Boot与MySQL技术,设计实现集欺诈识别、宣传教育、用户互动于一体的反欺诈系统,提升公众防范意识,助力企业合规与用户权益保护。
|
14天前
|
机器学习/深度学习 人工智能 前端开发
通义DeepResearch全面开源!同步分享可落地的高阶Agent构建方法论
通义研究团队开源发布通义 DeepResearch —— 首个在性能上可与 OpenAI DeepResearch 相媲美、并在多项权威基准测试中取得领先表现的全开源 Web Agent。
1356 87
|
2天前
|
JavaScript Java 大数据
基于JavaWeb的销售管理系统设计系统
本系统基于Java、MySQL、Spring Boot与Vue.js技术,构建高效、可扩展的销售管理平台,实现客户、订单、数据可视化等全流程自动化管理,提升企业运营效率与决策能力。
|
3天前
|
弹性计算 安全 数据安全/隐私保护
2025年阿里云域名备案流程(新手图文详细流程)
本文图文详解阿里云账号注册、服务器租赁、域名购买及备案全流程,涵盖企业实名认证、信息模板创建、域名备案提交与管局审核等关键步骤,助您快速完成网站上线前的准备工作。
192 82
2025年阿里云域名备案流程(新手图文详细流程)