实验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
相关文章
|
3天前
|
人工智能 运维 安全
|
1天前
|
人工智能 异构计算
敬请锁定《C位面对面》,洞察通用计算如何在AI时代持续赋能企业创新,助力业务发展!
敬请锁定《C位面对面》,洞察通用计算如何在AI时代持续赋能企业创新,助力业务发展!
|
8天前
|
人工智能 JavaScript 测试技术
Qwen3-Coder入门教程|10分钟搞定安装配置
Qwen3-Coder 挑战赛简介:无论你是编程小白还是办公达人,都能通过本教程快速上手 Qwen-Code CLI,利用 AI 轻松实现代码编写、文档处理等任务。内容涵盖 API 配置、CLI 安装及多种实用案例,助你提升效率,体验智能编码的乐趣。
767 109
|
3天前
|
机器学习/深度学习 传感器 算法
Edge Impulse:面向微型机器学习的MLOps平台——论文解读
Edge Impulse 是一个面向微型机器学习(TinyML)的云端MLOps平台,致力于解决嵌入式与边缘设备上机器学习开发的碎片化与异构性难题。它提供端到端工具链,涵盖数据采集、信号处理、模型训练、优化压缩及部署全流程,支持资源受限设备的高效AI实现。平台集成AutoML、量化压缩与跨硬件编译技术,显著提升开发效率与模型性能,广泛应用于物联网、可穿戴设备与边缘智能场景。
171 127
|
3天前
|
算法 Python
【轴承故障诊断】一种用于轴承故障诊断的稀疏贝叶斯学习(SBL),两种群稀疏学习算法来提取故障脉冲,第一种仅利用故障脉冲的群稀疏性,第二种则利用故障脉冲的额外周期性行为(Matlab代码实现)
【轴承故障诊断】一种用于轴承故障诊断的稀疏贝叶斯学习(SBL),两种群稀疏学习算法来提取故障脉冲,第一种仅利用故障脉冲的群稀疏性,第二种则利用故障脉冲的额外周期性行为(Matlab代码实现)
230 152
|
5天前
|
Java 数据库 数据安全/隐私保护
Spring 微服务和多租户:处理多个客户端
本文介绍了如何在 Spring Boot 微服务架构中实现多租户。多租户允许单个应用实例为多个客户提供独立服务,尤其适用于 SaaS 应用。文章探讨了多租户的类型、优势与挑战,并详细说明了如何通过 Spring Boot 的灵活配置实现租户隔离、动态租户管理及数据源路由,同时确保数据安全与系统可扩展性。结合微服务的优势,开发者可以构建高效、可维护的多租户系统。
212 127
|
4天前
|
机器学习/深度学习 存储 资源调度
CMSIS-NN:ARM Cortex-M处理器的高效神经网络内核——论文解读
CMSIS-NN是专为ARM Cortex-M系列微控制器优化的神经网络计算内核库,旨在支持资源受限的物联网边缘设备进行高效的深度学习推理。该库通过对卷积、池化、全连接层等关键操作进行定点量化、SIMD指令优化和内存布局调整,显著提升了模型在嵌入式设备上的运行效率。实验表明,CMSIS-NN在Cortex-M7处理器上的推理速度比基准实现提升了近5倍,大幅降低了功耗,为边缘AI应用提供了可行的技术路径。
224 128